support cgroup v2

Signed-off-by: WangFengTu <wangfengtu@huawei.com>
This commit is contained in:
WangFengTu 2021-02-08 14:07:25 +08:00
parent 0c8f2d72ed
commit 80162dc014
2 changed files with 590 additions and 1 deletions

View File

@ -0,0 +1,582 @@
From 0eac597a6f853c4eb41d7ebe58398c117798542c Mon Sep 17 00:00:00 2001
From: WangFengTu <wangfengtu@huawei.com>
Date: Fri, 29 Jan 2021 16:55:13 +0800
Subject: [PATCH] support cgroup v2
Signed-off-by: WangFengTu <wangfengtu@huawei.com>
---
src/lxc/cgroups/cgroup2_devices.c | 126 +++++++++++++++++++----------
src/lxc/cgroups/isulad_cgfsng.c | 56 ++++++++++++-
src/lxc/lxccontainer.c | 129 ++++++++++++++++++++++++++++++
3 files changed, 269 insertions(+), 42 deletions(-)
diff --git a/src/lxc/cgroups/cgroup2_devices.c b/src/lxc/cgroups/cgroup2_devices.c
index 4efb28fb..05613c51 100644
--- a/src/lxc/cgroups/cgroup2_devices.c
+++ b/src/lxc/cgroups/cgroup2_devices.c
@@ -25,6 +25,19 @@
#include <linux/bpf.h>
#include <linux/filter.h>
+#define BPF_LOG_BUF_SIZE (1 << 23) /* 8MB */
+#ifndef BPF_LOG_LEVEL1
+#define BPF_LOG_LEVEL1 1
+#endif
+
+#ifndef BPF_LOG_LEVEL2
+#define BPF_LOG_LEVEL2 2
+#endif
+
+#ifndef BPF_LOG_LEVEL
+#define BPF_LOG_LEVEL (BPF_LOG_LEVEL1 | BPF_LOG_LEVEL2)
+#endif
+
lxc_log_define(cgroup2_devices, cgroup);
static int bpf_program_add_instructions(struct bpf_program *prog,
@@ -42,6 +55,8 @@ static int bpf_program_add_instructions(struct bpf_program *prog,
return log_error_errno(-1, ENOMEM, "Failed to reallocate bpf cgroup program");
prog->instructions = new_insn;
+ memset(prog->instructions + prog->n_instructions, 0,
+ sizeof(struct bpf_insn) * count);
memcpy(prog->instructions + prog->n_instructions, instructions,
sizeof(struct bpf_insn) * count);
prog->n_instructions += count;
@@ -118,29 +133,27 @@ void bpf_program_free(struct bpf_program *prog)
.off = 0, \
.imm = 0})
-static int bpf_access_mask(const char *acc)
+static int bpf_access_mask(const char *acc, __u32 *mask)
{
- int mask = 0;
-
if (!acc)
- return mask;
+ return 0;
for (; *acc; acc++)
switch (*acc) {
case 'r':
- mask |= BPF_DEVCG_ACC_READ;
+ *mask |= BPF_DEVCG_ACC_READ;
break;
case 'w':
- mask |= BPF_DEVCG_ACC_WRITE;
+ *mask |= BPF_DEVCG_ACC_WRITE;
break;
case 'm':
- mask |= BPF_DEVCG_ACC_MKNOD;
+ *mask |= BPF_DEVCG_ACC_MKNOD;
break;
default:
return -EINVAL;
}
- return mask;
+ return 0;
}
static int bpf_device_type(char type)
@@ -157,19 +170,18 @@ static int bpf_device_type(char type)
return -1;
}
-static inline bool bpf_device_all_access(int access_mask)
+static inline bool bpf_device_all_access(__u32 access_mask)
{
- return (access_mask == (BPF_DEVCG_ACC_READ | BPF_DEVCG_ACC_WRITE |
- BPF_DEVCG_ACC_MKNOD));
+ return access_mask == (BPF_DEVCG_ACC_READ | BPF_DEVCG_ACC_WRITE | BPF_DEVCG_ACC_MKNOD);
}
struct bpf_program *bpf_program_new(uint32_t prog_type)
{
__do_free struct bpf_program *prog = NULL;
- prog = calloc(1, sizeof(struct bpf_program));
+ prog = zalloc(sizeof(struct bpf_program));
if (!prog)
- return NULL;
+ return ret_set_errno(NULL, ENOMEM);
prog->prog_type = prog_type;
prog->kernel_fd = -EBADF;
@@ -209,12 +221,10 @@ int bpf_program_append_device(struct bpf_program *prog, struct device_item *devi
{
int ret;
int jump_nr = 1;
- struct bpf_insn bpf_access_decision[] = {
- BPF_MOV64_IMM(BPF_REG_0, device->allow),
- BPF_EXIT_INSN(),
- };
- int access_mask;
+ __u32 access_mask = 0;
int device_type;
+ struct bpf_insn bpf_access_decision[2];
+ bool add_exist = false;
if (!prog || !device)
return ret_set_errno(-1, EINVAL);
@@ -225,6 +235,13 @@ int bpf_program_append_device(struct bpf_program *prog, struct device_item *devi
return 0;
}
+ ret = bpf_access_mask(device->access, &access_mask);
+ if (ret < 0)
+ return log_error_errno(ret, -ret, "Invalid access mask specified %s", device->access);
+
+ if (!bpf_device_all_access(access_mask))
+ jump_nr += 3;
+
device_type = bpf_device_type(device->type);
if (device_type < 0)
return log_error_errno(-1, EINVAL, "Invalid bpf cgroup device type %c", device->type);
@@ -232,63 +249,67 @@ int bpf_program_append_device(struct bpf_program *prog, struct device_item *devi
if (device_type > 0)
jump_nr++;
- access_mask = bpf_access_mask(device->access);
- if (!bpf_device_all_access(access_mask))
- jump_nr += 3;
-
- if (device->major != -1)
+ if (device->major >= 0)
jump_nr++;
- if (device->minor != -1)
+ if (device->minor >= 0)
jump_nr++;
if (device_type > 0) {
struct bpf_insn ins[] = {
- BPF_JMP_IMM(BPF_JNE, BPF_REG_2, device_type, jump_nr--),
+ BPF_JMP_IMM(BPF_JNE, BPF_REG_2, device_type, jump_nr--),
};
ret = bpf_program_add_instructions(prog, ins, ARRAY_SIZE(ins));
if (ret)
return log_error_errno(-1, errno, "Failed to add instructions to bpf cgroup program");
+ add_exist = true;
}
if (!bpf_device_all_access(access_mask)) {
struct bpf_insn ins[] = {
- BPF_MOV32_REG(BPF_REG_1, BPF_REG_3),
- BPF_ALU32_IMM(BPF_AND, BPF_REG_1, access_mask),
- BPF_JMP_REG(BPF_JNE, BPF_REG_1, BPF_REG_3, jump_nr),
+ BPF_MOV32_REG(BPF_REG_1, BPF_REG_3),
+ BPF_ALU32_IMM(BPF_AND, BPF_REG_1, access_mask),
+ BPF_JMP_REG(BPF_JNE, BPF_REG_1, BPF_REG_3, jump_nr-2),
};
jump_nr -= 3;
ret = bpf_program_add_instructions(prog, ins, ARRAY_SIZE(ins));
if (ret)
return log_error_errno(-1, errno, "Failed to add instructions to bpf cgroup program");
+ add_exist = true;
}
if (device->major >= 0) {
struct bpf_insn ins[] = {
- BPF_JMP_IMM(BPF_JNE, BPF_REG_4, device->major, jump_nr--),
+ BPF_JMP_IMM(BPF_JNE, BPF_REG_4, device->major, jump_nr--),
};
ret = bpf_program_add_instructions(prog, ins, ARRAY_SIZE(ins));
if (ret)
return log_error_errno(-1, errno, "Failed to add instructions to bpf cgroup program");
+ add_exist = true;
}
if (device->minor >= 0) {
struct bpf_insn ins[] = {
- BPF_JMP_IMM(BPF_JNE, BPF_REG_5, device->minor, jump_nr--),
+ BPF_JMP_IMM(BPF_JNE, BPF_REG_5, device->minor, jump_nr--),
};
ret = bpf_program_add_instructions(prog, ins, ARRAY_SIZE(ins));
if (ret)
return log_error_errno(-1, errno, "Failed to add instructions to bpf cgroup program");
+ add_exist = true;
}
- ret = bpf_program_add_instructions(prog, bpf_access_decision,
- ARRAY_SIZE(bpf_access_decision));
- if (ret)
- return log_error_errno(-1, errno, "Failed to add instructions to bpf cgroup program");
+ if (add_exist) {
+ bpf_access_decision[0] = BPF_MOV64_IMM(BPF_REG_0, device->allow);
+ bpf_access_decision[1] = BPF_EXIT_INSN();
+ ret = bpf_program_add_instructions(prog, bpf_access_decision,
+ ARRAY_SIZE(bpf_access_decision));
+ if (ret)
+ return log_error_errno(-1, errno, "Failed to add instructions to bpf cgroup program");
+ }
return 0;
}
@@ -310,30 +331,49 @@ int bpf_program_finalize(struct bpf_program *prog)
return bpf_program_add_instructions(prog, ins, ARRAY_SIZE(ins));
}
-static int bpf_program_load_kernel(struct bpf_program *prog, char *log_buf,
- size_t log_size)
+static int bpf_program_load_kernel(struct bpf_program *prog)
{
+ __do_free char *log_buf = NULL;
+ __u32 log_level = 0;
+ __u32 log_size = 0;
union bpf_attr attr;
+ struct rlimit limit = {
+ .rlim_cur = RLIM_INFINITY,
+ .rlim_max = RLIM_INFINITY,
+ };
if (prog->kernel_fd >= 0) {
- memset(log_buf, 0, log_size);
return 0;
}
+ if (lxc_log_get_level() <= LXC_LOG_LEVEL_DEBUG) {
+ log_buf = zalloc(BPF_LOG_BUF_SIZE);
+ if (!log_buf) {
+ WARN("Failed to allocate bpf log buffer");
+ } else {
+ log_level = BPF_LOG_LEVEL;
+ log_size = BPF_LOG_BUF_SIZE;
+ }
+ }
+
+ if (setrlimit(RLIMIT_MEMLOCK, &limit) < 0)
+ return log_error_errno(-1, errno, "Failed to set rlimit memlock to unlimited");
+
attr = (union bpf_attr){
.prog_type = prog->prog_type,
.insns = PTR_TO_UINT64(prog->instructions),
.insn_cnt = prog->n_instructions,
.license = PTR_TO_UINT64("GPL"),
.log_buf = PTR_TO_UINT64(log_buf),
- .log_level = !!log_buf,
+ .log_level = log_level,
.log_size = log_size,
};
prog->kernel_fd = bpf(BPF_PROG_LOAD, &attr, sizeof(attr));
if (prog->kernel_fd < 0)
- return log_error_errno(-1, errno, "Failed to load bpf program");
+ return log_error_errno(-1, errno, "Failed to load bpf program: %s", log_buf);
+ TRACE("Loaded bpf program: %s", log_buf ?: "(null)");
return 0;
}
@@ -362,7 +402,7 @@ int bpf_program_cgroup_attach(struct bpf_program *prog, int type,
return true;
}
- ret = bpf_program_load_kernel(prog, NULL, 0);
+ ret = bpf_program_load_kernel(prog);
if (ret < 0)
return log_error_errno(-1, ret, "Failed to load bpf program");
@@ -518,11 +558,15 @@ bool bpf_devices_cgroup_supported(void)
if (prog < 0)
return log_trace(false, "Failed to allocate new bpf device cgroup program");
+ ret = bpf_program_init(prog);
+ if (ret)
+ return log_error_errno(false, ENOMEM, "Failed to initialize bpf program");
+
ret = bpf_program_add_instructions(prog, dummy, ARRAY_SIZE(dummy));
if (ret < 0)
return log_trace(false, "Failed to add new instructions to bpf device cgroup program");
- ret = bpf_program_load_kernel(prog, NULL, 0);
+ ret = bpf_program_load_kernel(prog);
if (ret < 0)
return log_trace(false, "Failed to load new bpf device cgroup program");
diff --git a/src/lxc/cgroups/isulad_cgfsng.c b/src/lxc/cgroups/isulad_cgfsng.c
index e16f8a19..c80527d5 100644
--- a/src/lxc/cgroups/isulad_cgfsng.c
+++ b/src/lxc/cgroups/isulad_cgfsng.c
@@ -823,6 +823,9 @@ static bool isulad_cg_legacy_handle_cpuset_hierarchy(struct hierarchy *h, char *
char *cgpath, *slash;
bool sub_mk_success = false;
+ if (is_unified_hierarchy(h))
+ return true;
+
if (!string_in_list(h->controllers, "cpuset"))
return true;
@@ -1288,6 +1291,20 @@ __cgfsng_ops static bool isulad_cgfsng_mount(struct cgroup_ops *ops,
ERROR("Failed to create directory: %s", tmpfspath);
goto on_error;
}
+
+ if (ops->cgroup_layout == CGROUP_LAYOUT_UNIFIED) {
+ if (has_cgns && wants_force_mount) {
+ /*
+ * If cgroup namespaces are supported but the container
+ * will not have CAP_SYS_ADMIN after it has started we
+ * need to mount the cgroups manually.
+ */
+ return cg_mount_in_cgroup_namespace(type, ops->unified, tmpfspath) == 0;
+ }
+
+ return cg_mount_cgroup_full(type, ops->unified, tmpfspath) == 0;
+ }
+
ret = safe_mount(NULL, tmpfspath, "tmpfs",
MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_RELATIME,
"size=10240k,mode=755", root, handler->conf->lsm_se_mount_context);
@@ -2196,8 +2213,16 @@ __cgfsng_ops static int isulad_cgfsng_set(struct cgroup_ops *ops,
h = get_hierarchy(ops, controller);
if (h) {
char *fullpath;
-
fullpath = build_full_cgpath_from_monitorpath(h, path, filename);
+
+ if (strcmp(filename, "io.weight") == 0 || strcmp(filename, "io.bfq.weight") == 0) {
+ if (!file_exists(fullpath)) {
+ free(path);
+ free(fullpath);
+ return 0;
+ }
+ }
+
ret = lxc_write_to_file(fullpath, value, strlen(value), false, 0666);
free(fullpath);
}
@@ -2428,6 +2453,9 @@ __cgfsng_ops static bool isulad_cgfsng_setup_limits_legacy(struct cgroup_ops *op
if (!ops->hierarchies)
return ret_set_errno(false, EINVAL);
+ if (pure_unified_layout(ops))
+ return true;
+
sorted_cgroup_settings = sort_cgroup_settings(cgroup_settings);
if (!sorted_cgroup_settings)
return false;
@@ -2528,6 +2556,7 @@ static int bpf_device_cgroup_prepare(struct cgroup_ops *ops,
__cgfsng_ops static bool isulad_cgfsng_setup_limits(struct cgroup_ops *ops,
struct lxc_handler *handler)
{
+ __do_free char *path = NULL;
struct lxc_list *cgroup_settings, *iterator;
struct hierarchy *h;
struct lxc_conf *conf;
@@ -2549,6 +2578,9 @@ __cgfsng_ops static bool isulad_cgfsng_setup_limits(struct cgroup_ops *ops,
return true;
cgroup_settings = &conf->cgroup2;
+ if (!pure_unified_layout(ops))
+ return true;
+
if (!ops->unified)
return false;
h = ops->unified;
@@ -2560,7 +2592,29 @@ __cgfsng_ops static bool isulad_cgfsng_setup_limits(struct cgroup_ops *ops,
if (strncmp("devices", cg->subsystem, 7) == 0) {
ret = bpf_device_cgroup_prepare(ops, conf, cg->subsystem,
cg->value);
+ } else if (strcmp(cg->subsystem, "files.limit") == 0) {
+ long long int setvalue = 0;
+ const char *cgvalue = cg->value;
+
+ if (lxc_safe_long_long(cgvalue, &setvalue) != 0)
+ return log_error(false, "Invalid integer value %s", cgvalue);
+
+ if (setvalue <= 0)
+ cgvalue = "max";
+
+ ret = lxc_write_openat(h->container_full_path,
+ cg->subsystem, cgvalue,
+ strlen(cgvalue));
+ if (ret < 0)
+ return log_error_errno(false, errno, "Failed to set \"%s\" to \"%s\"",
+ cg->subsystem, cgvalue);
} else {
+ if (strcmp(cg->subsystem, "io.weight") == 0 || strcmp(cg->subsystem, "io.bfq.weight") == 0) {
+ path = must_make_path(h->container_full_path, cg->subsystem, NULL);
+ if (!file_exists(path)) {
+ continue;
+ }
+ }
ret = lxc_write_openat(h->container_full_path,
cg->subsystem, cg->value,
strlen(cg->value));
diff --git a/src/lxc/lxccontainer.c b/src/lxc/lxccontainer.c
index 06552ce5..5769b251 100644
--- a/src/lxc/lxccontainer.c
+++ b/src/lxc/lxccontainer.c
@@ -87,6 +87,9 @@
lxc_log_define(lxccontainer, lxc);
+typedef bool (*func_is_io_stat_read)(const char *value);
+typedef bool (*func_is_io_stat_write)(const char *value);
+
static bool do_lxcapi_destroy(struct lxc_container *c);
static const char *lxcapi_get_config_path(struct lxc_container *c);
#define do_lxcapi_get_config_path(c) lxcapi_get_config_path(c)
@@ -5768,6 +5771,26 @@ static uint64_t metrics_get_ull(struct lxc_container *c, struct cgroup_ops *cgro
return val;
}
+static uint64_t metrics_get_ull_with_max(struct lxc_container *c, struct cgroup_ops *cgroup_ops, const char *item)
+{
+ char buf[80] = {0};
+ int len = 0;
+ uint64_t val = 0;
+
+ len = cgroup_ops->get(cgroup_ops, item, buf, sizeof(buf), c->name, c->config_path);
+ if (len <= 0) {
+ DEBUG("unable to read cgroup item %s", item);
+ return 0;
+ }
+
+ if (strcmp(buf, "max") == 0) {
+ return ULONG_MAX;
+ }
+
+ val = strtoull(buf, NULL, 0);
+ return val;
+}
+
static inline bool is_blk_metrics_read(const char *value)
{
return strcmp(value, "Read") == 0;
@@ -5826,6 +5849,60 @@ err_out:
return;
}
+static void metrics_get_io_stats_v2(struct lxc_container *c, struct cgroup_ops *cgroup_ops, const char *item, struct lxc_blkio_metrics *stats, func_is_io_stat_read is_io_stat_read, func_is_io_stat_write is_io_stat_write)
+{
+#define BUFSIZE 4096
+ char buf[BUFSIZE] = {0};
+ int i = 0;
+ int j = 0;
+ int len = 0;
+ char **lines = NULL;
+ char **cols = NULL;
+ char **kv = NULL;
+
+ len = cgroup_ops->get(cgroup_ops, item, buf, sizeof(buf), c->name, c->config_path);
+ if (len <= 0) {
+ DEBUG("unable to read cgroup item %s", item);
+ return;
+ }
+
+ lines = lxc_string_split_and_trim(buf, '\n');
+ if (lines == NULL) {
+ return;
+ }
+
+ (void)memset(stats, 0, sizeof(struct lxc_blkio_metrics));
+ // line example:
+ // 259:0 rbytes=0 wbytes=12288 rios=0 wios=4 dbytes=0 dios=0
+ for (i = 0; lines[i]; i++) {
+ cols = lxc_string_split_and_trim(lines[i], ' ');
+ if (cols == NULL || lxc_array_len((void **)cols) < 2) {
+ goto err_out;
+ }
+ len = lxc_array_len((void **)cols);
+ for (j = 1; j < len; j++) {
+ kv = lxc_string_split(cols[j], '=');
+ if (kv == NULL || lxc_array_len((void **)kv) != 2) {
+ lxc_free_array((void **)kv, free);
+ continue;
+ }
+ if (is_io_stat_read(kv[0])) {
+ stats->read += strtoull(kv[1], NULL, 0);
+ } else if (is_io_stat_write(kv[0])) {
+ stats->write += strtoull(kv[1], NULL, 0);
+ }
+ lxc_free_array((void **)kv, free);
+ }
+ lxc_free_array((void **)cols, free);
+ }
+
+ stats->total = stats->read + stats->write;
+
+err_out:
+ lxc_free_array((void **)lines, free);
+ return;
+}
+
static uint64_t metrics_match_get_ull(struct lxc_container *c, struct cgroup_ops *cgroup_ops, const char *item, const char *match, int column)
{
#define BUFSIZE 4096
@@ -5874,6 +5951,54 @@ err_out:
return val;
}
+static bool is_io_stat_rbytes(const char *value)
+{
+ return strcmp(value, "rbytes") == 0;
+}
+
+static bool is_io_stat_wbytes(const char *value)
+{
+ return strcmp(value, "wbytes") == 0;
+}
+
+static bool is_io_stat_rios(const char *value)
+{
+ return strcmp(value, "rios") == 0;
+}
+
+static bool is_io_stat_wios(const char *value)
+{
+ return strcmp(value, "wios") == 0;
+}
+
+static bool unified_metrics_get(struct lxc_container *c, struct cgroup_ops *cgroup_ops, struct lxc_container_metrics *metrics)
+{
+ // cpu
+ metrics->cpu_use_nanos = metrics_match_get_ull(c, cgroup_ops, "cpu.stat", "usage_usec", 1) * 1000;
+ metrics->cpu_use_user = metrics_match_get_ull(c, cgroup_ops, "cpu.stat", "user_usec", 1) * 1000;
+ metrics->cpu_use_sys = metrics_match_get_ull(c, cgroup_ops, "cpu.stat", "system_usec", 1) * 1000;
+
+ // io
+ metrics_get_io_stats_v2(c, cgroup_ops, "io.stat", &metrics->io_service_bytes, is_io_stat_rbytes, is_io_stat_wbytes);
+ metrics_get_io_stats_v2(c, cgroup_ops, "io.stat", &metrics->io_serviced, is_io_stat_rios, is_io_stat_wios);
+
+ // memory
+ metrics->mem_used = metrics_get_ull(c, cgroup_ops, "memory.current");
+ metrics->mem_limit = metrics_get_ull_with_max(c, cgroup_ops, "memory.max");
+ metrics->inactive_file_total = metrics_match_get_ull(c, cgroup_ops, "memory.stat", "inactive_file", 1);
+ metrics->cache = metrics_match_get_ull(c, cgroup_ops, "memory.stat", "file", 1);
+ metrics->cache_total = metrics->cache;
+
+ // cgroup v2 does not support kernel memory
+ metrics->kmem_used = 0;
+ metrics->kmem_limit = 0;
+
+ // pids
+ metrics->pids_current = metrics_get_ull(c, cgroup_ops, "pids.current");
+
+ return true;
+}
+
/* isulad add get container metrics */
static bool do_lxcapi_get_container_metrics(struct lxc_container *c, struct lxc_container_metrics *metrics)
{
@@ -5897,6 +6022,10 @@ static bool do_lxcapi_get_container_metrics(struct lxc_container *c, struct lxc
return false;
}
+ if (cgroup_ops->cgroup_layout == CGROUP_LAYOUT_UNIFIED) {
+ return unified_metrics_get(c, cgroup_ops, metrics);
+ }
+
metrics->cpu_use_nanos = metrics_get_ull(c, cgroup_ops, "cpuacct.usage");
metrics->pids_current = metrics_get_ull(c, cgroup_ops, "pids.current");
--
2.20.1

View File

@ -1,4 +1,4 @@
%global _release 2021012801 %global _release 2021033101
Name: lxc Name: lxc
Version: 4.0.3 Version: 4.0.3
@ -27,6 +27,7 @@ Patch0016: 0016-avoid-using-void-pointers-in-caclulation.patch
Patch0017: 0017-fix-compilation-errors-without-libcap.patch Patch0017: 0017-fix-compilation-errors-without-libcap.patch
Patch0018: 0018-IO-fix-io-data-miss-when-exec-with-pipes.patch Patch0018: 0018-IO-fix-io-data-miss-when-exec-with-pipes.patch
Patch0019: 0019-metrics-add-total_inactive_file-metric-for-memory.patch Patch0019: 0019-metrics-add-total_inactive_file-metric-for-memory.patch
Patch0020: 0020-support-cgroup-v2.patch
BuildRequires: systemd-units git libtool graphviz docbook2X doxygen chrpath BuildRequires: systemd-units git libtool graphviz docbook2X doxygen chrpath
BuildRequires: pkgconfig(libseccomp) BuildRequires: pkgconfig(libseccomp)
@ -198,6 +199,12 @@ make check
%{_mandir}/*/man7/%{name}* %{_mandir}/*/man7/%{name}*
%changelog %changelog
* Wed Mar 31 2021 wangfengtu <wangfengtu@huawei.com> - 4.0.3-2021033101
- Type:enhancement
- ID:NA
- SUG:NA
- DESC: support cgroup v2
* Thu Jan 28 2021 lifeng <lifeng68@huawei.com> - 4.0.3-2021012801 * Thu Jan 28 2021 lifeng <lifeng68@huawei.com> - 4.0.3-2021012801
- Type:enhancement - Type:enhancement
- ID:NA - ID:NA