[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Qemu-devel] [PATCH v3 3/3] linux-user: Implement special usbfs ioct
From: |
Cortland Setlow Tölva |
Subject: |
Re: [Qemu-devel] [PATCH v3 3/3] linux-user: Implement special usbfs ioctls. |
Date: |
Thu, 18 Oct 2018 19:16:32 -0700 |
On Thu, Oct 18, 2018 at 11:48 AM Laurent Vivier <address@hidden> wrote:
>
> Le 08/10/2018 à 18:35, Cortland Tölva a écrit :
> > Userspace submits a USB Request Buffer to the kernel, optionally
> > discards it, and finally reaps the URB. Thunk buffers from target
> > to host and back.
> >
> > Tested by running an i386 scanner driver on ARMv7 and by running
> > the PowerPC lsusb utility on x86_64. The discardurb ioctl is
> > not exercised in these tests.
> >
> > Signed-off-by: Cortland Tölva <address@hidden>
> > ---
> > There are two alternatives for the strategy of holding lock_user on
> > memory from submit until reap. v3 of this series tries to determine
> > the access permissions for user memory from endpoint direction, but
> > the logic for this is complex. The first alternative is to request
> > write access. If that fails, request read access. If that fails, try
> > to submit the ioctl with no buffer - perhaps the user code filled in
> > fields the kernel will ignore. The second alternative is to read user
> > memory into an allocated buffer, pass it to the kernel, and write back
> > to target memory only if the kernel indicates that writes occurred.
> >
> > Changes from v1:
> > improve pointer cast to int compatibility
> > remove unimplemented types for usb streams
> > struct definitions moved to this patch where possible
> >
> > Changes from v2:
> > organize urb thunk metadata in a struct
> > hold lock_user from submit until discard
> > fixes for 64-bit hosts
> >
> > linux-user/ioctls.h | 8 ++
> > linux-user/syscall.c | 177
> > +++++++++++++++++++++++++++++++++++++++++++++
> > linux-user/syscall_defs.h | 4 +
> > linux-user/syscall_types.h | 20 +++++
> > 4 files changed, 209 insertions(+)
> >
> > diff --git a/linux-user/ioctls.h b/linux-user/ioctls.h
> > index 92f6177f1d..ae8951625f 100644
> ...
> > index 2641260186..9b7ea96cfb 100644
> > --- a/linux-user/syscall.c
> > +++ b/linux-user/syscall.c
> > @@ -96,6 +96,7 @@
> > #include <linux/fb.h>
> > #if defined(CONFIG_USBFS)
> > #include <linux/usbdevice_fs.h>
> > +#include <linux/usb/ch9.h>
> > #endif
> > #include <linux/vt.h>
> > #include <linux/dm-ioctl.h>
> > @@ -4199,6 +4200,182 @@ static abi_long do_ioctl_ifconf(const IOCTLEntry
> > *ie, uint8_t *buf_temp,
> > 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);
g_int64_hash means this GHashTable expects to be given a pointer to an int64_t,
and the int64_t is used as the key.
> > + }
> > + 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);
>
> Here the key of the hashtable seems to be the pointer to the host live_urb.
>
The key is pointed to by urb. It is the first member of the struct,
target_urb_adr.
> > +}
> > +
> > +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);
>
> And here the key is the pointer to the target_urb_adr
>
target_urb_adr is on the stack here, and it contains the key. Both
g_hash_table_lookup
and g_hash_table_insert take a pointer to the key, which is an int64_t
in this code.
> So I think urb_hashtable_insert() should be:
>
> g_hash_table_insert(urb_hashtable, urb->target_urb_adr, urb);
>
> and urb_hashtable_lookup() should be:
>
> return g_hash_table_lookup(urb_hashtable, target_urb_adr);
> ...
> Did I miss something?
My code might have been clearer if urb_hashtable_insert and
urb_hashtable_lookup had the same argument type. However,
I did not want to treat target_urb_adr as the first element in a
struct live_urb until checking that it was tracked in the hashtable.
The thing we are looking up has to be a target-sized pointer, so I
cannot use the g_direct_hash with host-sized pointers as keys.
The next best option was to use int64_t as the key.
>
> Thanks,
> Laurent
Thanks,
Cortland.