| From cfcc00dd4d13313e7d3f58019b8d31f2e77561a8 Mon Sep 17 00:00:00 2001 |
| From: Niklas Cassel <niklas.cassel@axis.com> |
| Date: Sat, 25 Feb 2017 01:17:53 +0100 |
| Subject: [PATCH] locking/rwsem: Fix down_write_killable() for |
| CONFIG_RWSEM_GENERIC_SPINLOCK=y |
| |
| commit 17fcbd590d0c3e35bd9646e2215f86586378bc42 upstream. |
| |
| We hang if SIGKILL has been sent, but the task is stuck in down_read() |
| (after do_exit()), even though no task is doing down_write() on the |
| rwsem in question: |
| |
| INFO: task libupnp:21868 blocked for more than 120 seconds. |
| libupnp D 0 21868 1 0x08100008 |
| ... |
| Call Trace: |
| __schedule() |
| schedule() |
| __down_read() |
| do_exit() |
| do_group_exit() |
| __wake_up_parent() |
| |
| This bug has already been fixed for CONFIG_RWSEM_XCHGADD_ALGORITHM=y in |
| the following commit: |
| |
| 04cafed7fc19 ("locking/rwsem: Fix down_write_killable()") |
| |
| ... however, this bug also exists for CONFIG_RWSEM_GENERIC_SPINLOCK=y. |
| |
| Signed-off-by: Niklas Cassel <niklas.cassel@axis.com> |
| Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> |
| Cc: <mhocko@suse.com> |
| Cc: <stable@vger.kernel.org> |
| Cc: Andrew Morton <akpm@linux-foundation.org> |
| Cc: Linus Torvalds <torvalds@linux-foundation.org> |
| Cc: Niklas Cassel <niklass@axis.com> |
| Cc: Paul E. McKenney <paulmck@linux.vnet.ibm.com> |
| Cc: Peter Zijlstra <peterz@infradead.org> |
| Cc: Thomas Gleixner <tglx@linutronix.de> |
| Fixes: d47996082f52 ("locking/rwsem: Introduce basis for down_write_killable()") |
| Link: http://lkml.kernel.org/r/1487981873-12649-1-git-send-email-niklass@axis.com |
| Signed-off-by: Ingo Molnar <mingo@kernel.org> |
| Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> |
| |
| diff --git a/kernel/locking/rwsem-spinlock.c b/kernel/locking/rwsem-spinlock.c |
| index 1591f6b3539f..e185b4e279e8 100644 |
| --- a/kernel/locking/rwsem-spinlock.c |
| +++ b/kernel/locking/rwsem-spinlock.c |
| @@ -216,10 +216,9 @@ int __sched __down_write_common(struct rw_semaphore *sem, int state) |
| */ |
| if (sem->count == 0) |
| break; |
| - if (signal_pending_state(state, current)) { |
| - ret = -EINTR; |
| - goto out; |
| - } |
| + if (signal_pending_state(state, current)) |
| + goto out_nolock; |
| + |
| set_task_state(tsk, state); |
| raw_spin_unlock_irqrestore(&sem->wait_lock, flags); |
| schedule(); |
| @@ -227,12 +226,19 @@ int __sched __down_write_common(struct rw_semaphore *sem, int state) |
| } |
| /* got the lock */ |
| sem->count = -1; |
| -out: |
| list_del(&waiter.list); |
| |
| raw_spin_unlock_irqrestore(&sem->wait_lock, flags); |
| |
| return ret; |
| + |
| +out_nolock: |
| + list_del(&waiter.list); |
| + if (!list_empty(&sem->wait_list)) |
| + __rwsem_do_wake(sem, 1); |
| + raw_spin_unlock_irqrestore(&sem->wait_lock, flags); |
| + |
| + return -EINTR; |
| } |
| |
| void __sched __down_write(struct rw_semaphore *sem) |
| -- |
| 2.12.0 |
| |