vfs: increment numvnodes without the vnode list lock unless under pressure

The vnode list lock is only needed to reclaim free vnodes or kick the vnlru
thread (or to block and not miss a wake up (but note the sleep has a timeout so
this would not be a correctness issue)). Try to get away without the lock by
just doing an atomic increment.

The lock is contended e.g., during poudriere -j 104 where about half of all
acquires come from vnode allocation code.

Note the entire scheme needs a rewrite, the above just reduces it's SMP impact.

Reviewed by:	kib
Differential Revision:	https://reviews.freebsd.org/D23140
This commit is contained in:
Mateusz Guzik 2020-01-16 21:45:21 +00:00
parent b7f50b9ad1
commit 66f67d5e5e
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=356812

View File

@ -1497,21 +1497,22 @@ vtryrecycle(struct vnode *vp)
* The routine can try to free a vnode or stall for up to 1 second waiting for
* vnlru to clear things up, but ultimately always performs a M_WAITOK allocation.
*/
static struct vnode *
vn_alloc(struct mount *mp)
static u_long vn_alloc_cyclecount;
static struct vnode * __noinline
vn_alloc_hard(struct mount *mp)
{
u_long rnumvnodes, rfreevnodes;
static u_long cyclecount;
mtx_lock(&vnode_list_mtx);
rnumvnodes = atomic_load_long(&numvnodes);
if (rnumvnodes + 1 < desiredvnodes) {
cyclecount = 0;
vn_alloc_cyclecount = 0;
goto alloc;
}
rfreevnodes = atomic_load_long(&freevnodes);
if (cyclecount++ >= rfreevnodes) {
cyclecount = 0;
if (vn_alloc_cyclecount++ >= rfreevnodes) {
vn_alloc_cyclecount = 0;
vstir = 1;
}
/*
@ -1546,6 +1547,22 @@ vn_alloc(struct mount *mp)
return (uma_zalloc(vnode_zone, M_WAITOK));
}
static struct vnode *
vn_alloc(struct mount *mp)
{
u_long rnumvnodes;
if (__predict_false(vn_alloc_cyclecount != 0))
return (vn_alloc_hard(mp));
rnumvnodes = atomic_fetchadd_long(&numvnodes, 1) + 1;
if (__predict_false(vnlru_under(rnumvnodes, vlowat))) {
atomic_subtract_long(&numvnodes, 1);
return (vn_alloc_hard(mp));
}
return (uma_zalloc(vnode_zone, M_WAITOK));
}
static void
vn_free(struct vnode *vp)
{