ALSA: ua101: fix crash when unplugging
If the device is unplugged while running, it is possible for a PCM device to be closed after the disconnect callback has returned. This means that kill_stream_urb() and disable_iso_interface() would try to access already-invalid or freed USB data structures. The function free_usb_related_resources() was intended to prevent this, but forgot to clear the affected variables. Reported-and-tested-by: Olivier Courtay <olivier@courtay.org> Signed-off-by: Clemens Ladisch <clemens@ladisch.de> Cc: 2.6.33+ <stable@vger.kernel.org> Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
parent
6bcbf64ace
commit
862a6244eb
|
@ -459,7 +459,8 @@ static void kill_stream_urbs(struct ua101_stream *stream)
|
|||
unsigned int i;
|
||||
|
||||
for (i = 0; i < stream->queue_length; ++i)
|
||||
usb_kill_urb(&stream->urbs[i]->urb);
|
||||
if (stream->urbs[i])
|
||||
usb_kill_urb(&stream->urbs[i]->urb);
|
||||
}
|
||||
|
||||
static int enable_iso_interface(struct ua101 *ua, unsigned int intf_index)
|
||||
|
@ -484,6 +485,9 @@ static void disable_iso_interface(struct ua101 *ua, unsigned int intf_index)
|
|||
{
|
||||
struct usb_host_interface *alts;
|
||||
|
||||
if (!ua->intf[intf_index])
|
||||
return;
|
||||
|
||||
alts = ua->intf[intf_index]->cur_altsetting;
|
||||
if (alts->desc.bAlternateSetting != 0) {
|
||||
int err = usb_set_interface(ua->dev,
|
||||
|
@ -1144,27 +1148,37 @@ static void free_stream_urbs(struct ua101_stream *stream)
|
|||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < stream->queue_length; ++i)
|
||||
for (i = 0; i < stream->queue_length; ++i) {
|
||||
kfree(stream->urbs[i]);
|
||||
stream->urbs[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void free_usb_related_resources(struct ua101 *ua,
|
||||
struct usb_interface *interface)
|
||||
{
|
||||
unsigned int i;
|
||||
struct usb_interface *intf;
|
||||
|
||||
mutex_lock(&ua->mutex);
|
||||
free_stream_urbs(&ua->capture);
|
||||
free_stream_urbs(&ua->playback);
|
||||
mutex_unlock(&ua->mutex);
|
||||
free_stream_buffers(ua, &ua->capture);
|
||||
free_stream_buffers(ua, &ua->playback);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(ua->intf); ++i)
|
||||
if (ua->intf[i]) {
|
||||
usb_set_intfdata(ua->intf[i], NULL);
|
||||
if (ua->intf[i] != interface)
|
||||
for (i = 0; i < ARRAY_SIZE(ua->intf); ++i) {
|
||||
mutex_lock(&ua->mutex);
|
||||
intf = ua->intf[i];
|
||||
ua->intf[i] = NULL;
|
||||
mutex_unlock(&ua->mutex);
|
||||
if (intf) {
|
||||
usb_set_intfdata(intf, NULL);
|
||||
if (intf != interface)
|
||||
usb_driver_release_interface(&ua101_driver,
|
||||
ua->intf[i]);
|
||||
intf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ua101_card_free(struct snd_card *card)
|
||||
|
|
Loading…
Reference in New Issue