]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
nspawn: add --volatile=overlay support
authorLennart Poettering <lennart@poettering.net>
Wed, 19 Dec 2018 00:02:06 +0000 (01:02 +0100)
committerLennart Poettering <lennart@poettering.net>
Fri, 1 Mar 2019 13:11:06 +0000 (14:11 +0100)
Fixes: #11054 #3847
src/nspawn/nspawn-mount.c
src/nspawn/nspawn.c
src/shared/volatile-util.c
src/shared/volatile-util.h

index 916070b3f256223277535a51698f5619e2d05837..eb0a26ef35bf491d935c77312fb142b37b46b67a 100644 (file)
@@ -959,6 +959,71 @@ fail:
         return r;
 }
 
+static int setup_volatile_overlay(
+                const char *directory,
+                bool userns, uid_t uid_shift, uid_t uid_range,
+                const char *selinux_apifs_context) {
+
+        _cleanup_free_ char *buf = NULL, *escaped_directory = NULL, *escaped_upper = NULL, *escaped_work = NULL;
+        char template[] = "/tmp/nspawn-volatile-XXXXXX";
+        const char *upper, *work, *options;
+        bool tmpfs_mounted = false;
+        int r;
+
+        assert(directory);
+
+        /* --volatile=overlay means we mount an overlayfs to the root dir. */
+
+        if (!mkdtemp(template))
+                return log_error_errno(errno, "Failed to create temporary directory: %m");
+
+        options = "mode=755";
+        r = tmpfs_patch_options(options, uid_shift == 0 ? UID_INVALID : uid_shift, selinux_apifs_context, &buf);
+        if (r < 0)
+                goto finish;
+        if (r > 0)
+                options = buf;
+
+        r = mount_verbose(LOG_ERR, "tmpfs", template, "tmpfs", MS_STRICTATIME, options);
+        if (r < 0)
+                goto finish;
+
+        tmpfs_mounted = true;
+
+        upper = strjoina(template, "/upper");
+        work = strjoina(template, "/work");
+
+        if (mkdir(upper, 0755) < 0) {
+                r = log_error_errno(errno, "Failed to create %s: %m", upper);
+                goto finish;
+        }
+        if (mkdir(work, 0755) < 0) {
+                r = log_error_errno(errno, "Failed to create %s: %m", work);
+                goto finish;
+        }
+
+        /* And now, let's overmount the root dir with an overlayfs that uses the root dir as lower dir. It's kinda nice
+         * that the kernel allows us to do that without going through some mount point rearrangements. */
+
+        escaped_directory = shell_escape(directory, ",:");
+        escaped_upper = shell_escape(upper, ",:");
+        escaped_work = shell_escape(work, ",:");
+        if (!escaped_directory || !escaped_upper || !escaped_work) {
+                r = -ENOMEM;
+                goto finish;
+        }
+
+        options = strjoina("lowerdir=", escaped_directory, ",upperdir=", escaped_upper, ",workdir=", escaped_work);
+        r = mount_verbose(LOG_ERR, "overlay", directory, "overlay", 0, options);
+
+finish:
+        if (tmpfs_mounted)
+                (void) umount_verbose(template);
+
+        (void) rmdir(template);
+        return r;
+}
+
 int setup_volatile_mode(
                 const char *directory,
                 VolatileMode mode,
@@ -973,6 +1038,9 @@ int setup_volatile_mode(
         case VOLATILE_STATE:
                 return setup_volatile_state(directory, userns, uid_shift, uid_range, selinux_apifs_context);
 
+        case VOLATILE_OVERLAY:
+                return setup_volatile_overlay(directory, userns, uid_shift, uid_range, selinux_apifs_context);
+
         default:
                 return 0;
         }
index bb070e1b35989fe035d532f0298abab40338a5a1..0bdfc7677a449c2459e5740aa302cd7b4bd60de1 100644 (file)
@@ -1431,9 +1431,9 @@ static int setup_timezone(const char *dest) {
         if (IN_SET(arg_timezone, TIMEZONE_AUTO, TIMEZONE_SYMLINK)) {
                 r = readlink_malloc("/etc/localtime", &p);
                 if (r == -ENOENT && arg_timezone == TIMEZONE_AUTO)
-                        m = arg_read_only && arg_volatile_mode != VOLATILE_YES ? TIMEZONE_OFF : TIMEZONE_DELETE;
+                        m = arg_read_only && IN_SET(arg_volatile_mode, VOLATILE_NO, VOLATILE_STATE) ? TIMEZONE_OFF : TIMEZONE_DELETE;
                 else if (r == -EINVAL && arg_timezone == TIMEZONE_AUTO) /* regular file? */
-                        m = arg_read_only && arg_volatile_mode != VOLATILE_YES ? TIMEZONE_BIND : TIMEZONE_COPY;
+                        m = arg_read_only && IN_SET(arg_volatile_mode, VOLATILE_NO, VOLATILE_STATE) ? TIMEZONE_BIND : TIMEZONE_COPY;
                 else if (r < 0) {
                         log_warning_errno(r, "Failed to read host's /etc/localtime symlink, not updating container timezone: %m");
                         /* To handle warning, delete /etc/localtime and replace it with a symbolic link to a time zone data
@@ -1444,7 +1444,7 @@ static int setup_timezone(const char *dest) {
                          */
                         return 0;
                 } else if (arg_timezone == TIMEZONE_AUTO)
-                        m = arg_read_only && arg_volatile_mode != VOLATILE_YES ? TIMEZONE_BIND : TIMEZONE_SYMLINK;
+                        m = arg_read_only && IN_SET(arg_volatile_mode, VOLATILE_NO, VOLATILE_STATE) ? TIMEZONE_BIND : TIMEZONE_SYMLINK;
                 else
                         m = arg_timezone;
         } else
@@ -1606,11 +1606,11 @@ static int setup_resolv_conf(const char *dest) {
                 if (arg_private_network)
                         m = RESOLV_CONF_OFF;
                 else if (have_resolv_conf(STATIC_RESOLV_CONF) > 0 && resolved_listening() > 0)
-                        m = arg_read_only && arg_volatile_mode != VOLATILE_YES ? RESOLV_CONF_BIND_STATIC : RESOLV_CONF_COPY_STATIC;
+                        m = arg_read_only && IN_SET(arg_volatile_mode, VOLATILE_NO, VOLATILE_STATE) ? RESOLV_CONF_BIND_STATIC : RESOLV_CONF_COPY_STATIC;
                 else if (have_resolv_conf("/etc/resolv.conf") > 0)
-                        m = arg_read_only && arg_volatile_mode != VOLATILE_YES ? RESOLV_CONF_BIND_HOST : RESOLV_CONF_COPY_HOST;
+                        m = arg_read_only && IN_SET(arg_volatile_mode, VOLATILE_NO, VOLATILE_STATE) ? RESOLV_CONF_BIND_HOST : RESOLV_CONF_COPY_HOST;
                 else
-                        m = arg_read_only && arg_volatile_mode != VOLATILE_YES ? RESOLV_CONF_OFF : RESOLV_CONF_DELETE;
+                        m = arg_read_only && IN_SET(arg_volatile_mode, VOLATILE_NO, VOLATILE_STATE) ? RESOLV_CONF_OFF : RESOLV_CONF_DELETE;
         } else
                 m = arg_resolv_conf;
 
index 4d75bc0e96e2eb0556f83e6bd93b0f0106439701..917ebfa4e43844530735812af6e288d48df4c026 100644 (file)
@@ -39,6 +39,7 @@ static const char* const volatile_mode_table[_VOLATILE_MODE_MAX] = {
         [VOLATILE_NO] = "no",
         [VOLATILE_YES] = "yes",
         [VOLATILE_STATE] = "state",
+        [VOLATILE_OVERLAY] = "overlay",
 };
 
 DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(volatile_mode, VolatileMode, VOLATILE_YES);
index 8761c44ab8553fe25c4d6509d618c84826515495..2d31bb11749d339a1b1d918663e5f4bf17c6ed08 100644 (file)
@@ -5,6 +5,7 @@ typedef enum VolatileMode {
         VOLATILE_NO,
         VOLATILE_YES,
         VOLATILE_STATE,
+        VOLATILE_OVERLAY,
         _VOLATILE_MODE_MAX,
         _VOLATILE_MODE_INVALID = -1
 } VolatileMode;