From 2ea8175b3d8ec118fa0f42392485ce0f4308456a Mon Sep 17 00:00:00 2001
From: licunlong <licunlong1@huawei.com>
Date: Thu, 6 May 2021 09:38:54 +0800
Subject: [PATCH] core-cgroup: support cpuset

This patch add support for cpuset subsystem.
---
 meson.build                                   |  2 +
 meson_options.txt                             |  3 +
 src/basic/cgroup-util.c                       |  3 +-
 src/basic/cgroup-util.h                       | 14 ++-
 src/basic/string-util.c                       | 42 +++++++++
 src/basic/string-util.h                       |  2 +
 src/core/cgroup.c                             | 86 ++++++++++++++++---
 src/core/cgroup.h                             | 10 ++-
 src/core/dbus-cgroup.c                        | 52 +++++++++--
 src/core/dbus-manager.c                       |  1 +
 src/core/load-fragment-gperf.gperf.in         |  5 ++
 src/core/load-fragment.c                      | 73 +++++++++++++++-
 src/core/load-fragment.h                      |  1 +
 src/core/main.c                               |  4 +
 src/core/manager.c                            |  1 +
 src/core/manager.h                            |  1 +
 src/core/system.conf.in                       |  1 +
 src/core/unit.c                               |  1 +
 src/shared/bus-unit-util.c                    | 15 +++-
 src/shared/cpu-set-util.c                     |  1 +
 src/test/test-cgroup-mask.c                   |  5 +-
 .../fuzz-unit-file/directives-all.service     |  5 ++
 test/fuzz/fuzz-unit-file/directives.mount     |  5 ++
 test/fuzz/fuzz-unit-file/directives.scope     |  5 ++
 test/fuzz/fuzz-unit-file/directives.service   |  5 ++
 test/fuzz/fuzz-unit-file/directives.slice     |  5 ++
 test/fuzz/fuzz-unit-file/directives.socket    |  5 ++
 test/fuzz/fuzz-unit-file/directives.swap      |  5 ++
 28 files changed, 328 insertions(+), 30 deletions(-)

diff --git a/meson.build b/meson.build
index b04551f..b089ac4 100644
--- a/meson.build
+++ b/meson.build
@@ -1502,6 +1502,7 @@ foreach term : ['analyze',
                 'backlight',
                 'binfmt',
                 'coredump',
+                'cpuset-cgv1',
                 'efi',
                 'environment-d',
                 'firstboot',
@@ -3905,6 +3906,7 @@ foreach tuple : [
         ['link-timesyncd-shared', get_option('link-timesyncd-shared')],
         ['fexecve'],
         ['standalone-binaries',   get_option('standalone-binaries')],
+        ['cpuset-cgv1'],
 ]
 
         if tuple.length() >= 2
diff --git a/meson_options.txt b/meson_options.txt
index bb51cfb..4c45798 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -460,3 +460,6 @@ option('analyze', type: 'boolean', value: 'true',
 
 option('bpf-framework', type : 'combo', choices : ['auto', 'true', 'false'],
     description: 'build BPF programs from source code in restricted C')
+
+option('cpuset-cgv1', type : 'boolean', value : 'true',
+       description : 'enable cgroup v1 cpuset support')
diff --git a/src/basic/cgroup-util.c b/src/basic/cgroup-util.c
index 1ff6160..01a4181 100644
--- a/src/basic/cgroup-util.c
+++ b/src/basic/cgroup-util.c
@@ -2155,12 +2155,13 @@ bool fd_is_cgroup_fs(int fd) {
 static const char *const cgroup_controller_table[_CGROUP_CONTROLLER_MAX] = {
         [CGROUP_CONTROLLER_CPU] = "cpu",
         [CGROUP_CONTROLLER_CPUACCT] = "cpuacct",
-        [CGROUP_CONTROLLER_CPUSET] = "cpuset",
+        [CGROUP_CONTROLLER_CPUSET2] = "cpuset2",
         [CGROUP_CONTROLLER_IO] = "io",
         [CGROUP_CONTROLLER_BLKIO] = "blkio",
         [CGROUP_CONTROLLER_MEMORY] = "memory",
         [CGROUP_CONTROLLER_DEVICES] = "devices",
         [CGROUP_CONTROLLER_PIDS] = "pids",
+        [CGROUP_CONTROLLER_CPUSET] = "cpuset",
         [CGROUP_CONTROLLER_BPF_FIREWALL] = "bpf-firewall",
         [CGROUP_CONTROLLER_BPF_DEVICES] = "bpf-devices",
         [CGROUP_CONTROLLER_BPF_FOREIGN] = "bpf-foreign",
diff --git a/src/basic/cgroup-util.h b/src/basic/cgroup-util.h
index ce2f4c6..09b3109 100644
--- a/src/basic/cgroup-util.h
+++ b/src/basic/cgroup-util.h
@@ -20,12 +20,13 @@ typedef enum CGroupController {
         /* Original cgroup controllers */
         CGROUP_CONTROLLER_CPU,
         CGROUP_CONTROLLER_CPUACCT,    /* v1 only */
-        CGROUP_CONTROLLER_CPUSET,     /* v2 only */
+        CGROUP_CONTROLLER_CPUSET2,    /* v2 only */
         CGROUP_CONTROLLER_IO,         /* v2 only */
         CGROUP_CONTROLLER_BLKIO,      /* v1 only */
         CGROUP_CONTROLLER_MEMORY,
         CGROUP_CONTROLLER_DEVICES,    /* v1 only */
         CGROUP_CONTROLLER_PIDS,
+        CGROUP_CONTROLLER_CPUSET,
 
         /* BPF-based pseudo-controllers, v2 only */
         CGROUP_CONTROLLER_BPF_FIREWALL,
@@ -43,22 +44,27 @@ typedef enum CGroupController {
 typedef enum CGroupMask {
         CGROUP_MASK_CPU = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_CPU),
         CGROUP_MASK_CPUACCT = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_CPUACCT),
-        CGROUP_MASK_CPUSET = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_CPUSET),
+        CGROUP_MASK_CPUSET2 = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_CPUSET2),
         CGROUP_MASK_IO = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_IO),
         CGROUP_MASK_BLKIO = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_BLKIO),
         CGROUP_MASK_MEMORY = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_MEMORY),
         CGROUP_MASK_DEVICES = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_DEVICES),
         CGROUP_MASK_PIDS = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_PIDS),
