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
This commit is contained in:
Konstantin Belousov 2008-09-16 11:55:53 +00:00
parent 2814d5ba5f
commit 6fecb4e41e

View File

@ -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)) {
/*
* Flush any dirty data and suspend filesystem.
*/
if ((error = vn_start_write(NULL, &mp, V_WAIT)) != 0)
return (error);
/*
* Flush any dirty data.
*/
if ((error = ffs_sync(mp, MNT_WAIT, td)) != 0) {
for (;;) {
vn_finished_write(mp);
return (error);
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);
}
/*