2013-07-11 09:06:37

by Ming Lei

[permalink] [raw]
Subject: [PATCH 00/50] USB: cleanup spin_lock in URB->complete()

Hi,

As we are going to run URB->complete() in tasklet context[1][2], and
hard interrupt may be enabled when running URB completion handler[3],
so we might need to disable interrupt when acquiring one lock in
the completion handler for the below reasons:

- URB->complete() holds a subsystem wide lock which may be acquired
in another hard irq context, and the subsystem wide lock is acquired
by spin_lock()/read_lock()/write_lock() in complete()

- URB->complete() holds a private lock with spin_lock()/read_lock()/write_lock()
but driver may export APIs to make other drivers acquire the same private
lock in its interrupt handler.

For the sake of safety and making the change simple, this patch set
converts all spin_lock()/read_lock()/write_lock() in completion handler
path into their irqsave version mechanically.

But if you are sure the above two cases do not happen in your driver,
please let me know and I can drop the unnecessary change.

Also if you find some conversions are missed, also please let me know so
that I can add it in the next round.


[1], http://marc.info/?l=linux-usb&m=137286322526312&w=2
[2], http://marc.info/?l=linux-usb&m=137286326726326&w=2
[3], http://marc.info/?l=linux-usb&m=137286330626363&w=2

drivers/bluetooth/bfusb.c | 12 ++++----
drivers/bluetooth/btusb.c | 5 ++--
drivers/hid/usbhid/hid-core.c | 5 ++--
drivers/input/misc/cm109.c | 10 ++++---
drivers/isdn/hardware/mISDN/hfcsusb.c | 36 ++++++++++++-----------
drivers/media/dvb-core/dvb_demux.c | 17 +++++++----
drivers/media/usb/cx231xx/cx231xx-audio.c | 6 ++++
drivers/media/usb/cx231xx/cx231xx-core.c | 10 ++++---
drivers/media/usb/cx231xx/cx231xx-vbi.c | 5 ++--
drivers/media/usb/em28xx/em28xx-audio.c | 3 ++
drivers/media/usb/em28xx/em28xx-core.c | 5 ++--
drivers/media/usb/sn9c102/sn9c102_core.c | 7 +++--
drivers/media/usb/tlg2300/pd-alsa.c | 3 ++
drivers/media/usb/tlg2300/pd-video.c | 5 ++--
drivers/media/usb/tm6000/tm6000-video.c | 5 ++--
drivers/net/usb/cdc-phonet.c | 5 ++--
drivers/net/usb/hso.c | 38 ++++++++++++++-----------
drivers/net/usb/kaweth.c | 7 +++--
drivers/net/usb/rtl8150.c | 5 ++--
drivers/net/wireless/ath/ath9k/hif_usb.c | 29 ++++++++++---------
drivers/net/wireless/ath/ath9k/htc_drv_txrx.c | 9 +++---
drivers/net/wireless/ath/ath9k/wmi.c | 11 +++----
drivers/net/wireless/ath/carl9170/rx.c | 5 ++--
drivers/net/wireless/libertas/if_usb.c | 5 ++--
drivers/net/wireless/libertas_tf/if_usb.c | 6 ++--
drivers/net/wireless/zd1211rw/zd_usb.c | 21 ++++++++------
drivers/staging/bcm/InterfaceRx.c | 5 ++--
drivers/staging/btmtk_usb/btmtk_usb.c | 5 ++--
drivers/staging/ced1401/usb1401.c | 35 ++++++++++++-----------
drivers/staging/vt6656/usbpipe.c | 9 +++---
drivers/usb/class/cdc-wdm.c | 16 +++++++----
drivers/usb/class/usblp.c | 10 ++++---
drivers/usb/core/devio.c | 5 ++--
drivers/usb/misc/adutux.c | 10 ++++---
drivers/usb/misc/iowarrior.c | 5 ++--
drivers/usb/misc/ldusb.c | 7 +++--
drivers/usb/misc/legousbtower.c | 5 ++--
drivers/usb/misc/usbtest.c | 10 ++++---
drivers/usb/misc/uss720.c | 6 +++-
drivers/usb/serial/cyberjack.c | 15 ++++++----
drivers/usb/serial/digi_acceleport.c | 23 ++++++++-------
drivers/usb/serial/io_edgeport.c | 14 +++++----
drivers/usb/serial/io_ti.c | 5 ++--
drivers/usb/serial/mos7720.c | 5 ++--
drivers/usb/serial/mos7840.c | 5 ++--
drivers/usb/serial/quatech2.c | 5 ++--
drivers/usb/serial/sierra.c | 9 +++---
drivers/usb/serial/symbolserial.c | 5 ++--
drivers/usb/serial/ti_usb_3410_5052.c | 9 +++---
drivers/usb/serial/usb_wwan.c | 5 ++--
sound/usb/caiaq/audio.c | 5 ++--
sound/usb/midi.c | 5 ++--
sound/usb/misc/ua101.c | 14 +++++++--
sound/usb/usx2y/usbusx2yaudio.c | 4 +++
54 files changed, 322 insertions(+), 209 deletions(-)


Thanks,
--
Ming Lei



2013-07-11 09:09:43

by Ming Lei

[permalink] [raw]
Subject: [PATCH 23/50] BT: bfusb: read_lock in complete() cleanup

Complete() will be run with interrupt enabled, so change to
read_lock_irqsave().

Cc: Marcel Holtmann <[email protected]>
Cc: Gustavo Padovan <[email protected]>
Cc: Johan Hedberg <[email protected]>
Cc: [email protected]
Signed-off-by: Ming Lei <[email protected]>
---
drivers/bluetooth/bfusb.c | 12 +++++++-----
1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/drivers/bluetooth/bfusb.c b/drivers/bluetooth/bfusb.c
index 995aee9..2e93501 100644
--- a/drivers/bluetooth/bfusb.c
+++ b/drivers/bluetooth/bfusb.c
@@ -186,6 +186,7 @@ static void bfusb_tx_complete(struct urb *urb)
{
struct sk_buff *skb = (struct sk_buff *) urb->context;
struct bfusb_data *data = (struct bfusb_data *) skb->dev;
+ unsigned long flags;

BT_DBG("bfusb %p urb %p skb %p len %d", data, urb, skb, skb->len);

@@ -199,14 +200,14 @@ static void bfusb_tx_complete(struct urb *urb)
else
data->hdev->stat.err_tx++;

- read_lock(&data->lock);
+ read_lock_irqsave(&data->lock, flags);

skb_unlink(skb, &data->pending_q);
skb_queue_tail(&data->completed_q, skb);

bfusb_tx_wakeup(data);

- read_unlock(&data->lock);
+ read_unlock_irqrestore(&data->lock, flags);
}


@@ -347,10 +348,11 @@ static void bfusb_rx_complete(struct urb *urb)
unsigned char *buf = urb->transfer_buffer;
int count = urb->actual_length;
int err, hdr, len;
+ unsigned long flags;

BT_DBG("bfusb %p urb %p skb %p len %d", data, urb, skb, skb->len);

- read_lock(&data->lock);
+ read_lock_irqsave(&data->lock, flags);

if (!test_bit(HCI_RUNNING, &data->hdev->flags))
goto unlock;
@@ -392,7 +394,7 @@ static void bfusb_rx_complete(struct urb *urb)

bfusb_rx_submit(data, urb);

- read_unlock(&data->lock);
+ read_unlock_irqrestore(&data->lock, flags);

return;

@@ -406,7 +408,7 @@ resubmit:
}

unlock:
- read_unlock(&data->lock);
+ read_unlock_irqrestore(&data->lock, flags);
}

static int bfusb_open(struct hci_dev *hdev)
--
1.7.9.5


2013-07-11 09:07:58

by Ming Lei

[permalink] [raw]
Subject: [PATCH 10/50] USB: serial: cyberjack: spin_lock in complete() cleanup

Complete() will be run with interrupt enabled, so change to
spin_lock_irqsave().

Cc: Matthias Bruestle and Harald Welte <[email protected]>
Signed-off-by: Ming Lei <[email protected]>
---
drivers/usb/serial/cyberjack.c | 15 +++++++++------
1 file changed, 9 insertions(+), 6 deletions(-)

diff --git a/drivers/usb/serial/cyberjack.c b/drivers/usb/serial/cyberjack.c
index 7814262..0ab0957 100644
--- a/drivers/usb/serial/cyberjack.c
+++ b/drivers/usb/serial/cyberjack.c
@@ -271,11 +271,12 @@ static void cyberjack_read_int_callback(struct urb *urb)
/* React only to interrupts signaling a bulk_in transfer */
if (urb->actual_length == 4 && data[0] == 0x01) {
short old_rdtodo;
+ unsigned long flags;

/* This is a announcement of coming bulk_ins. */
unsigned short size = ((unsigned short)data[3]<<8)+data[2]+3;

- spin_lock(&priv->lock);
+ spin_lock_irqsave(&priv->lock, flags);

old_rdtodo = priv->rdtodo;

@@ -290,7 +291,7 @@ static void cyberjack_read_int_callback(struct urb *urb)

dev_dbg(dev, "%s - rdtodo: %d\n", __func__, priv->rdtodo);

- spin_unlock(&priv->lock);
+ spin_unlock_irqrestore(&priv->lock, flags);

if (!old_rdtodo) {
result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
@@ -317,6 +318,7 @@ static void cyberjack_read_bulk_callback(struct urb *urb)
short todo;
int result;
int status = urb->status;
+ unsigned long flags;

usb_serial_debug_data(dev, __func__, urb->actual_length, data);
if (status) {
@@ -330,7 +332,7 @@ static void cyberjack_read_bulk_callback(struct urb *urb)
tty_flip_buffer_push(&port->port);
}

- spin_lock(&priv->lock);
+ spin_lock_irqsave(&priv->lock, flags);

/* Reduce urbs to do by one. */
priv->rdtodo -= urb->actual_length;
@@ -339,7 +341,7 @@ static void cyberjack_read_bulk_callback(struct urb *urb)
priv->rdtodo = 0;
todo = priv->rdtodo;

- spin_unlock(&priv->lock);
+ spin_unlock_irqrestore(&priv->lock, flags);

dev_dbg(dev, "%s - rdtodo: %d\n", __func__, todo);

@@ -359,6 +361,7 @@ static void cyberjack_write_bulk_callback(struct urb *urb)
struct cyberjack_private *priv = usb_get_serial_port_data(port);
struct device *dev = &port->dev;
int status = urb->status;
+ unsigned long flags;

set_bit(0, &port->write_urbs_free);
if (status) {
@@ -367,7 +370,7 @@ static void cyberjack_write_bulk_callback(struct urb *urb)
return;
}

- spin_lock(&priv->lock);
+ spin_lock_irqsave(&priv->lock, flags);

/* only do something if we have more data to send */
if (priv->wrfilled) {
@@ -411,7 +414,7 @@ static void cyberjack_write_bulk_callback(struct urb *urb)
}

exit:
- spin_unlock(&priv->lock);
+ spin_unlock_irqrestore(&priv->lock, flags);
usb_serial_port_softint(port);
}

--
1.7.9.5


2013-07-11 09:08:46

by Ming Lei

[permalink] [raw]
Subject: [PATCH 16/50] USB: serial: quatech2: spin_lock in complete() cleanup

Complete() will be run with interrupt enabled, so change to
spin_lock_irqsave().

Cc: Johan Hovold <[email protected]>
Signed-off-by: Ming Lei <[email protected]>
---
drivers/usb/serial/quatech2.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/usb/serial/quatech2.c b/drivers/usb/serial/quatech2.c
index d997432..95e5dbf 100644
--- a/drivers/usb/serial/quatech2.c
+++ b/drivers/usb/serial/quatech2.c
@@ -630,16 +630,17 @@ static void qt2_write_bulk_callback(struct urb *urb)
{
struct usb_serial_port *port;
struct qt2_port_private *port_priv;
+ unsigned long flags;

port = urb->context;
port_priv = usb_get_serial_port_data(port);

- spin_lock(&port_priv->urb_lock);
+ spin_lock_irqsave(&port_priv->urb_lock, flags);

port_priv->urb_in_use = false;
usb_serial_port_softint(port);

- spin_unlock(&port_priv->urb_lock);
+ spin_unlock_irqrestore(&port_priv->urb_lock, flags);

}

--
1.7.9.5


2013-07-11 13:02:08

by Sergei Shtylyov

[permalink] [raw]
Subject: Re: [PATCH 17/50] USB: serial: sierra: spin_lock in complete() cleanup

Hello.

On 11-07-2013 13:05, Ming Lei wrote:

> Complete() will be run with interrupt enabled, so change to
> spin_lock_irqsave().

> Cc: Johan Hovold <[email protected]>
> Signed-off-by: Ming Lei <[email protected]>
> ---
> drivers/usb/serial/sierra.c | 9 +++++----
> 1 file changed, 5 insertions(+), 4 deletions(-)

> diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c
> index de958c5..e79b6ad 100644
> --- a/drivers/usb/serial/sierra.c
> +++ b/drivers/usb/serial/sierra.c
> @@ -433,6 +433,7 @@ static void sierra_outdat_callback(struct urb *urb)
> struct sierra_port_private *portdata = usb_get_serial_port_data(port);
> struct sierra_intf_private *intfdata;
> int status = urb->status;
> + unsigned long flags;
>
> intfdata = port->serial->private;
>
> @@ -443,12 +444,12 @@ static void sierra_outdat_callback(struct urb *urb)
> dev_dbg(&port->dev, "%s - nonzero write bulk status "
> "received: %d\n", __func__, status);
>
> - spin_lock(&portdata->lock);
> + spin_lock_irqsave(&portdata->lock, flags);
> --portdata->outstanding_urbs;
> - spin_unlock(&portdata->lock);
> - spin_lock(&intfdata->susp_lock);
> + spin_unlock_irqrestore(&portdata->lock, flags);
> + spin_lock_irqsave(&intfdata->susp_lock, flags);

You are allowing an interrupt enabled window where previously it
wasn't possible. Why notleave these 2 lines as is?

> --intfdata->in_flight;
> - spin_unlock(&intfdata->susp_lock);
> + spin_unlock_irqrestore(&intfdata->susp_lock, flags);
>
> usb_serial_port_softint(port);
> }

WBR, Sergei


2013-07-11 09:10:06

by Ming Lei

[permalink] [raw]
Subject: [PATCH 26/50] USBNET: cdc-phonet: spin_lock in complete() cleanup

Complete() will be run with interrupt enabled, so change to
spin_lock_irqsave().

Cc: [email protected]
Signed-off-by: Ming Lei <[email protected]>
---
drivers/net/usb/cdc-phonet.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/net/usb/cdc-phonet.c b/drivers/net/usb/cdc-phonet.c
index 7d78669..413ec32 100644
--- a/drivers/net/usb/cdc-phonet.c
+++ b/drivers/net/usb/cdc-phonet.c
@@ -99,6 +99,7 @@ static void tx_complete(struct urb *req)
struct net_device *dev = skb->dev;
struct usbpn_dev *pnd = netdev_priv(dev);
int status = req->status;
+ unsigned long flags;

switch (status) {
case 0:
@@ -115,10 +116,10 @@ static void tx_complete(struct urb *req)
}
dev->stats.tx_packets++;

- spin_lock(&pnd->tx_lock);
+ spin_lock_irqsave(&pnd->tx_lock, flags);
pnd->tx_queue--;
netif_wake_queue(dev);
- spin_unlock(&pnd->tx_lock);
+ spin_unlock_irqrestore(&pnd->tx_lock, flags);

dev_kfree_skb_any(skb);
usb_free_urb(req);
--
1.7.9.5


2013-07-11 13:10:55

by Sergei Shtylyov

[permalink] [raw]
Subject: Re: [PATCH 46/50] Sound: usb: ua101: spin_lock in complete() cleanup

On 11-07-2013 13:06, Ming Lei wrote:

Here the subject doesn't match the patch.

> Complete() will be run with interrupt enabled, so disable local
> interrupt before holding a global lock which is held without irqsave.

> Cc: Clemens Ladisch <[email protected]>
> Cc: Jaroslav Kysela <[email protected]>
> Cc: Takashi Iwai <[email protected]>
> Cc: [email protected]
> Signed-off-by: Ming Lei <[email protected]>
> ---
> sound/usb/misc/ua101.c | 14 ++++++++++++--
> 1 file changed, 12 insertions(+), 2 deletions(-)

> diff --git a/sound/usb/misc/ua101.c b/sound/usb/misc/ua101.c
> index 8b5d2c5..52a60c6 100644
> --- a/sound/usb/misc/ua101.c
> +++ b/sound/usb/misc/ua101.c
> @@ -613,14 +613,24 @@ static int start_usb_playback(struct ua101 *ua)
>
> static void abort_alsa_capture(struct ua101 *ua)
> {
> - if (test_bit(ALSA_CAPTURE_RUNNING, &ua->states))
> + if (test_bit(ALSA_CAPTURE_RUNNING, &ua->states)) {
> + unsigned long flags;
> +
> + local_irq_save(flags);
> snd_pcm_stop(ua->capture.substream, SNDRV_PCM_STATE_XRUN);
> + local_irq_restore(flags);
> + }
> }
>
> static void abort_alsa_playback(struct ua101 *ua)
> {
> - if (test_bit(ALSA_PLAYBACK_RUNNING, &ua->states))
> + if (test_bit(ALSA_PLAYBACK_RUNNING, &ua->states)) {
> + unsigned long flags;
> +
> + local_irq_save(flags);
> snd_pcm_stop(ua->playback.substream, SNDRV_PCM_STATE_XRUN);
> + local_irq_restore(flags);
> + }
> }

WBR, Sergei


2013-07-11 09:12:21

by Ming Lei

[permalink] [raw]
Subject: [PATCH 43/50] sound: usb: midi: spin_lock in complete() cleanup

Complete() will be run with interrupt enabled, so change to
spin_lock_irqsave().

Cc: Jaroslav Kysela <[email protected]>
Cc: Takashi Iwai <[email protected]>
Cc: Clemens Ladisch <[email protected]>
Cc: [email protected]
Signed-off-by: Ming Lei <[email protected]>
---
sound/usb/midi.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/sound/usb/midi.c b/sound/usb/midi.c
index b901f46..86af276 100644
--- a/sound/usb/midi.c
+++ b/sound/usb/midi.c
@@ -279,15 +279,16 @@ static void snd_usbmidi_out_urb_complete(struct urb* urb)
struct out_urb_context *context = urb->context;
struct snd_usb_midi_out_endpoint* ep = context->ep;
unsigned int urb_index;
+ unsigned long flags;

