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/
_______________________________________________
[email protected]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel