ALSA: usb-audio: Fix mutex deadlock at disconnection
The recent change for USB-audio disconnection race fixes introduced a mutex deadlock again. There is a circular dependency between chip->shutdown_rwsem and pcm->open_mutex, depicted like below, when a device is opened during the disconnection operation: A. snd_usb_audio_disconnect() -> card.c::register_mutex -> chip->shutdown_rwsem (write) -> snd_card_disconnect() -> pcm.c::register_mutex -> pcm->open_mutex B. snd_pcm_open() -> pcm->open_mutex -> snd_usb_pcm_open() -> chip->shutdown_rwsem (read) Since the chip->shutdown_rwsem protection in the case A is required only for turning on the chip->shutdown flag and it doesn't have to be taken for the whole operation, we can reduce its window in snd_usb_audio_disconnect(). Reported-by: Jiri Slaby <jslaby@suse.cz> Cc: <stable@vger.kernel.org> Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
Родитель
effded75e2
Коммит
10e44239f6
|
@ -559,9 +559,11 @@ static void snd_usb_audio_disconnect(struct usb_device *dev,
|
||||||
return;
|
return;
|
||||||
|
|
||||||
card = chip->card;
|
card = chip->card;
|
||||||
mutex_lock(®ister_mutex);
|
|
||||||
down_write(&chip->shutdown_rwsem);
|
down_write(&chip->shutdown_rwsem);
|
||||||
chip->shutdown = 1;
|
chip->shutdown = 1;
|
||||||
|
up_write(&chip->shutdown_rwsem);
|
||||||
|
|
||||||
|
mutex_lock(®ister_mutex);
|
||||||
chip->num_interfaces--;
|
chip->num_interfaces--;
|
||||||
if (chip->num_interfaces <= 0) {
|
if (chip->num_interfaces <= 0) {
|
||||||
snd_card_disconnect(card);
|
snd_card_disconnect(card);
|
||||||
|
@ -582,11 +584,9 @@ static void snd_usb_audio_disconnect(struct usb_device *dev,
|
||||||
snd_usb_mixer_disconnect(p);
|
snd_usb_mixer_disconnect(p);
|
||||||
}
|
}
|
||||||
usb_chip[chip->index] = NULL;
|
usb_chip[chip->index] = NULL;
|
||||||
up_write(&chip->shutdown_rwsem);
|
|
||||||
mutex_unlock(®ister_mutex);
|
mutex_unlock(®ister_mutex);
|
||||||
snd_card_free_when_closed(card);
|
snd_card_free_when_closed(card);
|
||||||
} else {
|
} else {
|
||||||
up_write(&chip->shutdown_rwsem);
|
|
||||||
mutex_unlock(®ister_mutex);
|
mutex_unlock(®ister_mutex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче