]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
nspawn: drop cgroup v1 handling
authorMike Yuan <me@yhndnzj.com>
Sun, 16 Mar 2025 17:47:45 +0000 (18:47 +0100)
committerMike Yuan <me@yhndnzj.com>
Fri, 4 Apr 2025 12:36:11 +0000 (14:36 +0200)
docs/ENVIRONMENT.md
src/nspawn/meson.build
src/nspawn/nspawn-cgroup.c
src/nspawn/nspawn-cgroup.h
src/nspawn/nspawn-mount.h
src/nspawn/nspawn-util.c [deleted file]
src/nspawn/nspawn-util.h [deleted file]
src/nspawn/nspawn.c
src/nspawn/test-nspawn-util.c [deleted file]
test/units/TEST-13-NSPAWN.nspawn.sh

index 55f6d22b49e817b5f86fd3548cbc93c40e8c6691..c2ea147738066864b488a21e118a58b613f1b677 100644 (file)
@@ -150,9 +150,6 @@ All tools:
 
 `systemd-nspawn`:
 
-* `$SYSTEMD_NSPAWN_UNIFIED_HIERARCHY=1` — if set, force `systemd-nspawn` into
-  unified cgroup hierarchy mode.
-
 * `$SYSTEMD_NSPAWN_API_VFS_WRITABLE=1` — if set, make `/sys/`, `/proc/sys/`,
   and friends writable in the container. If set to "network", leave only
   `/proc/sys/net/` writable.
