diff options
| author | Takashi Iwai <tiwai@suse.de> | 2014-06-25 14:24:47 +0200 |
|---|---|---|
| committer | Moyster <oysterized@gmail.com> | 2018-05-16 13:59:57 +0200 |
| commit | 2e1d377a2afc671f4257ca662bde74ebfabc35f5 (patch) | |
| tree | e5d07b7b22b176a0d6263d72f8edb9e672e3b542 /sound/usb/endpoint.c | |
| parent | 750030b3f14b07395e7674e2cfe104874bbbf88f (diff) | |
ALSA: usb-audio: Fix races at disconnection and PCM closing
When a USB-audio device is disconnected while PCM is still running, we
still see some race: the disconnect callback calls
snd_usb_endpoint_free() that calls release_urbs() and then kfree()
while a PCM stream would be closed at the same time and calls
stop_endpoints() that leads to wait_clear_urbs(). That is, the EP
object might be deallocated while a PCM stream is syncing with
wait_clear_urbs() with the same EP.
Basically calling multiple wait_clear_urbs() would work fine, also
calling wait_clear_urbs() and release_urbs() would work, too, as
wait_clear_urbs() just reads some fields in ep. The problem is the
succeeding kfree() in snd_pcm_endpoint_free().
This patch moves out the EP deallocation into the later point, the
destructor callback. At this stage, all PCMs must have been already
closed, so it's safe to free the objects.
Reported-by: Alan Stern <stern@rowland.harvard.edu>
Cc: <stable@vger.kernel.org>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Change-Id: Ia550e71981fcf7cb36312ca458029f34471c1d1e
Git-commit: 92a586bdc06de6629dae1b357dac221253f55ff8
Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
[jackp@codeaurora.org: fixed minor conflict in sound/usb/endpoint.h]
Signed-off-by: Jack Pham <jackp@codeaurora.org>
Diffstat (limited to 'sound/usb/endpoint.c')
| -rw-r--r-- | sound/usb/endpoint.c | 17 |
1 files changed, 14 insertions, 3 deletions
diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c index 308c02b2a..e3e8560c2 100644 --- a/sound/usb/endpoint.c +++ b/sound/usb/endpoint.c @@ -957,19 +957,30 @@ int snd_usb_endpoint_deactivate(struct snd_usb_endpoint *ep) } /** + * snd_usb_endpoint_release: Tear down an snd_usb_endpoint + * + * @ep: the endpoint to release + * + * This function does not care for the endpoint's use count but will tear + * down all the streaming URBs immediately. + */ +void snd_usb_endpoint_release(struct snd_usb_endpoint *ep) +{ + release_urbs(ep, 1); +} + +/** * snd_usb_endpoint_free: Free the resources of an snd_usb_endpoint * * @ep: the list header of the endpoint to free * - * This function does not care for the endpoint's use count but will tear - * down all the streaming URBs immediately and free all resources. + * This free all resources of the given ep. */ void snd_usb_endpoint_free(struct list_head *head) { struct snd_usb_endpoint *ep; ep = list_entry(head, struct snd_usb_endpoint, list); - release_urbs(ep, 1); kfree(ep); } |
