diff options
author | Kirk McKusick <mckusick@FreeBSD.org> | 2000-07-11 22:07:57 +0000 |
---|---|---|
committer | Kirk McKusick <mckusick@FreeBSD.org> | 2000-07-11 22:07:57 +0000 |
commit | f2a2857bb34f5525f21ad016c25b20348d7a1fab (patch) | |
tree | ca1f94a427c4ab94cb5de2c2a7b557655d1a6376 /sys/kern/vfs_subr.c | |
parent | aa02fb5729dd652fa1da3f9e8e1152cca9010a1c (diff) | |
download | src-f2a2857bb34f5525f21ad016c25b20348d7a1fab.tar.gz src-f2a2857bb34f5525f21ad016c25b20348d7a1fab.zip |
Add snapshots to the fast filesystem. Most of the changes support
the gating of system calls that cause modifications to the underlying
filesystem. The gating can be enabled by any filesystem that needs
to consistently suspend operations by adding the vop_stdgetwritemount
to their set of vnops. Once gating is enabled, the function
vfs_write_suspend stops all new write operations to a filesystem,
allows any filesystem modifying system calls already in progress
to complete, then sync's the filesystem to disk and returns. The
function vfs_write_resume allows the suspended write operations to
begin again. Gating is not added by default for all filesystems as
for SMP systems it adds two extra locks to such critical kernel
paths as the write system call. Thus, gating should only be added
as needed.
Details on the use and current status of snapshots in FFS can be
found in /sys/ufs/ffs/README.snapshot so for brevity and timelyness
is not included here. Unless and until you create a snapshot file,
these changes should have no effect on your system (famous last words).
Notes
Notes:
svn path=/head/; revision=62976
Diffstat (limited to 'sys/kern/vfs_subr.c')
-rw-r--r-- | sys/kern/vfs_subr.c | 29 |
1 files changed, 26 insertions, 3 deletions
diff --git a/sys/kern/vfs_subr.c b/sys/kern/vfs_subr.c index 648366009d8c..0e5ec3f30304 100644 --- a/sys/kern/vfs_subr.c +++ b/sys/kern/vfs_subr.c @@ -453,6 +453,7 @@ getnewvnode(tag, mp, vops, vpp) int s, count; struct proc *p = curproc; /* XXX */ struct vnode *vp = NULL; + struct mount *vnmp; vm_object_t object; /* @@ -491,7 +492,14 @@ getnewvnode(tag, mp, vops, vpp) vp = NULL; continue; } - break; + /* + * Skip over it if its filesystem is being suspended. + */ + if (vn_start_write(vp, &vnmp, V_NOWAIT) == 0) + break; + simple_unlock(&vp->v_interlock); + TAILQ_INSERT_TAIL(&vnode_free_list, vp, v_freelist); + vp = NULL; } if (vp) { vp->v_flag |= VDOOMED; @@ -504,6 +512,7 @@ getnewvnode(tag, mp, vops, vpp) } else { simple_unlock(&vp->v_interlock); } + vn_finished_write(vnmp); #ifdef INVARIANTS { @@ -515,6 +524,8 @@ getnewvnode(tag, mp, vops, vpp) if (vp->v_numoutput) panic("Clean vnode has pending I/O's"); splx(s); + if (vp->v_writecount != 0) + panic("Non-zero write count"); } #endif vp->v_flag = 0; @@ -523,7 +534,6 @@ getnewvnode(tag, mp, vops, vpp) vp->v_cstart = 0; vp->v_clen = 0; vp->v_socket = 0; - vp->v_writecount = 0; /* XXX */ } else { simple_unlock(&vnode_free_list_slock); vp = (struct vnode *) zalloc(vnode_zone); @@ -946,6 +956,7 @@ sched_sync(void) { struct synclist *slp; struct vnode *vp; + struct mount *mp; long starttime; int s; struct proc *p = updateproc; @@ -970,10 +981,12 @@ sched_sync(void) splx(s); while ((vp = LIST_FIRST(slp)) != NULL) { - if (VOP_ISLOCKED(vp, NULL) == 0) { + if (VOP_ISLOCKED(vp, NULL) == 0 && + vn_start_write(vp, &mp, V_NOWAIT) == 0) { vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); (void) VOP_FSYNC(vp, p->p_ucred, MNT_LAZY, p); VOP_UNLOCK(vp, 0, p); + vn_finished_write(mp); } s = splbio(); if (LIST_FIRST(slp) == vp) { @@ -1386,6 +1399,7 @@ vrele(vp) struct proc *p = curproc; /* XXX */ KASSERT(vp != NULL, ("vrele: null vp")); + KASSERT(vp->v_writecount < vp->v_usecount, ("vrele: missed vn_close")); simple_lock(&vp->v_interlock); @@ -1427,6 +1441,7 @@ vput(vp) struct proc *p = curproc; /* XXX */ KASSERT(vp != NULL, ("vput: null vp")); + KASSERT(vp->v_writecount < vp->v_usecount, ("vput: missed vn_close")); simple_lock(&vp->v_interlock); @@ -1632,6 +1647,8 @@ vclean(vp, flags, p) * If the flush fails, just toss the buffers. */ if (flags & DOCLOSE) { + if (TAILQ_FIRST(&vp->v_dirtyblkhd) != NULL) + (void) vn_write_suspend_wait(vp, V_WAIT); if (vinvalbuf(vp, V_SAVE, NOCRED, p, 0, 0) != 0) vinvalbuf(vp, 0, NOCRED, p, 0, 0); } @@ -2785,12 +2802,18 @@ sync_fsync(ap) simple_unlock(&mountlist_slock); return (0); } + if (vn_start_write(NULL, &mp, V_NOWAIT) != 0) { + vfs_unbusy(mp, p); + simple_unlock(&mountlist_slock); + return (0); + } asyncflag = mp->mnt_flag & MNT_ASYNC; mp->mnt_flag &= ~MNT_ASYNC; vfs_msync(mp, MNT_NOWAIT); VFS_SYNC(mp, MNT_LAZY, ap->a_cred, p); if (asyncflag) mp->mnt_flag |= MNT_ASYNC; + vn_finished_write(mp); vfs_unbusy(mp, p); return (0); } |