Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

usb: cdc-wdm: use irqsave() in USB's complete callback

The USB completion callback does not disable interrupts while acquiring
the lock. We want to remove the local_irq_disable() invocation from
__usb_hcd_giveback_urb() and therefore it is required for the callback
handler to disable the interrupts while acquiring the lock.
The callback may be invoked either in IRQ or BH context depending on the
USB host controller.
Use the _irqsave() variant of the locking primitives.

Cc: Oliver Neukum <oneukum@suse.com>
Cc: "Bjørn Mork" <bjorn@mork.no>
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Sebastian Andrzej Siewior and committed by
Greg Kroah-Hartman
579b9cca 24b2068e

+10 -6
+10 -6
drivers/usb/class/cdc-wdm.c
··· 142 142 static void wdm_out_callback(struct urb *urb) 143 143 { 144 144 struct wdm_device *desc; 145 + unsigned long flags; 146 + 145 147 desc = urb->context; 146 - spin_lock(&desc->iuspin); 148 + spin_lock_irqsave(&desc->iuspin, flags); 147 149 desc->werr = urb->status; 148 - spin_unlock(&desc->iuspin); 150 + spin_unlock_irqrestore(&desc->iuspin, flags); 149 151 kfree(desc->outbuf); 150 152 desc->outbuf = NULL; 151 153 clear_bit(WDM_IN_USE, &desc->flags); ··· 156 154 157 155 static void wdm_in_callback(struct urb *urb) 158 156 { 157 + unsigned long flags; 159 158 struct wdm_device *desc = urb->context; 160 159 int status = urb->status; 161 160 int length = urb->actual_length; 162 161 163 - spin_lock(&desc->iuspin); 162 + spin_lock_irqsave(&desc->iuspin, flags); 164 163 clear_bit(WDM_RESPONDING, &desc->flags); 165 164 166 165 if (status) { ··· 223 220 set_bit(WDM_READ, &desc->flags); 224 221 wake_up(&desc->wait); 225 222 } 226 - spin_unlock(&desc->iuspin); 223 + spin_unlock_irqrestore(&desc->iuspin, flags); 227 224 } 228 225 229 226 static void wdm_int_callback(struct urb *urb) 230 227 { 228 + unsigned long flags; 231 229 int rv = 0; 232 230 int responding; 233 231 int status = urb->status; ··· 288 284 goto exit; 289 285 } 290 286 291 - spin_lock(&desc->iuspin); 287 + spin_lock_irqsave(&desc->iuspin, flags); 292 288 responding = test_and_set_bit(WDM_RESPONDING, &desc->flags); 293 289 if (!desc->resp_count++ && !responding 294 290 && !test_bit(WDM_DISCONNECTING, &desc->flags) ··· 296 292 rv = usb_submit_urb(desc->response, GFP_ATOMIC); 297 293 dev_dbg(&desc->intf->dev, "submit response URB %d\n", rv); 298 294 } 299 - spin_unlock(&desc->iuspin); 295 + spin_unlock_irqrestore(&desc->iuspin, flags); 300 296 if (rv < 0) { 301 297 clear_bit(WDM_RESPONDING, &desc->flags); 302 298 if (rv == -EPERM)