Index: head/sys/dev/acpica/acpi.c =================================================================== --- head/sys/dev/acpica/acpi.c +++ head/sys/dev/acpica/acpi.c @@ -46,6 +46,7 @@ #include #include #include +#include #include #include #include @@ -3081,6 +3082,7 @@ EVENTHANDLER_INVOKE(power_suspend_early); stop_all_proc(); + suspend_all_fs(); EVENTHANDLER_INVOKE(power_suspend); #ifdef EARLY_AP_STARTUP @@ -3240,6 +3242,7 @@ } #endif + resume_all_fs(); resume_all_proc(); EVENTHANDLER_INVOKE(power_resume); Index: head/sys/dev/xen/control/control.c =================================================================== --- head/sys/dev/xen/control/control.c +++ head/sys/dev/xen/control/control.c @@ -113,6 +113,7 @@ #include #include #include +#include #include #include #include @@ -204,6 +205,7 @@ xs_lock(); stop_all_proc(); xs_unlock(); + suspend_all_fs(); EVENTHANDLER_INVOKE(power_suspend); #ifdef EARLY_AP_STARTUP @@ -317,6 +319,7 @@ } #endif + resume_all_fs(); resume_all_proc(); EVENTHANDLER_INVOKE(power_resume); Index: head/sys/kern/vfs_mount.c =================================================================== --- head/sys/kern/vfs_mount.c +++ head/sys/kern/vfs_mount.c @@ -2507,3 +2507,67 @@ sbuf_delete(&sb); 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. + */ +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; + 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); +} Index: head/sys/sys/mount.h =================================================================== --- head/sys/sys/mount.h +++ head/sys/sys/mount.h @@ -463,6 +463,7 @@ #define MNTK_VMSETSIZE_BUG 0x00010000 #define MNTK_UNIONFS 0x00020000 /* A hack for F_ISUNIONSTACK */ #define MNTK_FPLOOKUP 0x00040000 /* fast path lookup is supported */ +#define MNTK_SUSPEND_ALL 0x00080000 /* Suspended by all-fs suspension */ #define MNTK_NOASYNC 0x00800000 /* disable async */ #define MNTK_UNMOUNT 0x01000000 /* unmount in progress */ #define MNTK_MWAIT 0x02000000 /* waiting for unmount to finish */ @@ -1047,6 +1048,9 @@ enum mount_counter { MNT_COUNT_REF, MNT_COUNT_LOCKREF, MNT_COUNT_WRITEOPCOUNT }; int vfs_mount_fetch_counter(struct mount *, enum mount_counter); + +void suspend_all_fs(void); +void resume_all_fs(void); /* * Code transitioning mnt_vfs_ops to > 0 issues IPIs until it observes