index b995e69cb3ff30ce0ae29477546f9e773959e747..bad408207abae09c8eda8b29ce06504523d028f2 100644 (file)
@@ -16,7 +16,6 @@ libnspawn_core_sources = files(
         'nspawn-settings.c',
         'nspawn-setuid.c',
         'nspawn-stub-pid1.c',
-        'nspawn-util.c',
 )
 
 nspawn_gperf_c = custom_target(
@@ -64,10 +63,6 @@ executables += [
                 'sources' : files('test-nspawn-tables.c'),
                 'conditions' : ['ENABLE_NSPAWN'],
         },
-        nspawn_test_template + {
-                'sources' : files('test-nspawn-util.c'),
-                'conditions' : ['ENABLE_NSPAWN'],
-        },
         nspawn_fuzz_template + {
                 'sources' : files('fuzz-nspawn-settings.c'),
                 'conditions' : ['ENABLE_NSPAWN'],
index 4ee21c07790854ffc2256845056c833eb0f832d5..8f246fa958d01be32e6ebbc16627f0ce9f8be22d 100644 (file)
@@ -5,32 +5,27 @@
 #include "alloc-util.h"
 #include "cgroup-setup.h"
 #include "fd-util.h"
-#include "fileio.h"
 #include "format-util.h"
 #include "fs-util.h"
 #include "mkdir.h"
 #include "mount-util.h"
 #include "mountpoint-util.h"
 #include "nspawn-cgroup.h"
-#include "nspawn-mount.h"
 #include "nsresource.h"
 #include "path-util.h"
-#include "rm-rf.h"
 #include "string-util.h"
-#include "strv.h"
-#include "tmpfile-util.h"
-#include "user-util.h"
 
 static int chown_cgroup_path(const char *path, uid_t uid_shift) {
         _cleanup_close_ int fd = -EBADF;
 
-        fd = open(path, O_RDONLY|O_CLOEXEC|O_DIRECTORY);
+        assert(path);
+
+        fd = open(path, O_PATH|O_CLOEXEC|O_DIRECTORY);
         if (fd < 0)
                 return -errno;
 
         FOREACH_STRING(fn,
                        ".",
-                       "cgroup.clone_children",
                        "cgroup.controllers",
                        "cgroup.events",
                        "cgroup.procs",
@@ -38,95 +33,27 @@ static int chown_cgroup_path(const char *path, uid_t uid_shift) {
                        "cgroup.subtree_control",
                        "cgroup.threads",
                        "memory.oom.group",
-                       "memory.reclaim",
-                       "notify_on_release",
-                       "tasks")
+                       "memory.reclaim")
                 if (fchownat(fd, fn, uid_shift, uid_shift, 0) < 0)
-                        log_full_errno(errno == ENOENT ? LOG_DEBUG :  LOG_WARNING, errno,
+                        log_full_errno(errno == ENOENT ? LOG_DEBUG : LOG_WARNING, errno,
                                        "Failed to chown \"%s/%s\", ignoring: %m", path, fn);
 
         return 0;
 }
 
-int sync_cgroup(pid_t pid, CGroupUnified unified_requested, uid_t uid_shift) {
-        _cleanup_(rmdir_and_freep) char *tree = NULL;
-        _cleanup_free_ char *cgroup = NULL;
-        char pid_string[DECIMAL_STR_MAX(pid) + 1];
-        bool undo_mount = false;
-        const char *fn;
-        int r, unified_controller;
-
-        unified_controller = cg_unified_controller(SYSTEMD_CGROUP_CONTROLLER);
-        if (unified_controller < 0)
-                return log_error_errno(unified_controller, "Failed to determine whether the systemd hierarchy is unified: %m");
-        if ((unified_controller > 0) == (unified_requested >= CGROUP_UNIFIED_SYSTEMD))
-                return 0;
-
-        /* When the host uses the legacy cgroup setup, but the
-         * container shall use the unified hierarchy, let's make sure
-         * we copy the path from the name=systemd hierarchy into the
-         * unified hierarchy. Similar for the reverse situation. */
-
-        r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, pid, &cgroup);
-        if (r < 0)
-                return log_error_errno(r, "Failed to get control group of " PID_FMT ": %m", pid);
-
-        /* In order to access the unified hierarchy we need to mount it */
-        r = mkdtemp_malloc("/tmp/unifiedXXXXXX", &tree);
-        if (r < 0)
-                return log_error_errno(r, "Failed to generate temporary mount point for unified hierarchy: %m");
-
-        if (unified_controller > 0)
-                r = mount_nofollow_verbose(LOG_ERR, "cgroup", tree, "cgroup",
-                                           MS_NOSUID|MS_NOEXEC|MS_NODEV, "none,name=systemd,xattr");
-        else
-                r = mount_nofollow_verbose(LOG_ERR, "cgroup", tree, "cgroup2",
-                                           MS_NOSUID|MS_NOEXEC|MS_NODEV, NULL);
-        if (r < 0)
-                goto finish;
-
-        undo_mount = true;
-
-        /* If nspawn dies abruptly the cgroup hierarchy created below
-         * its unit isn't cleaned up. So, let's remove it
-         * https://github.com/systemd/systemd/pull/4223#issuecomment-252519810 */
-        fn = strjoina(tree, cgroup);
-        (void) rm_rf(fn, REMOVE_ROOT|REMOVE_ONLY_DIRECTORIES);
-
-        fn = strjoina(tree, cgroup, "/cgroup.procs");
-
-        sprintf(pid_string, PID_FMT, pid);
-        r = write_string_file(fn, pid_string, WRITE_STRING_FILE_DISABLE_BUFFER|WRITE_STRING_FILE_MKDIR_0755);
-        if (r < 0) {
-                log_error_errno(r, "Failed to move process: %m");
-                goto finish;
-        }
-
-        fn = strjoina(tree, cgroup);
-        r = chown_cgroup_path(fn, uid_shift);
-        if (r < 0)
-                log_error_errno(r, "Failed to chown() cgroup %s: %m", fn);
-finish:
-        if (undo_mount)
-                (void) umount_verbose(LOG_ERR, tree, UMOUNT_NOFOLLOW);
-
-        return r;
-}
-
 int create_subcgroup(
                 pid_t pid,
                 bool keep_unit,
-                CGroupUnified unified_requested,
                 uid_t uid_shift,
                 int userns_fd,
                 UserNamespaceMode userns_mode) {
 
         _cleanup_free_ char *cgroup = NULL, *payload = NULL;
         CGroupMask supported;
-        char *e;
         int r;
 
         assert(pid > 1);
+        assert((userns_fd >= 0) == (userns_mode == USER_NAMESPACE_MANAGED));
 
         /* In the unified hierarchy inner nodes may only contain subgroups, but not processes. Hence, if we running in
          * the unified hierarchy and the container does the same, and we did not create a scope unit for the container
@@ -136,12 +63,7 @@ int create_subcgroup(
          * its attributes), while the host systemd will only delegate cgroups for children of the cgroup created for a
          * delegation unit, instead of the cgroup itself. This means, if we'd pass on the cgroup allocated from the
          * host systemd directly to the payload, the host and payload systemd might fight for the cgroup
-         * attributes. Hence, let's insert an intermediary cgroup to cover that case too.
-         *
-         * Note that we only bother with the main hierarchy here, not with any secondary ones. On the unified setup
-         * that's fine because there's only one hierarchy anyway and controllers are enabled directly on it. On the
-         * legacy setup, this is fine too, since delegation of controllers is generally not safe there, hence we won't
-         * do it. */
+         * attributes. Hence, let's insert an intermediary cgroup to cover that case too. */
 
         r = cg_mask_supported(&supported);
         if (r < 0)
@@ -155,7 +77,7 @@ int create_subcgroup(
                 return log_error_errno(r, "Failed to get our control group: %m");
 
         /* If the service manager already placed us in the supervisor cgroup, let's handle that. */
-        e = endswith(cgroup, "/supervisor");
+        char *e = endswith(cgroup, "/supervisor");
         if (e)
                 *e = 0; /* chop off, we want the main path delegated to us */
 
@@ -170,17 +92,7 @@ int create_subcgroup(
         if (r < 0)
                 return log_error_errno(r, "Failed to create %s subcgroup: %m", payload);
 
-        if (userns_mode != USER_NAMESPACE_MANAGED) {
-                _cleanup_free_ char *fs = NULL;
-                r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, payload, NULL, &fs);
-                if (r < 0)
-                        return log_error_errno(r, "Failed to get file system path for container cgroup: %m");
-
-                r = chown_cgroup_path(fs, uid_shift);
-                if (r < 0)
-                        return log_error_errno(r, "Failed to chown() cgroup %s: %m", fs);
-
-        } else if (userns_fd >= 0) {
+        if (userns_mode == USER_NAMESPACE_MANAGED) {
                 _cleanup_close_ int cgroup_fd = -EBADF;
 
                 cgroup_fd = cg_path_open(SYSTEMD_CGROUP_CONTROLLER, payload);
@@ -194,19 +106,15 @@ int create_subcgroup(
                 r = nsresource_add_cgroup(userns_fd, cgroup_fd);
                 if (r < 0)
                         return log_error_errno(r, "Failed to add cgroup %s to userns: %m", payload);
-        }
-
-        if (unified_requested == CGROUP_UNIFIED_SYSTEMD || (unified_requested == CGROUP_UNIFIED_NONE && cg_unified_controller(SYSTEMD_CGROUP_CONTROLLER) > 0)) {
-                _cleanup_free_ char *lfs = NULL;
-                /* Always propagate access rights from unified to legacy controller */
-
-                r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER_LEGACY, payload, NULL, &lfs);
+        } else {
+                _cleanup_free_ char *fs = NULL;
+                r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, payload, NULL, &fs);
                 if (r < 0)
                         return log_error_errno(r, "Failed to get file system path for container cgroup: %m");
 
-                r = chown_cgroup_path(lfs, uid_shift);
+                r = chown_cgroup_path(fs, uid_shift);
                 if (r < 0)
-                        return log_error_errno(r, "Failed to chown() cgroup %s: %m", lfs);
+                        return log_error_errno(r, "Failed to chown() cgroup %s: %m", fs);
         }
 
         if (keep_unit) {
@@ -225,325 +133,10 @@ int create_subcgroup(
         return 0;
 }
 
-/* Retrieve existing subsystems. This function is called in a new cgroup
- * namespace.
- */
-static int get_process_controllers(Set **ret) {
-        _cleanup_set_free_ Set *controllers = NULL;
-        _cleanup_fclose_ FILE *f = NULL;
-        int r;
-
-        assert(ret);
-
-        f = fopen("/proc/self/cgroup", "re");
-        if (!f)
-                return errno == ENOENT ? -ESRCH : -errno;
-
-        for (;;) {
-                _cleanup_free_ char *line = NULL;
-                char *e, *l;
-
-                r = read_line(f, LONG_LINE_MAX, &line);
-                if (r < 0)
-                        return r;
-                if (r == 0)
-                        break;
-
-                l = strchr(line, ':');
-                if (!l)
-                        continue;
-
-                l++;
-                e = strchr(l, ':');
-                if (!e)
-                        continue;
-
-                *e = 0;
-
-                if (STR_IN_SET(l, "", "name=systemd", "name=unified"))
-                        continue;
-
-                r = set_put_strdup(&controllers, l);
-                if (r < 0)
-                        return r;
-        }
-
-        *ret = TAKE_PTR(controllers);
-
-        return 0;
-}
-
-static int mount_legacy_cgroup_hierarchy(
-                const char *dest,
-                const char *controller,
-                const char *hierarchy,
-                bool read_only) {
-
-        const char *to, *fstype, *opts;
-        int r;
-
-        to = strjoina(strempty(dest), "/sys/fs/cgroup/", hierarchy);
-
-        r = path_is_mount_point_full(to, dest, /* flags = */ 0);
-        if (r < 0 && r != -ENOENT)
-                return log_error_errno(r, "Failed to determine if %s is mounted already: %m", to);
-        if (r > 0)
-                return 0;
-
-        (void) mkdir_p(to, 0755);
-
-        /* The superblock mount options of the mount point need to be
-         * identical to the hosts', and hence writable... */
-        if (streq(controller, SYSTEMD_CGROUP_CONTROLLER_HYBRID)) {
-                fstype = "cgroup2";
-                opts = NULL;
-        } else if (streq(controller, SYSTEMD_CGROUP_CONTROLLER_LEGACY)) {
-                fstype = "cgroup";
-                opts = "none,name=systemd,xattr";
-        } else {
-                fstype = "cgroup";
-                opts = controller;
-        }
-
-        r = mount_nofollow_verbose(LOG_ERR, "cgroup", to, fstype, MS_NOSUID|MS_NOEXEC|MS_NODEV, opts);
-        if (r < 0)
-                return r;
-
-        /* ... hence let's only make the bind mount read-only, not the superblock. */
-        if (read_only) {
-                r = mount_nofollow_verbose(LOG_ERR, NULL, to, NULL,
-                                           MS_BIND|MS_REMOUNT|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_RDONLY, NULL);
-                if (r < 0)
-                        return r;
-        }
-
-        return 1;
-}
-
-/* Mount a legacy cgroup hierarchy when cgroup namespaces are supported. */
-static int mount_legacy_cgns_supported(
-                const char *dest,
-                CGroupUnified unified_requested,
-                bool userns,
-                uid_t uid_shift,
-                uid_t uid_range,
-                const char *selinux_apifs_context) {
-
-        _cleanup_set_free_ Set *controllers = NULL;
-        const char *cgroup_root = "/sys/fs/cgroup", *c;
-        int r;
-
-        (void) mkdir_p(cgroup_root, 0755);
-
-        /* Mount a tmpfs to /sys/fs/cgroup if it's not mounted there yet. */
-        r = path_is_mount_point_full(cgroup_root, dest, AT_SYMLINK_FOLLOW);
-        if (r < 0)
-                return log_error_errno(r, "Failed to determine if /sys/fs/cgroup is already mounted: %m");
-        if (r == 0) {
-                _cleanup_free_ char *options = NULL;
-
-                /* When cgroup namespaces are enabled and user namespaces are
-                 * used then the mount of the cgroupfs is done *inside* the new
-                 * user namespace. We're root in the new user namespace and the
-                 * kernel will happily translate our uid/gid to the correct
-                 * uid/gid as seen from e.g. /proc/1/mountinfo. So we simply
-                 * pass uid 0 and not uid_shift to tmpfs_patch_options().
-                 */
-                r = tmpfs_patch_options("mode=0755" TMPFS_LIMITS_SYS_FS_CGROUP, 0, selinux_apifs_context, &options);
-                if (r < 0)
-                        return log_oom();
-
-                r = mount_nofollow_verbose(LOG_ERR, "tmpfs", cgroup_root, "tmpfs",
-                                           MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME, options);
-                if (r < 0)
-                        return r;
-        }
-
-        r = cg_all_unified();
-        if (r < 0)
-                return r;
-        if (r > 0)
-                goto skip_controllers;
-
-        r = get_process_controllers(&controllers);
-        if (r < 0)
-                return log_error_errno(r, "Failed to determine cgroup controllers: %m");
-
-        for (;;) {
-                _cleanup_free_ const char *controller = NULL;
-
-                controller = set_steal_first(controllers);
-                if (!controller)
-                        break;
-
-                r = mount_legacy_cgroup_hierarchy("", controller, controller, !userns);
-                if (r < 0)
-                        return r;
-
-                /* When multiple hierarchies are co-mounted, make their
-                 * constituting individual hierarchies a symlink to the
-                 * co-mount.
-                 */
-                c = controller;
-                for (;;) {
-                        _cleanup_free_ char *target = NULL, *tok = NULL;
-
-                        r = extract_first_word(&c, &tok, ",", 0);
-                        if (r < 0)
-                                return log_error_errno(r, "Failed to extract co-mounted cgroup controller: %m");
-                        if (r == 0)
-                                break;
-
-                        if (streq(controller, tok))
-                                break;
-
-                        target = path_join("/sys/fs/cgroup/", tok);
-                        if (!target)
-                                return log_oom();
-
-                        r = symlink_idempotent(controller, target, false);
-                        if (r == -EINVAL)
-                                return log_error_errno(r, "Invalid existing symlink for combined hierarchy: %m");
-                        if (r < 0)
-                                return log_error_errno(r, "Failed to create symlink for combined hierarchy: %m");
-                }
-        }
-
-skip_controllers:
-        if (unified_requested >= CGROUP_UNIFIED_SYSTEMD) {
-                r = mount_legacy_cgroup_hierarchy("", SYSTEMD_CGROUP_CONTROLLER_HYBRID, "unified", false);
-                if (r < 0)
-                        return r;
-        }
-
-        r = mount_legacy_cgroup_hierarchy("", SYSTEMD_CGROUP_CONTROLLER_LEGACY, "systemd", false);
-        if (r < 0)
-                return r;
-
-        if (!userns)
-                return mount_nofollow_verbose(LOG_ERR, NULL, cgroup_root, NULL,
-                                              MS_REMOUNT|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME|MS_RDONLY,
-                                              "mode=0755");
-
-        return 0;
-}
-
-/* Mount legacy cgroup hierarchy when cgroup namespaces are unsupported. */
-static int mount_legacy_cgns_unsupported(
-                const char *dest,
-                CGroupUnified unified_requested,
-                bool userns,
-                uid_t uid_shift,
-                uid_t uid_range,
-                const char *selinux_apifs_context) {
-
-        _cleanup_set_free_ Set *controllers = NULL;
-        const char *cgroup_root;
-        int r;
-
-        cgroup_root = prefix_roota(dest, "/sys/fs/cgroup");
-
-        (void) mkdir_p(cgroup_root, 0755);
-
-        /* Mount a tmpfs to /sys/fs/cgroup if it's not mounted there yet. */
-        r = path_is_mount_point_full(cgroup_root, dest, AT_SYMLINK_FOLLOW);
-        if (r < 0)
-                return log_error_errno(r, "Failed to determine if /sys/fs/cgroup is already mounted: %m");
-        if (r == 0) {
-                _cleanup_free_ char *options = NULL;
-
-                r = tmpfs_patch_options("mode=0755" TMPFS_LIMITS_SYS_FS_CGROUP,
-                                        uid_shift == 0 ? UID_INVALID : uid_shift,
-                                        selinux_apifs_context,
-                                        &options);
-                if (r < 0)
-                        return log_oom();
-
-                r = mount_nofollow_verbose(LOG_ERR, "tmpfs", cgroup_root, "tmpfs",
-                                           MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME, options);
-                if (r < 0)
-                        return r;
-        }
-
-        r = cg_all_unified();
-        if (r < 0)
-                return r;
-        if (r > 0)
-                goto skip_controllers;
-
-        r = cg_kernel_controllers(&controllers);
-        if (r < 0)
-                return log_error_errno(r, "Failed to determine cgroup controllers: %m");
-
-        for (;;) {
-                _cleanup_free_ char *controller = NULL, *origin = NULL, *combined = NULL;
-
-                controller = set_steal_first(controllers);
-                if (!controller)
-                        break;
-
-                origin = path_join("/sys/fs/cgroup/", controller);
-                if (!origin)
-                        return log_oom();
-
-                r = readlink_malloc(origin, &combined);
-                if (r == -EINVAL) {
-                        /* Not a symbolic link, but directly a single cgroup hierarchy */
-
-                        r = mount_legacy_cgroup_hierarchy(dest, controller, controller, true);
-                        if (r < 0)
-                                return r;
-
-                } else if (r < 0)
-                        return log_error_errno(r, "Failed to read link %s: %m", origin);
-                else {
-                        _cleanup_free_ char *target = NULL;
-
-                        target = path_join(dest, origin);
-                        if (!target)
-                                return log_oom();
-
-                        /* A symbolic link, a combination of controllers in one hierarchy */
-
-                        if (!filename_is_valid(combined)) {
-                                log_warning("Ignoring invalid combined hierarchy %s.", combined);
-                                continue;
-                        }
-
-                        r = mount_legacy_cgroup_hierarchy(dest, combined, combined, true);
-                        if (r < 0)
-                                return r;
-
-                        r = symlink_idempotent(combined, target, false);
-                        if (r == -EINVAL)
-                                return log_error_errno(r, "Invalid existing symlink for combined hierarchy: %m");
-                        if (r < 0)
-                                return log_error_errno(r, "Failed to create symlink for combined hierarchy: %m");
-                }
-        }
-
-skip_controllers:
-        if (unified_requested >= CGROUP_UNIFIED_SYSTEMD) {
-                r = mount_legacy_cgroup_hierarchy(dest, SYSTEMD_CGROUP_CONTROLLER_HYBRID, "unified", false);
-                if (r < 0)
-                        return r;
-        }
-
-        r = mount_legacy_cgroup_hierarchy(dest, SYSTEMD_CGROUP_CONTROLLER_LEGACY, "systemd", false);
-        if (r < 0)
-                return r;
-
-        return mount_nofollow_verbose(LOG_ERR, NULL, cgroup_root, NULL,
-                                      MS_REMOUNT|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME|MS_RDONLY,
-                                      "mode=0755");
-}
-
-static int mount_unified_cgroups(const char *dest) {
+int mount_cgroups(const char *dest) {
         const char *p;
         int r;
 
-        assert(dest);
-
         p = prefix_roota(dest, "/sys/fs/cgroup");
 
         (void) mkdir_p(p, 0755);
@@ -552,8 +145,7 @@ static int mount_unified_cgroups(const char *dest) {
         if (r < 0)
                 return log_error_errno(r, "Failed to determine if %s is mounted already: %m", p);
         if (r > 0) {
-                p = prefix_roota(dest, "/sys/fs/cgroup/cgroup.procs");
-                if (access(p, F_OK) >= 0)
+                if (access(strjoina(p, "/cgroup.procs"), F_OK) >= 0)
                         return 0;
                 if (errno != ENOENT)
                         return log_error_errno(errno, "Failed to determine if mount point %s contains the unified cgroup hierarchy: %m", p);
@@ -565,48 +157,11 @@ static int mount_unified_cgroups(const char *dest) {
         return mount_nofollow_verbose(LOG_ERR, "cgroup", p, "cgroup2", MS_NOSUID|MS_NOEXEC|MS_NODEV, NULL);
 }
 
-int mount_cgroups(
-                const char *dest,
-                CGroupUnified unified_requested,
-                bool userns,
-                uid_t uid_shift,
-                uid_t uid_range,
-                const char *selinux_apifs_context,
-                bool use_cgns) {
-
-        if (unified_requested >= CGROUP_UNIFIED_ALL)
-                return mount_unified_cgroups(dest);
-        if (use_cgns)
-                return mount_legacy_cgns_supported(dest, unified_requested, userns, uid_shift, uid_range, selinux_apifs_context);
-
-        return mount_legacy_cgns_unsupported(dest, unified_requested, userns, uid_shift, uid_range, selinux_apifs_context);
-}
-
-static int mount_systemd_cgroup_writable_one(const char *root, const char *own) {
-        int r;
-
-        assert(root);
-        assert(own);
-
-        /* Make our own cgroup a (writable) bind mount */
-        r = mount_nofollow_verbose(LOG_ERR, own, own, NULL, MS_BIND, NULL);
-        if (r < 0)
-                return r;
-
-        /* And then remount the systemd cgroup root read-only */
-        return mount_nofollow_verbose(LOG_ERR, NULL, root, NULL,
-                                      MS_BIND|MS_REMOUNT|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_RDONLY, NULL);
-}
-
-int mount_systemd_cgroup_writable(
-                const char *dest,
-                CGroupUnified unified_requested) {
-
+int bind_mount_cgroup_hierarchy(void) {
         _cleanup_free_ char *own_cgroup_path = NULL;
-        const char *root, *own;
         int r;
 
-        assert(dest);
+        /* NB: This must be called from the inner child, with /sys/fs/cgroup/ being a bind mount in mountns! */
 
         r = cg_pid_get_path(NULL, 0, &own_cgroup_path);
         if (r < 0)
@@ -616,25 +171,14 @@ int mount_systemd_cgroup_writable(
         if (path_equal(own_cgroup_path, "/"))
                 return 0;
 
-        if (unified_requested >= CGROUP_UNIFIED_ALL) {
-
-                root = prefix_roota(dest, "/sys/fs/cgroup");
-                own = strjoina(root, own_cgroup_path);
+        const char *p = strjoina("/sys/fs/cgroup", own_cgroup_path);
 
-        } else {
-
-                if (unified_requested >= CGROUP_UNIFIED_SYSTEMD) {
-                        root = prefix_roota(dest, "/sys/fs/cgroup/unified");
-                        own = strjoina(root, own_cgroup_path);
-
-                        r = mount_systemd_cgroup_writable_one(root, own);
-                        if (r < 0)
-                                return r;
-                }
-
-                root = prefix_roota(dest, "/sys/fs/cgroup/systemd");
-                own = strjoina(root, own_cgroup_path);
-        }
+        /* Make our own cgroup a (writable) bind mount */
+        r = mount_nofollow_verbose(LOG_ERR, p, p, NULL, MS_BIND, NULL);
+        if (r < 0)
+                return r;
 
-        return mount_systemd_cgroup_writable_one(root, own);
+        /* And then remount the systemd cgroup root read-only */
+        return mount_nofollow_verbose(LOG_ERR, NULL, "/sys/fs/cgroup", NULL,
+                                      MS_BIND|MS_REMOUNT|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_RDONLY, NULL);
 }
index 8f039ffb283f675c1138506f9779c08a2efe323f..92f473c1d7a29fcca3720b76ba2655e6c2fc711d 100644 (file)
@@ -4,11 +4,14 @@
 #include <stdbool.h>
 #include <sys/types.h>
 
-#include "cgroup-util.h"
 #include "nspawn-settings.h"
 
-int sync_cgroup(pid_t pid, CGroupUnified unified_requested, uid_t uid_shift);
-int create_subcgroup(pid_t pid, bool keep_unit, CGroupUnified unified_requested, uid_t uid_shift, int userns_fd, UserNamespaceMode userns_mode);
+int create_subcgroup(
+                pid_t pid,
+                bool keep_unit,
+                uid_t uid_shift,
+                int userns_fd,
+                UserNamespaceMode userns_mode);
 
-int mount_cgroups(const char *dest, CGroupUnified unified_requested, bool userns, uid_t uid_shift, uid_t uid_range, const char *selinux_apifs_context, bool use_cgns);
-int mount_systemd_cgroup_writable(const char *dest, CGroupUnified unified_requested);
+int mount_cgroups(const char *dest);
+int bind_mount_cgroup_hierarchy(void);
index 87b3b91c432a69e27aa7c0b835cb2ba11a6d5812..2efcd110fcd51741c4e1d4e3b9e521dcf2e992a1 100644 (file)
@@ -3,7 +3,6 @@
 
 #include <stdbool.h>
 
-#include "cgroup-util.h"
 #include "volatile-util.h"
 
 typedef enum MountSettingsMask {
diff --git a/src/nspawn/nspawn-util.c b/src/nspawn/nspawn-util.c
deleted file mode 100644 (file)
index 2cd73fe..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-
-#include "alloc-util.h"
-#include "glob-util.h"
-#include "log.h"
-#include "nspawn-util.h"
-#include "parse-util.h"
-#include "path-util.h"
-#include "string-util.h"
-
-int systemd_installation_has_version(const char *root, const char *minimal_version) {
-        bool found = false;
-        int r;
-
-        /* Try to guess if systemd installation is later than the specified version. This
-         * is hacky and likely to yield false negatives, particularly if the installation
-         * is non-standard. False positives should be relatively rare.
-         */
-
-        FOREACH_STRING(pattern,
-                       /* /lib works for systems without usr-merge, and for systems with a sane
-                        * usr-merge, where /lib is a symlink to /usr/lib. /usr/lib is necessary
-                        * for Gentoo which does a merge without making /lib a symlink.
-                        * Also support multiarch paths von Debian/Ubuntu; *-linux-* is a small
-                        * optimization based on the naming scheme of existing multiarch tuples.
-                        */
-                       "/lib/systemd/libsystemd-shared-*.so",
-                       "/lib64/systemd/libsystemd-shared-*.so",
-                       "/usr/lib/*-linux-*/systemd/libsystemd-shared-*.so",
-                       "/usr/lib/systemd/libsystemd-shared-*.so",
-                       "/usr/lib64/systemd/libsystemd-shared-*.so") {
-
-                _cleanup_strv_free_ char **names = NULL;
-                _cleanup_free_ char *path = NULL;
-                char *c;
-
-                path = path_join(root, pattern);
-                if (!path)
-                        return -ENOMEM;
-
-                r = glob_extend(&names, path, 0);
-                if (r == -ENOENT)
-                        continue;
-                if (r < 0)
-                        return r;
-
-                assert_se(c = endswith(path, "*.so"));
-                *c = '\0'; /* truncate the glob part */
-
-                STRV_FOREACH(name, names) {
-                        _cleanup_free_ char *bn = NULL;
-                        /* This is most likely to run only once, hence let's not optimize anything. */
-                        char *t, *t2;
-
-                        if (path_extract_filename(*name, &bn) < 0)
-                                continue;
-
-                        t = startswith(bn, "libsystemd-shared-");
-                        if (!t)
-                                continue;
-
-                        t2 = endswith(t, ".so");
-                        if (!t2)
-                                continue;
-                        *t2 = '\0';
-
-                        found = true;
-
-                        r = strverscmp_improved(t, minimal_version);
-                        log_debug("Found libsystemd shared at \"%s.so\", version %s (%s).",
-                                  *name, t,
-                                  r >= 0 ? "OK" : "too old");
-                        if (r >= 0)
-                                return true;
-                }
-        }
-
-        return !found ? -ENOENT : false;
-}
diff --git a/src/nspawn/nspawn-util.h b/src/nspawn/nspawn-util.h
deleted file mode 100644 (file)
index e83cd56..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-#pragma once
-
-int systemd_installation_has_version(const char *root, const char *minimal_version);
index 17b0c85185b0f95709090d7d29c17a49f101958d..4cd9cc70ae4dc8a5374aa64c171096e045db887b 100644 (file)
@@ -32,6 +32,7 @@
 #include "bus-util.h"
 #include "cap-list.h"
 #include "capability-util.h"
+#include "cgroup-setup.h"
 #include "cgroup-util.h"
 #include "chase.h"
 #include "chattr-util.h"
@@ -77,7 +78,6 @@
 #include "nspawn-settings.h"
 #include "nspawn-setuid.h"
 #include "nspawn-stub-pid1.h"
-#include "nspawn-util.h"
 #include "nspawn.h"
 #include "nsresource.h"
 #include "nulstr-util.h"
@@ -201,7 +201,6 @@ static UserNamespaceMode arg_userns_mode; /* initialized depending on arg_privil
 static uid_t arg_uid_shift = UID_INVALID, arg_uid_range = 0x10000U;
 static UserNamespaceOwnership arg_userns_ownership = _USER_NAMESPACE_OWNERSHIP_INVALID;
 static int arg_kill_signal = 0;
-static CGroupUnified arg_unified_cgroup_hierarchy = CGROUP_UNIFIED_UNKNOWN;
 static SettingsMask arg_settings_mask = 0;
 static int arg_settings_trusted = -1;
 static char **arg_parameters = NULL;
@@ -487,77 +486,6 @@ static int custom_mount_check_all(void) {
         return 0;
 }
 
-static int detect_unified_cgroup_hierarchy_from_environment(void) {
-        const char *e, *var = "SYSTEMD_NSPAWN_UNIFIED_HIERARCHY";
-        int r;
-
-        /* Allow the user to control whether the unified hierarchy is used */
-
-        e = getenv(var);
-        if (!e) {
-                /* $UNIFIED_CGROUP_HIERARCHY has been renamed to $SYSTEMD_NSPAWN_UNIFIED_HIERARCHY. */
-                var = "UNIFIED_CGROUP_HIERARCHY";
-                e = getenv(var);
-        }
-
-        if (!isempty(e)) {
-                r = parse_boolean(e);
-                if (r < 0)
-                        return log_error_errno(r, "Failed to parse $%s: %m", var);
-                if (r > 0)
-                        arg_unified_cgroup_hierarchy = CGROUP_UNIFIED_ALL;
-                else
-                        arg_unified_cgroup_hierarchy = CGROUP_UNIFIED_NONE;
-        }
-
-        return 0;
-}
-
-static int detect_unified_cgroup_hierarchy_from_image(const char *directory) {
-        int r;
-
-        if (arg_userns_mode == USER_NAMESPACE_MANAGED) {
-                /* We only support the unified mode when running unprivileged */
-                arg_unified_cgroup_hierarchy = CGROUP_UNIFIED_ALL;
-                return 0;
-        }
-
-        /* Let's inherit the mode to use from the host system, but let's take into consideration what systemd
-         * in the image actually supports. */
-        r = cg_all_unified();
-        if (r < 0)
-                return log_error_errno(r, "Failed to determine whether we are in all unified mode.");
-        if (r > 0) {
-                /* Unified cgroup hierarchy support was added in 230. Unfortunately the detection
-                 * routine only detects 231, so we'll have a false negative here for 230. If there is no
-                 * systemd installation in the container, we use the unified cgroup hierarchy. */
-                r = systemd_installation_has_version(directory, "230");
-                if (r < 0 && r != -ENOENT)
-                        return log_error_errno(r, "Failed to determine systemd version in container: %m");
-                if (r == 0)
-                        arg_unified_cgroup_hierarchy = CGROUP_UNIFIED_NONE;
-                else
-                        arg_unified_cgroup_hierarchy = CGROUP_UNIFIED_ALL;
-        } else if (cg_unified_controller(SYSTEMD_CGROUP_CONTROLLER) > 0) {
-                /* Mixed cgroup hierarchy support was added in 233. If there is no systemd installation in
-                 * the container, we use the unified cgroup hierarchy. */
-                r = systemd_installation_has_version(directory, "233");
-                if (r < 0 && r != -ENOENT)
-                        return log_error_errno(r, "Failed to determine systemd version in container: %m");
-                if (r == 0)
-                        arg_unified_cgroup_hierarchy = CGROUP_UNIFIED_NONE;
-                else
-                        arg_unified_cgroup_hierarchy = CGROUP_UNIFIED_SYSTEMD;
-        } else
-                arg_unified_cgroup_hierarchy = CGROUP_UNIFIED_NONE;
-
-        log_debug("Using %s hierarchy for container.",
-                  arg_unified_cgroup_hierarchy == CGROUP_UNIFIED_NONE ? "legacy" :
-                  arg_unified_cgroup_hierarchy == CGROUP_UNIFIED_SYSTEMD ? "hybrid" : "unified");
-
-        return 0;
-}
-
 static int parse_capability_spec(const char *spec, uint64_t *ret_mask) {
         uint64_t mask = 0;
         int r;
@@ -692,7 +620,7 @@ static int parse_environment(void) {
         else if (r != -ENXIO)
                 log_debug_errno(r, "Failed to parse $SYSTEMD_SUPPRESS_SYNC, ignoring: %m");
 
-        return detect_unified_cgroup_hierarchy_from_environment();
+        return 0;
 }
 
 static int parse_argv(int argc, char *argv[]) {
@@ -1682,25 +1610,6 @@ static int verify_arguments(void) {
         if (arg_userns_mode == USER_NAMESPACE_MANAGED && !arg_private_network)
                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Managed user namespace operation requires private networking, as otherwise /sys/ may not be mounted.");
 
-        if (arg_start_mode == START_PID2 && arg_unified_cgroup_hierarchy == CGROUP_UNIFIED_UNKNOWN) {
-                /* If we are running the stub init in the container, we don't need to look at what the init
-                 * in the container supports, because we are not using it. Let's immediately pick the right
-                 * setting based on the host system configuration.
-                 *
-                 * We only do this, if the user didn't use an environment variable to override the detection.
-                 */
-
-                r = cg_all_unified();
-                if (r < 0)
-                        return log_error_errno(r, "Failed to determine whether we are in all unified mode.");
-                if (r > 0)
-                        arg_unified_cgroup_hierarchy = CGROUP_UNIFIED_ALL;
-                else if (cg_unified_controller(SYSTEMD_CGROUP_CONTROLLER) > 0)
-                        arg_unified_cgroup_hierarchy = CGROUP_UNIFIED_SYSTEMD;
-                else
-                        arg_unified_cgroup_hierarchy = CGROUP_UNIFIED_NONE;
-        }
-
         if (!(arg_clone_ns_flags & CLONE_NEWPID) ||
             !(arg_clone_ns_flags & CLONE_NEWUTS)) {
                 arg_register = false;
@@ -3432,16 +3341,10 @@ static int inner_child(
                 r = unshare(CLONE_NEWCGROUP);
                 if (r < 0)
                         return log_error_errno(errno, "Failed to unshare cgroup namespace: %m");
-                r = mount_cgroups(
-                                "",
-                                arg_unified_cgroup_hierarchy,
-                                arg_userns_mode != USER_NAMESPACE_NO,
-                                arg_uid_shift,
-                                arg_uid_range,
-                                arg_selinux_apifs_context,
-                                true);
+
+                r = mount_cgroups(/* dest = */ NULL);
         } else
-                r = mount_systemd_cgroup_writable("", arg_unified_cgroup_hierarchy);
+                r = bind_mount_cgroup_hierarchy();
         if (r < 0)
                 return r;
 
@@ -4219,21 +4122,6 @@ static int outer_child(
                         return r;
         }
 
-        if (arg_unified_cgroup_hierarchy == CGROUP_UNIFIED_UNKNOWN) {
-                /* OK, we don't know yet which cgroup mode to use yet. Let's figure it out, and tell the parent. */
-
-                r = detect_unified_cgroup_hierarchy_from_image(directory);
-                if (r < 0)
-                        return r;
-
-                l = send(fd_outer_socket, &arg_unified_cgroup_hierarchy, sizeof(arg_unified_cgroup_hierarchy), MSG_NOSIGNAL);
-                if (l < 0)
-                        return log_error_errno(errno, "Failed to send cgroup mode: %m");
-                if (l != sizeof(arg_unified_cgroup_hierarchy))
-                        return log_error_errno(SYNTHETIC_ERRNO(EIO),
-                                               "Short write while sending cgroup mode.");
-        }
-
         r = recursive_chown(directory, chown_uid, chown_range);
         if (r < 0)
                 return r;
@@ -4329,14 +4217,7 @@ static int outer_child(
         (void) write_string_filef(p, WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_MODE_0444, SD_ID128_UUID_FORMAT_STR, SD_ID128_FORMAT_VAL(arg_uuid));
 
         if (!arg_use_cgns) {
-                r = mount_cgroups(
-                                directory,
-                                arg_unified_cgroup_hierarchy,
-                                arg_userns_mode != USER_NAMESPACE_NO,
-                                chown_uid,
-                                chown_range,
-                                arg_selinux_apifs_context,
-                                false);
+                r = mount_cgroups(directory);
                 if (r < 0)
                         return r;
         }
@@ -5378,16 +5259,6 @@ static int run_container(
                 }
         }
 
-        if (arg_unified_cgroup_hierarchy == CGROUP_UNIFIED_UNKNOWN) {
-                /* The child let us know the support cgroup mode it might have read from the image. */
-                l = recv(fd_outer_socket_pair[0], &arg_unified_cgroup_hierarchy, sizeof(arg_unified_cgroup_hierarchy), 0);
-                if (l < 0)
-                        return log_error_errno(errno, "Failed to read cgroup mode: %m");
-                if (l != sizeof(arg_unified_cgroup_hierarchy))
-                        return log_error_errno(SYNTHETIC_ERRNO(EIO), "Short read while reading cgroup mode (%zi bytes).%s",
-                                               l, l == 0 ? " The child is most likely dead." : "");
-        }
-
         /* Wait for the outer child. */
         r = wait_for_terminate_and_check("(sd-namespace)", *pid, WAIT_LOG_ABNORMAL);
         if (r < 0)
@@ -5582,17 +5453,12 @@ static int run_container(
         r = create_subcgroup(
                         *pid,
                         arg_keep_unit,
-                        arg_unified_cgroup_hierarchy,
                         arg_uid_shift,
                         userns_fd,
                         arg_userns_mode);
         if (r < 0)
                 return r;
 
-        r = sync_cgroup(*pid, arg_unified_cgroup_hierarchy, arg_uid_shift);
-        if (r < 0)
-                return r;
-
         /* Notify the child that the parent is ready with all its setup (including cgroup-ification), and
          * that the child can now hand over control to the code to run inside the container. */
         (void) barrier_place(&barrier); /* #4 */
@@ -5991,6 +5857,15 @@ static int run(int argc, char *argv[]) {
         if (arg_cleanup)
                 return do_cleanup();
 
+        r = cg_has_legacy();
+        if (r < 0)
+                goto finish;
+        if (r > 0) {
+                r = log_error_errno(SYNTHETIC_ERRNO(EPROTO),
+                                    "Detected host uses legacy cgroup v1 hierarchy, refusing.");
+                goto finish;
+        }
+
         r = cant_be_in_netns();
         if (r < 0)
                 goto finish;
@@ -6021,12 +5896,6 @@ static int run(int argc, char *argv[]) {
         if (!arg_private_network && arg_userns_mode != USER_NAMESPACE_NO && arg_uid_shift > 0)
                 arg_caps_retain &= ~(UINT64_C(1) << CAP_NET_BIND_SERVICE);
 
-        r = cg_unified(); /* initialize cache early */
-        if (r < 0) {
-                log_error_errno(r, "Failed to determine whether the unified cgroups hierarchy is used: %m");
-                goto finish;
-        }
-
         r = verify_arguments();
         if (r < 0)
                 goto finish;
@@ -6039,19 +5908,6 @@ static int run(int argc, char *argv[]) {
         if (r < 0)
                 goto finish;
 
-        /* Reapply environment settings. */
-        (void) detect_unified_cgroup_hierarchy_from_environment();
-
-        if (arg_userns_mode == USER_NAMESPACE_MANAGED) {
-                r = cg_all_unified();
-                if (r < 0) {
-                        log_error_errno(r, "Failed to determine if we are in unified cgroupv2 mode: %m");
-                        goto finish;
-                }
-                if (r == 0)
-                        return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Managed user namespace operation only supported in unified cgroupv2 mode.");
-        }
-
         /* Ignore SIGPIPE here, because we use splice() on the ptyfwd stuff and that will generate SIGPIPE if
          * the result is closed. Note that the container payload child will reset signal mask+handler anyway,
          * so just turning this off here means we only turn it off in nspawn itself, not any children. */
diff --git a/src/nspawn/test-nspawn-util.c b/src/nspawn/test-nspawn-util.c
deleted file mode 100644 (file)
index 45fc8ad..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-
-#include "nspawn-util.h"
-#include "rm-rf.h"
-#include "strv.h"
-#include "tests.h"
-#include "tmpfile-util.h"
-
-TEST(systemd_installation_has_version) {
-        int r;
-
-        FOREACH_STRING(version, "0", "231", PROJECT_VERSION_FULL, "999") {
-                r = systemd_installation_has_version(saved_argv[1], version);
-                /* The build environment may not have a systemd installation. */
-                if (r == -ENOENT)
-                        continue;
-                ASSERT_OK(r);
-                log_info("%s has systemd >= %s: %s",
-                         saved_argv[1] ?: "Current installation", version, yes_no(r));
-        }
-
-        _cleanup_(rm_rf_physical_and_freep) char *t = NULL;
-        ASSERT_OK(mkdtemp_malloc(NULL, &t));
-
-        ASSERT_ERROR(systemd_installation_has_version(t, PROJECT_VERSION_FULL), ENOENT);
-}
-
-/* This program can be called with a path to an installation root.
- * For example: build/test-nspawn-util /var/lib/machines/rawhide
- */
-DEFINE_TEST_MAIN(LOG_DEBUG);
index 50f54368c7c79e0fbb01f13ca28cb34838d25ac3..22b1abd57ceeb499305c88843f22ca13162a4394 100755 (executable)
@@ -49,15 +49,6 @@ at_exit() {
 
 trap at_exit EXIT
 
-# check cgroup-v2
-IS_CGROUPSV2_SUPPORTED=no
-mkdir -p /tmp/cgroup2
-if mount -t cgroup2 cgroup2 /tmp/cgroup2; then
-    IS_CGROUPSV2_SUPPORTED=yes
-    umount /tmp/cgroup2
-fi
-rmdir /tmp/cgroup2
-
 # check cgroup namespaces
 IS_CGNS_SUPPORTED=no
 if [[ -f /proc/1/ns/cgroup ]]; then
@@ -880,36 +871,30 @@ EOF
 }
 
 matrix_run_one() {
-    local cgroupsv2="${1:?}"
-    local use_cgns="${2:?}"
-    local api_vfs_writable="${3:?}"
+    local use_cgns="${1:?}"
+    local api_vfs_writable="${2:?}"
     local root
 
-    if [[ "$cgroupsv2" == "yes" && "$IS_CGROUPSV2_SUPPORTED" == "no" ]]; then
-        echo >&2 "Unified cgroup hierarchy is not supported, skipping..."
-        return 0
-    fi
-
     if [[ "$use_cgns" == "yes" && "$IS_CGNS_SUPPORTED" == "no" ]];  then
         echo >&2 "CGroup namespaces are not supported, skipping..."
         return 0
     fi
 
-    root="$(mktemp -d "/var/lib/machines/TEST-13-NSPAWN.unified-$1-cgns-$2-api-vfs-writable-$3.XXX")"
+    root="$(mktemp -d "/var/lib/machines/TEST-13-NSPAWN.cgns-$1-api-vfs-writable-$2.XXX")"
     create_dummy_container "$root"
 
-    SYSTEMD_NSPAWN_UNIFIED_HIERARCHY="$cgroupsv2" SYSTEMD_NSPAWN_USE_CGNS="$use_cgns" SYSTEMD_NSPAWN_API_VFS_WRITABLE="$api_vfs_writable" \
+    SYSTEMD_NSPAWN_USE_CGNS="$use_cgns" SYSTEMD_NSPAWN_API_VFS_WRITABLE="$api_vfs_writable" \
         systemd-nspawn --register=no \
                        --directory="$root" \
                        --boot
 
-    SYSTEMD_NSPAWN_UNIFIED_HIERARCHY="$cgroupsv2" SYSTEMD_NSPAWN_USE_CGNS="$use_cgns" SYSTEMD_NSPAWN_API_VFS_WRITABLE="$api_vfs_writable" \
+    SYSTEMD_NSPAWN_USE_CGNS="$use_cgns" SYSTEMD_NSPAWN_API_VFS_WRITABLE="$api_vfs_writable" \
         systemd-nspawn --register=no \
                        --directory="$root" \
                        --private-network \
                        --boot
 
-    if SYSTEMD_NSPAWN_UNIFIED_HIERARCHY="$cgroupsv2" SYSTEMD_NSPAWN_USE_CGNS="$use_cgns" SYSTEMD_NSPAWN_API_VFS_WRITABLE="$api_vfs_writable" \
+    if SYSTEMD_NSPAWN_USE_CGNS="$use_cgns" SYSTEMD_NSPAWN_API_VFS_WRITABLE="$api_vfs_writable" \
         systemd-nspawn --register=no \
                        --directory="$root" \
                        --private-users=pick \
@@ -919,7 +904,7 @@ matrix_run_one() {
         [[ "$IS_USERNS_SUPPORTED" == "no" && "$api_vfs_writable" == "network" ]] && return 1
     fi
 
-    if SYSTEMD_NSPAWN_UNIFIED_HIERARCHY="$cgroupsv2" SYSTEMD_NSPAWN_USE_CGNS="$use_cgns" SYSTEMD_NSPAWN_API_VFS_WRITABLE="$api_vfs_writable" \
+    if SYSTEMD_NSPAWN_USE_CGNS="$use_cgns" SYSTEMD_NSPAWN_API_VFS_WRITABLE="$api_vfs_writable" \
         systemd-nspawn --register=no \
                        --directory="$root" \
                        --private-network \
@@ -945,7 +930,7 @@ matrix_run_one() {
     # --network-namespace-path and network-related options cannot be used together
     for net_opt in "${net_opts[@]}"; do
         echo "$netns_opt in combination with $net_opt should fail"
-        if SYSTEMD_NSPAWN_UNIFIED_HIERARCHY="$cgroupsv2" SYSTEMD_NSPAWN_USE_CGNS="$use_cgns" SYSTEMD_NSPAWN_API_VFS_WRITABLE="$api_vfs_writable" \
+        if SYSTEMD_NSPAWN_USE_CGNS="$use_cgns" SYSTEMD_NSPAWN_API_VFS_WRITABLE="$api_vfs_writable" \
             systemd-nspawn --register=no \
                            --directory="$root" \
                            --boot \
@@ -957,7 +942,7 @@ matrix_run_one() {
     done
 
     # allow combination of --network-namespace-path and --private-network
-    SYSTEMD_NSPAWN_UNIFIED_HIERARCHY="$cgroupsv2" SYSTEMD_NSPAWN_USE_CGNS="$use_cgns" SYSTEMD_NSPAWN_API_VFS_WRITABLE="$api_vfs_writable" \
+    SYSTEMD_NSPAWN_USE_CGNS="$use_cgns" SYSTEMD_NSPAWN_API_VFS_WRITABLE="$api_vfs_writable" \
         systemd-nspawn --register=no \
                        --directory="$root" \
                        --boot \
@@ -967,7 +952,7 @@ matrix_run_one() {
     # test --network-namespace-path works with a network namespace created by "ip netns"
     ip netns add nspawn_test
     netns_opt="--network-namespace-path=/run/netns/nspawn_test"
-    SYSTEMD_NSPAWN_UNIFIED_HIERARCHY="$cgroupsv2" SYSTEMD_NSPAWN_USE_CGNS="$use_cgns" SYSTEMD_NSPAWN_API_VFS_WRITABLE="$api_vfs_writable" \
+    SYSTEMD_NSPAWN_USE_CGNS="$use_cgns" SYSTEMD_NSPAWN_API_VFS_WRITABLE="$api_vfs_writable" \
         systemd-nspawn --register=no \
                        --directory="$root" \
                        --network-namespace-path=/run/netns/nspawn_test \
@@ -983,10 +968,8 @@ testcase_api_vfs() {
     local api_vfs_writable
 
     for api_vfs_writable in yes no network; do
-        matrix_run_one no  no  $api_vfs_writable
-        matrix_run_one yes no  $api_vfs_writable
-        matrix_run_one no  yes $api_vfs_writable
-        matrix_run_one yes yes $api_vfs_writable
+        matrix_run_one no  $api_vfs_writable
+        matrix_run_one yes $api_vfs_writable
     done
 }