==== //depot/yahoo/ybsd_4/src/sys/sys/vnode.h#9 - /home/peter/ybsd_4/src/sys/sys/vnode.h ==== @@ -305,7 +305,7 @@ #define VMIGHTFREE(vp) \ (!((vp)->v_flag & (VFREE|VDOOMED)) && \ - !(vp)->v_holdcnt && !(vp)->v_usecount) + !(vp)->v_usecount) #define VSHOULDBUSY(vp) \ (((vp)->v_flag & VFREE) && \ ==== //depot/yahoo/ybsd_4/src/sys/kern/vfs_subr.c#8 - /home/peter/ybsd_4/src/sys/kern/vfs_subr.c ==== @@ -454,13 +454,15 @@ * underlying files, or the vnode may be in active use. It is not * desireable to reuse such vnodes. These conditions may cause the * number of vnodes to reach some minimum value regardless of what - * you set kern.maxvnodes to. Do not set kernl.maxvnodes too low. + * you set kern.maxvnodes to. Do not set kern.maxvnodes too low. */ -static void +static int vlrureclaim(struct mount *mp, int count) { struct vnode *vp; + int done; + done = 0; simple_lock(&mntvnode_slock); while (count && (vp = TAILQ_FIRST(&mp->mnt_nvnodelist)) != NULL) { TAILQ_REMOVE(&mp->mnt_nvnodelist, vp, v_nmntvnodes); @@ -474,6 +476,7 @@ simple_unlock(&mntvnode_slock); if (VMIGHTFREE(vp)) { vgonel(vp, curproc); + done++; } else { simple_unlock(&vp->v_interlock); } @@ -482,9 +485,63 @@ --count; } simple_unlock(&mntvnode_slock); + return done; } /* + * Attempt to recycle vnodes in a context that is always safe to block. + * Calling vlrurecycle() from the bowels of file system code has some + * interesting deadlock problems. + */ +static struct proc *vnlruproc; + +static void +vnlru_proc(void) +{ + struct mount *mp, *nmp; + int s; + int done; + struct proc *p = vnlruproc; + + EVENTHANDLER_REGISTER(shutdown_pre_sync, shutdown_kproc, p, + SHUTDOWN_PRI_FIRST); + + s = splbio(); + for (;;) { + kproc_suspend_loop(p); + if (numvnodes - freevnodes <= desiredvnodes) { + tsleep(&vnlruproc, PVFS, "vlruwt", hz); + continue; + } + done = 0; + simple_lock(&mountlist_slock); + for (mp = TAILQ_FIRST(&mountlist); mp != NULL; mp = nmp) { + if (vfs_busy(mp, LK_NOWAIT, &mountlist_slock, p)) { + nmp = TAILQ_NEXT(mp, mnt_list); + continue; + } + done += vlrureclaim(mp, 2); + simple_lock(&mountlist_slock); + nmp = TAILQ_NEXT(mp, mnt_list); + vfs_unbusy(mp, p); + } + simple_unlock(&mountlist_slock); + if (done == 0) { + printf("vnlru process failing to get anywhere, pausing..\n"); + tsleep(&lbolt, PPAUSE, "vlrup", 0); + } + } + splx(s); +} + +static struct kproc_desc vnlru_kp = { + "vnlru", + vnlru_proc, + &vnlruproc +}; +SYSINIT(vnlru, SI_SUB_KTHREAD_UPDATE, SI_ORDER_FIRST, kproc_start, &vnlru_kp) + +/* * Routines having to do with the management of the vnode table. */ extern vop_t **dead_vnodeop_p; @@ -508,12 +565,12 @@ /* * Try to reuse vnodes if we hit the max. This situation only - * occurs in certain large-memory (2G+) situations. For the - * algorithm to be stable we have to try to reuse at least 2. - * No hysteresis should be necessary. + * occurs in certain large-memory (2G+) situations. We cannot + * attempt to directly reclaim vnodes due to nasty recursion + * problems. */ if (numvnodes - freevnodes > desiredvnodes) - vlrureclaim(mp, 2); + wakeup(&vnlruproc); /* * Attempt to reuse a vnode already on the free list, allocating