diff options
-rw-r--r-- | sys/kern/vfs_subr.c | 82 | ||||
-rw-r--r-- | sys/kern/vfs_vnops.c | 3 | ||||
-rw-r--r-- | sys/sys/vnode.h | 4 |
3 files changed, 78 insertions, 11 deletions
diff --git a/sys/kern/vfs_subr.c b/sys/kern/vfs_subr.c index 3b1f854..ae297f0 100644 --- a/sys/kern/vfs_subr.c +++ b/sys/kern/vfs_subr.c @@ -59,6 +59,7 @@ #include <sys/namei.h> #include <sys/stat.h> #include <sys/sysctl.h> +#include <sys/syslog.h> #include <sys/vmmeter.h> #include <sys/vnode.h> @@ -532,13 +533,15 @@ vattr_null(vap) * 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; mtx_lock(&mntvnode_mtx); while (count && (vp = TAILQ_FIRST(&mp->mnt_nvnodelist)) != NULL) { TAILQ_REMOVE(&mp->mnt_nvnodelist, vp, v_nmntvnodes); @@ -552,6 +555,7 @@ vlrureclaim(struct mount *mp, int count) mtx_unlock(&mntvnode_mtx); if (VMIGHTFREE(vp)) { vgonel(vp, curthread); + done++; } else { mtx_unlock(&vp->v_interlock); } @@ -560,9 +564,69 @@ vlrureclaim(struct mount *mp, int count) --count; } mtx_unlock(&mntvnode_mtx); + 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 int vnlruproc_sig; + +static void +vnlru_proc(void) +{ + struct mount *mp, *nmp; + int s; + int done; + struct proc *p = vnlruproc; + struct thread *td = &p->p_thread; /* XXXKSE */ + + mtx_lock(&Giant); + + EVENTHANDLER_REGISTER(shutdown_pre_sync, kproc_shutdown, p, + SHUTDOWN_PRI_FIRST); + + s = splbio(); + for (;;) { + kthread_suspend_check(p); + if (numvnodes - freevnodes <= desiredvnodes * 9 / 10) { + vnlruproc_sig = 0; + tsleep(&vnlruproc, PVFS, "vlruwt", hz); + continue; + } + done = 0; + mtx_lock(&mountlist_mtx); + for (mp = TAILQ_FIRST(&mountlist); mp != NULL; mp = nmp) { + if (vfs_busy(mp, LK_NOWAIT, &mountlist_mtx, td)) { + nmp = TAILQ_NEXT(mp, mnt_list); + continue; + } + done += vlrureclaim(mp, 10); + mtx_lock(&mountlist_mtx); + nmp = TAILQ_NEXT(mp, mnt_list); + vfs_unbusy(mp, td); + } + mtx_unlock(&mountlist_mtx); + if (done == 0) { + printf("vnlru process getting nowhere, pausing..\n"); + tsleep(&vnlru_proc, PPAUSE, "vlrup", hz * 3); + } + } + 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. */ @@ -585,12 +649,14 @@ getnewvnode(tag, mp, vops, vpp) s = splbio(); /* * 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 (mp && numvnodes - freevnodes > desiredvnodes) - vlrureclaim(mp, 2); + if (vnlruproc_sig == 0 && numvnodes - freevnodes > desiredvnodes) { + vnlruproc_sig = 1; /* avoid unnecessary wakeups */ + wakeup(&vnlruproc); + } /* * Attempt to reuse a vnode already on the free list, allocating @@ -1555,7 +1621,7 @@ vget(vp, flags, td) mtx_lock(&vp->v_interlock); if (vp->v_flag & VXLOCK) { if (vp->v_vxproc == curthread) { - printf("VXLOCK interlock avoided\n"); + log(LOG_INFO, "VXLOCK interlock avoided\n"); } else { vp->v_flag |= VXWANT; msleep((caddr_t)vp, &vp->v_interlock, PINOD | PDROP, diff --git a/sys/kern/vfs_vnops.c b/sys/kern/vfs_vnops.c index 84c3ae1..70448d6 100644 --- a/sys/kern/vfs_vnops.c +++ b/sys/kern/vfs_vnops.c @@ -55,6 +55,7 @@ #include <sys/filio.h> #include <sys/ttycom.h> #include <sys/conf.h> +#include <sys/syslog.h> #include <machine/limits.h> @@ -701,7 +702,7 @@ debug_vn_lock(vp, flags, td, filename, line) error = ENOENT; } else { if (vp->v_vxproc != NULL) - printf("VXLOCK interlock avoided in vn_lock\n"); + log(LOG_INFO, "VXLOCK interlock avoided in vn_lock\n"); #ifdef DEBUG_LOCKS vp->filename = filename; vp->line = line; diff --git a/sys/sys/vnode.h b/sys/sys/vnode.h index 4fc0c15..bcf5a84 100644 --- a/sys/sys/vnode.h +++ b/sys/sys/vnode.h @@ -310,8 +310,8 @@ extern void (*lease_updatetime) __P((int deltat)); !((vp)->v_object->ref_count || (vp)->v_object->resident_page_count))) #define VMIGHTFREE(vp) \ - (!((vp)->v_flag & (VFREE|VDOOMED)) && \ - !(vp)->v_holdcnt && !(vp)->v_usecount) + (!((vp)->v_flag & (VFREE|VDOOMED|VXLOCK)) && \ + LIST_EMPTY(&(vp)->v_cache_src) && !(vp)->v_usecount) #define VSHOULDBUSY(vp) \ (((vp)->v_flag & VFREE) && \ |