qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] [PATCH v6 48/49] linux-user: Split out ioctl


From: Laurent Vivier
Subject: Re: [Qemu-devel] [PATCH v6 48/49] linux-user: Split out ioctl
Date: Wed, 13 Feb 2019 14:09:35 +0100
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Thunderbird/60.5.0

Hi,

this one is really a cut'n'paste but it introduces a problem with 
qemu-alpha, I don't know how/why:

  $ sudo unshare --ipc --uts --pid --fork --kill-child --mount chroot 
chroot/alpha/sid/
  Unsupported ioctl: cmd=0x80047476

And then it hangs.

I'll try to debug.

Thanks,
Laurent

On 18/01/2019 22:31, Richard Henderson wrote:
> Signed-off-by: Richard Henderson <address@hidden>
> ---
>  linux-user/syscall-defs.h      |   1 +
>  linux-user/syscall-ioctl.inc.c | 873 +++++++++++++++++++++++++++++++++
>  linux-user/syscall.c           | 843 +------------------------------
>  linux-user/strace.list         |   3 -
>  4 files changed, 875 insertions(+), 845 deletions(-)
>  create mode 100644 linux-user/syscall-ioctl.inc.c
> 
> diff --git a/linux-user/syscall-defs.h b/linux-user/syscall-defs.h
> index f8f280f376..f58b9745a4 100644
> --- a/linux-user/syscall-defs.h
> +++ b/linux-user/syscall-defs.h
> @@ -61,6 +61,7 @@ SYSCALL_DEF(getppid);
>  #ifdef TARGET_NR_getxpid
>  SYSCALL_DEF(getxpid);
>  #endif
> +SYSCALL_DEF(ioctl, ARG_DEC, ARG_HEX);
>  #ifdef TARGET_NR_ipc
>  SYSCALL_DEF_ARGS(ipc, ARG_HEX, ARG_DEC, ARG_DEC, ARG_HEX, ARG_PTR, ARG_HEX);
>  #endif
> diff --git a/linux-user/syscall-ioctl.inc.c b/linux-user/syscall-ioctl.inc.c
> new file mode 100644
> index 0000000000..820994105f
> --- /dev/null
> +++ b/linux-user/syscall-ioctl.inc.c
> @@ -0,0 +1,873 @@
> +/*
> + *  Linux ioctl syscall implementation
> + *  Copyright (c) 2003 Fabrice Bellard
> + *
> + *  This program is free software; you can redistribute it and/or modify
> + *  it under the terms of the GNU General Public License as published by
> + *  the Free Software Foundation; either version 2 of the License, or
> + *  (at your option) any later version.
> + *
> + *  This program is distributed in the hope that it will be useful,
> + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
> + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + *  GNU General Public License for more details.
> + *
> + *  You should have received a copy of the GNU General Public License
> + *  along with this program; if not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +typedef struct IOCTLEntry IOCTLEntry;
> +
> +typedef abi_long do_ioctl_fn(const IOCTLEntry *ie, uint8_t *buf_temp,
> +                             int fd, int cmd, abi_long arg);
> +
> +struct IOCTLEntry {
> +    int target_cmd;
> +    unsigned int host_cmd;
> +    const char *name;
> +    int access;
> +    do_ioctl_fn *do_ioctl;
> +    const argtype arg_type[5];
> +};
> +
> +#define IOC_R 0x0001
> +#define IOC_W 0x0002
> +#define IOC_RW (IOC_R | IOC_W)
> +
> +#define MAX_STRUCT_SIZE 4096
> +
> +#ifdef CONFIG_FIEMAP
> +/*
> + * So fiemap access checks don't overflow on 32 bit systems.
> + * This is very slightly smaller than the limit imposed by
> + * the underlying kernel.
> + */
> +#define FIEMAP_MAX_EXTENTS ((UINT_MAX - sizeof(struct fiemap))  \
> +                            / sizeof(struct fiemap_extent))
> +
> +static abi_long do_ioctl_fs_ioc_fiemap(const IOCTLEntry *ie, uint8_t 
> *buf_temp,
> +                                       int fd, int cmd, abi_long arg)
> +{
> +    /*
> +     * The parameter for this ioctl is a struct fiemap followed
> +     * by an array of struct fiemap_extent whose size is set
> +     * in fiemap->fm_extent_count. The array is filled in by the
> +     * ioctl.
> +     */
> +    int target_size_in, target_size_out;
> +    struct fiemap *fm;
> +    const argtype *arg_type = ie->arg_type;
> +    const argtype extent_arg_type[] = { MK_STRUCT(STRUCT_fiemap_extent) };
> +    void *argptr, *p;
> +    abi_long ret;
> +    int i, extent_size = thunk_type_size(extent_arg_type, 0);
> +    uint32_t outbufsz;
> +    int free_fm = 0;
> +
> +    assert(arg_type[0] == TYPE_PTR);
> +    assert(ie->access == IOC_RW);
> +    arg_type++;
> +    target_size_in = thunk_type_size(arg_type, 0);
> +    argptr = lock_user(VERIFY_READ, arg, target_size_in, 1);
> +    if (!argptr) {
> +        return -TARGET_EFAULT;
> +    }
> +    thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
> +    unlock_user(argptr, arg, 0);
> +    fm = (struct fiemap *)buf_temp;
> +    if (fm->fm_extent_count > FIEMAP_MAX_EXTENTS) {
> +        return -TARGET_EINVAL;
> +    }
> +
> +    outbufsz = sizeof(*fm) + sizeof(struct fiemap_extent) * 
> fm->fm_extent_count;
> +
> +    if (outbufsz > MAX_STRUCT_SIZE) {
> +        /*
> +         * We can't fit all the extents into the fixed size buffer.
> +         * Allocate one that is large enough and use it instead.
> +         */
> +        fm = g_try_malloc(outbufsz);
> +        if (!fm) {
> +            return -TARGET_ENOMEM;
> +        }
> +        memcpy(fm, buf_temp, sizeof(struct fiemap));
> +        free_fm = 1;
> +    }
> +    ret = get_errno(safe_ioctl(fd, ie->host_cmd, fm));
> +    if (!is_error(ret)) {
> +        target_size_out = target_size_in;
> +        /*
> +         * An extent_count of 0 means we were only counting the extents
> +         * so there are no structs to copy
> +         */
> +        if (fm->fm_extent_count != 0) {
> +            target_size_out += fm->fm_mapped_extents * extent_size;
> +        }
> +        argptr = lock_user(VERIFY_WRITE, arg, target_size_out, 0);
> +        if (!argptr) {
> +            ret = -TARGET_EFAULT;
> +        } else {
> +            /* Convert the struct fiemap */
> +            thunk_convert(argptr, fm, arg_type, THUNK_TARGET);
> +            if (fm->fm_extent_count != 0) {
> +                p = argptr + target_size_in;
> +                /* ...and then all the struct fiemap_extents */
> +                for (i = 0; i < fm->fm_mapped_extents; i++) {
> +                    thunk_convert(p, &fm->fm_extents[i], extent_arg_type,
> +                                  THUNK_TARGET);
> +                    p += extent_size;
> +                }
> +            }
> +            unlock_user(argptr, arg, target_size_out);
> +        }
> +    }
> +    if (free_fm) {
> +        g_free(fm);
> +    }
> +    return ret;
> +}
> +#endif
> +
> +static abi_long do_ioctl_ifconf(const IOCTLEntry *ie, uint8_t *buf_temp,
> +                                int fd, int cmd, abi_long arg)
> +{
> +    const argtype *arg_type = ie->arg_type;
> +    int target_size;
> +    void *argptr;
> +    int ret;
> +    struct ifconf *host_ifconf;
> +    uint32_t outbufsz;
> +    const argtype ifreq_arg_type[] = { MK_STRUCT(STRUCT_sockaddr_ifreq) };
> +    int target_ifreq_size;
> +    int nb_ifreq;
> +    int free_buf = 0;
> +    int i;
> +    int target_ifc_len;
> +    abi_long target_ifc_buf;
> +    int host_ifc_len;
> +    char *host_ifc_buf;
> +
> +    assert(arg_type[0] == TYPE_PTR);
> +    assert(ie->access == IOC_RW);
> +
> +    arg_type++;
> +    target_size = thunk_type_size(arg_type, 0);
> +
> +    argptr = lock_user(VERIFY_READ, arg, target_size, 1);
> +    if (!argptr) {
> +        return -TARGET_EFAULT;
> +    }
> +    thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
> +    unlock_user(argptr, arg, 0);
> +
> +    host_ifconf = (struct ifconf *)(unsigned long)buf_temp;
> +    target_ifc_len = host_ifconf->ifc_len;
> +    target_ifc_buf = (abi_long)(unsigned long)host_ifconf->ifc_buf;
> +
> +    target_ifreq_size = thunk_type_size(ifreq_arg_type, 0);
> +    nb_ifreq = target_ifc_len / target_ifreq_size;
> +    host_ifc_len = nb_ifreq * sizeof(struct ifreq);
> +
> +    outbufsz = sizeof(*host_ifconf) + host_ifc_len;
> +    if (outbufsz > MAX_STRUCT_SIZE) {
> +        /*
> +         * We can't fit all the extents into the fixed size buffer.
> +         * Allocate one that is large enough and use it instead.
> +         */
> +        host_ifconf = malloc(outbufsz);
> +        if (!host_ifconf) {
> +            return -TARGET_ENOMEM;
> +        }
> +        memcpy(host_ifconf, buf_temp, sizeof(*host_ifconf));
> +        free_buf = 1;
> +    }
> +    host_ifc_buf = (char *)host_ifconf + sizeof(*host_ifconf);
> +
> +    host_ifconf->ifc_len = host_ifc_len;
> +    host_ifconf->ifc_buf = host_ifc_buf;
> +
> +    ret = get_errno(safe_ioctl(fd, ie->host_cmd, host_ifconf));
> +    if (!is_error(ret)) {
> +        /* convert host ifc_len to target ifc_len */
> +
> +        nb_ifreq = host_ifconf->ifc_len / sizeof(struct ifreq);
> +        target_ifc_len = nb_ifreq * target_ifreq_size;
> +        host_ifconf->ifc_len = target_ifc_len;
> +
> +        /* restore target ifc_buf */
> +
> +        host_ifconf->ifc_buf = (char *)(unsigned long)target_ifc_buf;
> +
> +        /* copy struct ifconf to target user */
> +
> +        argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
> +        if (!argptr) {
> +            return -TARGET_EFAULT;
> +        }
> +        thunk_convert(argptr, host_ifconf, arg_type, THUNK_TARGET);
> +        unlock_user(argptr, arg, target_size);
> +
> +        /* copy ifreq[] to target user */
> +
> +        argptr = lock_user(VERIFY_WRITE, target_ifc_buf, target_ifc_len, 0);
> +        for (i = 0; i < nb_ifreq ; i++) {
> +            thunk_convert(argptr + i * target_ifreq_size,
> +                          host_ifc_buf + i * sizeof(struct ifreq),
> +                          ifreq_arg_type, THUNK_TARGET);
> +        }
> +        unlock_user(argptr, target_ifc_buf, target_ifc_len);
> +    }
> +
> +    if (free_buf) {
> +        free(host_ifconf);
> +    }
> +
> +    return ret;
> +}
> +
> +#if defined(CONFIG_USBFS)
> +#if HOST_LONG_BITS > 64
> +#error USBDEVFS thunks do not support >64 bit hosts yet.
> +#endif
> +struct live_urb {
> +    uint64_t target_urb_adr;
> +    uint64_t target_buf_adr;
> +    char *target_buf_ptr;
> +    struct usbdevfs_urb host_urb;
> +};
> +
> +static GHashTable *usbdevfs_urb_hashtable(void)
> +{
> +    static GHashTable *urb_hashtable;
> +
> +    if (!urb_hashtable) {
> +        urb_hashtable = g_hash_table_new(g_int64_hash, g_int64_equal);
> +    }
> +    return urb_hashtable;
> +}
> +
> +static void urb_hashtable_insert(struct live_urb *urb)
> +{
> +    GHashTable *urb_hashtable = usbdevfs_urb_hashtable();
> +    g_hash_table_insert(urb_hashtable, urb, urb);
> +}
> +
> +static struct live_urb *urb_hashtable_lookup(uint64_t target_urb_adr)
> +{
> +    GHashTable *urb_hashtable = usbdevfs_urb_hashtable();
> +    return g_hash_table_lookup(urb_hashtable, &target_urb_adr);
> +}
> +
> +static void urb_hashtable_remove(struct live_urb *urb)
> +{
> +    GHashTable *urb_hashtable = usbdevfs_urb_hashtable();
> +    g_hash_table_remove(urb_hashtable, urb);
> +}
> +
> +static abi_long
> +do_ioctl_usbdevfs_reapurb(const IOCTLEntry *ie, uint8_t *buf_temp,
> +                          int fd, int cmd, abi_long arg)
> +{
> +    const argtype usbfsurb_arg_type[] = { MK_STRUCT(STRUCT_usbdevfs_urb) };
> +    const argtype ptrvoid_arg_type[] = { TYPE_PTRVOID, 0, 0 };
> +    struct live_urb *lurb;
> +    void *argptr;
> +    uint64_t hurb;
> +    int target_size;
> +    uintptr_t target_urb_adr;
> +    abi_long ret;
> +
> +    target_size = thunk_type_size(usbfsurb_arg_type, THUNK_TARGET);
> +
> +    memset(buf_temp, 0, sizeof(uint64_t));
> +    ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
> +    if (is_error(ret)) {
> +        return ret;
> +    }
> +
> +    memcpy(&hurb, buf_temp, sizeof(uint64_t));
> +    lurb = (void *)((uintptr_t)hurb - offsetof(struct live_urb, host_urb));
> +    if (!lurb->target_urb_adr) {
> +        return -TARGET_EFAULT;
> +    }
> +    urb_hashtable_remove(lurb);
> +    unlock_user(lurb->target_buf_ptr, lurb->target_buf_adr,
> +                lurb->host_urb.buffer_length);
> +    lurb->target_buf_ptr = NULL;
> +
> +    /* restore the guest buffer pointer */
> +    lurb->host_urb.buffer = (void *)(uintptr_t)lurb->target_buf_adr;
> +
> +    /* update the guest urb struct */
> +    argptr = lock_user(VERIFY_WRITE, lurb->target_urb_adr, target_size, 0);
> +    if (!argptr) {
> +        g_free(lurb);
> +        return -TARGET_EFAULT;
> +    }
> +    thunk_convert(argptr, &lurb->host_urb, usbfsurb_arg_type, THUNK_TARGET);
> +    unlock_user(argptr, lurb->target_urb_adr, target_size);
> +
> +    target_size = thunk_type_size(ptrvoid_arg_type, THUNK_TARGET);
> +    /* write back the urb handle */
> +    argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
> +    if (!argptr) {
> +        g_free(lurb);
> +        return -TARGET_EFAULT;
> +    }
> +
> +    /* GHashTable uses 64-bit keys but thunk_convert expects uintptr_t */
> +    target_urb_adr = lurb->target_urb_adr;
> +    thunk_convert(argptr, &target_urb_adr, ptrvoid_arg_type, THUNK_TARGET);
> +    unlock_user(argptr, arg, target_size);
> +
> +    g_free(lurb);
> +    return ret;
> +}
> +
> +static abi_long
> +do_ioctl_usbdevfs_discardurb(const IOCTLEntry *ie,
> +                             uint8_t *buf_temp __attribute__((unused)),
> +                             int fd, int cmd, abi_long arg)
> +{
> +    struct live_urb *lurb;
> +
> +    /* map target address back to host URB with metadata. */
> +    lurb = urb_hashtable_lookup(arg);
> +    if (!lurb) {
> +        return -TARGET_EFAULT;
> +    }
> +    return get_errno(safe_ioctl(fd, ie->host_cmd, &lurb->host_urb));
> +}
> +
> +static abi_long
> +do_ioctl_usbdevfs_submiturb(const IOCTLEntry *ie, uint8_t *buf_temp,
> +                            int fd, int cmd, abi_long arg)
> +{
> +    const argtype *arg_type = ie->arg_type;
> +    int target_size;
> +    abi_long ret;
> +    void *argptr;
> +    int rw_dir;
> +    struct live_urb *lurb;
> +
> +    /*
> +     * each submitted URB needs to map to a unique ID for the
> +     * kernel, and that unique ID needs to be a pointer to
> +     * host memory.  hence, we need to malloc for each URB.
> +     * isochronous transfers have a variable length struct.
> +     */
> +    arg_type++;
> +    target_size = thunk_type_size(arg_type, THUNK_TARGET);
> +
> +    /* construct host copy of urb and metadata */
> +    lurb = g_try_malloc0(sizeof(struct live_urb));
> +    if (!lurb) {
> +        return -TARGET_ENOMEM;
> +    }
> +
> +    argptr = lock_user(VERIFY_READ, arg, target_size, 1);
> +    if (!argptr) {
> +        g_free(lurb);
> +        return -TARGET_EFAULT;
> +    }
> +    thunk_convert(&lurb->host_urb, argptr, arg_type, THUNK_HOST);
> +    unlock_user(argptr, arg, 0);
> +
> +    lurb->target_urb_adr = arg;
> +    lurb->target_buf_adr = (uintptr_t)lurb->host_urb.buffer;
> +
> +    /* buffer space used depends on endpoint type so lock the entire buffer 
> */
> +    /* control type urbs should check the buffer contents for true direction 
> */
> +    rw_dir = lurb->host_urb.endpoint & USB_DIR_IN ? VERIFY_WRITE : 
> VERIFY_READ;
> +    lurb->target_buf_ptr = lock_user(rw_dir, lurb->target_buf_adr,
> +                                     lurb->host_urb.buffer_length, 1);
> +    if (lurb->target_buf_ptr == NULL) {
> +        g_free(lurb);
> +        return -TARGET_EFAULT;
> +    }
> +
> +    /* update buffer pointer in host copy */
> +    lurb->host_urb.buffer = lurb->target_buf_ptr;
> +
> +    ret = get_errno(safe_ioctl(fd, ie->host_cmd, &lurb->host_urb));
> +    if (is_error(ret)) {
> +        unlock_user(lurb->target_buf_ptr, lurb->target_buf_adr, 0);
> +        g_free(lurb);
> +    } else {
> +        urb_hashtable_insert(lurb);
> +    }
> +
> +    return ret;
> +}
> +#endif /* CONFIG_USBFS */
> +
> +static abi_long do_ioctl_dm(const IOCTLEntry *ie, uint8_t *buf_temp, int fd,
> +                            int cmd, abi_long arg)
> +{
> +    void *argptr;
> +    struct dm_ioctl *host_dm;
> +    abi_long guest_data;
> +    uint32_t guest_data_size;
> +    int target_size;
> +    const argtype *arg_type = ie->arg_type;
> +    abi_long ret;
> +    void *big_buf = NULL;
> +    char *host_data;
> +
> +    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);
> +
> +    /* buf_temp is too small, so fetch things into a bigger buffer */
> +    big_buf = g_malloc0(((struct dm_ioctl *)buf_temp)->data_size * 2);
> +    memcpy(big_buf, buf_temp, target_size);
> +    buf_temp = big_buf;
> +    host_dm = big_buf;
> +
> +    guest_data = arg + host_dm->data_start;
> +    if ((guest_data - arg) < 0) {
> +        ret = -TARGET_EINVAL;
> +        goto out;
> +    }
> +    guest_data_size = host_dm->data_size - host_dm->data_start;
> +    host_data = (char *)host_dm + host_dm->data_start;
> +
> +    argptr = lock_user(VERIFY_READ, guest_data, guest_data_size, 1);
> +    if (!argptr) {
> +        ret = -TARGET_EFAULT;
> +        goto out;
> +    }
> +
> +    switch (ie->host_cmd) {
> +    case DM_REMOVE_ALL:
> +    case DM_LIST_DEVICES:
> +    case DM_DEV_CREATE:
> +    case DM_DEV_REMOVE:
> +    case DM_DEV_SUSPEND:
> +    case DM_DEV_STATUS:
> +    case DM_DEV_WAIT:
> +    case DM_TABLE_STATUS:
> +    case DM_TABLE_CLEAR:
> +    case DM_TABLE_DEPS:
> +    case DM_LIST_VERSIONS:
> +        /* no input data */
> +        break;
> +    case DM_DEV_RENAME:
> +    case DM_DEV_SET_GEOMETRY:
> +        /* data contains only strings */
> +        memcpy(host_data, argptr, guest_data_size);
> +        break;
> +    case DM_TARGET_MSG:
> +        memcpy(host_data, argptr, guest_data_size);
> +        *(uint64_t *)host_data = tswap64(*(uint64_t *)argptr);
> +        break;
> +    case DM_TABLE_LOAD:
> +    {
> +        void *gspec = argptr;
> +        void *cur_data = host_data;
> +        const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_spec) };
> +        int spec_size = thunk_type_size(arg_type, 0);
> +        int i;
> +
> +        for (i = 0; i < host_dm->target_count; i++) {
> +            struct dm_target_spec *spec = cur_data;
> +            uint32_t next;
> +            int slen;
> +
> +            thunk_convert(spec, gspec, arg_type, THUNK_HOST);
> +            slen = strlen((char *)gspec + spec_size) + 1;
> +            next = spec->next;
> +            spec->next = sizeof(*spec) + slen;
> +            strcpy((char *)&spec[1], gspec + spec_size);
> +            gspec += next;
> +            cur_data += spec->next;
> +        }
> +        break;
> +    }
> +    default:
> +        ret = -TARGET_EINVAL;
> +        unlock_user(argptr, guest_data, 0);
> +        goto out;
> +    }
> +    unlock_user(argptr, guest_data, 0);
> +
> +    ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
> +    if (!is_error(ret)) {
> +        guest_data = arg + host_dm->data_start;
> +        guest_data_size = host_dm->data_size - host_dm->data_start;
> +        argptr = lock_user(VERIFY_WRITE, guest_data, guest_data_size, 0);
> +        switch (ie->host_cmd) {
> +        case DM_REMOVE_ALL:
> +        case DM_DEV_CREATE:
> +        case DM_DEV_REMOVE:
> +        case DM_DEV_RENAME:
> +        case DM_DEV_SUSPEND:
> +        case DM_DEV_STATUS:
> +        case DM_TABLE_LOAD:
> +        case DM_TABLE_CLEAR:
> +        case DM_TARGET_MSG:
> +        case DM_DEV_SET_GEOMETRY:
> +            /* no return data */
> +            break;
> +        case DM_LIST_DEVICES:
> +        {
> +            struct dm_name_list *nl = (void *)host_dm + host_dm->data_start;
> +            uint32_t remaining_data = guest_data_size;
> +            void *cur_data = argptr;
> +            const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_name_list) };
> +            int nl_size = 12; /* can't use thunk_size due to alignment */
> +
> +            while (1) {
> +                uint32_t next = nl->next;
> +                if (next) {
> +                    nl->next = nl_size + (strlen(nl->name) + 1);
> +                }
> +                if (remaining_data < nl->next) {
> +                    host_dm->flags |= DM_BUFFER_FULL_FLAG;
> +                    break;
> +                }
> +                thunk_convert(cur_data, nl, arg_type, THUNK_TARGET);
> +                strcpy(cur_data + nl_size, nl->name);
> +                cur_data += nl->next;
> +                remaining_data -= nl->next;
> +                if (!next) {
> +                    break;
> +                }
> +                nl = (void *)nl + next;
> +            }
> +            break;
> +        }
> +        case DM_DEV_WAIT:
> +        case DM_TABLE_STATUS:
> +        {
> +            struct dm_target_spec *spec
> +                = (void *)host_dm + host_dm->data_start;
> +            void *cur_data = argptr;
> +            const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_spec) };
> +            int spec_size = thunk_type_size(arg_type, 0);
> +            int i;
> +
> +            for (i = 0; i < host_dm->target_count; i++) {
> +                uint32_t next = spec->next;
> +                int slen = strlen((char *)&spec[1]) + 1;
> +                spec->next = (cur_data - argptr) + spec_size + slen;
> +                if (guest_data_size < spec->next) {
> +                    host_dm->flags |= DM_BUFFER_FULL_FLAG;
> +                    break;
> +                }
> +                thunk_convert(cur_data, spec, arg_type, THUNK_TARGET);
> +                strcpy(cur_data + spec_size, (char *)&spec[1]);
> +                cur_data = argptr + spec->next;
> +                spec = (void *)host_dm + host_dm->data_start + next;
> +            }
> +            break;
> +        }
> +        case DM_TABLE_DEPS:
> +        {
> +            void *hdata = (void *)host_dm + host_dm->data_start;
> +            int count = *(uint32_t *)hdata;
> +            uint64_t *hdev = hdata + 8;
> +            uint64_t *gdev = argptr + 8;
> +            int i;
> +
> +            *(uint32_t *)argptr = tswap32(count);
> +            for (i = 0; i < count; i++) {
> +                *gdev = tswap64(*hdev);
> +                gdev++;
> +                hdev++;
> +            }
> +            break;
> +        }
> +        case DM_LIST_VERSIONS:
> +        {
> +            struct dm_target_versions *vers
> +                = (void *)host_dm + host_dm->data_start;
> +            uint32_t remaining_data = guest_data_size;
> +            void *cur_data = argptr;
> +            const argtype arg_type[]
> +                = { MK_STRUCT(STRUCT_dm_target_versions) };
> +            int vers_size = thunk_type_size(arg_type, 0);
> +
> +            while (1) {
> +                uint32_t next = vers->next;
> +                if (next) {
> +                    vers->next = vers_size + strlen(vers->name) + 1;
> +                }
> +                if (remaining_data < vers->next) {
> +                    host_dm->flags |= DM_BUFFER_FULL_FLAG;
> +                    break;
> +                }
> +                thunk_convert(cur_data, vers, arg_type, THUNK_TARGET);
> +                strcpy(cur_data + vers_size, vers->name);
> +                cur_data += vers->next;
> +                remaining_data -= vers->next;
> +                if (!next) {
> +                    break;
> +                }
> +                vers = (void *)vers + next;
> +            }
> +            break;
> +        }
> +        default:
> +            unlock_user(argptr, guest_data, 0);
> +            ret = -TARGET_EINVAL;
> +            goto out;
> +        }
> +        unlock_user(argptr, guest_data, guest_data_size);
> +
> +        argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
> +        if (!argptr) {
> +            ret = -TARGET_EFAULT;
> +            goto out;
> +        }
> +        thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
> +        unlock_user(argptr, arg, target_size);
> +    }
> +out:
> +    g_free(big_buf);
> +    return ret;
> +}
> +
> +static abi_long do_ioctl_blkpg(const IOCTLEntry *ie, uint8_t *buf_temp, int 
> fd,
> +                               int 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(safe_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, int cmd, abi_long arg)
> +{
> +    const argtype *arg_type = ie->arg_type;
> +    const StructEntry *se;
> +    const argtype *field_types;
> +    const int *dst_offsets, *src_offsets;
> +    int target_size;
> +    void *argptr;
> +    abi_ulong *target_rt_dev_ptr;
> +    unsigned long *host_rt_dev_ptr;
> +    abi_long ret;
> +    int i;
> +
> +    assert(ie->access == IOC_W);
> +    assert(*arg_type == TYPE_PTR);
> +    arg_type++;
> +    assert(*arg_type == TYPE_STRUCT);
> +    target_size = thunk_type_size(arg_type, 0);
> +    argptr = lock_user(VERIFY_READ, arg, target_size, 1);
> +    if (!argptr) {
> +        return -TARGET_EFAULT;
> +    }
> +    arg_type++;
> +    assert(*arg_type == (int)STRUCT_rtentry);
> +    se = struct_entries + *arg_type++;
> +    assert(se->convert[0] == NULL);
> +    /* convert struct here to be able to catch rt_dev string */
> +    field_types = se->field_types;
> +    dst_offsets = se->field_offsets[THUNK_HOST];
> +    src_offsets = se->field_offsets[THUNK_TARGET];
> +    for (i = 0; i < se->nb_fields; i++) {
> +        if (dst_offsets[i] == offsetof(struct rtentry, rt_dev)) {
> +            assert(*field_types == TYPE_PTRVOID);
> +            target_rt_dev_ptr = (abi_ulong *)(argptr + src_offsets[i]);
> +            host_rt_dev_ptr = (unsigned long *)(buf_temp + dst_offsets[i]);
> +            if (*target_rt_dev_ptr != 0) {
> +                *host_rt_dev_ptr = (unsigned long)lock_user_string(
> +                    tswapal(*target_rt_dev_ptr));
> +                if (!*host_rt_dev_ptr) {
> +                    unlock_user(argptr, arg, 0);
> +                    return -TARGET_EFAULT;
> +                }
> +            } else {
> +                *host_rt_dev_ptr = 0;
> +            }
> +            field_types++;
> +            continue;
> +        }
> +        field_types = thunk_convert(buf_temp + dst_offsets[i],
> +                                    argptr + src_offsets[i],
> +                                    field_types, THUNK_HOST);
> +    }
> +    unlock_user(argptr, arg, 0);
> +
> +    ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
> +    if (*host_rt_dev_ptr != 0) {
> +        unlock_user((void *)*host_rt_dev_ptr,
> +                    *target_rt_dev_ptr, 0);
> +    }
> +    return ret;
> +}
> +
> +static abi_long do_ioctl_kdsigaccept(const IOCTLEntry *ie, uint8_t *buf_temp,
> +                                     int fd, int cmd, abi_long arg)
> +{
> +    int sig = target_to_host_signal(arg);
> +    return get_errno(safe_ioctl(fd, ie->host_cmd, sig));
> +}
> +
> +#ifdef TIOCGPTPEER
> +static abi_long do_ioctl_tiocgptpeer(const IOCTLEntry *ie, uint8_t *buf_temp,
> +                                     int fd, int cmd, abi_long arg)
> +{
> +    int flags = target_to_host_bitmask(arg, fcntl_flags_tbl);
> +    return get_errno(safe_ioctl(fd, ie->host_cmd, flags));
> +}
> +#endif
> +
> +static IOCTLEntry ioctl_entries[] = {
> +#define IOCTL(cmd, access, ...)                                 \
> +    { TARGET_ ## cmd, cmd, #cmd, access, 0, {  __VA_ARGS__ } },
> +#define IOCTL_SPECIAL(cmd, access, dofn, ...)                           \
> +    { TARGET_ ## cmd, cmd, #cmd, access, dofn, {  __VA_ARGS__ } },
> +#define IOCTL_IGNORE(cmd)                       \
> +    { TARGET_ ## cmd, 0, #cmd },
> +#include "ioctls.h"
> +    { 0, 0, },
> +};
> +
> +/* ??? Implement proper locking for ioctls.  */
> +SYSCALL_IMPL(ioctl)
> +{
> +    int fd = arg1;
> +    abi_ulong cmd = arg2;
> +    abi_ulong arg = arg3;
> +    const IOCTLEntry *ie;
> +    const argtype *arg_type;
> +    abi_long ret;
> +    uint8_t buf_temp[MAX_STRUCT_SIZE];
> +    int target_size;
> +    void *argptr;
> +
> +    for (ie = ioctl_entries; ; ie++) {
> +        if (ie->target_cmd == 0) {
> +            gemu_log("Unsupported ioctl: cmd=0x%04lx\n", (long)cmd);
> +            return -TARGET_ENOSYS;
> +        }
> +        if (ie->target_cmd == cmd) {
> +            break;
> +        }
> +    }
> +
> +    arg_type = ie->arg_type;
> +    if (ie->do_ioctl) {
> +        return ie->do_ioctl(ie, buf_temp, fd, cmd, arg);
> +    } else if (!ie->host_cmd) {
> +        /*
> +         * Some architectures define BSD ioctls in their headers
> +         * that are not implemented in Linux.
> +         */
> +        return -TARGET_ENOSYS;
> +    }
> +
> +    switch (arg_type[0]) {
> +    case TYPE_NULL:
> +        /* no argument */
> +        ret = get_errno(safe_ioctl(fd, ie->host_cmd));
> +        break;
> +    case TYPE_PTRVOID:
> +    case TYPE_INT:
> +        ret = get_errno(safe_ioctl(fd, ie->host_cmd, arg));
> +        break;
> +    case TYPE_PTR:
> +        arg_type++;
> +        target_size = thunk_type_size(arg_type, 0);
> +        switch (ie->access) {
> +        case IOC_R:
> +            ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
> +            if (!is_error(ret)) {
> +                argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
> +                if (!argptr) {
> +                    return -TARGET_EFAULT;
> +                }
> +                thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
> +                unlock_user(argptr, arg, target_size);
> +            }
> +            break;
> +        case IOC_W:
> +            argptr = lock_user(VERIFY_READ, arg, target_size, 1);
> +            if (!argptr) {
> +                return -TARGET_EFAULT;
> +            }
> +            thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
> +            unlock_user(argptr, arg, 0);
> +            ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
> +            break;
> +        default:
> +        case IOC_RW:
> +            argptr = lock_user(VERIFY_READ, arg, target_size, 1);
> +            if (!argptr) {
> +                return -TARGET_EFAULT;
> +            }
> +            thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
> +            unlock_user(argptr, arg, 0);
> +            ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
> +            if (!is_error(ret)) {
> +                argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
> +                if (!argptr) {
> +                    return -TARGET_EFAULT;
> +                }
> +                thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
> +                unlock_user(argptr, arg, target_size);
> +            }
> +            break;
> +        }
> +        break;
> +    default:
> +        gemu_log("Unsupported ioctl type: cmd=0x%04lx type=%d\n",
> +                 (long)cmd, arg_type[0]);
> +        ret = -TARGET_ENOSYS;
> +        break;
> +    }
> +    return ret;
> +}
> diff --git a/linux-user/syscall.c b/linux-user/syscall.c
> index 82b7267b20..03ecf0a15a 100644
> --- a/linux-user/syscall.c
> +++ b/linux-user/syscall.c
> @@ -2935,846 +2935,6 @@ STRUCT_MAX
>  #undef STRUCT
>  #undef STRUCT_SPECIAL
>  
> -typedef struct IOCTLEntry IOCTLEntry;
> -
> -typedef abi_long do_ioctl_fn(const IOCTLEntry *ie, uint8_t *buf_temp,
> -                             int fd, int cmd, abi_long arg);
> -
> -struct IOCTLEntry {
> -    int target_cmd;
> -    unsigned int host_cmd;
> -    const char *name;
> -    int access;
> -    do_ioctl_fn *do_ioctl;
> -    const argtype arg_type[5];
> -};
> -
> -#define IOC_R 0x0001
> -#define IOC_W 0x0002
> -#define IOC_RW (IOC_R | IOC_W)
> -
> -#define MAX_STRUCT_SIZE 4096
> -
> -#ifdef CONFIG_FIEMAP
> -/* So fiemap access checks don't overflow on 32 bit systems.
> - * This is very slightly smaller than the limit imposed by
> - * the underlying kernel.
> - */
> -#define FIEMAP_MAX_EXTENTS ((UINT_MAX - sizeof(struct fiemap))  \
> -                            / sizeof(struct fiemap_extent))
> -
> -static abi_long do_ioctl_fs_ioc_fiemap(const IOCTLEntry *ie, uint8_t 
> *buf_temp,
> -                                       int fd, int cmd, abi_long arg)
> -{
> -    /* The parameter for this ioctl is a struct fiemap followed
> -     * by an array of struct fiemap_extent whose size is set
> -     * in fiemap->fm_extent_count. The array is filled in by the
> -     * ioctl.
> -     */
> -    int target_size_in, target_size_out;
> -    struct fiemap *fm;
> -    const argtype *arg_type = ie->arg_type;
> -    const argtype extent_arg_type[] = { MK_STRUCT(STRUCT_fiemap_extent) };
> -    void *argptr, *p;
> -    abi_long ret;
> -    int i, extent_size = thunk_type_size(extent_arg_type, 0);
> -    uint32_t outbufsz;
> -    int free_fm = 0;
> -
> -    assert(arg_type[0] == TYPE_PTR);
> -    assert(ie->access == IOC_RW);
> -    arg_type++;
> -    target_size_in = thunk_type_size(arg_type, 0);
> -    argptr = lock_user(VERIFY_READ, arg, target_size_in, 1);
> -    if (!argptr) {
> -        return -TARGET_EFAULT;
> -    }
> -    thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
> -    unlock_user(argptr, arg, 0);
> -    fm = (struct fiemap *)buf_temp;
> -    if (fm->fm_extent_count > FIEMAP_MAX_EXTENTS) {
> -        return -TARGET_EINVAL;
> -    }
> -
> -    outbufsz = sizeof (*fm) +
> -        (sizeof(struct fiemap_extent) * fm->fm_extent_count);
> -
> -    if (outbufsz > MAX_STRUCT_SIZE) {
> -        /* We can't fit all the extents into the fixed size buffer.
> -         * Allocate one that is large enough and use it instead.
> -         */
> -        fm = g_try_malloc(outbufsz);
> -        if (!fm) {
> -            return -TARGET_ENOMEM;
> -        }
> -        memcpy(fm, buf_temp, sizeof(struct fiemap));
> -        free_fm = 1;
> -    }
> -    ret = get_errno(safe_ioctl(fd, ie->host_cmd, fm));
> -    if (!is_error(ret)) {
> -        target_size_out = target_size_in;
> -        /* An extent_count of 0 means we were only counting the extents
> -         * so there are no structs to copy
> -         */
> -        if (fm->fm_extent_count != 0) {
> -            target_size_out += fm->fm_mapped_extents * extent_size;
> -        }
> -        argptr = lock_user(VERIFY_WRITE, arg, target_size_out, 0);
> -        if (!argptr) {
> -            ret = -TARGET_EFAULT;
> -        } else {
> -            /* Convert the struct fiemap */
> -            thunk_convert(argptr, fm, arg_type, THUNK_TARGET);
> -            if (fm->fm_extent_count != 0) {
> -                p = argptr + target_size_in;
> -                /* ...and then all the struct fiemap_extents */
> -                for (i = 0; i < fm->fm_mapped_extents; i++) {
> -                    thunk_convert(p, &fm->fm_extents[i], extent_arg_type,
> -                                  THUNK_TARGET);
> -                    p += extent_size;
> -                }
> -            }
> -            unlock_user(argptr, arg, target_size_out);
> -        }
> -    }
> -    if (free_fm) {
> -        g_free(fm);
> -    }
> -    return ret;
> -}
> -#endif
> -
> -static abi_long do_ioctl_ifconf(const IOCTLEntry *ie, uint8_t *buf_temp,
> -                                int fd, int cmd, abi_long arg)
> -{
> -    const argtype *arg_type = ie->arg_type;
> -    int target_size;
> -    void *argptr;
> -    int ret;
> -    struct ifconf *host_ifconf;
> -    uint32_t outbufsz;
> -    const argtype ifreq_arg_type[] = { MK_STRUCT(STRUCT_sockaddr_ifreq) };
> -    int target_ifreq_size;
> -    int nb_ifreq;
> -    int free_buf = 0;
> -    int i;
> -    int target_ifc_len;
> -    abi_long target_ifc_buf;
> -    int host_ifc_len;
> -    char *host_ifc_buf;
> -
> -    assert(arg_type[0] == TYPE_PTR);
> -    assert(ie->access == IOC_RW);
> -
> -    arg_type++;
> -    target_size = thunk_type_size(arg_type, 0);
> -
> -    argptr = lock_user(VERIFY_READ, arg, target_size, 1);
> -    if (!argptr)
> -        return -TARGET_EFAULT;
> -    thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
> -    unlock_user(argptr, arg, 0);
> -
> -    host_ifconf = (struct ifconf *)(unsigned long)buf_temp;
> -    target_ifc_len = host_ifconf->ifc_len;
> -    target_ifc_buf = (abi_long)(unsigned long)host_ifconf->ifc_buf;
> -
> -    target_ifreq_size = thunk_type_size(ifreq_arg_type, 0);
> -    nb_ifreq = target_ifc_len / target_ifreq_size;
> -    host_ifc_len = nb_ifreq * sizeof(struct ifreq);
> -
> -    outbufsz = sizeof(*host_ifconf) + host_ifc_len;
> -    if (outbufsz > MAX_STRUCT_SIZE) {
> -        /* We can't fit all the extents into the fixed size buffer.
> -         * Allocate one that is large enough and use it instead.
> -         */
> -        host_ifconf = malloc(outbufsz);
> -        if (!host_ifconf) {
> -            return -TARGET_ENOMEM;
> -        }
> -        memcpy(host_ifconf, buf_temp, sizeof(*host_ifconf));
> -        free_buf = 1;
> -    }
> -    host_ifc_buf = (char*)host_ifconf + sizeof(*host_ifconf);
> -
> -    host_ifconf->ifc_len = host_ifc_len;
> -    host_ifconf->ifc_buf = host_ifc_buf;
> -
> -    ret = get_errno(safe_ioctl(fd, ie->host_cmd, host_ifconf));
> -    if (!is_error(ret)) {
> -     /* convert host ifc_len to target ifc_len */
> -
> -        nb_ifreq = host_ifconf->ifc_len / sizeof(struct ifreq);
> -        target_ifc_len = nb_ifreq * target_ifreq_size;
> -        host_ifconf->ifc_len = target_ifc_len;
> -
> -     /* restore target ifc_buf */
> -
> -        host_ifconf->ifc_buf = (char *)(unsigned long)target_ifc_buf;
> -
> -     /* copy struct ifconf to target user */
> -
> -        argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
> -        if (!argptr)
> -            return -TARGET_EFAULT;
> -        thunk_convert(argptr, host_ifconf, arg_type, THUNK_TARGET);
> -        unlock_user(argptr, arg, target_size);
> -
> -     /* copy ifreq[] to target user */
> -
> -        argptr = lock_user(VERIFY_WRITE, target_ifc_buf, target_ifc_len, 0);
> -        for (i = 0; i < nb_ifreq ; i++) {
> -            thunk_convert(argptr + i * target_ifreq_size,
> -                          host_ifc_buf + i * sizeof(struct ifreq),
> -                          ifreq_arg_type, THUNK_TARGET);
> -        }
> -        unlock_user(argptr, target_ifc_buf, target_ifc_len);
> -    }
> -
> -    if (free_buf) {
> -        free(host_ifconf);
> -    }
> -
> -    return ret;
> -}
> -
> -#if defined(CONFIG_USBFS)
> -#if HOST_LONG_BITS > 64
> -#error USBDEVFS thunks do not support >64 bit hosts yet.
> -#endif
> -struct live_urb {
> -    uint64_t target_urb_adr;
> -    uint64_t target_buf_adr;
> -    char *target_buf_ptr;
> -    struct usbdevfs_urb host_urb;
> -};
> -
> -static GHashTable *usbdevfs_urb_hashtable(void)
> -{
> -    static GHashTable *urb_hashtable;
> -
> -    if (!urb_hashtable) {
> -        urb_hashtable = g_hash_table_new(g_int64_hash, g_int64_equal);
> -    }
> -    return urb_hashtable;
> -}
> -
> -static void urb_hashtable_insert(struct live_urb *urb)
> -{
> -    GHashTable *urb_hashtable = usbdevfs_urb_hashtable();
> -    g_hash_table_insert(urb_hashtable, urb, urb);
> -}
> -
> -static struct live_urb *urb_hashtable_lookup(uint64_t target_urb_adr)
> -{
> -    GHashTable *urb_hashtable = usbdevfs_urb_hashtable();
> -    return g_hash_table_lookup(urb_hashtable, &target_urb_adr);
> -}
> -
> -static void urb_hashtable_remove(struct live_urb *urb)
> -{
> -    GHashTable *urb_hashtable = usbdevfs_urb_hashtable();
> -    g_hash_table_remove(urb_hashtable, urb);
> -}
> -
> -static abi_long
> -do_ioctl_usbdevfs_reapurb(const IOCTLEntry *ie, uint8_t *buf_temp,
> -                          int fd, int cmd, abi_long arg)
> -{
> -    const argtype usbfsurb_arg_type[] = { MK_STRUCT(STRUCT_usbdevfs_urb) };
> -    const argtype ptrvoid_arg_type[] = { TYPE_PTRVOID, 0, 0 };
> -    struct live_urb *lurb;
> -    void *argptr;
> -    uint64_t hurb;
> -    int target_size;
> -    uintptr_t target_urb_adr;
> -    abi_long ret;
> -
> -    target_size = thunk_type_size(usbfsurb_arg_type, THUNK_TARGET);
> -
> -    memset(buf_temp, 0, sizeof(uint64_t));
> -    ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
> -    if (is_error(ret)) {
> -        return ret;
> -    }
> -
> -    memcpy(&hurb, buf_temp, sizeof(uint64_t));
> -    lurb = (void *)((uintptr_t)hurb - offsetof(struct live_urb, host_urb));
> -    if (!lurb->target_urb_adr) {
> -        return -TARGET_EFAULT;
> -    }
> -    urb_hashtable_remove(lurb);
> -    unlock_user(lurb->target_buf_ptr, lurb->target_buf_adr,
> -        lurb->host_urb.buffer_length);
> -    lurb->target_buf_ptr = NULL;
> -
> -    /* restore the guest buffer pointer */
> -    lurb->host_urb.buffer = (void *)(uintptr_t)lurb->target_buf_adr;
> -
> -    /* update the guest urb struct */
> -    argptr = lock_user(VERIFY_WRITE, lurb->target_urb_adr, target_size, 0);
> -    if (!argptr) {
> -        g_free(lurb);
> -        return -TARGET_EFAULT;
> -    }
> -    thunk_convert(argptr, &lurb->host_urb, usbfsurb_arg_type, THUNK_TARGET);
> -    unlock_user(argptr, lurb->target_urb_adr, target_size);
> -
> -    target_size = thunk_type_size(ptrvoid_arg_type, THUNK_TARGET);
> -    /* write back the urb handle */
> -    argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
> -    if (!argptr) {
> -        g_free(lurb);
> -        return -TARGET_EFAULT;
> -    }
> -
> -    /* GHashTable uses 64-bit keys but thunk_convert expects uintptr_t */
> -    target_urb_adr = lurb->target_urb_adr;
> -    thunk_convert(argptr, &target_urb_adr, ptrvoid_arg_type, THUNK_TARGET);
> -    unlock_user(argptr, arg, target_size);
> -
> -    g_free(lurb);
> -    return ret;
> -}
> -
> -static abi_long
> -do_ioctl_usbdevfs_discardurb(const IOCTLEntry *ie,
> -                             uint8_t *buf_temp __attribute__((unused)),
> -                             int fd, int cmd, abi_long arg)
> -{
> -    struct live_urb *lurb;
> -
> -    /* map target address back to host URB with metadata. */
> -    lurb = urb_hashtable_lookup(arg);
> -    if (!lurb) {
> -        return -TARGET_EFAULT;
> -    }
> -    return get_errno(safe_ioctl(fd, ie->host_cmd, &lurb->host_urb));
> -}
> -
> -static abi_long
> -do_ioctl_usbdevfs_submiturb(const IOCTLEntry *ie, uint8_t *buf_temp,
> -                            int fd, int cmd, abi_long arg)
> -{
> -    const argtype *arg_type = ie->arg_type;
> -    int target_size;
> -    abi_long ret;
> -    void *argptr;
> -    int rw_dir;
> -    struct live_urb *lurb;
> -
> -    /*
> -     * each submitted URB needs to map to a unique ID for the
> -     * kernel, and that unique ID needs to be a pointer to
> -     * host memory.  hence, we need to malloc for each URB.
> -     * isochronous transfers have a variable length struct.
> -     */
> -    arg_type++;
> -    target_size = thunk_type_size(arg_type, THUNK_TARGET);
> -
> -    /* construct host copy of urb and metadata */
> -    lurb = g_try_malloc0(sizeof(struct live_urb));
> -    if (!lurb) {
> -        return -TARGET_ENOMEM;
> -    }
> -
> -    argptr = lock_user(VERIFY_READ, arg, target_size, 1);
> -    if (!argptr) {
> -        g_free(lurb);
> -        return -TARGET_EFAULT;
> -    }
> -    thunk_convert(&lurb->host_urb, argptr, arg_type, THUNK_HOST);
> -    unlock_user(argptr, arg, 0);
> -
> -    lurb->target_urb_adr = arg;
> -    lurb->target_buf_adr = (uintptr_t)lurb->host_urb.buffer;
> -
> -    /* buffer space used depends on endpoint type so lock the entire buffer 
> */
> -    /* control type urbs should check the buffer contents for true direction 
> */
> -    rw_dir = lurb->host_urb.endpoint & USB_DIR_IN ? VERIFY_WRITE : 
> VERIFY_READ;
> -    lurb->target_buf_ptr = lock_user(rw_dir, lurb->target_buf_adr,
> -        lurb->host_urb.buffer_length, 1);
> -    if (lurb->target_buf_ptr == NULL) {
> -        g_free(lurb);
> -        return -TARGET_EFAULT;
> -    }
> -
> -    /* update buffer pointer in host copy */
> -    lurb->host_urb.buffer = lurb->target_buf_ptr;
> -
> -    ret = get_errno(safe_ioctl(fd, ie->host_cmd, &lurb->host_urb));
> -    if (is_error(ret)) {
> -        unlock_user(lurb->target_buf_ptr, lurb->target_buf_adr, 0);
> -        g_free(lurb);
> -    } else {
> -        urb_hashtable_insert(lurb);
> -    }
> -
> -    return ret;
> -}
> -#endif /* CONFIG_USBFS */
> -
> -static abi_long do_ioctl_dm(const IOCTLEntry *ie, uint8_t *buf_temp, int fd,
> -                            int cmd, abi_long arg)
> -{
> -    void *argptr;
> -    struct dm_ioctl *host_dm;
> -    abi_long guest_data;
> -    uint32_t guest_data_size;
> -    int target_size;
> -    const argtype *arg_type = ie->arg_type;
> -    abi_long ret;
> -    void *big_buf = NULL;
> -    char *host_data;
> -
> -    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);
> -
> -    /* buf_temp is too small, so fetch things into a bigger buffer */
> -    big_buf = g_malloc0(((struct dm_ioctl*)buf_temp)->data_size * 2);
> -    memcpy(big_buf, buf_temp, target_size);
> -    buf_temp = big_buf;
> -    host_dm = big_buf;
> -
> -    guest_data = arg + host_dm->data_start;
> -    if ((guest_data - arg) < 0) {
> -        ret = -TARGET_EINVAL;
> -        goto out;
> -    }
> -    guest_data_size = host_dm->data_size - host_dm->data_start;
> -    host_data = (char*)host_dm + host_dm->data_start;
> -
> -    argptr = lock_user(VERIFY_READ, guest_data, guest_data_size, 1);
> -    if (!argptr) {
> -        ret = -TARGET_EFAULT;
> -        goto out;
> -    }
> -
> -    switch (ie->host_cmd) {
> -    case DM_REMOVE_ALL:
> -    case DM_LIST_DEVICES:
> -    case DM_DEV_CREATE:
> -    case DM_DEV_REMOVE:
> -    case DM_DEV_SUSPEND:
> -    case DM_DEV_STATUS:
> -    case DM_DEV_WAIT:
> -    case DM_TABLE_STATUS:
> -    case DM_TABLE_CLEAR:
> -    case DM_TABLE_DEPS:
> -    case DM_LIST_VERSIONS:
> -        /* no input data */
> -        break;
> -    case DM_DEV_RENAME:
> -    case DM_DEV_SET_GEOMETRY:
> -        /* data contains only strings */
> -        memcpy(host_data, argptr, guest_data_size);
> -        break;
> -    case DM_TARGET_MSG:
> -        memcpy(host_data, argptr, guest_data_size);
> -        *(uint64_t*)host_data = tswap64(*(uint64_t*)argptr);
> -        break;
> -    case DM_TABLE_LOAD:
> -    {
> -        void *gspec = argptr;
> -        void *cur_data = host_data;
> -        const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_spec) };
> -        int spec_size = thunk_type_size(arg_type, 0);
> -        int i;
> -
> -        for (i = 0; i < host_dm->target_count; i++) {
> -            struct dm_target_spec *spec = cur_data;
> -            uint32_t next;
> -            int slen;
> -
> -            thunk_convert(spec, gspec, arg_type, THUNK_HOST);
> -            slen = strlen((char*)gspec + spec_size) + 1;
> -            next = spec->next;
> -            spec->next = sizeof(*spec) + slen;
> -            strcpy((char*)&spec[1], gspec + spec_size);
> -            gspec += next;
> -            cur_data += spec->next;
> -        }
> -        break;
> -    }
> -    default:
> -        ret = -TARGET_EINVAL;
> -        unlock_user(argptr, guest_data, 0);
> -        goto out;
> -    }
> -    unlock_user(argptr, guest_data, 0);
> -
> -    ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
> -    if (!is_error(ret)) {
> -        guest_data = arg + host_dm->data_start;
> -        guest_data_size = host_dm->data_size - host_dm->data_start;
> -        argptr = lock_user(VERIFY_WRITE, guest_data, guest_data_size, 0);
> -        switch (ie->host_cmd) {
> -        case DM_REMOVE_ALL:
> -        case DM_DEV_CREATE:
> -        case DM_DEV_REMOVE:
> -        case DM_DEV_RENAME:
> -        case DM_DEV_SUSPEND:
> -        case DM_DEV_STATUS:
> -        case DM_TABLE_LOAD:
> -        case DM_TABLE_CLEAR:
> -        case DM_TARGET_MSG:
> -        case DM_DEV_SET_GEOMETRY:
> -            /* no return data */
> -            break;
> -        case DM_LIST_DEVICES:
> -        {
> -            struct dm_name_list *nl = (void*)host_dm + host_dm->data_start;
> -            uint32_t remaining_data = guest_data_size;
> -            void *cur_data = argptr;
> -            const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_name_list) };
> -            int nl_size = 12; /* can't use thunk_size due to alignment */
> -
> -            while (1) {
> -                uint32_t next = nl->next;
> -                if (next) {
> -                    nl->next = nl_size + (strlen(nl->name) + 1);
> -                }
> -                if (remaining_data < nl->next) {
> -                    host_dm->flags |= DM_BUFFER_FULL_FLAG;
> -                    break;
> -                }
> -                thunk_convert(cur_data, nl, arg_type, THUNK_TARGET);
> -                strcpy(cur_data + nl_size, nl->name);
> -                cur_data += nl->next;
> -                remaining_data -= nl->next;
> -                if (!next) {
> -                    break;
> -                }
> -                nl = (void*)nl + next;
> -            }
> -            break;
> -        }
> -        case DM_DEV_WAIT:
> -        case DM_TABLE_STATUS:
> -        {
> -            struct dm_target_spec *spec = (void*)host_dm + 
> host_dm->data_start;
> -            void *cur_data = argptr;
> -            const argtype arg_type[] = { MK_STRUCT(STRUCT_dm_target_spec) };
> -            int spec_size = thunk_type_size(arg_type, 0);
> -            int i;
> -
> -            for (i = 0; i < host_dm->target_count; i++) {
> -                uint32_t next = spec->next;
> -                int slen = strlen((char*)&spec[1]) + 1;
> -                spec->next = (cur_data - argptr) + spec_size + slen;
> -                if (guest_data_size < spec->next) {
> -                    host_dm->flags |= DM_BUFFER_FULL_FLAG;
> -                    break;
> -                }
> -                thunk_convert(cur_data, spec, arg_type, THUNK_TARGET);
> -                strcpy(cur_data + spec_size, (char*)&spec[1]);
> -                cur_data = argptr + spec->next;
> -                spec = (void*)host_dm + host_dm->data_start + next;
> -            }
> -            break;
> -        }
> -        case DM_TABLE_DEPS:
> -        {
> -            void *hdata = (void*)host_dm + host_dm->data_start;
> -            int count = *(uint32_t*)hdata;
> -            uint64_t *hdev = hdata + 8;
> -            uint64_t *gdev = argptr + 8;
> -            int i;
> -
> -            *(uint32_t*)argptr = tswap32(count);
> -            for (i = 0; i < count; i++) {
> -                *gdev = tswap64(*hdev);
> -                gdev++;
> -                hdev++;
> -            }
> -            break;
> -        }
> -        case DM_LIST_VERSIONS:
> -        {
> -            struct dm_target_versions *vers = (void*)host_dm + 
> host_dm->data_start;
> -            uint32_t remaining_data = guest_data_size;
> -            void *cur_data = argptr;
> -            const argtype arg_type[] = { 
> MK_STRUCT(STRUCT_dm_target_versions) };
> -            int vers_size = thunk_type_size(arg_type, 0);
> -
> -            while (1) {
> -                uint32_t next = vers->next;
> -                if (next) {
> -                    vers->next = vers_size + (strlen(vers->name) + 1);
> -                }
> -                if (remaining_data < vers->next) {
> -                    host_dm->flags |= DM_BUFFER_FULL_FLAG;
> -                    break;
> -                }
> -                thunk_convert(cur_data, vers, arg_type, THUNK_TARGET);
> -                strcpy(cur_data + vers_size, vers->name);
> -                cur_data += vers->next;
> -                remaining_data -= vers->next;
> -                if (!next) {
> -                    break;
> -                }
> -                vers = (void*)vers + next;
> -            }
> -            break;
> -        }
> -        default:
> -            unlock_user(argptr, guest_data, 0);
> -            ret = -TARGET_EINVAL;
> -            goto out;
> -        }
> -        unlock_user(argptr, guest_data, guest_data_size);
> -
> -        argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
> -        if (!argptr) {
> -            ret = -TARGET_EFAULT;
> -            goto out;
> -        }
> -        thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
> -        unlock_user(argptr, arg, target_size);
> -    }
> -out:
> -    g_free(big_buf);
> -    return ret;
> -}
> -
> -static abi_long do_ioctl_blkpg(const IOCTLEntry *ie, uint8_t *buf_temp, int 
> fd,
> -                               int 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(safe_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, int cmd, abi_long arg)
> -{
> -    const argtype *arg_type = ie->arg_type;
> -    const StructEntry *se;
> -    const argtype *field_types;
> -    const int *dst_offsets, *src_offsets;
> -    int target_size;
> -    void *argptr;
> -    abi_ulong *target_rt_dev_ptr;
> -    unsigned long *host_rt_dev_ptr;
> -    abi_long ret;
> -    int i;
> -
> -    assert(ie->access == IOC_W);
> -    assert(*arg_type == TYPE_PTR);
> -    arg_type++;
> -    assert(*arg_type == TYPE_STRUCT);
> -    target_size = thunk_type_size(arg_type, 0);
> -    argptr = lock_user(VERIFY_READ, arg, target_size, 1);
> -    if (!argptr) {
> -        return -TARGET_EFAULT;
> -    }
> -    arg_type++;
> -    assert(*arg_type == (int)STRUCT_rtentry);
> -    se = struct_entries + *arg_type++;
> -    assert(se->convert[0] == NULL);
> -    /* convert struct here to be able to catch rt_dev string */
> -    field_types = se->field_types;
> -    dst_offsets = se->field_offsets[THUNK_HOST];
> -    src_offsets = se->field_offsets[THUNK_TARGET];
> -    for (i = 0; i < se->nb_fields; i++) {
> -        if (dst_offsets[i] == offsetof(struct rtentry, rt_dev)) {
> -            assert(*field_types == TYPE_PTRVOID);
> -            target_rt_dev_ptr = (abi_ulong *)(argptr + src_offsets[i]);
> -            host_rt_dev_ptr = (unsigned long *)(buf_temp + dst_offsets[i]);
> -            if (*target_rt_dev_ptr != 0) {
> -                *host_rt_dev_ptr = (unsigned long)lock_user_string(
> -                                                  
> tswapal(*target_rt_dev_ptr));
> -                if (!*host_rt_dev_ptr) {
> -                    unlock_user(argptr, arg, 0);
> -                    return -TARGET_EFAULT;
> -                }
> -            } else {
> -                *host_rt_dev_ptr = 0;
> -            }
> -            field_types++;
> -            continue;
> -        }
> -        field_types = thunk_convert(buf_temp + dst_offsets[i],
> -                                    argptr + src_offsets[i],
> -                                    field_types, THUNK_HOST);
> -    }
> -    unlock_user(argptr, arg, 0);
> -
> -    ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
> -    if (*host_rt_dev_ptr != 0) {
> -        unlock_user((void *)*host_rt_dev_ptr,
> -                    *target_rt_dev_ptr, 0);
> -    }
> -    return ret;
> -}
> -
> -static abi_long do_ioctl_kdsigaccept(const IOCTLEntry *ie, uint8_t *buf_temp,
> -                                     int fd, int cmd, abi_long arg)
> -{
> -    int sig = target_to_host_signal(arg);
> -    return get_errno(safe_ioctl(fd, ie->host_cmd, sig));
> -}
> -
> -#ifdef TIOCGPTPEER
> -static abi_long do_ioctl_tiocgptpeer(const IOCTLEntry *ie, uint8_t *buf_temp,
> -                                     int fd, int cmd, abi_long arg)
> -{
> -    int flags = target_to_host_bitmask(arg, fcntl_flags_tbl);
> -    return get_errno(safe_ioctl(fd, ie->host_cmd, flags));
> -}
> -#endif
> -
> -static IOCTLEntry ioctl_entries[] = {
> -#define IOCTL(cmd, access, ...) \
> -    { TARGET_ ## cmd, cmd, #cmd, access, 0, {  __VA_ARGS__ } },
> -#define IOCTL_SPECIAL(cmd, access, dofn, ...)                      \
> -    { TARGET_ ## cmd, cmd, #cmd, access, dofn, {  __VA_ARGS__ } },
> -#define IOCTL_IGNORE(cmd) \
> -    { TARGET_ ## cmd, 0, #cmd },
> -#include "ioctls.h"
> -    { 0, 0, },
> -};
> -
> -/* ??? Implement proper locking for ioctls.  */
> -/* do_ioctl() Must return target values and target errnos. */
> -static abi_long do_ioctl(int fd, int cmd, abi_long arg)
> -{
> -    const IOCTLEntry *ie;
> -    const argtype *arg_type;
> -    abi_long ret;
> -    uint8_t buf_temp[MAX_STRUCT_SIZE];
> -    int target_size;
> -    void *argptr;
> -
> -    ie = ioctl_entries;
> -    for(;;) {
> -        if (ie->target_cmd == 0) {
> -            gemu_log("Unsupported ioctl: cmd=0x%04lx\n", (long)cmd);
> -            return -TARGET_ENOSYS;
> -        }
> -        if (ie->target_cmd == cmd)
> -            break;
> -        ie++;
> -    }
> -    arg_type = ie->arg_type;
> -    if (ie->do_ioctl) {
> -        return ie->do_ioctl(ie, buf_temp, fd, cmd, arg);
> -    } else if (!ie->host_cmd) {
> -        /* Some architectures define BSD ioctls in their headers
> -           that are not implemented in Linux.  */
> -        return -TARGET_ENOSYS;
> -    }
> -
> -    switch(arg_type[0]) {
> -    case TYPE_NULL:
> -        /* no argument */
> -        ret = get_errno(safe_ioctl(fd, ie->host_cmd));
> -        break;
> -    case TYPE_PTRVOID:
> -    case TYPE_INT:
> -        ret = get_errno(safe_ioctl(fd, ie->host_cmd, arg));
> -        break;
> -    case TYPE_PTR:
> -        arg_type++;
> -        target_size = thunk_type_size(arg_type, 0);
> -        switch(ie->access) {
> -        case IOC_R:
> -            ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
> -            if (!is_error(ret)) {
> -                argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
> -                if (!argptr)
> -                    return -TARGET_EFAULT;
> -                thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
> -                unlock_user(argptr, arg, target_size);
> -            }
> -            break;
> -        case IOC_W:
> -            argptr = lock_user(VERIFY_READ, arg, target_size, 1);
> -            if (!argptr)
> -                return -TARGET_EFAULT;
> -            thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
> -            unlock_user(argptr, arg, 0);
> -            ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
> -            break;
> -        default:
> -        case IOC_RW:
> -            argptr = lock_user(VERIFY_READ, arg, target_size, 1);
> -            if (!argptr)
> -                return -TARGET_EFAULT;
> -            thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
> -            unlock_user(argptr, arg, 0);
> -            ret = get_errno(safe_ioctl(fd, ie->host_cmd, buf_temp));
> -            if (!is_error(ret)) {
> -                argptr = lock_user(VERIFY_WRITE, arg, target_size, 0);
> -                if (!argptr)
> -                    return -TARGET_EFAULT;
> -                thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
> -                unlock_user(argptr, arg, target_size);
> -            }
> -            break;
> -        }
> -        break;
> -    default:
> -        gemu_log("Unsupported ioctl type: cmd=0x%04lx type=%d\n",
> -                 (long)cmd, arg_type[0]);
> -        ret = -TARGET_ENOSYS;
> -        break;
> -    }
> -    return ret;
> -}
> -
>  static const bitmask_transtbl iflag_tbl[] = {
>          { TARGET_IGNBRK, TARGET_IGNBRK, IGNBRK, IGNBRK },
>          { TARGET_BRKINT, TARGET_BRKINT, BRKINT, BRKINT },
> @@ -5241,8 +4401,6 @@ static abi_long do_syscall1(void *cpu_env, int num, 
> abi_long arg1,
>      void *p;
>  
>      switch(num) {
> -    case TARGET_NR_ioctl:
> -        return do_ioctl(arg1, arg2, arg3);
>  #ifdef TARGET_NR_fcntl
>      case TARGET_NR_fcntl:
>          return do_fcntl(arg1, arg2, arg3);
> @@ -8811,6 +7969,7 @@ static abi_long do_syscall1(void *cpu_env, int num, 
> abi_long arg1,
>                                  int64_t arg5, int64_t arg6)
>  
>  #include "syscall-file.inc.c"
> +#include "syscall-ioctl.inc.c"
>  #include "syscall-ipc.inc.c"
>  #include "syscall-mem.inc.c"
>  #include "syscall-proc.inc.c"
> diff --git a/linux-user/strace.list b/linux-user/strace.list
> index 9f2f8977b4..15208b5349 100644
> --- a/linux-user/strace.list
> +++ b/linux-user/strace.list
> @@ -365,9 +365,6 @@
>  #ifdef TARGET_NR_io_cancel
>  { TARGET_NR_io_cancel, "io_cancel" , NULL, NULL, NULL },
>  #endif
> -#ifdef TARGET_NR_ioctl
> -{ TARGET_NR_ioctl, "ioctl" , NULL, NULL, NULL },
> -#endif
>  #ifdef TARGET_NR_io_destroy
>  { TARGET_NR_io_destroy, "io_destroy" , NULL, NULL, NULL },
>  #endif
> 




reply via email to

[Prev in Thread] Current Thread [Next in Thread]