+        CGROUP_MASK_CPUSET = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_CPUSET),
         CGROUP_MASK_BPF_FIREWALL = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_BPF_FIREWALL),
         CGROUP_MASK_BPF_DEVICES = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_BPF_DEVICES),
         CGROUP_MASK_BPF_FOREIGN = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_BPF_FOREIGN),
         CGROUP_MASK_BPF_SOCKET_BIND = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_BPF_SOCKET_BIND),
 
         /* All real cgroup v1 controllers */
-        CGROUP_MASK_V1 = CGROUP_MASK_CPU|CGROUP_MASK_CPUACCT|CGROUP_MASK_BLKIO|CGROUP_MASK_MEMORY|CGROUP_MASK_DEVICES|CGROUP_MASK_PIDS,
+        CGROUP_MASK_V1 = CGROUP_MASK_CPU|CGROUP_MASK_CPUACCT|CGROUP_MASK_BLKIO|CGROUP_MASK_MEMORY|CGROUP_MASK_DEVICES|CGROUP_MASK_PIDS
+#if ENABLE_CPUSET_CGV1
+        | CGROUP_MASK_CPUSET
+#endif
+        ,
 
         /* All real cgroup v2 controllers */
-        CGROUP_MASK_V2 = CGROUP_MASK_CPU|CGROUP_MASK_CPUSET|CGROUP_MASK_IO|CGROUP_MASK_MEMORY|CGROUP_MASK_PIDS,
+        CGROUP_MASK_V2 = CGROUP_MASK_CPU|CGROUP_MASK_CPUSET2|CGROUP_MASK_IO|CGROUP_MASK_MEMORY|CGROUP_MASK_PIDS,
 
         /* All cgroup v2 BPF pseudo-controllers */
         CGROUP_MASK_BPF = CGROUP_MASK_BPF_FIREWALL|CGROUP_MASK_BPF_DEVICES|CGROUP_MASK_BPF_FOREIGN|CGROUP_MASK_BPF_SOCKET_BIND,
diff --git a/src/basic/string-util.c b/src/basic/string-util.c
index a645958..45f358b 100644
--- a/src/basic/string-util.c
+++ b/src/basic/string-util.c
@@ -1146,3 +1146,45 @@ int string_contains_word_strv(const char *string, const char *separators, char *
                 *ret_word = found;
         return !!found;
 }
