public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
From: Pete Zaitcev <zaitcev@redhat.com>
To: johannes@erdfelt.com
Cc: Pete Zaitcev <zaitcev@redhat.com>,
	linux-kernel@vger.kernel.org, t.sailer@alumni.ethz.ch
Subject: Re: Patch for bizzare oops in USB
Date: Mon, 20 Aug 2001 17:44:48 -0400	[thread overview]
Message-ID: <20010820174448.A1299@devserv.devel.redhat.com> (raw)
In-Reply-To: <20010818013101.A7058@devserv.devel.redhat.com> <3B80FBA9.556B7B2B@scs.ch>
In-Reply-To: <3B80FBA9.556B7B2B@scs.ch>; from sailer@scs.ch on Mon, Aug 20, 2001 at 01:59:37PM +0200

> Date: Mon, 20 Aug 2001 13:59:37 +0200
> From: Thomas Sailer <sailer@scs.ch>

> > -       current->state = TASK_INTERRUPTIBLE;
> > +       current->state = TASK_UNINTERRUPTIBLE;  /* MUST BE SO. -- zaitcev */

> This is bad for other users of usb_control_msg/usb_bulk_msg that depend on
> the sleep to be interruptible. Instead of bouncing back and forth whether
> those routines shall sleep interruptibly or uninterruptibly, we should either
> provide two routines or a parameter that specifies whether the sleep
> shall be interruptible, or create a local version of usb_control_msg
> if ov511 is the only user requiring uninterruptible sleep.

A prolifiration of subtly different versions of basic primitives
is not an answer either. But wait, here's a better fix. The
root of the evil is that the waiting thread accesses urb->status
before a callback happened, which is unsafe.

BTW, I took a liberty to clean the thing up a bit. It looked as
if the author of that fragment was not sure of what he was doing,
and the style was quite dirty. I think a number of wrongs for
such a small fragment was astonishing.

 - "status" was an errno in the begining, then 5 lines down
   it's bool (== timeout), then it turns into system style once again.
 - Wasted pointer to wait head
 - Unused void *stuff.
 - typedef without _t and unprefixed type name in global header.
 - Urban legend of test for waitqueue_active() before wakeup.
   This is one half wrong because so many people do it,
   anyone has an idea why? Half a point deducted.
 - Confused and redundant checking for -EINPROGRESS
   (even if it was the cause of oops)

And the last one ...
 - THE GOD DAMN RACE THAT OOPS - that's 10 hacker points down!
   It only goes to show that replacing interruptible_sleep_on
   with add_wait_queue/schedule/remove_wait_queue does not make
   any racy code correct automatically.

Cheesh, I am surprised _anything_ in Linux kernel works.

-- Pete

--- linux-2.4.8/include/linux/usb.h	Fri Aug 10 18:16:46 2001
+++ linux-2.4.8-e/include/linux/usb.h	Mon Aug 20 10:28:36 2001
@@ -539,13 +539,12 @@
  *                         SYNCHRONOUS CALL SUPPORT                  *
  *-------------------------------------------------------------------*/
 
-typedef struct
+struct usb_api_data
 {
-  wait_queue_head_t *wakeup;
-
-  void* stuff;
-  /* more to follow */
-} api_wrapper_data;
+	wait_queue_head_t wqh;
+	int done;
+	/* void* stuff;	*/	/* Possible extension later. */
+};
 
 /* -------------------------------------------------------------------------- */
 
--- linux-2.4.8/drivers/usb/usb.c	Tue Jul 24 14:20:56 2001
+++ linux-2.4.8-e/drivers/usb/usb.c	Mon Aug 20 14:05:45 2001
@@ -1041,15 +1041,10 @@
  *-------------------------------------------------------------------*/
 static void usb_api_blocking_completion(urb_t *urb)
 {
-	api_wrapper_data *awd = (api_wrapper_data *)urb->context;
+	struct usb_api_data *awd = (struct usb_api_data *)urb->context;
 
-	if (waitqueue_active(awd->wakeup))
-		wake_up(awd->wakeup);
-#if 0
-	else
-		dbg("(blocking_completion): waitqueue empty!"); 
-		// even occurs if urb was unlinked by timeout...
-#endif
+	awd->done = 1;
+	wake_up(&awd->wqh);
 }
 
 /*-------------------------------------------------------------------*
@@ -1060,35 +1055,32 @@
 static int usb_start_wait_urb(urb_t *urb, int timeout, int* actual_length)
 { 
 	DECLARE_WAITQUEUE(wait, current);
-	DECLARE_WAIT_QUEUE_HEAD(wqh);
-	api_wrapper_data awd;
+	struct usb_api_data awd;
 	int status;
-  
-	awd.wakeup = &wqh;
-	init_waitqueue_head(&wqh); 	
+
+	init_waitqueue_head(&awd.wqh); 	
+	awd.done = 0;
+
 	current->state = TASK_INTERRUPTIBLE;
-	add_wait_queue(&wqh, &wait);
+	add_wait_queue(&awd.wqh, &wait);
+
 	urb->context = &awd;
 	status = usb_submit_urb(urb);
 	if (status) {
 		// something went wrong
 		usb_free_urb(urb);
 		current->state = TASK_RUNNING;
-		remove_wait_queue(&wqh, &wait);
+		remove_wait_queue(&awd.wqh, &wait);
 		return status;
 	}
 
-	if (urb->status == -EINPROGRESS) {
-		while (timeout && urb->status == -EINPROGRESS)
-			status = timeout = schedule_timeout(timeout);
-	} else
-		status = 1;
+	while (timeout && !awd.done)
+		timeout = schedule_timeout(timeout);
 
 	current->state = TASK_RUNNING;
-	remove_wait_queue(&wqh, &wait);
+	remove_wait_queue(&awd.wqh, &wait);
 
-	if (!status) {
-		// timeout
+	if (!timeout) {
 		printk("usb_control/bulk_msg: timeout\n");
 		usb_unlink_urb(urb);  // remove urb safely
 		status = -ETIMEDOUT;

  parent reply	other threads:[~2001-08-20 21:45 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2001-08-18  5:31 Patch for bizzare oops in USB Pete Zaitcev
2001-08-20 11:59 ` Thomas Sailer
2001-08-20 21:06   ` Pete Zaitcev
2001-08-21  8:29     ` Thomas Sailer
2001-08-20 21:44   ` Pete Zaitcev [this message]
2001-08-21  4:01     ` Johannes Erdfelt
2001-08-21  4:17       ` Pete Zaitcev
2001-08-20 22:12   ` Eugene Crosser

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20010820174448.A1299@devserv.devel.redhat.com \
    --to=zaitcev@redhat.com \
    --cc=johannes@erdfelt.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=t.sailer@alumni.ethz.ch \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox