From 4b0131e7b071bb06802a99fcf9a3717215b2362b Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Fri, 22 Aug 2014 12:22:28 +0200 Subject: [PATCH] linux-user: Convert blkpg to use a special subop handler The blkpg ioctl can take different payloads depending on the opcode in its payload structure. Create a new special ioctl handler that can only deal with partition style ones for now. Signed-off-by: Alexander Graf --- Andreas, if you like feel free to squash this into your patch and submit it upstream. --- linux-user/ioctls.h | 3 ++- linux-user/syscall.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++ linux-user/syscall_types.h | 2 +- 3 files changed, 56 insertions(+), 2 deletions(-) diff --git a/linux-user/ioctls.h b/linux-user/ioctls.h index 9b6cacb..8eb4446 100644 --- a/linux-user/ioctls.h +++ b/linux-user/ioctls.h @@ -96,7 +96,8 @@ IOCTL(BLKRAGET, IOC_R, MK_PTR(TYPE_LONG)) IOCTL(BLKSSZGET, IOC_R, MK_PTR(TYPE_LONG)) IOCTL(BLKBSZGET, IOC_R, MK_PTR(TYPE_INT)) - IOCTL(BLKPG, IOC_W, MK_PTR(MK_STRUCT(STRUCT_blkpg_ioctl_arg))) + IOCTL_SPECIAL(BLKPG, IOC_W, do_ioctl_blkpg, + MK_PTR(MK_STRUCT(STRUCT_blkpg_ioctl_arg))) #ifdef FIBMAP IOCTL(FIBMAP, IOC_W | IOC_R, MK_PTR(TYPE_LONG)) #endif diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 660095b..04b5119 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -3657,6 +3657,59 @@ out: return ret; } +static abi_long do_ioctl_blkpg(const IOCTLEntry *ie, uint8_t *buf_temp, int fd, + abi_long cmd, abi_long arg) +{ + void *argptr; + int target_size; + const argtype *arg_type = ie->arg_type; + const argtype part_arg_type[] = { MK_STRUCT(STRUCT_blkpg_partition) }; + abi_long ret; + + struct blkpg_ioctl_arg *host_blkpg = (void*)buf_temp; + struct blkpg_partition host_part; + + /* Read and convert blkpg */ + arg_type++; + target_size = thunk_type_size(arg_type, 0); + argptr = lock_user(VERIFY_READ, arg, target_size, 1); + if (!argptr) { + ret = -TARGET_EFAULT; + goto out; + } + thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST); + unlock_user(argptr, arg, 0); + + switch (host_blkpg->op) { + case BLKPG_ADD_PARTITION: + case BLKPG_DEL_PARTITION: + /* payload is struct blkpg_partition */ + break; + default: + /* Unknown opcode */ + ret = -TARGET_EINVAL; + goto out; + } + + /* Read and convert blkpg->data */ + arg = (abi_long)(uintptr_t)host_blkpg->data; + target_size = thunk_type_size(part_arg_type, 0); + argptr = lock_user(VERIFY_READ, arg, target_size, 1); + if (!argptr) { + ret = -TARGET_EFAULT; + goto out; + } + thunk_convert(&host_part, argptr, part_arg_type, THUNK_HOST); + unlock_user(argptr, arg, 0); + + /* Swizzle the data pointer to our local copy and call! */ + host_blkpg->data = &host_part; + ret = get_errno(ioctl(fd, ie->host_cmd, host_blkpg)); + +out: + return ret; +} + static abi_long do_ioctl_rt(const IOCTLEntry *ie, uint8_t *buf_temp, int fd, abi_long cmd, abi_long arg) { diff --git a/linux-user/syscall_types.h b/linux-user/syscall_types.h index 56e344c..a730c87 100644 --- a/linux-user/syscall_types.h +++ b/linux-user/syscall_types.h @@ -260,4 +260,4 @@ STRUCT(blkpg_ioctl_arg, TYPE_INT, /* op */ TYPE_INT, /* flags */ TYPE_INT, /* datalen */ - MK_PTR(MK_STRUCT(STRUCT_blkpg_partition))) /* data */ + TYPE_PTRVOID) /* data */