Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 34f3c89f authored by Takashi Iwai's avatar Takashi Iwai
Browse files

ALSA: usb-audio: Use rwsem for disconnect protection



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: default avatarMatthieu CASTET <matthieu.castet@parrot.com>
Cc: <stable@vger.kernel.org>
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent 978520b7
Loading
Loading
Loading
Loading
+8 −4
Original line number Diff line number Diff line
@@ -339,7 +339,7 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx,
	}

	mutex_init(&chip->mutex);
	mutex_init(&chip->shutdown_mutex);
	init_rwsem(&chip->shutdown_rwsem);
	chip->index = idx;
	chip->dev = dev;
	chip->card = card;
@@ -560,7 +560,7 @@ static void snd_usb_audio_disconnect(struct usb_device *dev,

	card = chip->card;
	mutex_lock(&register_mutex);
	mutex_lock(&chip->shutdown_mutex);
	down_write(&chip->shutdown_rwsem);
	chip->shutdown = 1;
	chip->num_interfaces--;
	if (chip->num_interfaces <= 0) {
@@ -582,11 +582,11 @@ static void snd_usb_audio_disconnect(struct usb_device *dev,
			snd_usb_mixer_disconnect(p);
		}
		usb_chip[chip->index] = NULL;
		mutex_unlock(&chip->shutdown_mutex);
		up_write(&chip->shutdown_rwsem);
		mutex_unlock(&register_mutex);
		snd_card_free_when_closed(card);
	} else {
		mutex_unlock(&chip->shutdown_mutex);
		up_write(&chip->shutdown_rwsem);
		mutex_unlock(&register_mutex);
	}
}
@@ -618,16 +618,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)
+6 −6
Original line number Diff line number Diff line
@@ -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);
	}
	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;
}
+6 −6
Original line number Diff line number Diff line
@@ -503,12 +503,12 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream,
		return -EINVAL;
	}

	mutex_lock(&subs->stream->chip->shutdown_mutex);
	down_read(&subs->stream->chip->shutdown_rwsem);
	if (subs->stream->chip->shutdown)
		ret = -ENODEV;
	else
		ret = set_format(subs, fmt);
	mutex_unlock(&subs->stream->chip->shutdown_mutex);
	up_read(&subs->stream->chip->shutdown_rwsem);
	if (ret < 0)
		return ret;

@@ -531,12 +531,12 @@ 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);
	if (!subs->stream->chip->shutdown) {
		stop_endpoints(subs, 0, 1, 1);
		deactivate_endpoints(subs);
	}
	mutex_unlock(&subs->stream->chip->shutdown_mutex);
	up_read(&subs->stream->chip->shutdown_rwsem);
	return snd_pcm_lib_free_vmalloc_buffer(substream);
}

@@ -558,7 +558,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;
@@ -608,7 +608,7 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream)
		ret = start_endpoints(subs, 1);

 unlock:
	mutex_unlock(&subs->stream->chip->shutdown_mutex);
	up_read(&subs->stream->chip->shutdown_rwsem);
	return ret;
}

+1 −1
Original line number Diff line number Diff line
@@ -37,7 +37,7 @@ struct snd_usb_audio {
	struct usb_interface *pm_intf;
	u32 usb_id;
	struct mutex mutex;
	struct mutex shutdown_mutex;
	struct rw_semaphore shutdown_rwsem;
	unsigned int shutdown:1;
	unsigned int probing:1;
	unsigned int autosuspended:1;