ChangeSet 1.1722.83.9, 2004/06/02 13:49:28-07:00, oliver@neukum.org [PATCH] USB: fix racy access to urb->status in cdc acm driver Hi, fix access to urb->status by introduction of an explicit flag for finished data transfer. - fix racy access to urb->status Signed-off-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman drivers/usb/class/cdc-acm.c | 16 ++++++++++------ drivers/usb/class/cdc-acm.h | 1 + 2 files changed, 11 insertions(+), 6 deletions(-) diff -Nru a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c --- a/drivers/usb/class/cdc-acm.c Fri Jun 18 11:05:57 2004 +++ b/drivers/usb/class/cdc-acm.c Fri Jun 18 11:05:57 2004 @@ -223,12 +223,14 @@ struct acm *acm = (struct acm *)urb->context; if (!ACM_READY(acm)) - return; + goto out; if (urb->status) dbg("nonzero write bulk status received: %d", urb->status); schedule_work(&acm->work); +out: + acm->ready_for_write = 1; } static void acm_softint(void *private) @@ -328,7 +330,7 @@ if (!ACM_READY(acm)) return -EINVAL; - if (acm->writeurb->status == -EINPROGRESS) + if (!acm->ready_for_write) return 0; if (!count) return 0; @@ -344,10 +346,11 @@ acm->writeurb->transfer_buffer_length = count; acm->writeurb->dev = acm->dev; - /* GFP_KERNEL probably works if from_user */ - stat = usb_submit_urb(acm->writeurb, GFP_ATOMIC); + acm->ready_for_write = 0; + stat = usb_submit_urb(acm->writeurb, GFP_NOIO); if (stat < 0) { dbg("usb_submit_urb(write bulk) failed"); + acm->ready_for_write = 1; return stat; } @@ -359,7 +362,7 @@ struct acm *acm = tty->driver_data; if (!ACM_READY(acm)) return -EINVAL; - return acm->writeurb->status == -EINPROGRESS ? 0 : acm->writesize; + return !acm->ready_for_write ? 0 : acm->writesize; } static int acm_tty_chars_in_buffer(struct tty_struct *tty) @@ -367,7 +370,7 @@ struct acm *acm = tty->driver_data; if (!ACM_READY(acm)) return -EINVAL; - return acm->writeurb->status == -EINPROGRESS ? acm->writeurb->transfer_buffer_length : 0; + return !acm->ready_for_write ? acm->writeurb->transfer_buffer_length : 0; } static void acm_tty_throttle(struct tty_struct *tty) @@ -610,6 +613,7 @@ acm->bh.func = acm_rx_tasklet; acm->bh.data = (unsigned long) acm; INIT_WORK(&acm->work, acm_softint, acm); + acm->ready_for_write = 1; if (!(buf = kmalloc(ctrlsize + readsize + acm->writesize, GFP_KERNEL))) { diff -Nru a/drivers/usb/class/cdc-acm.h b/drivers/usb/class/cdc-acm.h --- a/drivers/usb/class/cdc-acm.h Fri Jun 18 11:05:57 2004 +++ b/drivers/usb/class/cdc-acm.h Fri Jun 18 11:05:57 2004 @@ -96,6 +96,7 @@ unsigned int minor; /* acm minor number */ unsigned char throttle; /* throttled by tty layer */ unsigned char clocal; /* termios CLOCAL */ + unsigned char ready_for_write; /* write urb can be used */ }; /* "Union Functional Descriptor" from CDC spec 5.2.3.X */