+
+int string_isvalid_interval(const char *instr)
+{
+    const char *pstr  = instr;  /* tmp */
+    const char *pstr_front  = instr;  /* front char */
+    const char *pstr_behind = instr;  /* behind char */
+
+    if (isempty(instr))
+    {
+        return 1;
+    }
+
+    while (*pstr != '\0')
+    {
+        /* behind */
+        pstr_behind = pstr + 1;
+
+        /* 0-3,4,6,7-10 */
+        if (((*pstr < '0') || (*pstr > '9')) &&
+            (*pstr != '-') &&
+            (*pstr != ','))
+        {
+            return 2;
+        }
+
+        /* - , must is a num */
+        if (('-' == *pstr) || (',' == *pstr))
+        {
+            if ((*pstr_front < '0') || (*pstr_front > '9') ||
+                (*pstr_behind < '0') || (*pstr_behind > '9'))
+            {
+                return 3;
+            }
+        }
+
+        /* front */
+        pstr_front = pstr;
+        pstr++;
+    }
+
+    return 0;
+}
diff --git a/src/basic/string-util.h b/src/basic/string-util.h
index 9155e50..338dcd5 100644
--- a/src/basic/string-util.h
+++ b/src/basic/string-util.h
@@ -242,3 +242,5 @@ int string_contains_word_strv(const char *string, const char *separators, char *
 static inline int string_contains_word(const char *string, const char *separators, const char *word) {
         return string_contains_word_strv(string, separators, STRV_MAKE(word), NULL);
 }
+
+int string_isvalid_interval(const char *instr);
diff --git a/src/core/cgroup.c b/src/core/cgroup.c
index b27fce8..895f6b2 100644
--- a/src/core/cgroup.c
+++ b/src/core/cgroup.c
@@ -252,8 +252,14 @@ void cgroup_context_done(CGroupContext *c) {
         while (c->bpf_foreign_programs)
                 cgroup_context_remove_bpf_foreign_program(c, c->bpf_foreign_programs);
 
-        cpu_set_reset(&c->cpuset_cpus);
-        cpu_set_reset(&c->cpuset_mems);
+        if (c->cpuset_cpus)
+                c->cpuset_cpus = mfree(c->cpuset_cpus);
+
+        if (c->cpuset_mems)
+                c->cpuset_mems = mfree(c->cpuset_mems);
+
+        cpu_set_reset(&c->cpuset_cpus2);
+        cpu_set_reset(&c->cpuset_mems2);
 }
 
 static int unit_get_kernel_memory_limit(Unit *u, const char *file, uint64_t *ret) {
@@ -388,7 +394,7 @@ static char *format_cgroup_memory_limit_comparison(char *buf, size_t l, Unit *u,
 }
 
 void cgroup_context_dump(Unit *u, FILE* f, const char *prefix) {
-        _cleanup_free_ char *disable_controllers_str = NULL, *cpuset_cpus = NULL, *cpuset_mems = NULL;
+        _cleanup_free_ char *disable_controllers_str = NULL, *cpuset_cpus2 = NULL, *cpuset_mems2 = NULL;
         CGroupIODeviceLimit *il;
         CGroupIODeviceWeight *iw;
         CGroupIODeviceLatency *l;
@@ -418,14 +424,15 @@ void cgroup_context_dump(Unit *u, FILE* f, const char *prefix) {
 
         (void) cg_mask_to_string(c->disable_controllers, &disable_controllers_str);
 
-        cpuset_cpus = cpu_set_to_range_string(&c->cpuset_cpus);
-        cpuset_mems = cpu_set_to_range_string(&c->cpuset_mems);
+        cpuset_cpus2 = cpu_set_to_range_string(&c->cpuset_cpus2);
+        cpuset_mems2 = cpu_set_to_range_string(&c->cpuset_mems2);
 
         fprintf(f,
                 "%sCPUAccounting: %s\n"
                 "%sIOAccounting: %s\n"
                 "%sBlockIOAccounting: %s\n"
                 "%sMemoryAccounting: %s\n"
+                "%sCPUSetAccounting: %s\n"
                 "%sTasksAccounting: %s\n"
                 "%sIPAccounting: %s\n"
                 "%sCPUWeight: %" PRIu64 "\n"
@@ -448,6 +455,10 @@ void cgroup_context_dump(Unit *u, FILE* f, const char *prefix) {
                 "%sMemoryMax: %" PRIu64 "%s\n"
                 "%sMemorySwapMax: %" PRIu64 "%s\n"
                 "%sMemoryLimit: %" PRIu64 "\n"
+                "%sCPUSetCpus=%s\n"
+                "%sCPUSetMems=%s\n"
+                "%sCPUSetCloneChildren=%s\n"
+                "%sCPUSetMemMigrate=%s\n"
                 "%sTasksMax: %" PRIu64 "\n"
                 "%sDevicePolicy: %s\n"
                 "%sDisableControllers: %s\n"
@@ -460,6 +471,7 @@ void cgroup_context_dump(Unit *u, FILE* f, const char *prefix) {
                 prefix, yes_no(c->io_accounting),
                 prefix, yes_no(c->blockio_accounting),
                 prefix, yes_no(c->memory_accounting),
+                prefix, yes_no(c->cpuset_accounting),
                 prefix, yes_no(c->tasks_accounting),
                 prefix, yes_no(c->ip_accounting),
                 prefix, c->cpu_weight,
@@ -468,8 +480,8 @@ void cgroup_context_dump(Unit *u, FILE* f, const char *prefix) {
                 prefix, c->startup_cpu_shares,
                 prefix, format_timespan(q, sizeof(q), c->cpu_quota_per_sec_usec, 1),
                 prefix, format_timespan(v, sizeof(v), c->cpu_quota_period_usec, 1),
-                prefix, strempty(cpuset_cpus),
-                prefix, strempty(cpuset_mems),
+                prefix, strempty(cpuset_cpus2),
+                prefix, strempty(cpuset_mems2),
                 prefix, c->io_weight,
                 prefix, c->startup_io_weight,
                 prefix, c->blockio_weight,
@@ -482,6 +494,10 @@ void cgroup_context_dump(Unit *u, FILE* f, const char *prefix) {
                 prefix, c->memory_max, format_cgroup_memory_limit_comparison(cdd, sizeof(cdd), u, "MemoryMax"),
                 prefix, c->memory_swap_max, format_cgroup_memory_limit_comparison(cde, sizeof(cde), u, "MemorySwapMax"),
                 prefix, c->memory_limit,
+                prefix, c->cpuset_cpus,
+                prefix, c->cpuset_mems,
+                prefix, yes_no(c->cpuset_clone_children),
+                prefix, yes_no(c->cpuset_memory_migrate),
                 prefix, tasks_max_resolve(&c->tasks_max),
                 prefix, cgroup_device_policy_to_string(c->device_policy),
                 prefix, strempty(disable_controllers_str),
@@ -1325,9 +1341,9 @@ static void cgroup_context_apply(
                 }
         }
 
-        if ((apply_mask & CGROUP_MASK_CPUSET) && !is_local_root) {
-                cgroup_apply_unified_cpuset(u, &c->cpuset_cpus, "cpuset.cpus");
-                cgroup_apply_unified_cpuset(u, &c->cpuset_mems, "cpuset.mems");
+        if ((apply_mask & CGROUP_MASK_CPUSET2) && !is_local_root) {
+                cgroup_apply_unified_cpuset(u, &c->cpuset_cpus2, "cpuset.cpus");
+                cgroup_apply_unified_cpuset(u, &c->cpuset_mems2, "cpuset.mems");
         }
 
         /* The 'io' controller attributes are not exported on the host's root cgroup (being a pure cgroup v2
@@ -1511,6 +1527,45 @@ static void cgroup_context_apply(
                 }
         }
 
+        if ((apply_mask & CGROUP_MASK_CPUSET) && !is_local_root) {
+                (void) set_attribute_and_warn(u, "cpuset", "cgroup.clone_children", one_zero(c->cpuset_clone_children));
+                (void) set_attribute_and_warn(u, "cpuset", "cpuset.memory_migrate", one_zero(c->cpuset_memory_migrate));
+                if (c->cpuset_cpus) {
+                        if (streq(c->cpuset_cpus, "all")) {
+                                _cleanup_free_ char *str_cpuset_cpus = NULL;
+                                _cleanup_free_ char *cg_root_path_cpus = NULL;
+                                r = cg_get_root_path(&cg_root_path_cpus);
+                                if (r < 0)
+                                        log_info_errno(r, "Failed to determine root cgroup, ignoring cgroup cpuset cpus: %m");
+                                if (cg_root_path_cpus) {
+                                        r = cg_get_attribute("cpuset", cg_root_path_cpus, "cpuset.cpus", &str_cpuset_cpus);
+                                        if (r < 0)
+                                                log_error("cgroup context apply: cg get attribute is error(%d), path=%s.", r, cg_root_path_cpus);
+                                        if (str_cpuset_cpus)
+                                                (void) set_attribute_and_warn(u, "cpuset", "cpuset.cpus", str_cpuset_cpus);
+                                }
+                        } else
+                                (void) set_attribute_and_warn(u, "cpuset", "cpuset.cpus", c->cpuset_cpus);
+                }
+                if (c->cpuset_mems) {
+                        if (streq(c->cpuset_mems, "all")) {
+                                _cleanup_free_ char *str_cpuset_mems = NULL;
+                                _cleanup_free_ char *cg_root_path_mems = NULL;
+                                r = cg_get_root_path(&cg_root_path_mems);
+                                if (r < 0)
+                                        log_info_errno(r, "Failed to determine root cgroup, ignoring cgroup cpuset mems: %m");
+                                if (cg_root_path_mems) {
+                                        r = cg_get_attribute("cpuset", cg_root_path_mems, "cpuset.mems", &str_cpuset_mems);
+                                        if (r < 0)
+                                                log_error("cgroup context apply: cg get attribute is error(%d), path=%s.", r, cg_root_path_mems);
+                                        if (str_cpuset_mems)
+                                                (void) set_attribute_and_warn(u, "cpuset", "cpuset.mems", str_cpuset_mems);
+                                }
+                        } else
+                                (void) set_attribute_and_warn(u, "cpuset", "cpuset.mems", c->cpuset_mems);
+                }
+        }
+
         /* On cgroup v2 we can apply BPF everywhere. On cgroup v1 we apply it everywhere except for the root of
          * containers, where we leave this to the manager */
         if ((apply_mask & (CGROUP_MASK_DEVICES | CGROUP_MASK_BPF_DEVICES)) &&
@@ -1637,8 +1692,8 @@ static CGroupMask unit_get_cgroup_mask(Unit *u) {
             c->cpu_quota_per_sec_usec != USEC_INFINITY)
                 mask |= CGROUP_MASK_CPU;
 
-        if (c->cpuset_cpus.set || c->cpuset_mems.set)
-                mask |= CGROUP_MASK_CPUSET;
+        if (c->cpuset_cpus2.set || c->cpuset_mems2.set)
+                mask |= CGROUP_MASK_CPUSET2;
 
         if (cgroup_context_has_io_config(c) || cgroup_context_has_blockio_config(c))
                 mask |= CGROUP_MASK_IO | CGROUP_MASK_BLKIO;
@@ -1648,6 +1703,11 @@ static CGroupMask unit_get_cgroup_mask(Unit *u) {
             unit_has_unified_memory_config(u))
                 mask |= CGROUP_MASK_MEMORY;
 
+        if (c->cpuset_accounting ||
+            c->cpuset_cpus ||
+            c->cpuset_mems)
+                mask |= CGROUP_MASK_CPUSET;
+
         if (c->device_allow ||
             c->device_policy != CGROUP_DEVICE_POLICY_AUTO)
                 mask |= CGROUP_MASK_DEVICES | CGROUP_MASK_BPF_DEVICES;
@@ -4040,7 +4100,7 @@ int unit_get_cpuset(Unit *u, CPUSet *cpus, const char *name) {
         if (!u->cgroup_path)
                 return -ENODATA;
 
-        if ((u->cgroup_realized_mask & CGROUP_MASK_CPUSET) == 0)
+        if ((u->cgroup_realized_mask & CGROUP_MASK_CPUSET2) == 0)
                 return -ENODATA;
 
         r = cg_all_unified();
diff --git a/src/core/cgroup.h b/src/core/cgroup.h
index 3f8cad8..1e27104 100644
--- a/src/core/cgroup.h
+++ b/src/core/cgroup.h
@@ -115,6 +115,7 @@ struct CGroupContext {
         bool io_accounting;
         bool blockio_accounting;
         bool memory_accounting;
+        bool cpuset_accounting;
         bool tasks_accounting;
         bool ip_accounting;
 
@@ -131,8 +132,8 @@ struct CGroupContext {
         usec_t cpu_quota_per_sec_usec;
         usec_t cpu_quota_period_usec;
 
-        CPUSet cpuset_cpus;
-        CPUSet cpuset_mems;
+        CPUSet cpuset_cpus2;
+        CPUSet cpuset_mems2;
 
         uint64_t io_weight;
         uint64_t startup_io_weight;
@@ -148,6 +149,11 @@ struct CGroupContext {
         uint64_t memory_max;
         uint64_t memory_swap_max;
 
+        char *cpuset_cpus;
+        char *cpuset_mems;
+        bool cpuset_clone_children;
+        bool cpuset_memory_migrate;
+
         bool default_memory_min_set;
         bool default_memory_low_set;
         bool memory_min_set;
diff --git a/src/core/dbus-cgroup.c b/src/core/dbus-cgroup.c
index 84c3caf..0cdc98c 100644
--- a/src/core/dbus-cgroup.c
+++ b/src/core/dbus-cgroup.c
@@ -414,8 +414,8 @@ const sd_bus_vtable bus_cgroup_vtable[] = {
         SD_BUS_PROPERTY("StartupCPUShares", "t", NULL, offsetof(CGroupContext, startup_cpu_shares), 0),
         SD_BUS_PROPERTY("CPUQuotaPerSecUSec", "t", bus_property_get_usec, offsetof(CGroupContext, cpu_quota_per_sec_usec), 0),
         SD_BUS_PROPERTY("CPUQuotaPeriodUSec", "t", bus_property_get_usec, offsetof(CGroupContext, cpu_quota_period_usec), 0),
-        SD_BUS_PROPERTY("AllowedCPUs", "ay", property_get_cpuset, offsetof(CGroupContext, cpuset_cpus), 0),
-        SD_BUS_PROPERTY("AllowedMemoryNodes", "ay", property_get_cpuset, offsetof(CGroupContext, cpuset_mems), 0),
+        SD_BUS_PROPERTY("AllowedCPUs", "ay", property_get_cpuset, offsetof(CGroupContext, cpuset_cpus2), 0),
+        SD_BUS_PROPERTY("AllowedMemoryNodes", "ay", property_get_cpuset, offsetof(CGroupContext, cpuset_mems2), 0),
         SD_BUS_PROPERTY("IOAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, io_accounting), 0),
         SD_BUS_PROPERTY("IOWeight", "t", NULL, offsetof(CGroupContext, io_weight), 0),
         SD_BUS_PROPERTY("StartupIOWeight", "t", NULL, offsetof(CGroupContext, startup_io_weight), 0),
@@ -440,6 +440,11 @@ const sd_bus_vtable bus_cgroup_vtable[] = {
         SD_BUS_PROPERTY("MemoryMax", "t", NULL, offsetof(CGroupContext, memory_max), 0),
         SD_BUS_PROPERTY("MemorySwapMax", "t", NULL, offsetof(CGroupContext, memory_swap_max), 0),
         SD_BUS_PROPERTY("MemoryLimit", "t", NULL, offsetof(CGroupContext, memory_limit), 0),
+        SD_BUS_PROPERTY("CPUSetAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, cpuset_accounting), 0),
+        SD_BUS_PROPERTY("CPUSetCpus", "s", NULL, offsetof(CGroupContext, cpuset_cpus), 0),
+        SD_BUS_PROPERTY("CPUSetMems", "s", NULL, offsetof(CGroupContext, cpuset_mems), 0),
+        SD_BUS_PROPERTY("CPUSetCloneChildren", "b", bus_property_get_bool, offsetof(CGroupContext, cpuset_clone_children), 0),
+        SD_BUS_PROPERTY("CPUSetMemMigrate", "b", bus_property_get_bool, offsetof(CGroupContext, cpuset_memory_migrate), 0),
         SD_BUS_PROPERTY("DevicePolicy", "s", property_get_cgroup_device_policy, offsetof(CGroupContext, device_policy), 0),
         SD_BUS_PROPERTY("DeviceAllow", "a(ss)", property_get_device_allow, 0, 0),
         SD_BUS_PROPERTY("TasksAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, tasks_accounting), 0),
@@ -1065,6 +1070,43 @@ int bus_cgroup_set_property(
         if (streq(name, "MemoryLimitScale"))
                 return bus_cgroup_set_memory_scale(u, name, &c->memory_limit, message, flags, error);
 
+        if (streq(name, "CPUSetAccounting"))
+                return bus_cgroup_set_boolean(u, name, &c->cpuset_accounting, CGROUP_MASK_CPUSET, message, flags, error);
+
+        if (STR_IN_SET(name, "CPUSetCpus", "CPUSetMems")) {
+                const char *cpuset_str = NULL;
+
+                r = sd_bus_message_read(message, "s", &cpuset_str);
+                if (r < 0)
+                        return r;
+
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
+                        unit_invalidate_cgroup(u, CGROUP_MASK_CPUSET);
+                        if (streq(name, "CPUSetCpus")) {
+                                if (c->cpuset_cpus)
+                                        c->cpuset_cpus = mfree(c->cpuset_cpus);
+                                c->cpuset_cpus = strdup(cpuset_str);
+                                if (!c->cpuset_cpus)
+                                        return -ENOMEM;
+                                unit_write_settingf(u, flags, name, "CPUSetCpus=%s", cpuset_str);
+                        } else {
+                                if (c->cpuset_mems)
+                                        c->cpuset_mems = mfree(c->cpuset_mems);
+                                c->cpuset_mems = strdup(cpuset_str);
+                                if (!c->cpuset_mems)
+                                        return -ENOMEM;
+                                unit_write_settingf(u, flags, name, "CPUSetMems=%s", cpuset_str);
+                        }
+                }
+                return 1;
+        }
+
+        if (streq(name, "CPUSetCloneChildren"))
+                return bus_cgroup_set_boolean(u, name, &c->cpuset_clone_children, CGROUP_MASK_CPUSET, message, flags, error);
+
+        if (streq(name, "CPUSetMemMigrate"))
+                return bus_cgroup_set_boolean(u, name, &c->cpuset_memory_migrate, CGROUP_MASK_CPUSET, message, flags, error);
+
         if (streq(name, "TasksAccounting"))
                 return bus_cgroup_set_boolean(u, name, &c->tasks_accounting, CGROUP_MASK_PIDS, message, flags, error);
 
@@ -1146,15 +1188,15 @@ int bus_cgroup_set_property(
                                 return -ENOMEM;
 
                         if (streq(name, "AllowedCPUs"))
-                                set = &c->cpuset_cpus;
+                                set = &c->cpuset_cpus2;
                         else
-                                set = &c->cpuset_mems;
+                                set = &c->cpuset_mems2;
 
                         cpu_set_reset(set);
                         *set = new_set;
                         new_set = (CPUSet) {};
 
-                        unit_invalidate_cgroup(u, CGROUP_MASK_CPUSET);
+                        unit_invalidate_cgroup(u, CGROUP_MASK_CPUSET2);
                         unit_write_settingf(u, flags, name, "%s=%s", name, setstr);
                 }
 
diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c
index 05daba4..3d899a5 100644
--- a/src/core/dbus-manager.c
+++ b/src/core/dbus-manager.c
@@ -2696,6 +2696,7 @@ const sd_bus_vtable bus_manager_vtable[] = {
         SD_BUS_PROPERTY("DefaultCPUAccounting", "b", bus_property_get_bool, offsetof(Manager, default_cpu_accounting), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("DefaultBlockIOAccounting", "b", bus_property_get_bool, offsetof(Manager, default_blockio_accounting), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("DefaultMemoryAccounting", "b", bus_property_get_bool, offsetof(Manager, default_memory_accounting), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("DefaultCpusetAccounting", "b", bus_property_get_bool, offsetof(Manager, default_cpuset_accounting), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("DefaultTasksAccounting", "b", bus_property_get_bool, offsetof(Manager, default_tasks_accounting), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("DefaultLimitCPU", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_CPU]), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("DefaultLimitCPUSoft", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_CPU]), SD_BUS_VTABLE_PROPERTY_CONST),
diff --git a/src/core/load-fragment-gperf.gperf.in b/src/core/load-fragment-gperf.gperf.in
index 42441ea..60c9dbc 100644
--- a/src/core/load-fragment-gperf.gperf.in
+++ b/src/core/load-fragment-gperf.gperf.in
@@ -197,6 +197,11 @@
 {{type}}.MemoryMax,                        config_parse_memory_limit,                   0,                                  offsetof({{type}}, cgroup_context)
 {{type}}.MemorySwapMax,                    config_parse_memory_limit,                   0,                                  offsetof({{type}}, cgroup_context)
 {{type}}.MemoryLimit,                      config_parse_memory_limit,                   0,                                  offsetof({{type}}, cgroup_context)
+{{type}}.CPUSetAccounting,                 config_parse_bool,                           0,                                  offsetof({{type}}, cgroup_context.cpuset_accounting)
+{{type}}.CPUSetCpus,                       config_parse_cpuset_cpumems,                 0,                                  offsetof({{type}}, cgroup_context.cpuset_cpus)
+{{type}}.CPUSetMems,                       config_parse_cpuset_cpumems,                 0,                                  offsetof({{type}}, cgroup_context.cpuset_mems)
+{{type}}.CPUSetCloneChildren,              config_parse_bool,                           0,                                  offsetof({{type}}, cgroup_context.cpuset_clone_children)
+{{type}}.CPUSetMemMigrate,                 config_parse_bool,                           0,                                  offsetof({{type}}, cgroup_context.cpuset_memory_migrate)
 {{type}}.DeviceAllow,                      config_parse_device_allow,                   0,                                  offsetof({{type}}, cgroup_context)
 {{type}}.DevicePolicy,                     config_parse_device_policy,                  0,                                  offsetof({{type}}, cgroup_context.device_policy)
 {{type}}.IOAccounting,                     config_parse_bool,                           0,                                  offsetof({{type}}, cgroup_context.io_accounting)
diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c
index f357408..ed72997 100644
--- a/src/core/load-fragment.c
+++ b/src/core/load-fragment.c
@@ -3632,7 +3632,7 @@ int config_parse_allowed_cpus(
 
         CGroupContext *c = data;
 
-        (void) parse_cpu_set_extend(rvalue, &c->cpuset_cpus, true, unit, filename, line, lvalue);
+        (void) parse_cpu_set_extend(rvalue, &c->cpuset_cpus2, true, unit, filename, line, lvalue);
 
         return 0;
 }
@@ -3651,7 +3651,7 @@ int config_parse_allowed_mems(
 
         CGroupContext *c = data;
 
-        (void) parse_cpu_set_extend(rvalue, &c->cpuset_mems, true, unit, filename, line, lvalue);
+        (void) parse_cpu_set_extend(rvalue, &c->cpuset_mems2, true, unit, filename, line, lvalue);
 
         return 0;
 }
@@ -3722,6 +3722,75 @@ int config_parse_memory_limit(
         return 0;
 }
 
+int config_parse_cpuset_cpumems(
+                const char *unit,
+                const char *filename,
+                unsigned line,
+                const char *section,
+                unsigned section_line,
+                const char *lvalue,
+                int ltype,
+                const char *rvalue,
+                void *data,
+                void *userdata)
+{
+     char **pcpumems = data;
+     char *pinstr    = NULL;
+     int iret = 0;
+ 
+     assert(filename);
+     assert(lvalue);
+     assert(rvalue);
+     assert(data);
+     (void)section;
+     (void)section_line;
+     (void)ltype;
+     (void)userdata;
+
+     if (!utf8_is_valid(rvalue))
+     {
+          log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, rvalue);
+          return 0;
+     }
+
+     if (0 == strcmp(rvalue, "all"))
+     {
+          pinstr = strdup(rvalue);
+          if (!pinstr)
+          {
+              return log_oom();
+          }
+
+          free(*pcpumems);
+          *pcpumems = pinstr;
+
+          return 0;
+     }
+
+     /* 0-2,4 */
+     iret = string_isvalid_interval(rvalue);
+     if (0 != iret)
+     {
+          pinstr = NULL;
+          log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+                   "cpuset cpumems '%s' is invalid, Ignoring(%d).",
+                   rvalue, iret);
+     }
+     else
+     {
+          pinstr = strdup(rvalue);
+          if (!pinstr)
+          {
+              return log_oom();
+          }
+     }
+
+     free(*pcpumems);
+     *pcpumems = pinstr;
+
+     return 0;
+}
+
 int config_parse_tasks_max(
                 const char *unit,
                 const char *filename,
diff --git a/src/core/load-fragment.h b/src/core/load-fragment.h
index 45e9c39..1ecad67 100644
--- a/src/core/load-fragment.h
+++ b/src/core/load-fragment.h
@@ -74,6 +74,7 @@ CONFIG_PARSER_PROTOTYPE(config_parse_unit_slice);
 CONFIG_PARSER_PROTOTYPE(config_parse_cg_weight);
 CONFIG_PARSER_PROTOTYPE(config_parse_cpu_shares);
 CONFIG_PARSER_PROTOTYPE(config_parse_memory_limit);
+CONFIG_PARSER_PROTOTYPE(config_parse_cpuset_cpumems);
 CONFIG_PARSER_PROTOTYPE(config_parse_tasks_max);
 CONFIG_PARSER_PROTOTYPE(config_parse_delegate);
 CONFIG_PARSER_PROTOTYPE(config_parse_managed_oom_mode);
diff --git a/src/core/main.c b/src/core/main.c
index a9c6222..5726b35 100644
--- a/src/core/main.c
+++ b/src/core/main.c
@@ -148,6 +148,7 @@ static bool arg_default_io_accounting;
 static bool arg_default_ip_accounting;
 static bool arg_default_blockio_accounting;
 static bool arg_default_memory_accounting;
+static bool arg_default_cpuset_accounting;
 static bool arg_default_tasks_accounting;
 static TasksMax arg_default_tasks_max;
 static sd_id128_t arg_machine_id;
@@ -702,6 +703,7 @@ static int parse_config_file(void) {
                 { "Manager", "DefaultIPAccounting",          config_parse_bool,                  0, &arg_default_ip_accounting             },
                 { "Manager", "DefaultBlockIOAccounting",     config_parse_bool,                  0, &arg_default_blockio_accounting        },
                 { "Manager", "DefaultMemoryAccounting",      config_parse_bool,                  0, &arg_default_memory_accounting         },
+                { "Manager", "DefaultCpusetAccounting",      config_parse_bool,                  0, &arg_default_cpuset_accounting         },
                 { "Manager", "DefaultTasksAccounting",       config_parse_bool,                  0, &arg_default_tasks_accounting          },
                 { "Manager", "DefaultTasksMax",              config_parse_tasks_max,             0, &arg_default_tasks_max                 },
                 { "Manager", "CtrlAltDelBurstAction",        config_parse_emergency_action,      0, &arg_cad_burst_action                  },
@@ -773,6 +775,7 @@ static void set_manager_defaults(Manager *m) {
         m->default_ip_accounting = arg_default_ip_accounting;
         m->default_blockio_accounting = arg_default_blockio_accounting;
         m->default_memory_accounting = arg_default_memory_accounting;
+        m->default_cpuset_accounting = arg_default_cpuset_accounting;
         m->default_tasks_accounting = arg_default_tasks_accounting;
         m->default_tasks_max = arg_default_tasks_max;
         m->default_oom_policy = arg_default_oom_policy;
@@ -2414,6 +2417,7 @@ static void reset_arguments(void) {
         arg_default_ip_accounting = false;
         arg_default_blockio_accounting = false;
         arg_default_memory_accounting = MEMORY_ACCOUNTING_DEFAULT;
+        arg_default_cpuset_accounting = false;
         arg_default_tasks_accounting = true;
         arg_default_tasks_max = DEFAULT_TASKS_MAX;
         arg_machine_id = (sd_id128_t) {};
diff --git a/src/core/manager.c b/src/core/manager.c
index 452d68a..5196619 100644
--- a/src/core/manager.c
+++ b/src/core/manager.c
@@ -745,6 +745,7 @@ int manager_new(UnitFileScope scope, ManagerTestRunFlags test_run_flags, Manager
 
                 .default_timer_accuracy_usec = USEC_PER_MINUTE,
                 .default_memory_accounting = MEMORY_ACCOUNTING_DEFAULT,
+                .default_cpuset_accounting = false,
                 .default_tasks_accounting = true,
                 .default_tasks_max = TASKS_MAX_UNSET,
                 .default_timeout_start_usec = DEFAULT_TIMEOUT_USEC,
diff --git a/src/core/manager.h b/src/core/manager.h
index 5ce9361..50ccb1e 100644
--- a/src/core/manager.h
+++ b/src/core/manager.h
@@ -360,6 +360,7 @@ struct Manager {
 
         bool default_cpu_accounting;
         bool default_memory_accounting;
+        bool default_cpuset_accounting;
         bool default_io_accounting;
         bool default_blockio_accounting;
         bool default_tasks_accounting;
diff --git a/src/core/system.conf.in b/src/core/system.conf.in
index 4369703..015088c 100644
--- a/src/core/system.conf.in
+++ b/src/core/system.conf.in
@@ -53,6 +53,7 @@
 #DefaultIPAccounting=no
 #DefaultBlockIOAccounting=no
 #DefaultMemoryAccounting={{ 'yes' if MEMORY_ACCOUNTING_DEFAULT else 'no' }}
+#DefaultCpusetAccounting=
 #DefaultTasksAccounting=yes
 #DefaultTasksMax=80%
 #DefaultLimitCPU=
diff --git a/src/core/unit.c b/src/core/unit.c
index 366f602..d601f0c 100644
--- a/src/core/unit.c
+++ b/src/core/unit.c
@@ -177,6 +177,7 @@ static void unit_init(Unit *u) {
                 cc->io_accounting = u->manager->default_io_accounting;
                 cc->blockio_accounting = u->manager->default_blockio_accounting;
                 cc->memory_accounting = u->manager->default_memory_accounting;
+                cc->cpuset_accounting = u->manager->default_cpuset_accounting;
                 cc->tasks_accounting = u->manager->default_tasks_accounting;
                 cc->ip_accounting = u->manager->default_ip_accounting;
 
diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c
index d3a5b25..caad3ab 100644
--- a/src/shared/bus-unit-util.c
+++ b/src/shared/bus-unit-util.c
@@ -460,7 +460,10 @@ static int bus_append_cgroup_property(sd_bus_message *m, const char *field, cons
                               "IOAccounting",
                               "BlockIOAccounting",
                               "TasksAccounting",
-                              "IPAccounting"))
+                              "IPAccounting",
+                              "CPUSetAccounting",
+                              "CPUSetCloneChildren",
+                              "CPUSetMemMigrate"))
                 return bus_append_parse_boolean(m, field, eq);
 
         if (STR_IN_SET(field, "CPUWeight",
@@ -561,6 +564,16 @@ static int bus_append_cgroup_property(sd_bus_message *m, const char *field, cons
                 return bus_append_parse_size(m, field, eq, 1024);
         }
 
+        if (STR_IN_SET(field, "CPUSetCpus", "CPUSetMems")) {
+                if (string_isvalid_interval(eq) == 0 || streq(eq, "all"))
+                        r = sd_bus_message_append(m, "(sv)", field, "s", eq);
+                else
+                        r = -EINVAL;
+                if (r < 0)
+                        return bus_log_create_error(r);
+                return 1;
+        }
+
         if (streq(field, "CPUQuota")) {
                 if (isempty(eq))
                         r = sd_bus_message_append(m, "(sv)", "CPUQuotaPerSecUSec", "t", USEC_INFINITY);
diff --git a/src/shared/cpu-set-util.c b/src/shared/cpu-set-util.c
index e3e6963..2cb4a36 100644
--- a/src/shared/cpu-set-util.c
+++ b/src/shared/cpu-set-util.c
@@ -7,6 +7,7 @@
 
 #include "alloc-util.h"
 #include "cpu-set-util.h"
+#include "cgroup-util.h"
 #include "dirent-util.h"
 #include "errno-util.h"
 #include "extract-word.h"
diff --git a/src/test/test-cgroup-mask.c b/src/test/test-cgroup-mask.c
index 19e159b..425fe19 100644
--- a/src/test/test-cgroup-mask.c
+++ b/src/test/test-cgroup-mask.c
@@ -55,6 +55,7 @@ static int test_cgroup_mask(void) {
          * else. */
         m->default_cpu_accounting =
                 m->default_memory_accounting =
+                m->default_cpuset_accounting =
                 m->default_blockio_accounting =
                 m->default_io_accounting =
                 m->default_tasks_accounting = false;
@@ -140,10 +141,10 @@ static void test_cg_mask_to_string_one(CGroupMask mask, const char *t) {
 
 static void test_cg_mask_to_string(void) {
         test_cg_mask_to_string_one(0, NULL);
-        test_cg_mask_to_string_one(_CGROUP_MASK_ALL, "cpu cpuacct cpuset io blkio memory devices pids bpf-firewall bpf-devices bpf-foreign bpf-socket-bind");
+        test_cg_mask_to_string_one(_CGROUP_MASK_ALL, "cpu cpuacct cpuset2 io blkio memory devices pids cpuset bpf-firewall bpf-devices bpf-foreign bpf-socket-bind");
         test_cg_mask_to_string_one(CGROUP_MASK_CPU, "cpu");
         test_cg_mask_to_string_one(CGROUP_MASK_CPUACCT, "cpuacct");
-        test_cg_mask_to_string_one(CGROUP_MASK_CPUSET, "cpuset");
+        test_cg_mask_to_string_one(CGROUP_MASK_CPUSET2, "cpuset2");
         test_cg_mask_to_string_one(CGROUP_MASK_IO, "io");
         test_cg_mask_to_string_one(CGROUP_MASK_BLKIO, "blkio");
         test_cg_mask_to_string_one(CGROUP_MASK_MEMORY, "memory");
diff --git a/test/fuzz/fuzz-unit-file/directives-all.service b/test/fuzz/fuzz-unit-file/directives-all.service
index 3039d1c..5f8cdd8 100644
--- a/test/fuzz/fuzz-unit-file/directives-all.service
+++ b/test/fuzz/fuzz-unit-file/directives-all.service
@@ -48,6 +48,11 @@ BusName=
 CoredumpFilter=
 CPUAccounting=
 CPUQuota=
+CPUSetAccounting=
+CPUSetCloneChildren=
+CPUSetCpus=
+CPUSetMemMigrate=
+CPUSetMems=
 CPUShares=
 CPUWeight=
 CapabilityBoundingSet=
diff --git a/test/fuzz/fuzz-unit-file/directives.mount b/test/fuzz/fuzz-unit-file/directives.mount
index 451f291..3adfd5b 100644
--- a/test/fuzz/fuzz-unit-file/directives.mount
+++ b/test/fuzz/fuzz-unit-file/directives.mount
@@ -19,6 +19,11 @@ CPUQuotaPeriodSec=
 CPUSchedulingPolicy=
 CPUSchedulingPriority=
 CPUSchedulingResetOnFork=
+CPUSetAccounting=
+CPUSetCloneChildren=
+CPUSetCpus=
+CPUSetMemMigrate=
+CPUSetMems=
 CPUShares=
 CPUWeight=
 CacheDirectory=
diff --git a/test/fuzz/fuzz-unit-file/directives.scope b/test/fuzz/fuzz-unit-file/directives.scope
index 7e69cf8..c953f9c 100644
--- a/test/fuzz/fuzz-unit-file/directives.scope
+++ b/test/fuzz/fuzz-unit-file/directives.scope
@@ -11,6 +11,11 @@ BlockIOWriteBandwidth=
 CPUAccounting=
 CPUQuota=
 CPUQuotaPeriodSec=
+CPUSetAccounting=
+CPUSetCloneChildren=
+CPUSetCpus=
+CPUSetMemMigrate=
+CPUSetMems=
 CPUShares=
 CPUWeight=
 DefaultMemoryLow=
diff --git a/test/fuzz/fuzz-unit-file/directives.service b/test/fuzz/fuzz-unit-file/directives.service
index de7d2c7..aa5ad32 100644
--- a/test/fuzz/fuzz-unit-file/directives.service
+++ b/test/fuzz/fuzz-unit-file/directives.service
@@ -63,6 +63,11 @@ ConditionSecurity=
 ConditionUser=
 ConditionVirtualization=
 Conflicts=
+CPUSetAccounting=
+CPUSetCloneChildren=
+CPUSetCpus=
+CPUSetMemMigrate=
+CPUSetMems=
 DefaultDependencies=
 Description=
 Documentation=
diff --git a/test/fuzz/fuzz-unit-file/directives.slice b/test/fuzz/fuzz-unit-file/directives.slice
index 789ac8f..54cb55d 100644
--- a/test/fuzz/fuzz-unit-file/directives.slice
+++ b/test/fuzz/fuzz-unit-file/directives.slice
@@ -11,6 +11,11 @@ BlockIOWriteBandwidth=
 CPUAccounting=
 CPUQuota=
 CPUQuotaPeriodSec=
+CPUSetAccounting=
+CPUSetCloneChildren=
+CPUSetCpus=
+CPUSetMemMigrate=
+CPUSetMems=
 CPUShares=
 CPUWeight=
 DefaultMemoryLow=
diff --git a/test/fuzz/fuzz-unit-file/directives.socket b/test/fuzz/fuzz-unit-file/directives.socket
index 11f589e..aa9e758 100644
--- a/test/fuzz/fuzz-unit-file/directives.socket
+++ b/test/fuzz/fuzz-unit-file/directives.socket
@@ -24,6 +24,11 @@ CPUQuotaPeriodSec=
 CPUSchedulingPolicy=
 CPUSchedulingPriority=
 CPUSchedulingResetOnFork=
+CPUSetAccounting=
+CPUSetCloneChildren=
+CPUSetCpus=
+CPUSetMemMigrate=
+CPUSetMems=
 CPUShares=
 CPUWeight=
 CacheDirectory=
diff --git a/test/fuzz/fuzz-unit-file/directives.swap b/test/fuzz/fuzz-unit-file/directives.swap
index 582a136..bc07775 100644
--- a/test/fuzz/fuzz-unit-file/directives.swap
+++ b/test/fuzz/fuzz-unit-file/directives.swap
@@ -19,6 +19,11 @@ CPUQuotaPeriodSec=
 CPUSchedulingPolicy=
 CPUSchedulingPriority=
 CPUSchedulingResetOnFork=
+CPUSetAccounting=
+CPUSetCloneChildren=
+CPUSetCpus=
+CPUSetMemMigrate=
+CPUSetMems=
 CPUShares=
 CPUWeight=
 CacheDirectory=
-- 
2.33.0

