mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-08 03:40:35 +09:00
ALSA: usb-audio: Use rwsem for disconnect protection
commit 34f3c89fda upstream.
Replace mutex with rwsem for codec->shutdown protection so that
concurrent accesses are allowed.
Also add the protection to snd_usb_autosuspend() and
snd_usb_autoresume(), too.
Reported-by: Matthieu CASTET <matthieu.castet@parrot.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
ea7b69a0b6
commit
14565776be
@@ -335,7 +335,7 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx,
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
mutex_init(&chip->shutdown_mutex);
|
||||
init_rwsem(&chip->shutdown_rwsem);
|
||||
chip->index = idx;
|
||||
chip->dev = dev;
|
||||
chip->card = card;
|
||||
@@ -555,7 +555,7 @@ static void snd_usb_audio_disconnect(struct usb_device *dev, void *ptr)
|
||||
chip = ptr;
|
||||
card = chip->card;
|
||||
mutex_lock(®ister_mutex);
|
||||
mutex_lock(&chip->shutdown_mutex);
|
||||
down_write(&chip->shutdown_rwsem);
|
||||
chip->shutdown = 1;
|
||||
chip->num_interfaces--;
|
||||
if (chip->num_interfaces <= 0) {
|
||||
@@ -573,11 +573,11 @@ static void snd_usb_audio_disconnect(struct usb_device *dev, void *ptr)
|
||||
snd_usb_mixer_disconnect(p);
|
||||
}
|
||||
usb_chip[chip->index] = NULL;
|
||||
mutex_unlock(&chip->shutdown_mutex);
|
||||
up_write(&chip->shutdown_rwsem);
|
||||
mutex_unlock(®ister_mutex);
|
||||
snd_card_free_when_closed(card);
|
||||
} else {
|
||||
mutex_unlock(&chip->shutdown_mutex);
|
||||
up_write(&chip->shutdown_rwsem);
|
||||
mutex_unlock(®ister_mutex);
|
||||
}
|
||||
}
|
||||
@@ -609,16 +609,20 @@ int snd_usb_autoresume(struct snd_usb_audio *chip)
|
||||
{
|
||||
int err = -ENODEV;
|
||||
|
||||
down_read(&chip->shutdown_rwsem);
|
||||
if (!chip->shutdown && !chip->probing)
|
||||
err = usb_autopm_get_interface(chip->pm_intf);
|
||||
up_read(&chip->shutdown_rwsem);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
void snd_usb_autosuspend(struct snd_usb_audio *chip)
|
||||
{
|
||||
down_read(&chip->shutdown_rwsem);
|
||||
if (!chip->shutdown && !chip->probing)
|
||||
usb_autopm_put_interface(chip->pm_intf);
|
||||
up_read(&chip->shutdown_rwsem);
|
||||
}
|
||||
|
||||
static int usb_audio_suspend(struct usb_interface *intf, pm_message_t message)
|
||||
|
||||
@@ -292,7 +292,7 @@ static int get_ctl_value_v1(struct usb_mixer_elem_info *cval, int request, int v
|
||||
err = snd_usb_autoresume(cval->mixer->chip);
|
||||
if (err < 0)
|
||||
return -EIO;
|
||||
mutex_lock(&chip->shutdown_mutex);
|
||||
down_read(&chip->shutdown_rwsem);
|
||||
while (timeout-- > 0) {
|
||||
if (chip->shutdown)
|
||||
break;
|
||||
@@ -310,7 +310,7 @@ static int get_ctl_value_v1(struct usb_mixer_elem_info *cval, int request, int v
|
||||
err = -EINVAL;
|
||||
|
||||
out:
|
||||
mutex_unlock(&chip->shutdown_mutex);
|
||||
up_read(&chip->shutdown_rwsem);
|
||||
snd_usb_autosuspend(cval->mixer->chip);
|
||||
return err;
|
||||
}
|
||||
@@ -337,7 +337,7 @@ static int get_ctl_value_v2(struct usb_mixer_elem_info *cval, int request, int v
|
||||
if (ret)
|
||||
goto error;
|
||||
|
||||
mutex_lock(&chip->shutdown_mutex);
|
||||
down_read(&chip->shutdown_rwsem);
|
||||
if (chip->shutdown)
|
||||
ret = -ENODEV;
|
||||
else {
|
||||
@@ -346,7 +346,7 @@ static int get_ctl_value_v2(struct usb_mixer_elem_info *cval, int request, int v
|
||||
USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
|
||||
validx, idx, buf, size, 1000);
|
||||
}
|
||||
mutex_unlock(&chip->shutdown_mutex);
|
||||
up_read(&chip->shutdown_rwsem);
|
||||
snd_usb_autosuspend(chip);
|
||||
|
||||
if (ret < 0) {
|
||||
@@ -453,7 +453,7 @@ int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval,
|
||||
err = snd_usb_autoresume(chip);
|
||||
if (err < 0)
|
||||
return -EIO;
|
||||
mutex_lock(&chip->shutdown_mutex);
|
||||
down_read(&chip->shutdown_rwsem);
|
||||
while (timeout-- > 0) {
|
||||
if (chip->shutdown)
|
||||
break;
|
||||
@@ -471,7 +471,7 @@ int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval,
|
||||
err = -EINVAL;
|
||||
|
||||
out:
|
||||
mutex_unlock(&chip->shutdown_mutex);
|
||||
up_read(&chip->shutdown_rwsem);
|
||||
snd_usb_autosuspend(chip);
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -350,7 +350,7 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream,
|
||||
subs->period_bytes != params_period_bytes(hw_params) ||
|
||||
subs->cur_rate != rate;
|
||||
|
||||
mutex_lock(&subs->stream->chip->shutdown_mutex);
|
||||
down_read(&subs->stream->chip->shutdown_rwsem);
|
||||
if (subs->stream->chip->shutdown) {
|
||||
ret = -ENODEV;
|
||||
goto unlock;
|
||||
@@ -380,7 +380,7 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream,
|
||||
}
|
||||
|
||||
unlock:
|
||||
mutex_unlock(&subs->stream->chip->shutdown_mutex);
|
||||
up_read(&subs->stream->chip->shutdown_rwsem);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -396,9 +396,9 @@ static int snd_usb_hw_free(struct snd_pcm_substream *substream)
|
||||
subs->cur_audiofmt = NULL;
|
||||
subs->cur_rate = 0;
|
||||
subs->period_bytes = 0;
|
||||
mutex_lock(&subs->stream->chip->shutdown_mutex);
|
||||
down_read(&subs->stream->chip->shutdown_rwsem);
|
||||
snd_usb_release_substream_urbs(subs, 0);
|
||||
mutex_unlock(&subs->stream->chip->shutdown_mutex);
|
||||
up_read(&subs->stream->chip->shutdown_rwsem);
|
||||
return snd_pcm_lib_free_vmalloc_buffer(substream);
|
||||
}
|
||||
|
||||
@@ -418,7 +418,7 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream)
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
mutex_lock(&subs->stream->chip->shutdown_mutex);
|
||||
down_read(&subs->stream->chip->shutdown_rwsem);
|
||||
if (subs->stream->chip->shutdown) {
|
||||
ret = -ENODEV;
|
||||
goto unlock;
|
||||
@@ -435,7 +435,7 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream)
|
||||
|
||||
ret = snd_usb_substream_prepare(subs, runtime);
|
||||
unlock:
|
||||
mutex_unlock(&subs->stream->chip->shutdown_mutex);
|
||||
up_read(&subs->stream->chip->shutdown_rwsem);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ struct snd_usb_audio {
|
||||
struct snd_card *card;
|
||||
struct usb_interface *pm_intf;
|
||||
u32 usb_id;
|
||||
struct mutex shutdown_mutex;
|
||||
struct rw_semaphore shutdown_rwsem;
|
||||
unsigned int shutdown:1;
|
||||
unsigned int probing:1;
|
||||
unsigned int autosuspended:1;
|
||||
|
||||
Reference in New Issue
Block a user