Changeset View
Standalone View
head/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 | |||||
* suspended before the filesystem that owns the vnode. | |||||
mckusick: How are you ensuring that it handles the case where a filesystem mounted from a md(4) vnode… | |||||
kibAuthorUnsubmitted Done Inline ActionsNmount(2) adds new mount at the end of the mountlist. Because to configure vnode-backed md(4) you need to access the backing file, it means that mount over md(4) must appear after its backing filesystem in the mountlist. Iterating in reverse order makes me handle md-mount before backing mount. kib: Nmount(2) adds new mount at the end of the mountlist. Because to configure vnode-backed md(4)… | |||||
*/ | |||||
void | |||||
suspend_all_fs(void) | |||||
{ | |||||
struct mount *mp; | |||||
int error; | |||||
mtx_lock(&mountlist_mtx); | |||||
TAILQ_FOREACH_REVERSE(mp, &mountlist, mntlist, mnt_list) { | |||||
error = vfs_busy(mp, MBF_MNTLSTLOCK | MBF_NOWAIT); | |||||
if (error != 0) | |||||
continue; | |||||
mckusickUnsubmitted Done Inline ActionsIf this vfs_busy() fails, then this filesystem will not be suspended. Doesn't this result in less than all local filesystems being suspended? mckusick: If this vfs_busy() fails, then this filesystem will not be suspended. Doesn't this result in… | |||||
kibAuthorUnsubmitted Done Inline ActionsFailing vfs_busy() means that mp is currently being unmounted. It cannot be user-mode request for unmount, because all user processes were suspended by suspend_all_procs() done before suspend_all_fs(). As such, vfs_busy() either cannot fail at all, or if we actually have 'unmount on failure' code, which must use forced unmount, we cannot care less about this mount for suspension purposes. kib: Failing vfs_busy() means that mp is currently being unmounted. It cannot be user-mode request… | |||||
impUnsubmitted Not Done Inline ActionsThe goal here is to make a best-effort at persisting as much filesystem state as is practical in case we never resume for some reason. If some fail to do that for some filesystems due to edge cases, then we're still better off than before where no effort was made. So long as we deal properly with the case where we're flushing data to storage, that storage fails in a way that causes an forced unmount, we're OK. "Properly" here I think is covered: the filesystem fails at some point and it's unmounting doesn't cause the list to be corrupt such that we cant finish walking it. But now I see lots of mtx_lock(&mountlist_mtx) below, but no unlocks in the loop. is that implicitly unlocked somewhere? Or am I overlooking something? I see the unlock / lock dance in resume_all_fs() imp: The goal here is to make a best-effort at persisting as much filesystem state as is practical… | |||||
kibAuthorUnsubmitted Done Inline Actionsvfs_busy(MBF_MNTLSTLOCK) assumes that mountlist_mtx is locked and drop it. kib: vfs_busy(MBF_MNTLSTLOCK) assumes that mountlist_mtx is locked and drop it. | |||||
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); | |||||
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); | |||||
} |
How are you ensuring that it handles the case where a filesystem mounted from a md(4) vnode-backed device is suspended before the filesystem that owns the vnode?