Skip to content

Commit 048f45d

Browse files
kkdwvdKernel Patches Daemon
authored andcommitted
rqspinlock: Disable spinning for trylock fallback
The original trylock fallback was inherited from qspinlock, and then reused for the reentrant NMIs while the slow path is active. However, under contention, it is very unlikely for the trylock to succeed in taking the lock. In addition, a trylock also has no fairness guarantees, and thus is prone to starvation issues under extreme scenarios. The original qspinlock had no choice in terms of returning an error the caller; if the node count was breached, it had to fall back to trylock to attempt to take the lock. In case of rqspinlock, we do have the option of returning to the user. Thus, simply attempt the trylock once, and instead of spinning, return an error in case the lock cannot be taken. This ends up significantly reducing the time spent in the trylock fallback, since we no longer wait for the timeout duration trying to aimlessly acquire the lock when there's a high-probability that under contention, it won't be available to us anyway. Signed-off-by: Kumar Kartikeya Dwivedi <[email protected]>
1 parent 1caf560 commit 048f45d

File tree

1 file changed

+8
-10
lines changed

1 file changed

+8
-10
lines changed

kernel/bpf/rqspinlock.c

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -450,19 +450,17 @@ int __lockfunc resilient_queued_spin_lock_slowpath(rqspinlock_t *lock, u32 val)
450450
* not be nested NMIs taking spinlocks. That may not be true in
451451
* some architectures even though the chance of needing more than
452452
* 4 nodes will still be extremely unlikely. When that happens,
453-
* we fall back to spinning on the lock directly without using
454-
* any MCS node. This is not the most elegant solution, but is
455-
* simple enough.
453+
* we fall back to attempting a trylock operation without using
454+
* any MCS node. Unlike qspinlock which cannot fail, we have the
455+
* option of failing the slow path, and under contention, such a
456+
* trylock spinning will likely be treated unfairly due to lack of
457+
* queueing, hence do not spin.
456458
*/
457459
if (unlikely(idx >= _Q_MAX_NODES || (in_nmi() && idx > 0))) {
458460
lockevent_inc(lock_no_node);
459-
RES_RESET_TIMEOUT(ts, RES_DEF_TIMEOUT);
460-
while (!queued_spin_trylock(lock)) {
461-
if (RES_CHECK_TIMEOUT(ts, ret, ~0u)) {
462-
lockevent_inc(rqspinlock_lock_timeout);
463-
goto err_release_node;
464-
}
465-
cpu_relax();
461+
if (!queued_spin_trylock(lock)) {
462+
ret = -EDEADLK;
463+
goto err_release_node;
466464
}
467465
goto release;
468466
}

0 commit comments

Comments
 (0)