Index: sys/sys/vnode.h =================================================================== RCS file: /cvsroot/src/sys/sys/vnode.h,v retrieving revision 1.245 diff -p -u -2 -r1.245 vnode.h --- sys/sys/vnode.h 18 Mar 2014 10:21:47 -0000 1.245 +++ sys/sys/vnode.h 21 Mar 2014 09:42:41 -0000 @@ -200,5 +200,7 @@ typedef struct vnode vnode_t; #define VI_WRMAP 0x00000400 /* might have PROT_WRITE u. mappings */ #define VI_WRMAPDIRTY 0x00000800 /* might have dirty pages */ +#ifdef _VFS_VNODE_PRIVATE #define VI_XLOCK 0x00001000 /* vnode is locked to change type */ +#endif /* _VFS_VNODE_PRIVATE */ #define VI_ONWORKLST 0x00004000 /* On syncer work-list */ #ifdef _VFS_VNODE_PRIVATE @@ -206,7 +208,7 @@ typedef struct vnode vnode_t; #endif /* _VFS_VNODE_PRIVATE */ #define VI_LAYER 0x00020000 /* vnode is on a layer filesystem */ +#ifdef _VFS_VNODE_PRIVATE #define VI_LOCKSHARE 0x00040000 /* v_interlock is shared */ #define VI_CLEAN 0x00080000 /* has been reclaimed */ -#ifdef _VFS_VNODE_PRIVATE #define VI_CHANGING 0x00100000 /* vnode changes state */ #endif /* _VFS_VNODE_PRIVATE */ @@ -547,4 +549,5 @@ void vrele_flush(void); int vtruncbuf(struct vnode *, daddr_t, bool, int); void vwakeup(struct buf *); +int vdead_check(struct vnode *, bool); void vwait(struct vnode *, int); void vrevoke(struct vnode *); Index: sys/kern/vfs_vnode.c =================================================================== RCS file: /cvsroot/src/sys/kern/vfs_vnode.c,v retrieving revision 1.34 diff -p -u -2 -r1.34 vfs_vnode.c --- sys/kern/vfs_vnode.c 17 Mar 2014 09:27:37 -0000 1.34 +++ sys/kern/vfs_vnode.c 21 Mar 2014 09:42:44 -0000 @@ -1141,4 +1141,29 @@ vwakeup(struct buf *bp) /* + * Test a vnode for being or becoming dead. Returns one of: + * EBUSY: vnode is becoming dead, with "may_sleep == false" only. + * ENOENT: vnode is dead. + * 0: otherwise. + * + * Whenever this function returns a non-zero value all future + * calls will also return a non-zero value. + */ +int +vdead_check(struct vnode *vp, bool may_sleep) +{ + + KASSERT(mutex_owned(vp->v_interlock)); + if (ISSET(vp->v_iflag, VI_XLOCK)) { + if (! may_sleep) + return EBUSY; + vwait(vp, VI_XLOCK); + KASSERT(ISSET(vp->v_iflag, VI_CLEAN)); + } + if (ISSET(vp->v_iflag, VI_CLEAN)) + return ENOENT; + return 0; +} + +/* * Wait for a vnode (typically with VI_XLOCK set) to be cleaned or * recycled. Index: sys/miscfs/genfs/genfs_vnops.c =================================================================== RCS file: /cvsroot/src/sys/miscfs/genfs/genfs_vnops.c,v retrieving revision 1.191 diff -p -u -2 -r1.191 genfs_vnops.c --- sys/miscfs/genfs/genfs_vnops.c 12 Mar 2014 09:38:51 -0000 1.191 +++ sys/miscfs/genfs/genfs_vnops.c 21 Mar 2014 09:42:48 -0000 @@ -298,10 +298,7 @@ genfs_deadlock(void *v) return EBUSY; if (mutex_tryenter(vp->v_interlock)) { - if (ISSET(vp->v_iflag, VI_XLOCK)) - error = EBUSY; - else { - KASSERT(ISSET(vp->v_iflag, VI_CLEAN)); - error = (ISSET(flags, LK_RETRY) ? 0 : ENOENT); - } + error = vdead_check(vp, false); + if (error == ENOENT && ISSET(flags, LK_RETRY)) + error = 0; mutex_exit(vp->v_interlock); } else @@ -314,12 +311,14 @@ genfs_deadlock(void *v) rw_enter(&vp->v_lock, op); mutex_enter(vp->v_interlock); - if (ISSET(vp->v_iflag, VI_XLOCK)) { + error = vdead_check(vp, false); + if (error == EBUSY) { rw_exit(&vp->v_lock); - vwait(vp, VI_XLOCK); + error = vdead_check(vp, true); + KASSERT(error == ENOENT); mutex_exit(vp->v_interlock); rw_enter(&vp->v_lock, op); mutex_enter(vp->v_interlock); } - KASSERT(ISSET(vp->v_iflag, VI_CLEAN)); + KASSERT(error == ENOENT); mutex_exit(vp->v_interlock); if (! ISSET(flags, LK_RETRY)) { @@ -371,10 +370,5 @@ genfs_lock(void *v) } if (mutex_tryenter(vp->v_interlock)) { - if (ISSET(vp->v_iflag, VI_XLOCK)) - error = EBUSY; - else if (ISSET(vp->v_iflag, VI_CLEAN)) - error = ENOENT; - else - error = 0; + error = vdead_check(vp, false); mutex_exit(vp->v_interlock); } else @@ -390,14 +384,13 @@ genfs_lock(void *v) rw_enter(&vp->v_lock, op); mutex_enter(vp->v_interlock); - if (ISSET(vp->v_iflag, VI_XLOCK) || ISSET(vp->v_iflag, VI_CLEAN)) { + error = vdead_check(vp, false); + if (error) { rw_exit(&vp->v_lock); fstrans_done(mp); - vwait(vp, VI_XLOCK); - KASSERT(ISSET(vp->v_iflag, VI_CLEAN)); - mutex_exit(vp->v_interlock); - return ENOENT; + error = vdead_check(vp, true); + KASSERT(error == ENOENT); } mutex_exit(vp->v_interlock); - return 0; + return error; } Index: sys/miscfs/genfs/layer_vnops.c =================================================================== RCS file: /cvsroot/src/sys/miscfs/genfs/layer_vnops.c,v retrieving revision 1.56 diff -p -u -2 -r1.56 layer_vnops.c --- sys/miscfs/genfs/layer_vnops.c 12 Mar 2014 09:39:23 -0000 1.56 +++ sys/miscfs/genfs/layer_vnops.c 21 Mar 2014 09:42:51 -0000 @@ -724,10 +724,5 @@ layer_lock(void *v) return error; if (mutex_tryenter(vp->v_interlock)) { - if (ISSET(vp->v_iflag, VI_XLOCK)) - error = EBUSY; - else if (ISSET(vp->v_iflag, VI_CLEAN)) - error = ENOENT; - else - error = 0; + error = vdead_check(vp, false); mutex_exit(vp->v_interlock); } else @@ -743,14 +738,13 @@ layer_lock(void *v) mutex_enter(vp->v_interlock); - if (ISSET(vp->v_iflag, VI_XLOCK) || ISSET(vp->v_iflag, VI_CLEAN)) { + error = vdead_check(vp, false); + if (error) { VOP_UNLOCK(lowervp); - vwait(vp, VI_XLOCK); - KASSERT(ISSET(vp->v_iflag, VI_CLEAN)); - mutex_exit(vp->v_interlock); - return ENOENT; + error = vdead_check(vp, true); + KASSERT(error == ENOENT); } mutex_exit(vp->v_interlock); - return 0; + return error; } Index: sys/miscfs/specfs/spec_vnops.c =================================================================== RCS file: /cvsroot/src/sys/miscfs/specfs/spec_vnops.c,v retrieving revision 1.142 diff -p -u -2 -r1.142 spec_vnops.c --- sys/miscfs/specfs/spec_vnops.c 7 Feb 2014 15:29:22 -0000 1.142 +++ sys/miscfs/specfs/spec_vnops.c 21 Mar 2014 09:42:55 -0000 @@ -289,5 +289,5 @@ spec_node_lookup_by_dev(enum vtype type, mutex_enter(vp->v_interlock); /* If clean or being cleaned, then ignore it. */ - if ((vp->v_iflag & (VI_CLEAN | VI_XLOCK)) == 0) + if (vdead_check(vp, false) == 0) break; mutex_exit(vp->v_interlock); @@ -393,5 +393,4 @@ spec_node_revoke(vnode_t *vp) KASSERT(vp->v_type == VBLK || vp->v_type == VCHR); KASSERT(vp->v_specnode != NULL); - KASSERT((vp->v_iflag & VI_XLOCK) != 0); KASSERT(sn->sn_gone == false); @@ -864,5 +863,5 @@ spec_ioctl(void *v) dev = NODEV; mutex_enter(vp->v_interlock); - if ((vp->v_iflag & VI_XLOCK) == 0 && vp->v_specnode) { + if (vdead_check(vp, false) == 0 && vp->v_specnode) { dev = vp->v_rdev; } @@ -908,5 +907,5 @@ spec_poll(void *v) dev = NODEV; mutex_enter(vp->v_interlock); - if ((vp->v_iflag & VI_XLOCK) == 0 && vp->v_specnode) { + if (vdead_check(vp, false) == 0 && vp->v_specnode) { dev = vp->v_rdev; } @@ -1083,11 +1082,19 @@ spec_close(void *v) struct session *sess; dev_t dev = vp->v_rdev; - int mode, error, flags, flags1, count; + int flags = ap->a_fflag; + int mode, error, count; specnode_t *sn; specdev_t *sd; - flags = vp->v_iflag; + mutex_enter(vp->v_interlock); sn = vp->v_specnode; sd = sn->sn_dev; + /* + * If we're going away soon, make this non-blocking. + * Also ensures that we won't wedge in vn_lock below. + */ + if (vdead_check(vp, false) != 0) + flags |= FNONBLOCK; + mutex_exit(vp->v_interlock); switch (vp->v_type) { @@ -1171,28 +1178,18 @@ spec_close(void *v) return 0; - flags1 = ap->a_fflag; - - /* - * if VI_XLOCK is set, then we're going away soon, so make this - * non-blocking. Also ensures that we won't wedge in vn_lock below. - */ - if (flags & VI_XLOCK) - flags1 |= FNONBLOCK; - /* * If we're able to block, release the vnode lock & reacquire. We * might end up sleeping for someone else who wants our queues. They - * won't get them if we hold the vnode locked. Also, if VI_XLOCK is - * set, don't release the lock as we won't be able to regain it. + * won't get them if we hold the vnode locked. */ - if (!(flags1 & FNONBLOCK)) + if (!(flags & FNONBLOCK)) VOP_UNLOCK(vp); if (vp->v_type == VBLK) - error = bdev_close(dev, flags1, mode, curlwp); + error = bdev_close(dev, flags, mode, curlwp); else - error = cdev_close(dev, flags1, mode, curlwp); + error = cdev_close(dev, flags, mode, curlwp); - if (!(flags1 & FNONBLOCK)) + if (!(flags & FNONBLOCK)) vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); Index: sys/fs/union/union_vnops.c =================================================================== RCS file: /cvsroot/src/sys/fs/union/union_vnops.c,v retrieving revision 1.58 diff -p -u -2 -r1.58 union_vnops.c --- sys/fs/union/union_vnops.c 12 Mar 2014 09:40:05 -0000 1.58 +++ sys/fs/union/union_vnops.c 21 Mar 2014 09:42:59 -0000 @@ -1637,10 +1637,5 @@ union_lock(void *v) return error; if (mutex_tryenter(vp->v_interlock)) { - if (ISSET(vp->v_iflag, VI_XLOCK)) - error = EBUSY; - else if (ISSET(vp->v_iflag, VI_CLEAN)) - error = ENOENT; - else - error = 0; + error = vdead_check(vp, false); mutex_exit(vp->v_interlock); } else @@ -1666,13 +1661,12 @@ union_lock(void *v) mutex_enter(vp->v_interlock); - if (ISSET(vp->v_iflag, VI_XLOCK) || ISSET(vp->v_iflag, VI_CLEAN)) { + error = vdead_check(vp, false); + if (error) { union_unlock1(vp, lockvp); - vwait(vp, VI_XLOCK); - KASSERT(ISSET(vp->v_iflag, VI_CLEAN)); - mutex_exit(vp->v_interlock); - return ENOENT; + error = vdead_check(vp, true); + KASSERT(error == ENOENT); } mutex_exit(vp->v_interlock); - return 0; + return error; } Index: sys/ufs/ffs/ffs_vnops.c =================================================================== RCS file: /cvsroot/src/sys/ufs/ffs/ffs_vnops.c,v retrieving revision 1.123 diff -p -u -2 -r1.123 ffs_vnops.c --- sys/ufs/ffs/ffs_vnops.c 23 Jun 2013 07:28:37 -0000 1.123 +++ sys/ufs/ffs/ffs_vnops.c 21 Mar 2014 09:43:02 -0000 @@ -561,5 +561,5 @@ ffs_reclaim(void *v) * The inode must be freed and updated before being removed * from its hash chain. Other threads trying to gain a hold - * on the inode will be stalled because it is locked (VI_XLOCK). + * or lock on the inode will be stalled. */ error = UFS_WAPBL_BEGIN(mp); Index: sys/ufs/ext2fs/ext2fs_vnops.c =================================================================== RCS file: /cvsroot/src/sys/ufs/ext2fs/ext2fs_vnops.c,v retrieving revision 1.110 diff -p -u -2 -r1.110 ext2fs_vnops.c --- sys/ufs/ext2fs/ext2fs_vnops.c 23 Jan 2014 10:13:57 -0000 1.110 +++ sys/ufs/ext2fs/ext2fs_vnops.c 21 Mar 2014 09:43:05 -0000 @@ -1117,5 +1117,5 @@ ext2fs_reclaim(void *v) * The inode must be freed and updated before being removed * from its hash chain. Other threads trying to gain a hold - * on the inode will be stalled because it is locked (VI_XLOCK). + * or lock on the inode will be stalled. */ if (ip->i_omode == 1 && (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) Index: sys/ufs/lfs/lfs_segment.c =================================================================== RCS file: /cvsroot/src/sys/ufs/lfs/lfs_segment.c,v retrieving revision 1.235 diff -p -u -2 -r1.235 lfs_segment.c --- sys/ufs/lfs/lfs_segment.c 18 Mar 2014 10:21:47 -0000 1.235 +++ sys/ufs/lfs/lfs_segment.c 21 Mar 2014 09:43:09 -0000 @@ -282,9 +282,10 @@ lfs_vflush(struct vnode *vp) cv_wait(&vp->v_cv, vp->v_interlock); } + error = vdead_check(vp, false); mutex_exit(vp->v_interlock); - /* Protect against VI_XLOCK deadlock in vinvalbuf() */ - lfs_seglock(fs, SEGM_SYNC | ((vp->v_iflag & VI_XLOCK) ? SEGM_RECLAIM : 0)); - if (vp->v_iflag & VI_XLOCK) { + /* Protect against deadlock in vinvalbuf() */ + lfs_seglock(fs, SEGM_SYNC | ((error != 0) ? SEGM_RECLAIM : 0)); + if (error != 0) { fs->lfs_reclino = ip->i_number; } @@ -512,5 +513,5 @@ lfs_writevnodes(struct lfs *fs, struct m mutex_enter(vp->v_interlock); if (vp->v_type == VNON || (vp->v_iflag & VI_MARKER) || - (vp->v_iflag & VI_CLEAN) != 0) { + vdead_check(vp, false) != 0) { mutex_exit(vp->v_interlock); continue; @@ -2756,5 +2757,5 @@ lfs_shellsort(struct buf **bp_array, int /* - * Call vget with LK_NOWAIT. If we are the one who holds VI_XLOCK, + * Call vget with LK_NOWAIT. If we are the one who is dead, * however, we must press on. Just fake success in that case. */ Index: sys/ufs/lfs/lfs_syscalls.c =================================================================== RCS file: /cvsroot/src/sys/ufs/lfs/lfs_syscalls.c,v retrieving revision 1.151 diff -p -u -2 -r1.151 lfs_syscalls.c --- sys/ufs/lfs/lfs_syscalls.c 5 Mar 2014 09:37:29 -0000 1.151 +++ sys/ufs/lfs/lfs_syscalls.c 21 Mar 2014 09:43:12 -0000 @@ -744,5 +744,5 @@ lfs_bmapv(struct proc *p, fsid_t *fsidp, mutex_enter(&ulfs_ihash_lock); vp = ulfs_ihashlookup(ump->um_dev, blkp->bi_inode); - if (vp != NULL && !(vp->v_iflag & VI_XLOCK)) { + if (vp != NULL && vdead_check(vp, false) == 0) { ip = VTOI(vp); mutex_enter(vp->v_interlock); @@ -1051,6 +1051,6 @@ lfs_fasthashget(dev_t dev, ino_t ino, st mutex_enter(vp->v_interlock); mutex_exit(&ulfs_ihash_lock); - if (vp->v_iflag & VI_XLOCK) { - DLOG((DLOG_CLEAN, "lfs_fastvget: ino %d VI_XLOCK\n", + if (vdead_check(vp, false) != 0) { + DLOG((DLOG_CLEAN, "lfs_fastvget: ino %d dead\n", ino)); lfs_stats.clean_vnlocked++; Index: sys/ufs/lfs/lfs_vfsops.c =================================================================== RCS file: /cvsroot/src/sys/ufs/lfs/lfs_vfsops.c,v retrieving revision 1.318 diff -p -u -2 -r1.318 lfs_vfsops.c --- sys/ufs/lfs/lfs_vfsops.c 25 Feb 2014 18:30:13 -0000 1.318 +++ sys/ufs/lfs/lfs_vfsops.c 21 Mar 2014 09:43:16 -0000 @@ -242,5 +242,5 @@ lfs_sysctl_setup(struct sysctllog **clog { "flush_invoked", "Number of times flush was invoked" }, { "vflush_invoked", "Number of time vflush was called" }, - { "clean_inlocked", "Number of vnodes skipped for VI_XLOCK" }, + { "clean_inlocked", "Number of vnodes skipped for being dead" }, { "clean_vnlocked", "Number of vnodes skipped for vget failure" }, { "segs_reclaimed", "Number of segments reclaimed" }, @@ -1758,8 +1758,11 @@ lfs_gop_write(struct vnode *vp, struct v * reclaimed. */ - if (LFS_STARVED_FOR_SEGS(fs) && !(vp->v_iflag & VI_XLOCK)) { + mutex_enter(vp->v_interlock); + if (LFS_STARVED_FOR_SEGS(fs) && vdead_check(vp, false) == 0) { + mutex_exit(vp->v_interlock); failreason = "Starved for segs and not flushing vp"; goto tryagain; } + mutex_exit(vp->v_interlock); /* Index: sys/ufs/lfs/lfs_vnops.c =================================================================== RCS file: /cvsroot/src/sys/ufs/lfs/lfs_vnops.c,v retrieving revision 1.261 diff -p -u -2 -r1.261 lfs_vnops.c --- sys/ufs/lfs/lfs_vnops.c 23 Jan 2014 10:13:57 -0000 1.261 +++ sys/ufs/lfs/lfs_vnops.c 21 Mar 2014 09:43:20 -0000 @@ -634,5 +634,5 @@ lfs_mknod(void *v) /* * Call fsync to write the vnode so that we don't have to deal with - * flushing it when it's marked VU_DIROP|VI_XLOCK. + * flushing it when it's marked VU_DIROP or reclaiming. * * XXX KS - If we can't flush we also can't call vgone(), so must @@ -985,5 +985,5 @@ lfs_reclaim(void *v) * The inode must be freed and updated before being removed * from its hash chain. Other threads trying to gain a hold - * on the inode will be stalled because it is locked (VI_XLOCK). + * or lock on the inode will be stalled. */ if (ip->i_nlink <= 0 && (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) @@ -1204,8 +1204,9 @@ lfs_flush_dirops(struct lfs *fs) mutex_exit(&lfs_lock); vp = ITOV(ip); + mutex_enter(vp->v_interlock); KASSERT((ip->i_flag & IN_ADIROP) == 0); KASSERT(vp->v_uflag & VU_DIROP); - KASSERT(!(vp->v_iflag & VI_XLOCK)); + KASSERT(vdead_check(vp, false) == 0); /* @@ -1217,8 +1218,10 @@ lfs_flush_dirops(struct lfs *fs) * really need to lock. */ - if (vp->v_iflag & VI_XLOCK) { + if (vdead_check(vp, false) != 0) { + mutex_exit(vp->v_interlock); mutex_enter(&lfs_lock); continue; } + mutex_exit(vp->v_interlock); /* XXX see below * waslocked = VOP_ISLOCKED(vp); @@ -1325,5 +1328,6 @@ lfs_flush_pchain(struct lfs *fs) mutex_enter(vp->v_interlock); - if ((vp->v_iflag & VI_XLOCK) || (vp->v_uflag & VU_DIROP) != 0) { + if (vdead_check(vp, false) != 0 || + (vp->v_uflag & VU_DIROP) != 0) { mutex_exit(vp->v_interlock); continue; @@ -2269,5 +2273,5 @@ lfs_putpages(void *v) /* Note segments written by reclaim; only for debugging */ - if ((vp->v_iflag & VI_XLOCK) != 0) { + if (vdead_check(vp, false) != 0) { sp->seg_flags |= SEGM_RECLAIM; fs->lfs_reclino = ip->i_number; Index: sys/fs/puffs/puffs_vnops.c =================================================================== RCS file: /cvsroot/src/sys/fs/puffs/puffs_vnops.c,v retrieving revision 1.180 diff -p -u -2 -r1.180 puffs_vnops.c --- sys/fs/puffs/puffs_vnops.c 7 Feb 2014 15:29:21 -0000 1.180 +++ sys/fs/puffs/puffs_vnops.c 21 Mar 2014 09:43:23 -0000 @@ -1693,5 +1693,5 @@ puffs_vnop_fsync(void *v) if (dofaf == 0) { mutex_enter(vp->v_interlock); - if (vp->v_iflag & VI_XLOCK) + if (vdead_check(vp, false) != 0) dofaf = 1; mutex_exit(vp->v_interlock); @@ -2602,5 +2602,5 @@ puffs_vnop_strategy(void *v) if (BUF_ISWRITE(bp)) { mutex_enter(vp->v_interlock); - if (vp->v_iflag & VI_XLOCK) + if (vdead_check(vp, false) != 0) dofaf = 1; if (pn->pn_stat & PNODE_FAF) Index: usr.sbin/pstat/pstat.8 =================================================================== RCS file: /cvsroot/src/usr.sbin/pstat/pstat.8,v retrieving revision 1.39 diff -p -u -2 -r1.39 pstat.8 --- usr.sbin/pstat/pstat.8 5 Dec 2009 20:11:18 -0000 1.39 +++ usr.sbin/pstat/pstat.8 21 Mar 2014 09:43:26 -0000 @@ -30,5 +30,5 @@ .\" from: @(#)pstat.8 8.5 (Berkeley) 5/13/94 .\" -.Dd December 5, 2009 +.Dd March 19, 2014 .Dt PSTAT 8 .Os @@ -271,12 +271,4 @@ VISTTY vnode is a tty. .It E VEXECMAP vnode has PROT_EXEC mappings. -.It L -VXLOCK locked to change underlying type. -.It W -VXWANT process is waiting for vnode. -.It B -VBWAIT waiting for output to complete. -.It A -VALIASED vnode has an alias. .It D VDIROP lfs vnode involved in directory op. Index: usr.sbin/pstat/pstat.c =================================================================== RCS file: /cvsroot/src/usr.sbin/pstat/pstat.c,v retrieving revision 1.122 diff -p -u -2 -r1.122 pstat.c --- usr.sbin/pstat/pstat.c 24 Nov 2013 13:13:12 -0000 1.122 +++ usr.sbin/pstat/pstat.c 21 Mar 2014 09:43:30 -0000 @@ -385,5 +385,4 @@ const struct flagbit_desc vnode_flags[] { VV_ISTTY, 'I' }, { VI_EXECMAP, 'E' }, - { VI_XLOCK, 'L' }, { VU_DIROP, 'D' }, { VI_LAYER, 'Y' },