- spin_lock(&ep->buffer_lock);
+ spin_lock_irqsave(&ep->buffer_lock, flags);
urb_index = context - ep->urbs;
ep->active_urbs &= ~(1 << urb_index);
if (unlikely(ep->drain_urbs)) {
ep->drain_urbs &= ~(1 << urb_index);
wake_up(&ep->drain_wait);
}
- spin_unlock(&ep->buffer_lock);
+ spin_unlock_irqrestore(&ep->buffer_lock, flags);
if (urb->status < 0) {
int err = snd_usbmidi_urb_error(urb->status);
if (err < 0) {
--
1.7.9.5


2013-07-26 14:29:09

by Hans Verkuil

[permalink] [raw]
Subject: Re: [PATCH 35/50] media: usb: cx231xx: spin_lock in complete() cleanup



On 07/11/2013 11:05 AM, Ming Lei wrote:
> Complete() will be run with interrupt enabled, so change to
> spin_lock_irqsave().
>
> Cc: Mauro Carvalho Chehab <[email protected]>
> Cc: Hans Verkuil <[email protected]>
> Cc: [email protected]
> Signed-off-by: Ming Lei <[email protected]>
> ---
> drivers/media/usb/cx231xx/cx231xx-audio.c | 6 ++++++
> drivers/media/usb/cx231xx/cx231xx-core.c | 10 ++++++----
> drivers/media/usb/cx231xx/cx231xx-vbi.c | 5 +++--
> 3 files changed, 15 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/media/usb/cx231xx/cx231xx-audio.c b/drivers/media/usb/cx231xx/cx231xx-audio.c
> index 81a1d97..58c1b5c 100644
> --- a/drivers/media/usb/cx231xx/cx231xx-audio.c
> +++ b/drivers/media/usb/cx231xx/cx231xx-audio.c
> @@ -136,6 +136,7 @@ static void cx231xx_audio_isocirq(struct urb *urb)
> stride = runtime->frame_bits >> 3;
>
> for (i = 0; i < urb->number_of_packets; i++) {
> + unsigned long flags;
> int length = urb->iso_frame_desc[i].actual_length /
> stride;
> cp = (unsigned char *)urb->transfer_buffer +
> @@ -158,6 +159,7 @@ static void cx231xx_audio_isocirq(struct urb *urb)
> length * stride);
> }
>
> + local_irq_save(flags);
> snd_pcm_stream_lock(substream);

Can't you use snd_pcm_stream_lock_irqsave here?

Ditto for the other media drivers where this happens: em28xx and tlg2300.

I've reviewed the media driver changes and they look OK to me, so if
my comment above is fixed, then I can merge them for 3.12. Or are these
changes required for 3.11?

Regards,

Hans

>
> dev->adev.hwptr_done_capture += length;
> @@ -174,6 +176,7 @@ static void cx231xx_audio_isocirq(struct urb *urb)
> period_elapsed = 1;
> }
> snd_pcm_stream_unlock(substream);
> + local_irq_restore(flags);
> }
> if (period_elapsed)
> snd_pcm_period_elapsed(substream);
> @@ -224,6 +227,7 @@ static void cx231xx_audio_bulkirq(struct urb *urb)
> stride = runtime->frame_bits >> 3;
>
> if (1) {
> + unsigned long flags;
> int length = urb->actual_length /
> stride;
> cp = (unsigned char *)urb->transfer_buffer;
> @@ -242,6 +246,7 @@ static void cx231xx_audio_bulkirq(struct urb *urb)
> length * stride);
> }
>
> + local_irq_save(flags);
> snd_pcm_stream_lock(substream);
>
> dev->adev.hwptr_done_capture += length;
> @@ -258,6 +263,7 @@ static void cx231xx_audio_bulkirq(struct urb *urb)
> period_elapsed = 1;
> }
> snd_pcm_stream_unlock(substream);
> + local_irq_restore(flags);
> }
> if (period_elapsed)
> snd_pcm_period_elapsed(substream);
> diff --git a/drivers/media/usb/cx231xx/cx231xx-core.c b/drivers/media/usb/cx231xx/cx231xx-core.c
> index 4ba3ce0..593b397 100644
> --- a/drivers/media/usb/cx231xx/cx231xx-core.c
> +++ b/drivers/media/usb/cx231xx/cx231xx-core.c
> @@ -798,6 +798,7 @@ static void cx231xx_isoc_irq_callback(struct urb *urb)
> container_of(dma_q, struct cx231xx_video_mode, vidq);
> struct cx231xx *dev = container_of(vmode, struct cx231xx, video_mode);
> int i;
> + unsigned long flags;
>
> switch (urb->status) {
> case 0: /* success */
> @@ -813,9 +814,9 @@ static void cx231xx_isoc_irq_callback(struct urb *urb)
> }
>
> /* Copy data from URB */
> - spin_lock(&dev->video_mode.slock);
> + spin_lock_irqsave(&dev->video_mode.slock, flags);
> dev->video_mode.isoc_ctl.isoc_copy(dev, urb);
> - spin_unlock(&dev->video_mode.slock);
> + spin_unlock_irqrestore(&dev->video_mode.slock, flags);
>
> /* Reset urb buffers */
> for (i = 0; i < urb->number_of_packets; i++) {
> @@ -842,6 +843,7 @@ static void cx231xx_bulk_irq_callback(struct urb *urb)
> struct cx231xx_video_mode *vmode =
> container_of(dma_q, struct cx231xx_video_mode, vidq);
> struct cx231xx *dev = container_of(vmode, struct cx231xx, video_mode);
> + unsigned long flags;
>
> switch (urb->status) {
> case 0: /* success */
> @@ -857,9 +859,9 @@ static void cx231xx_bulk_irq_callback(struct urb *urb)
> }
>
> /* Copy data from URB */
> - spin_lock(&dev->video_mode.slock);
> + spin_lock_irqsave(&dev->video_mode.slock, flags);
> dev->video_mode.bulk_ctl.bulk_copy(dev, urb);
> - spin_unlock(&dev->video_mode.slock);
> + spin_unlock_irqrestore(&dev->video_mode.slock, flags);
>
> /* Reset urb buffers */
> urb->status = usb_submit_urb(urb, GFP_ATOMIC);
> diff --git a/drivers/media/usb/cx231xx/cx231xx-vbi.c b/drivers/media/usb/cx231xx/cx231xx-vbi.c
> index c027942..38e78f8 100644
> --- a/drivers/media/usb/cx231xx/cx231xx-vbi.c
> +++ b/drivers/media/usb/cx231xx/cx231xx-vbi.c
> @@ -306,6 +306,7 @@ static void cx231xx_irq_vbi_callback(struct urb *urb)
> struct cx231xx_video_mode *vmode =
> container_of(dma_q, struct cx231xx_video_mode, vidq);
> struct cx231xx *dev = container_of(vmode, struct cx231xx, vbi_mode);
> + unsigned long flags;
>
> switch (urb->status) {
> case 0: /* success */
> @@ -322,9 +323,9 @@ static void cx231xx_irq_vbi_callback(struct urb *urb)
> }
>
> /* Copy data from URB */
> - spin_lock(&dev->vbi_mode.slock);
> + spin_lock_irqsave(&dev->vbi_mode.slock, flags);
> dev->vbi_mode.bulk_ctl.bulk_copy(dev, urb);
> - spin_unlock(&dev->vbi_mode.slock);
> + spin_unlock_irqrestore(&dev->vbi_mode.slock, flags);
>
> /* Reset status */
> urb->status = 0;
>

2013-07-11 09:12:05

by Ming Lei

[permalink] [raw]
Subject: [PATCH 41/50] media: usb: em28xx: make sure irq disabled before acquiring lock

Complete() will be run with interrupt enabled, so add local_irq_save()
before acquiring the lock without irqsave().

Cc: Mauro Carvalho Chehab <[email protected]>
Cc: [email protected]
Signed-off-by: Ming Lei <[email protected]>
---
drivers/media/usb/em28xx/em28xx-audio.c | 3 +++
1 file changed, 3 insertions(+)

diff --git a/drivers/media/usb/em28xx/em28xx-audio.c b/drivers/media/usb/em28xx/em28xx-audio.c
index 2fdb66e..dca53ec 100644
--- a/drivers/media/usb/em28xx/em28xx-audio.c
+++ b/drivers/media/usb/em28xx/em28xx-audio.c
@@ -113,6 +113,7 @@ static void em28xx_audio_isocirq(struct urb *urb)
stride = runtime->frame_bits >> 3;

for (i = 0; i < urb->number_of_packets; i++) {
+ unsigned long flags;
int length =
urb->iso_frame_desc[i].actual_length / stride;
cp = (unsigned char *)urb->transfer_buffer +
@@ -134,6 +135,7 @@ static void em28xx_audio_isocirq(struct urb *urb)
length * stride);
}

+ local_irq_save(flags);
snd_pcm_stream_lock(substream);

dev->adev.hwptr_done_capture += length;
@@ -151,6 +153,7 @@ static void em28xx_audio_isocirq(struct urb *urb)
}

snd_pcm_stream_unlock(substream);
+ local_irq_restore(flags);
}
if (period_elapsed)
snd_pcm_period_elapsed(substream);
--
1.7.9.5


2013-07-11 09:09:51

by Ming Lei

[permalink] [raw]
Subject: [PATCH 24/50] input: cm109: spin_lock in complete() cleanup

Complete() will be run with interrupt enabled, so change to
spin_lock_irqsave().

Cc: Dmitry Torokhov <[email protected]>
Cc: [email protected]
Signed-off-by: Ming Lei <[email protected]>
---
drivers/input/misc/cm109.c | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/drivers/input/misc/cm109.c b/drivers/input/misc/cm109.c
index 082684e..cac4e37 100644
--- a/drivers/input/misc/cm109.c
+++ b/drivers/input/misc/cm109.c
@@ -340,6 +340,7 @@ static void cm109_urb_irq_callback(struct urb *urb)
struct cm109_dev *dev = urb->context;
const int status = urb->status;
int error;
+ unsigned long flags;

dev_dbg(&dev->intf->dev, "### URB IRQ: [0x%02x 0x%02x 0x%02x 0x%02x] keybit=0x%02x\n",
dev->irq_data->byte[0],
@@ -379,7 +380,7 @@ static void cm109_urb_irq_callback(struct urb *urb)

out:

- spin_lock(&dev->ctl_submit_lock);
+ spin_lock_irqsave(&dev->ctl_submit_lock, flags);

dev->irq_urb_pending = 0;

@@ -403,7 +404,7 @@ static void cm109_urb_irq_callback(struct urb *urb)
__func__, error);
}

- spin_unlock(&dev->ctl_submit_lock);
+ spin_unlock_irqrestore(&dev->ctl_submit_lock, flags);
}

static void cm109_urb_ctl_callback(struct urb *urb)
@@ -411,6 +412,7 @@ static void cm109_urb_ctl_callback(struct urb *urb)
struct cm109_dev *dev = urb->context;
const int status = urb->status;
int error;
+ unsigned long flags;

dev_dbg(&dev->intf->dev, "### URB CTL: [0x%02x 0x%02x 0x%02x 0x%02x]\n",
dev->ctl_data->byte[0],
@@ -421,7 +423,7 @@ static void cm109_urb_ctl_callback(struct urb *urb)
if (status)
dev_err(&dev->intf->dev, "%s: urb status %d\n", __func__, status);

- spin_lock(&dev->ctl_submit_lock);
+ spin_lock_irqsave(&dev->ctl_submit_lock, flags);

dev->ctl_urb_pending = 0;

@@ -442,7 +444,7 @@ static void cm109_urb_ctl_callback(struct urb *urb)
}
}

- spin_unlock(&dev->ctl_submit_lock);
+ spin_unlock_irqrestore(&dev->ctl_submit_lock, flags);
}

static void cm109_toggle_buzzer_async(struct cm109_dev *dev)
--
1.7.9.5


2013-07-14 14:33:47

by Ming Lei

[permalink] [raw]
Subject: Re: [PATCH 00/50] USB: cleanup spin_lock in URB->complete()

On Sun, Jul 14, 2013 at 9:17 PM, Andy Walls <[email protected]> wrote:
> On Thu, 2013-07-11 at 17:05 +0800, Ming Lei wrote:
>> Hi,
>>
>> As we are going to run URB->complete() in tasklet context[1][2],
>
> Hi,
>
> Please pardon my naivete, but why was it decided to use tasklets to
> defer work, as opposed to some other deferred work mechanism?
>
> It seems to me that getting rid of tasklets has been an objective for
> years:
>
> http://lwn.net/Articles/239633/
> http://lwn.net/Articles/520076/
> http://lwn.net/Articles/240054/

We discussed the problem in the below link previously[1], Steven
and Thomas suggested to use threaded irq handler, but which
may degrade USB mass storage performance, so we have to
take tasklet now until we rewrite transport part of USB mass storage
driver.

Also the conversion[2] has avoided the tasklet spin lock problem
already.


[1], http://marc.info/?t=137079119200001&r=1&w=2
[2], http://marc.info/?l=linux-usb&m=137286326726326&w=2


Thanks,
--
Ming Lei

2013-07-11 13:13:37

by Sergei Shtylyov

[permalink] [raw]
Subject: Re: [PATCH 42/50] media: usb: tlg2300: spin_lock in complete() cleanup

On 11-07-2013 13:06, Ming Lei wrote:

Subject doesn't match the patch.

> Complete() will be run with interrupt enabled, so disable local
> interrupt before holding a global lock which is held without
> irqsave.
>
> Cc: Mauro Carvalho Chehab <[email protected]>
> Cc: [email protected]
> Signed-off-by: Ming Lei <[email protected]>
> ---
> drivers/media/usb/tlg2300/pd-alsa.c | 3 +++
> 1 file changed, 3 insertions(+)

> diff --git a/drivers/media/usb/tlg2300/pd-alsa.c b/drivers/media/usb/tlg2300/pd-alsa.c
> index 3f3e141..cbccc96 100644
> --- a/drivers/media/usb/tlg2300/pd-alsa.c
> +++ b/drivers/media/usb/tlg2300/pd-alsa.c
[...]
> @@ -156,6 +157,7 @@ static inline void handle_audio_data(struct urb *urb, int *period_elapsed)
> memcpy(runtime->dma_area + oldptr * stride, cp, len * stride);
>
> /* update the statas */
> + local_irq_save(flags);
> snd_pcm_stream_lock(pa->capture_pcm_substream);
> pa->rcv_position += len;
> if (pa->rcv_position >= runtime->buffer_size)
> @@ -167,6 +169,7 @@ static inline void handle_audio_data(struct urb *urb, int *period_elapsed)
> *period_elapsed = 1;
> }
> snd_pcm_stream_unlock(pa->capture_pcm_substream);
> + local_irq_restore(flags);
> }

WBR, Sergei



2013-07-11 09:09:25

by Ming Lei

[permalink] [raw]
Subject: [PATCH 21/50] hid: usbhid: spin_lock in complete() cleanup

Complete() will be run with interrupt enabled, so change to
spin_lock_irqsave().

Cc: Jiri Kosina <[email protected]>
Cc: [email protected]
Signed-off-by: Ming Lei <[email protected]>
---
drivers/hid/usbhid/hid-core.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c
index 9941828..e1d8518 100644
--- a/drivers/hid/usbhid/hid-core.c
+++ b/drivers/hid/usbhid/hid-core.c
@@ -489,8 +489,9 @@ static void hid_ctrl(struct urb *urb)
struct hid_device *hid = urb->context;
struct usbhid_device *usbhid = hid->driver_data;
int unplug = 0, status = urb->status;
+ unsigned long flags;

- spin_lock(&usbhid->lock);
+ spin_lock_irqsave(&usbhid->lock, flags);

switch (status) {
case 0: /* success */
@@ -525,7 +526,7 @@ static void hid_ctrl(struct urb *urb)
}

clear_bit(HID_CTRL_RUNNING, &usbhid->iofl);
- spin_unlock(&usbhid->lock);
+ spin_unlock_irqrestore(&usbhid->lock, flags);
usb_autopm_put_interface_async(usbhid->intf);
wake_up(&usbhid->wait);
}
--
1.7.9.5


2013-07-11 12:15:26

by Sergei Shtylyov

[permalink] [raw]
Subject: Re: [PATCH 05/50] USB: misc: uss720: spin_lock in complete() cleanup

Hello.

On 11-07-2013 13:05, Ming Lei wrote:

> Complete() will be run with interrupt enabled, so change to
> spin_lock_irqsave().

> Signed-off-by: Ming Lei <[email protected]>
> ---
> drivers/usb/misc/uss720.c | 6 +++++-
> 1 file changed, 5 insertions(+), 1 deletion(-)

> diff --git a/drivers/usb/misc/uss720.c b/drivers/usb/misc/uss720.c
> index e129cf6..f7d15e8 100644
> --- a/drivers/usb/misc/uss720.c
> +++ b/drivers/usb/misc/uss720.c
> @@ -121,6 +121,7 @@ static void async_complete(struct urb *urb)
> dev_err(&urb->dev->dev, "async_complete: urb error %d\n",
> status);
> } else if (rq->dr.bRequest == 3) {
> + unsigned long flags;

Empty line wouldn't hurt here, after declaration.

> memcpy(priv->reg, rq->reg, sizeof(priv->reg));

WBR, Sergei



2013-07-11 09:07:15

by Ming Lei

[permalink] [raw]
Subject: [PATCH 05/50] USB: misc: uss720: spin_lock in complete() cleanup

Complete() will be run with interrupt enabled, so change to
spin_lock_irqsave().

Signed-off-by: Ming Lei <[email protected]>
---
drivers/usb/misc/uss720.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/drivers/usb/misc/uss720.c b/drivers/usb/misc/uss720.c
index e129cf6..f7d15e8 100644
--- a/drivers/usb/misc/uss720.c
+++ b/drivers/usb/misc/uss720.c
@@ -121,6 +121,7 @@ static void async_complete(struct urb *urb)
dev_err(&urb->dev->dev, "async_complete: urb error %d\n",
status);
} else if (rq->dr.bRequest == 3) {
+ unsigned long flags;
memcpy(priv->reg, rq->reg, sizeof(priv->reg));
#if 0
dev_dbg(&priv->usbdev->dev,
@@ -131,8 +132,11 @@ static void async_complete(struct urb *urb)
(unsigned int)priv->reg[6]);
#endif
/* if nAck interrupts are enabled and we have an interrupt, call the interrupt procedure */
- if (rq->reg[2] & rq->reg[1] & 0x10 && pp)
+ if (rq->reg[2] & rq->reg[1] & 0x10 && pp) {
+ local_irq_save(flags);
parport_generic_irq(pp);
+ local_irq_restore(flags);
+ }
}
complete(&rq->compl);
kref_put(&rq->ref_count, destroy_async);
--
1.7.9.5


2013-07-11 14:06:18

by Daniel Mack

[permalink] [raw]
Subject: Re: [PATCH 44/50] sound: usb: caiaq: spin_lock in complete() cleanup

On 11.07.2013 11:06, Ming Lei wrote:
> Complete() will be run with interrupt enabled, so change to
> spin_lock_irqsave().
>
> Cc: Daniel Mack <[email protected]>
> Cc: Jaroslav Kysela <[email protected]>
> Cc: Takashi Iwai <[email protected]>
> Cc: [email protected]
> Signed-off-by: Ming Lei <[email protected]>

Sound right to me, thanks.

Acked-by: Daniel Mack <[email protected]>



> ---
> sound/usb/caiaq/audio.c | 5 +++--
> 1 file changed, 3 insertions(+), 2 deletions(-)
>
> diff --git a/sound/usb/caiaq/audio.c b/sound/usb/caiaq/audio.c
> index 7103b09..e5675ab 100644
> --- a/sound/usb/caiaq/audio.c
> +++ b/sound/usb/caiaq/audio.c
> @@ -672,10 +672,11 @@ static void read_completed(struct urb *urb)
> offset += len;
>
> if (len > 0) {
> - spin_lock(&cdev->spinlock);
> + unsigned long flags;
> + spin_lock_irqsave(&cdev->spinlock, flags);
> fill_out_urb(cdev, out, &out->iso_frame_desc[outframe]);
> read_in_urb(cdev, urb, &urb->iso_frame_desc[frame]);
> - spin_unlock(&cdev->spinlock);
> + spin_unlock_irqrestore(&cdev->spinlock, flags);
> check_for_elapsed_periods(cdev, cdev->sub_playback);
> check_for_elapsed_periods(cdev, cdev->sub_capture);
> send_it = 1;
>


2013-07-11 13:47:08

by Sergei Shtylyov

[permalink] [raw]
Subject: Re: [PATCH 08/50] USB: legousbtower: spin_lock in complete() cleanup

Hello.

On 11-07-2013 16:36, Oliver Neukum wrote:

>> I don't think this patch passes checkpatch.pl.

> This series is a mechanical replacement in dozens of drivers.

That mechanicity shows too much in some patches.

> We cannot demand nice formatting. If you want to do something
> productive, check the locking in the driver.

I'm not paid for it and don't have time to do it for free.

> Regards
> Oliver

WBR, Sergei



2013-07-27 09:34:11

by Ming Lei

[permalink] [raw]
Subject: Re: [PATCH 35/50] media: usb: cx231xx: spin_lock in complete() cleanup

On Fri, Jul 26, 2013 at 10:28 PM, Hans Verkuil <[email protected]> wrote:
>
>
> On 07/11/2013 11:05 AM, Ming Lei wrote:
>> Complete() will be run with interrupt enabled, so change to
>> spin_lock_irqsave().
>>
>> Cc: Mauro Carvalho Chehab <[email protected]>
>> Cc: Hans Verkuil <[email protected]>
>> Cc: [email protected]
>> Signed-off-by: Ming Lei <[email protected]>
>> ---
>> drivers/media/usb/cx231xx/cx231xx-audio.c | 6 ++++++
>> drivers/media/usb/cx231xx/cx231xx-core.c | 10 ++++++----
>> drivers/media/usb/cx231xx/cx231xx-vbi.c | 5 +++--
>> 3 files changed, 15 insertions(+), 6 deletions(-)
>>
>> diff --git a/drivers/media/usb/cx231xx/cx231xx-audio.c b/drivers/media/usb/cx231xx/cx231xx-audio.c
>> index 81a1d97..58c1b5c 100644
>> --- a/drivers/media/usb/cx231xx/cx231xx-audio.c
>> +++ b/drivers/media/usb/cx231xx/cx231xx-audio.c
>> @@ -136,6 +136,7 @@ static void cx231xx_audio_isocirq(struct urb *urb)
>> stride = runtime->frame_bits >> 3;
>>
>> for (i = 0; i < urb->number_of_packets; i++) {
>> + unsigned long flags;
>> int length = urb->iso_frame_desc[i].actual_length /
>> stride;
>> cp = (unsigned char *)urb->transfer_buffer +
>> @@ -158,6 +159,7 @@ static void cx231xx_audio_isocirq(struct urb *urb)
>> length * stride);
>> }
>>
>> + local_irq_save(flags);
>> snd_pcm_stream_lock(substream);
>
> Can't you use snd_pcm_stream_lock_irqsave here?

Sure, that is already in my mind, :-)

> Ditto for the other media drivers where this happens: em28xx and tlg2300.

Yes.

>
> I've reviewed the media driver changes and they look OK to me, so if
> my comment above is fixed, then I can merge them for 3.12. Or are these
> changes required for 3.11?

These are for 3.12.

I will send out v2 next week, and thanks for your review.

Thanks,
--
Ming Lei

2013-07-11 09:11:34

by Ming Lei

[permalink] [raw]
Subject: [PATCH 37/50] media: usb: sn9x102: spin_lock in complete() cleanup

Complete() will be run with interrupt enabled, so change to
spin_lock_irqsave().

Cc: Mauro Carvalho Chehab <[email protected]>
Cc: [email protected]
Signed-off-by: Ming Lei <[email protected]>
---
drivers/media/usb/sn9c102/sn9c102_core.c | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/drivers/media/usb/sn9c102/sn9c102_core.c b/drivers/media/usb/sn9c102/sn9c102_core.c
index 2cb44de..33dc595 100644
--- a/drivers/media/usb/sn9c102/sn9c102_core.c
+++ b/drivers/media/usb/sn9c102/sn9c102_core.c
@@ -784,12 +784,14 @@ end_of_frame:
cam->sensor.pix_format.pixelformat ==
V4L2_PIX_FMT_JPEG) && eof)) {
u32 b;
+ unsigned long flags;

b = (*f)->buf.bytesused;
(*f)->state = F_DONE;
(*f)->buf.sequence= ++cam->frame_count;

- spin_lock(&cam->queue_lock);
+ spin_lock_irqsave(&cam->queue_lock,
+ flags);
list_move_tail(&(*f)->frame,
&cam->outqueue);
if (!list_empty(&cam->inqueue))
@@ -799,7 +801,8 @@ end_of_frame:
frame );
else
(*f) = NULL;
- spin_unlock(&cam->queue_lock);
+ spin_unlock_irqrestore(&cam->queue_lock,
+ flags);

