Interesting. Very interesting.

Well, clearly one thing I can do is try to place locks around everything
to eliminate this race condition.  But this raises two concerns to me:

(1) Lots of locks means poor performance
(2) Lots of drivers probably suffer from this same problem.  usb-storage
is probably just one of the few that does so many repeated transfers over
such a long period of time to make this visible.

It occurs to me that the best answer is probably to make it so that
usb_sndbulkpipe checks for a NULL device and make it so that
usb_bulk_msg() can also handle a NULL device.  Returning an error to
indicate "invalid device" would probably be the best way to go.

Taking this approach at a lower level would then make it easier for
drivers which need to do multi-stage transactions to avoid race
conditions.  Otherwise, my driver needs to either lock around a large and
time-lengthy piece of code, or lock and unlock repeatedly around each
stage of the transaction.

Matt Dharm

On Thu, 23 Mar 2000, Pavel Machek wrote:

> Hi!
> 
> > (o) Fixes an over-agressive sanity check that affects ORB drives and
> > someone's CD-ROM drive.
> > (o) Frees _most_ resources when driver is rmmod'ed.  About 16 bytes/device
> > still remain.  This is being worked on.
> > (o) Allows the driver to be insmod'ed and rmmod'ed repeatedly.  This works
> > with OHCI, and Georg Acher has a patch for usb-uhci to fix this bug.  A
> > patch for uhci.o is also needed.  Georg should be submitting his patch
> > soon.  I do not know when a patch from JE is coming.
> > (o) Adds my name to the maintainers file
> 
> Now I know why it oopses when I unplug it in error loop:
> 
> at one of marked points, us->pusb_dev gets NULL, and because
> usb_sndbulkpipe does no checking, oops is imminent.
> 
> (Checking for NULL and returning prevents oops but induces panic bit
> later.)
> 
> static int Bulk_transport(Scsi_Cmnd *srb, struct us_data *us)
> {
>       struct bulk_cb_wrap bcb;
>       struct bulk_cs_wrap bcs;
>       int result;
>       int pipe;
>       int partial;
>       
>       /* set up the command wrapper */
>       bcb.Signature = US_BULK_CB_SIGN;
>       bcb.DataTransferLength = us_transfer_length(srb);
>       bcb.Flags = US_DIRECTION(srb->cmnd[0]) << 7;
>       bcb.Tag = srb->serial_number;
>       bcb.Lun = 0;
>       bcb.Length = srb->cmd_len;
>       
>       /* construct the pipe handle */
> ========>>>>>
>       pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out);
>       
>       /* copy the command payload */
>       memset(bcb.CDB, 0, sizeof(bcb.CDB));
>       memcpy(bcb.CDB, srb->cmnd, bcb.Length);
>       
>       /* send it to out endpoint */
>       US_DEBUGP("Bulk command S 0x%x T 0x%x L %d F %d CL %d\n",
>                 bcb.Signature, bcb.Tag, bcb.DataTransferLength,
>                 bcb.Flags, bcb.Length);
>       result = usb_bulk_msg(us->pusb_dev, pipe, &bcb,
>                             US_BULK_CB_WRAP_LEN, &partial, HZ*5);
>       US_DEBUGP("Bulk command transfer result=%d\n", result);
>       
>       /* if we stall, we need to clear it before we go on */
>       if (result == -EPIPE) {
>               US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe);
>               usb_clear_halt(us->pusb_dev, pipe);
>       }
>       
>       /* if the command transfered well, then we go to the data stage */
>       if (result == 0) {
>               /* send/receive data payload, if there is any */
>               if (bcb.DataTransferLength) {
>                       us_transfer(srb, bcb.Flags);
>                       US_DEBUGP("Bulk data transfer result 0x%x\n", 
>                                 srb->result);
>               }
>       }
>       
>       /* See flow chart on pg 15 of the Bulk Only Transport spec for
>        * an explanation of how this code works.
>        */
>       
>       /* construct the pipe handle */
> =========>>>>>>>
>       pipe = usb_rcvbulkpipe(us->pusb_dev, us->ep_in);
>       
>       /* get CSW for device status */
>       result = usb_bulk_msg(us->pusb_dev, pipe, &bcs,
>                             US_BULK_CS_WRAP_LEN, &partial, HZ*5);
>       
>       /* did the attempt to read the CSW fail? */
>       if (result == -EPIPE) {
>               US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe);
>               usb_clear_halt(us->pusb_dev, pipe);
>               
>               /* get the status again */
>               result = usb_bulk_msg(us->pusb_dev, pipe, &bcs,
>                                     US_BULK_CS_WRAP_LEN, &partial, HZ*5);
>               
>               /* if it fails again, we need a reset and return an error*/
>               if (result == -EPIPE) {
>                       Bulk_reset(us);
> 
> 

-- 
Matthew Dharm                              Home: [EMAIL PROTECTED] 
Engineer, Qualcomm, Inc.                         Work: [EMAIL PROTECTED]

It's monday.  It must be monday.
                                        -- Greg
User Friendly, 5/4/1998


---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to