NetBSD-Bugs archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
kern/60603: Sisyphean vdrain task
>Number: 60603
>Category: kern
>Synopsis: Sisyphean vdrain task
>Confidential: no
>Severity: serious
>Priority: medium
>Responsible: kern-bug-people
>State: open
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Sun Aug 16 14:00:01 +0000 2026
>Originator: Taylor R Campbell
>Release: current, 11
>Organization:
Desirable Vnode Classifieds, Inc.
>Environment:
>Description:
The vdrain task runs in the background to keep the number of
vnodes below desiredvnodes. It is scheduled asynchronously
from various vnode operations like vrele. If it fails to bring
the number of vnodes below its target, it pauses for a tick and
tries again.
701 /*
702 * threadpool task to keep the number of vnodes below desiredvnodes.
703 */
704 static void
705 vdrain_task(struct threadpool_job *job)
706 {
707 u_int target;
708
709 target = desiredvnodes - desiredvnodes / 16;
710
711 mutex_enter(&vdrain_lock);
712
713 while (!vdrain_one(target))
714 kpause("vdrain", false, 1, &vdrain_lock);
715
716 threadpool_job_done(job);
717 mutex_exit(&vdrain_lock);
718 }
https://nxr.netbsd.org/xref/src/sys/kern/vfs_vnode.c?r=1.158#701
But there's a snag: in this loop, the vdrain task never
reconsiders its target, even if desiredvnodes changes
concurrently.
If you set sysctl -w kern.maxvnodes=N, the sysctl backend will
set desiredvnodes to N and then try to bring it down with
vfs_drainvnodes, which fails and puts desiredvnodes back if we
can't meet the target;
694 static int
695 sysctl_kern_maxvnodes(SYSCTLFN_ARGS)
696 {
...
720 old_vnodes = desiredvnodes;
721 desiredvnodes = new_vnodes;
722 error = vfs_drainvnodes();
723 if (error) {
724 desiredvnodes = old_vnodes;
725 return (error);
726 }
https://nxr.netbsd.org/xref/src/sys/kern/init_sysctl.c?r=1.230#689
2112 int
2113 vfs_drainvnodes(void)
2114 {
2115
2116 mutex_enter(&vdrain_lock);
2117
2118 if (!vdrain_one(desiredvnodes)) {
2119 mutex_exit(&vdrain_lock);
2120 return SET_ERROR(EBUSY);
2121 }
2122
2123 mutex_exit(&vdrain_lock);
...
2128 return 0;
2129 }
https://nxr.netbsd.org/xref/src/sys/kern/vfs_vnode.c?r=1.158#2112
But if the vdrain task started with the unattainably low
desiredvnodes, it will remain stuck indefinitely like Sisyphus,
perpetually rolling a vnode limit up the hill until it loses
grip and the limit rolls right back down the hill.
Also, all access to desiredvnodes is uncoordinated and racy,
and should be serialized by a mutex or something.
>How-To-Repeat:
sysctl -w kern.maxvnodes=<small> on a system with a lot of
files open
>Fix:
1. Recompute target inside the loop like we did before the
thread -> task conversion in vfs_vnode.c rev. 1.152.
2. Serialize access to desiredvnodes with a mutex or rwlock
or pserialize or something.
Home |
Main Index |
Thread Index |
Old Index