memcpy(cam->sysfs.frame_header,
cam->sof.header, soflen);
--
1.7.9.5


2013-07-11 09:07:08

by Ming Lei

[permalink] [raw]
Subject: [PATCH 04/50] USB: adutux: spin_lock in complete() cleanup

Complete() will be run with interrupt enabled, so change to
spin_lock_irqsave().

Cc: Lisa Nguyen <[email protected]>
Signed-off-by: Ming Lei <[email protected]>
---
drivers/usb/misc/adutux.c | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/drivers/usb/misc/adutux.c b/drivers/usb/misc/adutux.c
index eb3c8c1..387c75e 100644
--- a/drivers/usb/misc/adutux.c
+++ b/drivers/usb/misc/adutux.c
@@ -195,12 +195,13 @@ static void adu_interrupt_in_callback(struct urb *urb)
{
struct adu_device *dev = urb->context;
int status = urb->status;
+ unsigned long flags;

dbg(4, " %s : enter, status %d", __func__, status);
adu_debug_data(5, __func__, urb->actual_length,
urb->transfer_buffer);

- spin_lock(&dev->buflock);
+ spin_lock_irqsave(&dev->buflock, flags);

if (status != 0) {
if ((status != -ENOENT) && (status != -ECONNRESET) &&
@@ -229,7 +230,7 @@ static void adu_interrupt_in_callback(struct urb *urb)

exit:
dev->read_urb_finished = 1;
- spin_unlock(&dev->buflock);
+ spin_unlock_irqrestore(&dev->buflock, flags);
/* always wake up so we recover from errors */
wake_up_interruptible(&dev->read_wait);
adu_debug_data(5, __func__, urb->actual_length,
@@ -241,6 +242,7 @@ static void adu_interrupt_out_callback(struct urb *urb)
{
struct adu_device *dev = urb->context;
int status = urb->status;
+ unsigned long flags;

dbg(4, " %s : enter, status %d", __func__, status);
adu_debug_data(5, __func__, urb->actual_length, urb->transfer_buffer);
@@ -254,10 +256,10 @@ static void adu_interrupt_out_callback(struct urb *urb)
goto exit;
}

- spin_lock(&dev->buflock);
+ spin_lock_irqsave(&dev->buflock, flags);
dev->out_urb_finished = 1;
wake_up(&dev->write_wait);
- spin_unlock(&dev->buflock);
+ spin_unlock_irqrestore(&dev->buflock, flags);
exit:

adu_debug_data(5, __func__, urb->actual_length,
--
1.7.9.5


2013-07-11 12:18:21

by Sergei Shtylyov

[permalink] [raw]
Subject: Re: [PATCH 08/50] USB: legousbtower: spin_lock in complete() cleanup

Hello.

On 11-07-2013 13:05, Ming Lei wrote:

> Complete() will be run with interrupt enabled, so change to
> spin_lock_irqsave().

> Cc: Juergen Stuber <[email protected]>
> Signed-off-by: Ming Lei <[email protected]>
> ---
> drivers/usb/misc/legousbtower.c | 5 +++--
> 1 file changed, 3 insertions(+), 2 deletions(-)

> diff --git a/drivers/usb/misc/legousbtower.c b/drivers/usb/misc/legousbtower.c
> index 8089479..4044989 100644
> --- a/drivers/usb/misc/legousbtower.c
> +++ b/drivers/usb/misc/legousbtower.c
> @@ -771,6 +771,7 @@ static void tower_interrupt_in_callback (struct urb *urb)
> struct lego_usb_tower *dev = urb->context;
> int status = urb->status;
> int retval;
> + unsigned long flags;
>
> dbg(4, "%s: enter, status %d", __func__, status);
>
> @@ -788,7 +789,7 @@ static void tower_interrupt_in_callback (struct urb *urb)
> }
>
> if (urb->actual_length > 0) {
> - spin_lock (&dev->read_buffer_lock);
> + spin_lock_irqsave (&dev->read_buffer_lock, flags);
> if (dev->read_buffer_length + urb->actual_length < read_buffer_size) {
> memcpy (dev->read_buffer + dev->read_buffer_length,
> dev->interrupt_in_buffer,
> @@ -799,7 +800,7 @@ static void tower_interrupt_in_callback (struct urb *urb)
> } else {
> printk(KERN_WARNING "%s: read_buffer overflow, %d bytes dropped", __func__, urb->actual_length);
> }
> - spin_unlock (&dev->read_buffer_lock);
> + spin_unlock_irqrestore (&dev->read_buffer_lock, flags);
> }

I don't think this patch passes checkpatch.pl.

WBR, Sergei



2013-07-11 09:09:17

by Ming Lei

[permalink] [raw]
Subject: [PATCH 20/50] USB: serial: usb_wwan: spin_lock in complete() cleanup

Complete() will be run with interrupt enabled, so change to
spin_lock_irqsave().

Cc: Johan Hovold <[email protected]>
Signed-off-by: Ming Lei <[email protected]>
---
drivers/usb/serial/usb_wwan.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/usb/serial/usb_wwan.c b/drivers/usb/serial/usb_wwan.c
index 8257d30..c807d65 100644
--- a/drivers/usb/serial/usb_wwan.c
+++ b/drivers/usb/serial/usb_wwan.c
@@ -312,6 +312,7 @@ static void usb_wwan_outdat_callback(struct urb *urb)
struct usb_wwan_port_private *portdata;
struct usb_wwan_intf_private *intfdata;
int i;
+ unsigned long flags;

port = urb->context;
intfdata = port->serial->private;
@@ -319,9 +320,9 @@ static void usb_wwan_outdat_callback(struct urb *urb)
usb_serial_port_softint(port);
usb_autopm_put_interface_async(port->serial->interface);
portdata = usb_get_serial_port_data(port);
- spin_lock(&intfdata->susp_lock);
+ spin_lock_irqsave(&intfdata->susp_lock, flags);
intfdata->in_flight--;
- spin_unlock(&intfdata->susp_lock);
+ spin_unlock_irqrestore(&intfdata->susp_lock, flags);

for (i = 0; i < N_OUT_URB; ++i) {
if (portdata->out_urbs[i] == urb) {
--
1.7.9.5


2013-07-11 09:11:02

by Ming Lei

[permalink] [raw]
Subject: [PATCH 33/50] wireless: libertas: spin_lock in complete() cleanup

Complete() will be run with interrupt enabled, so change to
spin_lock_irqsave().

Cc: "John W. Linville" <[email protected]>
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Signed-off-by: Ming Lei <[email protected]>
---
drivers/net/wireless/libertas/if_usb.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c
index 2798077..f6a8396 100644
--- a/drivers/net/wireless/libertas/if_usb.c
+++ b/drivers/net/wireless/libertas/if_usb.c
@@ -626,6 +626,7 @@ static inline void process_cmdrequest(int recvlength, uint8_t *recvbuff,
struct lbs_private *priv)
{
u8 i;
+ unsigned long flags;

if (recvlength > LBS_CMD_BUFFER_SIZE) {
lbs_deb_usbd(&cardp->udev->dev,
@@ -636,7 +637,7 @@ static inline void process_cmdrequest(int recvlength, uint8_t *recvbuff,

BUG_ON(!in_interrupt());

- spin_lock(&priv->driver_lock);
+ spin_lock_irqsave(&priv->driver_lock, flags);

i = (priv->resp_idx == 0) ? 1 : 0;
BUG_ON(priv->resp_len[i]);
@@ -646,7 +647,7 @@ static inline void process_cmdrequest(int recvlength, uint8_t *recvbuff,
kfree_skb(skb);
lbs_notify_command_response(priv, i);

- spin_unlock(&priv->driver_lock);
+ spin_unlock_irqrestore(&priv->driver_lock, flags);

lbs_deb_usbd(&cardp->udev->dev,
"Wake up main thread to handle cmd response\n");
--
1.7.9.5


2013-07-11 09:12:38

by Ming Lei

[permalink] [raw]
Subject: [PATCH 45/50] sound: usb: usx2y: spin_lock in complete() cleanup

Complete() will be run with interrupt enabled, so change to
spin_lock_irqsave().

Cc: Jaroslav Kysela <[email protected]>
Cc: Takashi Iwai <[email protected]>
Cc: [email protected]
Signed-off-by: Ming Lei <[email protected]>
---
sound/usb/usx2y/usbusx2yaudio.c | 4 ++++
1 file changed, 4 insertions(+)

diff --git a/sound/usb/usx2y/usbusx2yaudio.c b/sound/usb/usx2y/usbusx2yaudio.c
index 4967fe9..e2ee893 100644
--- a/sound/usb/usx2y/usbusx2yaudio.c
+++ b/sound/usb/usx2y/usbusx2yaudio.c
@@ -273,7 +273,11 @@ static void usX2Y_clients_stop(struct usX2Ydev *usX2Y)
struct snd_usX2Y_substream *subs = usX2Y->subs[s];
if (subs) {
if (atomic_read(&subs->state) >= state_PRERUNNING) {
+ unsigned long flags;
+
+ local_irq_save(flags);
snd_pcm_stop(subs->pcm_substream, SNDRV_PCM_STATE_XRUN);
+ local_irq_restore(flags);
}
for (u = 0; u < NRURBS; u++) {
struct urb *urb = subs->urb[u];
--
1.7.9.5


2013-07-11 09:06:52

by Ming Lei

[permalink] [raw]
Subject: [PATCH 02/50] USB: cdc-wdm: spin_lock in complete() cleanup

Complete() will be run with interrupt enabled, so change to
spin_lock_irqsave().

Cc: Oliver Neukum <[email protected]>
Signed-off-by: Ming Lei <[email protected]>
---
drivers/usb/class/cdc-wdm.c | 16 ++++++++++------
1 file changed, 10 insertions(+), 6 deletions(-)

diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c
index 8a230f0..5f78d18 100644
--- a/drivers/usb/class/cdc-wdm.c
+++ b/drivers/usb/class/cdc-wdm.c
@@ -143,10 +143,12 @@ found:
static void wdm_out_callback(struct urb *urb)
{
struct wdm_device *desc;
+ unsigned long flags;
+
desc = urb->context;
- spin_lock(&desc->iuspin);
+ spin_lock_irqsave(&desc->iuspin, flags);
desc->werr = urb->status;
- spin_unlock(&desc->iuspin);
+ spin_unlock_irqrestore(&desc->iuspin, flags);
kfree(desc->outbuf);
desc->outbuf = NULL;
clear_bit(WDM_IN_USE, &desc->flags);
@@ -158,8 +160,9 @@ static void wdm_in_callback(struct urb *urb)
struct wdm_device *desc = urb->context;
int status = urb->status;
int length = urb->actual_length;
+ unsigned long flags;

- spin_lock(&desc->iuspin);
+ spin_lock_irqsave(&desc->iuspin, flags);
clear_bit(WDM_RESPONDING, &desc->flags);

if (status) {
@@ -203,7 +206,7 @@ skip_error:
wake_up(&desc->wait);

set_bit(WDM_READ, &desc->flags);
- spin_unlock(&desc->iuspin);
+ spin_unlock_irqrestore(&desc->iuspin, flags);
}

static void wdm_int_callback(struct urb *urb)
@@ -212,6 +215,7 @@ static void wdm_int_callback(struct urb *urb)
int status = urb->status;
struct wdm_device *desc;
struct usb_cdc_notification *dr;
+ unsigned long flags;

desc = urb->context;
dr = (struct usb_cdc_notification *)desc->sbuf;
@@ -260,7 +264,7 @@ static void wdm_int_callback(struct urb *urb)
goto exit;
}

- spin_lock(&desc->iuspin);
+ spin_lock_irqsave(&desc->iuspin, flags);
clear_bit(WDM_READ, &desc->flags);
set_bit(WDM_RESPONDING, &desc->flags);
if (!test_bit(WDM_DISCONNECTING, &desc->flags)
@@ -269,7 +273,7 @@ static void wdm_int_callback(struct urb *urb)
dev_dbg(&desc->intf->dev, "%s: usb_submit_urb %d",
__func__, rv);
}
- spin_unlock(&desc->iuspin);
+ spin_unlock_irqrestore(&desc->iuspin, flags);
if (rv < 0) {
clear_bit(WDM_RESPONDING, &desc->flags);
if (rv == -EPERM)
--
1.7.9.5


2013-07-11 09:13:09

by Ming Lei

[permalink] [raw]
Subject: [PATCH 49/50] staging: ced1401: spin_lock in complete() cleanup

Complete() will be run with interrupt enabled, so change to
spin_lock_irqsave().

Cc: [email protected]
Signed-off-by: Ming Lei <[email protected]>
---
drivers/staging/ced1401/usb1401.c | 35 +++++++++++++++++++----------------
1 file changed, 19 insertions(+), 16 deletions(-)

diff --git a/drivers/staging/ced1401/usb1401.c b/drivers/staging/ced1401/usb1401.c
index 97c55f9..70d2f43 100644
--- a/drivers/staging/ced1401/usb1401.c
+++ b/drivers/staging/ced1401/usb1401.c
@@ -265,6 +265,7 @@ static void ced_writechar_callback(struct urb *pUrb)
{
DEVICE_EXTENSION *pdx = pUrb->context;
int nGot = pUrb->actual_length; /* what we transferred */
+ unsigned long flags;

if (pUrb->status) { /* sync/async unlink faults aren't errors */
if (!
@@ -275,24 +276,24 @@ static void ced_writechar_callback(struct urb *pUrb)
__func__, pUrb->status);
}

- spin_lock(&pdx->err_lock);
+ spin_lock_irqsave(&pdx->err_lock, flags);
pdx->errors = pUrb->status;
- spin_unlock(&pdx->err_lock);
+ spin_unlock_irqrestore(&pdx->err_lock, flags);
nGot = 0; /* and tidy up again if so */

- spin_lock(&pdx->charOutLock); /* already at irq level */
+ spin_lock_irqsave(&pdx->charOutLock, flags); /* already at irq level */
pdx->dwOutBuffGet = 0; /* Reset the output buffer */
pdx->dwOutBuffPut = 0;
pdx->dwNumOutput = 0; /* Clear the char count */
pdx->bPipeError[0] = 1; /* Flag an error for later */
pdx->bSendCharsPending = false; /* Allow other threads again */
- spin_unlock(&pdx->charOutLock); /* already at irq level */
+ spin_unlock_irqrestore(&pdx->charOutLock, flags); /* already at irq level */
dev_dbg(&pdx->interface->dev,
"%s - char out done, 0 chars sent", __func__);
} else {
dev_dbg(&pdx->interface->dev,
"%s - char out done, %d chars sent", __func__, nGot);
- spin_lock(&pdx->charOutLock); /* already at irq level */
+ spin_lock_irqsave(&pdx->charOutLock, flags); /* already at irq level */
pdx->dwNumOutput -= nGot; /* Now adjust the char send buffer */
pdx->dwOutBuffGet += nGot; /* to match what we did */
if (pdx->dwOutBuffGet >= OUTBUF_SZ) /* Can't do this any earlier as data could be overwritten */
@@ -305,7 +306,7 @@ static void ced_writechar_callback(struct urb *pUrb)
unsigned int dwCount = pdx->dwNumOutput; /* maximum to send */
if ((pdx->dwOutBuffGet + dwCount) > OUTBUF_SZ) /* does it cross buffer end? */
dwCount = OUTBUF_SZ - pdx->dwOutBuffGet;
- spin_unlock(&pdx->charOutLock); /* we are done with stuff that changes */
+ spin_unlock_irqrestore(&pdx->charOutLock, flags); /* we are done with stuff that changes */
memcpy(pdx->pCoherCharOut, pDat, dwCount); /* copy output data to the buffer */
usb_fill_bulk_urb(pdx->pUrbCharOut, pdx->udev,
usb_sndbulkpipe(pdx->udev,
@@ -318,7 +319,7 @@ static void ced_writechar_callback(struct urb *pUrb)
iReturn = usb_submit_urb(pdx->pUrbCharOut, GFP_ATOMIC);
dev_dbg(&pdx->interface->dev, "%s n=%d>%s<", __func__,
dwCount, pDat);
- spin_lock(&pdx->charOutLock); /* grab lock for errors */
+ spin_lock_irqsave(&pdx->charOutLock, flags); /* grab lock for errors */
if (iReturn) {
pdx->bPipeError[nPipe] = 1; /* Flag an error to be handled later */
pdx->bSendCharsPending = false; /* Allow other threads again */
@@ -329,7 +330,7 @@ static void ced_writechar_callback(struct urb *pUrb)
}
} else
pdx->bSendCharsPending = false; /* Allow other threads again */
- spin_unlock(&pdx->charOutLock); /* already at irq level */
+ spin_unlock_irqrestore(&pdx->charOutLock, flags); /* already at irq level */
}
}

@@ -505,8 +506,9 @@ static void staged_callback(struct urb *pUrb)
unsigned int nGot = pUrb->actual_length; /* what we transferred */
bool bCancel = false;
bool bRestartCharInput; /* used at the end */
+ unsigned long flags;

- spin_lock(&pdx->stagedLock); /* stop ReadWriteMem() action while this routine is running */
+ spin_lock_irqsave(&pdx->stagedLock, flags); /* stop ReadWriteMem() action while this routine is running */
pdx->bStagedUrbPending = false; /* clear the flag for staged IRP pending */

if (pUrb->status) { /* sync/async unlink faults aren't errors */
@@ -679,7 +681,7 @@ static void staged_callback(struct urb *pUrb)
bRestartCharInput = !bCancel && (pdx->dwDMAFlag == MODE_CHAR)
&& !pdx->bXFerWaiting;

- spin_unlock(&pdx->stagedLock); /* Finally release the lock again */
+ spin_unlock_irqrestore(&pdx->stagedLock, flags); /* Finally release the lock again */

/* This is not correct as dwDMAFlag is protected by the staged lock, but it is treated */
/* in Allowi as if it were protected by the char lock. In any case, most systems will */
@@ -1093,6 +1095,7 @@ static void ced_readchar_callback(struct urb *pUrb)
{
DEVICE_EXTENSION *pdx = pUrb->context;
int nGot = pUrb->actual_length; /* what we transferred */
+ unsigned long flags;

if (pUrb->status) { /* Do we have a problem to handle? */
int nPipe = pdx->nPipes == 4 ? 1 : 0; /* The pipe number to use for error */
@@ -1108,19 +1111,19 @@ static void ced_readchar_callback(struct urb *pUrb)
"%s - 0 chars pUrb->status=%d (shutdown?)",
__func__, pUrb->status);

- spin_lock(&pdx->err_lock);
+ spin_lock_irqsave(&pdx->err_lock, flags);
pdx->errors = pUrb->status;
- spin_unlock(&pdx->err_lock);
+ spin_unlock_irqrestore(&pdx->err_lock, flags);
nGot = 0; /* and tidy up again if so */

- spin_lock(&pdx->charInLock); /* already at irq level */
+ spin_lock_irqsave(&pdx->charInLock, flags); /* already at irq level */
pdx->bPipeError[nPipe] = 1; /* Flag an error for later */
} else {
if ((nGot > 1) && ((pdx->pCoherCharIn[0] & 0x7f) == 0x1b)) { /* Esc sequence? */
Handle1401Esc(pdx, &pdx->pCoherCharIn[1], nGot - 1); /* handle it */
- spin_lock(&pdx->charInLock); /* already at irq level */
+ spin_lock_irqsave(&pdx->charInLock, flags); /* already at irq level */
} else {
- spin_lock(&pdx->charInLock); /* already at irq level */
+ spin_lock_irqsave(&pdx->charInLock, flags); /* already at irq level */
if (nGot > 0) {
unsigned int i;
if (nGot < INBUF_SZ) {
@@ -1147,7 +1150,7 @@ static void ced_readchar_callback(struct urb *pUrb)
}

pdx->bReadCharsPending = false; /* No longer have a pending read */
- spin_unlock(&pdx->charInLock); /* already at irq level */
+ spin_unlock_irqrestore(&pdx->charInLock, flags); /* already at irq level */

Allowi(pdx); /* see if we can do the next one */
}
--
1.7.9.5


2013-07-11 09:10:22

by Ming Lei

[permalink] [raw]
Subject: [PATCH 28/50] USBNET: kaweth: spin_lock in complete() cleanup

Complete() will be run with interrupt enabled, so change to
spin_lock_irqsave().

Cc: [email protected]
Signed-off-by: Ming Lei <[email protected]>
---
drivers/net/usb/kaweth.c | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/drivers/net/usb/kaweth.c b/drivers/net/usb/kaweth.c
index afb117c..4addbbf 100644
--- a/drivers/net/usb/kaweth.c
+++ b/drivers/net/usb/kaweth.c
@@ -598,6 +598,7 @@ static void kaweth_usb_receive(struct urb *urb)
struct kaweth_device *kaweth = urb->context;
struct net_device *net = kaweth->net;
int status = urb->status;
+ unsigned long flags;

int count = urb->actual_length;
int count2 = urb->transfer_buffer_length;
@@ -630,12 +631,12 @@ static void kaweth_usb_receive(struct urb *urb)
kaweth->stats.rx_errors++;
dev_dbg(dev, "Status was -EOVERFLOW.\n");
}
- spin_lock(&kaweth->device_lock);
+ spin_lock_irqsave(&kaweth->device_lock, flags);
if (IS_BLOCKED(kaweth->status)) {
- spin_unlock(&kaweth->device_lock);
+ spin_unlock_irqrestore(&kaweth->device_lock, flags);
return;
}
- spin_unlock(&kaweth->device_lock);
+ spin_unlock_irqrestore(&kaweth->device_lock, flags);

if(status && status != -EREMOTEIO && count != 1) {
dev_err(&kaweth->intf->dev,
--
1.7.9.5


2013-07-11 09:11:11

by Ming Lei

[permalink] [raw]
Subject: [PATCH 34/50] wireless: libertas_tf: spin_lock in complete() cleanup

Complete() will be run with interrupt enabled, so change to
spin_lock_irqsave().

Cc: "John W. Linville" <[email protected]>
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Signed-off-by: Ming Lei <[email protected]>
---
drivers/net/wireless/libertas_tf/if_usb.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/libertas_tf/if_usb.c b/drivers/net/wireless/libertas_tf/if_usb.c
index d576dd6..0e9e972 100644
--- a/drivers/net/wireless/libertas_tf/if_usb.c
+++ b/drivers/net/wireless/libertas_tf/if_usb.c
@@ -610,6 +610,8 @@ static inline void process_cmdrequest(int recvlength, uint8_t *recvbuff,
struct if_usb_card *cardp,
struct lbtf_private *priv)
{
+ unsigned long flags;
+
if (recvlength > LBS_CMD_BUFFER_SIZE) {
lbtf_deb_usbd(&cardp->udev->dev,
"The receive buffer is too large\n");
@@ -619,12 +621,12 @@ static inline void process_cmdrequest(int recvlength, uint8_t *recvbuff,

BUG_ON(!in_interrupt());

- spin_lock(&priv->driver_lock);
+ spin_lock_irqsave(&priv->driver_lock, flags);
memcpy(priv->cmd_resp_buff, recvbuff + MESSAGE_HEADER_LEN,
recvlength - MESSAGE_HEADER_LEN);
kfree_skb(skb);
lbtf_cmd_response_rx(priv);
- spin_unlock(&priv->driver_lock);
+ spin_unlock_irqrestore(&priv->driver_lock, flags);
}

/**
--
1.7.9.5


2013-07-11 09:08:54

by Ming Lei

[permalink] [raw]
Subject: [PATCH 17/50] USB: serial: sierra: spin_lock in complete() cleanup

Complete() will be run with interrupt enabled, so change to
spin_lock_irqsave().

Cc: Johan Hovold <[email protected]>
Signed-off-by: Ming Lei <[email protected]>
---
drivers/usb/serial/sierra.c | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c
index de958c5..e79b6ad 100644
--- a/drivers/usb/serial/sierra.c
+++ b/drivers/usb/serial/sierra.c
@@ -433,6 +433,7 @@ static void sierra_outdat_callback(struct urb *urb)
struct sierra_port_private *portdata = usb_get_serial_port_data(port);
struct sierra_intf_private *intfdata;
int status = urb->status;
+ unsigned long flags;

intfdata = port->serial->private;

@@ -443,12 +444,12 @@ static void sierra_outdat_callback(struct urb *urb)
dev_dbg(&port->dev, "%s - nonzero write bulk status "
"received: %d\n", __func__, status);

- spin_lock(&portdata->lock);
+ spin_lock_irqsave(&portdata->lock, flags);
--portdata->outstanding_urbs;
- spin_unlock(&portdata->lock);
- spin_lock(&intfdata->susp_lock);
+ spin_unlock_irqrestore(&portdata->lock, flags);
+ spin_lock_irqsave(&intfdata->susp_lock, flags);
--intfdata->in_flight;
- spin_unlock(&intfdata->susp_lock);
+ spin_unlock_irqrestore(&intfdata->susp_lock, flags);

usb_serial_port_softint(port);
}
--
1.7.9.5


2013-07-11 09:10:29

by Ming Lei

[permalink] [raw]
Subject: [PATCH 29/50] USBNET: rtl8150: spin_lock in complete() cleanup

Complete() will be run with interrupt enabled, so change to
spin_lock_irqsave().

Cc: [email protected]
Signed-off-by: Ming Lei <[email protected]>
---
drivers/net/usb/rtl8150.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/net/usb/rtl8150.c b/drivers/net/usb/rtl8150.c
index 6cbdac6..199e0fb 100644
--- a/drivers/net/usb/rtl8150.c
+++ b/drivers/net/usb/rtl8150.c
@@ -372,6 +372,7 @@ static void read_bulk_callback(struct urb *urb)
u16 rx_stat;
int status = urb->status;
int result;
+ unsigned long flags;

dev = urb->context;
if (!dev)
@@ -413,9 +414,9 @@ static void read_bulk_callback(struct urb *urb)
netdev->stats.rx_packets++;
netdev->stats.rx_bytes += pkt_len;

- spin_lock(&dev->rx_pool_lock);
+ spin_lock_irqsave(&dev->rx_pool_lock, flags);
skb = pull_skb(dev);
- spin_unlock(&dev->rx_pool_lock);
+ spin_unlock_irqrestore(&dev->rx_pool_lock, flags);
if (!skb)
goto resched;

--
1.7.9.5


2013-07-11 09:09:09

by Ming Lei

[permalink] [raw]
Subject: [PATCH 19/50] USB: serial: ti_usb_3410_5052: spin_lock in complete() cleanup

Complete() will be run with interrupt enabled, so change to
spin_lock_irqsave().

Cc: Johan Hovold <[email protected]>
Signed-off-by: Ming Lei <[email protected]>
---
drivers/usb/serial/ti_usb_3410_5052.c | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c
index 7182bb7..4b984e9 100644
--- a/drivers/usb/serial/ti_usb_3410_5052.c
+++ b/drivers/usb/serial/ti_usb_3410_5052.c
@@ -1081,6 +1081,7 @@ static void ti_bulk_in_callback(struct urb *urb)
struct device *dev = &urb->dev->dev;
int status = urb->status;
int retval = 0;
+ unsigned long flags;

switch (status) {
case 0:
@@ -1116,20 +1117,20 @@ static void ti_bulk_in_callback(struct urb *urb)
__func__);
else
ti_recv(port, urb->transfer_buffer, urb->actual_length);
- spin_lock(&tport->tp_lock);
+ spin_lock_irqsave(&tport->tp_lock, flags);
port->icount.rx += urb->actual_length;
- spin_unlock(&tport->tp_lock);
+ spin_unlock_irqrestore(&tport->tp_lock, flags);
}

exit:
/* continue to read unless stopping */
- spin_lock(&tport->tp_lock);
+ spin_lock_irqsave(&tport->tp_lock, flags);
if (tport->tp_read_urb_state == TI_READ_URB_RUNNING)
retval = usb_submit_urb(urb, GFP_ATOMIC);
else if (tport->tp_read_urb_state == TI_READ_URB_STOPPING)
tport->tp_read_urb_state = TI_READ_URB_STOPPED;

- spin_unlock(&tport->tp_lock);
+ spin_unlock_irqrestore(&tport->tp_lock, flags);
if (retval)
dev_err(dev, "%s - resubmit read urb failed, %d\n",
__func__, retval);
--
1.7.9.5


2013-07-11 09:07:31

by Ming Lei

[permalink] [raw]
Subject: [PATCH 07/50] USB: ldusb: spin_lock in complete() cleanup

Complete() will be run with interrupt enabled, so change to
spin_lock_irqsave().

Signed-off-by: Ming Lei <[email protected]>
---
drivers/usb/misc/ldusb.c | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/drivers/usb/misc/ldusb.c b/drivers/usb/misc/ldusb.c
index ac76229..8bae18e 100644
--- a/drivers/usb/misc/ldusb.c
+++ b/drivers/usb/misc/ldusb.c
@@ -249,6 +249,7 @@ static void ld_usb_interrupt_in_callback(struct urb *urb)
unsigned int next_ring_head;
int status = urb->status;
int retval;
+ unsigned long flags;

if (status) {
if (status == -ENOENT ||
@@ -258,12 +259,12 @@ static void ld_usb_interrupt_in_callback(struct urb *urb)
} else {
dbg_info(&dev->intf->dev, "%s: nonzero status received: %d\n",
__func__, status);
- spin_lock(&dev->rbsl);
+ spin_lock_irqsave(&dev->rbsl, flags);
goto resubmit; /* maybe we can recover */
}
}

- spin_lock(&dev->rbsl);
+ spin_lock_irqsave(&dev->rbsl, flags);
if (urb->actual_length > 0) {
next_ring_head = (dev->ring_head+1) % ring_buffer_size;
if (next_ring_head != dev->ring_tail) {
@@ -292,7 +293,7 @@ resubmit:
dev->buffer_overflow = 1;
}
}
- spin_unlock(&dev->rbsl);
+ spin_unlock_irqrestore(&dev->rbsl, flags);
exit:
dev->interrupt_in_done = 1;
wake_up_interruptible(&dev->read_wait);
--
1.7.9.5


2013-07-11 09:07:51

by Ming Lei

[permalink] [raw]
Subject: [PATCH 09/50] USB: usbtest: spin_lock in complete() cleanup

Complete() will be run with interrupt enabled, so change to
spin_lock_irqsave().

Signed-off-by: Ming Lei <[email protected]>
---
drivers/usb/misc/usbtest.c | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c
index 8b4ca1c..5c73df5 100644
--- a/drivers/usb/misc/usbtest.c
+++ b/drivers/usb/misc/usbtest.c
@@ -804,11 +804,12 @@ static void ctrl_complete(struct urb *urb)
struct usb_ctrlrequest *reqp;
struct subcase *subcase;
int status = urb->status;
+ unsigned long flags;

reqp = (struct usb_ctrlrequest *)urb->setup_packet;
subcase = container_of(reqp, struct subcase, setup);

- spin_lock(&ctx->lock);
+ spin_lock_irqsave(&ctx->lock, flags);
ctx->count--;
ctx->pending--;

@@ -907,7 +908,7 @@ error:
/* signal completion when nothing's queued */
if (ctx->pending == 0)
complete(&ctx->complete);
- spin_unlock(&ctx->lock);
+ spin_unlock_irqrestore(&ctx->lock, flags);
}

static int
@@ -1552,8 +1553,9 @@ struct iso_context {
static void iso_callback(struct urb *urb)
{
struct iso_context *ctx = urb->context;
+ unsigned long flags;

- spin_lock(&ctx->lock);
+ spin_lock_irqsave(&ctx->lock, flags);
ctx->count--;

ctx->packet_count += urb->number_of_packets;
@@ -1593,7 +1595,7 @@ static void iso_callback(struct urb *urb)
complete(&ctx->done);
}
done:
- spin_unlock(&ctx->lock);
+ spin_unlock_irqrestore(&ctx->lock, flags);
}

static struct urb *iso_alloc_urb(
--
1.7.9.5


2013-07-11 14:13:38

by Ming Lei

[permalink] [raw]
Subject: Re: [PATCH 45/50] sound: usb: usx2y: spin_lock in complete() cleanup

On Thu, Jul 11, 2013 at 9:50 PM, Takashi Iwai <[email protected]> wrote:
> At Thu, 11 Jul 2013 17:08:30 +0400,
> Sergei Shtylyov wrote:
>>
>> On 11-07-2013 13:06, Ming Lei wrote:
>>
>> > Complete() will be run with interrupt enabled, so change to
>> > spin_lock_irqsave().
>>
>> Changelog doesn't match the patch.
>
> Yep, but moreover...
>
>> > Cc: Jaroslav Kysela <[email protected]>
>> > Cc: Takashi Iwai <[email protected]>
>> > Cc: [email protected]
>> > Signed-off-by: Ming Lei <[email protected]>
>> > ---
>> > sound/usb/usx2y/usbusx2yaudio.c | 4 ++++
>> > 1 file changed, 4 insertions(+)
>>
>> > diff --git a/sound/usb/usx2y/usbusx2yaudio.c b/sound/usb/usx2y/usbusx2yaudio.c
>> > index 4967fe9..e2ee893 100644
>> > --- a/sound/usb/usx2y/usbusx2yaudio.c
>> > +++ b/sound/usb/usx2y/usbusx2yaudio.c
>> > @@ -273,7 +273,11 @@ static void usX2Y_clients_stop(struct usX2Ydev *usX2Y)
>> > struct snd_usX2Y_substream *subs = usX2Y->subs[s];
>> > if (subs) {
>> > if (atomic_read(&subs->state) >= state_PRERUNNING) {
>> > + unsigned long flags;
>> > +
>> > + local_irq_save(flags);
>> > snd_pcm_stop(subs->pcm_substream, SNDRV_PCM_STATE_XRUN);
>> > + local_irq_restore(flags);
>> > }
>
> ... actually this snd_pcm_stop() call should have been covered by
> snd_pcm_stream_lock(). Maybe it'd be enough to have a single patch
> together with the change, i.e. wrapping with
> snd_pcm_stream_lock_irqsave().

Please use snd_pcm_stream_lock_irqsave() so that I can avoid sending
out similar patch later, :-)

>
> I'll prepare the patch for 3.11 independently from your patch series,
> so please drop this one.

OK, thanks for dealing with that.

>
>
> BTW, the word "cleanup" in the subject is inappropriate. This is
> rather a fix together with the core change.

It is a cleanup since the patchset only addresses lock problem which
is caused by the tasklet conversion.

>
> And, I wonder whether we can take a safer approach. When the caller
> condition changed, we often introduced either a different ops
> (e.g. ioctl case) or a flag for the new condition, at least during the
> transition period.

Interrupt is't enabled until all current drivers are cleaned up, so it is really
safe, please see patch [2].

>
> Last but not least, is a conversion to tasklet really preferred?
> tasklet is rather an obsoleted infrastructure nowadays, and people
> don't recommend to use it any longer, AFAIK.

We discussed the problem in the below link previously[1], Steven
and Thomas suggested to use threaded irq handler, but which
may degrade USB mass storage performance, so we have to
take tasklet now until we rewrite transport part of USB mass storage
driver.

Also the conversion[2] has avoided the tasklet spin lock problem
already.


[1], http://marc.info/?t=137079119200001&r=1&w=2
[2], http://marc.info/?l=linux-usb&m=137286326726326&w=2

Thanks,
--
Ming Lei

2013-07-11 09:08:38

by Ming Lei

[permalink] [raw]
Subject: [PATCH 15/50] USB: serial: mos77840: spin_lock in complete() cleanup

Complete() will be run with interrupt enabled, so change to
spin_lock_irqsave().

Cc: Johan Hovold <[email protected]>
Signed-off-by: Ming Lei <[email protected]>
---
drivers/usb/serial/mos7840.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c
index 0a818b2..f21dcd0 100644
--- a/drivers/usb/serial/mos7840.c
+++ b/drivers/usb/serial/mos7840.c
@@ -788,17 +788,18 @@ static void mos7840_bulk_out_data_callback(struct urb *urb)
struct usb_serial_port *port;
int status = urb->status;
int i;
+ unsigned long flags;

mos7840_port = urb->context;
port = mos7840_port->port;
- spin_lock(&mos7840_port->pool_lock);
+ spin_lock_irqsave(&mos7840_port->pool_lock, flags);
for (i = 0; i < NUM_URBS; i++) {
if (urb == mos7840_port->write_urb_pool[i]) {
mos7840_port->busy[i] = 0;
break;
}
}
- spin_unlock(&mos7840_port->pool_lock);
+ spin_unlock_irqrestore(&mos7840_port->pool_lock, flags);

if (status) {
dev_dbg(&port->dev, "nonzero write bulk status received:%d\n", status);
--
1.7.9.5


2013-07-11 13:08:34

by Sergei Shtylyov

[permalink] [raw]
Subject: Re: [PATCH 45/50] sound: usb: usx2y: spin_lock in complete() cleanup

On 11-07-2013 13:06, Ming Lei wrote:

> Complete() will be run with interrupt enabled, so change to
> spin_lock_irqsave().

Changelog doesn't match the patch.

> Cc: Jaroslav Kysela <[email protected]>
> Cc: Takashi Iwai <[email protected]>
> Cc: [email protected]
> Signed-off-by: Ming Lei <[email protected]>
> ---
> sound/usb/usx2y/usbusx2yaudio.c | 4 ++++
> 1 file changed, 4 insertions(+)

> diff --git a/sound/usb/usx2y/usbusx2yaudio.c b/sound/usb/usx2y/usbusx2yaudio.c
> index 4967fe9..e2ee893 100644
> --- a/sound/usb/usx2y/usbusx2yaudio.c
> +++ b/sound/usb/usx2y/usbusx2yaudio.c
> @@ -273,7 +273,11 @@ static void usX2Y_clients_stop(struct usX2Ydev *usX2Y)
> struct snd_usX2Y_substream *subs = usX2Y->subs[s];
> if (subs) {
> if (atomic_read(&subs->state) >= state_PRERUNNING) {
> + unsigned long flags;
> +
> + local_irq_save(flags);
> snd_pcm_stop(subs->pcm_substream, SNDRV_PCM_STATE_XRUN);
> + local_irq_restore(flags);
> }

WBR, Sergei



2013-07-11 09:08:30

by Ming Lei

[permalink] [raw]
Subject: [PATCH 14/50] USB: serial: mos7720: spin_lock in complete() cleanup

Complete() will be run with interrupt enabled, so change to
spin_lock_irqsave().

Cc: Johan Hovold <[email protected]>
Signed-off-by: Ming Lei <[email protected]>
---
drivers/usb/serial/mos7720.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c
index 51da424..9b8c866 100644
--- a/drivers/usb/serial/mos7720.c
+++ b/drivers/usb/serial/mos7720.c
@@ -338,14 +338,15 @@ static void async_complete(struct urb *urb)
{
struct urbtracker *urbtrack = urb->context;
int status = urb->status;
+ unsigned long flags;

if (unlikely(status))
dev_dbg(&urb->dev->dev, "%s - nonzero urb status received: %d\n", __func__, status);

/* remove the urbtracker from the active_urbs list */
- spin_lock(&urbtrack->mos_parport->listlock);
+ spin_lock_irqsave(&urbtrack->mos_parport->listlock, flags);
list_del(&urbtrack->urblist_entry);
- spin_unlock(&urbtrack->mos_parport->listlock);
+ spin_unlock_irqrestore(&urbtrack->mos_parport->listlock, flags);
kref_put(&urbtrack->ref_count, destroy_urbtracker);
}

--
1.7.9.5


2013-07-11 09:12:30

by Ming Lei

[permalink] [raw]
Subject: [PATCH 44/50] sound: usb: caiaq: spin_lock in complete() cleanup

Complete() will be run with interrupt enabled, so change to
spin_lock_irqsave().

Cc: Daniel Mack <[email protected]>
Cc: Jaroslav Kysela <[email protected]>
Cc: Takashi Iwai <[email protected]>
Cc: [email protected]
Signed-off-by: Ming Lei <[email protected]>
---
sound/usb/caiaq/audio.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/sound/usb/caiaq/audio.c b/sound/usb/caiaq/audio.c
index 7103b09..e5675ab 100644
--- a/sound/usb/caiaq/audio.c
+++ b/sound/usb/caiaq/audio.c
@@ -672,10 +672,11 @@ static void read_completed(struct urb *urb)
offset += len;

if (len > 0) {
- spin_lock(&cdev->spinlock);
+ unsigned long flags;
+ spin_lock_irqsave(&cdev->spinlock, flags);
fill_out_urb(cdev, out, &out->iso_frame_desc[outframe]);
read_in_urb(cdev, urb, &urb->iso_frame_desc[frame]);
- spin_unlock(&cdev->spinlock);
+ spin_unlock_irqrestore(&cdev->spinlock, flags);
check_for_elapsed_periods(cdev, cdev->sub_playback);
check_for_elapsed_periods(cdev, cdev->sub_capture);
send_it = 1;
--
1.7.9.5


2013-07-11 13:12:08

by Sergei Shtylyov

[permalink] [raw]
Subject: Re: [PATCH 44/50] sound: usb: caiaq: spin_lock in complete() cleanup

On 11-07-2013 13:06, Ming Lei wrote:

> Complete() will be run with interrupt enabled, so change to
> spin_lock_irqsave().

> Cc: Daniel Mack <[email protected]>
> Cc: Jaroslav Kysela <[email protected]>
> Cc: Takashi Iwai <[email protected]>
> Cc: [email protected]
> Signed-off-by: Ming Lei <[email protected]>
> ---
> sound/usb/caiaq/audio.c | 5 +++--
> 1 file changed, 3 insertions(+), 2 deletions(-)

> diff --git a/sound/usb/caiaq/audio.c b/sound/usb/caiaq/audio.c
> index 7103b09..e5675ab 100644
> --- a/sound/usb/caiaq/audio.c
> +++ b/sound/usb/caiaq/audio.c
> @@ -672,10 +672,11 @@ static void read_completed(struct urb *urb)
> offset += len;
>
> if (len > 0) {
> - spin_lock(&cdev->spinlock);
> + unsigned long flags;

Emoty line wouldn't hurt here, after declaration.

> + spin_lock_irqsave(&cdev->spinlock, flags);
> fill_out_urb(cdev, out, &out->iso_frame_desc[outframe]);
> read_in_urb(cdev, urb, &urb->iso_frame_desc[frame]);
> - spin_unlock(&cdev->spinlock);
> + spin_unlock_irqrestore(&cdev->spinlock, flags);

WBR, Sergei


2013-07-11 09:12:13

by Ming Lei

[permalink] [raw]
Subject: [PATCH 42/50] media: usb: tlg2300: spin_lock in complete() cleanup

Complete() will be run with interrupt enabled, so disable local
interrupt before holding a global lock which is held without
irqsave.

Cc: Mauro Carvalho Chehab <[email protected]>
Cc: [email protected]
Signed-off-by: Ming Lei <[email protected]>
---
drivers/media/usb/tlg2300/pd-alsa.c | 3 +++
1 file changed, 3 insertions(+)

diff --git a/drivers/media/usb/tlg2300/pd-alsa.c b/drivers/media/usb/tlg2300/pd-alsa.c
index 3f3e141..cbccc96 100644
--- a/drivers/media/usb/tlg2300/pd-alsa.c
+++ b/drivers/media/usb/tlg2300/pd-alsa.c
@@ -141,6 +141,7 @@ static inline void handle_audio_data(struct urb *urb, int *period_elapsed)
int len = urb->actual_length / stride;
unsigned char *cp = urb->transfer_buffer;
unsigned int oldptr = pa->rcv_position;
+ unsigned long flags;

if (urb->actual_length == AUDIO_BUF_SIZE - 4)
len -= (AUDIO_TRAILER_SIZE / stride);
@@ -156,6 +157,7 @@ static inline void handle_audio_data(struct urb *urb, int *period_elapsed)
memcpy(runtime->dma_area + oldptr * stride, cp, len * stride);

/* update the statas */
+ local_irq_save(flags);
snd_pcm_stream_lock(pa->capture_pcm_substream);
pa->rcv_position += len;
if (pa->rcv_position >= runtime->buffer_size)
@@ -167,6 +169,7 @@ static inline void handle_audio_data(struct urb *urb, int *period_elapsed)
*period_elapsed = 1;
}
snd_pcm_stream_unlock(pa->capture_pcm_substream);
+ local_irq_restore(flags);
}

static void complete_handler_audio(struct urb *urb)
--
1.7.9.5


2013-07-11 09:12:54

by Ming Lei

[permalink] [raw]
Subject: [PATCH 47/50] staging: btmtk_usb: spin_lock in complete() cleanup

Complete() will be run with interrupt enabled, so change to
spin_lock_irqsave().

Cc: [email protected]
Signed-off-by: Ming Lei <[email protected]>
---
drivers/staging/btmtk_usb/btmtk_usb.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/staging/btmtk_usb/btmtk_usb.c b/drivers/staging/btmtk_usb/btmtk_usb.c
index 0e783e8..ea10d4f 100644
--- a/drivers/staging/btmtk_usb/btmtk_usb.c
+++ b/drivers/staging/btmtk_usb/btmtk_usb.c
@@ -1218,6 +1218,7 @@ static void btmtk_usb_tx_complete(struct urb *urb)
struct sk_buff *skb = urb->context;
struct hci_dev *hdev = (struct hci_dev *)skb->dev;
struct btmtk_usb_data *data = hci_get_drvdata(hdev);
+ unsigned long flags;

BT_DBG("%s: %s urb %p status %d count %d\n", __func__, hdev->name,
urb, urb->status, urb->actual_length);
@@ -1231,9 +1232,9 @@ static void btmtk_usb_tx_complete(struct urb *urb)
hdev->stat.err_tx++;

done:
- spin_lock(&data->txlock);
+ spin_lock_irqsave(&data->txlock, flags);
data->tx_in_flight--;
- spin_unlock(&data->txlock);
+ spin_unlock_irqrestore(&data->txlock, flags);

kfree(urb->setup_packet);

--
1.7.9.5


2013-07-11 09:06:44

by Ming Lei

[permalink] [raw]
Subject: [PATCH 01/50] USB: devio: spin_lock in complete() cleanup

Complete() will be run with interrupt enabled, so change to
spin_lock_irqsave().

Cc: Alan Stern <[email protected]>
Signed-off-by: Ming Lei <[email protected]>
---
drivers/usb/core/devio.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
index 0598650..21e6ec6 100644
--- a/drivers/usb/core/devio.c
+++ b/drivers/usb/core/devio.c
@@ -495,8 +495,9 @@ static void async_completed(struct urb *urb)
u32 secid = 0;
const struct cred *cred = NULL;
int signr;
+ unsigned long flags;

- spin_lock(&ps->lock);
+ spin_lock_irqsave(&ps->lock, flags);
list_move_tail(&as->asynclist, &ps->async_completed);
as->status = urb->status;
signr = as->signr;
@@ -518,7 +519,7 @@ static void async_completed(struct urb *urb)
if (as->status < 0 && as->bulk_addr && as->status != -ECONNRESET &&
as->status != -ENOENT)
cancel_bulk_urbs(ps, as->bulk_addr);
- spin_unlock(&ps->lock);
+ spin_unlock_irqrestore(&ps->lock, flags);

if (signr) {
kill_pid_info_as_cred(sinfo.si_signo, &sinfo, pid, cred, secid);
--
1.7.9.5


2013-07-11 09:12:46

by Ming Lei

[permalink] [raw]
Subject: [PATCH 46/50] Sound: usb: ua101: spin_lock in complete() cleanup

Complete() will be run with interrupt enabled, so disable local
interrupt before holding a global lock which is held without irqsave.

Cc: Clemens Ladisch <[email protected]>
Cc: Jaroslav Kysela <[email protected]>
Cc: Takashi Iwai <[email protected]>
Cc: [email protected]
Signed-off-by: Ming Lei <[email protected]>
---
sound/usb/misc/ua101.c | 14 ++++++++++++--
1 file changed, 12 insertions(+), 2 deletions(-)

diff --git a/sound/usb/misc/ua101.c b/sound/usb/misc/ua101.c
index 8b5d2c5..52a60c6 100644
--- a/sound/usb/misc/ua101.c
+++ b/sound/usb/misc/ua101.c
@@ -613,14 +613,24 @@ static int start_usb_playback(struct ua101 *ua)

static void abort_alsa_capture(struct ua101 *ua)
{
- if (test_bit(ALSA_CAPTURE_RUNNING, &ua->states))
+ if (test_bit(ALSA_CAPTURE_RUNNING, &ua->states)) {
+ unsigned long flags;
+
+ local_irq_save(flags);
snd_pcm_stop(ua->capture.substream, SNDRV_PCM_STATE_XRUN);
+ local_irq_restore(flags);
+ }
}

static void abort_alsa_playback(struct ua101 *ua)
{
- if (test_bit(ALSA_PLAYBACK_RUNNING, &ua->states))
+ if (test_bit(ALSA_PLAYBACK_RUNNING, &ua->states)) {
+ unsigned long flags;
+
+ local_irq_save(flags);
snd_pcm_stop(ua->playback.substream, SNDRV_PCM_STATE_XRUN);
+ local_irq_restore(flags);
+ }
}

static int set_stream_hw(struct ua101 *ua, struct snd_pcm_substream *substream,
--
1.7.9.5


2013-07-11 09:10:14

by Ming Lei

[permalink] [raw]
Subject: [PATCH 27/50] USBNET: hso: spin_lock in complete() cleanup

Complete() will be run with interrupt enabled, so change to
spin_lock_irqsave().

Cc: [email protected]
Signed-off-by: Ming Lei <[email protected]>
---
drivers/net/usb/hso.c | 38 ++++++++++++++++++++++----------------
1 file changed, 22 insertions(+), 16 deletions(-)

diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c
index cba1d46..c865441 100644
--- a/drivers/net/usb/hso.c
+++ b/drivers/net/usb/hso.c
@@ -1008,6 +1008,7 @@ static void read_bulk_callback(struct urb *urb)
struct net_device *net;
int result;
int status = urb->status;
+ unsigned long flags;

/* is al ok? (Filip: Who's Al ?) */
if (status) {
@@ -1036,11 +1037,11 @@ static void read_bulk_callback(struct urb *urb)
if (urb->actual_length) {
/* Handle the IP stream, add header and push it onto network
* stack if the packet is complete. */
- spin_lock(&odev->net_lock);
+ spin_lock_irqsave(&odev->net_lock, flags);
packetizeRx(odev, urb->transfer_buffer, urb->actual_length,
(urb->transfer_buffer_length >
urb->actual_length) ? 1 : 0);
- spin_unlock(&odev->net_lock);
+ spin_unlock_irqrestore(&odev->net_lock, flags);
}

/* We are done with this URB, resubmit it. Prep the USB to wait for
@@ -1201,6 +1202,7 @@ static void hso_std_serial_read_bulk_callback(struct urb *urb)
{
struct hso_serial *serial = urb->context;
int status = urb->status;
+ unsigned long flags;

/* sanity check */
if (!serial) {
@@ -1223,17 +1225,17 @@ static void hso_std_serial_read_bulk_callback(struct urb *urb)
if (serial->parent->port_spec & HSO_INFO_CRC_BUG)
fix_crc_bug(urb, serial->in_endp->wMaxPacketSize);
/* Valid data, handle RX data */
- spin_lock(&serial->serial_lock);
+ spin_lock_irqsave(&serial->serial_lock, flags);
serial->rx_urb_filled[hso_urb_to_index(serial, urb)] = 1;
put_rxbuf_data_and_resubmit_bulk_urb(serial);
- spin_unlock(&serial->serial_lock);
+ spin_unlock_irqrestore(&serial->serial_lock, flags);
} else if (status == -ENOENT || status == -ECONNRESET) {
/* Unlinked - check for throttled port. */
D2("Port %d, successfully unlinked urb", serial->minor);
- spin_lock(&serial->serial_lock);
+ spin_lock_irqsave(&serial->serial_lock, flags);
serial->rx_urb_filled[hso_urb_to_index(serial, urb)] = 0;
hso_resubmit_rx_bulk_urb(serial, urb);
- spin_unlock(&serial->serial_lock);
+ spin_unlock_irqrestore(&serial->serial_lock, flags);
} else {
D2("Port %d, status = %d for read urb", serial->minor, status);
return;
@@ -1510,12 +1512,13 @@ static void tiocmget_intr_callback(struct urb *urb)
DUMP(serial_state_notification,
sizeof(struct hso_serial_state_notification));
} else {
+ unsigned long flags;

UART_state_bitmap = le16_to_cpu(serial_state_notification->
UART_state_bitmap);
prev_UART_state_bitmap = tiocmget->prev_UART_state_bitmap;
icount = &tiocmget->icount;
- spin_lock(&serial->serial_lock);
+ spin_lock_irqsave(&serial->serial_lock, flags);
if ((UART_state_bitmap & B_OVERRUN) !=
(prev_UART_state_bitmap & B_OVERRUN))
icount->parity++;
@@ -1538,7 +1541,7 @@ static void tiocmget_intr_callback(struct urb *urb)
(prev_UART_state_bitmap & B_RX_CARRIER))
icount->dcd++;
tiocmget->prev_UART_state_bitmap = UART_state_bitmap;
- spin_unlock(&serial->serial_lock);
+ spin_unlock_irqrestore(&serial->serial_lock, flags);
tiocmget->intr_completed = 1;
wake_up_interruptible(&tiocmget->waitq);
}
@@ -1883,8 +1886,9 @@ static void intr_callback(struct urb *urb)
serial = get_serial_by_shared_int_and_type(shared_int,
(1 << i));
if (serial != NULL) {
+ unsigned long flags;
D1("Pending read interrupt on port %d\n", i);
- spin_lock(&serial->serial_lock);
+ spin_lock_irqsave(&serial->serial_lock, flags);
if (serial->rx_state == RX_IDLE &&
serial->port.count > 0) {
/* Setup and send a ctrl req read on
@@ -1898,7 +1902,7 @@ static void intr_callback(struct urb *urb)
D1("Already a read pending on "
"port %d or port not open\n", i);
}
- spin_unlock(&serial->serial_lock);
+ spin_unlock_irqrestore(&serial->serial_lock, flags);
}
}
}
@@ -1925,6 +1929,7 @@ static void hso_std_serial_write_bulk_callback(struct urb *urb)
{
struct hso_serial *serial = urb->context;
int status = urb->status;
+ unsigned long flags;

/* sanity check */
if (!serial) {
@@ -1932,9 +1937,9 @@ static void hso_std_serial_write_bulk_callback(struct urb *urb)
return;
}

- spin_lock(&serial->serial_lock);
+ spin_lock_irqsave(&serial->serial_lock, flags);
serial->tx_urb_used = 0;
- spin_unlock(&serial->serial_lock);
+ spin_unlock_irqrestore(&serial->serial_lock, flags);
if (status) {
handle_usb_error(status, __func__, serial->parent);
return;
@@ -1976,14 +1981,15 @@ static void ctrl_callback(struct urb *urb)
struct hso_serial *serial = urb->context;
struct usb_ctrlrequest *req;
int status = urb->status;
+ unsigned long flags;

/* sanity check */
if (!serial)
return;

- spin_lock(&serial->serial_lock);
+ spin_lock_irqsave(&serial->serial_lock, flags);
serial->tx_urb_used = 0;
- spin_unlock(&serial->serial_lock);
+ spin_unlock_irqrestore(&serial->serial_lock, flags);
if (status) {
handle_usb_error(status, __func__, serial->parent);
return;
@@ -1999,9 +2005,9 @@ static void ctrl_callback(struct urb *urb)
(USB_DIR_IN | USB_TYPE_OPTION_VENDOR | USB_RECIP_INTERFACE)) {
/* response to a read command */
serial->rx_urb_filled[0] = 1;
- spin_lock(&serial->serial_lock);
+ spin_lock_irqsave(&serial->serial_lock, flags);
put_rxbuf_data_and_resubmit_ctrl_urb(serial);
- spin_unlock(&serial->serial_lock);
+ spin_unlock_irqrestore(&serial->serial_lock, flags);
} else {
hso_put_activity(serial->parent);
tty_port_tty_wakeup(&serial->port);
--
1.7.9.5


2013-07-11 14:32:51

by Takashi Iwai

[permalink] [raw]
Subject: Re: [PATCH 45/50] sound: usb: usx2y: spin_lock in complete() cleanup

At Thu, 11 Jul 2013 22:13:35 +0800,
Ming Lei wrote:
>
> On Thu, Jul 11, 2013 at 9:50 PM, Takashi Iwai <[email protected]> wrote:
> > At Thu, 11 Jul 2013 17:08:30 +0400,
> > Sergei Shtylyov wrote:
> >>
> >> On 11-07-2013 13:06, Ming Lei wrote:
> >>
> >> > Complete() will be run with interrupt enabled, so change to
> >> > spin_lock_irqsave().
> >>
> >> Changelog doesn't match the patch.
> >
> > Yep, but moreover...
> >
> >> > Cc: Jaroslav Kysela <[email protected]>
> >> > Cc: Takashi Iwai <[email protected]>
> >> > Cc: [email protected]
> >> > Signed-off-by: Ming Lei <[email protected]>
> >> > ---
> >> > sound/usb/usx2y/usbusx2yaudio.c | 4 ++++
> >> > 1 file changed, 4 insertions(+)
> >>
> >> > diff --git a/sound/usb/usx2y/usbusx2yaudio.c b/sound/usb/usx2y/usbusx2yaudio.c
> >> > index 4967fe9..e2ee893 100644
> >> > --- a/sound/usb/usx2y/usbusx2yaudio.c
> >> > +++ b/sound/usb/usx2y/usbusx2yaudio.c
> >> > @@ -273,7 +273,11 @@ static void usX2Y_clients_stop(struct usX2Ydev *usX2Y)
> >> > struct snd_usX2Y_substream *subs = usX2Y->subs[s];
> >> > if (subs) {
> >> > if (atomic_read(&subs->state) >= state_PRERUNNING) {
> >> > + unsigned long flags;
> >> > +
> >> > + local_irq_save(flags);
> >> > snd_pcm_stop(subs->pcm_substream, SNDRV_PCM_STATE_XRUN);
> >> > + local_irq_restore(flags);
> >> > }
> >
> > ... actually this snd_pcm_stop() call should have been covered by
> > snd_pcm_stream_lock(). Maybe it'd be enough to have a single patch
> > together with the change, i.e. wrapping with
> > snd_pcm_stream_lock_irqsave().
>
> Please use snd_pcm_stream_lock_irqsave() so that I can avoid sending
> out similar patch later, :-)
>
> >
> > I'll prepare the patch for 3.11 independently from your patch series,
> > so please drop this one.
>
> OK, thanks for dealing with that.
>
> >
> >
> > BTW, the word "cleanup" in the subject is inappropriate. This is
> > rather a fix together with the core change.
>
> It is a cleanup since the patchset only addresses lock problem which
> is caused by the tasklet conversion.

Well, the conversion to irqsave() is needed for the future drop of
irq_save() in the caller, right? Then this isn't a cleanup but a
preparation for movement ahead.


> > And, I wonder whether we can take a safer approach. When the caller
> > condition changed, we often introduced either a different ops
> > (e.g. ioctl case) or a flag for the new condition, at least during the
> > transition period.
>
> Interrupt is't enabled until all current drivers are cleaned up, so it is really
> safe, please see patch [2].

OK.

> > Last but not least, is a conversion to tasklet really preferred?
> > tasklet is rather an obsoleted infrastructure nowadays, and people
> > don't recommend to use it any longer, AFAIK.
>
> We discussed the problem in the below link previously[1], Steven
> and Thomas suggested to use threaded irq handler, but which
> may degrade USB mass storage performance, so we have to
> take tasklet now until we rewrite transport part of USB mass storage
> driver.
>
> Also the conversion[2] has avoided the tasklet spin lock problem
> already.

OK, good to know.


thanks,

Takashi


> [1], http://marc.info/?t=137079119200001&r=1&w=2
> [2], http://marc.info/?l=linux-usb&m=137286326726326&w=2
>
> Thanks,
> --
> Ming Lei
>

2013-07-11 13:49:36

by Takashi Iwai

[permalink] [raw]
Subject: Re: [PATCH 45/50] sound: usb: usx2y: spin_lock in complete() cleanup

At Thu, 11 Jul 2013 17:08:30 +0400,
Sergei Shtylyov wrote:
>
> On 11-07-2013 13:06, Ming Lei wrote:
>
> > Complete() will be run with interrupt enabled, so change to
> > spin_lock_irqsave().
>
> Changelog doesn't match the patch.

Yep, but moreover...

> > Cc: Jaroslav Kysela <[email protected]>
> > Cc: Takashi Iwai <[email protected]>
> > Cc: [email protected]
> > Signed-off-by: Ming Lei <[email protected]>
> > ---
> > sound/usb/usx2y/usbusx2yaudio.c | 4 ++++
> > 1 file changed, 4 insertions(+)
>
> > diff --git a/sound/usb/usx2y/usbusx2yaudio.c b/sound/usb/usx2y/usbusx2yaudio.c
> > index 4967fe9..e2ee893 100644
> > --- a/sound/usb/usx2y/usbusx2yaudio.c
> > +++ b/sound/usb/usx2y/usbusx2yaudio.c
> > @@ -273,7 +273,11 @@ static void usX2Y_clients_stop(struct usX2Ydev *usX2Y)
> > struct snd_usX2Y_substream *subs = usX2Y->subs[s];
> > if (subs) {
> > if (atomic_read(&subs->state) >= state_PRERUNNING) {
> > + unsigned long flags;
> > +
> > + local_irq_save(flags);
> > snd_pcm_stop(subs->pcm_substream, SNDRV_PCM_STATE_XRUN);
> > + local_irq_restore(flags);
> > }

... actually this snd_pcm_stop() call should have been covered by
snd_pcm_stream_lock(). Maybe it'd be enough to have a single patch
together with the change, i.e. wrapping with
snd_pcm_stream_lock_irqsave().

I'll prepare the patch for 3.11 independently from your patch series,
so please drop this one.


BTW, the word "cleanup" in the subject is inappropriate. This is
rather a fix together with the core change.

And, I wonder whether we can take a safer approach. When the caller
condition changed, we often introduced either a different ops
(e.g. ioctl case) or a flag for the new condition, at least during the
transition period.

Last but not least, is a conversion to tasklet really preferred?
tasklet is rather an obsoleted infrastructure nowadays, and people
don't recommend to use it any longer, AFAIK.


thanks,

Takashi

2013-07-11 09:10:54

by Ming Lei

[permalink] [raw]
Subject: [PATCH 32/50] wireless: ath: carl9170: spin_lock in complete() cleanup

Complete() will be run with interrupt enabled, so change to
spin_lock_irqsave().

Cc: Christian Lamparter <[email protected]>
Cc: "John W. Linville" <[email protected]>
Cc: [email protected]
Cc: [email protected]
Signed-off-by: Ming Lei <[email protected]>
---
drivers/net/wireless/ath/carl9170/rx.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/ath/carl9170/rx.c b/drivers/net/wireless/ath/carl9170/rx.c
index 4684dd9..61f62a6 100644
--- a/drivers/net/wireless/ath/carl9170/rx.c
+++ b/drivers/net/wireless/ath/carl9170/rx.c
@@ -129,6 +129,7 @@ static int carl9170_check_sequence(struct ar9170 *ar, unsigned int seq)

static void carl9170_cmd_callback(struct ar9170 *ar, u32 len, void *buffer)
{
+ unsigned long flags;
/*
* Some commands may have a variable response length
* and we cannot predict the correct length in advance.
@@ -148,7 +149,7 @@ static void carl9170_cmd_callback(struct ar9170 *ar, u32 len, void *buffer)
carl9170_restart(ar, CARL9170_RR_INVALID_RSP);
}

- spin_lock(&ar->cmd_lock);
+ spin_lock_irqsave(&ar->cmd_lock, flags);
if (ar->readbuf) {
if (len >= 4)
memcpy(ar->readbuf, buffer + 4, len - 4);
@@ -156,7 +157,7 @@ static void carl9170_cmd_callback(struct ar9170 *ar, u32 len, void *buffer)
ar->readbuf = NULL;
}
complete(&ar->cmd_wait);
- spin_unlock(&ar->cmd_lock);
+ spin_unlock_irqrestore(&ar->cmd_lock, flags);
}

void carl9170_handle_command_response(struct ar9170 *ar, void *buf, u32 len)
--
1.7.9.5


2013-07-11 12:42:50

by Devin Heitmueller

[permalink] [raw]
Subject: Re: [PATCH 36/50] media: usb: em28xx: spin_lock in complete() cleanup

On Thu, Jul 11, 2013 at 5:05 AM, Ming Lei <[email protected]> wrote:
> Complete() will be run with interrupt enabled, so change to
> spin_lock_irqsave().
>
> Cc: Mauro Carvalho Chehab <[email protected]>
> Cc: [email protected]
> Signed-off-by: Ming Lei <[email protected]>
> ---
> drivers/media/usb/em28xx/em28xx-core.c | 5 +++--
> 1 file changed, 3 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/media/usb/em28xx/em28xx-core.c b/drivers/media/usb/em28xx/em28xx-core.c
> index fc157af..0d698f9 100644
> --- a/drivers/media/usb/em28xx/em28xx-core.c
> +++ b/drivers/media/usb/em28xx/em28xx-core.c
> @@ -941,6 +941,7 @@ static void em28xx_irq_callback(struct urb *urb)
> {
> struct em28xx *dev = urb->context;
> int i;
> + unsigned long flags;
>
> switch (urb->status) {
> case 0: /* success */
> @@ -956,9 +957,9 @@ static void em28xx_irq_callback(struct urb *urb)
> }
>
> /* Copy data from URB */
> - spin_lock(&dev->slock);
> + spin_lock_irqsave(&dev->slock, flags);
> dev->usb_ctl.urb_data_copy(dev, urb);
> - spin_unlock(&dev->slock);
> + spin_unlock_irqrestore(&dev->slock, flags);
>
> /* Reset urb buffers */
> for (i = 0; i < urb->number_of_packets; i++) {
> --
> 1.7.9.5
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-media" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html

I actually stumbled across this a couple of weeks ago, and have had an
identical patch running in a local dev tree.

Reviewed-by: Devin Heitmueller <[email protected]>
Tested-by: Devin Heitmueller <[email protected]>

--
Devin J. Heitmueller - Kernel Labs
http://www.kernellabs.com

2013-07-11 09:09:02

by Ming Lei

[permalink] [raw]
Subject: [PATCH 18/50] USB: serial: symbolserial: spin_lock in complete() cleanup

Complete() will be run with interrupt enabled, so change to
spin_lock_irqsave().

Cc: Johan Hovold <[email protected]>
Signed-off-by: Ming Lei <[email protected]>
---
drivers/usb/serial/symbolserial.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/usb/serial/symbolserial.c b/drivers/usb/serial/symbolserial.c
index 9b16489..b4f5cbe 100644
--- a/drivers/usb/serial/symbolserial.c
+++ b/drivers/usb/serial/symbolserial.c
@@ -41,6 +41,7 @@ static void symbol_int_callback(struct urb *urb)
int status = urb->status;
int result;
int data_length;
+ unsigned long flags;

switch (status) {
case 0:
@@ -81,7 +82,7 @@ static void symbol_int_callback(struct urb *urb)
}

exit:
- spin_lock(&priv->lock);
+ spin_lock_irqsave(&priv->lock, flags);

/* Continue trying to always read if we should */
if (!priv->throttled) {
@@ -92,7 +93,7 @@ exit:
__func__, result);
} else
priv->actually_throttled = true;
- spin_unlock(&priv->lock);
+ spin_unlock_irqrestore(&priv->lock, flags);
}

static int symbol_open(struct tty_struct *tty, struct usb_serial_port *port)
--
1.7.9.5


2013-07-11 12:42:52

by Ming Lei

[permalink] [raw]
Subject: Re: [PATCH 08/50] USB: legousbtower: spin_lock in complete() cleanup

On Thu, Jul 11, 2013 at 8:18 PM, Sergei Shtylyov
<[email protected]> wrote:
> Hello.
>
>
> On 11-07-2013 13:05, Ming Lei wrote:
>
>> Complete() will be run with interrupt enabled, so change to
>> spin_lock_irqsave().
>
>
>> Cc: Juergen Stuber <[email protected]>
>> Signed-off-by: Ming Lei <[email protected]>
>> ---
>> drivers/usb/misc/legousbtower.c | 5 +++--
>> 1 file changed, 3 insertions(+), 2 deletions(-)
>
>
>> diff --git a/drivers/usb/misc/legousbtower.c
>> b/drivers/usb/misc/legousbtower.c
>> index 8089479..4044989 100644
>> --- a/drivers/usb/misc/legousbtower.c
>> +++ b/drivers/usb/misc/legousbtower.c
>> @@ -771,6 +771,7 @@ static void tower_interrupt_in_callback (struct urb
>> *urb)
>> struct lego_usb_tower *dev = urb->context;
>> int status = urb->status;
>> int retval;
>> + unsigned long flags;
>>
>> dbg(4, "%s: enter, status %d", __func__, status);
>>
>> @@ -788,7 +789,7 @@ static void tower_interrupt_in_callback (struct urb
>> *urb)
>> }
>>
>> if (urb->actual_length > 0) {
>> - spin_lock (&dev->read_buffer_lock);
>> + spin_lock_irqsave (&dev->read_buffer_lock, flags);
>> if (dev->read_buffer_length + urb->actual_length <
>> read_buffer_size) {
>> memcpy (dev->read_buffer +
>> dev->read_buffer_length,
>> dev->interrupt_in_buffer,
>> @@ -799,7 +800,7 @@ static void tower_interrupt_in_callback (struct urb
>> *urb)
>> } else {
>> printk(KERN_WARNING "%s: read_buffer overflow, %d
>> bytes dropped", __func__, urb->actual_length);
>> }
>> - spin_unlock (&dev->read_buffer_lock);
>> + spin_unlock_irqrestore (&dev->read_buffer_lock, flags);
>> }
>
>
> I don't think this patch passes checkpatch.pl.

No errors reported from checkpatch.pl, only warnings which isn't introduced
by this patch.

Thanks,
--
Ming Lei

2013-07-11 09:08:06

by Ming Lei

[permalink] [raw]
Subject: [PATCH 11/50] USB: serial: digi_acceleportldusb: spin_lock in complete() cleanup

Complete() will be run with interrupt enabled, so change to
spin_lock_irqsave().

Cc: Peter Berger <[email protected]>
Cc: Al Borchers <[email protected]>
Signed-off-by: Ming Lei <[email protected]>
---
drivers/usb/serial/digi_acceleport.c | 23 +++++++++++++----------
1 file changed, 13 insertions(+), 10 deletions(-)

diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c
index 19b467f..95b1959 100644
--- a/drivers/usb/serial/digi_acceleport.c
+++ b/drivers/usb/serial/digi_acceleport.c
@@ -988,6 +988,7 @@ static void digi_write_bulk_callback(struct urb *urb)
struct digi_serial *serial_priv;
int ret = 0;
int status = urb->status;
+ unsigned long flags;

/* port and serial sanity check */
if (port == NULL || (priv = usb_get_serial_port_data(port)) == NULL) {
@@ -1006,15 +1007,15 @@ static void digi_write_bulk_callback(struct urb *urb)
/* handle oob callback */
if (priv->dp_port_num == serial_priv->ds_oob_port_num) {
dev_dbg(&port->dev, "digi_write_bulk_callback: oob callback\n");
- spin_lock(&priv->dp_port_lock);
+ spin_lock_irqsave(&priv->dp_port_lock, flags);
priv->dp_write_urb_in_use = 0;
wake_up_interruptible(&port->write_wait);
- spin_unlock(&priv->dp_port_lock);
+ spin_unlock_irqrestore(&priv->dp_port_lock, flags);
return;
}

/* try to send any buffered data on this port */
- spin_lock(&priv->dp_port_lock);
+ spin_lock_irqsave(&priv->dp_port_lock, flags);
priv->dp_write_urb_in_use = 0;
if (priv->dp_out_buf_len > 0) {
*((unsigned char *)(port->write_urb->transfer_buffer))
@@ -1037,7 +1038,7 @@ static void digi_write_bulk_callback(struct urb *urb)
/* lost the race in write_chan(). */
schedule_work(&priv->dp_wakeup_work);

- spin_unlock(&priv->dp_port_lock);
+ spin_unlock_irqrestore(&priv->dp_port_lock, flags);
if (ret && ret != -EPERM)
dev_err_console(port,
"%s: usb_submit_urb failed, ret=%d, port=%d\n",
@@ -1388,6 +1389,7 @@ static int digi_read_inb_callback(struct urb *urb)
unsigned char *data = ((unsigned char *)urb->transfer_buffer) + 3;
int flag, throttled;
int status = urb->status;
+ unsigned long flags;

/* do not process callbacks on closed ports */
/* but do continue the read chain */
@@ -1404,7 +1406,7 @@ static int digi_read_inb_callback(struct urb *urb)
return -1;
}

- spin_lock(&priv->dp_port_lock);
+ spin_lock_irqsave(&priv->dp_port_lock, flags);

/* check for throttle; if set, do not resubmit read urb */
/* indicate the read chain needs to be restarted on unthrottle */
@@ -1438,7 +1440,7 @@ static int digi_read_inb_callback(struct urb *urb)
tty_flip_buffer_push(&port->port);
}
}
- spin_unlock(&priv->dp_port_lock);
+ spin_unlock_irqrestore(&priv->dp_port_lock, flags);

if (opcode == DIGI_CMD_RECEIVE_DISABLE)
dev_dbg(&port->dev, "%s: got RECEIVE_DISABLE\n", __func__);
@@ -1469,6 +1471,7 @@ static int digi_read_oob_callback(struct urb *urb)
int opcode, line, status, val;
int i;
unsigned int rts;
+ unsigned long flags;

/* handle each oob command */
for (i = 0; i < urb->actual_length - 3;) {
@@ -1496,7 +1499,7 @@ static int digi_read_oob_callback(struct urb *urb)
rts = tty->termios.c_cflag & CRTSCTS;

if (tty && opcode == DIGI_CMD_READ_INPUT_SIGNALS) {
- spin_lock(&priv->dp_port_lock);
+ spin_lock_irqsave(&priv->dp_port_lock, flags);
/* convert from digi flags to termiox flags */
if (val & DIGI_READ_INPUT_SIGNALS_CTS) {
priv->dp_modem_signals |= TIOCM_CTS;
@@ -1524,12 +1527,12 @@ static int digi_read_oob_callback(struct urb *urb)
else
priv->dp_modem_signals &= ~TIOCM_CD;

- spin_unlock(&priv->dp_port_lock);
+ spin_unlock_irqrestore(&priv->dp_port_lock, flags);
} else if (opcode == DIGI_CMD_TRANSMIT_IDLE) {
- spin_lock(&priv->dp_port_lock);
+ spin_lock_irqsave(&priv->dp_port_lock, flags);
priv->dp_transmit_idle = 1;
wake_up_interruptible(&priv->dp_transmit_idle_wait);
- spin_unlock(&priv->dp_port_lock);
+ spin_unlock_irqrestore(&priv->dp_port_lock, flags);
} else if (opcode == DIGI_CMD_IFLUSH_FIFO) {
wake_up_interruptible(&priv->dp_flush_wait);
}
--
1.7.9.5


2013-07-11 09:07:00

by Ming Lei

[permalink] [raw]
Subject: [PATCH 03/50] USB: usblp: spin_lock in complete() cleanup

Complete() will be run with interrupt enabled, so change to
spin_lock_irqsave().

Cc: Pete Zaitcev <[email protected]>
Signed-off-by: Ming Lei <[email protected]>
---
drivers/usb/class/usblp.c | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c
index d4c47d5..04163d8 100644
--- a/drivers/usb/class/usblp.c
+++ b/drivers/usb/class/usblp.c
@@ -297,6 +297,7 @@ static void usblp_bulk_read(struct urb *urb)
{
struct usblp *usblp = urb->context;
int status = urb->status;
+ unsigned long flags;

if (usblp->present && usblp->used) {
if (status)
@@ -304,14 +305,14 @@ static void usblp_bulk_read(struct urb *urb)
"nonzero read bulk status received: %d\n",
usblp->minor, status);
}
- spin_lock(&usblp->lock);
+ spin_lock_irqsave(&usblp->lock, flags);
if (status < 0)
usblp->rstatus = status;
else
usblp->rstatus = urb->actual_length;
usblp->rcomplete = 1;
wake_up(&usblp->rwait);
- spin_unlock(&usblp->lock);
+ spin_unlock_irqrestore(&usblp->lock, flags);

usb_free_urb(urb);
}
@@ -320,6 +321,7 @@ static void usblp_bulk_write(struct urb *urb)
{
struct usblp *usblp = urb->context;
int status = urb->status;
+ unsigned long flags;

if (usblp->present && usblp->used) {
if (status)
@@ -327,7 +329,7 @@ static void usblp_bulk_write(struct urb *urb)
"nonzero write bulk status received: %d\n",
usblp->minor, status);
}
- spin_lock(&usblp->lock);
+ spin_lock_irqsave(&usblp->lock, flags);
if (status < 0)
usblp->wstatus = status;
else
@@ -335,7 +337,7 @@ static void usblp_bulk_write(struct urb *urb)
usblp->no_paper = 0;
usblp->wcomplete = 1;
wake_up(&usblp->wwait);
- spin_unlock(&usblp->lock);
+ spin_unlock_irqrestore(&usblp->lock, flags);

usb_free_urb(urb);
}
--
1.7.9.5


2013-07-11 09:11:42

by Ming Lei

[permalink] [raw]
Subject: [PATCH 38/50] media: usb: tlg2300: spin_lock in complete() cleanup

Complete() will be run with interrupt enabled, so change to
spin_lock_irqsave().

Cc: Mauro Carvalho Chehab <[email protected]>
Cc: [email protected]
Signed-off-by: Ming Lei <[email protected]>
---
drivers/media/usb/tlg2300/pd-video.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/media/usb/tlg2300/pd-video.c b/drivers/media/usb/tlg2300/pd-video.c
index 8df668d..4e5bd07 100644
--- a/drivers/media/usb/tlg2300/pd-video.c
+++ b/drivers/media/usb/tlg2300/pd-video.c
@@ -151,11 +151,12 @@ static void init_copy(struct video_data *video, bool index)
static bool get_frame(struct front_face *front, int *need_init)
{
struct videobuf_buffer *vb = front->curr_frame;
+ unsigned long flags;

if (vb)
return true;

- spin_lock(&front->queue_lock);
+ spin_lock_irqsave(&front->queue_lock, flags);
if (!list_empty(&front->active)) {
vb = list_entry(front->active.next,
struct videobuf_buffer, queue);
@@ -164,7 +165,7 @@ static bool get_frame(struct front_face *front, int *need_init)
front->curr_frame = vb;
list_del_init(&vb->queue);
}
- spin_unlock(&front->queue_lock);
+ spin_unlock_irqrestore(&front->queue_lock, flags);

return !!vb;
}
--
1.7.9.5


2013-07-11 09:07:23

by Ming Lei

[permalink] [raw]
Subject: [PATCH 06/50] USB: iowarrior: spin_lock in complete() cleanup

Complete() will be run with interrupt enabled, so change to
spin_lock_irqsave().

Signed-off-by: Ming Lei <[email protected]>
---
drivers/usb/misc/iowarrior.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/usb/misc/iowarrior.c b/drivers/usb/misc/iowarrior.c
index d36f34e..010ed6d 100644
--- a/drivers/usb/misc/iowarrior.c
+++ b/drivers/usb/misc/iowarrior.c
@@ -162,6 +162,7 @@ static void iowarrior_callback(struct urb *urb)
int offset;
int status = urb->status;
int retval;
+ unsigned long flags;

switch (status) {
case 0:
@@ -175,7 +176,7 @@ static void iowarrior_callback(struct urb *urb)
goto exit;
}

- spin_lock(&dev->intr_idx_lock);
+ spin_lock_irqsave(&dev->intr_idx_lock, flags);
intr_idx = atomic_read(&dev->intr_idx);
/* aux_idx become previous intr_idx */
aux_idx = (intr_idx == 0) ? (MAX_INTERRUPT_BUFFER - 1) : (intr_idx - 1);
@@ -211,7 +212,7 @@ static void iowarrior_callback(struct urb *urb)
*(dev->read_queue + offset + (dev->report_size)) = dev->serial_number++;

atomic_set(&dev->intr_idx, aux_idx);
- spin_unlock(&dev->intr_idx_lock);
+ spin_unlock_irqrestore(&dev->intr_idx_lock, flags);
/* tell the blocking read about the new data */
wake_up_interruptible(&dev->read_wait);

--
1.7.9.5


2013-07-11 12:34:48

by Oliver Neukum

[permalink] [raw]
Subject: Re: [PATCH 08/50] USB: legousbtower: spin_lock in complete() cleanup

On Thursday 11 July 2013 16:18:17 Sergei Shtylyov wrote:

> I don't think this patch passes checkpatch.pl.

This series is a mechanical replacement in dozens of drivers.
We cannot demand nice formatting. If you want to do something
productive, check the locking in the driver.

Regards
Oliver


2013-07-11 09:08:15

by Ming Lei

[permalink] [raw]
Subject: [PATCH 12/50] USB: serial: io_edgeport: spin_lock in complete() cleanup

Complete() will be run with interrupt enabled, so change to
spin_lock_irqsave().

Cc: Johan Hovold <[email protected]>
Signed-off-by: Ming Lei <[email protected]>
---
drivers/usb/serial/io_edgeport.c | 14 ++++++++------
1 file changed, 8 insertions(+), 6 deletions(-)

diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c
index dc2803b..af2f7d8 100644
--- a/drivers/usb/serial/io_edgeport.c
+++ b/drivers/usb/serial/io_edgeport.c
@@ -569,6 +569,7 @@ static void edge_interrupt_callback(struct urb *urb)
int portNumber;
int result;
int status = urb->status;
+ unsigned long flags;

switch (status) {
case 0:
@@ -594,7 +595,7 @@ static void edge_interrupt_callback(struct urb *urb)
if (length > 1) {
bytes_avail = data[0] | (data[1] << 8);
if (bytes_avail) {
- spin_lock(&edge_serial->es_lock);
+ spin_lock_irqsave(&edge_serial->es_lock, flags);
edge_serial->rxBytesAvail += bytes_avail;
dev_dbg(dev,
"%s - bytes_avail=%d, rxBytesAvail=%d, read_in_progress=%d\n",
@@ -617,7 +618,7 @@ static void edge_interrupt_callback(struct urb *urb)
edge_serial->read_in_progress = false;
}
}
- spin_unlock(&edge_serial->es_lock);
+ spin_unlock_irqrestore(&edge_serial->es_lock, flags);
}
}
/* grab the txcredits for the ports if available */
@@ -630,9 +631,9 @@ static void edge_interrupt_callback(struct urb *urb)
port = edge_serial->serial->port[portNumber];
edge_port = usb_get_serial_port_data(port);
if (edge_port->open) {
- spin_lock(&edge_port->ep_lock);
+ spin_lock_irqsave(&edge_port->ep_lock, flags);
edge_port->txCredits += txCredits;
- spin_unlock(&edge_port->ep_lock);
+ spin_unlock_irqrestore(&edge_port->ep_lock, flags);
dev_dbg(dev, "%s - txcredits for port%d = %d\n",
__func__, portNumber,
edge_port->txCredits);
@@ -673,6 +674,7 @@ static void edge_bulk_in_callback(struct urb *urb)
int retval;
__u16 raw_data_length;
int status = urb->status;
+ unsigned long flags;

if (status) {
dev_dbg(&urb->dev->dev, "%s - nonzero read bulk status received: %d\n",
@@ -692,7 +694,7 @@ static void edge_bulk_in_callback(struct urb *urb)

usb_serial_debug_data(dev, __func__, raw_data_length, data);

- spin_lock(&edge_serial->es_lock);
+ spin_lock_irqsave(&edge_serial->es_lock, flags);

/* decrement our rxBytes available by the number that we just got */
edge_serial->rxBytesAvail -= raw_data_length;
@@ -716,7 +718,7 @@ static void edge_bulk_in_callback(struct urb *urb)
edge_serial->read_in_progress = false;
}

- spin_unlock(&edge_serial->es_lock);
+ spin_unlock_irqrestore(&edge_serial->es_lock, flags);
}


--
1.7.9.5


2013-07-11 09:08:22

by Ming Lei

[permalink] [raw]
Subject: [PATCH 13/50] USB: serial: io_ti: spin_lock in complete() cleanup

Complete() will be run with interrupt enabled, so change to
spin_lock_irqsave().

Cc: Johan Hovold <[email protected]>
Signed-off-by: Ming Lei <[email protected]>
---
drivers/usb/serial/io_ti.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c
index 60054e7..4943194 100644
--- a/drivers/usb/serial/io_ti.c
+++ b/drivers/usb/serial/io_ti.c
@@ -1615,6 +1615,7 @@ static void edge_bulk_in_callback(struct urb *urb)
int retval = 0;
int port_number;
int status = urb->status;
+ unsigned long flags;

switch (status) {
case 0:
@@ -1663,13 +1664,13 @@ static void edge_bulk_in_callback(struct urb *urb)

exit:
/* continue read unless stopped */
- spin_lock(&edge_port->ep_lock);
+ spin_lock_irqsave(&edge_port->ep_lock, flags);
if (edge_port->ep_read_urb_state == EDGE_READ_URB_RUNNING)
retval = usb_submit_urb(urb, GFP_ATOMIC);
else if (edge_port->ep_read_urb_state == EDGE_READ_URB_STOPPING)
edge_port->ep_read_urb_state = EDGE_READ_URB_STOPPED;

- spin_unlock(&edge_port->ep_lock);
+ spin_unlock_irqrestore(&edge_port->ep_lock, flags);
if (retval)
dev_err(dev, "%s - usb_submit_urb failed with result %d\n", __func__, retval);
}
--
1.7.9.5


2013-07-11 09:10:46

by Ming Lei

[permalink] [raw]
Subject: [PATCH 31/50] wireless: zd1211rw: spin_lock in complete() cleanup

Complete() will be run with interrupt enabled, so change to
spin_lock_irqsave().

Cc: Daniel Drake <[email protected]>
Cc: Ulrich Kunitz <[email protected]>
Cc: "John W. Linville" <[email protected]>
Cc: [email protected]
Cc: [email protected]
Signed-off-by: Ming Lei <[email protected]>
---
drivers/net/wireless/zd1211rw/zd_usb.c | 21 ++++++++++++---------
1 file changed, 12 insertions(+), 9 deletions(-)

diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c
index 7ef0b4a..8169ee0 100644
--- a/drivers/net/wireless/zd1211rw/zd_usb.c
+++ b/drivers/net/wireless/zd1211rw/zd_usb.c
@@ -372,14 +372,15 @@ static inline void handle_regs_int_override(struct urb *urb)
{
struct zd_usb *usb = urb->context;
struct zd_usb_interrupt *intr = &usb->intr;
+ unsigned long flags;

- spin_lock(&intr->lock);
+ spin_lock_irqsave(&intr->lock, flags);
if (atomic_read(&intr->read_regs_enabled)) {
atomic_set(&intr->read_regs_enabled, 0);
intr->read_regs_int_overridden = 1;
complete(&intr->read_regs.completion);
}
- spin_unlock(&intr->lock);
+ spin_unlock_irqrestore(&intr->lock, flags);
}

static inline void handle_regs_int(struct urb *urb)
@@ -388,9 +389,10 @@ static inline void handle_regs_int(struct urb *urb)
struct zd_usb_interrupt *intr = &usb->intr;
int len;
u16 int_num;
+ unsigned long flags;

ZD_ASSERT(in_interrupt());
- spin_lock(&intr->lock);
+ spin_lock_irqsave(&intr->lock, flags);

int_num = le16_to_cpu(*(__le16 *)(urb->transfer_buffer+2));
if (int_num == CR_INTERRUPT) {
@@ -426,7 +428,7 @@ static inline void handle_regs_int(struct urb *urb)
}

out:
- spin_unlock(&intr->lock);
+ spin_unlock_irqrestore(&intr->lock, flags);

/* CR_INTERRUPT might override read_reg too. */
if (int_num == CR_INTERRUPT && atomic_read(&intr->read_regs_enabled))
@@ -666,6 +668,7 @@ static void rx_urb_complete(struct urb *urb)
struct zd_usb_rx *rx;
const u8 *buffer;
unsigned int length;
+ unsigned long flags;

switch (urb->status) {
case 0:
@@ -694,14 +697,14 @@ static void rx_urb_complete(struct urb *urb)
/* If there is an old first fragment, we don't care. */
dev_dbg_f(urb_dev(urb), "*** first fragment ***\n");
ZD_ASSERT(length <= ARRAY_SIZE(rx->fragment));
- spin_lock(&rx->lock);
+ spin_lock_irqsave(&rx->lock, flags);
memcpy(rx->fragment, buffer, length);
rx->fragment_length = length;
- spin_unlock(&rx->lock);
+ spin_unlock_irqrestore(&rx->lock, flags);
goto resubmit;
}

- spin_lock(&rx->lock);
+ spin_lock_irqsave(&rx->lock, flags);
if (rx->fragment_length > 0) {
/* We are on a second fragment, we believe */
ZD_ASSERT(length + rx->fragment_length <=
@@ -711,9 +714,9 @@ static void rx_urb_complete(struct urb *urb)
handle_rx_packet(usb, rx->fragment,
rx->fragment_length + length);
rx->fragment_length = 0;
- spin_unlock(&rx->lock);
+ spin_unlock_irqrestore(&rx->lock, flags);
} else {
- spin_unlock(&rx->lock);
+ spin_unlock_irqrestore(&rx->lock, flags);
handle_rx_packet(usb, buffer, length);
}

--
1.7.9.5


2013-07-11 09:09:35

by Ming Lei

[permalink] [raw]
Subject: [PATCH 22/50] BT: btusb: spin_lock in complete() cleanup

Complete() will be run with interrupt enabled, so change to
spin_lock_irqsave().

Cc: Marcel Holtmann <[email protected]>
Cc: Gustavo Padovan <[email protected]>
Cc: Johan Hedberg <[email protected]>
Cc: [email protected]
Signed-off-by: Ming Lei <[email protected]>
---
drivers/bluetooth/btusb.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index ea63958..018b8b0 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -573,6 +573,7 @@ static void btusb_tx_complete(struct urb *urb)
struct sk_buff *skb = urb->context;
struct hci_dev *hdev = (struct hci_dev *) skb->dev;
struct btusb_data *data = hci_get_drvdata(hdev);
+ unsigned long flags;

BT_DBG("%s urb %p status %d count %d", hdev->name,
urb, urb->status, urb->actual_length);
@@ -586,9 +587,9 @@ static void btusb_tx_complete(struct urb *urb)
hdev->stat.err_tx++;

done:
- spin_lock(&data->txlock);
+ spin_lock_irqsave(&data->txlock, flags);
data->tx_in_flight--;
- spin_unlock(&data->txlock);
+ spin_unlock_irqrestore(&data->txlock, flags);

kfree(urb->setup_packet);

--
1.7.9.5


2013-07-11 09:11:26

by Ming Lei

[permalink] [raw]
Subject: [PATCH 36/50] media: usb: em28xx: spin_lock in complete() cleanup

Complete() will be run with interrupt enabled, so change to
spin_lock_irqsave().

Cc: Mauro Carvalho Chehab <[email protected]>
Cc: [email protected]
Signed-off-by: Ming Lei <[email protected]>
---
drivers/media/usb/em28xx/em28xx-core.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/media/usb/em28xx/em28xx-core.c b/drivers/media/usb/em28xx/em28xx-core.c
index fc157af..0d698f9 100644
--- a/drivers/media/usb/em28xx/em28xx-core.c
+++ b/drivers/media/usb/em28xx/em28xx-core.c
@@ -941,6 +941,7 @@ static void em28xx_irq_callback(struct urb *urb)
{
struct em28xx *dev = urb->context;
int i;
+ unsigned long flags;

switch (urb->status) {
case 0: /* success */
@@ -956,9 +957,9 @@ static void em28xx_irq_callback(struct urb *urb)
}

/* Copy data from URB */
- spin_lock(&dev->slock);
+ spin_lock_irqsave(&dev->slock, flags);
dev->usb_ctl.urb_data_copy(dev, urb);
- spin_unlock(&dev->slock);
+ spin_unlock_irqrestore(&dev->slock, flags);

/* Reset urb buffers */
for (i = 0; i < urb->number_of_packets; i++) {
--
1.7.9.5


2013-07-11 09:11:19

by Ming Lei

[permalink] [raw]
Subject: [PATCH 35/50] media: usb: cx231xx: spin_lock in complete() cleanup

Complete() will be run with interrupt enabled, so change to
spin_lock_irqsave().

Cc: Mauro Carvalho Chehab <[email protected]>
Cc: Hans Verkuil <[email protected]>
Cc: [email protected]
Signed-off-by: Ming Lei <[email protected]>
---
drivers/media/usb/cx231xx/cx231xx-audio.c | 6 ++++++
drivers/media/usb/cx231xx/cx231xx-core.c | 10 ++++++----
drivers/media/usb/cx231xx/cx231xx-vbi.c | 5 +++--
3 files changed, 15 insertions(+), 6 deletions(-)

diff --git a/drivers/media/usb/cx231xx/cx231xx-audio.c b/drivers/media/usb/cx231xx/cx231xx-audio.c
index 81a1d97..58c1b5c 100644
--- a/drivers/media/usb/cx231xx/cx231xx-audio.c
+++ b/drivers/media/usb/cx231xx/cx231xx-audio.c
@@ -136,6 +136,7 @@ static void cx231xx_audio_isocirq(struct urb *urb)
stride = runtime->frame_bits >> 3;

for (i = 0; i < urb->number_of_packets; i++) {
+ unsigned long flags;
int length = urb->iso_frame_desc[i].actual_length /
stride;
cp = (unsigned char *)urb->transfer_buffer +
@@ -158,6 +159,7 @@ static void cx231xx_audio_isocirq(struct urb *urb)
length * stride);
}

+ local_irq_save(flags);
snd_pcm_stream_lock(substream);

dev->adev.hwptr_done_capture += length;
@@ -174,6 +176,7 @@ static void cx231xx_audio_isocirq(struct urb *urb)
period_elapsed = 1;
}
snd_pcm_stream_unlock(substream);
+ local_irq_restore(flags);
}
if (period_elapsed)
snd_pcm_period_elapsed(substream);
@@ -224,6 +227,7 @@ static void cx231xx_audio_bulkirq(struct urb *urb)
stride = runtime->frame_bits >> 3;

if (1) {
+ unsigned long flags;
int length = urb->actual_length /
stride;
cp = (unsigned char *)urb->transfer_buffer;
@@ -242,6 +246,7 @@ static void cx231xx_audio_bulkirq(struct urb *urb)
length * stride);
}

+ local_irq_save(flags);
snd_pcm_stream_lock(substream);

dev->adev.hwptr_done_capture += length;
@@ -258,6 +263,7 @@ static void cx231xx_audio_bulkirq(struct urb *urb)
period_elapsed = 1;
}
snd_pcm_stream_unlock(substream);
+ local_irq_restore(flags);
}
if (period_elapsed)
snd_pcm_period_elapsed(substream);
diff --git a/drivers/media/usb/cx231xx/cx231xx-core.c b/drivers/media/usb/cx231xx/cx231xx-core.c
index 4ba3ce0..593b397 100644
--- a/drivers/media/usb/cx231xx/cx231xx-core.c
+++ b/drivers/media/usb/cx231xx/cx231xx-core.c
@@ -798,6 +798,7 @@ static void cx231xx_isoc_irq_callback(struct urb *urb)
container_of(dma_q, struct cx231xx_video_mode, vidq);
struct cx231xx *dev = container_of(vmode, struct cx231xx, video_mode);
int i;
+ unsigned long flags;

switch (urb->status) {
case 0: /* success */
@@ -813,9 +814,9 @@ static void cx231xx_isoc_irq_callback(struct urb *urb)
}

/* Copy data from URB */
- spin_lock(&dev->video_mode.slock);
+ spin_lock_irqsave(&dev->video_mode.slock, flags);
dev->video_mode.isoc_ctl.isoc_copy(dev, urb);
- spin_unlock(&dev->video_mode.slock);
+ spin_unlock_irqrestore(&dev->video_mode.slock, flags);

/* Reset urb buffers */
for (i = 0; i < urb->number_of_packets; i++) {
@@ -842,6 +843,7 @@ static void cx231xx_bulk_irq_callback(struct urb *urb)
struct cx231xx_video_mode *vmode =
container_of(dma_q, struct cx231xx_video_mode, vidq);
struct cx231xx *dev = container_of(vmode, struct cx231xx, video_mode);
+ unsigned long flags;

switch (urb->status) {
case 0: /* success */
@@ -857,9 +859,9 @@ static void cx231xx_bulk_irq_callback(struct urb *urb)
}

/* Copy data from URB */
- spin_lock(&dev->video_mode.slock);
+ spin_lock_irqsave(&dev->video_mode.slock, flags);
dev->video_mode.bulk_ctl.bulk_copy(dev, urb);
- spin_unlock(&dev->video_mode.slock);
+ spin_unlock_irqrestore(&dev->video_mode.slock, flags);

/* Reset urb buffers */
urb->status = usb_submit_urb(urb, GFP_ATOMIC);
diff --git a/drivers/media/usb/cx231xx/cx231xx-vbi.c b/drivers/media/usb/cx231xx/cx231xx-vbi.c
index c027942..38e78f8 100644
--- a/drivers/media/usb/cx231xx/cx231xx-vbi.c
+++ b/drivers/media/usb/cx231xx/cx231xx-vbi.c
@@ -306,6 +306,7 @@ static void cx231xx_irq_vbi_callback(struct urb *urb)
struct cx231xx_video_mode *vmode =
container_of(dma_q, struct cx231xx_video_mode, vidq);
struct cx231xx *dev = container_of(vmode, struct cx231xx, vbi_mode);
+ unsigned long flags;

switch (urb->status) {
case 0: /* success */
@@ -322,9 +323,9 @@ static void cx231xx_irq_vbi_callback(struct urb *urb)
}

/* Copy data from URB */
- spin_lock(&dev->vbi_mode.slock);
+ spin_lock_irqsave(&dev->vbi_mode.slock, flags);
dev->vbi_mode.bulk_ctl.bulk_copy(dev, urb);
- spin_unlock(&dev->vbi_mode.slock);
+ spin_unlock_irqrestore(&dev->vbi_mode.slock, flags);

/* Reset status */
urb->status = 0;
--
1.7.9.5


2013-07-11 09:10:38

by Ming Lei

[permalink] [raw]
Subject: [PATCH 30/50] wireless: ath9k: spin_lock in complete() cleanup

Complete() will be run with interrupt enabled, so change to
spin_lock_irqsave().

Cc: "Luis R. Rodriguez" <[email protected]>
Cc: "John W. Linville" <[email protected]>
Cc: [email protected]
Cc: [email protected]
Signed-off-by: Ming Lei <[email protected]>
---
drivers/net/wireless/ath/ath9k/hif_usb.c | 29 ++++++++++++++-----------
drivers/net/wireless/ath/ath9k/htc_drv_txrx.c | 9 ++++----
drivers/net/wireless/ath/ath9k/wmi.c | 11 +++++-----
3 files changed, 27 insertions(+), 22 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c
index 9e582e1..9d5e15a 100644
--- a/drivers/net/wireless/ath/ath9k/hif_usb.c
+++ b/drivers/net/wireless/ath/ath9k/hif_usb.c
@@ -136,6 +136,7 @@ static void hif_usb_mgmt_cb(struct urb *urb)
struct cmd_buf *cmd = (struct cmd_buf *)urb->context;
struct hif_device_usb *hif_dev;
bool txok = true;
+ unsigned long flags;

if (!cmd || !cmd->skb || !cmd->hif_dev)
return;
@@ -155,14 +156,14 @@ static void hif_usb_mgmt_cb(struct urb *urb)
* If the URBs are being flushed, no need to complete
* this packet.
*/
- spin_lock(&hif_dev->tx.tx_lock);
+ spin_lock_irqsave(&hif_dev->tx.tx_lock, flags);
if (hif_dev->tx.flags & HIF_USB_TX_FLUSH) {
- spin_unlock(&hif_dev->tx.tx_lock);
+ spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags);
dev_kfree_skb_any(cmd->skb);
kfree(cmd);
return;
}
- spin_unlock(&hif_dev->tx.tx_lock);
+ spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags);

break;
default:
@@ -253,6 +254,7 @@ static void hif_usb_tx_cb(struct urb *urb)
struct tx_buf *tx_buf = (struct tx_buf *) urb->context;
struct hif_device_usb *hif_dev;
bool txok = true;
+ unsigned long flags;

if (!tx_buf || !tx_buf->hif_dev)
return;
@@ -272,13 +274,13 @@ static void hif_usb_tx_cb(struct urb *urb)
* If the URBs are being flushed, no need to add this
* URB to the free list.
*/
- spin_lock(&hif_dev->tx.tx_lock);
+ spin_lock_irqsave(&hif_dev->tx.tx_lock, flags);
if (hif_dev->tx.flags & HIF_USB_TX_FLUSH) {
- spin_unlock(&hif_dev->tx.tx_lock);
+ spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags);
ath9k_skb_queue_purge(hif_dev, &tx_buf->skb_queue);
return;
}
- spin_unlock(&hif_dev->tx.tx_lock);
+ spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags);

break;
default:
@@ -293,13 +295,13 @@ static void hif_usb_tx_cb(struct urb *urb)
__skb_queue_head_init(&tx_buf->skb_queue);

/* Add this TX buffer to the free list */
- spin_lock(&hif_dev->tx.tx_lock);
+ spin_lock_irqsave(&hif_dev->tx.tx_lock, flags);
list_move_tail(&tx_buf->list, &hif_dev->tx.tx_buf);
hif_dev->tx.tx_buf_cnt++;
if (!(hif_dev->tx.flags & HIF_USB_TX_STOP))
__hif_usb_tx(hif_dev); /* Check for pending SKBs */
TX_STAT_INC(buf_completed);
- spin_unlock(&hif_dev->tx.tx_lock);
+ spin_unlock_irqrestore(&hif_dev->tx.tx_lock, flags);
}

/* TX lock has to be taken */
@@ -530,8 +532,9 @@ static void ath9k_hif_usb_rx_stream(struct hif_device_usb *hif_dev,
int rx_remain_len, rx_pkt_len;
u16 pool_index = 0;
u8 *ptr;
+ unsigned long flags;

- spin_lock(&hif_dev->rx_lock);
+ spin_lock_irqsave(&hif_dev->rx_lock, flags);

rx_remain_len = hif_dev->rx_remain_len;
rx_pkt_len = hif_dev->rx_transfer_len;
@@ -559,7 +562,7 @@ static void ath9k_hif_usb_rx_stream(struct hif_device_usb *hif_dev,
}
}

- spin_unlock(&hif_dev->rx_lock);
+ spin_unlock_irqrestore(&hif_dev->rx_lock, flags);

while (index < len) {
u16 pkt_len;
@@ -585,7 +588,7 @@ static void ath9k_hif_usb_rx_stream(struct hif_device_usb *hif_dev,
index = index + 4 + pkt_len + pad_len;

if (index > MAX_RX_BUF_SIZE) {
- spin_lock(&hif_dev->rx_lock);
+ spin_lock_irqsave(&hif_dev->rx_lock, flags);
hif_dev->rx_remain_len = index - MAX_RX_BUF_SIZE;
hif_dev->rx_transfer_len =
MAX_RX_BUF_SIZE - chk_idx - 4;
@@ -595,7 +598,7 @@ static void ath9k_hif_usb_rx_stream(struct hif_device_usb *hif_dev,
if (!nskb) {
dev_err(&hif_dev->udev->dev,
"ath9k_htc: RX memory allocation error\n");
- spin_unlock(&hif_dev->rx_lock);
+ spin_unlock_irqrestore(&hif_dev->rx_lock, flags);
goto err;
}
skb_reserve(nskb, 32);
@@ -606,7 +609,7 @@ static void ath9k_hif_usb_rx_stream(struct hif_device_usb *hif_dev,

/* Record the buffer pointer */
hif_dev->remain_skb = nskb;
- spin_unlock(&hif_dev->rx_lock);
+ spin_unlock_irqrestore(&hif_dev->rx_lock, flags);
} else {
nskb = __dev_alloc_skb(pkt_len + 32, GFP_ATOMIC);
if (!nskb) {
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
index e602c95..a6f34f8 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
@@ -1156,25 +1156,26 @@ void ath9k_htc_rxep(void *drv_priv, struct sk_buff *skb,
struct ath_hw *ah = priv->ah;
struct ath_common *common = ath9k_hw_common(ah);
struct ath9k_htc_rxbuf *rxbuf = NULL, *tmp_buf = NULL;
+ unsigned long flags;

- spin_lock(&priv->rx.rxbuflock);
+ spin_lock_irqsave(&priv->rx.rxbuflock, flags);
list_for_each_entry(tmp_buf, &priv->rx.rxbuf, list) {
if (!tmp_buf->in_process) {
rxbuf = tmp_buf;
break;
}
}
- spin_unlock(&priv->rx.rxbuflock);
+ spin_unlock_irqrestore(&priv->rx.rxbuflock, flags);

if (rxbuf == NULL) {
ath_dbg(common, ANY, "No free RX buffer\n");
goto err;
}

- spin_lock(&priv->rx.rxbuflock);
+ spin_lock_irqsave(&priv->rx.rxbuflock, flags);
rxbuf->skb = skb;
rxbuf->in_process = true;
- spin_unlock(&priv->rx.rxbuflock);
+ spin_unlock_irqrestore(&priv->rx.rxbuflock, flags);

tasklet_schedule(&priv->rx_tasklet);
return;
diff --git a/drivers/net/wireless/ath/ath9k/wmi.c b/drivers/net/wireless/ath/ath9k/wmi.c
index 65c8894..101b771 100644
--- a/drivers/net/wireless/ath/ath9k/wmi.c
+++ b/drivers/net/wireless/ath/ath9k/wmi.c
@@ -207,6 +207,7 @@ static void ath9k_wmi_ctrl_rx(void *priv, struct sk_buff *skb,
struct wmi *wmi = (struct wmi *) priv;
struct wmi_cmd_hdr *hdr;
u16 cmd_id;
+ unsigned long flags;

if (unlikely(wmi->stopped))
goto free_skb;
@@ -215,20 +216,20 @@ static void ath9k_wmi_ctrl_rx(void *priv, struct sk_buff *skb,
cmd_id = be16_to_cpu(hdr->command_id);

if (cmd_id & 0x1000) {
- spin_lock(&wmi->wmi_lock);
+ spin_lock_irqsave(&wmi->wmi_lock, flags);
__skb_queue_tail(&wmi->wmi_event_queue, skb);
- spin_unlock(&wmi->wmi_lock);
+ spin_unlock_irqrestore(&wmi->wmi_lock, flags);
tasklet_schedule(&wmi->wmi_event_tasklet);
return;
}

/* Check if there has been a timeout. */
- spin_lock(&wmi->wmi_lock);
+ spin_lock_irqsave(&wmi->wmi_lock, flags);
if (cmd_id != wmi->last_cmd_id) {
- spin_unlock(&wmi->wmi_lock);
+ spin_unlock_irqrestore(&wmi->wmi_lock, flags);
goto free_skb;
}
- spin_unlock(&wmi->wmi_lock);
+ spin_unlock_irqrestore(&wmi->wmi_lock, flags);

/* WMI command response */
ath9k_wmi_rsp_callback(wmi, skb);
--
1.7.9.5


2013-07-11 09:07:43

by Ming Lei

[permalink] [raw]
Subject: [PATCH 08/50] USB: legousbtower: spin_lock in complete() cleanup

Complete() will be run with interrupt enabled, so change to
spin_lock_irqsave().

Cc: Juergen Stuber <[email protected]>
Signed-off-by: Ming Lei <[email protected]>
---
drivers/usb/misc/legousbtower.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/usb/misc/legousbtower.c b/drivers/usb/misc/legousbtower.c
index 8089479..4044989 100644
--- a/drivers/usb/misc/legousbtower.c
+++ b/drivers/usb/misc/legousbtower.c
@@ -771,6 +771,7 @@ static void tower_interrupt_in_callback (struct urb *urb)
struct lego_usb_tower *dev = urb->context;
int status = urb->status;
int retval;
+ unsigned long flags;

dbg(4, "%s: enter, status %d", __func__, status);

@@ -788,7 +789,7 @@ static void tower_interrupt_in_callback (struct urb *urb)
}

if (urb->actual_length > 0) {
- spin_lock (&dev->read_buffer_lock);
+ spin_lock_irqsave (&dev->read_buffer_lock, flags);
if (dev->read_buffer_length + urb->actual_length < read_buffer_size) {
memcpy (dev->read_buffer + dev->read_buffer_length,
dev->interrupt_in_buffer,
@@ -799,7 +800,7 @@ static void tower_interrupt_in_callback (struct urb *urb)
} else {
printk(KERN_WARNING "%s: read_buffer overflow, %d bytes dropped", __func__, urb->actual_length);
}
- spin_unlock (&dev->read_buffer_lock);
+ spin_unlock_irqrestore (&dev->read_buffer_lock, flags);
}

resubmit:
--
1.7.9.5


2013-07-11 14:53:02

by Ming Lei

[permalink] [raw]
Subject: Re: [PATCH 45/50] sound: usb: usx2y: spin_lock in complete() cleanup

On Thu, Jul 11, 2013 at 10:34 PM, Takashi Iwai <[email protected]> wrote:
> At Thu, 11 Jul 2013 22:13:35 +0800,
> Ming Lei wrote:
>>
>> On Thu, Jul 11, 2013 at 9:50 PM, Takashi Iwai <[email protected]> wrote:
>> > At Thu, 11 Jul 2013 17:08:30 +0400,
>> > Sergei Shtylyov wrote:
>> >>
>> >> On 11-07-2013 13:06, Ming Lei wrote:
>> >>
>> >> > Complete() will be run with interrupt enabled, so change to
>> >> > spin_lock_irqsave().
>> >>
>> >> Changelog doesn't match the patch.
>> >
>> > Yep, but moreover...
>> >
>> >> > Cc: Jaroslav Kysela <[email protected]>
>> >> > Cc: Takashi Iwai <[email protected]>
>> >> > Cc: [email protected]
>> >> > Signed-off-by: Ming Lei <[email protected]>
>> >> > ---
>> >> > sound/usb/usx2y/usbusx2yaudio.c | 4 ++++
>> >> > 1 file changed, 4 insertions(+)
>> >>
>> >> > diff --git a/sound/usb/usx2y/usbusx2yaudio.c b/sound/usb/usx2y/usbusx2yaudio.c
>> >> > index 4967fe9..e2ee893 100644
>> >> > --- a/sound/usb/usx2y/usbusx2yaudio.c
>> >> > +++ b/sound/usb/usx2y/usbusx2yaudio.c
>> >> > @@ -273,7 +273,11 @@ static void usX2Y_clients_stop(struct usX2Ydev *usX2Y)
>> >> > struct snd_usX2Y_substream *subs = usX2Y->subs[s];
>> >> > if (subs) {
>> >> > if (atomic_read(&subs->state) >= state_PRERUNNING) {
>> >> > + unsigned long flags;
>> >> > +
>> >> > + local_irq_save(flags);
>> >> > snd_pcm_stop(subs->pcm_substream, SNDRV_PCM_STATE_XRUN);
>> >> > + local_irq_restore(flags);
>> >> > }
>> >
>> > ... actually this snd_pcm_stop() call should have been covered by
>> > snd_pcm_stream_lock(). Maybe it'd be enough to have a single patch
>> > together with the change, i.e. wrapping with
>> > snd_pcm_stream_lock_irqsave().
>>
>> Please use snd_pcm_stream_lock_irqsave() so that I can avoid sending
>> out similar patch later, :-)
>>
>> >
>> > I'll prepare the patch for 3.11 independently from your patch series,
>> > so please drop this one.
>>
>> OK, thanks for dealing with that.
>>
>> >
>> >
>> > BTW, the word "cleanup" in the subject is inappropriate. This is
>> > rather a fix together with the core change.
>>
>> It is a cleanup since the patchset only addresses lock problem which
>> is caused by the tasklet conversion.
>
> Well, the conversion to irqsave() is needed for the future drop of
> irq_save() in the caller, right? Then this isn't a cleanup but a
> preparation for movement ahead.

Sounds more accurate, and I will change the title in next round, :-)

Thanks,
--
Ming Lei

2013-07-14 13:26:44

by Andy Walls

[permalink] [raw]
Subject: Re: [PATCH 00/50] USB: cleanup spin_lock in URB->complete()

On Thu, 2013-07-11 at 17:05 +0800, Ming Lei wrote:
> Hi,
>
> As we are going to run URB->complete() in tasklet context[1][2],

Hi,

Please pardon my naivete, but why was it decided to use tasklets to
defer work, as opposed to some other deferred work mechanism?

It seems to me that getting rid of tasklets has been an objective for
years:

http://lwn.net/Articles/239633/
http://lwn.net/Articles/520076/
http://lwn.net/Articles/240054/


Regards,
Andy

> and
> hard interrupt may be enabled when running URB completion handler[3],
> so we might need to disable interrupt when acquiring one lock in
> the completion handler for the below reasons:
>
> - URB->complete() holds a subsystem wide lock which may be acquired
> in another hard irq context, and the subsystem wide lock is acquired
> by spin_lock()/read_lock()/write_lock() in complete()
>
> - URB->complete() holds a private lock with spin_lock()/read_lock()/write_lock()
> but driver may export APIs to make other drivers acquire the same private
> lock in its interrupt handler.
>
> For the sake of safety and making the change simple, this patch set
> converts all spin_lock()/read_lock()/write_lock() in completion handler
> path into their irqsave version mechanically.
>
> But if you are sure the above two cases do not happen in your driver,
> please let me know and I can drop the unnecessary change.
>
> Also if you find some conversions are missed, also please let me know so
> that I can add it in the next round.
>
>
> [1], http://marc.info/?l=linux-usb&m=137286322526312&w=2
> [2], http://marc.info/?l=linux-usb&m=137286326726326&w=2
> [3], http://marc.info/?l=linux-usb&m=137286330626363&w=2
>
[snip]
>
>
> Thanks,
> --
> Ming Lei



2013-07-11 09:13:17

by Ming Lei

[permalink] [raw]
Subject: [PATCH 50/50] staging: vt6656: spin_lock in complete() cleanup

Complete() will be run with interrupt enabled, so change to
spin_lock_irqsave().

Cc: [email protected]
Signed-off-by: Ming Lei <[email protected]>
---
drivers/staging/vt6656/usbpipe.c | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/drivers/staging/vt6656/usbpipe.c b/drivers/staging/vt6656/usbpipe.c
index 098be60..0282f2e 100644
--- a/drivers/staging/vt6656/usbpipe.c
+++ b/drivers/staging/vt6656/usbpipe.c
@@ -485,6 +485,7 @@ static void s_nsBulkInUsbIoCompleteRead(struct urb *urb)
int bIndicateReceive = false;
int bReAllocSkb = false;
int status;
+ unsigned long flags;

DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"---->s_nsBulkInUsbIoCompleteRead\n");
status = urb->status;
@@ -515,18 +516,18 @@ static void s_nsBulkInUsbIoCompleteRead(struct urb *urb)
STAvUpdateUSBCounter(&pDevice->scStatistic.USB_BulkInStat, status);

if (bIndicateReceive) {
- spin_lock(&pDevice->lock);
+ spin_lock_irqsave(&pDevice->lock, flags);
if (RXbBulkInProcessData(pDevice, pRCB, bytesRead) == true)
bReAllocSkb = true;
- spin_unlock(&pDevice->lock);
+ spin_unlock_irqrestore(&pDevice->lock, flags);
}
pRCB->Ref--;
if (pRCB->Ref == 0)
{
DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"RxvFreeNormal %d \n",pDevice->NumRecvFreeList);
- spin_lock(&pDevice->lock);
+ spin_lock_irqsave(&pDevice->lock, flags);
RXvFreeRCB(pRCB, bReAllocSkb);
- spin_unlock(&pDevice->lock);
+ spin_unlock_irqrestore(&pDevice->lock, flags);
}

return;
--
1.7.9.5


2013-07-11 09:13:02

by Ming Lei

[permalink] [raw]
Subject: [PATCH 48/50] staging: bcm: spin_lock in complete() cleanup

Complete() will be run with interrupt enabled, so change to
spin_lock_irqsave().

Cc: [email protected]
Signed-off-by: Ming Lei <[email protected]>
---
drivers/staging/bcm/InterfaceRx.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/staging/bcm/InterfaceRx.c b/drivers/staging/bcm/InterfaceRx.c
index 26f5bc7..00af901 100644
--- a/drivers/staging/bcm/InterfaceRx.c
+++ b/drivers/staging/bcm/InterfaceRx.c
@@ -47,6 +47,7 @@ static void read_bulk_callback(struct urb *urb)
struct bcm_interface_adapter *psIntfAdapter = pRcb->psIntfAdapter;
struct bcm_mini_adapter *Adapter = psIntfAdapter->psAdapter;
struct bcm_leader *pLeader = urb->transfer_buffer;
+ unsigned long flags;

if (unlikely(netif_msg_rx_status(Adapter)))
pr_info(PFX "%s: rx urb status %d length %d\n",
@@ -129,9 +130,9 @@ static void read_bulk_callback(struct urb *urb)
(sizeof(struct bcm_leader)), pLeader->PLength);
skb->len = pLeader->PLength + sizeof(USHORT);

- spin_lock(&Adapter->control_queue_lock);
+ spin_lock_irqsave(&Adapter->control_queue_lock, flags);
ENQUEUEPACKET(Adapter->RxControlHead,Adapter->RxControlTail,skb);
- spin_unlock(&Adapter->control_queue_lock);
+ spin_unlock_irqretore(&Adapter->control_queue_lock, flags);

atomic_inc(&Adapter->cntrlpktCnt);
wake_up(&Adapter->process_rx_cntrlpkt);
--
1.7.9.5


2013-07-11 09:09:59

by Ming Lei

[permalink] [raw]
Subject: [PATCH 25/50] ISDN: hfcsusb: spin_lock in complete() cleanup

Complete() will be run with interrupt enabled, so change to
spin_lock_irqsave().

Cc: Karsten Keil <[email protected]>
Cc: "David S. Miller" <[email protected]>
Cc: [email protected]
Signed-off-by: Ming Lei <[email protected]>
---
drivers/isdn/hardware/mISDN/hfcsusb.c | 36 ++++++++++++++++++---------------
1 file changed, 20 insertions(+), 16 deletions(-)

diff --git a/drivers/isdn/hardware/mISDN/hfcsusb.c b/drivers/isdn/hardware/mISDN/hfcsusb.c
index 114f3bc..082f9e0 100644
--- a/drivers/isdn/hardware/mISDN/hfcsusb.c
+++ b/drivers/isdn/hardware/mISDN/hfcsusb.c
@@ -819,6 +819,7 @@ hfcsusb_rx_frame(struct usb_fifo *fifo, __u8 *data, unsigned int len,
int fifon = fifo->fifonum;
int i;
int hdlc = 0;
+ unsigned long flags;

if (debug & DBG_HFC_CALL_TRACE)
printk(KERN_DEBUG "%s: %s: fifo(%i) len(%i) "
@@ -835,7 +836,7 @@ hfcsusb_rx_frame(struct usb_fifo *fifo, __u8 *data, unsigned int len,
return;
}

- spin_lock(&hw->lock);
+ spin_lock_irqsave(&hw->lock, flags);
if (fifo->dch) {
rx_skb = fifo->dch->rx_skb;
maxlen = fifo->dch->maxlen;
@@ -844,7 +845,7 @@ hfcsusb_rx_frame(struct usb_fifo *fifo, __u8 *data, unsigned int len,
if (fifo->bch) {
if (test_bit(FLG_RX_OFF, &fifo->bch->Flags)) {
fifo->bch->dropcnt += len;
- spin_unlock(&hw->lock);
+ spin_unlock_irqrestore(&hw->lock, flags);
return;
}
maxlen = bchannel_get_rxbuf(fifo->bch, len);
@@ -854,7 +855,7 @@ hfcsusb_rx_frame(struct usb_fifo *fifo, __u8 *data, unsigned int len,
skb_trim(rx_skb, 0);
pr_warning("%s.B%d: No bufferspace for %d bytes\n",
hw->name, fifo->bch->nr, len);
- spin_unlock(&hw->lock);
+ spin_unlock_irqrestore(&hw->lock, flags);
return;
}
maxlen = fifo->bch->maxlen;
@@ -878,7 +879,7 @@ hfcsusb_rx_frame(struct usb_fifo *fifo, __u8 *data, unsigned int len,
} else {
printk(KERN_DEBUG "%s: %s: No mem for rx_skb\n",
hw->name, __func__);
- spin_unlock(&hw->lock);
+ spin_unlock_irqrestore(&hw->lock, flags);
return;
}
}
@@ -888,7 +889,7 @@ hfcsusb_rx_frame(struct usb_fifo *fifo, __u8 *data, unsigned int len,
"for fifo(%d) HFCUSB_D_RX\n",
hw->name, __func__, fifon);
skb_trim(rx_skb, 0);
- spin_unlock(&hw->lock);
+ spin_unlock_irqrestore(&hw->lock, flags);
return;
}
}
@@ -942,7 +943,7 @@ hfcsusb_rx_frame(struct usb_fifo *fifo, __u8 *data, unsigned int len,
/* deliver transparent data to layer2 */
recv_Bchannel(fifo->bch, MISDN_ID_ANY, false);
}
- spin_unlock(&hw->lock);
+ spin_unlock_irqrestore(&hw->lock, flags);
}

static void
@@ -979,18 +980,19 @@ rx_iso_complete(struct urb *urb)
__u8 *buf;
static __u8 eof[8];
__u8 s0_state;
+ unsigned long flags;

fifon = fifo->fifonum;
status = urb->status;

- spin_lock(&hw->lock);
+ spin_lock_irqsave(&hw->lock, flags);
if (fifo->stop_gracefull) {
fifo->stop_gracefull = 0;
fifo->active = 0;
- spin_unlock(&hw->lock);
+ spin_unlock_irqrestore(&hw->lock, flags);
return;
}
- spin_unlock(&hw->lock);
+ spin_unlock_irqrestore(&hw->lock, flags);

/*
* ISO transfer only partially completed,
@@ -1096,15 +1098,16 @@ rx_int_complete(struct urb *urb)
struct usb_fifo *fifo = (struct usb_fifo *) urb->context;
struct hfcsusb *hw = fifo->hw;
static __u8 eof[8];
+ unsigned long flags;

- spin_lock(&hw->lock);
+ spin_lock_irqsave(&hw->lock, flags);
if (fifo->stop_gracefull) {
fifo->stop_gracefull = 0;
fifo->active = 0;
- spin_unlock(&hw->lock);
+ spin_unlock_irqrestore(&hw->lock, flags);
return;
}
- spin_unlock(&hw->lock);
+ spin_unlock_irqrestore(&hw->lock, flags);

fifon = fifo->fifonum;
if ((!fifo->active) || (urb->status)) {
@@ -1172,12 +1175,13 @@ tx_iso_complete(struct urb *urb)
int *tx_idx;
int frame_complete, fifon, status, fillempty = 0;
__u8 threshbit, *p;
+ unsigned long flags;

- spin_lock(&hw->lock);
+ spin_lock_irqsave(&hw->lock, flags);
if (fifo->stop_gracefull) {
fifo->stop_gracefull = 0;
fifo->active = 0;
- spin_unlock(&hw->lock);
+ spin_unlock_irqrestore(&hw->lock, flags);
return;
}

@@ -1195,7 +1199,7 @@ tx_iso_complete(struct urb *urb)
} else {
printk(KERN_DEBUG "%s: %s: neither BCH nor DCH\n",
hw->name, __func__);
- spin_unlock(&hw->lock);
+ spin_unlock_irqrestore(&hw->lock, flags);
return;
}

@@ -1375,7 +1379,7 @@ tx_iso_complete(struct urb *urb)
hw->name, __func__,
symbolic(urb_errlist, status), status, fifon);
}
- spin_unlock(&hw->lock);
+ spin_unlock_irqrestore(&hw->lock, flags);
}

/*
--
1.7.9.5


2013-07-11 09:11:50

by Ming Lei

[permalink] [raw]
Subject: [PATCH 39/50] media: usb: tm6000: spin_lock in complete() cleanup

Complete() will be run with interrupt enabled, so change to
spin_lock_irqsave().

Cc: Mauro Carvalho Chehab <[email protected]>
Cc: [email protected]
Signed-off-by: Ming Lei <[email protected]>
---
drivers/media/usb/tm6000/tm6000-video.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/media/usb/tm6000/tm6000-video.c b/drivers/media/usb/tm6000/tm6000-video.c
index cc1aa14..8bb440f 100644
--- a/drivers/media/usb/tm6000/tm6000-video.c
+++ b/drivers/media/usb/tm6000/tm6000-video.c
@@ -434,6 +434,7 @@ static void tm6000_irq_callback(struct urb *urb)
struct tm6000_dmaqueue *dma_q = urb->context;
struct tm6000_core *dev = container_of(dma_q, struct tm6000_core, vidq);
int i;
+ unsigned long flags;

switch (urb->status) {
case 0:
@@ -450,9 +451,9 @@ static void tm6000_irq_callback(struct urb *urb)
break;
}

- spin_lock(&dev->slock);
+ spin_lock_irqsave(&dev->slock, flags);
tm6000_isoc_copy(urb);
- spin_unlock(&dev->slock);
+ spin_unlock_irqrestore(&dev->slock, flags);

/* Reset urb buffers */
for (i = 0; i < urb->number_of_packets; i++) {
--
1.7.9.5


2013-07-11 09:11:57

by Ming Lei

[permalink] [raw]
Subject: [PATCH 40/50] media: dvb-core: spin_lock in complete() cleanup

Complete() will be run with interrupt enabled, so change to
spin_lock_irqsave().

These functions may be called inside URB->complete(), so use
spin_lock_irqsave().

Cc: Mauro Carvalho Chehab <[email protected]>
Cc: [email protected]
Signed-off-by: Ming Lei <[email protected]>
---
drivers/media/dvb-core/dvb_demux.c | 17 +++++++++++------
1 file changed, 11 insertions(+), 6 deletions(-)

diff --git a/drivers/media/dvb-core/dvb_demux.c b/drivers/media/dvb-core/dvb_demux.c
index 3485655..58de441 100644
--- a/drivers/media/dvb-core/dvb_demux.c
+++ b/drivers/media/dvb-core/dvb_demux.c
@@ -476,7 +476,9 @@ static void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf)
void dvb_dmx_swfilter_packets(struct dvb_demux *demux, const u8 *buf,
size_t count)
{
- spin_lock(&demux->lock);
+ unsigned long flags;
+
+ spin_lock_irqsave(&demux->lock, flags);

while (count--) {
if (buf[0] == 0x47)
@@ -484,7 +486,7 @@ void dvb_dmx_swfilter_packets(struct dvb_demux *demux, const u8 *buf,
buf += 188;
}

- spin_unlock(&demux->lock);
+ spin_unlock_irqrestore(&demux->lock, flags);
}

EXPORT_SYMBOL(dvb_dmx_swfilter_packets);
@@ -519,8 +521,9 @@ static inline void _dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf,
{
int p = 0, i, j;
const u8 *q;
+ unsigned long flags;

- spin_lock(&demux->lock);
+ spin_lock_irqsave(&demux->lock, flags);

if (demux->tsbufp) { /* tsbuf[0] is now 0x47. */
i = demux->tsbufp;
@@ -564,7 +567,7 @@ static inline void _dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf,
}

bailout:
- spin_unlock(&demux->lock);
+ spin_unlock_irqrestore(&demux->lock, flags);
}

void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count)
@@ -581,11 +584,13 @@ EXPORT_SYMBOL(dvb_dmx_swfilter_204);

void dvb_dmx_swfilter_raw(struct dvb_demux *demux, const u8 *buf, size_t count)
{
- spin_lock(&demux->lock);
+ unsigned long flags;
+
+ spin_lock_irqsave(&demux->lock, flags);

demux->feed->cb.ts(buf, count, NULL, 0, &demux->feed->feed.ts, DMX_OK);

- spin_unlock(&demux->lock);
+ spin_unlock_irqrestore(&demux->lock, flags);
}
EXPORT_SYMBOL(dvb_dmx_swfilter_raw);

--
1.7.9.5