1
0
mirror of https://git.FreeBSD.org/src.git synced 2024-10-18 02:19:39 +00:00

vfs: make skipping LRU requeue optional

As explained in the comment in the code it is a bottleneck in certain
workloads. On the other hand it does not need to be skipped in most
cases, while transiently running into the lock being contended happens a
lot.

(cherry picked from commit 0a9aa6fdf5)
This commit is contained in:
Mateusz Guzik 2024-07-08 12:24:41 +00:00
parent d6b6165ebb
commit b7f6841e00

View File

@ -224,6 +224,10 @@ static counter_u64_t vnode_skipped_requeues;
SYSCTL_COUNTER_U64(_vfs_vnode_stats, OID_AUTO, skipped_requeues, CTLFLAG_RD, &vnode_skipped_requeues,
"Number of times LRU requeue was skipped due to lock contention");
static __read_mostly bool vnode_can_skip_requeue;
SYSCTL_BOOL(_vfs_vnode_param, OID_AUTO, can_skip_requeue, CTLFLAG_RW,
&vnode_can_skip_requeue, 0, "Is LRU requeue skippable");
static u_long deferred_inact;
SYSCTL_ULONG(_vfs, OID_AUTO, deferred_inact, CTLFLAG_RD,
&deferred_inact, 0, "Number of times inactive processing was deferred");
@ -3785,31 +3789,41 @@ vdbatch_process(struct vdbatch *vd)
* lock contention, where vnode_list_mtx becomes the primary bottleneck
* if multiple CPUs get here (one real-world example is highly parallel
* do-nothing make , which will stat *tons* of vnodes). Since it is
* quasi-LRU (read: not that great even if fully honoured) just dodge
* the problem. Parties which don't like it are welcome to implement
* something better.
* quasi-LRU (read: not that great even if fully honoured) provide an
* option to just dodge the problem. Parties which don't like it are
* welcome to implement something better.
*/
critical_enter();
if (mtx_trylock(&vnode_list_mtx)) {
for (i = 0; i < VDBATCH_SIZE; i++) {
vp = vd->tab[i];
vd->tab[i] = NULL;
TAILQ_REMOVE(&vnode_list, vp, v_vnodelist);
TAILQ_INSERT_TAIL(&vnode_list, vp, v_vnodelist);
MPASS(vp->v_dbatchcpu != NOCPU);
vp->v_dbatchcpu = NOCPU;
}
mtx_unlock(&vnode_list_mtx);
} else {
counter_u64_add(vnode_skipped_requeues, 1);
if (vnode_can_skip_requeue) {
if (!mtx_trylock(&vnode_list_mtx)) {
counter_u64_add(vnode_skipped_requeues, 1);
critical_enter();
for (i = 0; i < VDBATCH_SIZE; i++) {
vp = vd->tab[i];
vd->tab[i] = NULL;
MPASS(vp->v_dbatchcpu != NOCPU);
vp->v_dbatchcpu = NOCPU;
}
vd->index = 0;
critical_exit();
return;
for (i = 0; i < VDBATCH_SIZE; i++) {
vp = vd->tab[i];
vd->tab[i] = NULL;
MPASS(vp->v_dbatchcpu != NOCPU);
vp->v_dbatchcpu = NOCPU;
}
/* fallthrough to locked processing */
} else {
mtx_lock(&vnode_list_mtx);
}
mtx_assert(&vnode_list_mtx, MA_OWNED);
critical_enter();
for (i = 0; i < VDBATCH_SIZE; i++) {
vp = vd->tab[i];
vd->tab[i] = NULL;
TAILQ_REMOVE(&vnode_list, vp, v_vnodelist);
TAILQ_INSERT_TAIL(&vnode_list, vp, v_vnodelist);
MPASS(vp->v_dbatchcpu != NOCPU);
vp->v_dbatchcpu = NOCPU;
}
mtx_unlock(&vnode_list_mtx);
vd->index = 0;
critical_exit();
}