From: Greg Kroah-Hartman Date: Mon, 30 Oct 2017 08:57:32 +0000 (+0100) Subject: 4.9-stable patches X-Git-Tag: v3.18.79~15 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=a31469959924c9098db1cc2fedf6cca804a1e386;p=thirdparty%2Fkernel%2Fstable-queue.git 4.9-stable patches added patches: alsa-hda-fix-headset-mic-problem-for-dell-machines-with-alc236.patch alsa-hda-realtek-add-support-for-alc236-alc3204.patch ceph-unlock-dangling-spinlock-in-try_flush_caps.patch workqueue-replace-pool-manager_arb-mutex-with-a-flag.patch --- diff --git a/queue-4.9/alsa-hda-fix-headset-mic-problem-for-dell-machines-with-alc236.patch b/queue-4.9/alsa-hda-fix-headset-mic-problem-for-dell-machines-with-alc236.patch new file mode 100644 index 00000000000..61c628f6fa2 --- /dev/null +++ b/queue-4.9/alsa-hda-fix-headset-mic-problem-for-dell-machines-with-alc236.patch @@ -0,0 +1,38 @@ +From f265788c336979090ac80b9ae173aa817c4fe40d Mon Sep 17 00:00:00 2001 +From: Hui Wang +Date: Tue, 24 Oct 2017 16:53:34 +0800 +Subject: ALSA: hda - fix headset mic problem for Dell machines with alc236 + +From: Hui Wang + +commit f265788c336979090ac80b9ae173aa817c4fe40d upstream. + +We have several Dell laptops which use the codec alc236, the headset +mic can't work on these machines. Following the commit 736f20a70, we +add the pin cfg table to make the headset mic work. + +Signed-off-by: Hui Wang +Signed-off-by: Takashi Iwai +Signed-off-by: Greg Kroah-Hartman + +--- + sound/pci/hda/patch_realtek.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +--- a/sound/pci/hda/patch_realtek.c ++++ b/sound/pci/hda/patch_realtek.c +@@ -5861,6 +5861,14 @@ static const struct snd_hda_pin_quirk al + ALC225_STANDARD_PINS, + {0x12, 0xb7a60130}, + {0x1b, 0x90170110}), ++ SND_HDA_PIN_QUIRK(0x10ec0236, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, ++ {0x12, 0x90a60140}, ++ {0x14, 0x90170110}, ++ {0x21, 0x02211020}), ++ SND_HDA_PIN_QUIRK(0x10ec0236, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, ++ {0x12, 0x90a60140}, ++ {0x14, 0x90170150}, ++ {0x21, 0x02211020}), + SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL2_MIC_NO_PRESENCE, + {0x14, 0x90170110}, + {0x21, 0x02211020}), diff --git a/queue-4.9/alsa-hda-realtek-add-support-for-alc236-alc3204.patch b/queue-4.9/alsa-hda-realtek-add-support-for-alc236-alc3204.patch new file mode 100644 index 00000000000..a64145f7280 --- /dev/null +++ b/queue-4.9/alsa-hda-realtek-add-support-for-alc236-alc3204.patch @@ -0,0 +1,110 @@ +From 736f20a7060857ff569e9e9586ae6c1204a73e07 Mon Sep 17 00:00:00 2001 +From: Kailang Yang +Date: Fri, 20 Oct 2017 15:06:34 +0800 +Subject: ALSA: hda/realtek - Add support for ALC236/ALC3204 + +From: Kailang Yang + +commit 736f20a7060857ff569e9e9586ae6c1204a73e07 upstream. + +Add support for ALC236/ALC3204. +Add headset mode support for ALC236/ALC3204. + +Signed-off-by: Kailang Yang +Signed-off-by: Takashi Iwai +Signed-off-by: Greg Kroah-Hartman + +--- + sound/pci/hda/patch_realtek.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +--- a/sound/pci/hda/patch_realtek.c ++++ b/sound/pci/hda/patch_realtek.c +@@ -329,6 +329,7 @@ static void alc_fill_eapd_coef(struct hd + break; + case 0x10ec0225: + case 0x10ec0233: ++ case 0x10ec0236: + case 0x10ec0255: + case 0x10ec0256: + case 0x10ec0282: +@@ -909,6 +910,7 @@ static struct alc_codec_rename_pci_table + { 0x10ec0275, 0x1028, 0, "ALC3260" }, + { 0x10ec0899, 0x1028, 0, "ALC3861" }, + { 0x10ec0298, 0x1028, 0, "ALC3266" }, ++ { 0x10ec0236, 0x1028, 0, "ALC3204" }, + { 0x10ec0256, 0x1028, 0, "ALC3246" }, + { 0x10ec0225, 0x1028, 0, "ALC3253" }, + { 0x10ec0295, 0x1028, 0, "ALC3254" }, +@@ -3694,6 +3696,7 @@ static void alc_headset_mode_unplugged(s + alc_process_coef_fw(codec, coef0255_1); + alc_process_coef_fw(codec, coef0255); + break; ++ case 0x10ec0236: + case 0x10ec0256: + alc_process_coef_fw(codec, coef0256); + alc_process_coef_fw(codec, coef0255); +@@ -3777,6 +3780,7 @@ static void alc_headset_mode_mic_in(stru + + + switch (codec->core.vendor_id) { ++ case 0x10ec0236: + case 0x10ec0255: + case 0x10ec0256: + alc_write_coef_idx(codec, 0x45, 0xc489); +@@ -3885,6 +3889,7 @@ static void alc_headset_mode_default(str + case 0x10ec0295: + alc_process_coef_fw(codec, coef0225); + break; ++ case 0x10ec0236: + case 0x10ec0255: + case 0x10ec0256: + alc_process_coef_fw(codec, coef0255); +@@ -3971,6 +3976,7 @@ static void alc_headset_mode_ctia(struct + case 0x10ec0255: + alc_process_coef_fw(codec, coef0255); + break; ++ case 0x10ec0236: + case 0x10ec0256: + alc_process_coef_fw(codec, coef0256); + break; +@@ -4064,6 +4070,7 @@ static void alc_headset_mode_omtp(struct + case 0x10ec0255: + alc_process_coef_fw(codec, coef0255); + break; ++ case 0x10ec0236: + case 0x10ec0256: + alc_process_coef_fw(codec, coef0256); + break; +@@ -4131,6 +4138,7 @@ static void alc_determine_headset_type(s + }; + + switch (codec->core.vendor_id) { ++ case 0x10ec0236: + case 0x10ec0255: + case 0x10ec0256: + alc_process_coef_fw(codec, coef0255); +@@ -4335,6 +4343,7 @@ static void alc255_set_default_jack_type + case 0x10ec0255: + alc_process_coef_fw(codec, alc255fw); + break; ++ case 0x10ec0236: + case 0x10ec0256: + alc_process_coef_fw(codec, alc256fw); + break; +@@ -6226,6 +6235,7 @@ static int patch_alc269(struct hda_codec + case 0x10ec0255: + spec->codec_variant = ALC269_TYPE_ALC255; + break; ++ case 0x10ec0236: + case 0x10ec0256: + spec->codec_variant = ALC269_TYPE_ALC256; + spec->gen.mixer_nid = 0; /* ALC256 does not have any loopback mixer path */ +@@ -7205,6 +7215,7 @@ static const struct hda_device_id snd_hd + HDA_CODEC_ENTRY(0x10ec0233, "ALC233", patch_alc269), + HDA_CODEC_ENTRY(0x10ec0234, "ALC234", patch_alc269), + HDA_CODEC_ENTRY(0x10ec0235, "ALC233", patch_alc269), ++ HDA_CODEC_ENTRY(0x10ec0236, "ALC236", patch_alc269), + HDA_CODEC_ENTRY(0x10ec0255, "ALC255", patch_alc269), + HDA_CODEC_ENTRY(0x10ec0256, "ALC256", patch_alc269), + HDA_CODEC_ENTRY(0x10ec0260, "ALC260", patch_alc260), diff --git a/queue-4.9/ceph-unlock-dangling-spinlock-in-try_flush_caps.patch b/queue-4.9/ceph-unlock-dangling-spinlock-in-try_flush_caps.patch new file mode 100644 index 00000000000..566239ff2b3 --- /dev/null +++ b/queue-4.9/ceph-unlock-dangling-spinlock-in-try_flush_caps.patch @@ -0,0 +1,48 @@ +From 6c2838fbdedb9b72a81c931d49e56b229b6cdbca Mon Sep 17 00:00:00 2001 +From: Jeff Layton +Date: Thu, 19 Oct 2017 08:52:58 -0400 +Subject: ceph: unlock dangling spinlock in try_flush_caps() + +From: Jeff Layton + +commit 6c2838fbdedb9b72a81c931d49e56b229b6cdbca upstream. + +sparse warns: + + fs/ceph/caps.c:2042:9: warning: context imbalance in 'try_flush_caps' - wrong count at exit + +We need to exit this function with the lock unlocked, but a couple of +cases leave it locked. + +Signed-off-by: Jeff Layton +Reviewed-by: "Yan, Zheng" +Reviewed-by: Ilya Dryomov +Signed-off-by: Ilya Dryomov +Signed-off-by: Greg Kroah-Hartman + +--- + fs/ceph/caps.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +--- a/fs/ceph/caps.c ++++ b/fs/ceph/caps.c +@@ -1900,6 +1900,7 @@ static int try_flush_caps(struct inode * + retry: + spin_lock(&ci->i_ceph_lock); + if (ci->i_ceph_flags & CEPH_I_NOFLUSH) { ++ spin_unlock(&ci->i_ceph_lock); + dout("try_flush_caps skipping %p I_NOFLUSH set\n", inode); + goto out; + } +@@ -1917,8 +1918,10 @@ retry: + mutex_lock(&session->s_mutex); + goto retry; + } +- if (cap->session->s_state < CEPH_MDS_SESSION_OPEN) ++ if (cap->session->s_state < CEPH_MDS_SESSION_OPEN) { ++ spin_unlock(&ci->i_ceph_lock); + goto out; ++ } + + flushing = __mark_caps_flushing(inode, session, true, + &flush_tid, &oldest_flush_tid); diff --git a/queue-4.9/workqueue-replace-pool-manager_arb-mutex-with-a-flag.patch b/queue-4.9/workqueue-replace-pool-manager_arb-mutex-with-a-flag.patch new file mode 100644 index 00000000000..17e3cd8c0bd --- /dev/null +++ b/queue-4.9/workqueue-replace-pool-manager_arb-mutex-with-a-flag.patch @@ -0,0 +1,181 @@ +From 692b48258dda7c302e777d7d5f4217244478f1f6 Mon Sep 17 00:00:00 2001 +From: Tejun Heo +Date: Mon, 9 Oct 2017 08:04:13 -0700 +Subject: workqueue: replace pool->manager_arb mutex with a flag + +From: Tejun Heo + +commit 692b48258dda7c302e777d7d5f4217244478f1f6 upstream. + +Josef reported a HARDIRQ-safe -> HARDIRQ-unsafe lock order detected by +lockdep: + + [ 1270.472259] WARNING: HARDIRQ-safe -> HARDIRQ-unsafe lock order detected + [ 1270.472783] 4.14.0-rc1-xfstests-12888-g76833e8 #110 Not tainted + [ 1270.473240] ----------------------------------------------------- + [ 1270.473710] kworker/u5:2/5157 [HC0[0]:SC0[0]:HE0:SE1] is trying to acquire: + [ 1270.474239] (&(&lock->wait_lock)->rlock){+.+.}, at: [] __mutex_unlock_slowpath+0xa2/0x280 + [ 1270.474994] + [ 1270.474994] and this task is already holding: + [ 1270.475440] (&pool->lock/1){-.-.}, at: [] worker_thread+0x366/0x3c0 + [ 1270.476046] which would create a new lock dependency: + [ 1270.476436] (&pool->lock/1){-.-.} -> (&(&lock->wait_lock)->rlock){+.+.} + [ 1270.476949] + [ 1270.476949] but this new dependency connects a HARDIRQ-irq-safe lock: + [ 1270.477553] (&pool->lock/1){-.-.} + ... + [ 1270.488900] to a HARDIRQ-irq-unsafe lock: + [ 1270.489327] (&(&lock->wait_lock)->rlock){+.+.} + ... + [ 1270.494735] Possible interrupt unsafe locking scenario: + [ 1270.494735] + [ 1270.495250] CPU0 CPU1 + [ 1270.495600] ---- ---- + [ 1270.495947] lock(&(&lock->wait_lock)->rlock); + [ 1270.496295] local_irq_disable(); + [ 1270.496753] lock(&pool->lock/1); + [ 1270.497205] lock(&(&lock->wait_lock)->rlock); + [ 1270.497744] + [ 1270.497948] lock(&pool->lock/1); + +, which will cause a irq inversion deadlock if the above lock scenario +happens. + +The root cause of this safe -> unsafe lock order is the +mutex_unlock(pool->manager_arb) in manage_workers() with pool->lock +held. + +Unlocking mutex while holding an irq spinlock was never safe and this +problem has been around forever but it never got noticed because the +only time the mutex is usually trylocked while holding irqlock making +actual failures very unlikely and lockdep annotation missed the +condition until the recent b9c16a0e1f73 ("locking/mutex: Fix +lockdep_assert_held() fail"). + +Using mutex for pool->manager_arb has always been a bit of stretch. +It primarily is an mechanism to arbitrate managership between workers +which can easily be done with a pool flag. The only reason it became +a mutex is that pool destruction path wants to exclude parallel +managing operations. + +This patch replaces the mutex with a new pool flag POOL_MANAGER_ACTIVE +and make the destruction path wait for the current manager on a wait +queue. + +v2: Drop unnecessary flag clearing before pool destruction as + suggested by Boqun. + +Signed-off-by: Tejun Heo +Reported-by: Josef Bacik +Reviewed-by: Lai Jiangshan +Cc: Peter Zijlstra +Cc: Boqun Feng +Signed-off-by: Greg Kroah-Hartman + +--- + kernel/workqueue.c | 37 +++++++++++++++---------------------- + 1 file changed, 15 insertions(+), 22 deletions(-) + +--- a/kernel/workqueue.c ++++ b/kernel/workqueue.c +@@ -68,6 +68,7 @@ enum { + * attach_mutex to avoid changing binding state while + * worker_attach_to_pool() is in progress. + */ ++ POOL_MANAGER_ACTIVE = 1 << 0, /* being managed */ + POOL_DISASSOCIATED = 1 << 2, /* cpu can't serve workers */ + + /* worker flags */ +@@ -165,7 +166,6 @@ struct worker_pool { + /* L: hash of busy workers */ + + /* see manage_workers() for details on the two manager mutexes */ +- struct mutex manager_arb; /* manager arbitration */ + struct worker *manager; /* L: purely informational */ + struct mutex attach_mutex; /* attach/detach exclusion */ + struct list_head workers; /* A: attached workers */ +@@ -297,6 +297,7 @@ static struct workqueue_attrs *wq_update + + static DEFINE_MUTEX(wq_pool_mutex); /* protects pools and workqueues list */ + static DEFINE_SPINLOCK(wq_mayday_lock); /* protects wq->maydays list */ ++static DECLARE_WAIT_QUEUE_HEAD(wq_manager_wait); /* wait for manager to go away */ + + static LIST_HEAD(workqueues); /* PR: list of all workqueues */ + static bool workqueue_freezing; /* PL: have wqs started freezing? */ +@@ -799,7 +800,7 @@ static bool need_to_create_worker(struct + /* Do we have too many workers and should some go away? */ + static bool too_many_workers(struct worker_pool *pool) + { +- bool managing = mutex_is_locked(&pool->manager_arb); ++ bool managing = pool->flags & POOL_MANAGER_ACTIVE; + int nr_idle = pool->nr_idle + managing; /* manager is considered idle */ + int nr_busy = pool->nr_workers - nr_idle; + +@@ -1979,24 +1980,17 @@ static bool manage_workers(struct worker + { + struct worker_pool *pool = worker->pool; + +- /* +- * Anyone who successfully grabs manager_arb wins the arbitration +- * and becomes the manager. mutex_trylock() on pool->manager_arb +- * failure while holding pool->lock reliably indicates that someone +- * else is managing the pool and the worker which failed trylock +- * can proceed to executing work items. This means that anyone +- * grabbing manager_arb is responsible for actually performing +- * manager duties. If manager_arb is grabbed and released without +- * actual management, the pool may stall indefinitely. +- */ +- if (!mutex_trylock(&pool->manager_arb)) ++ if (pool->flags & POOL_MANAGER_ACTIVE) + return false; ++ ++ pool->flags |= POOL_MANAGER_ACTIVE; + pool->manager = worker; + + maybe_create_worker(pool); + + pool->manager = NULL; +- mutex_unlock(&pool->manager_arb); ++ pool->flags &= ~POOL_MANAGER_ACTIVE; ++ wake_up(&wq_manager_wait); + return true; + } + +@@ -3203,7 +3197,6 @@ static int init_worker_pool(struct worke + setup_timer(&pool->mayday_timer, pool_mayday_timeout, + (unsigned long)pool); + +- mutex_init(&pool->manager_arb); + mutex_init(&pool->attach_mutex); + INIT_LIST_HEAD(&pool->workers); + +@@ -3273,13 +3266,15 @@ static void put_unbound_pool(struct work + hash_del(&pool->hash_node); + + /* +- * Become the manager and destroy all workers. Grabbing +- * manager_arb prevents @pool's workers from blocking on +- * attach_mutex. ++ * Become the manager and destroy all workers. This prevents ++ * @pool's workers from blocking on attach_mutex. We're the last ++ * manager and @pool gets freed with the flag set. + */ +- mutex_lock(&pool->manager_arb); +- + spin_lock_irq(&pool->lock); ++ wait_event_lock_irq(wq_manager_wait, ++ !(pool->flags & POOL_MANAGER_ACTIVE), pool->lock); ++ pool->flags |= POOL_MANAGER_ACTIVE; ++ + while ((worker = first_idle_worker(pool))) + destroy_worker(worker); + WARN_ON(pool->nr_workers || pool->nr_idle); +@@ -3293,8 +3288,6 @@ static void put_unbound_pool(struct work + if (pool->detach_completion) + wait_for_completion(pool->detach_completion); + +- mutex_unlock(&pool->manager_arb); +- + /* shut down the timers */ + del_timer_sync(&pool->idle_timer); + del_timer_sync(&pool->mayday_timer);