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

Reply via email to