[systemd-devel] [PATCH] shutdown: pivot_root to a tmpfs directory to properly umount root
harald at redhat.com
harald at redhat.com
Fri May 20 08:11:07 PDT 2011
From: Harald Hoyer <harald at redhat.com>
umount /boot
mount a tmpfs on /boot
mount bind all needed dirs
pivot_root to /boot
umount all mountpoints as before
see root be umounted properly and all dm devices deconstructed
---
src/shutdown.c | 154 +++++++++++++++++++++++++++++++++++++++++++++++++++----
1 files changed, 142 insertions(+), 12 deletions(-)
diff --git a/src/shutdown.c b/src/shutdown.c
index a2f3b53..66813ed 100644
--- a/src/shutdown.c
+++ b/src/shutdown.c
@@ -24,6 +24,11 @@
#include <sys/reboot.h>
#include <linux/reboot.h>
#include <sys/wait.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mount.h>
+#include <sys/syscall.h>
+#include <fcntl.h>
#include <dirent.h>
#include <errno.h>
#include <unistd.h>
@@ -38,6 +43,7 @@
#define TIMEOUT_USEC (5 * USEC_PER_SEC)
#define FINALIZE_ATTEMPTS 50
+#define pivot_root(new_root,put_old) syscall(SYS_pivot_root,new_root,put_old)
static bool ignore_proc(pid_t pid) {
if (pid == 1)
@@ -192,11 +198,112 @@ finish:
sigprocmask(SIG_SETMASK, &oldmask, NULL);
}
+static bool prepare_new_root(void) {
+ int r = false;
+ const char *dirs[] = { "/boot/oldroot",
+ "/boot/proc",
+ "/boot/sys",
+ "/boot/dev",
+ "/boot/run",
+ NULL };
+ const char **dir;
+ const char *msg;
+
+ umount("/boot");
+
+ msg = "Could not remount tmpfs on /boot";
+
+ if (mount("tmpfs", "/boot", "tmpfs", 0, "mode=0755") != 0)
+ goto out;
+
+ for (dir = &dirs[0]; *dir != NULL; dir++) {
+ asprintf((char **) &msg, "mkdir %s: %%m", *dir);
+ if (mkdir(*dir, 0755) != 0) {
+ if (errno != EEXIST)
+ goto out;
+ }
+ free((char *) msg);
+ }
+
+ log_info("mkdir in tmpfs");
+
+ msg = "Failed to mount bind /sys on /boot/sys";
+ if (mount("/sys", "/boot/sys", NULL, MS_BIND, NULL) != 0)
+ goto out;
+ msg = "Failed to mount bind /proc on /boot/proc";
+ if (mount("/proc", "/boot/proc", NULL, MS_BIND, NULL) != 0)
+ goto out;
+ msg = "Failed to mount bind /dev on /boot/dev";
+ if (mount("/dev", "/boot/dev", NULL, MS_BIND, NULL) != 0)
+ goto out;
+ msg = "Failed to mount bind /run on /boot/run";
+ if (mount("/run", "/boot/run", NULL, MS_BIND, NULL) != 0)
+ goto out;
+
+ msg = "Failed copying " SYSTEMD_SHUTDOWN_BINARY_PATH " to /boot";
+ if (install_bin(SYSTEMD_SHUTDOWN_BINARY_PATH, "/boot") != 0)
+ goto out;
+
+ msg = "Failed copying directory " SYSTEM_SHUTDOWN_PATH " to /boot/" SYSTEM_SHUTDOWN_PATH;
+ if (copy_execute_directory(SYSTEM_SHUTDOWN_PATH, "/boot") != 0)
+ goto out;
+
+ /* For debugging purposes, copy a small shutdown root
+ cp_a("/lib/systemd/shutdown-root", "/boot");
+ */
+
+ r = true;
+out:
+ if (!r)
+ log_error("%s: %m", msg);
+ return r;
+}
+
+static bool pivot_to_new_root(void) {
+ int fd;
+ int r = 0;
+ chdir("/boot");
+
+ /*
+ In case some evil process made "/" MS_SHARED
+ It works for pivot_root, but the ref count for the root device
+ is not decreasing :-/
+ */
+ if (mount(NULL, "/", NULL, MS_PRIVATE, NULL) != 0) {
+ log_error("Failed to make \"/\" private mount %m: ");
+ return false;
+ }
+ if (mount(NULL, "/boot", NULL, MS_PRIVATE, NULL) != 0) {
+ log_error("Failed to make /boot private mount %m: ");
+ return false;
+ }
+
+ r = pivot_root(".", "oldroot");
+ if (r!=0) {
+ log_error("pivot failed: %m");
+ /* only chroot, if pivot root succeded */
+ return false;
+ }
+ chroot(".");
+
+ fd = open("dev/console", O_RDONLY);
+ dup2(fd, STDIN_FILENO);
+ close_nointr_nofail(fd);
+ fd = open("dev/console", O_WRONLY);
+ dup2(fd, STDOUT_FILENO);
+ close_nointr_nofail(fd);
+ fd = open("dev/console", O_WRONLY);
+ dup2(fd, STDERR_FILENO);
+ close_nointr_nofail(fd);
+ return true;
+}
+
int main(int argc, char *argv[]) {
int cmd, r;
unsigned retries;
bool need_umount = true, need_swapoff = true, need_loop_detach = true, need_dm_detach = true;
bool killed_everbody = false, in_container;
+ bool pivoted = false;
log_parse_environment();
log_set_target(LOG_TARGET_CONSOLE); /* syslog will die if not gone yet */
@@ -208,6 +315,17 @@ int main(int argc, char *argv[]) {
goto error;
}
+ if (argc == 3) {
+ if (! streq(argv[2], "pivoted")) {
+ log_error("Invalid number of arguments.");
+ r = -EINVAL;
+ goto error;
+ }
+ argc--;
+ argv[2] = NULL;
+ pivoted = true;
+ }
+
if (argc != 2) {
log_error("Invalid number of arguments.");
r = -EINVAL;
@@ -230,6 +348,18 @@ int main(int argc, char *argv[]) {
goto error;
}
+ if (!(pivoted || in_container)) {
+ char *new_argv[4];
+ new_argv[0] = strdup(argv[0]);
+ new_argv[1] = strdup(argv[1]);
+ new_argv[2] = strdup("pivoted");
+ new_argv[3] = NULL;
+ if (prepare_new_root() && pivot_to_new_root()) {
+ execv(SYSTEMD_SHUTDOWN_BINARY_PATH, new_argv);
+ log_error("Failed to execute shutdown binary: %m");
+ }
+ }
+
/* lock us into memory */
if (mlockall(MCL_CURRENT|MCL_FUTURE) != 0)
log_warning("Cannot lock process memory: %m");
@@ -247,17 +377,6 @@ int main(int argc, char *argv[]) {
for (retries = 0; retries < FINALIZE_ATTEMPTS; retries++) {
bool changed = false;
- if (need_umount) {
- log_info("Unmounting file systems.");
- r = umount_all(&changed);
- if (r == 0)
- need_umount = false;
- else if (r > 0)
- log_info("Not all file systems unmounted, %d left.", r);
- else
- log_error("Failed to unmount file systems: %s", strerror(-r));
- }
-
if (need_swapoff) {
log_info("Disabling swaps.");
r = swapoff_all(&changed);
@@ -269,6 +388,17 @@ int main(int argc, char *argv[]) {
log_error("Failed to turn off swaps: %s", strerror(-r));
}
+ if (need_umount) {
+ log_info("Unmounting file systems.");
+ r = umount_all(&changed);
+ if (r == 0)
+ need_umount = false;
+ else if (r > 0)
+ log_info("Not all file systems unmounted, %d left.", r);
+ else
+ log_error("Failed to unmount file systems: %s", strerror(-r));
+ }
+
if (need_loop_detach) {
log_info("Detaching loop devices.");
r = loopback_detach_all(&changed);
@@ -353,7 +483,7 @@ int main(int argc, char *argv[]) {
log_error("Failed to invoke reboot(): %m");
r = -errno;
- error:
+error:
log_error("Critical error while doing system shutdown: %s", strerror(-r));
freeze();
--
1.7.3.4
More information about the systemd-devel
mailing list