Merge pull request #27670 from poettering/switch-root-umount-all
umount all mounts during MS_MOVE switch root
This commit is contained in:
+30
-8
@@ -43,24 +43,28 @@
|
||||
#include "tmpfile-util.h"
|
||||
#include "user-util.h"
|
||||
|
||||
int umount_recursive(const char *prefix, int flags) {
|
||||
int umount_recursive_full(const char *prefix, int flags, char **keep) {
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
int n = 0, r;
|
||||
bool again;
|
||||
|
||||
/* Try to umount everything recursively below a directory. Also, take care of stacked mounts, and
|
||||
* keep unmounting them until they are gone. */
|
||||
|
||||
do {
|
||||
f = fopen("/proc/self/mountinfo", "re"); /* Pin the file, in case we unmount /proc/ as part of the logic here */
|
||||
if (!f)
|
||||
return log_debug_errno(errno, "Failed to open /proc/self/mountinfo: %m");
|
||||
|
||||
for (;;) {
|
||||
_cleanup_(mnt_free_tablep) struct libmnt_table *table = NULL;
|
||||
_cleanup_(mnt_free_iterp) struct libmnt_iter *iter = NULL;
|
||||
bool again = false;
|
||||
|
||||
again = false;
|
||||
|
||||
r = libmount_parse("/proc/self/mountinfo", NULL, &table, &iter);
|
||||
r = libmount_parse("/proc/self/mountinfo", f, &table, &iter);
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to parse /proc/self/mountinfo: %m");
|
||||
|
||||
for (;;) {
|
||||
bool shall_keep = false;
|
||||
struct libmnt_fs *fs;
|
||||
const char *path;
|
||||
|
||||
@@ -74,8 +78,21 @@ int umount_recursive(const char *prefix, int flags) {
|
||||
if (!path)
|
||||
continue;
|
||||
|
||||
if (!path_startswith(path, prefix))
|
||||
if (prefix && !path_startswith(path, prefix)) {
|
||||
log_debug("Not unmounting %s, outside of prefix: %s", path, prefix);
|
||||
continue;
|
||||
}
|
||||
|
||||
STRV_FOREACH(k, keep)
|
||||
/* Match against anything in the path to the dirs to keep, or below the dirs to keep */
|
||||
if (path_startswith(path, *k) || path_startswith(*k, path)) {
|
||||
shall_keep = true;
|
||||
break;
|
||||
}
|
||||
if (shall_keep) {
|
||||
log_debug("Not unmounting %s, referenced by keep list.", path);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (umount2(path, flags | UMOUNT_NOFOLLOW) < 0) {
|
||||
log_debug_errno(errno, "Failed to umount %s, ignoring: %m", path);
|
||||
@@ -89,7 +106,12 @@ int umount_recursive(const char *prefix, int flags) {
|
||||
|
||||
break;
|
||||
}
|
||||
} while (again);
|
||||
|
||||
if (!again)
|
||||
break;
|
||||
|
||||
rewind(f);
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
@@ -12,7 +12,12 @@
|
||||
#include "macro.h"
|
||||
|
||||
int repeat_unmount(const char *path, int flags);
|
||||
int umount_recursive(const char *target, int flags);
|
||||
|
||||
int umount_recursive_full(const char *target, int flags, char **keep);
|
||||
|
||||
static inline int umount_recursive(const char *target, int flags) {
|
||||
return umount_recursive_full(target, flags, NULL);
|
||||
}
|
||||
|
||||
int bind_remount_recursive_with_mountinfo(const char *prefix, unsigned long new_flags, unsigned long flags_mask, char **deny_list, FILE *proc_self_mountinfo);
|
||||
static inline int bind_remount_recursive(const char *prefix, unsigned long new_flags, unsigned long flags_mask, char **deny_list) {
|
||||
|
||||
@@ -114,6 +114,14 @@ int switch_root(const char *new_root,
|
||||
if (r < 0) {
|
||||
log_debug_errno(r, "Pivoting root file system failed, moving mounts instead: %m");
|
||||
|
||||
/* If we have to use MS_MOVE let's first try to get rid of *all* mounts we can, with the
|
||||
* exception of the path we want to switch to, plus everything leading to it and within
|
||||
* it. This is necessary because unlike pivot_root() just moving the mount to the root via
|
||||
* MS_MOVE won't magically unmount anything below it. Once the chroot() succeeds the mounts
|
||||
* below would still be around but invisible to us, because not accessible via
|
||||
* /proc/self/mountinfo. Hence, let's clean everything up first, as long as we still can. */
|
||||
(void) umount_recursive_full(NULL, MNT_DETACH, STRV_MAKE(new_root));
|
||||
|
||||
if (mount(".", "/", NULL, MS_MOVE, NULL) < 0)
|
||||
return log_error_errno(errno, "Failed to move %s to /: %m", new_root);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user