Module Name: src Committed By: hannken Date: Wed Mar 5 09:37:29 UTC 2014
Modified Files: src/share/man/man9: vnode.9 src/sys/kern: vfs_mount.c vfs_vnode.c src/sys/sys: mount.h param.h vnode.h src/sys/ufs/ext2fs: ext2fs_vfsops.c src/sys/ufs/ffs: ffs_vfsops.c src/sys/ufs/lfs: lfs_syscalls.c Log Message: Current support for iterating over mnt_vnodelist is rudimentary. Every caller has to care about list and vnode mutexes, reference count being zero, intermediate vnode states like VI_CLEAN, VI_XLOCK, VI_MARKER and so on. Add an interface to iterate over a vnode list: void vfs_vnode_iterator_init(struct mount *mp, struct vnode_iterator **marker) void vfs_vnode_iterator_destroy(struct vnode_iterator *marker) bool vfs_vnode_iterator_next(struct vnode_iterator *marker, struct vnode **vpp) vfs_vnode_iterator_next() returns either "false / *vpp == NULL" when done or "true / *vpp != NULL" to return the next referenced vnode from the list. To make vrecycle() work in this environment change it to bool vrecycle(struct vnode *vp) where "vp" is a referenced vnode to be destroyed if this is the last reference. Discussed on tech-kern. Welcome to 6.99.34 To generate a diff of this commit: cvs rdiff -u -r1.59 -r1.60 src/share/man/man9/vnode.9 cvs rdiff -u -r1.26 -r1.27 src/sys/kern/vfs_mount.c cvs rdiff -u -r1.32 -r1.33 src/sys/kern/vfs_vnode.c cvs rdiff -u -r1.211 -r1.212 src/sys/sys/mount.h cvs rdiff -u -r1.442 -r1.443 src/sys/sys/param.h cvs rdiff -u -r1.243 -r1.244 src/sys/sys/vnode.h cvs rdiff -u -r1.176 -r1.177 src/sys/ufs/ext2fs/ext2fs_vfsops.c cvs rdiff -u -r1.292 -r1.293 src/sys/ufs/ffs/ffs_vfsops.c cvs rdiff -u -r1.150 -r1.151 src/sys/ufs/lfs/lfs_syscalls.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/share/man/man9/vnode.9 diff -u src/share/man/man9/vnode.9:1.59 src/share/man/man9/vnode.9:1.60 --- src/share/man/man9/vnode.9:1.59 Sat Feb 22 11:28:18 2014 +++ src/share/man/man9/vnode.9 Wed Mar 5 09:37:29 2014 @@ -1,4 +1,4 @@ -.\" $NetBSD: vnode.9,v 1.59 2014/02/22 11:28:18 wiz Exp $ +.\" $NetBSD: vnode.9,v 1.60 2014/03/05 09:37:29 hannken Exp $ .\" .\" Copyright (c) 2001, 2005, 2006 The NetBSD Foundation, Inc. .\" All rights reserved. @@ -27,7 +27,7 @@ .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE .\" POSSIBILITY OF SUCH DAMAGE. .\" -.Dd February 22, 2014 +.Dd March 5, 2014 .Dt VNODE 9 .Os .Sh NAME @@ -79,7 +79,7 @@ .Ft void .Fn ungetnewvnode "struct vnode *vp" .Ft int -.Fn vrecycle "struct vnode *vp" "struct kmutex_t *inter_lkp" +.Fn vrecycle "struct vnode *vp" .Ft void .Fn vgone "struct vnode *vp" .Ft void @@ -616,12 +616,12 @@ This function is needed for .Xr VFS_VGET 9 which may need to push back a vnode in case of a locking race condition. -.It Fn vrecycle "vp" "inter_lkp" -Recycle the unused vnode +.It Fn vrecycle "vp" +Recycle the referenced vnode .Fa vp -from the front of the freelist. +if this is the last reference. .Fn vrecycle -is a null operation if the reference count is greater than zero. +is a null operation if the reference count is greater than one. .It Fn vgone "vp" Eliminate all activity associated with the unlocked vnode .Fa vp Index: src/sys/kern/vfs_mount.c diff -u src/sys/kern/vfs_mount.c:1.26 src/sys/kern/vfs_mount.c:1.27 --- src/sys/kern/vfs_mount.c:1.26 Thu Feb 27 13:00:06 2014 +++ src/sys/kern/vfs_mount.c Wed Mar 5 09:37:29 2014 @@ -1,4 +1,4 @@ -/* $NetBSD: vfs_mount.c,v 1.26 2014/02/27 13:00:06 hannken Exp $ */ +/* $NetBSD: vfs_mount.c,v 1.27 2014/03/05 09:37:29 hannken Exp $ */ /*- * Copyright (c) 1997-2011 The NetBSD Foundation, Inc. @@ -67,7 +67,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: vfs_mount.c,v 1.26 2014/02/27 13:00:06 hannken Exp $"); +__KERNEL_RCSID(0, "$NetBSD: vfs_mount.c,v 1.27 2014/03/05 09:37:29 hannken Exp $"); #include <sys/param.h> #include <sys/kernel.h> @@ -375,6 +375,82 @@ vunmark(vnode_t *mvp) return vp; } +struct vnode_iterator { + struct vnode vi_vnode; +}; + +void +vfs_vnode_iterator_init(struct mount *mp, struct vnode_iterator **vipp) +{ + struct vnode *vp; + + vp = vnalloc(mp); + + mutex_enter(&mntvnode_lock); + TAILQ_INSERT_HEAD(&mp->mnt_vnodelist, vp, v_mntvnodes); + vp->v_usecount = 1; + mutex_exit(&mntvnode_lock); + + *vipp = (struct vnode_iterator *)vp; +} + +void +vfs_vnode_iterator_destroy(struct vnode_iterator *vi) +{ + struct vnode *mvp = &vi->vi_vnode; + + mutex_enter(&mntvnode_lock); + KASSERT(ISSET(mvp->v_iflag, VI_MARKER)); + if (mvp->v_usecount != 0) + TAILQ_REMOVE(&mvp->v_mount->mnt_vnodelist, mvp, v_mntvnodes); + mutex_exit(&mntvnode_lock); + vnfree(mvp); +} + +bool +vfs_vnode_iterator_next(struct vnode_iterator *vi, struct vnode **vpp) +{ + struct vnode *mvp = &vi->vi_vnode; + struct mount *mp = mvp->v_mount; + struct vnode *vp; + int error; + + KASSERT(ISSET(mvp->v_iflag, VI_MARKER)); + + do { + mutex_enter(&mntvnode_lock); + vp = TAILQ_NEXT(mvp, v_mntvnodes); + TAILQ_REMOVE(&mp->mnt_vnodelist, mvp, v_mntvnodes); + mvp->v_usecount = 0; + if (vp == NULL) { + mutex_exit(&mntvnode_lock); + *vpp = NULL; + return false; + } + + mutex_enter(vp->v_interlock); + while ((vp->v_iflag & VI_MARKER) != 0) { + mutex_exit(vp->v_interlock); + vp = TAILQ_NEXT(vp, v_mntvnodes); + if (vp == NULL) { + mutex_exit(&mntvnode_lock); + *vpp = NULL; + return false; + } + mutex_enter(vp->v_interlock); + } + + TAILQ_INSERT_AFTER(&mp->mnt_vnodelist, vp, mvp, v_mntvnodes); + mvp->v_usecount = 1; + mutex_exit(&mntvnode_lock); + error = vget(vp, 0); + KASSERT(error == 0 || error == ENOENT); + } while (error != 0); + + *vpp = vp; + return true; +} + /* * Move a vnode from one mount queue to another. */ @@ -426,99 +502,78 @@ struct ctldebug debug1 = { "busyprt", &b #endif static vnode_t * -vflushnext(vnode_t *mvp, int *when) +vflushnext(struct vnode_iterator *marker, int *when) { + struct vnode *vp; if (hardclock_ticks > *when) { - mutex_exit(&mntvnode_lock); yield(); - mutex_enter(&mntvnode_lock); *when = hardclock_ticks + hz / 10; } - return vunmark(mvp); + if (vfs_vnode_iterator_next(marker, &vp)) + return vp; + return NULL; } int vflush(struct mount *mp, vnode_t *skipvp, int flags) { - vnode_t *vp, *mvp; + vnode_t *vp; + struct vnode_iterator *marker; int busy = 0, when = 0; /* First, flush out any vnode references from vrele_list. */ vrele_flush(); - /* Allocate a marker vnode. */ - mvp = vnalloc(mp); - - /* - * NOTE: not using the TAILQ_FOREACH here since in this loop vgone() - * and vclean() are called. - */ - mutex_enter(&mntvnode_lock); - for (vp = TAILQ_FIRST(&mp->mnt_vnodelist); - vp != NULL; - vp = vflushnext(mvp, &when)) { - vmark(mvp, vp); - if (vp->v_mount != mp || vismarker(vp)) - continue; + vfs_vnode_iterator_init(mp, &marker); + while ((vp = vflushnext(marker, &when)) != NULL) { /* * Skip over a selected vnode. */ - if (vp == skipvp) - continue; - /* - * First try to recycle the vnode. - */ - if (vrecycle(vp, &mntvnode_lock)) { - mutex_enter(&mntvnode_lock); - continue; - } - mutex_enter(vp->v_interlock); - /* - * Ignore clean but still referenced vnodes. - */ - if ((vp->v_iflag & VI_CLEAN) != 0) { - mutex_exit(vp->v_interlock); + if (vp == skipvp) { + vrele(vp); continue; } /* * Skip over a vnodes marked VSYSTEM. */ if ((flags & SKIPSYSTEM) && (vp->v_vflag & VV_SYSTEM)) { - mutex_exit(vp->v_interlock); + vrele(vp); continue; } /* * If WRITECLOSE is set, only flush out regular file * vnodes open for writing. */ - if ((flags & WRITECLOSE) && - (vp->v_writecount == 0 || vp->v_type != VREG)) { + if ((flags & WRITECLOSE) && vp->v_type == VREG) { + mutex_enter(vp->v_interlock); + if (vp->v_writecount == 0) { + mutex_exit(vp->v_interlock); + vrele(vp); + continue; + } mutex_exit(vp->v_interlock); - continue; } /* + * First try to recycle the vnode. + */ + if (vrecycle(vp)) + continue; + /* * If FORCECLOSE is set, forcibly close the vnode. - * For block or character devices, revert to an - * anonymous device. For all other files, just - * kill them. */ if (flags & FORCECLOSE) { - mutex_exit(&mntvnode_lock); - if (vget(vp, 0) == 0) - vgone(vp); - mutex_enter(&mntvnode_lock); + vgone(vp); continue; } #ifdef DEBUG if (busyprt) vprint("vflush: busy vnode", vp); #endif - mutex_exit(vp->v_interlock); + vrele(vp); busy++; } - mutex_exit(&mntvnode_lock); - vnfree(mvp); + vfs_vnode_iterator_destroy(marker); if (busy) return (EBUSY); return (0); Index: src/sys/kern/vfs_vnode.c diff -u src/sys/kern/vfs_vnode.c:1.32 src/sys/kern/vfs_vnode.c:1.33 --- src/sys/kern/vfs_vnode.c:1.32 Thu Feb 27 16:51:38 2014 +++ src/sys/kern/vfs_vnode.c Wed Mar 5 09:37:29 2014 @@ -1,4 +1,4 @@ -/* $NetBSD: vfs_vnode.c,v 1.32 2014/02/27 16:51:38 hannken Exp $ */ +/* $NetBSD: vfs_vnode.c,v 1.33 2014/03/05 09:37:29 hannken Exp $ */ /*- * Copyright (c) 1997-2011 The NetBSD Foundation, Inc. @@ -116,7 +116,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: vfs_vnode.c,v 1.32 2014/02/27 16:51:38 hannken Exp $"); +__KERNEL_RCSID(0, "$NetBSD: vfs_vnode.c,v 1.33 2014/03/05 09:37:29 hannken Exp $"); #define _VFS_VNODE_PRIVATE @@ -1029,30 +1029,33 @@ vclean(vnode_t *vp) } /* - * Recycle an unused vnode to the front of the free list. - * Release the passed interlock if the vnode will be recycled. + * Recycle an unused vnode if caller holds the last reference. */ -int -vrecycle(vnode_t *vp, kmutex_t *inter_lkp) +bool +vrecycle(vnode_t *vp) { + mutex_enter(vp->v_interlock); + KASSERT((vp->v_iflag & VI_MARKER) == 0); - mutex_enter(vp->v_interlock); - if (vp->v_usecount != 0 || (vp->v_iflag & (VI_CLEAN|VI_XLOCK)) != 0) { + if (vp->v_usecount != 1) { mutex_exit(vp->v_interlock); - return 0; + return false; } - if (inter_lkp) { - mutex_exit(inter_lkp); + if ((vp->v_iflag & VI_CHANGING) != 0) + vwait(vp, VI_CHANGING); + if (vp->v_usecount != 1) { + mutex_exit(vp->v_interlock); + return false; + } else if ((vp->v_iflag & VI_CLEAN) != 0) { + mutex_exit(vp->v_interlock); + return true; } - vremfree(vp); - vp->v_usecount = 1; - KASSERT((vp->v_iflag & VI_CHANGING) == 0); vp->v_iflag |= VI_CHANGING; vclean(vp); vrelel(vp, VRELEL_CHANGING_SET); - return 1; + return true; } /* Index: src/sys/sys/mount.h diff -u src/sys/sys/mount.h:1.211 src/sys/sys/mount.h:1.212 --- src/sys/sys/mount.h:1.211 Thu Feb 27 13:00:06 2014 +++ src/sys/sys/mount.h Wed Mar 5 09:37:29 2014 @@ -1,4 +1,4 @@ -/* $NetBSD: mount.h,v 1.211 2014/02/27 13:00:06 hannken Exp $ */ +/* $NetBSD: mount.h,v 1.212 2014/03/05 09:37:29 hannken Exp $ */ /* * Copyright (c) 1989, 1991, 1993 @@ -433,6 +433,11 @@ int vfs_quotactl_cursorrewind(struct mou int vfs_quotactl_quotaon(struct mount *, int, const char *); int vfs_quotactl_quotaoff(struct mount *, int); +struct vnode_iterator; /* Opaque. */ +void vfs_vnode_iterator_init(struct mount *, struct vnode_iterator **); +void vfs_vnode_iterator_destroy(struct vnode_iterator *); +bool vfs_vnode_iterator_next(struct vnode_iterator *, struct vnode **); + extern TAILQ_HEAD(mntlist, mount) mountlist; /* mounted filesystem list */ extern struct vfsops *vfssw[]; /* filesystem type table */ extern int nvfssw; Index: src/sys/sys/param.h diff -u src/sys/sys/param.h:1.442 src/sys/sys/param.h:1.443 --- src/sys/sys/param.h:1.442 Thu Feb 27 16:51:39 2014 +++ src/sys/sys/param.h Wed Mar 5 09:37:29 2014 @@ -1,4 +1,4 @@ -/* $NetBSD: param.h,v 1.442 2014/02/27 16:51:39 hannken Exp $ */ +/* $NetBSD: param.h,v 1.443 2014/03/05 09:37:29 hannken Exp $ */ /*- * Copyright (c) 1982, 1986, 1989, 1993 @@ -63,7 +63,7 @@ * 2.99.9 (299000900) */ -#define __NetBSD_Version__ 699003300 /* NetBSD 6.99.33 */ +#define __NetBSD_Version__ 699003400 /* NetBSD 6.99.34 */ #define __NetBSD_Prereq__(M,m,p) (((((M) * 100000000) + \ (m) * 1000000) + (p) * 100) <= __NetBSD_Version__) Index: src/sys/sys/vnode.h diff -u src/sys/sys/vnode.h:1.243 src/sys/sys/vnode.h:1.244 --- src/sys/sys/vnode.h:1.243 Sun Dec 1 17:29:40 2013 +++ src/sys/sys/vnode.h Wed Mar 5 09:37:29 2014 @@ -1,4 +1,4 @@ -/* $NetBSD: vnode.h,v 1.243 2013/12/01 17:29:40 christos Exp $ */ +/* $NetBSD: vnode.h,v 1.244 2014/03/05 09:37:29 hannken Exp $ */ /*- * Copyright (c) 2008 The NetBSD Foundation, Inc. @@ -545,7 +545,7 @@ void vgone(struct vnode *); int vinvalbuf(struct vnode *, int, kauth_cred_t, struct lwp *, bool, int); void vprint(const char *, struct vnode *); void vput(struct vnode *); -int vrecycle(struct vnode *, kmutex_t *); +bool vrecycle(struct vnode *); void vrele(struct vnode *); void vrele_async(struct vnode *); void vrele_flush(void); Index: src/sys/ufs/ext2fs/ext2fs_vfsops.c diff -u src/sys/ufs/ext2fs/ext2fs_vfsops.c:1.176 src/sys/ufs/ext2fs/ext2fs_vfsops.c:1.177 --- src/sys/ufs/ext2fs/ext2fs_vfsops.c:1.176 Tue Feb 25 18:30:13 2014 +++ src/sys/ufs/ext2fs/ext2fs_vfsops.c Wed Mar 5 09:37:29 2014 @@ -1,4 +1,4 @@ -/* $NetBSD: ext2fs_vfsops.c,v 1.176 2014/02/25 18:30:13 pooka Exp $ */ +/* $NetBSD: ext2fs_vfsops.c,v 1.177 2014/03/05 09:37:29 hannken Exp $ */ /* * Copyright (c) 1989, 1991, 1993, 1994 @@ -60,7 +60,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: ext2fs_vfsops.c,v 1.176 2014/02/25 18:30:13 pooka Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ext2fs_vfsops.c,v 1.177 2014/03/05 09:37:29 hannken Exp $"); #if defined(_KERNEL_OPT) #include "opt_compat_netbsd.h" @@ -512,7 +512,7 @@ fail: int ext2fs_reload(struct mount *mp, kauth_cred_t cred, struct lwp *l) { - struct vnode *vp, *mvp, *devvp; + struct vnode *vp, *devvp; struct inode *ip; struct buf *bp; struct m_ext2fs *fs; @@ -520,6 +520,7 @@ ext2fs_reload(struct mount *mp, kauth_cr int i, error; void *cp; struct ufsmount *ump; + struct vnode_iterator *marker; if ((mp->mnt_flag & MNT_RDONLY) == 0) return (EINVAL); @@ -585,35 +586,19 @@ ext2fs_reload(struct mount *mp, kauth_cr brelse(bp, 0); } - /* Allocate a marker vnode. */ - mvp = vnalloc(mp); - /* - * NOTE: not using the TAILQ_FOREACH here since in this loop vgone() - * and vclean() can be called indirectly - */ - mutex_enter(&mntvnode_lock); -loop: - for (vp = TAILQ_FIRST(&mp->mnt_vnodelist); vp; vp = vunmark(mvp)) { - vmark(mvp, vp); - if (vp->v_mount != mp || vismarker(vp)) - continue; + vfs_vnode_iterator_init(mp, &marker); + while (vfs_vnode_iterator_next(marker, &vp)) { /* * Step 4: invalidate all inactive vnodes. */ - if (vrecycle(vp, &mntvnode_lock)) { - mutex_enter(&mntvnode_lock); - (void)vunmark(mvp); - goto loop; - } + if (vrecycle(vp)) + continue; /* * Step 5: invalidate all cached file data. */ - mutex_enter(vp->v_interlock); - mutex_exit(&mntvnode_lock); - if (vget(vp, LK_EXCLUSIVE)) { - mutex_enter(&mntvnode_lock); - (void)vunmark(mvp); - goto loop; + if (vn_lock(vp, LK_EXCLUSIVE)) { + vrele(vp); + continue; } if (vinvalbuf(vp, 0, cred, l, 0, 0)) panic("ext2fs_reload: dirty2"); @@ -625,8 +610,6 @@ loop: (int)fs->e2fs_bsize, NOCRED, 0, &bp); if (error) { vput(vp); - mutex_enter(&mntvnode_lock); - (void)vunmark(mvp); break; } cp = (char *)bp->b_data + @@ -635,10 +618,8 @@ loop: ext2fs_set_inode_guid(ip); brelse(bp, 0); vput(vp); - mutex_enter(&mntvnode_lock); } - mutex_exit(&mntvnode_lock); - vnfree(mvp); + vfs_vnode_iterator_destroy(marker); return (error); } Index: src/sys/ufs/ffs/ffs_vfsops.c diff -u src/sys/ufs/ffs/ffs_vfsops.c:1.292 src/sys/ufs/ffs/ffs_vfsops.c:1.293 --- src/sys/ufs/ffs/ffs_vfsops.c:1.292 Tue Feb 25 18:30:13 2014 +++ src/sys/ufs/ffs/ffs_vfsops.c Wed Mar 5 09:37:29 2014 @@ -1,4 +1,4 @@ -/* $NetBSD: ffs_vfsops.c,v 1.292 2014/02/25 18:30:13 pooka Exp $ */ +/* $NetBSD: ffs_vfsops.c,v 1.293 2014/03/05 09:37:29 hannken Exp $ */ /*- * Copyright (c) 2008, 2009 The NetBSD Foundation, Inc. @@ -61,7 +61,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: ffs_vfsops.c,v 1.292 2014/02/25 18:30:13 pooka Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ffs_vfsops.c,v 1.293 2014/03/05 09:37:29 hannken Exp $"); #if defined(_KERNEL_OPT) #include "opt_ffs.h" @@ -636,7 +636,7 @@ fail: int ffs_reload(struct mount *mp, kauth_cred_t cred, struct lwp *l) { - struct vnode *vp, *mvp, *devvp; + struct vnode *vp, *devvp; struct inode *ip; void *space; struct buf *bp; @@ -646,6 +646,7 @@ ffs_reload(struct mount *mp, kauth_cred_ int32_t *lp; struct ufsmount *ump; daddr_t sblockloc; + struct vnode_iterator *marker; if ((mp->mnt_flag & MNT_RDONLY) == 0) return (EINVAL); @@ -805,34 +806,19 @@ ffs_reload(struct mount *mp, kauth_cred_ *lp++ = fs->fs_contigsumsize; } - /* Allocate a marker vnode. */ - mvp = vnalloc(mp); - /* - * NOTE: not using the TAILQ_FOREACH here since in this loop vgone() - * and vclean() can be called indirectly - */ - mutex_enter(&mntvnode_lock); - loop: - for (vp = TAILQ_FIRST(&mp->mnt_vnodelist); vp; vp = vunmark(mvp)) { - vmark(mvp, vp); - if (vp->v_mount != mp || vismarker(vp)) - continue; + vfs_vnode_iterator_init(mp, &marker); + while (vfs_vnode_iterator_next(marker, &vp)) { /* * Step 4: invalidate all inactive vnodes. */ - if (vrecycle(vp, &mntvnode_lock)) { - mutex_enter(&mntvnode_lock); - (void)vunmark(mvp); - goto loop; - } + if (vrecycle(vp)) + continue; /* * Step 5: invalidate all cached file data. */ - mutex_enter(vp->v_interlock); - mutex_exit(&mntvnode_lock); - if (vget(vp, LK_EXCLUSIVE)) { - (void)vunmark(mvp); - goto loop; + if (vn_lock(vp, LK_EXCLUSIVE)) { + vrele(vp); + continue; } if (vinvalbuf(vp, 0, cred, l, 0, 0)) panic("ffs_reload: dirty2"); @@ -844,16 +830,13 @@ ffs_reload(struct mount *mp, kauth_cred_ (int)fs->fs_bsize, NOCRED, 0, &bp); if (error) { vput(vp); - (void)vunmark(mvp); break; } ffs_load_inode(bp, ip, fs, ip->i_number); brelse(bp, 0); vput(vp); - mutex_enter(&mntvnode_lock); } - mutex_exit(&mntvnode_lock); - vnfree(mvp); + vfs_vnode_iterator_destroy(marker); return (error); } Index: src/sys/ufs/lfs/lfs_syscalls.c diff -u src/sys/ufs/lfs/lfs_syscalls.c:1.150 src/sys/ufs/lfs/lfs_syscalls.c:1.151 --- src/sys/ufs/lfs/lfs_syscalls.c:1.150 Tue Oct 29 09:53:51 2013 +++ src/sys/ufs/lfs/lfs_syscalls.c Wed Mar 5 09:37:29 2014 @@ -1,4 +1,4 @@ -/* $NetBSD: lfs_syscalls.c,v 1.150 2013/10/29 09:53:51 hannken Exp $ */ +/* $NetBSD: lfs_syscalls.c,v 1.151 2014/03/05 09:37:29 hannken Exp $ */ /*- * Copyright (c) 1999, 2000, 2001, 2002, 2003, 2007, 2007, 2008 @@ -61,7 +61,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: lfs_syscalls.c,v 1.150 2013/10/29 09:53:51 hannken Exp $"); +__KERNEL_RCSID(0, "$NetBSD: lfs_syscalls.c,v 1.151 2014/03/05 09:37:29 hannken Exp $"); #ifndef LFS # define LFS /* for prototypes in syscallargs.h */ @@ -712,8 +712,13 @@ lfs_bmapv(struct proc *p, fsid_t *fsidp, */ if (v_daddr != LFS_UNUSED_DADDR) { lfs_vunref(vp); - if (VTOI(vp)->i_lfs_iflags & LFSI_BMAP) - vrecycle(vp, NULL); + if (VTOI(vp)->i_lfs_iflags & LFSI_BMAP) { + mutex_enter(vp->v_interlock); + if (vget(vp, LK_NOWAIT) == 0) { + if (! vrecycle(vp)) + vrele(vp); + } + } numrefed--; } @@ -822,8 +827,13 @@ lfs_bmapv(struct proc *p, fsid_t *fsidp, if (v_daddr != LFS_UNUSED_DADDR) { lfs_vunref(vp); /* Recycle as above. */ - if (ip->i_lfs_iflags & LFSI_BMAP) - vrecycle(vp, NULL); + if (ip->i_lfs_iflags & LFSI_BMAP) { + mutex_enter(vp->v_interlock); + if (vget(vp, LK_NOWAIT) == 0) { + if (! vrecycle(vp)) + vrele(vp); + } + } numrefed--; }