On Mon, 7 May 2007, Oliver Neukum wrote: > Am Samstag, 5. Mai 2007 17:30 schrieb Alan Stern: > > > The bound isn't on the time a device may have data -- it's on the time > > allowed for a transfer to complete. And the upper bound would be imposed > > by the driver. How long is it willing to hold up suspend processing > > because of ongoing I/O? The driver must decide one way or another. > > OK, what do you think of this approach?
Looks basically okay. There are a few issues... > --- a/include/linux/usb.h 2007-05-04 10:50:18.000000000 +0200 > +++ b/include/linux/usb.h 2007-05-07 14:48:09.000000000 +0200 > /** > * struct urb - USB Request Block > * @urb_list: For use by current owner of the URB. > + * @anchor: to anchor URBs to a common mooring Don't you want to add a kerneldoc line for anchor_list too? > @@ -1270,6 +1286,11 @@ extern struct urb *usb_get_urb(struct ur > extern int usb_submit_urb(struct urb *urb, gfp_t mem_flags); > extern int usb_unlink_urb(struct urb *urb); > extern void usb_kill_urb(struct urb *urb); > +extern void usb_kill_associated_urbs(struct usb_anchor *old, struct > usb_anchor *new); usb_kill_anchored_urbs() instead of _associated_ ? > +extern void usb_associate_urb_to_anchor(struct urb *u, struct usb_anchor *a); Perhaps usb_add_urb_to_anchor() ? Or even usb_anchor_urb() -- like usb_unanchor_urb() ? > +extern void usb_unanchor_urb(struct urb *urb); > +extern int usb_wait_anchor_empty_timeout(struct usb_anchor *anchor, int > timeout); > +extern void usb_free_anchored_urbs(struct usb_anchor *anchor); Is this last one really needed? See below... > --- a/drivers/usb/core/urb.c 2007-05-04 10:53:14.000000000 +0200 > +++ b/drivers/usb/core/urb.c 2007-05-07 14:48:12.000000000 +0200 > @@ -11,6 +12,9 @@ > static void urb_destroy(struct kref *kref) > { > struct urb *urb = to_urb(kref); > + unsigned long flags; > + > + usb_unanchor_urb(urb); > kfree(urb); > } The anchor should take a reference to the URB; then urb_destroy() won't need to be changed. > +/** > + * usb_associate_urb_to_anchor - anchors an URB while it is processed > + * @u: pointer to the urb to anchor > + * @a: pointer to the anchor > + * > + * This can be called to have access to URBs which are to be executed > + * without bothering to track them > + */ > + > +void usb_associate_urb_to_anchor(struct urb *u, struct usb_anchor *a) How come you sometimes refer to the URB function argument as "u" and sometimes as "urb"? Ditto for "a" and "anchor"? > +{ > + unsigned long flags; > + > + spin_lock_irqsave(&a->lock, flags); > + list_add_tail(&u->anchor_list, &a->urb_list); > + u->anchor = a; > + spin_unlock_irqrestore(&a->lock, flags); > +} Call usb_get_urb() here. > +void usb_unanchor_urb(struct urb *urb) > +{ > + unsigned long flags; > + struct usb_anchor *anchor; > + > + if (!urb) > + return; > + > + anchor = urb->anchor; > + if (!anchor) > + return; > + > + spin_lock_irqsave(&anchor->lock, flags); > + urb->anchor = NULL; > + list_del(&urb->anchor_list); > + spin_unlock_irqrestore(&anchor->lock, flags); > + if (list_empty(&anchor->urb_list)) > + wake_up(&anchor->wait); > +} And call usb_put_urb() here. > +/** > + * usb_kill_associated_urbs - cancel transfer requests en masse > + * @old: anchor the requests are bound to > + * @new: anchor the request which were canceled shall be bound to, may be > NULL > + * > + * this allows all outstanding URBs to be cancelled and bound to an anchor > + * for later processing > + */ > + > +void usb_kill_associated_urbs(struct usb_anchor *old, struct usb_anchor *new) > +{ > + unsigned long flags; > + struct urb *victim; How come you sometimes refer to URB local variables as "victim", sometimes as "lazarus", and sometimes as "n", but never as "urb"? > + > + spin_lock_irqsave(&old->lock, flags); > + while (!list_empty(&old->urb_list)) { > + victim = list_entry(old->urb_list.prev, struct urb, > anchor_list); > + list_del(&victim->anchor_list); You're better off not removing victim from its old anchor at all; usb_kill_urb() will do that for you during completion handling. And you certainly don't want to call list_del() without also setting victim->anchor to NULL. > + /* we must make sure the URB isn't freed before we kill it*/ > + usb_get_urb(victim); > + spin_unlock_irqrestore(&old->lock, flags); > + usb_kill_urb(victim); > + /* we may transfer only if we killed */ > + if (new && victim->status == -ENOENT) > + list_add(&victim->anchor_list, &new->urb_list); Likewise, don't call list_add() without setting victim->anchor. Better yet, call usb_anchor_urb(). Or better still, don't allow this "new" argument at all. It's not clear why you might need it. It doesn't get used in the model usb-skeleton code, for instance. > + else > + usb_put_urb(victim); Get rid of the "else"; since you always increment the refcount, you must always decrement it. > + spin_lock_irqsave(&old->lock, flags); > + } > + spin_unlock_irqrestore(&old->lock, flags); > +} > + > +int usb_wait_anchor_empty_timeout(struct usb_anchor *anchor, int timeout) > +{ > + int res; > + > + res = wait_event_timeout(anchor->wait, list_empty(&anchor->urb_list), > timeout); Maybe make this an interruptible wait? > + return res; > +} > + > +void usb_free_anchored_urbs(struct usb_anchor *anchor) > +{ > + struct urb *lazarus, *n; > + > + list_for_each_entry_safe(lazarus, n, &anchor->urb_list, urb_list) { > + usb_buffer_free(lazarus->dev, lazarus->transfer_buffer_length, > + lazarus->transfer_buffer, lazarus->transfer_dma); > + list_del(&lazarus->anchor_list); > + usb_free_urb(lazarus); > + } > +} I don't see the point of this routine. For example, usb-skeleton frees the transfer buffer during skel_write_bulk_callback(); you wouldn't want to free it again. In general the fire-and-forget model has to work that way. URBs and their buffers will be freed by the completion handler. Alan Stern ------------------------------------------------------------------------- This SF.net email is sponsored by DB2 Express Download DB2 Express C - the FREE version of DB2 express and take control of your XML. No limits. Just data. Click to get it now. http://sourceforge.net/powerbar/db2/ _______________________________________________ linux-usb-devel@lists.sourceforge.net To unsubscribe, use the last form field at: https://lists.sourceforge.net/lists/listinfo/linux-usb-devel