[alsa-devel] [PATCH] ALSA: usb - prevent kernel panic on disconnect

Fix 100% reproducible kernel panic when a USB audio device is disconnected during playback. When the PCM substream is NULL, any dereference causes a kernel panic. This isn't a recent problem, the crash happened with a 2.6.35 kernel as well
Note that this is only a work-around, it does not address the root cause of this inconsistency between urbs and PCM states. The dmesg below shows two calls to snd_urb_complete, the substream is NULL and the state is either running or stopped. This doesn't make any sense.
Thanks to Sarah Sharp sarah.a.sharp@linux.intel.com for her help.
usb 6-1: USB disconnect, address 16 ALSA urb.c:492: frame 0 active: -84 ALSA urb.c:197: cannot submit urb (err = -19) ALSA urb.c:492: frame 0 active: -84 ALSA urb.c:197: cannot submit urb (err = -19) ALSA urb.c:492: frame 0 active: -84 ALSA urb.c:197: cannot submit urb (err = -19) ALSA urb.c:492: frame 0 active: -84 ALSA urb.c:197: cannot submit urb (err = -19) ALSA urb.c:492: frame 0 active: -84 ALSA urb.c:197: cannot submit urb (err = -19) ALSA urb.c:197: cannot submit urb (err = -19) ALSA urb.c:492: frame 0 active: -84 ALSA urb.c:197: cannot submit urb (err = -19) ALSA urb.c:492: frame 0 active: -84 ALSA urb.c:197: cannot submit urb (err = -19) ALSA urb.c:492: frame 0 active: -84 ALSA urb.c:197: cannot submit urb (err = -19) ALSA urb.c:186: NULL substream (subs->running 1) <- How is this possible? ALSA urb.c:186: NULL substream (subs->running 0)
Signed-off-by: Pierre-Louis Bossart pierre-louis.bossart@intel.com --- usb/urb.c | 12 ++++++++++++ 1 files changed, 12 insertions(+), 0 deletions(-)
diff --git a/usb/urb.c b/usb/urb.c index e184349..1a264c2 100644 --- a/usb/urb.c +++ b/usb/urb.c @@ -170,6 +170,12 @@ static void snd_complete_urb(struct urb *urb) struct snd_pcm_substream *substream = ctx->subs->pcm_substream; int err = 0;
+ if (substream == NULL) { + snd_printd(KERN_ERR "NULL substream (subs->running %d)\n", subs->running); + clear_bit(ctx->index, &subs->active_mask); + return; + } + if ((subs->running && subs->ops.retire(subs, substream->runtime, urb)) || !subs->running || /* can be stopped during retire callback */ (err = subs->ops.prepare(subs, substream->runtime, urb)) < 0 || @@ -193,6 +199,12 @@ static void snd_complete_sync_urb(struct urb *urb) struct snd_pcm_substream *substream = ctx->subs->pcm_substream; int err = 0;
+ if (substream == NULL) { + snd_printd(KERN_ERR "NULL substream (subs->running %d)\n", subs->running); + clear_bit(ctx->index + 16, &subs->active_mask); + return; + } + if ((subs->running && subs->ops.retire_sync(subs, substream->runtime, urb)) || !subs->running || /* can be stopped during retire callback */ (err = subs->ops.prepare_sync(subs, substream->runtime, urb)) < 0 ||

Hello,
I encountered a similar problem while developing drivers for the dmx 6fire usb. Perhaps my finding could provide you with some more information about the kernel panic. I found out that if the device is removed, the isoc-packet status indicate an error in the in-urb-retire method; the urb status still is 0. This happens a few ms before the actual disconnect() handler is called. I also looked into the snd-usb-audio driver and could not find any isoc-packet status check. Maybe this could lead to inconsistencies between PCM stream state and urbs.
Greets, Torsten
---- On Wed, 09 Feb 2011 20:13:24 +0100 Pierre-Louis Bossart wrote ----
Fix 100% reproducible kernel panic when a USB audio device is disconnected during playback. When the PCM substream is NULL, any dereference causes a kernel panic. This isn't a recent problem, the crash happened with a 2.6.35 kernel as well
Note that this is only a work-around, it does not address the root cause of this inconsistency between urbs and PCM states. The dmesg below shows two calls to snd_urb_complete, the substream is NULL and the state is either running or stopped. This doesn't make any sense.
Thanks to Sarah Sharp for her help.
participants (2)
-
Pierre-Louis Bossart
-
Torsten Schenk