locking/rwsem: Don't hog RCU read lock while optimistically spinning

There's no reason to hold an RCU read lock the entire time while
optimistically spinning for a rwsem. This can needlessly lengthen RCU
grace periods and slow down synchronize_rcu() when it doesn't brute
force the RCU grace period via rcupdate.rcu_expedited=1.

Signed-off-by: Sultan Alsawaf <sultan@kerneltoast.com>
Signed-off-by: Ruchit <ruchitmarathe@gmail.com>
tirimbino
Sultan Alsawaf 3 years ago committed by Ruchit
parent ba0c1427ea
commit 36451b1a39
  1. 26
      kernel/locking/rwsem-xadd.c

@ -400,32 +400,36 @@ static noinline bool rwsem_spin_on_owner(struct rw_semaphore *sem)
{
struct task_struct *owner = READ_ONCE(sem->owner);
if (!is_rwsem_owner_spinnable(owner))
if (!owner || !is_rwsem_owner_spinnable(owner))
return false;
rcu_read_lock();
while (owner && (READ_ONCE(sem->owner) == owner)) {
while (true) {
bool on_cpu, same_owner;
/*
* Ensure we emit the owner->on_cpu, dereference _after_
* checking sem->owner still matches owner, if that fails,
* Ensure sem->owner still matches owner. If that fails,
* owner might point to free()d memory, if it still matches,
* the rcu_read_lock() ensures the memory stays valid.
*/
barrier();
rcu_read_lock();
same_owner = sem->owner == owner;
if (same_owner)
on_cpu = owner->on_cpu &&
!vcpu_is_preempted(task_cpu(owner));
rcu_read_unlock();
if (!same_owner)
break;
/*
* abort spinning when need_resched or owner is not running or
* owner's cpu is preempted.
*/
if (!owner->on_cpu || need_resched() ||
vcpu_is_preempted(task_cpu(owner))) {
rcu_read_unlock();
if (!on_cpu || need_resched())
return false;
}
cpu_relax();
}
rcu_read_unlock();
/*
* If there is a new owner or the owner is not set, we continue

Loading…
Cancel
Save