Am Donnerstag, 20. Dezember 2007 17:37:49 schrieb Greg KH: > On Thu, Dec 20, 2007 at 10:32:50AM -0500, Alan Stern wrote: > > On Thu, 20 Dec 2007, Oliver Neukum wrote: > > > > > Hi, > > > > > > the mos7720 driver sends two commands to the device whenever it is > > > closed. It does so unconditionally even if the device has been > > > disconnected. > > > It seems to me that this is wrong. Making sure that this does not happen > > > for disconnected devices takes a bit of infrastructure in the generic > > > part. > > > However I am not sure whether this interfeeres with hanging up the tty. > > > What do you think? > > > > There's nothing wrong with trying to send those commands if the device > > really is disconnected. The attempts will fail quickly. > > > > The problem arises when the device is still connected but the driver > > has been unbound. That is illegal; a driver is never supposed to > > access a device once its unbind method has returned. > > > > Do other serial drivers suffer from a similar problem? > > The io_edgeport-like devices all want to send a "flush" type command > when they are closed, and it doesn't look like they check for disconnect > either :(
>From a more general angle, perhaps what we provide with usb_kill_urb() is not ideally suited to combat this problem. What about a construction like this: Signed-off-by: Oliver Neukum <[EMAIL PROTECTED]> Regards Oliver ---- --- linux-2.6.24-rc5-vanilla/drivers/usb/core/urb.c 2007-12-20 13:13:52.000000000 +0100 +++ linux-2.6.24-rc5-work/drivers/usb/core/urb.c 2007-12-17 20:47:50.000000000 +0100 @@ -10,6 +10,8 @@ #define to_urb(d) container_of(d, struct urb, kref) +static DEFINE_MUTEX(usb_reject_mutex); + static void urb_destroy(struct kref *kref) { struct urb *urb = to_urb(kref); @@ -537,21 +539,52 @@ int usb_unlink_urb(struct urb *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); +} + +/** + * usb_poison_urb - cancel an URB, wait for it to finish, prevent its use + * @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 + * cannot be reused. These features make + * this an ideal way to stop I/O in a disconnect() callback or close() + * function. If the request has not already finished or been unlinked + * the completion handler will see urb->status == -ENOENT. + * + * After the routine has been run, attempts to resubmit the URB will fail + * with error -EPERM. Thus even if a driver tries to resubmit, the device + * won't be bothered + * + * 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); } /** @@ -603,3 +636,4 @@ EXPORT_SYMBOL(usb_get_urb); EXPORT_SYMBOL(usb_submit_urb); EXPORT_SYMBOL(usb_unlink_urb); EXPORT_SYMBOL(usb_kill_urb); +EXPORT_SYMBOL(usb_poison_urb); - To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html