summaryrefslogtreecommitdiffstats
path: root/sys/ufs/ffs/ffs_vfsops.c
diff options
context:
space:
mode:
authortegge <tegge@FreeBSD.org>2006-03-08 23:43:39 +0000
committertegge <tegge@FreeBSD.org>2006-03-08 23:43:39 +0000
commit2e0e03c06ff6c78e7d6f269c98e20d8e2eeb58dc (patch)
tree8446efea303e7dd86046218298bbbd2e8b1e8a1b /sys/ufs/ffs/ffs_vfsops.c
parentb33c92af90c5ffdd40c36b6a8094d3ae01b92331 (diff)
downloadFreeBSD-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/ufs/ffs/ffs_vfsops.c')
-rw-r--r--sys/ufs/ffs/ffs_vfsops.c55
1 files changed, 48 insertions, 7 deletions
diff --git a/sys/ufs/ffs/ffs_vfsops.c b/sys/ufs/ffs/ffs_vfsops.c
index c6c6510..f4245db 100644
--- a/sys/ufs/ffs/ffs_vfsops.c
+++ b/sys/ufs/ffs/ffs_vfsops.c
@@ -70,7 +70,7 @@ __FBSDID("$FreeBSD$");
static uma_zone_t uma_inode, uma_ufs1, uma_ufs2;
-static int ffs_sbupdate(struct ufsmount *, int);
+static int ffs_sbupdate(struct ufsmount *, int, int);
static int ffs_reload(struct mount *, struct thread *);
static int ffs_mountfs(struct vnode *, struct mount *, struct thread *);
static void ffs_oldfscompat_read(struct fs *, struct ufsmount *,
@@ -234,7 +234,7 @@ ffs_mount(struct mount *mp, struct thread *td)
}
if ((fs->fs_flags & (FS_UNCLEAN | FS_NEEDSFSCK)) == 0)
fs->fs_clean = 1;
- if ((error = ffs_sbupdate(ump, MNT_WAIT)) != 0) {
+ if ((error = ffs_sbupdate(ump, MNT_WAIT, 0)) != 0) {
fs->fs_ronly = 0;
fs->fs_clean = 0;
vn_finished_write(mp);
@@ -301,7 +301,7 @@ ffs_mount(struct mount *mp, struct thread *td)
fs->fs_ronly = 0;
mp->mnt_flag &= ~MNT_RDONLY;
fs->fs_clean = 0;
- if ((error = ffs_sbupdate(ump, MNT_WAIT)) != 0) {
+ if ((error = ffs_sbupdate(ump, MNT_WAIT, 0)) != 0) {
vn_finished_write(mp);
return (error);
}
@@ -806,7 +806,7 @@ ffs_mountfs(devvp, mp, td)
ffs_snapshot_mount(mp);
fs->fs_fmod = 1;
fs->fs_clean = 0;
- (void) ffs_sbupdate(ump, MNT_WAIT);
+ (void) ffs_sbupdate(ump, MNT_WAIT, 0);
}
/*
* Initialize filesystem stat information in mount struct.
@@ -988,7 +988,7 @@ ffs_unmount(mp, mntflags, td)
UFS_UNLOCK(ump);
if (fs->fs_ronly == 0) {
fs->fs_clean = fs->fs_flags & (FS_UNCLEAN|FS_NEEDSFSCK) ? 0 : 1;
- error = ffs_sbupdate(ump, MNT_WAIT);
+ error = ffs_sbupdate(ump, MNT_WAIT, 0);
if (error) {
fs->fs_clean = 0;
return (error);
@@ -1113,6 +1113,12 @@ ffs_sync(mp, waitfor, td)
struct ufsmount *ump = VFSTOUFS(mp);
struct fs *fs;
int error, count, wait, lockreq, allerror = 0;
+ int suspend;
+ int suspended;
+ int secondary_writes;
+ int secondary_accwrites;
+ int softdep_deps;
+ int softdep_accdeps;
struct bufobj *bo;
fs = ump->um_fs;
@@ -1124,14 +1130,30 @@ ffs_sync(mp, waitfor, td)
* Write back each (modified) inode.
*/
wait = 0;
+ suspend = 0;
+ suspended = 0;
lockreq = LK_EXCLUSIVE | LK_NOWAIT;
+ if (waitfor == MNT_SUSPEND) {
+ suspend = 1;
+ waitfor = MNT_WAIT;
+ }
if (waitfor == MNT_WAIT) {
wait = 1;
lockreq = LK_EXCLUSIVE;
}
lockreq |= LK_INTERLOCK | LK_SLEEPFAIL;
MNT_ILOCK(mp);
+ MNT_REF(mp);
loop:
+ /* Grab snapshot of secondary write counts */
+ secondary_writes = mp->mnt_secondary_writes;
+ secondary_accwrites = mp->mnt_secondary_accwrites;
+
+ /* Grab snapshot of softdep dependency counts */
+ MNT_IUNLOCK(mp);
+ softdep_get_depcounts(mp, &softdep_deps, &softdep_accdeps);
+ MNT_ILOCK(mp);
+
MNT_VNODE_FOREACH(vp, mp, mvp) {
/*
* Depend on the mntvnode_slock to keep things stable enough
@@ -1165,6 +1187,7 @@ loop:
vput(vp);
MNT_ILOCK(mp);
}
+ MNT_REL(mp);
MNT_IUNLOCK(mp);
/*
* Force stale filesystem control information to be flushed.
@@ -1194,12 +1217,25 @@ loop:
MNT_ILOCK(mp);
goto loop;
}
+ } else if (suspend != 0) {
+ if (softdep_check_suspend(mp,
+ devvp,
+ softdep_deps,
+ softdep_accdeps,
+ secondary_writes,
+ secondary_accwrites) != 0)
+ goto loop; /* More work needed */
+ mtx_assert(MNT_MTX(mp), MA_OWNED);
+ mp->mnt_kern_flag |= MNTK_SUSPENDED;
+ MNT_IUNLOCK(mp);
+ suspended = 1;
} else
VI_UNLOCK(devvp);
/*
* Write back modified superblock.
*/
- if (fs->fs_fmod != 0 && (error = ffs_sbupdate(ump, waitfor)) != 0)
+ if (fs->fs_fmod != 0 &&
+ (error = ffs_sbupdate(ump, waitfor, suspended)) != 0)
allerror = error;
return (allerror);
}
@@ -1449,9 +1485,10 @@ ffs_uninit(vfsp)
* Write a superblock and associated information back to disk.
*/
static int
-ffs_sbupdate(mp, waitfor)
+ffs_sbupdate(mp, waitfor, suspended)
struct ufsmount *mp;
int waitfor;
+ int suspended;
{
struct fs *fs = mp->um_fs;
struct buf *sbbp;
@@ -1482,6 +1519,8 @@ ffs_sbupdate(mp, waitfor)
size, 0, 0, 0);
bcopy(space, bp->b_data, (u_int)size);
space = (char *)space + size;
+ if (suspended)
+ bp->b_flags |= B_VALIDSUSPWRT;
if (waitfor != MNT_WAIT)
bawrite(bp);
else if ((error = bwrite(bp)) != 0)
@@ -1513,6 +1552,8 @@ ffs_sbupdate(mp, waitfor)
fs->fs_time = time_second;
bcopy((caddr_t)fs, bp->b_data, (u_int)fs->fs_sbsize);
ffs_oldfscompat_write((struct fs *)bp->b_data, mp);
+ if (suspended)
+ bp->b_flags |= B_VALIDSUSPWRT;
if (waitfor != MNT_WAIT)
bawrite(bp);
else if ((error = bwrite(bp)) != 0)
OpenPOWER on IntegriCloud