From 7af2a1d9939a1a91fed21ee364a3c3acc8c9b954 Mon Sep 17 00:00:00 2001 From: Sasha Levin Date: Mon, 4 Nov 2019 11:02:15 -0500 Subject: [PATCH] fixes for 4.9 Signed-off-by: Sasha Levin --- ...fix-mutex-deadlock-at-releasing-card.patch | 133 +++++++++ ...w-standard-export_symbol-declaration.patch | 147 ++++++++++ ...-timer-limit-max-instances-per-timer.patch | 253 ++++++++++++++++++ ...implify-error-path-in-snd_timer_open.patch | 130 +++++++++ queue-4.9/series | 4 + 5 files changed, 667 insertions(+) create mode 100644 queue-4.9/alsa-timer-fix-mutex-deadlock-at-releasing-card.patch create mode 100644 queue-4.9/alsa-timer-follow-standard-export_symbol-declaration.patch create mode 100644 queue-4.9/alsa-timer-limit-max-instances-per-timer.patch create mode 100644 queue-4.9/alsa-timer-simplify-error-path-in-snd_timer_open.patch diff --git a/queue-4.9/alsa-timer-fix-mutex-deadlock-at-releasing-card.patch b/queue-4.9/alsa-timer-fix-mutex-deadlock-at-releasing-card.patch new file mode 100644 index 00000000000..b000460c798 --- /dev/null +++ b/queue-4.9/alsa-timer-fix-mutex-deadlock-at-releasing-card.patch @@ -0,0 +1,133 @@ +From 635f7ef2cc4ea7adc147380526ce75f4bfe9a8b9 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 6eb4e97662d9c..19d90aa082184 100644 +--- a/sound/core/timer.c ++++ b/sound/core/timer.c +@@ -239,7 +239,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 +@@ -251,6 +252,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); +@@ -274,7 +276,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; +@@ -326,7 +328,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; + } +@@ -336,12 +338,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; + } +@@ -351,7 +356,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; +@@ -403,7 +409,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); + } + +@@ -415,14 +421,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.9/alsa-timer-follow-standard-export_symbol-declaration.patch b/queue-4.9/alsa-timer-follow-standard-export_symbol-declaration.patch new file mode 100644 index 00000000000..ef483834c6d --- /dev/null +++ b/queue-4.9/alsa-timer-follow-standard-export_symbol-declaration.patch @@ -0,0 +1,147 @@ +From 67272ec0784f5ee30b9c64022cf207b93995c46e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 16 Jun 2017 16:16:05 +0200 +Subject: ALSA: timer: Follow standard EXPORT_SYMBOL() declarations + +From: Takashi Iwai + +[ Upstream commit 988563929d5b65c021439880ac6bd1b207722f26 ] + +Just a tidy up to follow the standard EXPORT_SYMBOL*() declarations +in order to improve grep-ability. + +- Move EXPORT_SYMBOL*() to the position right after its definition + +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + sound/core/timer.c | 27 +++++++++++++-------------- + 1 file changed, 13 insertions(+), 14 deletions(-) + +diff --git a/sound/core/timer.c b/sound/core/timer.c +index 152254193c697..cfcc6718aafce 100644 +--- a/sound/core/timer.c ++++ b/sound/core/timer.c +@@ -318,6 +318,7 @@ int snd_timer_open(struct snd_timer_instance **ti, + *ti = timeri; + return 0; + } ++EXPORT_SYMBOL(snd_timer_open); + + /* + * close a timer instance +@@ -383,6 +384,7 @@ int snd_timer_close(struct snd_timer_instance *timeri) + mutex_unlock(®ister_mutex); + return 0; + } ++EXPORT_SYMBOL(snd_timer_close); + + unsigned long snd_timer_resolution(struct snd_timer_instance *timeri) + { +@@ -397,6 +399,7 @@ unsigned long snd_timer_resolution(struct snd_timer_instance *timeri) + } + return 0; + } ++EXPORT_SYMBOL(snd_timer_resolution); + + static void snd_timer_notify1(struct snd_timer_instance *ti, int event) + { +@@ -588,6 +591,7 @@ int snd_timer_start(struct snd_timer_instance *timeri, unsigned int ticks) + else + return snd_timer_start1(timeri, true, ticks); + } ++EXPORT_SYMBOL(snd_timer_start); + + /* + * stop the timer instance. +@@ -601,6 +605,7 @@ int snd_timer_stop(struct snd_timer_instance *timeri) + else + return snd_timer_stop1(timeri, true); + } ++EXPORT_SYMBOL(snd_timer_stop); + + /* + * start again.. the tick is kept. +@@ -616,6 +621,7 @@ int snd_timer_continue(struct snd_timer_instance *timeri) + else + return snd_timer_start1(timeri, false, 0); + } ++EXPORT_SYMBOL(snd_timer_continue); + + /* + * pause.. remember the ticks left +@@ -627,6 +633,7 @@ int snd_timer_pause(struct snd_timer_instance * timeri) + else + return snd_timer_stop1(timeri, false); + } ++EXPORT_SYMBOL(snd_timer_pause); + + /* + * reschedule the timer +@@ -808,6 +815,7 @@ void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left) + if (use_tasklet) + tasklet_schedule(&timer->task_queue); + } ++EXPORT_SYMBOL(snd_timer_interrupt); + + /* + +@@ -858,6 +866,7 @@ int snd_timer_new(struct snd_card *card, char *id, struct snd_timer_id *tid, + *rtimer = timer; + return 0; + } ++EXPORT_SYMBOL(snd_timer_new); + + static int snd_timer_free(struct snd_timer *timer) + { +@@ -977,6 +986,7 @@ void snd_timer_notify(struct snd_timer *timer, int event, struct timespec *tstam + } + spin_unlock_irqrestore(&timer->lock, flags); + } ++EXPORT_SYMBOL(snd_timer_notify); + + /* + * exported functions for global timers +@@ -992,11 +1002,13 @@ int snd_timer_global_new(char *id, int device, struct snd_timer **rtimer) + tid.subdevice = 0; + return snd_timer_new(NULL, id, &tid, rtimer); + } ++EXPORT_SYMBOL(snd_timer_global_new); + + int snd_timer_global_free(struct snd_timer *timer) + { + return snd_timer_free(timer); + } ++EXPORT_SYMBOL(snd_timer_global_free); + + int snd_timer_global_register(struct snd_timer *timer) + { +@@ -1006,6 +1018,7 @@ int snd_timer_global_register(struct snd_timer *timer) + dev.device_data = timer; + return snd_timer_dev_register(&dev); + } ++EXPORT_SYMBOL(snd_timer_global_register); + + /* + * System timer +@@ -2121,17 +2134,3 @@ static void __exit alsa_timer_exit(void) + + module_init(alsa_timer_init) + module_exit(alsa_timer_exit) +- +-EXPORT_SYMBOL(snd_timer_open); +-EXPORT_SYMBOL(snd_timer_close); +-EXPORT_SYMBOL(snd_timer_resolution); +-EXPORT_SYMBOL(snd_timer_start); +-EXPORT_SYMBOL(snd_timer_stop); +-EXPORT_SYMBOL(snd_timer_continue); +-EXPORT_SYMBOL(snd_timer_pause); +-EXPORT_SYMBOL(snd_timer_new); +-EXPORT_SYMBOL(snd_timer_notify); +-EXPORT_SYMBOL(snd_timer_global_new); +-EXPORT_SYMBOL(snd_timer_global_free); +-EXPORT_SYMBOL(snd_timer_global_register); +-EXPORT_SYMBOL(snd_timer_interrupt); +-- +2.20.1 + diff --git a/queue-4.9/alsa-timer-limit-max-instances-per-timer.patch b/queue-4.9/alsa-timer-limit-max-instances-per-timer.patch new file mode 100644 index 00000000000..1b0c32d2388 --- /dev/null +++ b/queue-4.9/alsa-timer-limit-max-instances-per-timer.patch @@ -0,0 +1,253 @@ +From 5da6a4bd1d2a53d4ffd0ef9edc675a26382955c0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 5 Nov 2017 10:07:43 +0100 +Subject: ALSA: timer: Limit max instances per timer +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Takashi Iwai + +[ Upstream commit 9b7d869ee5a77ed4a462372bb89af622e705bfb8 ] + +Currently we allow unlimited number of timer instances, and it may +bring the system hogging way too much CPU when too many timer +instances are opened and processed concurrently. This may end up with +a soft-lockup report as triggered by syzkaller, especially when +hrtimer backend is deployed. + +Since such insane number of instances aren't demanded by the normal +use case of ALSA sequencer and it merely opens a risk only for abuse, +this patch introduces the upper limit for the number of instances per +timer backend. As default, it's set to 1000, but for the fine-grained +timer like hrtimer, it's set to 100. + +Reported-by: syzbot +Tested-by: Jérôme Glisse +Cc: +Signed-off-by: Takashi Iwai +Signed-off-by: Sasha Levin +--- + include/sound/timer.h | 2 ++ + sound/core/hrtimer.c | 1 + + sound/core/timer.c | 67 ++++++++++++++++++++++++++++++++++--------- + 3 files changed, 57 insertions(+), 13 deletions(-) + +diff --git a/include/sound/timer.h b/include/sound/timer.h +index c4d76ff056c6e..7ae226ab69908 100644 +--- a/include/sound/timer.h ++++ b/include/sound/timer.h +@@ -90,6 +90,8 @@ struct snd_timer { + struct list_head ack_list_head; + struct list_head sack_list_head; /* slow ack list head */ + struct tasklet_struct task_queue; ++ int max_instances; /* upper limit of timer instances */ ++ int num_instances; /* current number of timer instances */ + }; + + struct snd_timer_instance { +diff --git a/sound/core/hrtimer.c b/sound/core/hrtimer.c +index e2f27022b363c..d7dddb75e7bb8 100644 +--- a/sound/core/hrtimer.c ++++ b/sound/core/hrtimer.c +@@ -159,6 +159,7 @@ static int __init snd_hrtimer_init(void) + timer->hw = hrtimer_hw; + timer->hw.resolution = resolution; + timer->hw.ticks = NANO_SEC / resolution; ++ timer->max_instances = 100; /* lower the limit */ + + err = snd_timer_global_register(timer); + if (err < 0) { +diff --git a/sound/core/timer.c b/sound/core/timer.c +index cfcc6718aafce..95c5838747754 100644 +--- a/sound/core/timer.c ++++ b/sound/core/timer.c +@@ -179,7 +179,7 @@ static void snd_timer_request(struct snd_timer_id *tid) + * + * call this with register_mutex down. + */ +-static void snd_timer_check_slave(struct snd_timer_instance *slave) ++static int snd_timer_check_slave(struct snd_timer_instance *slave) + { + struct snd_timer *timer; + struct snd_timer_instance *master; +@@ -189,16 +189,21 @@ static void snd_timer_check_slave(struct snd_timer_instance *slave) + list_for_each_entry(master, &timer->open_list_head, open_list) { + if (slave->slave_class == master->slave_class && + slave->slave_id == master->slave_id) { ++ if (master->timer->num_instances >= ++ master->timer->max_instances) ++ return -EBUSY; + list_move_tail(&slave->open_list, + &master->slave_list_head); ++ master->timer->num_instances++; + spin_lock_irq(&slave_active_lock); + slave->master = master; + slave->timer = master->timer; + spin_unlock_irq(&slave_active_lock); +- return; ++ return 0; + } + } + } ++ return 0; + } + + /* +@@ -207,7 +212,7 @@ static void snd_timer_check_slave(struct snd_timer_instance *slave) + * + * call this with register_mutex down. + */ +-static void snd_timer_check_master(struct snd_timer_instance *master) ++static int snd_timer_check_master(struct snd_timer_instance *master) + { + struct snd_timer_instance *slave, *tmp; + +@@ -215,7 +220,11 @@ static void snd_timer_check_master(struct snd_timer_instance *master) + list_for_each_entry_safe(slave, tmp, &snd_timer_slave_list, open_list) { + if (slave->slave_class == master->slave_class && + slave->slave_id == master->slave_id) { ++ if (master->timer->num_instances >= ++ master->timer->max_instances) ++ return -EBUSY; + list_move_tail(&slave->open_list, &master->slave_list_head); ++ master->timer->num_instances++; + spin_lock_irq(&slave_active_lock); + spin_lock(&master->timer->lock); + slave->master = master; +@@ -227,8 +236,11 @@ static void snd_timer_check_master(struct snd_timer_instance *master) + spin_unlock_irq(&slave_active_lock); + } + } ++ return 0; + } + ++static int snd_timer_close_locked(struct snd_timer_instance *timeri); ++ + /* + * open a timer instance + * when opening a master, the slave id must be here given. +@@ -239,6 +251,7 @@ int snd_timer_open(struct snd_timer_instance **ti, + { + struct snd_timer *timer; + struct snd_timer_instance *timeri = NULL; ++ int err; + + if (tid->dev_class == SNDRV_TIMER_CLASS_SLAVE) { + /* open a slave instance */ +@@ -258,10 +271,14 @@ int snd_timer_open(struct snd_timer_instance **ti, + timeri->slave_id = tid->device; + timeri->flags |= SNDRV_TIMER_IFLG_SLAVE; + list_add_tail(&timeri->open_list, &snd_timer_slave_list); +- snd_timer_check_slave(timeri); ++ err = snd_timer_check_slave(timeri); ++ if (err < 0) { ++ snd_timer_close_locked(timeri); ++ timeri = NULL; ++ } + mutex_unlock(®ister_mutex); + *ti = timeri; +- return 0; ++ return err; + } + + /* open a master instance */ +@@ -287,6 +304,10 @@ int snd_timer_open(struct snd_timer_instance **ti, + return -EBUSY; + } + } ++ if (timer->num_instances >= timer->max_instances) { ++ mutex_unlock(®ister_mutex); ++ return -EBUSY; ++ } + timeri = snd_timer_instance_new(owner, timer); + if (!timeri) { + mutex_unlock(®ister_mutex); +@@ -313,25 +334,27 @@ int snd_timer_open(struct snd_timer_instance **ti, + } + + list_add_tail(&timeri->open_list, &timer->open_list_head); +- snd_timer_check_master(timeri); ++ timer->num_instances++; ++ err = snd_timer_check_master(timeri); ++ if (err < 0) { ++ snd_timer_close_locked(timeri); ++ timeri = NULL; ++ } + mutex_unlock(®ister_mutex); + *ti = timeri; +- return 0; ++ return err; + } + EXPORT_SYMBOL(snd_timer_open); + + /* + * close a timer instance ++ * call this with register_mutex down. + */ +-int snd_timer_close(struct snd_timer_instance *timeri) ++static int snd_timer_close_locked(struct snd_timer_instance *timeri) + { + struct snd_timer *timer = NULL; + struct snd_timer_instance *slave, *tmp; + +- if (snd_BUG_ON(!timeri)) +- return -ENXIO; +- +- mutex_lock(®ister_mutex); + list_del(&timeri->open_list); + + /* force to stop the timer */ +@@ -339,6 +362,7 @@ int snd_timer_close(struct snd_timer_instance *timeri) + + timer = timeri->timer; + if (timer) { ++ timer->num_instances--; + /* wait, until the active callback is finished */ + spin_lock_irq(&timer->lock); + while (timeri->flags & SNDRV_TIMER_IFLG_CALLBACK) { +@@ -354,6 +378,7 @@ int snd_timer_close(struct snd_timer_instance *timeri) + list_for_each_entry_safe(slave, tmp, &timeri->slave_list_head, + open_list) { + list_move_tail(&slave->open_list, &snd_timer_slave_list); ++ timer->num_instances--; + slave->master = NULL; + slave->timer = NULL; + list_del_init(&slave->ack_list); +@@ -381,9 +406,24 @@ int snd_timer_close(struct snd_timer_instance *timeri) + module_put(timer->module); + } + +- mutex_unlock(®ister_mutex); + return 0; + } ++ ++/* ++ * close a timer instance ++ */ ++int snd_timer_close(struct snd_timer_instance *timeri) ++{ ++ int err; ++ ++ if (snd_BUG_ON(!timeri)) ++ return -ENXIO; ++ ++ mutex_lock(®ister_mutex); ++ err = snd_timer_close_locked(timeri); ++ mutex_unlock(®ister_mutex); ++ return err; ++} + EXPORT_SYMBOL(snd_timer_close); + + unsigned long snd_timer_resolution(struct snd_timer_instance *timeri) +@@ -854,6 +894,7 @@ int snd_timer_new(struct snd_card *card, char *id, struct snd_timer_id *tid, + spin_lock_init(&timer->lock); + tasklet_init(&timer->task_queue, snd_timer_tasklet, + (unsigned long)timer); ++ timer->max_instances = 1000; /* default limit per timer */ + if (card != NULL) { + timer->module = card->module; + err = snd_device_new(card, SNDRV_DEV_TIMER, timer, &ops); +-- +2.20.1 + diff --git a/queue-4.9/alsa-timer-simplify-error-path-in-snd_timer_open.patch b/queue-4.9/alsa-timer-simplify-error-path-in-snd_timer_open.patch new file mode 100644 index 00000000000..528b23aeb9d --- /dev/null +++ b/queue-4.9/alsa-timer-simplify-error-path-in-snd_timer_open.patch @@ -0,0 +1,130 @@ +From 782f1b929d8feb20e52fd731fd2335c78d97fa20 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 95c5838747754..6eb4e97662d9c 100644 +--- a/sound/core/timer.c ++++ b/sound/core/timer.c +@@ -253,19 +253,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; +@@ -276,13 +277,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) { +@@ -293,25 +291,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) +@@ -320,16 +319,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; + } + } + +@@ -340,6 +339,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.9/series b/queue-4.9/series index 96c3e53c0af..af755090e3f 100644 --- a/queue-4.9/series +++ b/queue-4.9/series @@ -56,3 +56,7 @@ 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-follow-standard-export_symbol-declaration.patch +alsa-timer-limit-max-instances-per-timer.patch +alsa-timer-simplify-error-path-in-snd_timer_open.patch +alsa-timer-fix-mutex-deadlock-at-releasing-card.patch -- 2.47.2