Commit 48079d84 authored by Matthew Dharm's avatar Matthew Dharm Committed by Greg Kroah-Hartman

[PATCH] USB storage: remove tests against EINPROGRESS

This patch removes tests of urb->status for EINPROGRESS.  As was pointed
out, that's not such a good idea, for a variety of reasons.

In the process, a semaphore became useless.
parent 6888f4e6
...@@ -370,16 +370,20 @@ unsigned int usb_stor_transfer_length(Scsi_Cmnd *srb) ...@@ -370,16 +370,20 @@ unsigned int usb_stor_transfer_length(Scsi_Cmnd *srb)
* as those occurring during device-specific initialization, must be handled * as those occurring during device-specific initialization, must be handled
* by a separate code path.) * by a separate code path.)
* *
* The abort function first sets the machine state, then acquires the lock * The abort function first sets the machine state, then atomically
* on the current_urb before checking if it needs to be aborted. * tests-and-clears the CAN_CANCEL bit in us->flags to see if the current_urb
* needs to be aborted.
* *
* When a function submits the current_urb, it must first grab the * The submit function first verifies that the submission completed without
* current_urb_sem to prevent the abort function from trying to cancel the * errors, and only then sets the CAN_CANCEL bit. This prevents the abort
* URB while the submit call is underway. After a function submits the * function from trying to cancel the URB while the submit call is underway.
* current_urb, it -MUST- test the state to see if we got aborted just before * Next, the submit function must test the state to see if we got aborted
* the submission. If so, it's essential to abort the URB if it's still in * before the submission or before setting the CAN_CANCEL bit. If so, it's
* progress. Either way, the function must then release the lock and wait * essential to abort the URB if it hasn't been cancelled already (i.e.,
* for the URB to finish. * if the CAN_CANCEL bit is still set). Either way, the function must then
* wait for the URB to finish. Note that because the USB_ASYNC_UNLINK flag
* is set, the URB can still be in progress even after a call to
* usb_unlink_urb() returns.
* *
* (It's also permissible, but not necessary, to test the state -before- * (It's also permissible, but not necessary, to test the state -before-
* submitting the URB. Doing so would prevent an unnecessary submission if * submitting the URB. Doing so would prevent an unnecessary submission if
...@@ -389,7 +393,7 @@ unsigned int usb_stor_transfer_length(Scsi_Cmnd *srb) ...@@ -389,7 +393,7 @@ unsigned int usb_stor_transfer_length(Scsi_Cmnd *srb)
* *
* The idea is that (1) once the state is changed to ABORTING, either the * The idea is that (1) once the state is changed to ABORTING, either the
* aborting function or the submitting function is guaranteed to call * aborting function or the submitting function is guaranteed to call
* usb_unlink_urb() for an active URB, and (2) current_urb_sem prevents * usb_unlink_urb() for an active URB, and (2) test_and_clear_bit() prevents
* usb_unlink_urb() from being called more than once or from being called * usb_unlink_urb() from being called more than once or from being called
* during usb_submit_urb(). * during usb_submit_urb().
*/ */
...@@ -424,28 +428,30 @@ static int usb_stor_msg_common(struct us_data *us) ...@@ -424,28 +428,30 @@ static int usb_stor_msg_common(struct us_data *us)
us->current_urb->error_count = 0; us->current_urb->error_count = 0;
us->current_urb->transfer_flags = USB_ASYNC_UNLINK; us->current_urb->transfer_flags = USB_ASYNC_UNLINK;
/* lock and submit the URB */ /* submit the URB */
down(&(us->current_urb_sem));
status = usb_submit_urb(us->current_urb, GFP_NOIO); status = usb_submit_urb(us->current_urb, GFP_NOIO);
if (status) { if (status) {
/* something went wrong */ /* something went wrong */
up(&(us->current_urb_sem));
return status; return status;
} }
/* since the URB has been submitted successfully, it's now okay
* to cancel it */
set_bit(US_FLIDX_CAN_CANCEL, &us->flags);
/* has the current command been aborted? */ /* has the current command been aborted? */
if (atomic_read(&us->sm_state) == US_STATE_ABORTING) { if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
/* cancel the URB, if it hasn't been cancelled already */ /* cancel the URB, if it hasn't been cancelled already */
if (us->current_urb->status == -EINPROGRESS) { if (test_and_clear_bit(US_FLIDX_CAN_CANCEL, &us->flags)) {
US_DEBUGP("-- cancelling URB\n"); US_DEBUGP("-- cancelling URB\n");
usb_unlink_urb(us->current_urb); usb_unlink_urb(us->current_urb);
} }
} }
up(&(us->current_urb_sem));
/* wait for the completion of the URB */ /* wait for the completion of the URB */
wait_for_completion(&urb_done); wait_for_completion(&urb_done);
clear_bit(US_FLIDX_CAN_CANCEL, &us->flags);
/* return the URB status */ /* return the URB status */
return us->current_urb->status; return us->current_urb->status;
...@@ -867,15 +873,13 @@ void usb_stor_abort_transport(struct us_data *us) ...@@ -867,15 +873,13 @@ void usb_stor_abort_transport(struct us_data *us)
/* If the state machine is blocked waiting for an URB or an IRQ, /* If the state machine is blocked waiting for an URB or an IRQ,
* let's wake it up */ * let's wake it up */
/* If we have an URB pending, cancel it. Note that we guarantee with /* If we have an URB pending, cancel it. The test_and_clear_bit()
* the current_urb_sem that if a URB has just been submitted, it * call guarantees that if a URB has just been submitted, it
* won't be cancelled more than once. */ * won't be cancelled more than once. */
down(&(us->current_urb_sem)); if (test_and_clear_bit(US_FLIDX_CAN_CANCEL, &us->flags)) {
if (us->current_urb->status == -EINPROGRESS) {
US_DEBUGP("-- cancelling URB\n"); US_DEBUGP("-- cancelling URB\n");
usb_unlink_urb(us->current_urb); usb_unlink_urb(us->current_urb);
} }
up(&(us->current_urb_sem));
/* If we are waiting for an IRQ, simulate it */ /* If we are waiting for an IRQ, simulate it */
if (test_bit(US_FLIDX_IP_WANTED, &us->flags)) { if (test_bit(US_FLIDX_IP_WANTED, &us->flags)) {
......
...@@ -825,7 +825,6 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum, ...@@ -825,7 +825,6 @@ static void * storage_probe(struct usb_device *dev, unsigned int ifnum,
init_completion(&(ss->notify)); init_completion(&(ss->notify));
init_MUTEX_LOCKED(&(ss->ip_waitq)); init_MUTEX_LOCKED(&(ss->ip_waitq));
init_MUTEX(&(ss->irq_urb_sem)); init_MUTEX(&(ss->irq_urb_sem));
init_MUTEX(&(ss->current_urb_sem));
init_MUTEX_LOCKED(&(ss->dev_semaphore)); init_MUTEX_LOCKED(&(ss->dev_semaphore));
/* copy over the subclass and protocol data */ /* copy over the subclass and protocol data */
......
...@@ -106,6 +106,7 @@ struct us_unusual_dev { ...@@ -106,6 +106,7 @@ struct us_unusual_dev {
#define US_FL_DEV_ATTACHED 0x00010000 /* is the device attached? */ #define US_FL_DEV_ATTACHED 0x00010000 /* is the device attached? */
#define US_FLIDX_IP_WANTED 17 /* 0x00020000 is an IRQ expected? */ #define US_FLIDX_IP_WANTED 17 /* 0x00020000 is an IRQ expected? */
#define US_FLIDX_CAN_CANCEL 18 /* 0x00040000 okay to cancel current_urb? */
/* processing state machine states */ /* processing state machine states */
...@@ -177,7 +178,6 @@ struct us_data { ...@@ -177,7 +178,6 @@ struct us_data {
unsigned char irqdata[2]; /* data from USB IRQ */ unsigned char irqdata[2]; /* data from USB IRQ */
/* control and bulk communications data */ /* control and bulk communications data */
struct semaphore current_urb_sem; /* protect current_urb */
struct urb *current_urb; /* non-int USB requests */ struct urb *current_urb; /* non-int USB requests */
struct usb_ctrlrequest *dr; /* control requests */ struct usb_ctrlrequest *dr; /* control requests */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment