Changeset View
Standalone View
sys/kern/vfs_mount.c
Show First 20 Lines • Show All 2,501 Lines • ▼ Show 20 Lines | if (donew) | ||||
mount_devctl_event_mntopt(&sb, "optnew", mp->mnt_optnew); | mount_devctl_event_mntopt(&sb, "optnew", mp->mnt_optnew); | ||||
sbuf_finish(&sb); | sbuf_finish(&sb); | ||||
if (sbuf_error(&sb) == 0) | if (sbuf_error(&sb) == 0) | ||||
devctl_notify("VFS", "FS", type, sbuf_data(&sb)); | devctl_notify("VFS", "FS", type, sbuf_data(&sb)); | ||||
sbuf_delete(&sb); | sbuf_delete(&sb); | ||||
free(buf, M_MOUNT); | free(buf, M_MOUNT); | ||||
} | } | ||||
/* | |||||
* Suspend write operations on all local writeable filesystems. Does | |||||
* full sync of them in the process. | |||||
* | |||||
* Iterate over the mount points in reverse order, suspending most | |||||
* recently mounted filesystems first. It handles a case where a | |||||
* filesystem mounted from a md(4) vnode-backed device should be | |||||
markj: "where a filesystem mounted from a md(4) vnode-backed device should be suspended before the… | |||||
* suspended before the filesystem that owns the vnode. | |||||
*/ | |||||
void | |||||
suspend_all_fs(void) | |||||
Done Inline ActionsWith user processes suspended, what is the risk that one of them holds this lock but is waiting? Is that enough to also guard against a filesystem that goes away due to automatic unmount too which might still race this? imp: With user processes suspended, what is the risk that one of them holds this lock but is waiting? | |||||
Done Inline ActionsUnless there is a bug in the process suspension, it should be safe. Suspension cares to only claim that the process is suspended for ALL_PROC case when all threads are either at kernel->user boundary, or interruptible safe-sleep (so for instance NFS intr sleep while owning a vnode or buffer lock is not safe). Do we already have async unmount in tree ? That said, vfs_busy() syncs with unmount, this is the reason for it there. kib: Unless there is a bug in the process suspension, it should be safe. Suspension cares to only… | |||||
{ | |||||
Done Inline ActionsHow is safe traversal guaranteed if we are dropping the mountlist lock? markj: How is safe traversal guaranteed if we are dropping the mountlist lock? | |||||
Done Inline ActionsIt is enough to guarantee that mp is not unmounted (it is type-stable but we want it on the list). This is provided by vfs_busy(). Additional safety is provided by the fact that I suspended all usermode processes before suspending fs. BTW I only unbusy on resume, this might be over-reaction but it is easier to structure code this way. kib: It is enough to guarantee that mp is not unmounted (it is type-stable but we want it on the… | |||||
struct mount *mp; | |||||
int error; | |||||
mtx_lock(&mountlist_mtx); | |||||
Done Inline ActionsWhy just the local fs? Not necessarily a problem, but wondering the reason imp: Why just the local fs? Not necessarily a problem, but wondering the reason | |||||
Done Inline ActionsFIlesystem consistency for non-local fs is the problem of remote machine, not our. That said, non-local filesystems take non-deterministic time to sync, and really nobody tried to suspend e.g. NFS. Lets work out the most important case first. kib: FIlesystem consistency for non-local fs is the problem of remote machine, not our.
That said… | |||||
TAILQ_FOREACH_REVERSE(mp, &mountlist, mntlist, mnt_list) { | |||||
error = vfs_busy(mp, MBF_MNTLSTLOCK | MBF_NOWAIT); | |||||
if (error != 0) | |||||
continue; | |||||
if ((mp->mnt_flag & (MNT_RDONLY | MNT_LOCAL)) != MNT_LOCAL || | |||||
(mp->mnt_kern_flag & MNTK_SUSPEND) != 0) { | |||||
mtx_lock(&mountlist_mtx); | |||||
vfs_unbusy(mp); | |||||
continue; | |||||
} | |||||
error = vfs_write_suspend(mp, 0); | |||||
if (error == 0) { | |||||
MNT_ILOCK(mp); | |||||
Done Inline ActionsIt might be nice to print an error message here, since the most likely scenario is that fsync() failed. markj: It might be nice to print an error message here, since the most likely scenario is that fsync()… | |||||
MPASS((mp->mnt_kern_flag & MNTK_SUSPEND_ALL) == 0); | |||||
mp->mnt_kern_flag |= MNTK_SUSPEND_ALL; | |||||
MNT_IUNLOCK(mp); | |||||
mtx_lock(&mountlist_mtx); | |||||
} else { | |||||
printf("suspend of %s failed, error %d\n", | |||||
mp->mnt_stat.f_mntonname, error); | |||||
mtx_lock(&mountlist_mtx); | |||||
vfs_unbusy(mp); | |||||
} | |||||
} | |||||
mtx_unlock(&mountlist_mtx); | |||||
} | |||||
void | |||||
resume_all_fs(void) | |||||
{ | |||||
struct mount *mp; | |||||
mtx_lock(&mountlist_mtx); | |||||
TAILQ_FOREACH(mp, &mountlist, mnt_list) { | |||||
if ((mp->mnt_kern_flag & MNTK_SUSPEND_ALL) == 0) | |||||
continue; | |||||
mtx_unlock(&mountlist_mtx); | |||||
MNT_ILOCK(mp); | |||||
MPASS((mp->mnt_kern_flag & MNTK_SUSPEND) != 0); | |||||
mp->mnt_kern_flag &= ~MNTK_SUSPEND_ALL; | |||||
MNT_IUNLOCK(mp); | |||||
vfs_write_resume(mp, 0); | |||||
mtx_lock(&mountlist_mtx); | |||||
vfs_unbusy(mp); | |||||
} | |||||
mtx_unlock(&mountlist_mtx); | |||||
} |
"where a filesystem mounted from a md(4) vnode-backed device should be suspended before the filesystem that owns the vnode" is a bit clearer to me.