]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
fixes for 4.14
authorSasha Levin <sashal@kernel.org>
Mon, 4 Nov 2019 16:02:15 +0000 (11:02 -0500)
committerSasha Levin <sashal@kernel.org>
Mon, 4 Nov 2019 16:02:15 +0000 (11:02 -0500)
Signed-off-by: Sasha Levin <sashal@kernel.org>
queue-4.14/alsa-timer-fix-mutex-deadlock-at-releasing-card.patch [new file with mode: 0644]
queue-4.14/alsa-timer-simplify-error-path-in-snd_timer_open.patch [new file with mode: 0644]
queue-4.14/series

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 (file)
index 0000000..47bd7b9
--- /dev/null
@@ -0,0 +1,133 @@
+From e6ee0406e0e1cd8cbd422d7e0af7007713045237 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 30 Oct 2019 22:42:57 +0100
+Subject: ALSA: timer: Fix mutex deadlock at releasing card
+
+From: Takashi Iwai <tiwai@suse.de>
+
+[ 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 <kirill.shutemov@linux.intel.com>
+Cc: <stable@vger.kernel.org>
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ 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(&register_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(&register_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(&register_mutex);
+-      err = snd_timer_close_locked(timeri);
++      err = snd_timer_close_locked(timeri, &card_dev_to_put);
+       mutex_unlock(&register_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 (file)
index 0000000..a3d96b2
--- /dev/null
@@ -0,0 +1,130 @@
+From cba646fe5094093e4940ba2a0058728a7e13c7fc Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 28 Mar 2019 17:11:10 +0100
+Subject: ALSA: timer: Simplify error path in snd_timer_open()
+
+From: Takashi Iwai <tiwai@suse.de>
+
+[ 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 <tiwai@suse.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ 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(&register_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(&register_mutex);
+               timeri = snd_timer_instance_new(owner, NULL);
+               if (!timeri) {
+-                      mutex_unlock(&register_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(&register_mutex);
+-              *ti = timeri;
+-              return err;
++              goto unlock;
+       }
+       /* open a master instance */
+-      mutex_lock(&register_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(&register_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(&register_mutex);
+-                      return -EBUSY;
++                      err = -EBUSY;
++                      timeri = NULL;
++                      goto unlock;
+               }
+       }
+       if (timer->num_instances >= timer->max_instances) {
+-              mutex_unlock(&register_mutex);
+-              return -EBUSY;
++              err = -EBUSY;
++              goto unlock;
+       }
+       timeri = snd_timer_instance_new(owner, timer);
+       if (!timeri) {
+-              mutex_unlock(&register_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(&register_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(&register_mutex);
+       *ti = timeri;
+       return err;
+-- 
+2.20.1
+
index 9233b4d161a76521aba3ef6c142be5ca45cf2b54..d8deaa550ad61eff180be88591f407419cd8dfec 100644 (file)
@@ -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