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

Commit 839f4e86 authored by Takashi Iwai's avatar Takashi Iwai Committed by Greg Kroah-Hartman
Browse files

ALSA: jack: Fix mutex call in snd_jack_report()



[ Upstream commit 89dbb335cb6a627a4067bc42caa09c8bc3326d40 ]

snd_jack_report() is supposed to be callable from an IRQ context, too,
and it's indeed used in that way from virtsnd driver.  The fix for
input_dev race in commit 1b6a6fc5280e ("ALSA: jack: Access input_dev
under mutex"), however, introduced a mutex lock in snd_jack_report(),
and this resulted in a potential sleep-in-atomic.

For addressing that problem, this patch changes the relevant code to
use the object get/put and removes the mutex usage.  That is,
snd_jack_report(), it takes input_get_device() and leaves with
input_put_device() for assuring the input_dev being assigned.

Although the whole mutex could be reduced, we keep it because it can
be still a protection for potential races between creation and
deletion.

Fixes: 1b6a6fc5280e ("ALSA: jack: Access input_dev under mutex")
Reported-by: default avatarDan Carpenter <dan.carpenter@linaro.org>
Closes: https://lore.kernel.org/r/cf95f7fe-a748-4990-8378-000491b40329@moroto.mountain


Tested-by: default avatarAmadeusz Sławiński <amadeuszx.slawinski@linux.intel.com>
Cc: <stable@vger.kernel.org>
Link: https://lore.kernel.org/r/20230706155357.3470-1-tiwai@suse.de


Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
parent ce5311e7
Loading
Loading
Loading
Loading
+7 −8
Original line number Diff line number Diff line
@@ -378,6 +378,7 @@ void snd_jack_report(struct snd_jack *jack, int status)
{
	struct snd_jack_kctl *jack_kctl;
#ifdef CONFIG_SND_JACK_INPUT_DEV
	struct input_dev *idev;
	int i;
#endif

@@ -389,30 +390,28 @@ void snd_jack_report(struct snd_jack *jack, int status)
					    status & jack_kctl->mask_bits);

#ifdef CONFIG_SND_JACK_INPUT_DEV
	mutex_lock(&jack->input_dev_lock);
	if (!jack->input_dev) {
		mutex_unlock(&jack->input_dev_lock);
	idev = input_get_device(jack->input_dev);
	if (!idev)
		return;
	}

	for (i = 0; i < ARRAY_SIZE(jack->key); i++) {
		int testbit = SND_JACK_BTN_0 >> i;

		if (jack->type & testbit)
			input_report_key(jack->input_dev, jack->key[i],
			input_report_key(idev, jack->key[i],
					 status & testbit);
	}

	for (i = 0; i < ARRAY_SIZE(jack_switch_types); i++) {
		int testbit = 1 << i;
		if (jack->type & testbit)
			input_report_switch(jack->input_dev,
			input_report_switch(idev,
					    jack_switch_types[i],
					    status & testbit);
	}

	input_sync(jack->input_dev);
	mutex_unlock(&jack->input_dev_lock);
	input_sync(idev);
	input_put_device(idev);
#endif /* CONFIG_SND_JACK_INPUT_DEV */
}
EXPORT_SYMBOL(snd_jack_report);