From f50d5ec4e37772bc94961c609b5de758725d8349 Mon Sep 17 00:00:00 2001 From: smh Date: Tue, 9 Apr 2013 15:35:26 +0000 Subject: [PATCH] MFC r241556: Add a KPI to allow to reserve some amount of space in the numvnodes counter, without actually allocating the vnodes. For KBI stability, the td_vp_reserv was moved to the end of struct thread. Reviewed by: avg Approved by: avg (co-mentor) git-svn-id: svn://svn.freebsd.org/base/stable/8@249310 ccf9f872-aa2e-dd11-9fc8-001c23d0bc1f --- sys/kern/kern_thread.c | 1 + sys/kern/subr_trap.c | 2 + sys/kern/vfs_subr.c | 96 +++++++++++++++++++++++++++++++----------- sys/sys/proc.h | 1 + sys/sys/vnode.h | 2 + 5 files changed, 78 insertions(+), 24 deletions(-) diff --git a/sys/kern/kern_thread.c b/sys/kern/kern_thread.c index 5ada3a23e..5cb8276b8 100644 --- a/sys/kern/kern_thread.c +++ b/sys/kern/kern_thread.c @@ -159,6 +159,7 @@ thread_init(void *mem, int size, int flags) td->td_sleepqueue = sleepq_alloc(); td->td_turnstile = turnstile_alloc(); + td->td_vp_reserv = 0; EVENTHANDLER_INVOKE(thread_init, td); td->td_sched = (struct td_sched *)&td[1]; umtx_thread_init(td); diff --git a/sys/kern/subr_trap.c b/sys/kern/subr_trap.c index 618787f28..63b072c68 100644 --- a/sys/kern/subr_trap.c +++ b/sys/kern/subr_trap.c @@ -132,6 +132,8 @@ userret(struct thread *td, struct trapframe *frame) sched_userret(td); KASSERT(td->td_locks == 0, ("userret: Returning with %d locks held.", td->td_locks)); + KASSERT(td->td_vp_reserv == 0, + ("userret: Returning while holding vnode reservation")); #ifdef VIMAGE /* Unfortunately td_vnet_lpush needs VNET_DEBUG. */ VNET_ASSERT(curvnet == NULL, diff --git a/sys/kern/vfs_subr.c b/sys/kern/vfs_subr.c index 1a8b967b2..5813fe059 100644 --- a/sys/kern/vfs_subr.c +++ b/sys/kern/vfs_subr.c @@ -977,34 +977,22 @@ vtryrecycle(struct vnode *vp) } /* - * Return the next vnode from the free list. + * Wait for available vnodes. */ -int -getnewvnode(const char *tag, struct mount *mp, struct vop_vector *vops, - struct vnode **vpp) +static int +getnewvnode_wait(int suspended) { - struct vnode *vp = NULL; - struct bufobj *bo; - CTR3(KTR_VFS, "%s: mp %p with tag %s", __func__, mp, tag); - mtx_lock(&vnode_free_list_mtx); - /* - * Lend our context to reclaim vnodes if they've exceeded the max. - */ - if (freevnodes > wantfreevnodes) - vnlru_free(1); - /* - * Wait for available vnodes. - */ + mtx_assert(&vnode_free_list_mtx, MA_OWNED); if (numvnodes > desiredvnodes) { - if (mp != NULL && (mp->mnt_kern_flag & MNTK_SUSPEND)) { + if (suspended) { /* * File system is beeing suspended, we cannot risk a * deadlock here, so allocate new vnode anyway. */ if (freevnodes > wantfreevnodes) vnlru_free(freevnodes - wantfreevnodes); - goto alloc; + return (0); } if (vnlruproc_sig == 0) { vnlruproc_sig = 1; /* avoid unnecessary wakeups */ @@ -1012,16 +1000,76 @@ getnewvnode(const char *tag, struct mount *mp, struct vop_vector *vops, } msleep(&vnlruproc_sig, &vnode_free_list_mtx, PVFS, "vlruwk", hz); -#if 0 /* XXX Not all VFS_VGET/ffs_vget callers check returns. */ - if (numvnodes > desiredvnodes) { - mtx_unlock(&vnode_free_list_mtx); - return (ENFILE); + } + return (numvnodes > desiredvnodes ? ENFILE : 0); +} + +void +getnewvnode_reserve(u_int count) +{ + struct thread *td; + + td = curthread; + mtx_lock(&vnode_free_list_mtx); + while (count > 0) { + if (getnewvnode_wait(0) == 0) { + count--; + td->td_vp_reserv++; + numvnodes++; } -#endif } -alloc: + mtx_unlock(&vnode_free_list_mtx); +} + +void +getnewvnode_drop_reserve(void) +{ + struct thread *td; + + td = curthread; + mtx_lock(&vnode_free_list_mtx); + KASSERT(numvnodes >= td->td_vp_reserv, ("reserve too large")); + numvnodes -= td->td_vp_reserv; + mtx_unlock(&vnode_free_list_mtx); + td->td_vp_reserv = 0; +} + +/* + * Return the next vnode from the free list. + */ +int +getnewvnode(const char *tag, struct mount *mp, struct vop_vector *vops, + struct vnode **vpp) +{ + struct vnode *vp; + struct bufobj *bo; + struct thread *td; + int error; + + CTR3(KTR_VFS, "%s: mp %p with tag %s", __func__, mp, tag); + vp = NULL; + td = curthread; + if (td->td_vp_reserv > 0) { + td->td_vp_reserv -= 1; + goto alloc; + } + mtx_lock(&vnode_free_list_mtx); + /* + * Lend our context to reclaim vnodes if they've exceeded the max. + */ + if (freevnodes > wantfreevnodes) + vnlru_free(1); + error = getnewvnode_wait(mp != NULL && (mp->mnt_kern_flag & + MNTK_SUSPEND)); +#if 0 /* XXX Not all VFS_VGET/ffs_vget callers check returns. */ + if (error != 0) { + mtx_unlock(&vnode_free_list_mtx); + return (error); + } +#endif numvnodes++; mtx_unlock(&vnode_free_list_mtx); +alloc: vp = (struct vnode *) uma_zalloc(vnode_zone, M_WAITOK|M_ZERO); /* * Setup locks. diff --git a/sys/sys/proc.h b/sys/sys/proc.h index d8f447dbd..eadd418be 100644 --- a/sys/sys/proc.h +++ b/sys/sys/proc.h @@ -308,6 +308,7 @@ struct thread { struct rusage_ext td_rux; /* (t) Internal rusage information. */ struct vm_map_entry *td_map_def_user; /* (k) Deferred entries. */ pid_t td_dbg_forked; /* (c) Child pid for debugger. */ + u_int td_vp_reserv; /* (k) Count of reserved vnodes. */ }; struct mtx *thread_lock_block(struct thread *); diff --git a/sys/sys/vnode.h b/sys/sys/vnode.h index 07715c003..ce58ee89f 100644 --- a/sys/sys/vnode.h +++ b/sys/sys/vnode.h @@ -604,6 +604,8 @@ void cvtstat(struct stat *st, struct ostat *ost); void cvtnstat(struct stat *sb, struct nstat *nsb); int getnewvnode(const char *tag, struct mount *mp, struct vop_vector *vops, struct vnode **vpp); +void getnewvnode_reserve(u_int count); +void getnewvnode_drop_reserve(void); int insmntque1(struct vnode *vp, struct mount *mp, void (*dtr)(struct vnode *, void *), void *dtr_arg); int insmntque(struct vnode *vp, struct mount *mp); -- 2.45.0