* Re: Bug with USB proc_bulk in 2.4 kernel and possibly bug in proc_ioctl in 2.6
[not found] <mailman.1152332281.24203.linux-kernel2news@redhat.com>
@ 2006-07-08 20:28 ` Pete Zaitcev
2006-07-10 19:58 ` Bug with USB proc_bulk in 2.4 kernel Benjamin Cherian
0 siblings, 1 reply; 26+ messages in thread
From: Pete Zaitcev @ 2006-07-08 20:28 UTC (permalink / raw)
To: Benjamin Cherian; +Cc: zaitcev, linux-kernel, mtosatti
On Fri, 7 Jul 2006 17:24:56 -0700, Benjamin Cherian <benjamin.cherian.kernel@gmail.com> wrote:
> I believe that there is a bug in the proc_bulk function in drivers/usb/devio.c
> in the current 2.4 kernel. In the 2.4.28 proc_ioctl was changed so that the
> device would be locked before proc_bulk was called (See line 1275 of
> devio.c). In 2.4.27, no locking occurred. However, this leads to problems if
> one thread is continuously attempting to read and another one needs to write
> because the write thread can never access the device. []
The decision to cripple the devio in this way was conscious. The problem
scenario with 2.4.27 and earlier was how many devices would fail if
a control and other transfer were submitted simultaneously. In other
words, when desktop components (e.g. HAL) rescanned /proc/bus/usb/devices,
some other devices would throw errors. The most notorious example
would be TEAC CD-210PU, because of how widespread and popular it is.
In other words, I crippled your application for the sake of a bunch
of users of other devices. You have to realize though, that your
concerns weren't voiced in the time and it was widely believed that
user-mode drivers did not submit several URBs at once (primarily
because the queueing in HCDs of 2.4 was a suspect).
> I would have submitted a patch, but it seems like the locking/unlocking
> mechanism is different in 2.4 and 2.6 and I wasn't sure if I would break
> other stuff.
If you do send a patch, you need to account for the serialization
somehow. The linux-usb-devel people considered a few ideas, such
as per-device blacklists and locking flags, backport of string caching
from 2.6 (to alleviate the most common case of /proc/usb/usb/devices).
But it seems to me that the best approach would be if you made
a special case for bulk+bulk and locked out control transfers somehow.
Another option is to look at an in-kernel driver architecture for
your device. What is it, anyway?
-- Pete
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: Bug with USB proc_bulk in 2.4 kernel
2006-07-08 20:28 ` Bug with USB proc_bulk in 2.4 kernel and possibly bug in proc_ioctl in 2.6 Pete Zaitcev
@ 2006-07-10 19:58 ` Benjamin Cherian
2006-07-10 20:40 ` Pete Zaitcev
0 siblings, 1 reply; 26+ messages in thread
From: Benjamin Cherian @ 2006-07-10 19:58 UTC (permalink / raw)
To: Pete Zaitcev; +Cc: linux-kernel, linux-usb-devel
Hi,
On Saturday 08 July 2006 13:28, you wrote:
> The decision to cripple the devio in this way was conscious. The problem
> scenario with 2.4.27 and earlier was how many devices would fail if
> a control and other transfer were submitted simultaneously. In other
> words, when desktop components (e.g. HAL) rescanned /proc/bus/usb/devices,
> some other devices would throw errors. The most notorious example
> would be TEAC CD-210PU, because of how widespread and popular it is.
>
> In other words, I crippled your application for the sake of a bunch
> of users of other devices. You have to realize though, that your
> concerns weren't voiced in the time and it was widely believed that
> user-mode drivers did not submit several URBs at once (primarily
> because the queueing in HCDs of 2.4 was a suspect).
I understand your decision but this does not follow the USB spec. According
to the spec, two threads should be able to perform operations on the same
device at the same time.
> But it seems to me that the best approach would be if you made
> a special case for bulk+bulk and locked out control transfers somehow.
This is exactly what I suggested in my first email. It just involves adding a
couple of lines of code, but I'm not sure how the unlock function works in
2.4. In 2.6, the device is unlocked WITHIN proc_bulk before usb_bulk_mesg is
called and is locked after usb_bulk_mesg returns. Therefore, the device is
still locked during control transfers.
Thanks,
Ben
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: Bug with USB proc_bulk in 2.4 kernel
2006-07-10 19:58 ` Bug with USB proc_bulk in 2.4 kernel Benjamin Cherian
@ 2006-07-10 20:40 ` Pete Zaitcev
2006-07-17 21:35 ` Benjamin Cherian
0 siblings, 1 reply; 26+ messages in thread
From: Pete Zaitcev @ 2006-07-10 20:40 UTC (permalink / raw)
To: Benjamin Cherian; +Cc: linux-kernel, linux-usb-devel, zaitcev
On Mon, 10 Jul 2006 12:58:32 -0700, Benjamin Cherian <benjamin.cherian.kernel@gmail.com> wrote:
> I understand your decision but this does not follow the USB spec. According
> to the spec, two threads should be able to perform operations on the same
> device at the same time.
This consideration is wholly irrelevant to the pertinent topic,
because the very issue arises from devices being non-compliant.
If we want them to operate, we have to apply workarounds, which
may but us outside of the spec envelope. So I am not even going
to argue if the spec in fact mandates this behaviour.
> > But it seems to me that the best approach would be if you made
> > a special case for bulk+bulk and locked out control transfers somehow.
>
> This is exactly what I suggested in my first email. It just involves adding a
> couple of lines of code, but I'm not sure how the unlock function works in
> 2.4. In 2.6, the device is unlocked WITHIN proc_bulk before usb_bulk_mesg is
> called and is locked after usb_bulk_mesg returns. Therefore, the device is
> still locked during control transfers.
I explained why this technique is not applicable to 2.4 in the part
of the message you failed to quote. To recap, if bulk methods were
simply to drop locks with a "couple of lines of code", they would allow
control transfers to happen simultaneously with bulk transfers.
It happens to work in 2.6 only because of its string caching feature.
Indeed, Stuart Hayes of Dell reported that he can cause TEAC CD-210PU
to break under 2.6.16 in the same way it did in 2.4.27, simply by doing
"lsusb -v" instead of "cat /proc/bus/usb/devices". The issue is still
with us. Greg chose to bypass it in 2.6, instead of fixing it, due
to the amount of work involved.
This is a fixable issue, but it's not two lines of code. And its
impact is very limited. If you, the person who actually suffers, are
not willing to do the necessary work, then why would anyone else be?
Still, I would be happy to consider your patch, if it were to emerge.
-- Pete
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: Bug with USB proc_bulk in 2.4 kernel
2006-07-10 20:40 ` Pete Zaitcev
@ 2006-07-17 21:35 ` Benjamin Cherian
2006-07-17 22:19 ` Pete Zaitcev
0 siblings, 1 reply; 26+ messages in thread
From: Benjamin Cherian @ 2006-07-17 21:35 UTC (permalink / raw)
To: Pete Zaitcev; +Cc: linux-kernel, linux-usb-devel
Hi Pete,
> This consideration is wholly irrelevant to the pertinent topic,
> because the very issue arises from devices being non-compliant.
> If we want them to operate, we have to apply workarounds, which
> may but us outside of the spec envelope. So I am not even going
> to argue if the spec in fact mandates this behaviour.
I understand the need to apply workarounds. But here is why the spec is
relevant. By applying workarounds you have *broken* the functionality of
Linux with respect to the USB specification. In my opinion, workarounds
should be constrained to fixing the problem rather than creating new ones.
> > This is exactly what I suggested in my first email. It just involves
> > adding a couple of lines of code, but I'm not sure how the unlock
> > function works in 2.4. In 2.6, the device is unlocked WITHIN proc_bulk
> > before usb_bulk_mesg is called and is locked after usb_bulk_mesg returns.
> > Therefore, the device is still locked during control transfers.
>
> I explained why this technique is not applicable to 2.4 in the part
> of the message you failed to quote. To recap, if bulk methods were
> simply to drop locks with a "couple of lines of code", they would allow
> control transfers to happen simultaneously with bulk transfers.
> It happens to work in 2.6 only because of its string caching feature.
> Indeed, Stuart Hayes of Dell reported that he can cause TEAC CD-210PU
> to break under 2.6.16 in the same way it did in 2.4.27, simply by doing
> "lsusb -v" instead of "cat /proc/bus/usb/devices". The issue is still
> with us. Greg chose to bypass it in 2.6, instead of fixing it, due
> to the amount of work involved.
Honestly, you provided very little information in your initial email. I had
to dig through the kernel source to make sense of what was going on. Even
for the above, I'm not understanding why "lsusb -v" causes problems under
2.6.16. Does the "-v" option cause the kernel to send control packets to the
device? You have to understand that the USB driver stack under Linux is not
my domain of expertise and I'm coming to you with a problem that is not of my
doing. It would help a great deal to receive more details from you.
> This is a fixable issue, but it's not two lines of code. And its
> impact is very limited. If you, the person who actually suffers, are
> not willing to do the necessary work, then why would anyone else be?
> Still, I would be happy to consider your patch, if it were to emerge.
It is really looking like you are backing me into a corner to make the change
myself. However, before doing so I'd like to say that I am disappointed that
the kernel developer list has not been more accommodating to this issue. I
understand that this problem only affects very few people. However, please
consider the spirit of what has happened here. My device adheres to the
specification. In an effort to fix other devices that do not adhere to the
specification you have broken my device. Then I am being asked to make
modifications to the OS, when clearly this is not my domain. We all want
Linux to be a primetime operating system and this sort of interaction with
the developers list is *not* representative of that desire.
Besides, the device that is being broken is a 10x CD-ROM drive! Who even uses
these anymore? :-)
Regards,
Benjamin Cherian
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: Bug with USB proc_bulk in 2.4 kernel
2006-07-17 21:35 ` Benjamin Cherian
@ 2006-07-17 22:19 ` Pete Zaitcev
2006-07-18 17:04 ` Benjamin Cherian
0 siblings, 1 reply; 26+ messages in thread
From: Pete Zaitcev @ 2006-07-17 22:19 UTC (permalink / raw)
To: Benjamin Cherian; +Cc: linux-kernel, linux-usb-devel, zaitcev
On Mon, 17 Jul 2006 14:35:21 -0700, Benjamin Cherian <benjamin.cherian.kernel@gmail.com> wrote:
I'm skipping the discussion of the spec, but going further, here's
what we have:
> It is really looking like you are backing me into a corner to make the change
> myself. However, before doing so I'd like to say that I am disappointed that
> the kernel developer list has not been more accommodating to this issue.
I understand, this is not a good situation. The problem is, it's 2.4.
It is upgraded very slowly, if at all. You came around about a year after
the fact. At the time, my initial approaches threw similar regressions
(with ADSL modems). Of course it's very tempting for me to off-load both
the work and the responsibility on you.
> Besides, the device that is being broken is a 10x CD-ROM drive!
> Who even uses these anymore? :-)
This was my reaction too, when Dell people came knocking. But apparently,
that thing is very popular. Also, they backed up their request with
a bag of money. In the end, I was glad I did "fix" that thing. Later,
it turned out to be OEM-ed by NEC, Fujitsu, and others; our own QA
uses it a lot as well. This happens because the 210PU offers significant
savings in power and space in OEM applications, and for casual users,
it's a perfect jump drive.
It's the same kind of question as, "who even uses 2.4 anymore".
By the way, did you consider an in-kernel driver? For me, it seems much
safer to reimplement the whole thing that way than to monkey with devio
again and risk more regressions.
Another option would be to change USBDEVFS_BULK to USBDEVFS_SUBMITURB.
Did you look at doing that?
Yours,
-- Pete
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: Bug with USB proc_bulk in 2.4 kernel
2006-07-17 22:19 ` Pete Zaitcev
@ 2006-07-18 17:04 ` Benjamin Cherian
2006-07-19 1:33 ` Pete Zaitcev
0 siblings, 1 reply; 26+ messages in thread
From: Benjamin Cherian @ 2006-07-18 17:04 UTC (permalink / raw)
To: Pete Zaitcev; +Cc: linux-kernel, linux-usb-devl
Pete,
> It's the same kind of question as, "who even uses 2.4 anymore".
We asked to same question to the user who told us about this bug :-). It
happened after the user built his own kernel (2.4.32) for Fedora Core 1,
which uses a much older version.
> By the way, did you consider an in-kernel driver? For me, it seems much
> safer to reimplement the whole thing that way than to monkey with devio
> again and risk more regressions.
We're currently using libusb. We don't have to time to patch and maintain a
driver that's actually in the tree. And our customers are definitely not
going to patch and build their own kernel either.
> Another option would be to change USBDEVFS_BULK to USBDEVFS_SUBMITURB.
> Did you look at doing that?
We did that as well. But when you try to reap an URB there is no timeout. So
if something goes wrong you're stuck waiting for the operation to finish or
for the user to physically unplug the device.
>Of course it's very tempting for me to off-load both
>the work and the responsibility on you.
All right then. I'll send you a patch that backports the string caching
mechanism from 2.6 in a few days. Would you be able to test it with the
210PU?
Thanks,
Ben
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: Bug with USB proc_bulk in 2.4 kernel
2006-07-18 17:04 ` Benjamin Cherian
@ 2006-07-19 1:33 ` Pete Zaitcev
2006-07-20 17:43 ` Benjamin Cherian
0 siblings, 1 reply; 26+ messages in thread
From: Pete Zaitcev @ 2006-07-19 1:33 UTC (permalink / raw)
To: Benjamin Cherian; +Cc: linux-kernel, linux-usb-devl, zaitcev
On Tue, 18 Jul 2006 10:04:54 -0700, Benjamin Cherian <benjamin.cherian.kernel@gmail.com> wrote:
> > Another option would be to change USBDEVFS_BULK to USBDEVFS_SUBMITURB.
> > Did you look at doing that?
> We did that as well. But when you try to reap an URB there is no timeout. So
> if something goes wrong you're stuck waiting for the operation to finish or
> for the user to physically unplug the device.
This can't be right. Surely alarm(2) should work?
> >Of course it's very tempting for me to off-load both
> >the work and the responsibility on you.
>
> All right then. I'll send you a patch that backports the string caching
> mechanism from 2.6 in a few days. Would you be able to test it with the
> 210PU?
Yes, that would be fine.
Although I am starting to think about creating a custom locking
scheme in devio.c after all. It seems like less work.
-- Pete
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: Bug with USB proc_bulk in 2.4 kernel
2006-07-19 1:33 ` Pete Zaitcev
@ 2006-07-20 17:43 ` Benjamin Cherian
2006-07-25 6:07 ` Pete Zaitcev
0 siblings, 1 reply; 26+ messages in thread
From: Benjamin Cherian @ 2006-07-20 17:43 UTC (permalink / raw)
To: Pete Zaitcev; +Cc: linux-kernel, linux-usb-devel
Pete,
Thanks for the reply.
> > All right then. I'll send you a patch that backports the string caching
> > mechanism from 2.6 in a few days. Would you be able to test it with the
> > 210PU?
>
> Yes, that would be fine.
We should get back to you in a couple weeks with this.
> Although I am starting to think about creating a custom locking
> scheme in devio.c after all. It seems like less work.
What's your timeframe for this? Good luck with it.
Thanks,
Ben
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: Bug with USB proc_bulk in 2.4 kernel
2006-07-20 17:43 ` Benjamin Cherian
@ 2006-07-25 6:07 ` Pete Zaitcev
2006-07-25 19:31 ` Willy Tarreau
2006-07-27 22:21 ` Benjamin Cherian
0 siblings, 2 replies; 26+ messages in thread
From: Pete Zaitcev @ 2006-07-25 6:07 UTC (permalink / raw)
To: Benjamin Cherian; +Cc: linux-kernel, linux-usb-devel, zaitcev, mtosatti
On Thu, 20 Jul 2006 10:43:59 -0700, Benjamin Cherian <benjamin.cherian.kernel@gmail.com> wrote:
> > Although I am starting to think about creating a custom locking
> > scheme in devio.c after all. It seems like less work.
> What's your timeframe for this? Good luck with it.
OK, now I hate my life, I hate you, I hate Stuart, but most of all
I hate the anonymous Japanese who wrote the microcode for TEAC CD-210PU.
Anyway, please test the attached patch. Does it do what you want?
-- Pete
diff -urp -X dontdiff linux-2.4.32/drivers/usb/devices.c linux-2.4.32-wk/drivers/usb/devices.c
--- linux-2.4.32/drivers/usb/devices.c 2004-11-17 03:54:21.000000000 -0800
+++ linux-2.4.32-wk/drivers/usb/devices.c 2006-07-24 22:30:54.000000000 -0700
@@ -392,7 +392,7 @@ static char *usb_dump_desc(char *start,
* Grab device's exclusive_access mutex to prevent its driver or
* devio from using this device while we are accessing it.
*/
- down (&dev->exclusive_access);
+ usb_excl_lock(dev, 3, 0);
start = usb_dump_device_descriptor(start, end, &dev->descriptor);
@@ -411,7 +411,7 @@ static char *usb_dump_desc(char *start,
}
out:
- up (&dev->exclusive_access);
+ usb_excl_unlock(dev, 3);
return start;
}
diff -urp -X dontdiff linux-2.4.32/drivers/usb/devio.c linux-2.4.32-wk/drivers/usb/devio.c
--- linux-2.4.32/drivers/usb/devio.c 2006-04-13 19:02:30.000000000 -0700
+++ linux-2.4.32-wk/drivers/usb/devio.c 2006-07-24 22:39:32.000000000 -0700
@@ -623,7 +623,12 @@ static int proc_bulk(struct dev_state *p
free_page((unsigned long)tbuf);
return -EINVAL;
}
+ if (usb_excl_lock(dev, 1, 1) != 0) {
+ free_page((unsigned long)tbuf);
+ return -ERESTARTSYS;
+ }
i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo);
+ usb_excl_unlock(dev, 1);
if (!i && len2) {
if (copy_to_user(bulk.data, tbuf, len2)) {
free_page((unsigned long)tbuf);
@@ -637,7 +642,12 @@ static int proc_bulk(struct dev_state *p
return -EFAULT;
}
}
+ if (usb_excl_lock(dev, 2, 1) != 0) {
+ free_page((unsigned long)tbuf);
+ return -ERESTARTSYS;
+ }
i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo);
+ usb_excl_unlock(dev, 2);
}
free_page((unsigned long)tbuf);
if (i < 0) {
@@ -1160,12 +1170,6 @@ static int usbdev_ioctl_exclusive(struct
inode->i_mtime = CURRENT_TIME;
break;
- case USBDEVFS_BULK:
- ret = proc_bulk(ps, (void *)arg);
- if (ret >= 0)
- inode->i_mtime = CURRENT_TIME;
- break;
-
case USBDEVFS_RESETEP:
ret = proc_resetep(ps, (void *)arg);
if (ret >= 0)
@@ -1259,8 +1263,13 @@ static int usbdev_ioctl(struct inode *in
ret = proc_disconnectsignal(ps, (void *)arg);
break;
- case USBDEVFS_CONTROL:
case USBDEVFS_BULK:
+ ret = proc_bulk(ps, (void *)arg);
+ if (ret >= 0)
+ inode->i_mtime = CURRENT_TIME;
+ break;
+
+ case USBDEVFS_CONTROL:
case USBDEVFS_RESETEP:
case USBDEVFS_RESET:
case USBDEVFS_CLEAR_HALT:
@@ -1272,9 +1281,9 @@ static int usbdev_ioctl(struct inode *in
case USBDEVFS_RELEASEINTERFACE:
case USBDEVFS_IOCTL:
ret = -ERESTARTSYS;
- if (down_interruptible(&ps->dev->exclusive_access) == 0) {
+ if (usb_excl_lock(&ps->dev, 3, 1) == 0) {
ret = usbdev_ioctl_exclusive(ps, inode, cmd, arg);
- up(&ps->dev->exclusive_access);
+ usb_excl_unlock(&ps->dev, 3);
}
break;
diff -urp -X dontdiff linux-2.4.32/drivers/usb/storage/transport.c linux-2.4.32-wk/drivers/usb/storage/transport.c
--- linux-2.4.32/drivers/usb/storage/transport.c 2005-04-03 18:42:19.000000000 -0700
+++ linux-2.4.32-wk/drivers/usb/storage/transport.c 2006-07-24 22:58:58.000000000 -0700
@@ -628,16 +628,16 @@ void usb_stor_invoke_transport(Scsi_Cmnd
int result;
/*
- * Grab device's exclusive_access mutex to prevent libusb/usbfs from
+ * Grab device's exclusive access lock to prevent libusb/usbfs from
* sending out a command in the middle of ours (if libusb sends a
* get_descriptor or something on pipe 0 after our CBW and before
* our CSW, and then we get a stall, we have trouble).
*/
- down(&(us->pusb_dev->exclusive_access));
+ usb_excl_lock(us->pusb_dev, 3, 0);
/* send the command to the transport layer */
result = us->transport(srb, us);
- up(&(us->pusb_dev->exclusive_access));
+ usb_excl_unlock(us->pusb_dev, 3);
/* if the command gets aborted by the higher layers, we need to
* short-circuit all other processing
@@ -757,9 +757,9 @@ void usb_stor_invoke_transport(Scsi_Cmnd
srb->use_sg = 0;
/* issue the auto-sense command */
- down(&(us->pusb_dev->exclusive_access));
+ usb_excl_lock(us->pusb_dev, 3, 0);
temp_result = us->transport(us->srb, us);
- up(&(us->pusb_dev->exclusive_access));
+ usb_excl_unlock(us->pusb_dev, 3);
/* let's clean up right away */
srb->request_buffer = old_request_buffer;
diff -urp -X dontdiff linux-2.4.32/drivers/usb/usb.c linux-2.4.32-wk/drivers/usb/usb.c
--- linux-2.4.32/drivers/usb/usb.c 2004-11-17 03:54:21.000000000 -0800
+++ linux-2.4.32-wk/drivers/usb/usb.c 2006-07-24 22:41:19.000000000 -0700
@@ -989,7 +989,8 @@ struct usb_device *usb_alloc_dev(struct
INIT_LIST_HEAD(&dev->filelist);
init_MUTEX(&dev->serialize);
- init_MUTEX(&dev->exclusive_access);
+ spin_lock_init(&dev->excl_lock);
+ init_waitqueue_head(&dev->excl_wait);
dev->bus->op->allocate(dev);
@@ -2380,6 +2381,59 @@ struct list_head *usb_bus_get_list(void)
}
#endif
+int usb_excl_lock(struct usb_device *dev, unsigned int type, int interruptible)
+{
+ DECLARE_WAITQUEUE(waita, current);
+
+ add_wait_queue(&dev->excl_wait, &waita);
+ if (interruptible)
+ set_current_state(TASK_INTERRUPTIBLE);
+ else
+ set_current_state(TASK_UNINTERRUPTIBLE);
+
+ for (;;) {
+ spin_lock_irq(&dev->excl_lock);
+ switch (type) {
+ case 1: /* 1 - read */
+ case 2: /* 2 - write */
+ case 3: /* 3 - control: excludes both read and write */
+ if ((dev->excl_type & type) == 0) {
+ dev->excl_type |= type;
+ spin_unlock_irq(&dev->excl_lock);
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&dev->excl_wait, &waita);
+ return 0;
+ }
+ break;
+ default:
+ spin_unlock_irq(&dev->excl_lock);
+ return -EINVAL;
+ }
+ spin_unlock_irq(&dev->excl_lock);
+
+ if (interruptible) {
+ schedule();
+ if (signal_pending(current)) {
+ remove_wait_queue(&dev->excl_wait, &waita);
+ return 1;
+ }
+ set_current_state(TASK_INTERRUPTIBLE);
+ } else {
+ schedule();
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ }
+ }
+}
+
+void usb_excl_unlock(struct usb_device *dev, unsigned int type)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->excl_lock, flags);
+ dev->excl_type &= ~type;
+ wake_up(&dev->excl_wait);
+ spin_unlock_irqrestore(&dev->excl_lock, flags);
+}
/*
* Init
diff -urp -X dontdiff linux-2.4.32/include/linux/usb.h linux-2.4.32-wk/include/linux/usb.h
--- linux-2.4.32/include/linux/usb.h 2005-12-22 17:08:01.000000000 -0800
+++ linux-2.4.32-wk/include/linux/usb.h 2006-07-24 22:30:02.000000000 -0700
@@ -828,8 +828,19 @@ struct usb_device {
atomic_t refcnt; /* Reference count */
struct semaphore serialize;
- struct semaphore exclusive_access; /* prevent driver & proc accesses */
- /* from overlapping cmds at device */
+
+ /*
+ * This is our custom open-coded lock, similar to r/w locks in concept.
+ * It prevents drivers and /proc access from simultaneous access.
+ * Type:
+ * 0 - unlocked
+ * 1 - locked for reads
+ * 2 - locked for writes
+ * 3 - locked for everything
+ */
+ wait_queue_head_t excl_wait;
+ spinlock_t excl_lock;
+ unsigned excl_type;
unsigned int toggle[2]; /* one bit for each endpoint ([0] = IN, [1] = OUT) */
unsigned int halted[2]; /* endpoint halts; one bit per endpoint # & direction; */
@@ -904,6 +915,8 @@ extern void usb_destroy_configuration(st
int usb_get_current_frame_number (struct usb_device *usb_dev);
+int usb_excl_lock(struct usb_device *dev, unsigned int type, int interruptible);
+void usb_excl_unlock(struct usb_device *dev, unsigned int type);
/**
* usb_make_path - returns stable device path in the usb tree
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: Bug with USB proc_bulk in 2.4 kernel
2006-07-25 6:07 ` Pete Zaitcev
@ 2006-07-25 19:31 ` Willy Tarreau
2006-07-27 22:21 ` Benjamin Cherian
1 sibling, 0 replies; 26+ messages in thread
From: Willy Tarreau @ 2006-07-25 19:31 UTC (permalink / raw)
To: Pete Zaitcev; +Cc: Benjamin Cherian, linux-kernel, linux-usb-devel, mtosatti
Hi Pete,
On Mon, Jul 24, 2006 at 11:07:32PM -0700, Pete Zaitcev wrote:
> On Thu, 20 Jul 2006 10:43:59 -0700, Benjamin Cherian <benjamin.cherian.kernel@gmail.com> wrote:
>
> > > Although I am starting to think about creating a custom locking
> > > scheme in devio.c after all. It seems like less work.
>
> > What's your timeframe for this? Good luck with it.
>
> OK, now I hate my life, I hate you, I hate Stuart, but most of all
> I hate the anonymous Japanese who wrote the microcode for TEAC CD-210PU.
> Anyway, please test the attached patch. Does it do what you want?
I'm very glad that you're still maintaining 2.4 code so much actively. Do
you think of any possible side effects that non-TEAC users might encounter ?
If you feel more comfortable after some particular corner-case tests on other
hardware, please ask.
> -- Pete
Cheers,
Willy
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: Bug with USB proc_bulk in 2.4 kernel
2006-07-25 6:07 ` Pete Zaitcev
2006-07-25 19:31 ` Willy Tarreau
@ 2006-07-27 22:21 ` Benjamin Cherian
2006-07-27 23:49 ` Pete Zaitcev
2006-07-30 7:35 ` Pete Zaitcev
1 sibling, 2 replies; 26+ messages in thread
From: Benjamin Cherian @ 2006-07-27 22:21 UTC (permalink / raw)
To: Pete Zaitcev; +Cc: linux-kernel, linux-usb-devel, mtosatti
On Monday 24 July 2006 23:07, Pete Zaitcev wrote:
> Anyway, please test the attached patch. Does it do what you want?
Sorry to say that it doesnt. When calling usb_get_string_simple in libusb, the
program segfaults with the patched kernel. I believe that
usb_get_string_simple eventually calls usbdev_ioctl.
Thanks,
Ben
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: Bug with USB proc_bulk in 2.4 kernel
2006-07-27 22:21 ` Benjamin Cherian
@ 2006-07-27 23:49 ` Pete Zaitcev
2006-07-28 17:37 ` Benjamin Cherian
2006-07-30 7:35 ` Pete Zaitcev
1 sibling, 1 reply; 26+ messages in thread
From: Pete Zaitcev @ 2006-07-27 23:49 UTC (permalink / raw)
To: Benjamin Cherian; +Cc: linux-kernel, linux-usb-devel, mtosatti, zaitcev
On Thu, 27 Jul 2006 15:21:37 -0700, Benjamin Cherian <benjamin.cherian.kernel@gmail.com> wrote:
> On Monday 24 July 2006 23:07, Pete Zaitcev wrote:
> > Anyway, please test the attached patch. Does it do what you want?
>
> Sorry to say that it doesnt. When calling usb_get_string_simple in libusb,
> the program segfaults with the patched kernel. I believe that
> usb_get_string_simple eventually calls usbdev_ioctl.
Thanks for testing, I'll look into it.
By the way, you didn't tell me if you tried to use alarm(2) across
submitted URBs. This is the technique ADSL modem drivers use. They
also have to have input and output streams running simultaneously.
-- Pete
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: Bug with USB proc_bulk in 2.4 kernel
2006-07-27 23:49 ` Pete Zaitcev
@ 2006-07-28 17:37 ` Benjamin Cherian
0 siblings, 0 replies; 26+ messages in thread
From: Benjamin Cherian @ 2006-07-28 17:37 UTC (permalink / raw)
To: Pete Zaitcev; +Cc: linux-kernel, linux-usb-devel, mtosatti
Hi Pete,
Thanks for the reply.
> By the way, you didn't tell me if you tried to use alarm(2) across
> submitted URBs. This is the technique ADSL modem drivers use. They
> also have to have input and output streams running simultaneously.
I'm making a library to operate my device, and I don't want to use alarm,
because the user might need to use alarm in his own applications.
Thanks again,
Ben
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: Bug with USB proc_bulk in 2.4 kernel
2006-07-27 22:21 ` Benjamin Cherian
2006-07-27 23:49 ` Pete Zaitcev
@ 2006-07-30 7:35 ` Pete Zaitcev
2006-07-31 18:41 ` Benjamin Cherian
1 sibling, 1 reply; 26+ messages in thread
From: Pete Zaitcev @ 2006-07-30 7:35 UTC (permalink / raw)
To: Benjamin Cherian; +Cc: w, linux-kernel, linux-usb-devel
On Thu, 27 Jul 2006 15:21:37 -0700, Benjamin Cherian <benjamin.cherian.kernel@gmail.com> wrote:
> On Monday 24 July 2006 23:07, Pete Zaitcev wrote:
> > Anyway, please test the attached patch. Does it do what you want?
>
> Sorry to say that it doesnt. When calling usb_get_string_simple in libusb,
> the program segfaults with the patched kernel. I believe that
> usb_get_string_simple eventually calls usbdev_ioctl.
Indeed, I should've tested better, sorry. How about now?
-- Pete
diff -urp -X dontdiff linux-2.4.32/drivers/usb/devices.c linux-2.4.32-wk/drivers/usb/devices.c
--- linux-2.4.32/drivers/usb/devices.c 2004-11-17 03:54:21.000000000 -0800
+++ linux-2.4.32-wk/drivers/usb/devices.c 2006-07-24 22:30:54.000000000 -0700
@@ -392,7 +392,7 @@ static char *usb_dump_desc(char *start,
* Grab device's exclusive_access mutex to prevent its driver or
* devio from using this device while we are accessing it.
*/
- down (&dev->exclusive_access);
+ usb_excl_lock(dev, 3, 0);
start = usb_dump_device_descriptor(start, end, &dev->descriptor);
@@ -411,7 +411,7 @@ static char *usb_dump_desc(char *start,
}
out:
- up (&dev->exclusive_access);
+ usb_excl_unlock(dev, 3);
return start;
}
diff -urp -X dontdiff linux-2.4.32/drivers/usb/devio.c linux-2.4.32-wk/drivers/usb/devio.c
--- linux-2.4.32/drivers/usb/devio.c 2006-04-13 19:02:30.000000000 -0700
+++ linux-2.4.32-wk/drivers/usb/devio.c 2006-07-30 00:27:13.000000000 -0700
@@ -623,7 +623,12 @@ static int proc_bulk(struct dev_state *p
free_page((unsigned long)tbuf);
return -EINVAL;
}
+ if (usb_excl_lock(dev, 1, 1) != 0) {
+ free_page((unsigned long)tbuf);
+ return -ERESTARTSYS;
+ }
i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo);
+ usb_excl_unlock(dev, 1);
if (!i && len2) {
if (copy_to_user(bulk.data, tbuf, len2)) {
free_page((unsigned long)tbuf);
@@ -637,7 +642,12 @@ static int proc_bulk(struct dev_state *p
return -EFAULT;
}
}
+ if (usb_excl_lock(dev, 2, 1) != 0) {
+ free_page((unsigned long)tbuf);
+ return -ERESTARTSYS;
+ }
i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo);
+ usb_excl_unlock(dev, 2);
}
free_page((unsigned long)tbuf);
if (i < 0) {
@@ -1160,12 +1170,6 @@ static int usbdev_ioctl_exclusive(struct
inode->i_mtime = CURRENT_TIME;
break;
- case USBDEVFS_BULK:
- ret = proc_bulk(ps, (void *)arg);
- if (ret >= 0)
- inode->i_mtime = CURRENT_TIME;
- break;
-
case USBDEVFS_RESETEP:
ret = proc_resetep(ps, (void *)arg);
if (ret >= 0)
@@ -1259,8 +1263,13 @@ static int usbdev_ioctl(struct inode *in
ret = proc_disconnectsignal(ps, (void *)arg);
break;
- case USBDEVFS_CONTROL:
case USBDEVFS_BULK:
+ ret = proc_bulk(ps, (void *)arg);
+ if (ret >= 0)
+ inode->i_mtime = CURRENT_TIME;
+ break;
+
+ case USBDEVFS_CONTROL:
case USBDEVFS_RESETEP:
case USBDEVFS_RESET:
case USBDEVFS_CLEAR_HALT:
@@ -1272,9 +1281,9 @@ static int usbdev_ioctl(struct inode *in
case USBDEVFS_RELEASEINTERFACE:
case USBDEVFS_IOCTL:
ret = -ERESTARTSYS;
- if (down_interruptible(&ps->dev->exclusive_access) == 0) {
+ if (usb_excl_lock(ps->dev, 3, 1) == 0) {
ret = usbdev_ioctl_exclusive(ps, inode, cmd, arg);
- up(&ps->dev->exclusive_access);
+ usb_excl_unlock(ps->dev, 3);
}
break;
diff -urp -X dontdiff linux-2.4.32/drivers/usb/storage/transport.c linux-2.4.32-wk/drivers/usb/storage/transport.c
--- linux-2.4.32/drivers/usb/storage/transport.c 2005-04-03 18:42:19.000000000 -0700
+++ linux-2.4.32-wk/drivers/usb/storage/transport.c 2006-07-24 22:58:58.000000000 -0700
@@ -628,16 +628,16 @@ void usb_stor_invoke_transport(Scsi_Cmnd
int result;
/*
- * Grab device's exclusive_access mutex to prevent libusb/usbfs from
+ * Grab device's exclusive access lock to prevent libusb/usbfs from
* sending out a command in the middle of ours (if libusb sends a
* get_descriptor or something on pipe 0 after our CBW and before
* our CSW, and then we get a stall, we have trouble).
*/
- down(&(us->pusb_dev->exclusive_access));
+ usb_excl_lock(us->pusb_dev, 3, 0);
/* send the command to the transport layer */
result = us->transport(srb, us);
- up(&(us->pusb_dev->exclusive_access));
+ usb_excl_unlock(us->pusb_dev, 3);
/* if the command gets aborted by the higher layers, we need to
* short-circuit all other processing
@@ -757,9 +757,9 @@ void usb_stor_invoke_transport(Scsi_Cmnd
srb->use_sg = 0;
/* issue the auto-sense command */
- down(&(us->pusb_dev->exclusive_access));
+ usb_excl_lock(us->pusb_dev, 3, 0);
temp_result = us->transport(us->srb, us);
- up(&(us->pusb_dev->exclusive_access));
+ usb_excl_unlock(us->pusb_dev, 3);
/* let's clean up right away */
srb->request_buffer = old_request_buffer;
diff -urp -X dontdiff linux-2.4.32/drivers/usb/usb.c linux-2.4.32-wk/drivers/usb/usb.c
--- linux-2.4.32/drivers/usb/usb.c 2004-11-17 03:54:21.000000000 -0800
+++ linux-2.4.32-wk/drivers/usb/usb.c 2006-07-24 22:41:19.000000000 -0700
@@ -989,7 +989,8 @@ struct usb_device *usb_alloc_dev(struct
INIT_LIST_HEAD(&dev->filelist);
init_MUTEX(&dev->serialize);
- init_MUTEX(&dev->exclusive_access);
+ spin_lock_init(&dev->excl_lock);
+ init_waitqueue_head(&dev->excl_wait);
dev->bus->op->allocate(dev);
@@ -2380,6 +2381,59 @@ struct list_head *usb_bus_get_list(void)
}
#endif
+int usb_excl_lock(struct usb_device *dev, unsigned int type, int interruptible)
+{
+ DECLARE_WAITQUEUE(waita, current);
+
+ add_wait_queue(&dev->excl_wait, &waita);
+ if (interruptible)
+ set_current_state(TASK_INTERRUPTIBLE);
+ else
+ set_current_state(TASK_UNINTERRUPTIBLE);
+
+ for (;;) {
+ spin_lock_irq(&dev->excl_lock);
+ switch (type) {
+ case 1: /* 1 - read */
+ case 2: /* 2 - write */
+ case 3: /* 3 - control: excludes both read and write */
+ if ((dev->excl_type & type) == 0) {
+ dev->excl_type |= type;
+ spin_unlock_irq(&dev->excl_lock);
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&dev->excl_wait, &waita);
+ return 0;
+ }
+ break;
+ default:
+ spin_unlock_irq(&dev->excl_lock);
+ return -EINVAL;
+ }
+ spin_unlock_irq(&dev->excl_lock);
+
+ if (interruptible) {
+ schedule();
+ if (signal_pending(current)) {
+ remove_wait_queue(&dev->excl_wait, &waita);
+ return 1;
+ }
+ set_current_state(TASK_INTERRUPTIBLE);
+ } else {
+ schedule();
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ }
+ }
+}
+
+void usb_excl_unlock(struct usb_device *dev, unsigned int type)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->excl_lock, flags);
+ dev->excl_type &= ~type;
+ wake_up(&dev->excl_wait);
+ spin_unlock_irqrestore(&dev->excl_lock, flags);
+}
/*
* Init
diff -urp -X dontdiff linux-2.4.32/include/linux/usb.h linux-2.4.32-wk/include/linux/usb.h
--- linux-2.4.32/include/linux/usb.h 2005-12-22 17:08:01.000000000 -0800
+++ linux-2.4.32-wk/include/linux/usb.h 2006-07-24 22:30:02.000000000 -0700
@@ -828,8 +828,19 @@ struct usb_device {
atomic_t refcnt; /* Reference count */
struct semaphore serialize;
- struct semaphore exclusive_access; /* prevent driver & proc accesses */
- /* from overlapping cmds at device */
+
+ /*
+ * This is our custom open-coded lock, similar to r/w locks in concept.
+ * It prevents drivers and /proc access from simultaneous access.
+ * Type:
+ * 0 - unlocked
+ * 1 - locked for reads
+ * 2 - locked for writes
+ * 3 - locked for everything
+ */
+ wait_queue_head_t excl_wait;
+ spinlock_t excl_lock;
+ unsigned excl_type;
unsigned int toggle[2]; /* one bit for each endpoint ([0] = IN, [1] = OUT) */
unsigned int halted[2]; /* endpoint halts; one bit per endpoint # & direction; */
@@ -904,6 +915,8 @@ extern void usb_destroy_configuration(st
int usb_get_current_frame_number (struct usb_device *usb_dev);
+int usb_excl_lock(struct usb_device *dev, unsigned int type, int interruptible);
+void usb_excl_unlock(struct usb_device *dev, unsigned int type);
/**
* usb_make_path - returns stable device path in the usb tree
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: Bug with USB proc_bulk in 2.4 kernel
2006-07-30 7:35 ` Pete Zaitcev
@ 2006-07-31 18:41 ` Benjamin Cherian
2006-08-02 19:51 ` Willy Tarreau
0 siblings, 1 reply; 26+ messages in thread
From: Benjamin Cherian @ 2006-07-31 18:41 UTC (permalink / raw)
To: Pete Zaitcev; +Cc: w, linux-kernel, linux-usb-devel
Hi Pete,
>How about now?
Much better! For me, everything seems to be working. No segfaults, and
everything seems to work.
Thanks,
Ben
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: Bug with USB proc_bulk in 2.4 kernel
2006-07-31 18:41 ` Benjamin Cherian
@ 2006-08-02 19:51 ` Willy Tarreau
2006-08-03 1:02 ` Pete Zaitcev
0 siblings, 1 reply; 26+ messages in thread
From: Willy Tarreau @ 2006-08-02 19:51 UTC (permalink / raw)
To: Benjamin Cherian; +Cc: Pete Zaitcev, linux-kernel, linux-usb-devel
Hi Benjamin, Hi Pete,
On Mon, Jul 31, 2006 at 11:41:28AM -0700, Benjamin Cherian wrote:
> Hi Pete,
>
> >How about now?
>
> Much better! For me, everything seems to be working. No segfaults, and
> everything seems to work.
That's very good news.
Pete, do you consider your work as appropriate for mainline ? In this
case, I can queue it for 2.4.34.
> Thanks,
>
> Ben
Thanks guys,
Willy
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: Bug with USB proc_bulk in 2.4 kernel
2006-08-02 19:51 ` Willy Tarreau
@ 2006-08-03 1:02 ` Pete Zaitcev
2006-08-03 2:33 ` Willy Tarreau
0 siblings, 1 reply; 26+ messages in thread
From: Pete Zaitcev @ 2006-08-03 1:02 UTC (permalink / raw)
To: Willy Tarreau
Cc: benjamin.cherian.kernel, linux-kernel, linux-usb-devel, zaitcev
On Wed, 2 Aug 2006 21:51:00 +0200, Willy Tarreau <w@1wt.eu> wrote:
> Pete, do you consider your work as appropriate for mainline ? In this
> case, I can queue it for 2.4.34.
Yes, please use the attached patch. The one I sent for testing
missed necessary exports. This is also tested with TEAC CD-210PU.
I suppose the worst that can happen is that someone will complain
about a regression in 2008 :-)
-- Pete
diff -urp -X dontdiff linux-2.4.32/drivers/usb/devices.c linux-2.4.32-wk/drivers/usb/devices.c
--- linux-2.4.32/drivers/usb/devices.c 2004-11-17 03:54:21.000000000 -0800
+++ linux-2.4.32-wk/drivers/usb/devices.c 2006-07-24 22:30:54.000000000 -0700
@@ -392,7 +392,7 @@ static char *usb_dump_desc(char *start,
* Grab device's exclusive_access mutex to prevent its driver or
* devio from using this device while we are accessing it.
*/
- down (&dev->exclusive_access);
+ usb_excl_lock(dev, 3, 0);
start = usb_dump_device_descriptor(start, end, &dev->descriptor);
@@ -411,7 +411,7 @@ static char *usb_dump_desc(char *start,
}
out:
- up (&dev->exclusive_access);
+ usb_excl_unlock(dev, 3);
return start;
}
diff -urp -X dontdiff linux-2.4.32/drivers/usb/devio.c linux-2.4.32-wk/drivers/usb/devio.c
--- linux-2.4.32/drivers/usb/devio.c 2006-04-13 19:02:30.000000000 -0700
+++ linux-2.4.32-wk/drivers/usb/devio.c 2006-07-30 00:27:13.000000000 -0700
@@ -623,7 +623,12 @@ static int proc_bulk(struct dev_state *p
free_page((unsigned long)tbuf);
return -EINVAL;
}
+ if (usb_excl_lock(dev, 1, 1) != 0) {
+ free_page((unsigned long)tbuf);
+ return -ERESTARTSYS;
+ }
i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo);
+ usb_excl_unlock(dev, 1);
if (!i && len2) {
if (copy_to_user(bulk.data, tbuf, len2)) {
free_page((unsigned long)tbuf);
@@ -637,7 +642,12 @@ static int proc_bulk(struct dev_state *p
return -EFAULT;
}
}
+ if (usb_excl_lock(dev, 2, 1) != 0) {
+ free_page((unsigned long)tbuf);
+ return -ERESTARTSYS;
+ }
i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo);
+ usb_excl_unlock(dev, 2);
}
free_page((unsigned long)tbuf);
if (i < 0) {
@@ -1160,12 +1170,6 @@ static int usbdev_ioctl_exclusive(struct
inode->i_mtime = CURRENT_TIME;
break;
- case USBDEVFS_BULK:
- ret = proc_bulk(ps, (void *)arg);
- if (ret >= 0)
- inode->i_mtime = CURRENT_TIME;
- break;
-
case USBDEVFS_RESETEP:
ret = proc_resetep(ps, (void *)arg);
if (ret >= 0)
@@ -1259,8 +1263,13 @@ static int usbdev_ioctl(struct inode *in
ret = proc_disconnectsignal(ps, (void *)arg);
break;
- case USBDEVFS_CONTROL:
case USBDEVFS_BULK:
+ ret = proc_bulk(ps, (void *)arg);
+ if (ret >= 0)
+ inode->i_mtime = CURRENT_TIME;
+ break;
+
+ case USBDEVFS_CONTROL:
case USBDEVFS_RESETEP:
case USBDEVFS_RESET:
case USBDEVFS_CLEAR_HALT:
@@ -1272,9 +1281,9 @@ static int usbdev_ioctl(struct inode *in
case USBDEVFS_RELEASEINTERFACE:
case USBDEVFS_IOCTL:
ret = -ERESTARTSYS;
- if (down_interruptible(&ps->dev->exclusive_access) == 0) {
+ if (usb_excl_lock(ps->dev, 3, 1) == 0) {
ret = usbdev_ioctl_exclusive(ps, inode, cmd, arg);
- up(&ps->dev->exclusive_access);
+ usb_excl_unlock(ps->dev, 3);
}
break;
diff -urp -X dontdiff linux-2.4.32/drivers/usb/storage/transport.c linux-2.4.32-wk/drivers/usb/storage/transport.c
--- linux-2.4.32/drivers/usb/storage/transport.c 2005-04-03 18:42:19.000000000 -0700
+++ linux-2.4.32-wk/drivers/usb/storage/transport.c 2006-07-24 22:58:58.000000000 -0700
@@ -628,16 +628,16 @@ void usb_stor_invoke_transport(Scsi_Cmnd
int result;
/*
- * Grab device's exclusive_access mutex to prevent libusb/usbfs from
+ * Grab device's exclusive access lock to prevent libusb/usbfs from
* sending out a command in the middle of ours (if libusb sends a
* get_descriptor or something on pipe 0 after our CBW and before
* our CSW, and then we get a stall, we have trouble).
*/
- down(&(us->pusb_dev->exclusive_access));
+ usb_excl_lock(us->pusb_dev, 3, 0);
/* send the command to the transport layer */
result = us->transport(srb, us);
- up(&(us->pusb_dev->exclusive_access));
+ usb_excl_unlock(us->pusb_dev, 3);
/* if the command gets aborted by the higher layers, we need to
* short-circuit all other processing
@@ -757,9 +757,9 @@ void usb_stor_invoke_transport(Scsi_Cmnd
srb->use_sg = 0;
/* issue the auto-sense command */
- down(&(us->pusb_dev->exclusive_access));
+ usb_excl_lock(us->pusb_dev, 3, 0);
temp_result = us->transport(us->srb, us);
- up(&(us->pusb_dev->exclusive_access));
+ usb_excl_unlock(us->pusb_dev, 3);
/* let's clean up right away */
srb->request_buffer = old_request_buffer;
diff -urp -X dontdiff linux-2.4.32/drivers/usb/usb.c linux-2.4.32-wk/drivers/usb/usb.c
--- linux-2.4.32/drivers/usb/usb.c 2004-11-17 03:54:21.000000000 -0800
+++ linux-2.4.32-wk/drivers/usb/usb.c 2006-08-02 17:44:50.000000000 -0700
@@ -989,7 +989,8 @@ struct usb_device *usb_alloc_dev(struct
INIT_LIST_HEAD(&dev->filelist);
init_MUTEX(&dev->serialize);
- init_MUTEX(&dev->exclusive_access);
+ spin_lock_init(&dev->excl_lock);
+ init_waitqueue_head(&dev->excl_wait);
dev->bus->op->allocate(dev);
@@ -2380,6 +2381,59 @@ struct list_head *usb_bus_get_list(void)
}
#endif
+int usb_excl_lock(struct usb_device *dev, unsigned int type, int interruptible)
+{
+ DECLARE_WAITQUEUE(waita, current);
+
+ add_wait_queue(&dev->excl_wait, &waita);
+ if (interruptible)
+ set_current_state(TASK_INTERRUPTIBLE);
+ else
+ set_current_state(TASK_UNINTERRUPTIBLE);
+
+ for (;;) {
+ spin_lock_irq(&dev->excl_lock);
+ switch (type) {
+ case 1: /* 1 - read */
+ case 2: /* 2 - write */
+ case 3: /* 3 - control: excludes both read and write */
+ if ((dev->excl_type & type) == 0) {
+ dev->excl_type |= type;
+ spin_unlock_irq(&dev->excl_lock);
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&dev->excl_wait, &waita);
+ return 0;
+ }
+ break;
+ default:
+ spin_unlock_irq(&dev->excl_lock);
+ return -EINVAL;
+ }
+ spin_unlock_irq(&dev->excl_lock);
+
+ if (interruptible) {
+ schedule();
+ if (signal_pending(current)) {
+ remove_wait_queue(&dev->excl_wait, &waita);
+ return 1;
+ }
+ set_current_state(TASK_INTERRUPTIBLE);
+ } else {
+ schedule();
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ }
+ }
+}
+
+void usb_excl_unlock(struct usb_device *dev, unsigned int type)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->excl_lock, flags);
+ dev->excl_type &= ~type;
+ wake_up(&dev->excl_wait);
+ spin_unlock_irqrestore(&dev->excl_lock, flags);
+}
/*
* Init
@@ -2473,5 +2527,8 @@ EXPORT_SYMBOL(usb_unlink_urb);
EXPORT_SYMBOL(usb_control_msg);
EXPORT_SYMBOL(usb_bulk_msg);
+EXPORT_SYMBOL(usb_excl_lock);
+EXPORT_SYMBOL(usb_excl_unlock);
+
EXPORT_SYMBOL(usb_devfs_handle);
MODULE_LICENSE("GPL");
diff -urp -X dontdiff linux-2.4.32/include/linux/usb.h linux-2.4.32-wk/include/linux/usb.h
--- linux-2.4.32/include/linux/usb.h 2005-12-22 17:08:01.000000000 -0800
+++ linux-2.4.32-wk/include/linux/usb.h 2006-07-24 22:30:02.000000000 -0700
@@ -828,8 +828,19 @@ struct usb_device {
atomic_t refcnt; /* Reference count */
struct semaphore serialize;
- struct semaphore exclusive_access; /* prevent driver & proc accesses */
- /* from overlapping cmds at device */
+
+ /*
+ * This is our custom open-coded lock, similar to r/w locks in concept.
+ * It prevents drivers and /proc access from simultaneous access.
+ * Type:
+ * 0 - unlocked
+ * 1 - locked for reads
+ * 2 - locked for writes
+ * 3 - locked for everything
+ */
+ wait_queue_head_t excl_wait;
+ spinlock_t excl_lock;
+ unsigned excl_type;
unsigned int toggle[2]; /* one bit for each endpoint ([0] = IN, [1] = OUT) */
unsigned int halted[2]; /* endpoint halts; one bit per endpoint # & direction; */
@@ -904,6 +915,8 @@ extern void usb_destroy_configuration(st
int usb_get_current_frame_number (struct usb_device *usb_dev);
+int usb_excl_lock(struct usb_device *dev, unsigned int type, int interruptible);
+void usb_excl_unlock(struct usb_device *dev, unsigned int type);
/**
* usb_make_path - returns stable device path in the usb tree
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: Bug with USB proc_bulk in 2.4 kernel
2006-08-03 1:02 ` Pete Zaitcev
@ 2006-08-03 2:33 ` Willy Tarreau
2006-08-03 6:00 ` Pete Zaitcev
0 siblings, 1 reply; 26+ messages in thread
From: Willy Tarreau @ 2006-08-03 2:33 UTC (permalink / raw)
To: Pete Zaitcev; +Cc: benjamin.cherian.kernel, linux-kernel, linux-usb-devel
On Wed, Aug 02, 2006 at 06:02:16PM -0700, Pete Zaitcev wrote:
> On Wed, 2 Aug 2006 21:51:00 +0200, Willy Tarreau <w@1wt.eu> wrote:
>
> > Pete, do you consider your work as appropriate for mainline ? In this
> > case, I can queue it for 2.4.34.
>
> Yes, please use the attached patch. The one I sent for testing
> missed necessary exports. This is also tested with TEAC CD-210PU.
> I suppose the worst that can happen is that someone will complain
> about a regression in 2008 :-)
OK, fine :-)
Would you be so kind as to give me a short description about what
it really does (2-3 lines) and a signed-off line so that I can
feed the changelog appropriately please ? Otherwise, my explanations
from your previous mails might not completely match reality.
Thanks,
Willy
> -- Pete
>
> diff -urp -X dontdiff linux-2.4.32/drivers/usb/devices.c linux-2.4.32-wk/drivers/usb/devices.c
> --- linux-2.4.32/drivers/usb/devices.c 2004-11-17 03:54:21.000000000 -0800
> +++ linux-2.4.32-wk/drivers/usb/devices.c 2006-07-24 22:30:54.000000000 -0700
> @@ -392,7 +392,7 @@ static char *usb_dump_desc(char *start,
> * Grab device's exclusive_access mutex to prevent its driver or
> * devio from using this device while we are accessing it.
> */
> - down (&dev->exclusive_access);
> + usb_excl_lock(dev, 3, 0);
>
> start = usb_dump_device_descriptor(start, end, &dev->descriptor);
>
> @@ -411,7 +411,7 @@ static char *usb_dump_desc(char *start,
> }
>
> out:
> - up (&dev->exclusive_access);
> + usb_excl_unlock(dev, 3);
> return start;
> }
>
> diff -urp -X dontdiff linux-2.4.32/drivers/usb/devio.c linux-2.4.32-wk/drivers/usb/devio.c
> --- linux-2.4.32/drivers/usb/devio.c 2006-04-13 19:02:30.000000000 -0700
> +++ linux-2.4.32-wk/drivers/usb/devio.c 2006-07-30 00:27:13.000000000 -0700
> @@ -623,7 +623,12 @@ static int proc_bulk(struct dev_state *p
> free_page((unsigned long)tbuf);
> return -EINVAL;
> }
> + if (usb_excl_lock(dev, 1, 1) != 0) {
> + free_page((unsigned long)tbuf);
> + return -ERESTARTSYS;
> + }
> i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo);
> + usb_excl_unlock(dev, 1);
> if (!i && len2) {
> if (copy_to_user(bulk.data, tbuf, len2)) {
> free_page((unsigned long)tbuf);
> @@ -637,7 +642,12 @@ static int proc_bulk(struct dev_state *p
> return -EFAULT;
> }
> }
> + if (usb_excl_lock(dev, 2, 1) != 0) {
> + free_page((unsigned long)tbuf);
> + return -ERESTARTSYS;
> + }
> i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo);
> + usb_excl_unlock(dev, 2);
> }
> free_page((unsigned long)tbuf);
> if (i < 0) {
> @@ -1160,12 +1170,6 @@ static int usbdev_ioctl_exclusive(struct
> inode->i_mtime = CURRENT_TIME;
> break;
>
> - case USBDEVFS_BULK:
> - ret = proc_bulk(ps, (void *)arg);
> - if (ret >= 0)
> - inode->i_mtime = CURRENT_TIME;
> - break;
> -
> case USBDEVFS_RESETEP:
> ret = proc_resetep(ps, (void *)arg);
> if (ret >= 0)
> @@ -1259,8 +1263,13 @@ static int usbdev_ioctl(struct inode *in
> ret = proc_disconnectsignal(ps, (void *)arg);
> break;
>
> - case USBDEVFS_CONTROL:
> case USBDEVFS_BULK:
> + ret = proc_bulk(ps, (void *)arg);
> + if (ret >= 0)
> + inode->i_mtime = CURRENT_TIME;
> + break;
> +
> + case USBDEVFS_CONTROL:
> case USBDEVFS_RESETEP:
> case USBDEVFS_RESET:
> case USBDEVFS_CLEAR_HALT:
> @@ -1272,9 +1281,9 @@ static int usbdev_ioctl(struct inode *in
> case USBDEVFS_RELEASEINTERFACE:
> case USBDEVFS_IOCTL:
> ret = -ERESTARTSYS;
> - if (down_interruptible(&ps->dev->exclusive_access) == 0) {
> + if (usb_excl_lock(ps->dev, 3, 1) == 0) {
> ret = usbdev_ioctl_exclusive(ps, inode, cmd, arg);
> - up(&ps->dev->exclusive_access);
> + usb_excl_unlock(ps->dev, 3);
> }
> break;
>
> diff -urp -X dontdiff linux-2.4.32/drivers/usb/storage/transport.c linux-2.4.32-wk/drivers/usb/storage/transport.c
> --- linux-2.4.32/drivers/usb/storage/transport.c 2005-04-03 18:42:19.000000000 -0700
> +++ linux-2.4.32-wk/drivers/usb/storage/transport.c 2006-07-24 22:58:58.000000000 -0700
> @@ -628,16 +628,16 @@ void usb_stor_invoke_transport(Scsi_Cmnd
> int result;
>
> /*
> - * Grab device's exclusive_access mutex to prevent libusb/usbfs from
> + * Grab device's exclusive access lock to prevent libusb/usbfs from
> * sending out a command in the middle of ours (if libusb sends a
> * get_descriptor or something on pipe 0 after our CBW and before
> * our CSW, and then we get a stall, we have trouble).
> */
> - down(&(us->pusb_dev->exclusive_access));
> + usb_excl_lock(us->pusb_dev, 3, 0);
>
> /* send the command to the transport layer */
> result = us->transport(srb, us);
> - up(&(us->pusb_dev->exclusive_access));
> + usb_excl_unlock(us->pusb_dev, 3);
>
> /* if the command gets aborted by the higher layers, we need to
> * short-circuit all other processing
> @@ -757,9 +757,9 @@ void usb_stor_invoke_transport(Scsi_Cmnd
> srb->use_sg = 0;
>
> /* issue the auto-sense command */
> - down(&(us->pusb_dev->exclusive_access));
> + usb_excl_lock(us->pusb_dev, 3, 0);
> temp_result = us->transport(us->srb, us);
> - up(&(us->pusb_dev->exclusive_access));
> + usb_excl_unlock(us->pusb_dev, 3);
>
> /* let's clean up right away */
> srb->request_buffer = old_request_buffer;
> diff -urp -X dontdiff linux-2.4.32/drivers/usb/usb.c linux-2.4.32-wk/drivers/usb/usb.c
> --- linux-2.4.32/drivers/usb/usb.c 2004-11-17 03:54:21.000000000 -0800
> +++ linux-2.4.32-wk/drivers/usb/usb.c 2006-08-02 17:44:50.000000000 -0700
> @@ -989,7 +989,8 @@ struct usb_device *usb_alloc_dev(struct
> INIT_LIST_HEAD(&dev->filelist);
>
> init_MUTEX(&dev->serialize);
> - init_MUTEX(&dev->exclusive_access);
> + spin_lock_init(&dev->excl_lock);
> + init_waitqueue_head(&dev->excl_wait);
>
> dev->bus->op->allocate(dev);
>
> @@ -2380,6 +2381,59 @@ struct list_head *usb_bus_get_list(void)
> }
> #endif
>
> +int usb_excl_lock(struct usb_device *dev, unsigned int type, int interruptible)
> +{
> + DECLARE_WAITQUEUE(waita, current);
> +
> + add_wait_queue(&dev->excl_wait, &waita);
> + if (interruptible)
> + set_current_state(TASK_INTERRUPTIBLE);
> + else
> + set_current_state(TASK_UNINTERRUPTIBLE);
> +
> + for (;;) {
> + spin_lock_irq(&dev->excl_lock);
> + switch (type) {
> + case 1: /* 1 - read */
> + case 2: /* 2 - write */
> + case 3: /* 3 - control: excludes both read and write */
> + if ((dev->excl_type & type) == 0) {
> + dev->excl_type |= type;
> + spin_unlock_irq(&dev->excl_lock);
> + set_current_state(TASK_RUNNING);
> + remove_wait_queue(&dev->excl_wait, &waita);
> + return 0;
> + }
> + break;
> + default:
> + spin_unlock_irq(&dev->excl_lock);
> + return -EINVAL;
> + }
> + spin_unlock_irq(&dev->excl_lock);
> +
> + if (interruptible) {
> + schedule();
> + if (signal_pending(current)) {
> + remove_wait_queue(&dev->excl_wait, &waita);
> + return 1;
> + }
> + set_current_state(TASK_INTERRUPTIBLE);
> + } else {
> + schedule();
> + set_current_state(TASK_UNINTERRUPTIBLE);
> + }
> + }
> +}
> +
> +void usb_excl_unlock(struct usb_device *dev, unsigned int type)
> +{
> + unsigned long flags;
> +
> + spin_lock_irqsave(&dev->excl_lock, flags);
> + dev->excl_type &= ~type;
> + wake_up(&dev->excl_wait);
> + spin_unlock_irqrestore(&dev->excl_lock, flags);
> +}
>
> /*
> * Init
> @@ -2473,5 +2527,8 @@ EXPORT_SYMBOL(usb_unlink_urb);
> EXPORT_SYMBOL(usb_control_msg);
> EXPORT_SYMBOL(usb_bulk_msg);
>
> +EXPORT_SYMBOL(usb_excl_lock);
> +EXPORT_SYMBOL(usb_excl_unlock);
> +
> EXPORT_SYMBOL(usb_devfs_handle);
> MODULE_LICENSE("GPL");
> diff -urp -X dontdiff linux-2.4.32/include/linux/usb.h linux-2.4.32-wk/include/linux/usb.h
> --- linux-2.4.32/include/linux/usb.h 2005-12-22 17:08:01.000000000 -0800
> +++ linux-2.4.32-wk/include/linux/usb.h 2006-07-24 22:30:02.000000000 -0700
> @@ -828,8 +828,19 @@ struct usb_device {
>
> atomic_t refcnt; /* Reference count */
> struct semaphore serialize;
> - struct semaphore exclusive_access; /* prevent driver & proc accesses */
> - /* from overlapping cmds at device */
> +
> + /*
> + * This is our custom open-coded lock, similar to r/w locks in concept.
> + * It prevents drivers and /proc access from simultaneous access.
> + * Type:
> + * 0 - unlocked
> + * 1 - locked for reads
> + * 2 - locked for writes
> + * 3 - locked for everything
> + */
> + wait_queue_head_t excl_wait;
> + spinlock_t excl_lock;
> + unsigned excl_type;
>
> unsigned int toggle[2]; /* one bit for each endpoint ([0] = IN, [1] = OUT) */
> unsigned int halted[2]; /* endpoint halts; one bit per endpoint # & direction; */
> @@ -904,6 +915,8 @@ extern void usb_destroy_configuration(st
>
> int usb_get_current_frame_number (struct usb_device *usb_dev);
>
> +int usb_excl_lock(struct usb_device *dev, unsigned int type, int interruptible);
> +void usb_excl_unlock(struct usb_device *dev, unsigned int type);
>
> /**
> * usb_make_path - returns stable device path in the usb tree
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: Bug with USB proc_bulk in 2.4 kernel
2006-08-03 2:33 ` Willy Tarreau
@ 2006-08-03 6:00 ` Pete Zaitcev
2006-08-03 6:29 ` Willy Tarreau
0 siblings, 1 reply; 26+ messages in thread
From: Pete Zaitcev @ 2006-08-03 6:00 UTC (permalink / raw)
To: Willy Tarreau
Cc: benjamin.cherian.kernel, linux-kernel, linux-usb-devel, zaitcev
Replace the semaphore exclusive_access with an open-coded lock for
the special use. The lock can be taken for: read, write, and both.
This way, two bulk URBs can be submitted simultaneously with ioctl
USBDEVFS_BULK: one read and one write. Such access was possible
before 2.4.28.
Signed-off-By: Pete Zaitcev <zaitcev@redhat.com>
---
The semaphore was introduced in 2.4.28 for the purpose of exclusion
between access from device.c (cat /proc/bus/usb/devices), devio.c
through libusb, and in-kernel driver. Currently, only usb-storage
observes the locking protocol. The most popular device which locks
in case of simultaneous access is TEAC CD-210PU.
diff -urp -X dontdiff linux-2.4.32/drivers/usb/devices.c linux-2.4.32-wk/drivers/usb/devices.c
--- linux-2.4.32/drivers/usb/devices.c 2004-11-17 03:54:21.000000000 -0800
+++ linux-2.4.32-wk/drivers/usb/devices.c 2006-07-24 22:30:54.000000000 -0700
@@ -392,7 +392,7 @@ static char *usb_dump_desc(char *start,
* Grab device's exclusive_access mutex to prevent its driver or
* devio from using this device while we are accessing it.
*/
- down (&dev->exclusive_access);
+ usb_excl_lock(dev, 3, 0);
start = usb_dump_device_descriptor(start, end, &dev->descriptor);
@@ -411,7 +411,7 @@ static char *usb_dump_desc(char *start,
}
out:
- up (&dev->exclusive_access);
+ usb_excl_unlock(dev, 3);
return start;
}
diff -urp -X dontdiff linux-2.4.32/drivers/usb/devio.c linux-2.4.32-wk/drivers/usb/devio.c
--- linux-2.4.32/drivers/usb/devio.c 2006-04-13 19:02:30.000000000 -0700
+++ linux-2.4.32-wk/drivers/usb/devio.c 2006-07-30 00:27:13.000000000 -0700
@@ -623,7 +623,12 @@ static int proc_bulk(struct dev_state *p
free_page((unsigned long)tbuf);
return -EINVAL;
}
+ if (usb_excl_lock(dev, 1, 1) != 0) {
+ free_page((unsigned long)tbuf);
+ return -ERESTARTSYS;
+ }
i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo);
+ usb_excl_unlock(dev, 1);
if (!i && len2) {
if (copy_to_user(bulk.data, tbuf, len2)) {
free_page((unsigned long)tbuf);
@@ -637,7 +642,12 @@ static int proc_bulk(struct dev_state *p
return -EFAULT;
}
}
+ if (usb_excl_lock(dev, 2, 1) != 0) {
+ free_page((unsigned long)tbuf);
+ return -ERESTARTSYS;
+ }
i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo);
+ usb_excl_unlock(dev, 2);
}
free_page((unsigned long)tbuf);
if (i < 0) {
@@ -1160,12 +1170,6 @@ static int usbdev_ioctl_exclusive(struct
inode->i_mtime = CURRENT_TIME;
break;
- case USBDEVFS_BULK:
- ret = proc_bulk(ps, (void *)arg);
- if (ret >= 0)
- inode->i_mtime = CURRENT_TIME;
- break;
-
case USBDEVFS_RESETEP:
ret = proc_resetep(ps, (void *)arg);
if (ret >= 0)
@@ -1259,8 +1263,13 @@ static int usbdev_ioctl(struct inode *in
ret = proc_disconnectsignal(ps, (void *)arg);
break;
- case USBDEVFS_CONTROL:
case USBDEVFS_BULK:
+ ret = proc_bulk(ps, (void *)arg);
+ if (ret >= 0)
+ inode->i_mtime = CURRENT_TIME;
+ break;
+
+ case USBDEVFS_CONTROL:
case USBDEVFS_RESETEP:
case USBDEVFS_RESET:
case USBDEVFS_CLEAR_HALT:
@@ -1272,9 +1281,9 @@ static int usbdev_ioctl(struct inode *in
case USBDEVFS_RELEASEINTERFACE:
case USBDEVFS_IOCTL:
ret = -ERESTARTSYS;
- if (down_interruptible(&ps->dev->exclusive_access) == 0) {
+ if (usb_excl_lock(ps->dev, 3, 1) == 0) {
ret = usbdev_ioctl_exclusive(ps, inode, cmd, arg);
- up(&ps->dev->exclusive_access);
+ usb_excl_unlock(ps->dev, 3);
}
break;
diff -urp -X dontdiff linux-2.4.32/drivers/usb/storage/transport.c linux-2.4.32-wk/drivers/usb/storage/transport.c
--- linux-2.4.32/drivers/usb/storage/transport.c 2005-04-03 18:42:19.000000000 -0700
+++ linux-2.4.32-wk/drivers/usb/storage/transport.c 2006-07-24 22:58:58.000000000 -0700
@@ -628,16 +628,16 @@ void usb_stor_invoke_transport(Scsi_Cmnd
int result;
/*
- * Grab device's exclusive_access mutex to prevent libusb/usbfs from
+ * Grab device's exclusive access lock to prevent libusb/usbfs from
* sending out a command in the middle of ours (if libusb sends a
* get_descriptor or something on pipe 0 after our CBW and before
* our CSW, and then we get a stall, we have trouble).
*/
- down(&(us->pusb_dev->exclusive_access));
+ usb_excl_lock(us->pusb_dev, 3, 0);
/* send the command to the transport layer */
result = us->transport(srb, us);
- up(&(us->pusb_dev->exclusive_access));
+ usb_excl_unlock(us->pusb_dev, 3);
/* if the command gets aborted by the higher layers, we need to
* short-circuit all other processing
@@ -757,9 +757,9 @@ void usb_stor_invoke_transport(Scsi_Cmnd
srb->use_sg = 0;
/* issue the auto-sense command */
- down(&(us->pusb_dev->exclusive_access));
+ usb_excl_lock(us->pusb_dev, 3, 0);
temp_result = us->transport(us->srb, us);
- up(&(us->pusb_dev->exclusive_access));
+ usb_excl_unlock(us->pusb_dev, 3);
/* let's clean up right away */
srb->request_buffer = old_request_buffer;
diff -urp -X dontdiff linux-2.4.32/drivers/usb/usb.c linux-2.4.32-wk/drivers/usb/usb.c
--- linux-2.4.32/drivers/usb/usb.c 2004-11-17 03:54:21.000000000 -0800
+++ linux-2.4.32-wk/drivers/usb/usb.c 2006-08-02 22:56:53.000000000 -0700
@@ -989,7 +989,8 @@ struct usb_device *usb_alloc_dev(struct
INIT_LIST_HEAD(&dev->filelist);
init_MUTEX(&dev->serialize);
- init_MUTEX(&dev->exclusive_access);
+ spin_lock_init(&dev->excl_lock);
+ init_waitqueue_head(&dev->excl_wait);
dev->bus->op->allocate(dev);
@@ -2380,6 +2381,61 @@ struct list_head *usb_bus_get_list(void)
}
#endif
+int usb_excl_lock(struct usb_device *dev, unsigned int type, int interruptible)
+{
+ DECLARE_WAITQUEUE(waita, current);
+
+ add_wait_queue(&dev->excl_wait, &waita);
+ if (interruptible)
+ set_current_state(TASK_INTERRUPTIBLE);
+ else
+ set_current_state(TASK_UNINTERRUPTIBLE);
+
+ for (;;) {
+ spin_lock_irq(&dev->excl_lock);
+ switch (type) {
+ case 1: /* 1 - read */
+ case 2: /* 2 - write */
+ case 3: /* 3 - control: excludes both read and write */
+ if ((dev->excl_type & type) == 0) {
+ dev->excl_type |= type;
+ spin_unlock_irq(&dev->excl_lock);
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&dev->excl_wait, &waita);
+ return 0;
+ }
+ break;
+ default:
+ spin_unlock_irq(&dev->excl_lock);
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&dev->excl_wait, &waita);
+ return -EINVAL;
+ }
+ spin_unlock_irq(&dev->excl_lock);
+
+ if (interruptible) {
+ schedule();
+ if (signal_pending(current)) {
+ remove_wait_queue(&dev->excl_wait, &waita);
+ return 1;
+ }
+ set_current_state(TASK_INTERRUPTIBLE);
+ } else {
+ schedule();
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ }
+ }
+}
+
+void usb_excl_unlock(struct usb_device *dev, unsigned int type)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->excl_lock, flags);
+ dev->excl_type &= ~type;
+ wake_up(&dev->excl_wait);
+ spin_unlock_irqrestore(&dev->excl_lock, flags);
+}
/*
* Init
@@ -2473,5 +2529,8 @@ EXPORT_SYMBOL(usb_unlink_urb);
EXPORT_SYMBOL(usb_control_msg);
EXPORT_SYMBOL(usb_bulk_msg);
+EXPORT_SYMBOL(usb_excl_lock);
+EXPORT_SYMBOL(usb_excl_unlock);
+
EXPORT_SYMBOL(usb_devfs_handle);
MODULE_LICENSE("GPL");
diff -urp -X dontdiff linux-2.4.32/include/linux/usb.h linux-2.4.32-wk/include/linux/usb.h
--- linux-2.4.32/include/linux/usb.h 2005-12-22 17:08:01.000000000 -0800
+++ linux-2.4.32-wk/include/linux/usb.h 2006-07-24 22:30:02.000000000 -0700
@@ -828,8 +828,19 @@ struct usb_device {
atomic_t refcnt; /* Reference count */
struct semaphore serialize;
- struct semaphore exclusive_access; /* prevent driver & proc accesses */
- /* from overlapping cmds at device */
+
+ /*
+ * This is our custom open-coded lock, similar to r/w locks in concept.
+ * It prevents drivers and /proc access from simultaneous access.
+ * Type:
+ * 0 - unlocked
+ * 1 - locked for reads
+ * 2 - locked for writes
+ * 3 - locked for everything
+ */
+ wait_queue_head_t excl_wait;
+ spinlock_t excl_lock;
+ unsigned excl_type;
unsigned int toggle[2]; /* one bit for each endpoint ([0] = IN, [1] = OUT) */
unsigned int halted[2]; /* endpoint halts; one bit per endpoint # & direction; */
@@ -904,6 +915,8 @@ extern void usb_destroy_configuration(st
int usb_get_current_frame_number (struct usb_device *usb_dev);
+int usb_excl_lock(struct usb_device *dev, unsigned int type, int interruptible);
+void usb_excl_unlock(struct usb_device *dev, unsigned int type);
/**
* usb_make_path - returns stable device path in the usb tree
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: Bug with USB proc_bulk in 2.4 kernel
2006-08-03 6:00 ` Pete Zaitcev
@ 2006-08-03 6:29 ` Willy Tarreau
2006-08-04 16:57 ` Benjamin Cherian
0 siblings, 1 reply; 26+ messages in thread
From: Willy Tarreau @ 2006-08-03 6:29 UTC (permalink / raw)
To: Pete Zaitcev; +Cc: benjamin.cherian.kernel, linux-kernel, linux-usb-devel
On Wed, Aug 02, 2006 at 11:00:58PM -0700, Pete Zaitcev wrote:
> Replace the semaphore exclusive_access with an open-coded lock for
> the special use. The lock can be taken for: read, write, and both.
> This way, two bulk URBs can be submitted simultaneously with ioctl
> USBDEVFS_BULK: one read and one write. Such access was possible
> before 2.4.28.
>
> Signed-off-By: Pete Zaitcev <zaitcev@redhat.com>
>
> ---
>
> The semaphore was introduced in 2.4.28 for the purpose of exclusion
> between access from device.c (cat /proc/bus/usb/devices), devio.c
> through libusb, and in-kernel driver. Currently, only usb-storage
> observes the locking protocol. The most popular device which locks
> in case of simultaneous access is TEAC CD-210PU.
Perfect. Patch queued, thanks Pete.
Willy
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: Bug with USB proc_bulk in 2.4 kernel
2006-08-04 16:57 ` Benjamin Cherian
@ 2006-08-04 16:55 ` Willy Tarreau
2006-08-09 17:01 ` Benjamin Cherian
0 siblings, 1 reply; 26+ messages in thread
From: Willy Tarreau @ 2006-08-04 16:55 UTC (permalink / raw)
To: Benjamin Cherian
Cc: Pete Zaitcev, linux-kernel, linux-usb-devel, mtosatti, marcelo
On Fri, Aug 04, 2006 at 09:57:04AM -0700, Benjamin Cherian wrote:
> Willy,
>
> On Wednesday 02 August 2006 23:29, Willy Tarreau wrote:
> > Perfect. Patch queued, thanks Pete.
>
> Do you know if it would be possible for this to get into 2.4.33? I know its
> already at rc3, but it would be nice if this patch could be pushed out sooner
> since 2.4.34 will probably not be out for a while. I would really appreciate
> it. Thanks to both you and Pete for your help.
The problem is that Marcelo is very very busy those days (as you might have
noticed from the delay between each release), and there are a good bunch of
security fixes in -rc3 which should wait too much in -rc. Maybe an -rc4
would be OK, but I don't know if Marcelo has enough time to spend on yet
another RC. Otherwise, if I produce a 2.4.34-pre1 about one week after 2.4.33,
does that fit your needs ? I already have a few fixes waiting which might be
worth a first pre-release.
> Ben
Regards,
Willy
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: Bug with USB proc_bulk in 2.4 kernel
2006-08-03 6:29 ` Willy Tarreau
@ 2006-08-04 16:57 ` Benjamin Cherian
2006-08-04 16:55 ` Willy Tarreau
0 siblings, 1 reply; 26+ messages in thread
From: Benjamin Cherian @ 2006-08-04 16:57 UTC (permalink / raw)
To: Willy Tarreau; +Cc: Pete Zaitcev, linux-kernel, linux-usb-devel
Willy,
On Wednesday 02 August 2006 23:29, Willy Tarreau wrote:
> Perfect. Patch queued, thanks Pete.
Do you know if it would be possible for this to get into 2.4.33? I know its
already at rc3, but it would be nice if this patch could be pushed out sooner
since 2.4.34 will probably not be out for a while. I would really appreciate
it. Thanks to both you and Pete for your help.
Ben
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: Bug with USB proc_bulk in 2.4 kernel
2006-08-04 16:55 ` Willy Tarreau
@ 2006-08-09 17:01 ` Benjamin Cherian
2006-08-09 17:02 ` Willy Tarreau
0 siblings, 1 reply; 26+ messages in thread
From: Benjamin Cherian @ 2006-08-09 17:01 UTC (permalink / raw)
To: Willy Tarreau
Cc: Pete Zaitcev, linux-kernel, linux-usb-devel, mtosatti, marcelo
Willy,
Sorry I didn't notice your email till now.
On Friday 04 August 2006 09:55, Willy Tarreau wrote:
> The problem is that Marcelo is very very busy those days (as you might have
> noticed from the delay between each release), and there are a good bunch of
> security fixes in -rc3 which should wait too much in -rc. Maybe an -rc4
> would be OK, but I don't know if Marcelo has enough time to spend on yet
> another RC. Otherwise, if I produce a 2.4.34-pre1 about one week after
> 2.4.33, does that fit your needs ? I already have a few fixes waiting which
> might be worth a first pre-release.
It would be nice if you could do another rc, because otherwise it seems the
patch wouldn't get into a stable kernel for a long time. But if it's really
too much work for Marcelo, I would understand you putting it in th 2.4.34
pre-release.
Thanks again,
Ben
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: Bug with USB proc_bulk in 2.4 kernel
2006-08-09 17:01 ` Benjamin Cherian
@ 2006-08-09 17:02 ` Willy Tarreau
2006-08-12 0:14 ` Marcelo Tosatti
0 siblings, 1 reply; 26+ messages in thread
From: Willy Tarreau @ 2006-08-09 17:02 UTC (permalink / raw)
To: Benjamin Cherian
Cc: Pete Zaitcev, linux-kernel, linux-usb-devel, mtosatti, marcelo
Hi Benjamin,
On Wed, Aug 09, 2006 at 10:01:41AM -0700, Benjamin Cherian wrote:
> Willy,
> Sorry I didn't notice your email till now.
no problem.
> On Friday 04 August 2006 09:55, Willy Tarreau wrote:
> > The problem is that Marcelo is very very busy those days (as you might have
> > noticed from the delay between each release), and there are a good bunch of
> > security fixes in -rc3 which should wait too much in -rc. Maybe an -rc4
> > would be OK, but I don't know if Marcelo has enough time to spend on yet
> > another RC. Otherwise, if I produce a 2.4.34-pre1 about one week after
> > 2.4.33, does that fit your needs ? I already have a few fixes waiting which
> > might be worth a first pre-release.
>
> It would be nice if you could do another rc, because otherwise it seems the
> patch wouldn't get into a stable kernel for a long time. But if it's really
> too much work for Marcelo, I would understand you putting it in th 2.4.34
> pre-release.
The real problem is that Marcelo seems to be *very* busy. I failed to get
any contact from him from one week now. It's even becoming worrying, I hope
he's alright. I don't know how much time it would take him to produce another
release, but it will for sure delay 2.4.33 for a few weeks during which Marcelo
will still be bound to this time-consuming task. It's left to him to decide
anyway. In normal ciscumstances, I would for sure add another -rc, but delays
get stretched too far given the number of vulnerabilities fixed in 2.4.33.
> Thanks again,
> Ben
Regards,
Willy
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: Bug with USB proc_bulk in 2.4 kernel
2006-08-09 17:02 ` Willy Tarreau
@ 2006-08-12 0:14 ` Marcelo Tosatti
2006-08-12 3:21 ` Willy Tarreau
0 siblings, 1 reply; 26+ messages in thread
From: Marcelo Tosatti @ 2006-08-12 0:14 UTC (permalink / raw)
To: Willy Tarreau
Cc: Benjamin Cherian, Pete Zaitcev, linux-kernel, linux-usb-devel, marcelo
On Wed, Aug 09, 2006 at 07:02:01PM +0200, Willy Tarreau wrote:
> Hi Benjamin,
>
> On Wed, Aug 09, 2006 at 10:01:41AM -0700, Benjamin Cherian wrote:
> > Willy,
> > Sorry I didn't notice your email till now.
>
> no problem.
>
> > On Friday 04 August 2006 09:55, Willy Tarreau wrote:
> > > The problem is that Marcelo is very very busy those days (as you might have
> > > noticed from the delay between each release), and there are a good bunch of
> > > security fixes in -rc3 which should wait too much in -rc. Maybe an -rc4
> > > would be OK, but I don't know if Marcelo has enough time to spend on yet
> > > another RC. Otherwise, if I produce a 2.4.34-pre1 about one week after
> > > 2.4.33, does that fit your needs ? I already have a few fixes waiting which
> > > might be worth a first pre-release.
> >
> > It would be nice if you could do another rc, because otherwise it seems the
> > patch wouldn't get into a stable kernel for a long time. But if it's really
> > too much work for Marcelo, I would understand you putting it in th 2.4.34
> > pre-release.
>
> The real problem is that Marcelo seems to be *very* busy. I failed to get
> any contact from him from one week now. It's even becoming worrying, I hope
> he's alright. I don't know how much time it would take him to produce another
> release, but it will for sure delay 2.4.33 for a few weeks during which Marcelo
> will still be bound to this time-consuming task. It's left to him to decide
> anyway. In normal ciscumstances, I would for sure add another -rc, but delays
> get stretched too far given the number of vulnerabilities fixed in 2.4.33.
The reason for so much delay was a serious accident which resulted in 2
weeks of hospitalization with no Internet connnectivity (and no mental
state for work).
Sorry about that.
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: Bug with USB proc_bulk in 2.4 kernel
2006-08-12 0:14 ` Marcelo Tosatti
@ 2006-08-12 3:21 ` Willy Tarreau
0 siblings, 0 replies; 26+ messages in thread
From: Willy Tarreau @ 2006-08-12 3:21 UTC (permalink / raw)
To: Marcelo Tosatti
Cc: Benjamin Cherian, Pete Zaitcev, linux-kernel, linux-usb-devel, marcelo
On Fri, Aug 11, 2006 at 09:14:57PM -0300, Marcelo Tosatti wrote:
>
> The reason for so much delay was a serious accident which resulted in 2
> weeks of hospitalization with no Internet connnectivity (and no mental
> state for work).
>
> Sorry about that.
Hey Marcelo,
you don't have to apologize for this !!! I think that everybody's already
very happy that you released 2.4.33 as soon as you left the hospital !
I wish you a good and fast recovery.
Cheers,
Willy
^ permalink raw reply [flat|nested] 26+ messages in thread
end of thread, other threads:[~2006-08-12 3:40 UTC | newest]
Thread overview: 26+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
[not found] <mailman.1152332281.24203.linux-kernel2news@redhat.com>
2006-07-08 20:28 ` Bug with USB proc_bulk in 2.4 kernel and possibly bug in proc_ioctl in 2.6 Pete Zaitcev
2006-07-10 19:58 ` Bug with USB proc_bulk in 2.4 kernel Benjamin Cherian
2006-07-10 20:40 ` Pete Zaitcev
2006-07-17 21:35 ` Benjamin Cherian
2006-07-17 22:19 ` Pete Zaitcev
2006-07-18 17:04 ` Benjamin Cherian
2006-07-19 1:33 ` Pete Zaitcev
2006-07-20 17:43 ` Benjamin Cherian
2006-07-25 6:07 ` Pete Zaitcev
2006-07-25 19:31 ` Willy Tarreau
2006-07-27 22:21 ` Benjamin Cherian
2006-07-27 23:49 ` Pete Zaitcev
2006-07-28 17:37 ` Benjamin Cherian
2006-07-30 7:35 ` Pete Zaitcev
2006-07-31 18:41 ` Benjamin Cherian
2006-08-02 19:51 ` Willy Tarreau
2006-08-03 1:02 ` Pete Zaitcev
2006-08-03 2:33 ` Willy Tarreau
2006-08-03 6:00 ` Pete Zaitcev
2006-08-03 6:29 ` Willy Tarreau
2006-08-04 16:57 ` Benjamin Cherian
2006-08-04 16:55 ` Willy Tarreau
2006-08-09 17:01 ` Benjamin Cherian
2006-08-09 17:02 ` Willy Tarreau
2006-08-12 0:14 ` Marcelo Tosatti
2006-08-12 3:21 ` Willy Tarreau
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).