diff options
author | tegge <tegge@FreeBSD.org> | 2006-03-08 23:43:39 +0000 |
---|---|---|
committer | tegge <tegge@FreeBSD.org> | 2006-03-08 23:43:39 +0000 |
commit | 2e0e03c06ff6c78e7d6f269c98e20d8e2eeb58dc (patch) | |
tree | 8446efea303e7dd86046218298bbbd2e8b1e8a1b /sys/kern/vfs_vnops.c | |
parent | b33c92af90c5ffdd40c36b6a8094d3ae01b92331 (diff) | |
download | FreeBSD-src-2e0e03c06ff6c78e7d6f269c98e20d8e2eeb58dc.zip FreeBSD-src-2e0e03c06ff6c78e7d6f269c98e20d8e2eeb58dc.tar.gz |
Use vn_start_secondary_write() and vn_finished_secondary_write() as a
replacement for vn_write_suspend_wait() to better account for secondary write
processing.
Close race where secondary writes could be started after ffs_sync() returned
but before the file system was marked as suspended.
Detect if secondary writes or softdep processing occurred during vnode sync
loop in ffs_sync() and retry the loop if needed.
Diffstat (limited to 'sys/kern/vfs_vnops.c')
-rw-r--r-- | sys/kern/vfs_vnops.c | 79 |
1 files changed, 77 insertions, 2 deletions
diff --git a/sys/kern/vfs_vnops.c b/sys/kern/vfs_vnops.c index fda74f1..79a233d 100644 --- a/sys/kern/vfs_vnops.c +++ b/sys/kern/vfs_vnops.c @@ -951,6 +951,58 @@ vn_write_suspend_wait(vp, mp, flags) } /* + * Secondary suspension. Used by operations such as vop_inactive + * routines that are needed by the higher level functions. These + * are allowed to proceed until all the higher level functions have + * completed (indicated by mnt_writeopcount dropping to zero). At that + * time, these operations are halted until the suspension is over. + */ +int +vn_start_secondary_write(vp, mpp, flags) + struct vnode *vp; + struct mount **mpp; + int flags; +{ + struct mount *mp; + int error; + + retry: + if (vp != NULL) { + if ((error = VOP_GETWRITEMOUNT(vp, mpp)) != 0) { + *mpp = NULL; + if (error != EOPNOTSUPP) + return (error); + return (0); + } + } + /* + * If we are not suspended or have not yet reached suspended + * mode, then let the operation proceed. + */ + if ((mp = *mpp) == NULL) + return (0); + MNT_ILOCK(mp); + if ((mp->mnt_kern_flag & MNTK_SUSPENDED) == 0) { + mp->mnt_secondary_writes++; + mp->mnt_secondary_accwrites++; + MNT_IUNLOCK(mp); + return (0); + } + if (flags & V_NOWAIT) { + MNT_IUNLOCK(mp); + return (EWOULDBLOCK); + } + /* + * Wait for the suspension to finish. + */ + error = msleep(&mp->mnt_flag, MNT_MTX(mp), + (PUSER - 1) | (flags & PCATCH) | PDROP, "suspfs", 0); + if (error == 0) + goto retry; + return (error); +} + +/* * Filesystem write operation has completed. If we are suspending and this * operation is the last one, notify the suspender that the suspension is * now in effect. @@ -971,6 +1023,30 @@ vn_finished_write(mp) MNT_IUNLOCK(mp); } + +/* + * Filesystem secondary write operation has completed. If we are + * suspending and this operation is the last one, notify the suspender + * that the suspension is now in effect. + */ +void +vn_finished_secondary_write(mp) + struct mount *mp; +{ + if (mp == NULL) + return; + MNT_ILOCK(mp); + mp->mnt_secondary_writes--; + if (mp->mnt_secondary_writes < 0) + panic("vn_finished_secondary_write: neg cnt"); + if ((mp->mnt_kern_flag & MNTK_SUSPEND) != 0 && + mp->mnt_secondary_writes <= 0) + wakeup(&mp->mnt_secondary_writes); + MNT_IUNLOCK(mp); +} + + + /* * Request a filesystem to suspend write operations. */ @@ -991,12 +1067,11 @@ vfs_write_suspend(mp) MNT_MTX(mp), (PUSER - 1)|PDROP, "suspwt", 0); else MNT_IUNLOCK(mp); - if ((error = VFS_SYNC(mp, MNT_WAIT, td)) != 0) { + if ((error = VFS_SYNC(mp, MNT_SUSPEND, td)) != 0) { vfs_write_resume(mp); return (error); } MNT_ILOCK(mp); - mp->mnt_kern_flag |= MNTK_SUSPENDED; unlock: MNT_IUNLOCK(mp); return (error); |