return -errno;
}
- /*
- 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 -errno;
- }
+ /* Work-around for a kernel bug: for some reason the kernel
+ * refuses switching root if any file systems are mounted
+ * MS_SHARED. Hence remount them MS_PRIVATE here as a
+ * work-around.
+ *
+ * https://bugzilla.redhat.com/show_bug.cgi?id=847418 */
+ if (mount(NULL, "/", NULL, MS_REC|MS_PRIVATE, NULL) < 0)
+ log_warning("Failed to make \"/\" private mount: %m");
if (pivot_root(".", "oldroot") < 0) {
log_error("pivot failed: %m");
- /* only chroot if pivot root succeded */
+ /* only chroot if pivot root succeeded */
return -errno;
}
mlockall(MCL_CURRENT|MCL_FUTURE);
log_info("Sending SIGTERM to remaining processes...");
- broadcast_signal(SIGTERM);
+ broadcast_signal(SIGTERM, true);
log_info("Sending SIGKILL to remaining processes...");
- broadcast_signal(SIGKILL);
+ broadcast_signal(SIGKILL, true);
if (in_container) {
need_swapoff = false;
arguments[2] = NULL;
execute_directory(SYSTEM_SHUTDOWN_PATH, NULL, arguments);
- /* If we are in a container, just exit, this will kill our
- * container for good. */
- if (in_container) {
- log_error("Exiting container.");
- exit(0);
- }
-
- if (access("/run/initramfs/shutdown", X_OK) == 0) {
+ if (!in_container &&
+ access("/run/initramfs/shutdown", X_OK) == 0) {
if (prepare_new_root() >= 0 &&
pivot_to_new_root() >= 0) {
}
}
- sync();
+ /* The kernel will automaticall flush ATA disks and suchlike
+ * on reboot(), but the file systems need to be synce'd
+ * explicitly in advance. So let's do this here, but not
+ * needlessly slow down containers. */
+ if (!in_container)
+ sync();
if (cmd == LINUX_REBOOT_CMD_KEXEC) {
- /* We cheat and exec kexec to avoid doing all its work */
- pid_t pid = fork();
-
- if (pid < 0)
- log_error("Could not fork: %m. Falling back to normal reboot.");
- else if (pid > 0) {
- wait_for_terminate_and_warn("kexec", pid);
- log_warning("kexec failed. Falling back to normal reboot.");
- } else {
- /* Child */
- const char *args[3] = { "/sbin/kexec", "-e", NULL };
- execv(args[0], (char * const *) args);
- return EXIT_FAILURE;
+
+ if (!in_container) {
+ /* We cheat and exec kexec to avoid doing all its work */
+ pid_t pid = fork();
+
+ if (pid < 0)
+ log_error("Could not fork: %m. Falling back to normal reboot.");
+ else if (pid > 0) {
+ wait_for_terminate_and_warn("kexec", pid);
+ log_warning("kexec failed. Falling back to normal reboot.");
+ } else {
+ /* Child */
+ const char *args[3] = { "/sbin/kexec", "-e", NULL };
+ execv(args[0], (char * const *) args);
+ return EXIT_FAILURE;
+ }
}
cmd = RB_AUTOBOOT;
}
reboot(cmd);
+
+ if (errno == EPERM && in_container) {
+ /* If we are in a container, and we lacked
+ * CAP_SYS_BOOT just exit, this will kill our
+ * container for good. */
+ log_error("Exiting container.");
+ exit(0);
+ }
+
log_error("Failed to invoke reboot(): %m");
r = -errno;