Skip to content

Commit

Permalink
locking/rwsem: Allow slowpath writer to ignore handoff bit if not set…
Browse files Browse the repository at this point in the history
… by first waiter

commit 6eebd5f upstream.

With commit d257cc8 ("locking/rwsem: Make handoff bit handling more
consistent"), the writer that sets the handoff bit can be interrupted
out without clearing the bit if the wait queue isn't empty. This disables
reader and writer optimistic lock spinning and stealing.

Now if a non-first writer in the queue is somehow woken up or a new
waiter enters the slowpath, it can't acquire the lock.  This is not the
case before commit d257cc8 as the writer that set the handoff bit
will clear it when exiting out via the out_nolock path. This is less
efficient as the busy rwsem stays in an unlock state for a longer time.

In some cases, this new behavior may cause lockups as shown in [1] and
[2].

This patch allows a non-first writer to ignore the handoff bit if it
is not originally set or initiated by the first waiter. This patch is
shown to be effective in fixing the lockup problem reported in [1].

[1] https://lore.kernel.org/lkml/20220617134325.GC30825@techsingularity.net/
[2] https://lore.kernel.org/lkml/3f02975c-1a9d-be20-32cf-f1d8e3dfafcc@oracle.com/

Fixes: d257cc8 ("locking/rwsem: Make handoff bit handling more consistent")
Signed-off-by: Waiman Long <longman@redhat.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Acked-by: John Donnelly <john.p.donnelly@oracle.com>
Tested-by: Mel Gorman <mgorman@techsingularity.net>
Link: https://lore.kernel.org/r/20220622200419.778799-1-longman@redhat.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
Waiman Long authored and gregkh committed Aug 3, 2022
1 parent 66d31ce commit d10e819
Showing 1 changed file with 20 additions and 10 deletions.
30 changes: 20 additions & 10 deletions kernel/locking/rwsem.c
Original file line number Diff line number Diff line change
Expand Up @@ -335,8 +335,6 @@ struct rwsem_waiter {
struct task_struct *task;
enum rwsem_waiter_type type;
unsigned long timeout;

/* Writer only, not initialized in reader */
bool handoff_set;
};
#define rwsem_first_waiter(sem) \
Expand Down Expand Up @@ -456,10 +454,12 @@ static void rwsem_mark_wake(struct rw_semaphore *sem,
* to give up the lock), request a HANDOFF to
* force the issue.
*/
if (!(oldcount & RWSEM_FLAG_HANDOFF) &&
time_after(jiffies, waiter->timeout)) {
adjustment -= RWSEM_FLAG_HANDOFF;
lockevent_inc(rwsem_rlock_handoff);
if (time_after(jiffies, waiter->timeout)) {
if (!(oldcount & RWSEM_FLAG_HANDOFF)) {
adjustment -= RWSEM_FLAG_HANDOFF;
lockevent_inc(rwsem_rlock_handoff);
}
waiter->handoff_set = true;
}

atomic_long_add(-adjustment, &sem->count);
Expand Down Expand Up @@ -569,7 +569,7 @@ static void rwsem_mark_wake(struct rw_semaphore *sem,
static inline bool rwsem_try_write_lock(struct rw_semaphore *sem,
struct rwsem_waiter *waiter)
{
bool first = rwsem_first_waiter(sem) == waiter;
struct rwsem_waiter *first = rwsem_first_waiter(sem);
long count, new;

lockdep_assert_held(&sem->wait_lock);
Expand All @@ -579,11 +579,20 @@ static inline bool rwsem_try_write_lock(struct rw_semaphore *sem,
bool has_handoff = !!(count & RWSEM_FLAG_HANDOFF);

if (has_handoff) {
if (!first)
/*
* Honor handoff bit and yield only when the first
* waiter is the one that set it. Otherwisee, we
* still try to acquire the rwsem.
*/
if (first->handoff_set && (waiter != first))
return false;

/* First waiter inherits a previously set handoff bit */
waiter->handoff_set = true;
/*
* First waiter can inherit a previously set handoff
* bit and spin on rwsem if lock acquisition fails.
*/
if (waiter == first)
waiter->handoff_set = true;
}

new = count;
Expand Down Expand Up @@ -978,6 +987,7 @@ rwsem_down_read_slowpath(struct rw_semaphore *sem, long count, unsigned int stat
waiter.task = current;
waiter.type = RWSEM_WAITING_FOR_READ;
waiter.timeout = jiffies + RWSEM_WAIT_TIMEOUT;
waiter.handoff_set = false;

raw_spin_lock_irq(&sem->wait_lock);
if (list_empty(&sem->wait_list)) {
Expand Down

0 comments on commit d10e819

Please sign in to comment.