[ostree] switchroot: Use MS_MOVE to / rather than chroot
- From: Colin Walters <walters src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [ostree] switchroot: Use MS_MOVE to / rather than chroot
- Date: Tue, 12 Feb 2013 01:48:05 +0000 (UTC)
commit c9f56564a374be6051e62ec97da3b340da21ff54
Author: Colin Walters <walters verbum org>
Date: Mon Feb 11 20:46:53 2013 -0500
switchroot: Use MS_MOVE to / rather than chroot
This fixes a number of bugs; the two biggest are:
1) On shutdown systemd can correctly umount /
2) We can use linux-user-chroot inside the system, as is
necessary to do upgrades
See http://lists.freedesktop.org/archives/systemd-devel/2012-September/006703.html
src/switchroot/ostree-switch-root.c | 111 ++++++++++++++++++-----------------
1 files changed, 56 insertions(+), 55 deletions(-)
---
diff --git a/src/switchroot/ostree-switch-root.c b/src/switchroot/ostree-switch-root.c
index 86c6855..6e74373 100644
--- a/src/switchroot/ostree-switch-root.c
+++ b/src/switchroot/ostree-switch-root.c
@@ -153,8 +153,7 @@ main(int argc, char *argv[])
const char *initramfs_move_mounts[] = { "/dev", "/proc", "/sys", "/run", NULL };
const char *toproot_bind_mounts[] = { "/home", "/root", "/tmp", NULL };
const char *ostree_bind_mounts[] = { "/var", NULL };
- const char *readonly_bind_mounts[] = { "/bin", "/lib", "/sbin", "/usr",
- NULL };
+ const char *readonly_bind_mounts[] = { "/usr", NULL };
const char *root_mountpoint = NULL;
const char *ostree_target = NULL;
const char *ostree_subinit = NULL;
@@ -194,16 +193,6 @@ main(int argc, char *argv[])
}
ostree_osname = strndup (ostree_target, p - ostree_target);
- /* For now, we just remount the root filesystem read/write. This is
- * kind of ugly, but to do this properly we'd basically have to have
- * to be fully integrated into the init process.
- */
- if (mount (NULL, root_mountpoint, NULL, MS_MGC_VAL|MS_REMOUNT, NULL) < 0)
- {
- perrorv ("Failed to remount %s read/write", root_mountpoint);
- exit (1);
- }
-
snprintf (destpath, sizeof(destpath), "%s/ostree/deploy/%s",
root_mountpoint, ostree_target);
if (stat (destpath, &stbuf) < 0)
@@ -212,53 +201,32 @@ main(int argc, char *argv[])
exit (1);
}
- for (i = 0; initramfs_move_mounts[i] != NULL; i++)
- {
- const char *path = initramfs_move_mounts[i];
- snprintf (destpath, sizeof(destpath), "%s/ostree/deploy/%s%s", root_mountpoint, ostree_target, path);
- if (mount (path, destpath, NULL, MS_MOVE, NULL) < 0)
- {
- perrorv ("failed to move mount of %s to %s", path, destpath);
- exit (1);
- }
- }
-
- if (chdir (root_mountpoint) < 0)
+ /* 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)
{
- perrorv ("failed to chdir to %s", root_mountpoint);
+ perrorv ("mount(/, MS_PRIVATE): ");
exit (1);
}
initramfs_fd = open ("/", O_RDONLY);
- if (mount (root_mountpoint, "/", NULL, MS_MOVE, NULL) < 0)
- {
- perrorv ("failed move %s to /", root_mountpoint);
- return -1;
- }
-
- if (chroot (".") < 0)
- {
- perrorv ("failed to chroot to .");
- exit (1);
- }
-
- if (initramfs_fd >= 0)
+ for (i = 0; initramfs_move_mounts[i] != NULL; i++)
{
- cleanup_pid = fork ();
- if (cleanup_pid == 0)
+ const char *path = initramfs_move_mounts[i];
+ snprintf (destpath, sizeof(destpath), "%s/ostree/deploy/%s%s", root_mountpoint, ostree_target, path);
+ if (mount (path, destpath, NULL, MS_MOVE, NULL) < 0)
{
- recursive_remove (initramfs_fd);
- exit (0);
+ perrorv ("failed to move mount of %s to %s", path, destpath);
+ exit (1);
}
- close (initramfs_fd);
}
- /* From this point on we're chrooted into the real root filesystem,
- * so we no longer refer to root_mountpoint.
- */
-
- snprintf (destpath, sizeof(destpath), "/ostree/deploy/%s", ostree_target);
+ snprintf (destpath, sizeof(destpath), "%s/ostree/deploy/%s", root_mountpoint, ostree_target);
fprintf (stderr, "Examining %s\n", destpath);
if (lstat (destpath, &stbuf) < 0)
{
@@ -279,12 +247,20 @@ main(int argc, char *argv[])
if (ostree_target_path[len-1] == '/')
ostree_target_path[len-1] = '\0';
fprintf (stderr, "Resolved OSTree target to: %s\n", ostree_target_path);
- asprintf (&deploy_path, "/ostree/deploy/%s/%s", ostree_osname, ostree_target_path);
+ asprintf (&deploy_path, "%s/ostree/deploy/%s/%s", root_mountpoint,
+ ostree_osname, ostree_target_path);
+
+ /* Make deploy_path a bind mount, so we can move it later */
+ if (mount (deploy_path, deploy_path, NULL, MS_BIND, NULL) < 0)
+ {
+ perrorv ("failed to initial bind mount %s", deploy_path);
+ exit (1);
+ }
snprintf (destpath, sizeof(destpath), "%s/sysroot", deploy_path);
- if (mount ("/", destpath, NULL, MS_BIND, NULL) < 0)
+ if (mount (root_mountpoint, destpath, NULL, MS_BIND, NULL) < 0)
{
- perrorv ("Failed to bind mount / to '%s'", destpath);
+ perrorv ("Failed to bind mount %s to '%s'", root_mountpoint, destpath);
exit (1);
}
@@ -298,8 +274,9 @@ main(int argc, char *argv[])
for (i = 0; toproot_bind_mounts[i] != NULL; i++)
{
+ snprintf (srcpath, sizeof(srcpath), "%s%s", root_mountpoint, toproot_bind_mounts[i]);
snprintf (destpath, sizeof(destpath), "%s%s", deploy_path, toproot_bind_mounts[i]);
- if (mount (toproot_bind_mounts[i], destpath, NULL, MS_BIND & ~MS_RDONLY, NULL) < 0)
+ if (mount (srcpath, destpath, NULL, MS_BIND & ~MS_RDONLY, NULL) < 0)
{
perrorv ("failed to bind mount (class:toproot) %s to %s", toproot_bind_mounts[i], destpath);
exit (1);
@@ -308,7 +285,8 @@ main(int argc, char *argv[])
for (i = 0; ostree_bind_mounts[i] != NULL; i++)
{
- snprintf (srcpath, sizeof(srcpath), "/ostree/deploy/%s%s", ostree_osname, ostree_bind_mounts[i]);
+ snprintf (srcpath, sizeof(srcpath), "%s/ostree/deploy/%s%s", root_mountpoint,
+ ostree_osname, ostree_bind_mounts[i]);
snprintf (destpath, sizeof(destpath), "%s%s", deploy_path, ostree_bind_mounts[i]);
if (mount (srcpath, destpath, NULL, MS_MGC_VAL|MS_BIND, NULL) < 0)
{
@@ -332,7 +310,19 @@ main(int argc, char *argv[])
}
}
- if (chroot (deploy_path) < 0)
+ if (chdir (deploy_path) < 0)
+ {
+ perrorv ("failed to chdir to subroot (initial)");
+ exit (1);
+ }
+
+ if (mount (deploy_path, "/", NULL, MS_MOVE, NULL) < 0)
+ {
+ perrorv ("failed to MS_MOVE %s to /", deploy_path);
+ exit (1);
+ }
+
+ if (chroot (".") < 0)
{
perrorv ("failed to change root to '%s'", deploy_path);
exit (1);
@@ -340,10 +330,21 @@ main(int argc, char *argv[])
if (chdir ("/") < 0)
{
- perrorv ("failed to chdir to subroot");
+ perrorv ("failed to chdir to / (after MS_MOVE of /)");
exit (1);
}
+ if (initramfs_fd >= 0)
+ {
+ cleanup_pid = fork ();
+ if (cleanup_pid == 0)
+ {
+ recursive_remove (initramfs_fd);
+ exit (0);
+ }
+ close (initramfs_fd);
+ }
+
init_argv = malloc (sizeof (char*)*((argc-before_init_argc)+2));
init_argv[0] = (char*)ostree_subinit;
for (i = 0; i < argc-before_init_argc; i++)
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]