diff options
| author | Greg Kroah-Hartman <gregkh@suse.de> | 2008-08-14 06:58:32 -0700 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@suse.de> | 2008-08-14 06:58:32 -0700 |
| commit | 5241b373252bbdf2e4c69fd6f5b1bb5a40cb85a2 (patch) | |
| tree | d8f317fbebd3470e96b5e9f520cb7595210da583 /usb | |
| parent | eaa5df2a6d6f9b87334b5724bc4eb1eb75fc260e (diff) | |
| download | patches-5241b373252bbdf2e4c69fd6f5b1bb5a40cb85a2.tar.gz | |
2.6.27-rc3-git2 resync
Diffstat (limited to 'usb')
| -rw-r--r-- | usb/drivers-usb-class-usblp.c-adjust-error-handling-code.patch | 88 | ||||
| -rw-r--r-- | usb/ub-remove-sg_stat.patch | 37 | ||||
| -rw-r--r-- | usb/usb-extend-poisoning-to-anchors.patch | 158 | ||||
| -rw-r--r-- | usb/usb-kill-urbs-permanently.patch | 120 |
4 files changed, 403 insertions, 0 deletions
diff --git a/usb/drivers-usb-class-usblp.c-adjust-error-handling-code.patch b/usb/drivers-usb-class-usblp.c-adjust-error-handling-code.patch new file mode 100644 index 00000000000000..8cc18ed4560cea --- /dev/null +++ b/usb/drivers-usb-class-usblp.c-adjust-error-handling-code.patch @@ -0,0 +1,88 @@ +From linux-usb-owner@vger.kernel.org Thu Jul 31 10:35:53 2008 +From: Julia Lawall <julia@diku.dk> +Date: Wed, 16 Jul 2008 18:00:42 +0200 (CEST) +Subject: [PATCH retry] drivers/usb/class/usblp.c: adjust error handling code +To: Oliver Neukum <oliver@neukum.org> +Cc: zaitcev@redhat.com, linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org, kernel-janitors@vger.kernel.org +Message-ID: <Pine.LNX.4.64.0807161758520.28783@ask.diku.dk> + + +From: Julia Lawall <julia@diku.dk> + +In this code, it is possible to tell statically whether usblp will be NULL +in the error handling code. + +Oliver Neukum suggested to make a goto to the final return rather than +return directly. + +The semantic match that finds this problem is as follows: +(http://www.emn.fr/x-info/coccinelle/) + +// <smpl> +@@ +identifier f,err,l,l1; +type T; +expression x,E; +statement S; +@@ + +x = NULL +... when != goto l1; +* x = f(...) +... when != x +err = E; +goto l; +... +* if (x != NULL) + S +return err; +// </smpl> + +Signed-off-by: Julia Lawall <julia@diku.dk> +Cc: Pete Zaitcev <zaitcev@redhat.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/class/usblp.c | 18 +++++++++--------- + 1 file changed, 9 insertions(+), 9 deletions(-) + +--- a/drivers/usb/class/usblp.c ++++ b/drivers/usb/class/usblp.c +@@ -1076,15 +1076,16 @@ static int usblp_probe(struct usb_interf + const struct usb_device_id *id) + { + struct usb_device *dev = interface_to_usbdev (intf); +- struct usblp *usblp = NULL; ++ struct usblp *usblp; + int protocol; + int retval; + + /* Malloc and start initializing usblp structure so we can use it + * directly. */ +- if (!(usblp = kzalloc(sizeof(struct usblp), GFP_KERNEL))) { ++ usblp = kzalloc(sizeof(struct usblp), GFP_KERNEL); ++ if (!usblp) { + retval = -ENOMEM; +- goto abort; ++ goto abort_ret; + } + usblp->dev = dev; + mutex_init(&usblp->wmut); +@@ -1179,12 +1180,11 @@ abort_intfdata: + usb_set_intfdata (intf, NULL); + device_remove_file(&intf->dev, &dev_attr_ieee1284_id); + abort: +- if (usblp) { +- kfree(usblp->readbuf); +- kfree(usblp->statusbuf); +- kfree(usblp->device_id_string); +- kfree(usblp); +- } ++ kfree(usblp->readbuf); ++ kfree(usblp->statusbuf); ++ kfree(usblp->device_id_string); ++ kfree(usblp); ++abort_ret: + return retval; + } + diff --git a/usb/ub-remove-sg_stat.patch b/usb/ub-remove-sg_stat.patch new file mode 100644 index 00000000000000..efd29f107e3e90 --- /dev/null +++ b/usb/ub-remove-sg_stat.patch @@ -0,0 +1,37 @@ +From zaitcev@redhat.com Wed Aug 6 15:15:12 2008 +From: Pete Zaitcev <zaitcev@redhat.com> +Date: Mon, 4 Aug 2008 17:15:40 -0600 +Subject: ub: remove sg_stat +To: greg@kroah.com +Cc: linux-usb@vger.kernel.org +Message-ID: <20080804171540.36698160.zaitcev@redhat.com> + + +Remove forgotten code related to sg_stat[]. + +Signed-off-by: Pete Zaitcev <zaitcev@redhat.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/block/ub.c | 3 --- + 1 file changed, 3 deletions(-) + +--- a/drivers/block/ub.c ++++ b/drivers/block/ub.c +@@ -349,8 +349,6 @@ struct ub_dev { + + struct work_struct reset_work; + wait_queue_head_t reset_wait; +- +- int sg_stat[6]; + }; + + /* +@@ -685,7 +683,6 @@ static int ub_request_fn_1(struct ub_lun + goto drop; + } + urq->nsg = n_elem; +- sc->sg_stat[n_elem < 5 ? n_elem : 5]++; + + if (blk_pc_request(rq)) { + ub_cmd_build_packet(sc, lun, cmd, urq); diff --git a/usb/usb-extend-poisoning-to-anchors.patch b/usb/usb-extend-poisoning-to-anchors.patch new file mode 100644 index 00000000000000..67fa887d000c03 --- /dev/null +++ b/usb/usb-extend-poisoning-to-anchors.patch @@ -0,0 +1,158 @@ +From oliver@neukum.org Thu Jul 31 10:29:55 2008 +From: Oliver Neukum <oliver@neukum.org> +Date: Tue, 29 Jul 2008 16:18:47 +0200 +Subject: USB: extend poisoning to anchors +To: Greg KH <greg@kroah.com> +Cc: Alan Stern <stern@rowland.harvard.edu>, linux-usb@vger.kernel.org +Message-ID: <200807291618.48198.oliver@neukum.org> +Content-Disposition: inline + + +this extends the poisoning concept to anchors. This way poisoning +will work with fire and forget drivers. + +Signed-off-by: Oliver Neukum <oneukum@suse.de> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/core/urb.c | 57 +++++++++++++++++++++++++++++++++++++++++-------- + include/linux/usb.h | 2 + + 2 files changed, 50 insertions(+), 9 deletions(-) + +--- a/drivers/usb/core/urb.c ++++ b/drivers/usb/core/urb.c +@@ -10,6 +10,8 @@ + + #define to_urb(d) container_of(d, struct urb, kref) + ++static DEFINE_SPINLOCK(usb_reject_lock); ++ + static void urb_destroy(struct kref *kref) + { + struct urb *urb = to_urb(kref); +@@ -127,6 +129,13 @@ void usb_anchor_urb(struct urb *urb, str + usb_get_urb(urb); + list_add_tail(&urb->anchor_list, &anchor->urb_list); + urb->anchor = anchor; ++ ++ if (unlikely(anchor->poisoned)) { ++ spin_lock(&usb_reject_lock); ++ urb->reject++; ++ spin_unlock(&usb_reject_lock); ++ } ++ + spin_unlock_irqrestore(&anchor->lock, flags); + } + EXPORT_SYMBOL_GPL(usb_anchor_urb); +@@ -522,7 +531,6 @@ int usb_unlink_urb(struct urb *urb) + } + EXPORT_SYMBOL_GPL(usb_unlink_urb); + +-static DEFINE_MUTEX(usb_reject_mutex); + /** + * usb_kill_urb - cancel a transfer request and wait for it to finish + * @urb: pointer to URB describing a previously submitted request, +@@ -548,16 +556,16 @@ void usb_kill_urb(struct urb *urb) + might_sleep(); + if (!(urb && urb->dev && urb->ep)) + return; +- mutex_lock(&usb_reject_mutex); ++ spin_lock_irq(&usb_reject_lock); + ++urb->reject; +- mutex_unlock(&usb_reject_mutex); ++ spin_unlock_irq(&usb_reject_lock); + + usb_hcd_unlink_urb(urb, -ENOENT); + wait_event(usb_kill_urb_queue, atomic_read(&urb->use_count) == 0); + +- mutex_lock(&usb_reject_mutex); ++ spin_lock_irq(&usb_reject_lock); + --urb->reject; +- mutex_unlock(&usb_reject_mutex); ++ spin_unlock_irq(&usb_reject_lock); + } + EXPORT_SYMBOL_GPL(usb_kill_urb); + +@@ -586,9 +594,9 @@ void usb_poison_urb(struct urb *urb) + might_sleep(); + if (!(urb && urb->dev && urb->ep)) + return; +- mutex_lock(&usb_reject_mutex); ++ spin_lock_irq(&usb_reject_lock); + ++urb->reject; +- mutex_unlock(&usb_reject_mutex); ++ spin_unlock_irq(&usb_reject_lock); + + usb_hcd_unlink_urb(urb, -ENOENT); + wait_event(usb_kill_urb_queue, atomic_read(&urb->use_count) == 0); +@@ -597,12 +605,14 @@ EXPORT_SYMBOL_GPL(usb_poison_urb); + + void usb_unpoison_urb(struct urb *urb) + { ++ unsigned long flags; ++ + if (!urb) + return; + +- mutex_lock(&usb_reject_mutex); ++ spin_lock_irqsave(&usb_reject_lock, flags); + --urb->reject; +- mutex_unlock(&usb_reject_mutex); ++ spin_unlock_irqrestore(&usb_reject_lock, flags); + } + EXPORT_SYMBOL_GPL(usb_unpoison_urb); + +@@ -633,6 +643,35 @@ void usb_kill_anchored_urbs(struct usb_a + } + EXPORT_SYMBOL_GPL(usb_kill_anchored_urbs); + ++ ++/** ++ * usb_poison_anchored_urbs - cease all traffic from an anchor ++ * @anchor: anchor the requests are bound to ++ * ++ * this allows all outstanding URBs to be poisoned starting ++ * from the back of the queue. Newly added URBs will also be ++ * poisoned ++ */ ++void usb_poison_anchored_urbs(struct usb_anchor *anchor) ++{ ++ struct urb *victim; ++ ++ spin_lock_irq(&anchor->lock); ++ anchor->poisoned = 1; ++ while (!list_empty(&anchor->urb_list)) { ++ victim = list_entry(anchor->urb_list.prev, struct urb, ++ anchor_list); ++ /* we must make sure the URB isn't freed before we kill it*/ ++ usb_get_urb(victim); ++ spin_unlock_irq(&anchor->lock); ++ /* this will unanchor the URB */ ++ usb_poison_urb(victim); ++ usb_put_urb(victim); ++ spin_lock_irq(&anchor->lock); ++ } ++ spin_unlock_irq(&anchor->lock); ++} ++EXPORT_SYMBOL_GPL(usb_poison_anchored_urbs); + /** + * usb_unlink_anchored_urbs - asynchronously cancel transfer requests en masse + * @anchor: anchor the requests are bound to +--- a/include/linux/usb.h ++++ b/include/linux/usb.h +@@ -1132,6 +1132,7 @@ struct usb_anchor { + struct list_head urb_list; + wait_queue_head_t wait; + spinlock_t lock; ++ unsigned int poisoned:1; + }; + + static inline void init_usb_anchor(struct usb_anchor *anchor) +@@ -1459,6 +1460,7 @@ extern void usb_kill_urb(struct urb *urb + extern void usb_poison_urb(struct urb *urb); + extern void usb_unpoison_urb(struct urb *urb); + extern void usb_kill_anchored_urbs(struct usb_anchor *anchor); ++extern void usb_poison_anchored_urbs(struct usb_anchor *anchor); + extern void usb_unlink_anchored_urbs(struct usb_anchor *anchor); + extern void usb_anchor_urb(struct urb *urb, struct usb_anchor *anchor); + extern void usb_unanchor_urb(struct urb *urb); diff --git a/usb/usb-kill-urbs-permanently.patch b/usb/usb-kill-urbs-permanently.patch new file mode 100644 index 00000000000000..8d2e152f86710a --- /dev/null +++ b/usb/usb-kill-urbs-permanently.patch @@ -0,0 +1,120 @@ +From oliver@neukum.org Thu Jul 31 10:27:14 2008 +From: Oliver Neukum <oliver@neukum.org> +Date: Tue, 29 Jul 2008 15:26:15 +0200 +Subject: USB: kill URBs permanently +To: Greg KH <greg@kroah.com> +Cc: Alan Stern <stern@rowland.harvard.edu>, linux-usb@vger.kernel.org +Message-ID: <200807291526.16217.oliver@neukum.org> +Content-Disposition: inline + + +looking at usb_kill_urb() it seems to me that it is unnecessarily lenient. +In the use case of disconnect() you never want to use the URB again +(for the same device) But leaving urb->reject elevated will make it easier +to avoid races between read/write and disconnect. + +Signed-off-by: Oliver Neukum <oneukum@suse.de> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + + +--- + drivers/usb/core/urb.c | 56 +++++++++++++++++++++++++++++++++++++++++++------ + include/linux/usb.h | 2 + + 2 files changed, 52 insertions(+), 6 deletions(-) + +--- a/drivers/usb/core/urb.c ++++ b/drivers/usb/core/urb.c +@@ -522,6 +522,7 @@ int usb_unlink_urb(struct urb *urb) + } + EXPORT_SYMBOL_GPL(usb_unlink_urb); + ++static DEFINE_MUTEX(usb_reject_mutex); + /** + * usb_kill_urb - cancel a transfer request and wait for it to finish + * @urb: pointer to URB describing a previously submitted request, +@@ -544,25 +545,68 @@ EXPORT_SYMBOL_GPL(usb_unlink_urb); + */ + void usb_kill_urb(struct urb *urb) + { +- static DEFINE_MUTEX(reject_mutex); +- + might_sleep(); + if (!(urb && urb->dev && urb->ep)) + return; +- mutex_lock(&reject_mutex); ++ mutex_lock(&usb_reject_mutex); + ++urb->reject; +- mutex_unlock(&reject_mutex); ++ mutex_unlock(&usb_reject_mutex); + + usb_hcd_unlink_urb(urb, -ENOENT); + wait_event(usb_kill_urb_queue, atomic_read(&urb->use_count) == 0); + +- mutex_lock(&reject_mutex); ++ mutex_lock(&usb_reject_mutex); + --urb->reject; +- mutex_unlock(&reject_mutex); ++ mutex_unlock(&usb_reject_mutex); + } + EXPORT_SYMBOL_GPL(usb_kill_urb); + + /** ++ * usb_poison_urb - reliably kill a transfer and prevent further use of an URB ++ * @urb: pointer to URB describing a previously submitted request, ++ * may be NULL ++ * ++ * This routine cancels an in-progress request. It is guaranteed that ++ * upon return all completion handlers will have finished and the URB ++ * will be totally idle and cannot be reused. These features make ++ * this an ideal way to stop I/O in a disconnect() callback. ++ * If the request has not already finished or been unlinked ++ * the completion handler will see urb->status == -ENOENT. ++ * ++ * After and while the routine runs, attempts to resubmit the URB will fail ++ * with error -EPERM. Thus even if the URB's completion handler always ++ * tries to resubmit, it will not succeed and the URB will become idle. ++ * ++ * This routine may not be used in an interrupt context (such as a bottom ++ * half or a completion handler), or when holding a spinlock, or in other ++ * situations where the caller can't schedule(). ++ */ ++void usb_poison_urb(struct urb *urb) ++{ ++ might_sleep(); ++ if (!(urb && urb->dev && urb->ep)) ++ return; ++ mutex_lock(&usb_reject_mutex); ++ ++urb->reject; ++ mutex_unlock(&usb_reject_mutex); ++ ++ usb_hcd_unlink_urb(urb, -ENOENT); ++ wait_event(usb_kill_urb_queue, atomic_read(&urb->use_count) == 0); ++} ++EXPORT_SYMBOL_GPL(usb_poison_urb); ++ ++void usb_unpoison_urb(struct urb *urb) ++{ ++ if (!urb) ++ return; ++ ++ mutex_lock(&usb_reject_mutex); ++ --urb->reject; ++ mutex_unlock(&usb_reject_mutex); ++} ++EXPORT_SYMBOL_GPL(usb_unpoison_urb); ++ ++/** + * usb_kill_anchored_urbs - cancel transfer requests en masse + * @anchor: anchor the requests are bound to + * +--- a/include/linux/usb.h ++++ b/include/linux/usb.h +@@ -1456,6 +1456,8 @@ 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_poison_urb(struct urb *urb); ++extern void usb_unpoison_urb(struct urb *urb); + extern void usb_kill_anchored_urbs(struct usb_anchor *anchor); + extern void usb_unlink_anchored_urbs(struct usb_anchor *anchor); + extern void usb_anchor_urb(struct urb *urb, struct usb_anchor *anchor); |
