From: Sasha Levin Date: Mon, 4 Nov 2019 16:02:15 +0000 (-0500) Subject: fixes for 4.14 X-Git-Tag: v4.4.199~8 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=2448a040976f0e92c4efa32680de33e8c5504be1;p=thirdparty%2Fkernel%2Fstable-queue.git fixes for 4.14 Signed-off-by: Sasha Levin --- diff --git a/queue-4.14/alsa-timer-fix-mutex-deadlock-at-releasing-card.patch b/queue-4.14/alsa-timer-fix-mutex-deadlock-at-releasing-card.patch new file mode 100644 index 00000000000..47bd7b9ea02 --- /dev/null +++ b/queue-4.14/alsa-timer-fix-mutex-deadlock-at-releasing-card.patch @@ -0,0 +1,133 @@ +From e6ee0406e0e1cd8cbd422d7e0af7007713045237 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 30 Oct 2019 22:42:57 +0100 +Subject: ALSA: timer: Fix mutex deadlock at releasing card + +From: Takashi Iwai + +[ Upstream commit a39331867335d4a94b6165e306265c9e24aca073 ] + +When a card is disconnected while in use, the system waits until all +opened files are closed then releases the card. This is done via +put_device() of the card device in each device release code. + +The recently reported mutex deadlock bug happens in this code path; +snd_timer_close() for the timer device deals with the global +register_mutex and it calls put_device() there. When this timer +device is the last one, the card gets freed and it eventually calls +snd_timer_free(), which has again the protection with the global +register_mutex -- boom. + +Basically put_device() call itself is race-free, so a relative simple +workaround is to move this put_device() call out of the mutex. For +achieving that, in this patch, snd_timer_close_locked() got a new +argument to store the card device pointer in return, and each caller +invokes put_device() with the returned object after the mutex unlock. + +Reported-and-tested-by: Kirill A. Shutemov +Cc: +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/core/timer.c | 24 +++++++++++++++++------- + 1 file changed, 17 insertions(+), 7 deletions(-) + +diff --git a/sound/core/timer.c b/sound/core/timer.c +index b50f7601cc2b0..161ab19cb7220 100644 +--- a/sound/core/timer.c ++++ b/sound/core/timer.c +@@ -240,7 +240,8 @@ static int snd_timer_check_master(struct snd_timer_instance *master) + return 0; + } + +-static int snd_timer_close_locked(struct snd_timer_instance *timeri); ++static int snd_timer_close_locked(struct snd_timer_instance *timeri, ++ struct device **card_devp_to_put); + + /* + * open a timer instance +@@ -252,6 +253,7 @@ int snd_timer_open(struct snd_timer_instance **ti, + { + struct snd_timer *timer; + struct snd_timer_instance *timeri = NULL; ++ struct device *card_dev_to_put = NULL; + int err; + + mutex_lock(®ister_mutex); +@@ -275,7 +277,7 @@ int snd_timer_open(struct snd_timer_instance **ti, + list_add_tail(&timeri->open_list, &snd_timer_slave_list); + err = snd_timer_check_slave(timeri); + if (err < 0) { +- snd_timer_close_locked(timeri); ++ snd_timer_close_locked(timeri, &card_dev_to_put); + timeri = NULL; + } + goto unlock; +@@ -327,7 +329,7 @@ int snd_timer_open(struct snd_timer_instance **ti, + timeri = NULL; + + if (timer->card) +- put_device(&timer->card->card_dev); ++ card_dev_to_put = &timer->card->card_dev; + module_put(timer->module); + goto unlock; + } +@@ -337,12 +339,15 @@ int snd_timer_open(struct snd_timer_instance **ti, + timer->num_instances++; + err = snd_timer_check_master(timeri); + if (err < 0) { +- snd_timer_close_locked(timeri); ++ snd_timer_close_locked(timeri, &card_dev_to_put); + timeri = NULL; + } + + unlock: + mutex_unlock(®ister_mutex); ++ /* put_device() is called after unlock for avoiding deadlock */ ++ if (card_dev_to_put) ++ put_device(card_dev_to_put); + *ti = timeri; + return err; + } +@@ -352,7 +357,8 @@ EXPORT_SYMBOL(snd_timer_open); + * close a timer instance + * call this with register_mutex down. + */ +-static int snd_timer_close_locked(struct snd_timer_instance *timeri) ++static int snd_timer_close_locked(struct snd_timer_instance *timeri, ++ struct device **card_devp_to_put) + { + struct snd_timer *timer = NULL; + struct snd_timer_instance *slave, *tmp; +@@ -404,7 +410,7 @@ static int snd_timer_close_locked(struct snd_timer_instance *timeri) + timer->hw.close(timer); + /* release a card refcount for safe disconnection */ + if (timer->card) +- put_device(&timer->card->card_dev); ++ *card_devp_to_put = &timer->card->card_dev; + module_put(timer->module); + } + +@@ -416,14 +422,18 @@ static int snd_timer_close_locked(struct snd_timer_instance *timeri) + */ + int snd_timer_close(struct snd_timer_instance *timeri) + { ++ struct device *card_dev_to_put = NULL; + int err; + + if (snd_BUG_ON(!timeri)) + return -ENXIO; + + mutex_lock(®ister_mutex); +- err = snd_timer_close_locked(timeri); ++ err = snd_timer_close_locked(timeri, &card_dev_to_put); + mutex_unlock(®ister_mutex); ++ /* put_device() is called after unlock for avoiding deadlock */ ++ if (card_dev_to_put) ++ put_device(card_dev_to_put); + return err; + } + EXPORT_SYMBOL(snd_timer_close); +-- +2.20.1 + diff --git a/queue-4.14/alsa-timer-simplify-error-path-in-snd_timer_open.patch b/queue-4.14/alsa-timer-simplify-error-path-in-snd_timer_open.patch new file mode 100644 index 00000000000..a3d96b21b0b --- /dev/null +++ b/queue-4.14/alsa-timer-simplify-error-path-in-snd_timer_open.patch @@ -0,0 +1,130 @@ +From cba646fe5094093e4940ba2a0058728a7e13c7fc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 28 Mar 2019 17:11:10 +0100 +Subject: ALSA: timer: Simplify error path in snd_timer_open() + +From: Takashi Iwai + +[ Upstream commit 41672c0c24a62699d20aab53b98d843b16483053 ] + +Just a minor refactoring to use the standard goto for error paths in +snd_timer_open() instead of open code. The first mutex_lock() is +moved to the beginning of the function to make the code clearer. + +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/core/timer.c | 39 ++++++++++++++++++++------------------- + 1 file changed, 20 insertions(+), 19 deletions(-) + +diff --git a/sound/core/timer.c b/sound/core/timer.c +index 2c0f292226d79..b50f7601cc2b0 100644 +--- a/sound/core/timer.c ++++ b/sound/core/timer.c +@@ -254,19 +254,20 @@ int snd_timer_open(struct snd_timer_instance **ti, + struct snd_timer_instance *timeri = NULL; + int err; + ++ mutex_lock(®ister_mutex); + if (tid->dev_class == SNDRV_TIMER_CLASS_SLAVE) { + /* open a slave instance */ + if (tid->dev_sclass <= SNDRV_TIMER_SCLASS_NONE || + tid->dev_sclass > SNDRV_TIMER_SCLASS_OSS_SEQUENCER) { + pr_debug("ALSA: timer: invalid slave class %i\n", + tid->dev_sclass); +- return -EINVAL; ++ err = -EINVAL; ++ goto unlock; + } +- mutex_lock(®ister_mutex); + timeri = snd_timer_instance_new(owner, NULL); + if (!timeri) { +- mutex_unlock(®ister_mutex); +- return -ENOMEM; ++ err = -ENOMEM; ++ goto unlock; + } + timeri->slave_class = tid->dev_sclass; + timeri->slave_id = tid->device; +@@ -277,13 +278,10 @@ int snd_timer_open(struct snd_timer_instance **ti, + snd_timer_close_locked(timeri); + timeri = NULL; + } +- mutex_unlock(®ister_mutex); +- *ti = timeri; +- return err; ++ goto unlock; + } + + /* open a master instance */ +- mutex_lock(®ister_mutex); + timer = snd_timer_find(tid); + #ifdef CONFIG_MODULES + if (!timer) { +@@ -294,25 +292,26 @@ int snd_timer_open(struct snd_timer_instance **ti, + } + #endif + if (!timer) { +- mutex_unlock(®ister_mutex); +- return -ENODEV; ++ err = -ENODEV; ++ goto unlock; + } + if (!list_empty(&timer->open_list_head)) { + timeri = list_entry(timer->open_list_head.next, + struct snd_timer_instance, open_list); + if (timeri->flags & SNDRV_TIMER_IFLG_EXCLUSIVE) { +- mutex_unlock(®ister_mutex); +- return -EBUSY; ++ err = -EBUSY; ++ timeri = NULL; ++ goto unlock; + } + } + if (timer->num_instances >= timer->max_instances) { +- mutex_unlock(®ister_mutex); +- return -EBUSY; ++ err = -EBUSY; ++ goto unlock; + } + timeri = snd_timer_instance_new(owner, timer); + if (!timeri) { +- mutex_unlock(®ister_mutex); +- return -ENOMEM; ++ err = -ENOMEM; ++ goto unlock; + } + /* take a card refcount for safe disconnection */ + if (timer->card) +@@ -321,16 +320,16 @@ int snd_timer_open(struct snd_timer_instance **ti, + timeri->slave_id = slave_id; + + if (list_empty(&timer->open_list_head) && timer->hw.open) { +- int err = timer->hw.open(timer); ++ err = timer->hw.open(timer); + if (err) { + kfree(timeri->owner); + kfree(timeri); ++ timeri = NULL; + + if (timer->card) + put_device(&timer->card->card_dev); + module_put(timer->module); +- mutex_unlock(®ister_mutex); +- return err; ++ goto unlock; + } + } + +@@ -341,6 +340,8 @@ int snd_timer_open(struct snd_timer_instance **ti, + snd_timer_close_locked(timeri); + timeri = NULL; + } ++ ++ unlock: + mutex_unlock(®ister_mutex); + *ti = timeri; + return err; +-- +2.20.1 + diff --git a/queue-4.14/series b/queue-4.14/series index 9233b4d161a..d8deaa550ad 100644 --- a/queue-4.14/series +++ b/queue-4.14/series @@ -91,3 +91,5 @@ sch_netem-fix-rcu-splat-in-netem_enqueue.patch sctp-fix-the-issue-that-flags-are-ignored-when-using-kernel_connect.patch sctp-not-bind-the-socket-in-sctp_connect.patch xfs-correctly-invert-xfs_buftarg-lru-isolation-logic.patch +alsa-timer-simplify-error-path-in-snd_timer_open.patch +alsa-timer-fix-mutex-deadlock-at-releasing-card.patch