summaryrefslogtreecommitdiffstats
path: root/sys/ufs/ffs
diff options
context:
space:
mode:
authorkib <kib@FreeBSD.org>2008-09-16 11:55:53 +0000
committerkib <kib@FreeBSD.org>2008-09-16 11:55:53 +0000
commit18a31165411408c2799cd8b270c2ede7b7811bba (patch)
tree4ed80a058f112fde0502406c612d91d93c98ed28 /sys/ufs/ffs
parentf6863a9ef79ec34cd371070704d592a2b5c019c1 (diff)
downloadFreeBSD-src-18a31165411408c2799cd8b270c2ede7b7811bba.zip
FreeBSD-src-18a31165411408c2799cd8b270c2ede7b7811bba.tar.gz
Suspend the write operations on the UFS filesystem being unmounted or
remounted from rw to ro. Proposed and reviewed by: tegge In collaboration with: pho MFC after: 1 month
Diffstat (limited to 'sys/ufs/ffs')
-rw-r--r--sys/ufs/ffs/ffs_vfsops.c87
1 files changed, 73 insertions, 14 deletions
diff --git a/sys/ufs/ffs/ffs_vfsops.c b/sys/ufs/ffs/ffs_vfsops.c
index 86b3f60..767ca49 100644
--- a/sys/ufs/ffs/ffs_vfsops.c
+++ b/sys/ufs/ffs/ffs_vfsops.c
@@ -189,14 +189,35 @@ ffs_mount(struct mount *mp, struct thread *td)
devvp = ump->um_devvp;
if (fs->fs_ronly == 0 &&
vfs_flagopt(mp->mnt_optnew, "ro", NULL, 0)) {
- if ((error = vn_start_write(NULL, &mp, V_WAIT)) != 0)
- return (error);
/*
- * Flush any dirty data.
+ * Flush any dirty data and suspend filesystem.
*/
- if ((error = ffs_sync(mp, MNT_WAIT, td)) != 0) {
- vn_finished_write(mp);
+ if ((error = vn_start_write(NULL, &mp, V_WAIT)) != 0)
return (error);
+ for (;;) {
+ vn_finished_write(mp);
+ if ((error = vfs_write_suspend(mp)) != 0)
+ return (error);
+ MNT_ILOCK(mp);
+ if (mp->mnt_kern_flag & MNTK_SUSPENDED) {
+ /*
+ * Allow the secondary writes
+ * to proceed.
+ */
+ mp->mnt_kern_flag &= ~(MNTK_SUSPENDED |
+ MNTK_SUSPEND2);
+ wakeup(&mp->mnt_flag);
+ MNT_IUNLOCK(mp);
+ /*
+ * Allow the curthread to
+ * ignore the suspension to
+ * synchronize on-disk state.
+ */
+ curthread->td_pflags |= TDP_IGNSUSP;
+ break;
+ }
+ MNT_IUNLOCK(mp);
+ vn_start_write(NULL, &mp, V_WAIT);
}
/*
* Check for and optionally get rid of files open
@@ -211,7 +232,7 @@ ffs_mount(struct mount *mp, struct thread *td)
error = ffs_flushfiles(mp, flags, td);
}
if (error) {
- vn_finished_write(mp);
+ vfs_write_resume(mp);
return (error);
}
if (fs->fs_pendingblocks != 0 ||
@@ -228,10 +249,9 @@ ffs_mount(struct mount *mp, struct thread *td)
if ((error = ffs_sbupdate(ump, MNT_WAIT, 0)) != 0) {
fs->fs_ronly = 0;
fs->fs_clean = 0;
- vn_finished_write(mp);
+ vfs_write_resume(mp);
return (error);
}
- vn_finished_write(mp);
DROP_GIANT();
g_topology_lock();
g_access(ump->um_cp, 0, -1, 0);
@@ -241,6 +261,11 @@ ffs_mount(struct mount *mp, struct thread *td)
MNT_ILOCK(mp);
mp->mnt_flag |= MNT_RDONLY;
MNT_IUNLOCK(mp);
+ /*
+ * Allow the writers to note that filesystem
+ * is ro now.
+ */
+ vfs_write_resume(mp);
}
if ((mp->mnt_flag & MNT_RELOAD) &&
(error = ffs_reload(mp, td)) != 0)
@@ -1004,12 +1029,15 @@ ffs_unmount(mp, mntflags, td)
{
struct ufsmount *ump = VFSTOUFS(mp);
struct fs *fs;
- int error, flags;
+ int error, flags, susp;
flags = 0;
+ fs = ump->um_fs;
if (mntflags & MNT_FORCE) {
flags |= FORCECLOSE;
- }
+ susp = fs->fs_ronly != 0;
+ } else
+ susp = 0;
#ifdef UFS_EXTATTR
if ((error = ufs_extattr_stop(mp, td))) {
if (error != EOPNOTSUPP)
@@ -1019,14 +1047,34 @@ ffs_unmount(mp, mntflags, td)
ufs_extattr_uepm_destroy(&ump->um_extattr);
}
#endif
+ if (susp) {
+ /*
+ * dounmount already called vn_start_write().
+ */
+ for (;;) {
+ vn_finished_write(mp);
+ if ((error = vfs_write_suspend(mp)) != 0)
+ return (error);
+ MNT_ILOCK(mp);
+ if (mp->mnt_kern_flag & MNTK_SUSPENDED) {
+ mp->mnt_kern_flag &= ~(MNTK_SUSPENDED |
+ MNTK_SUSPEND2);
+ wakeup(&mp->mnt_flag);
+ MNT_IUNLOCK(mp);
+ curthread->td_pflags |= TDP_IGNSUSP;
+ break;
+ }
+ MNT_IUNLOCK(mp);
+ vn_start_write(NULL, &mp, V_WAIT);
+ }
+ }
if (mp->mnt_flag & MNT_SOFTDEP) {
if ((error = softdep_flushfiles(mp, flags, td)) != 0)
- return (error);
+ goto fail;
} else {
if ((error = ffs_flushfiles(mp, flags, td)) != 0)
- return (error);
+ goto fail;
}
- fs = ump->um_fs;
UFS_LOCK(ump);
if (fs->fs_pendingblocks != 0 || fs->fs_pendinginodes != 0) {
printf("%s: unmount pending error: blocks %jd files %d\n",
@@ -1041,9 +1089,13 @@ ffs_unmount(mp, mntflags, td)
error = ffs_sbupdate(ump, MNT_WAIT, 0);
if (error) {
fs->fs_clean = 0;
- return (error);
+ goto fail;
}
}
+ if (susp) {
+ vfs_write_resume(mp);
+ vn_start_write(NULL, &mp, V_WAIT);
+ }
DROP_GIANT();
g_topology_lock();
g_vfs_close(ump->um_cp, td);
@@ -1063,6 +1115,13 @@ ffs_unmount(mp, mntflags, td)
mp->mnt_flag &= ~MNT_LOCAL;
MNT_IUNLOCK(mp);
return (error);
+
+fail:
+ if (susp) {
+ vfs_write_resume(mp);
+ vn_start_write(NULL, &mp, V_WAIT);
+ }
+ return (error);
}
/*
OpenPOWER on IntegriCloud