FROMLIST: locking/rwsem: Limit # of null owner retries for handoff writer
Commit91d2a812df("locking/rwsem: Make handoff writer optimistically spin on owner") assumes that when the owner field is changed to NULL, the lock will become free soon. That assumption may not be correct especially if the handoff writer doing the spinning is a RT task which may preempt another task from completing its action of either freeing the rwsem or properly setting up owner. To prevent this live lock scenario, we have to limit the number of trylock attempts without sleeping. The current limit is now set to 8 to allow enough time for the other task to hopefully complete its action. By adding new lock events to track the number of NULL owner retries with handoff flag set before a successful trylock when running a 96 threads locking microbenchmark with equal number of readers and writers running on a 2-core 96-thread system for 15 seconds, the following stats are obtained. Note that none of locking threads are RT tasks. Retries of successful trylock Count ----------------------------- ----- 1 1738 2 19 3 11 4 2 5 1 6 1 7 1 8 0 X 1 The last row is the one failed attempt that needs more than 8 retries. So a retry count maximum of 8 should capture most of them if no RT task is in the mix. Bug: 252734649 Fixes:91d2a812df("locking/rwsem: Make handoff writer optimistically spin on owner") Reported-by: Mukesh Ojha <quic_mojha@quicinc.com> Signed-off-by: Waiman Long <longman@redhat.com> Link: https://lore.kernel.org/lkml/20221012133333.1265281-3-longman@redhat.com/ Signed-off-by: wangting11 <wangting11@xiaomi.com> Change-Id: Iae4764e9a74d78e2ec7019947cb8bd9e64c26d78
This commit is contained in:
@@ -1088,6 +1088,7 @@ rwsem_down_write_slowpath(struct rw_semaphore *sem, int state)
|
||||
{
|
||||
long count;
|
||||
struct rwsem_waiter waiter;
|
||||
int null_owner_retries;
|
||||
DEFINE_WAKE_Q(wake_q);
|
||||
bool already_on_list = false;
|
||||
|
||||
@@ -1153,7 +1154,7 @@ wait:
|
||||
/* wait until we successfully acquire the lock */
|
||||
trace_android_vh_rwsem_write_wait_start(sem);
|
||||
set_current_state(state);
|
||||
for (;;) {
|
||||
for (null_owner_retries = 0;;) {
|
||||
if (rwsem_try_write_lock(sem, &waiter)) {
|
||||
/* rwsem_try_write_lock() implies ACQUIRE on success */
|
||||
break;
|
||||
@@ -1179,8 +1180,21 @@ wait:
|
||||
owner_state = rwsem_spin_on_owner(sem);
|
||||
preempt_enable();
|
||||
|
||||
if (owner_state == OWNER_NULL)
|
||||
/*
|
||||
* owner is NULL doesn't guarantee the lock is free.
|
||||
* An incoming reader will temporarily increment the
|
||||
* reader count without changing owner and the
|
||||
* rwsem_try_write_lock() will fails if the reader
|
||||
* is not able to decrement it in time. Allow 8
|
||||
* trylock attempts when hitting a NULL owner before
|
||||
* going to sleep.
|
||||
*/
|
||||
if ((owner_state == OWNER_NULL) &&
|
||||
(null_owner_retries < 8)) {
|
||||
null_owner_retries++;
|
||||
goto trylock_again;
|
||||
}
|
||||
null_owner_retries = 0;
|
||||
}
|
||||
|
||||
schedule();
|
||||
|
||||
Reference in New Issue
Block a user