diff options
author | Takashi Iwai <tiwai@suse.de> | 2012-10-16 16:43:39 +0200 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2012-10-30 11:07:15 +0100 |
commit | 0914f7961babbf28aaa2f19b453951fb4841c03f (patch) | |
tree | fe5c14256a1d7b2116341300dd1e8ed94ac5f576 /sound/core/rawmidi.c | |
parent | a0830dbd4e42b38aefdf3fb61ba5019a1a99ea85 (diff) | |
download | linux-0914f7961babbf28aaa2f19b453951fb4841c03f.tar.bz2 |
ALSA: Avoid endless sleep after disconnect
When disconnect callback is called, each component should wake up
sleepers and check card->shutdown flag for avoiding the endless sleep
blocking the proper resource release.
Cc: <stable@vger.kernel.org>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/core/rawmidi.c')
-rw-r--r-- | sound/core/rawmidi.c | 20 |
1 files changed, 20 insertions, 0 deletions
diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c index 7d4f62ab6711..1bb95aeea084 100644 --- a/sound/core/rawmidi.c +++ b/sound/core/rawmidi.c @@ -424,6 +424,10 @@ static int snd_rawmidi_open(struct inode *inode, struct file *file) mutex_unlock(&rmidi->open_mutex); schedule(); mutex_lock(&rmidi->open_mutex); + if (rmidi->card->shutdown) { + err = -ENODEV; + break; + } if (signal_pending(current)) { err = -ERESTARTSYS; break; @@ -995,6 +999,8 @@ static ssize_t snd_rawmidi_read(struct file *file, char __user *buf, size_t coun spin_unlock_irq(&runtime->lock); schedule(); remove_wait_queue(&runtime->sleep, &wait); + if (rfile->rmidi->card->shutdown) + return -ENODEV; if (signal_pending(current)) return result > 0 ? result : -ERESTARTSYS; if (!runtime->avail) @@ -1238,6 +1244,8 @@ static ssize_t snd_rawmidi_write(struct file *file, const char __user *buf, spin_unlock_irq(&runtime->lock); timeout = schedule_timeout(30 * HZ); remove_wait_queue(&runtime->sleep, &wait); + if (rfile->rmidi->card->shutdown) + return -ENODEV; if (signal_pending(current)) return result > 0 ? result : -ERESTARTSYS; if (!runtime->avail && !timeout) @@ -1613,9 +1621,20 @@ static int snd_rawmidi_dev_register(struct snd_device *device) static int snd_rawmidi_dev_disconnect(struct snd_device *device) { struct snd_rawmidi *rmidi = device->device_data; + int dir; mutex_lock(®ister_mutex); + mutex_lock(&rmidi->open_mutex); + wake_up(&rmidi->open_wait); list_del_init(&rmidi->list); + for (dir = 0; dir < 2; dir++) { + struct snd_rawmidi_substream *s; + list_for_each_entry(s, &rmidi->streams[dir].substreams, list) { + if (s->runtime) + wake_up(&s->runtime->sleep); + } + } + #ifdef CONFIG_SND_OSSEMUL if (rmidi->ossreg) { if ((int)rmidi->device == midi_map[rmidi->card->number]) { @@ -1630,6 +1649,7 @@ static int snd_rawmidi_dev_disconnect(struct snd_device *device) } #endif /* CONFIG_SND_OSSEMUL */ snd_unregister_device(SNDRV_DEVICE_TYPE_RAWMIDI, rmidi->card, rmidi->device); + mutex_unlock(&rmidi->open_mutex); mutex_unlock(®ister_mutex); return 0; } |