diff options
author | tegge <tegge@FreeBSD.org> | 2006-03-11 01:08:37 +0000 |
---|---|---|
committer | tegge <tegge@FreeBSD.org> | 2006-03-11 01:08:37 +0000 |
commit | 69041c93c00904511474c4edc5cb7b7eb0c4f558 (patch) | |
tree | c9982c1b049f435cfe486a86b24a5c35e0589234 /sys/ufs | |
parent | dffb931651deee52af7d1976b0f14baf193bba39 (diff) | |
download | FreeBSD-src-69041c93c00904511474c4edc5cb7b7eb0c4f558.zip FreeBSD-src-69041c93c00904511474c4edc5cb7b7eb0c4f558.tar.gz |
Block secondary writes while expunging active unlinked files.
Fix detection of active unlinked files by checking VI_OWEINACT and
VI_DOINGINACT in addition to v_usecount.
Defer inactive handling for unlinked files if the file system is mostly
suspended (secondary writes being blocked).
Perform deferred inactive handling after the file system is resumed.
Diffstat (limited to 'sys/ufs')
-rw-r--r-- | sys/ufs/ffs/ffs_snapshot.c | 89 | ||||
-rw-r--r-- | sys/ufs/ffs/ffs_vfsops.c | 2 | ||||
-rw-r--r-- | sys/ufs/ufs/ufs_inode.c | 27 |
3 files changed, 115 insertions, 3 deletions
diff --git a/sys/ufs/ffs/ffs_snapshot.c b/sys/ufs/ffs/ffs_snapshot.c index fb69fc2..fcd713a 100644 --- a/sys/ufs/ffs/ffs_snapshot.c +++ b/sys/ufs/ffs/ffs_snapshot.c @@ -159,6 +159,7 @@ static int snapacct_ufs2(struct vnode *, ufs2_daddr_t *, ufs2_daddr_t *, static int mapacct_ufs2(struct vnode *, ufs2_daddr_t *, ufs2_daddr_t *, struct fs *, ufs_lbn_t, int); static int readblock(struct vnode *vp, struct buf *, ufs2_daddr_t); +static void process_deferred_inactive(struct mount *); /* * To ensure the consistency of snapshots across crashes, we must @@ -268,10 +269,12 @@ restart: } VOP_LEASE(nd.ni_dvp, td, KERNCRED, LEASE_WRITE); error = VOP_CREATE(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vat); + vhold(nd.ni_dvp); vput(nd.ni_dvp); if (error) { NDFREE(&nd, NDF_ONLY_PNBUF); vn_finished_write(wrtmp); + vdrop(nd.ni_dvp); return (error); } vp = nd.ni_vp; @@ -496,7 +499,9 @@ loop: VI_LOCK(xvp); MNT_IUNLOCK(mp); if ((xvp->v_iflag & VI_DOOMED) || - xvp->v_usecount == 0 || xvp->v_type == VNON || + (xvp->v_usecount == 0 && + (xvp->v_iflag & (VI_OWEINACT | VI_DOINGINACT)) == 0) || + xvp->v_type == VNON || (VTOI(xvp)->i_flags & SF_SNAPSHOT)) { VI_UNLOCK(xvp); MNT_ILOCK(mp); @@ -511,22 +516,36 @@ loop: MNT_ILOCK(mp); continue; } + vholdl(xvp); if (vn_lock(xvp, LK_EXCLUSIVE | LK_INTERLOCK, td) != 0) { MNT_ILOCK(mp); MNT_VNODE_FOREACH_ABORT_ILOCKED(mp, mvp); + vdrop(xvp); goto loop; } + VI_LOCK(xvp); + if (xvp->v_usecount == 0 && + (xvp->v_iflag & (VI_OWEINACT | VI_DOINGINACT)) == 0) { + VI_UNLOCK(xvp); + VOP_UNLOCK(xvp, 0, td); + vdrop(xvp); + MNT_ILOCK(mp); + continue; + } + VI_UNLOCK(xvp); if (snapdebug) vprint("ffs_snapshot: busy vnode", xvp); if (VOP_GETATTR(xvp, &vat, td->td_ucred, td) == 0 && vat.va_nlink > 0) { VOP_UNLOCK(xvp, 0, td); + vdrop(xvp); MNT_ILOCK(mp); continue; } xp = VTOI(xvp); if (ffs_checkfreefile(copy_fs, vp, xp->i_number)) { VOP_UNLOCK(xvp, 0, td); + vdrop(xvp); MNT_ILOCK(mp); continue; } @@ -557,6 +576,7 @@ loop: error = ffs_freefile(ump, copy_fs, vp, xp->i_number, xp->i_mode); VOP_UNLOCK(xvp, 0, td); + vdrop(xvp); if (error) { free(copy_fs->fs_csp, M_UFSMNT); bawrite(sbp); @@ -567,6 +587,7 @@ loop: MNT_ILOCK(mp); } MNT_IUNLOCK(mp); + vdrop(nd.ni_dvp); /* * If there already exist snapshots on this filesystem, grab a * reference to their shared lock. If this is the first snapshot @@ -783,6 +804,7 @@ out: else VOP_UNLOCK(vp, 0, td); vn_finished_write(wrtmp); + process_deferred_inactive(mp); return (error); } @@ -2237,4 +2259,69 @@ readblock(vp, bp, lbn) return (bp->b_error); } + +/* + * Process file deletes that were deferred by ufs_inactive() due to + * the file system being suspended. + */ +static void +process_deferred_inactive(struct mount *mp) +{ + struct vnode *vp, *mvp; + struct thread *td; + int error; + + td = curthread; + (void) vn_start_secondary_write(NULL, &mp, V_WAIT); + MNT_ILOCK(mp); + loop: + MNT_VNODE_FOREACH(vp, mp, mvp) { + VI_LOCK(vp); + if ((vp->v_iflag & (VI_DOOMED | VI_OWEINACT)) != VI_OWEINACT || + vp->v_usecount > 0 || + vp->v_type == VNON) { + VI_UNLOCK(vp); + continue; + } + MNT_IUNLOCK(mp); + vholdl(vp); + error = vn_lock(vp, LK_EXCLUSIVE | LK_INTERLOCK, td); + if (error != 0) { + vdrop(vp); + MNT_ILOCK(mp); + if (error == ENOENT) + continue; /* vnode recycled */ + MNT_VNODE_FOREACH_ABORT_ILOCKED(mp, mvp); + goto loop; + } + VI_LOCK(vp); + if ((vp->v_iflag & VI_OWEINACT) == 0) { + VI_UNLOCK(vp); + VOP_UNLOCK(vp, 0, td); + vdrop(vp); + MNT_ILOCK(mp); + continue; + } + + VNASSERT((vp->v_iflag & VI_DOINGINACT) == 0, vp, + ("process_deferred_inactive: " + "recursed on VI_DOINGINACT")); + vp->v_iflag |= VI_DOINGINACT; + vp->v_iflag &= ~VI_OWEINACT; + VI_UNLOCK(vp); + (void) VOP_INACTIVE(vp, td); + VI_LOCK(vp); + VNASSERT(vp->v_iflag & VI_DOINGINACT, vp, + ("process_deferred_inactive: lost VI_DOINGINACT")); + VNASSERT((vp->v_iflag & VI_OWEINACT) == 0, vp, + ("process_deferred_inactive: got VI_OWEINACT")); + vp->v_iflag &= ~VI_DOINGINACT; + VI_UNLOCK(vp); + VOP_UNLOCK(vp, 0, td); + vdrop(vp); + MNT_ILOCK(mp); + } + MNT_IUNLOCK(mp); + vn_finished_secondary_write(mp); +} #endif diff --git a/sys/ufs/ffs/ffs_vfsops.c b/sys/ufs/ffs/ffs_vfsops.c index edfc8eb..6ad9bc7 100644 --- a/sys/ufs/ffs/ffs_vfsops.c +++ b/sys/ufs/ffs/ffs_vfsops.c @@ -1224,7 +1224,7 @@ loop: secondary_accwrites) != 0) goto loop; /* More work needed */ mtx_assert(MNT_MTX(mp), MA_OWNED); - mp->mnt_kern_flag |= MNTK_SUSPENDED; + mp->mnt_kern_flag |= MNTK_SUSPEND2 | MNTK_SUSPENDED; MNT_IUNLOCK(mp); suspended = 1; } else diff --git a/sys/ufs/ufs/ufs_inode.c b/sys/ufs/ufs/ufs_inode.c index 091756c..b85c9a3 100644 --- a/sys/ufs/ufs/ufs_inode.c +++ b/sys/ufs/ufs/ufs_inode.c @@ -86,7 +86,32 @@ ufs_inactive(ap) if (ip->i_effnlink == 0 && DOINGSOFTDEP(vp)) softdep_releasefile(ip); if (ip->i_nlink <= 0 && (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) { - (void) vn_start_secondary_write(vp, &mp, V_WAIT); + loop: + if (vn_start_secondary_write(vp, &mp, V_NOWAIT) != 0) { + /* Cannot delete file while file system is suspended */ + if ((vp->v_iflag & VI_DOOMED) != 0) { + /* Cannot return before file is deleted */ + (void) vn_start_secondary_write(vp, &mp, + V_WAIT); + } else { + MNT_ILOCK(mp); + if ((mp->mnt_kern_flag & + (MNTK_SUSPEND2 | MNTK_SUSPENDED)) == 0) { + MNT_IUNLOCK(mp); + goto loop; + } + /* + * Fail to inactivate vnode now and + * let ffs_snapshot() clean up after + * it has resumed the file system. + */ + VI_LOCK(vp); + vp->v_iflag |= VI_OWEINACT; + VI_UNLOCK(vp); + MNT_IUNLOCK(mp); + return (0); + } + } #ifdef QUOTA if (!getinoquota(ip)) (void)chkiq(ip, -1, NOCRED, FORCE); |