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/ufs/ffs/ffs_vfsops.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/ufs/ffs/ffs_vfsops.c')
-rw-r--r-- | sys/ufs/ffs/ffs_vfsops.c | 55 |
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) |