Skip to content

Commit

Permalink
locking/rwsem: Fix down_write_killable() for CONFIG_RWSEM_GENERIC_SPI…
Browse files Browse the repository at this point in the history
…NLOCK=y

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:

 04cafed ("locking/rwsem: Fix down_write_killable()")

... however, this bug also exists for CONFIG_RWSEM_GENERIC_SPINLOCK=y.

Signed-off-by: Niklas Cassel <[email protected]>
Signed-off-by: Peter Zijlstra (Intel) <[email protected]>
Cc: <[email protected]>
Cc: <[email protected]>
Cc: Andrew Morton <[email protected]>
Cc: Linus Torvalds <[email protected]>
Cc: Niklas Cassel <[email protected]>
Cc: Paul E. McKenney <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Fixes: d479960 ("locking/rwsem: Introduce basis for down_write_killable()")
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: Ingo Molnar <[email protected]>
Niklas Cassel authored and Ingo Molnar committed Mar 16, 2017
1 parent 9bbb25a commit 17fcbd5
Showing 1 changed file with 11 additions and 5 deletions.
16 changes: 11 additions & 5 deletions kernel/locking/rwsem-spinlock.c
Original file line number Diff line number Diff line change
@@ -213,23 +213,29 @@ 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_current_state(state);
raw_spin_unlock_irqrestore(&sem->wait_lock, flags);
schedule();
raw_spin_lock_irqsave(&sem->wait_lock, flags);
}
/* 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)

0 comments on commit 17fcbd5

Please sign in to comment.