<div dir="ltr"><div dir="ltr"><br></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Tue, Jan 15, 2019 at 4:52 PM Christophe Fergeau <<a href="mailto:cfergeau@redhat.com">cfergeau@redhat.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">Hey,<br>
<br>
On Mon, Jan 07, 2019 at 03:50:12PM +0200, Yuri Benditovich wrote:<br>
> ><br>
> > > if (!priv->host)<br>
> > > - g_error("Out of memory allocating usbredirhost");<br>
> > > + g_error("Out of memory initializing redirection support");<br>
> > ><br>
> > > -#if USBREDIR_VERSION >= 0x000701<br>
> > > - usbredirhost_set_buffered_output_size_cb(priv->host,<br>
> > usbredir_buffered_output_size_callback);<br>
> > > -#endif<br>
> > > #ifdef USE_LZ4<br>
> > > spice_channel_set_capability(channel,<br>
> > SPICE_SPICEVMC_CAP_DATA_COMPRESS_LZ4);<br>
> > > #endif<br>
> > > @@ -299,8 +279,6 @@ static gboolean spice_usbredir_channel_open_device(<br>
> > > {<br>
> > > SpiceUsbredirChannelPrivate *priv = channel->priv;<br>
> > > SpiceSession *session;<br>
> > > - libusb_device_handle *handle = NULL;<br>
> > > - int rc, status;<br>
> > > SpiceUsbDeviceManager *manager;<br>
> > ><br>
> > > g_return_val_if_fail(priv->state == STATE_DISCONNECTED<br>
> > > @@ -309,21 +287,16 @@ static gboolean spice_usbredir_channel_open_device(<br>
> > > #endif<br>
> > > , FALSE);<br>
> > ><br>
> > > - rc = libusb_open(priv->device, &handle);<br>
> > > - if (rc != 0) {<br>
> > > - g_set_error(err, SPICE_CLIENT_ERROR, SPICE_CLIENT_ERROR_FAILED,<br>
> > > - "Could not open usb device: %s [%i]",<br>
> > > - spice_usbutil_libusb_strerror(rc), rc);<br>
> > > - return FALSE;<br>
> > > - }<br>
> > > -<br>
> > > priv->catch_error = err;<br>
> > > - status = usbredirhost_set_device(priv->host, handle);<br>
> > > - priv->catch_error = NULL;<br>
> > > - if (status != usb_redir_success) {<br>
> > > - g_return_val_if_fail(err == NULL || *err != NULL, FALSE);<br>
> > > + if (!spice_usb_backend_channel_attach(priv->host, priv->device,<br>
> > err)) {<br>
> > > + priv->catch_error = NULL;<br>
> > > + if (*err == NULL) {<br>
> > > + g_set_error(err, SPICE_CLIENT_ERROR,<br>
> > SPICE_CLIENT_ERROR_FAILED,<br>
> > > + "Error attaching device: (no error information)");<br>
> ><br>
> > You could line up the "Error .." with the opening parenthesis.<br>
> ><br>
> ><br>
> This is not described exactly in Spice coding style document and existing<br>
> code of spice-gtk<br>
> uses different solution for indentation, so this is point of personal<br>
> preference.<br>
<br>
>From a quick look, aligning multiple line arguments lists seem much more<br>
common that then opposite. See the g_set_error call that this hunk is<br>
removing for example.<br>
<br>
> > > @@ -362,8 +335,7 @@ static void spice_usbredir_channel_open_acl_cb(<br>
> > > spice_usbredir_channel_open_device(channel, &err);<br>
> > > }<br>
> > > if (err) {<br>
> > > - libusb_unref_device(priv->device);<br>
> > > - priv->device = NULL;<br>
> > > + g_clear_pointer(&priv->device,<br>
> > spice_usb_backend_device_release);<br>
> ><br>
> > _unref rather than _release?<br>
> ><br>
> <br>
> This can be changed in V3, although I would prefer not to change it.<br>
> Semantics of ref/unref and acquire/release are not different.<br>
> Please let me know whether this change in mandatory.<br>
<br>
I assume you mean that the semantics of ref/unref and acquire/release<br>
*are* different? If this is what you mean, how are they different?<br>
If the semantics are the same, then let's use the same name.<br></blockquote><div><br></div><div>No, I mean that this is the same and there is no difference between ref/unref</div><div>and acquire/release; ref/unref is used in glib, so I prefer to use acquire/release.</div><div>I do not have a goal to mimic libusb, I rather prefer to remove any knowledge</div><div>about libusb from all the parts of spice-gtk except of backend code.</div><div>I've asked whether this change is mandatory, i.e. if this leads the rejection of the patch.</div><div>Please respond, preferrably yes or no.</div><div> <br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<br>
> > > @@ -446,7 +420,8 @@ void spice_usbredir_channel_connect_device_async(<br>
> > > goto done;<br>
> > > }<br>
> > ><br>
> > > - priv->device = libusb_ref_device(device);<br>
> > > + spice_usb_backend_device_acquire(device);<br>
> > > + priv->device = device;<br>
> ><br>
> > You could mimic libusb API actually,<br>
> > priv->device = spice_usb_backend_device_ref(device);<br>
> ><br>
> <br>
> I do not think I need to mimic libusb or something other.<br>
> Please let me know whether this change is mandatory.<br>
<br>
libusb_ref_device, g_object_ref all return a pointer to the new ref, and<br>
this makes that code slightly simpler, so just a suggestion in case you<br>
think that's a good change.<br>
<br>
> ><br>
> > > + void *msc;<br>
> > > + } d;<br>
> > > + gboolean is_libusb;<br>
> > > + gint ref_count;<br>
> > > + SpiceUsbBackendChannel *attached_to;<br>
> ><br>
> > You don't need 'msc' just yet, nor 'is_libusb', and I'm not sure about<br>
> > 'attached_to'<br>
> ><br>
> <br>
> msc can be changed to reserved if you do not like it so much.<br>
> removal of is_libusb makes further merges harder (and current commit is<br>
> only prerequisite for further merge).<br>
> attached_to is useful for debugging/support<br>
> Please let me know whether this is a requirement.<br>
<br>
This patch is refactoring the existing code so that we can add more<br>
stuff on top of it. It should not be adding new things, especially if<br>
they are not used in the current commit. attached_to can be added in a<br>
separate commit with the debugging checks that it lets us do, msc can be<br>
added when it's needed.<br>
<br></blockquote><div><br></div><div>Changing the code as you suggest makes further patches more complicated.</div><div>Please let me know whether this is a requirement. </div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
> <br>
> ><br>
> > > + void *hotplug_user_data;<br>
> > > + libusb_hotplug_callback_handle hotplug_handle;<br>
> > > +};<br>
> > > +<br>
> > > +struct _SpiceUsbBackendChannel<br>
> > > +{<br>
> > > + struct usbredirhost *usbredirhost;<br>
> > > + uint8_t *read_buf;<br>
> > > + int read_buf_size;<br>
> > > + struct usbredirfilter_rule *rules;<br>
> > > + int rules_count;<br>
> > > + SpiceUsbBackendDevice *attached;<br>
> ><br>
> > I don't think this is used.<br>
> ><br>
> <br>
> The same as is_libusb.<br>
> In general even now the reference to attached device and attached channel<br>
> are useful for debugging and parsing logs and dumps.<br>
<br>
If it's not used in this commit, then it does not belong in it. Once it<br>
starts being used, then we can add it. Or if it's a debugging feature,<br>
just add it in its own commit with a description of why we want it.<br>
<br>
> ><br>
> > > + SpiceUsbBackendChannelInitData channel_data;<br>
> ><br>
> > I don't think 'channel_data' is a much more descriptive than the<br>
> > previously used 'data'. SpiceUsbBackendChannelInitData is a bunch of<br>
> > vfuncs/callbacks, so maybe use one of these words in the naming?<br>
> ><br>
> <br>
> It can be renamed in V3, please provide the name you agree with.<br>
<br>
backend_vfuncs maybe? Overall, this just feels like something odd we put<br>
in each SpiceUsbBackendChannel instances for lack of a good place in the<br>
design.<br>
<br>
> <br>
> <br>
> ><br>
> > > +};<br>
> > > +<br>
> > > +// it's unclear why we use this procedure instead of libusb_error_name,<br>
> > > +// which by definition supports any error that libusb returns<br>
> ><br>
> > Why not add a commit before this one switching libusb_error_name() then?<br>
> ><br>
> <br>
> Because this looks strange: first change it in 10 places then remove all of<br>
> them in next commit.<br>
> Also because this make the merge very difficult (for me).<br>
<br>
On your cd redirection branch, do a git rebase -i origin/master^ and<br>
say that you want to edit the commit for the current git master. Do the<br>
libusb_error_name() change there, commit it. <br>
git revert HEAD<br>
git rebase --continue<br>
<br>
Then you rebase once more to do squash the revert with this commit, and<br>
you need to edit this commit to make it use libusb_error_name() too.<br>
<br>
> I can remove this note. I can use libusb_error_name instead of this<br>
> procedure.<br>
<br>
If what I described above is complicated, then remove the comment from<br>
this commit, and you can have a followup commit switching to<br>
libusb_error_name().<br>
<br>
> ><br>
> > > +#endif<br>
> > > +#endif<br>
> > > + }<br>
> > > + SPICE_DEBUG("%s <<", __FUNCTION__);<br>
> > > + return be;<br>
> > > +}<br>
> > > +<br>
> > > +gboolean spice_usb_backend_handle_events(SpiceUsbBackend *be)<br>
> > > +{<br>
> > > + SPICE_DEBUG("%s >>", __FUNCTION__);<br>
> > > + gboolean ok = FALSE;<br>
> > > + if (be->libusb_context) {<br>
> > > + SPICE_DEBUG("%s >> libusb", __FUNCTION__);<br>
> > > + int res = libusb_handle_events(be->libusb_context);<br>
> > > + ok = res == 0;<br>
> > > + if (res && res != LIBUSB_ERROR_INTERRUPTED) {<br>
> > > + const char *desc = spice_usbutil_libusb_strerror(res);<br>
> > > + g_warning("Error handling USB events: %s [%i]", desc, res);<br>
> > > + ok = FALSE;<br>
> ><br>
> > You don't really need 'ok' in that method, just return FALSE; here...<br>
> ><br>
> <br>
> Please let me know whether this change is mandatory.<br>
> <br>
> <br>
> ><br>
> > > + }<br>
> > > + }<br>
> > > + SPICE_DEBUG("%s << %s %d", __FUNCTION__,<br>
> > > + be->libusb_context ? "libusb" : "no libusb", ok);<br>
> > > + return ok;<br>
> ><br>
> > ... and return TRUE; there (and I'm not sure how useful the SPICE_DEBUG<br>
> > are going to be?)<br>
> ><br>
> ><br>
> Please let me know whether this change is mandatory.<br>
> Reformatting the code will make further merger more difficult.<br>
<br>
Complaining about merge conflicts related to a 10 line function is not a<br>
very compelling argument against making code simpler/easier to read in a<br>
preliminary patch...<br>
<br></blockquote><div><br></div><div>Please let me know whether this change is mandatory. <br></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
> > > +gboolean spice_usb_backend_handle_hotplug(SpiceUsbBackend *be,<br>
> > > + void *user_data,<br>
> > > + usb_hot_plug_callback proc)<br>
> ><br>
> > Why not<br>
> > spice_usb_backend_enable_hotplug/spice_usb_backend_disable_hotplug?<br>
> > (and now that we have a proper SpiceUsbBackend struct wrapping the<br>
> > libusb stuff, I wonder if it would not make sense to just turn it into a<br>
> > gobject, and emit signals when we get new devices).<br>
> ><br>
> ><br>
> Regarding 'why not to split it to two procedures': this is point of<br>
> personal preference. If the splitting is mandatory, please let me<br>
> know, I'll do that in V3.<br>
<br>
Well, this function is not handling anything, it's setting up a handler<br>
for future hotplug events. So in my opinion, the naming is misleading.<br>
<br>
<br>
> Regarding turning it to GObject - this will discard entire patch and spawn<br>
> completely different activity that requires additional debugging. Is<br>
> this is mandatory, we will need to reevaluate our ability to deliver<br>
> the patches.<br>
<br>
I agree this is a matter that would have been easier to solve<br>
during the initial design/while writing the code.<br>
<br>
<br>
> > > +SpiceUsbBackendDevice<br>
> > **spice_usb_backend_get_device_list(SpiceUsbBackend *be)<br>
> > > +{<br>
> > > + LOUD_DEBUG("%s >>", __FUNCTION__);<br>
> > > + libusb_device **devlist = NULL, **dev;<br>
> > > + SpiceUsbBackendDevice *d, **list;<br>
> > > +<br>
> > > + int n = 0, index;<br>
> > > +<br>
> > > + if (be && be->libusb_context) {<br>
> > > + libusb_get_device_list(be->libusb_context, &devlist);<br>
> > > + }<br>
> > > +<br>
> > > + // add all the libusb device that not present in our list<br>
> > > + for (dev = devlist; dev && *dev; dev++) {<br>
> > > + n++;<br>
> > > + }<br>
> > > +<br>
> > > + list = g_new0(SpiceUsbBackendDevice*, n + 1);<br>
> > > +<br>
> > > + index = 0;<br>
> > > +<br>
> > > + for (dev = devlist; dev && *dev; dev++) {<br>
> > > + d = allocate_backend_device(*dev);<br>
> > > + if (!d) {<br>
> > > + libusb_unref_device(*dev);<br>
> > > + } else {<br>
> > > + SPICE_DEBUG("created dev %p, usblib dev %p", d, *dev);<br>
> > > + list[index++] = d;<br>
> > > + }<br>
> > > + }<br>
> > > +<br>
> > > + if (devlist) {<br>
> > > + libusb_free_device_list(devlist, 0);<br>
> > > + }<br>
> > > +<br>
> > > + LOUD_DEBUG("%s <<", __FUNCTION__);<br>
> > > + return list;<br>
> > > +}<br>
> ><br>
> > I still think this could be made slightly simpler with GArray/GPtrArray.<br>
> ><br>
> <br>
> I do not see any advantage at all, just additional change that makes<br>
> further merges more complicated.<br>
<br>
<br>
This makes the method a bit shorter, and avoids the bookkeeping related<br>
to list length and position in the list:<br>
<br>
SpiceUsbBackendDevice **spice_usb_backend_get_device_list(SpiceUsbBackend *be)<br>
{<br>
LOUD_DEBUG("%s >>", __FUNCTION__);<br>
libusb_device **devlist = NULL;<br>
libusb_device **dev;<br>
GPtrArray *devices = g_ptr_array_new();<br>
<br>
if (be && be->libusb_context) {<br>
libusb_get_device_list(be->libusb_context, &devlist);<br>
}<br>
<br>
for (dev = devlist; dev && *dev; dev++) {<br>
SpiceUsbBackendDevice *d;<br>
d = allocate_backend_device(*dev);<br>
if (!d) {<br>
libusb_unref_device(*dev);<br>
} else {<br>
SPICE_DEBUG("created dev %p, usblib dev %p", d, *dev);<br>
g_ptr_array_add(devices, d);<br>
}<br>
}<br>
g_ptr_array_add(devices, NULL);<br>
<br>
if (devlist) {<br>
libusb_free_device_list(devlist, 0);<br>
}<br>
<br>
LOUD_DEBUG("%s <<", __FUNCTION__);<br>
return (SpiceUsbBackendDevice **)g_ptr_array_free(devices, FALSE);<br>
}<br>
<br>
> > > +SpiceUsbBackendChannel<br>
> > *spice_usb_backend_channel_initialize(SpiceUsbBackend *be,<br>
> > > + const<br>
> > SpiceUsbBackendChannelInitData *init_data)<br>
> > > +{<br>
> > > + SpiceUsbBackendChannel *ch = g_new0(SpiceUsbBackendChannel, 1);<br>
> > > + SPICE_DEBUG("%s >>", __FUNCTION__);<br>
> > > + ch->channel_data = *init_data;<br>
> > > + if (be->libusb_context) {<br>
> ><br>
> > You probably can just have g_return_val_if_fail(be->libusb_context !=<br>
> > NULL, NULL) at the very beginning of that method,<br>
> > and only do the allocation after that.<br>
> ><br>
> <br>
> Please let me know whether this is mandatory.<br>
> I can do that but then later it should be rewritten again.<br>
<br>
As your prefer.<br>
<br>
> > > +typedef struct UsbDeviceInformation<br>
> > > +{<br>
> > > + uint16_t bus;<br>
> > > + uint16_t address;<br>
> > > + uint16_t vid;<br>
> > > + uint16_t pid;<br>
> > > + uint8_t class;<br>
> > > + uint8_t subclass;<br>
> > > + uint8_t protocol;<br>
> > > + uint8_t isochronous;<br>
> > > +} UsbDeviceInformation;<br>
> ><br>
> > As already mentioned in the past, please let's not duplicate very similar<br>
> > information with different names/different types in 2 structures with<br>
> > very close names (UsbDeviceInformation and SpiceUsbDeviceInfo)<br>
> ><br>
> ><br>
> I do not see any possibility to do that in context of current commit.<br>
> This can be done later when SpiceUsbDevice will have persistent link<br>
> to backend device with it's information. For now this information is not<br>
> duplicated, it is cached in SpiceUsbDeviceInfo and can be returned<br>
> without looking for backend device.<br>
> If this is mandatory requirement, please let me know - this discards<br>
> current commit and we will need to reevaluate our plans.<br>
<br>
I think you are explaining why you cannot have a single instance of that<br>
data in memory. I don't really mind if we have multiple instances of<br>
that data in memory, however having 2 different types being used to<br>
store what is essentially the same thing is what I'm objecting to.<br>
How complicated would it be to use the same type each time we need to<br>
store USB information?<br>
<br></blockquote><div><br></div><div>If I would change the name of the structure in usb-device-manager in my initial commit,</div><div>I'd immediately asked NOT to do changes that are not related to current commit.</div><div>Again, I try to make this patch more simple.</div><div>Additional changes (NOT related directly to this patch) IMO can be done later.</div><div>make this patch more complicated.</div><div>Please let me know whether this is mandatory.</div><div> <br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<br>
> > > +<br>
> > > +typedef void (*usb_channel_error_callback)(void *user_data, const char<br>
> > *msg);<br>
> > > +typedef int (*usb_channel_write_callback)(void *user_data, uint8_t<br>
> > *data, int count);<br>
> > > +typedef gboolean (*usb_channel_is_ready_callback)(void *user_data);<br>
> > > +typedef uint64_t (*usb_channel_get_queue_size)(void *user_data);<br>
> > > +<br>
> > > +typedef struct SpiceUsbBackendChannelInitData<br>
> > > +{<br>
> > > + void *user_data;<br>
> > > + usb_channel_error_callback on_error;<br>
> > > + usb_channel_write_callback write_callback;<br>
> > > + usb_channel_is_ready_callback is_channel_ready;<br>
> > > + usb_channel_get_queue_size get_queue_size;<br>
> ><br>
> > I would not add typedef for these vfuncs, I think the types are only<br>
> > used here, so I'd directly use:<br>
> > void *user_data;<br>
> > void (*on_error)(void *user_data, const char *msg);<br>
> > ...<br>
> ><br>
> ><br>
> Please let me know whether this is mandatory.<br>
<br>
Please change it, unless you plan to make extensive use of these types<br>
later on.<br>
<br>
> > > @@ -122,8 +124,7 @@ static ssize_t<br>
> > > g_udev_client_list_devices(GUdevClient *self, GList **devs,<br>
> > > GError **err, const gchar *name)<br>
> > > {<br>
> > > - gssize rc;<br>
> > > - libusb_device **lusb_list, **dev;<br>
> > > + SpiceUsbBackendDevice **lusb_list, **dev;<br>
> > > GUdevClientPrivate *priv;<br>
> > > GUdevDeviceInfo *udevinfo;<br>
> > > GUdevDevice *udevice;<br>
> > > @@ -136,13 +137,8 @@ g_udev_client_list_devices(GUdevClient *self, GList<br>
> > **devs,<br>
> > ><br>
> > > g_return_val_if_fail(self->priv->ctx != NULL, -3);<br>
> > ><br>
> > > - rc = libusb_get_device_list(priv->ctx, &lusb_list);<br>
> > > - if (rc < 0) {<br>
> > > - const char *errstr = spice_usbutil_libusb_strerror(rc);<br>
> > > - g_warning("%s: libusb_get_device_list failed - %s", name,<br>
> > errstr);<br>
> > > - g_set_error(err, G_UDEV_CLIENT_ERROR,<br>
> > G_UDEV_CLIENT_LIBUSB_FAILED,<br>
> > > - "%s: Error getting device list from libusb: %s<br>
> > [%"G_GSSIZE_FORMAT"]",<br>
> > > - name, errstr, rc);<br>
> > > + lusb_list = spice_usb_backend_get_device_list(priv->ctx);<br>
> > > + if (!lusb_list) {<br>
> > > return -4;<br>
> > > }<br>
> ><br>
> > Why did you remove the g_set_error?<br>
> ><br>
> ><br>
> Possible, just because this never happens, empty list it will receive<br>
> anyway.<br>
> I can return it back, if you like it.<br>
<br>
Hmm, should spice_usb_backend_get_device_list() be able to return errors<br>
such as what was done before? I think before we could differentiate<br>
between "empty list of usb devices" and "an error occurred while getting<br>
the list", while now all we know is that we got an empty list. But we<br>
still return -4 on an empty list, which I assume indicates an error?<br>
So why not stop setting the GError?<br>
<br>
> Please respond regarding 2 serious questions:<br>
> - whether there is change in indirection level or wrong use of obtained<br>
> libdev<br>
<br>
I'll answer this in a separate email, I did not have time to consider it<br>
yet.<br>
<br>
> - whether we discard this commit to avoid caching of device properties<br>
> If we do not discard it, please let me know whether specific mentioned<br>
> changes are mandatory.<br>
<br>
and as indicated before, I think there was a misunderstanding on this<br>
one, what I object to is introducing a new type to hold USB device<br>
information, I don't necessarily object to the additional 'caching'.<br>
<br></blockquote><div><br></div><div>New type (public one) is introduced because the usb-device-manager uses</div><div>private data structure to the same, so the backed can't just reuse it.</div><div>Usb-device-manager will be able use this public type, if it will be required at all.</div><div>From my point of view, further simplification of the usb-device-manager will</div><div>remove the need to have any separate data structure.</div><div><br></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
Christophe<br>
</blockquote></div></div>