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