Lennart Poettering 46f254
From 891a4918ef75fa81e22691156c050d061bd53dd3 Mon Sep 17 00:00:00 2001
Lennart Poettering 46f254
From: Lennart Poettering <lennart@poettering.net>
Lennart Poettering 46f254
Date: Fri, 16 Nov 2012 18:15:30 +0100
Lennart Poettering 46f254
Subject: [PATCH] switch-root: try pivot_root() before overmounting /
Lennart Poettering 46f254
Lennart Poettering 46f254
We should always try to umount the old root dir if possible, instead of
Lennart Poettering 46f254
overmounting it -- if that's possible.
Lennart Poettering 46f254
Lennart Poettering 46f254
The initial ("first") kernel rootfs can never be umounted, hence
Lennart Poettering 46f254
for the usual nitrd case we never bothered using pivot_root() and
Lennart Poettering 46f254
hence with fully unmounting it. However, fedup now tranisitions twice
Lennart Poettering 46f254
during boot, and in that case it is highly desirable that the "second"
Lennart Poettering 46f254
root dir is entirely unmounted when we switch to the "third". This patch
Lennart Poettering 46f254
makes that possible.
Lennart Poettering 46f254
Lennart Poettering 46f254
The pivot_root() needs a directory in the "third" root dir, to move the
Lennart Poettering 46f254
"second" root dir to. We use /mnt for that, under the assumption that
Lennart Poettering 46f254
this directory is likely to exist, and is not itself a mount point.
Lennart Poettering 46f254
---
Lennart Poettering 46f254
 src/core/switch-root.c | 27 ++++++++++++++++++++++++++-
Lennart Poettering 46f254
 1 file changed, 26 insertions(+), 1 deletion(-)
Lennart Poettering 46f254
Lennart Poettering 46f254
diff --git a/src/core/switch-root.c b/src/core/switch-root.c
Lennart Poettering 46f254
index 150332a..ce0e41d 100644
Lennart Poettering 46f254
--- a/src/core/switch-root.c
Lennart Poettering 46f254
+++ b/src/core/switch-root.c
Lennart Poettering 46f254
@@ -30,6 +30,7 @@
Lennart Poettering 46f254
 #include "util.h"
Lennart Poettering 46f254
 #include "path-util.h"
Lennart Poettering 46f254
 #include "switch-root.h"
Lennart Poettering 46f254
+#include "missing.h"
Lennart Poettering 46f254
 
Lennart Poettering 46f254
 int switch_root(const char *new_root) {
Lennart Poettering 46f254
 
Lennart Poettering 46f254
@@ -44,10 +45,21 @@ int switch_root(const char *new_root) {
Lennart Poettering 46f254
         struct stat new_root_stat;
Lennart Poettering 46f254
         bool old_root_remove;
Lennart Poettering 46f254
         const char *i;
Lennart Poettering 46f254
+        _cleanup_free_ char *temporary_old_root = NULL;
Lennart Poettering 46f254
 
Lennart Poettering 46f254
         if (path_equal(new_root, "/"))
Lennart Poettering 46f254
                 return 0;
Lennart Poettering 46f254
 
Lennart Poettering 46f254
+        /* When using pivot_root() we assume that /mnt exists as place
Lennart Poettering 46f254
+         * we can temporarily move the old root to. As we immediately
Lennart Poettering 46f254
+         * unmount it from there it doesn't matter much which
Lennart Poettering 46f254
+         * directory we choose for this, but it should be more likely
Lennart Poettering 46f254
+         * than not that /mnt exists and is suitable as mount point
Lennart Poettering 46f254
+         * and is on the same fs as the old root dir */
Lennart Poettering 46f254
+        temporary_old_root = strappend(new_root, "/mnt");
Lennart Poettering 46f254
+        if (!temporary_old_root)
Lennart Poettering 46f254
+                return -ENOMEM;
Lennart Poettering 46f254
+
Lennart Poettering 46f254
         old_root_remove = in_initrd();
Lennart Poettering 46f254
 
Lennart Poettering 46f254
         if (stat(new_root, &new_root_stat) < 0) {
Lennart Poettering 46f254
@@ -103,7 +115,20 @@ int switch_root(const char *new_root) {
Lennart Poettering 46f254
                         log_warning("Failed to open root directory: %m");
Lennart Poettering 46f254
         }
Lennart Poettering 46f254
 
Lennart Poettering 46f254
-        if (mount(new_root, "/", NULL, MS_MOVE, NULL) < 0) {
Lennart Poettering 46f254
+        /* We first try a pivot_root() so that we can umount the old
Lennart Poettering 46f254
+         * root dir. In many cases (i.e. where rootfs is /), that's
Lennart Poettering 46f254
+         * not possible however, and hence we simply overmount root */
Lennart Poettering 46f254
+        if (pivot_root(new_root, temporary_old_root) >= 0) {
Lennart Poettering 46f254
+
Lennart Poettering 46f254
+                /* Immediately get rid of the old root. Since we are
Lennart Poettering 46f254
+                 * running off it we need to do this lazily. */
Lennart Poettering 46f254
+                if (umount2(temporary_old_root, MNT_DETACH) < 0) {
Lennart Poettering 46f254
+                        r = -errno;
Lennart Poettering 46f254
+                        log_error("Failed to umount old root dir %s: %m", temporary_old_root);
Lennart Poettering 46f254
+                        goto fail;
Lennart Poettering 46f254
+                }
Lennart Poettering 46f254
+
Lennart Poettering 46f254
+        } else if (mount(new_root, "/", NULL, MS_MOVE, NULL) < 0) {
Lennart Poettering 46f254
                 r = -errno;
Lennart Poettering 46f254
                 log_error("Failed to mount moving %s to /: %m", new_root);
Lennart Poettering 46f254
                 goto fail;
Lennart Poettering 46f254
-- 
Lennart Poettering 46f254
1.7.12.1
Lennart Poettering 46f254