summaryrefslogtreecommitdiff
path: root/0027-feature-add-support-for-cgroup-v2-metrics.patch
diff options
context:
space:
mode:
authorCoprDistGit <infra@openeuler.org>2024-09-03 03:24:28 +0000
committerCoprDistGit <infra@openeuler.org>2024-09-03 03:24:28 +0000
commite45819fcb4a96649a4030db7684f140d5ca46735 (patch)
tree544dac3e30a0448eabdc50add41aa3a18982d9f1 /0027-feature-add-support-for-cgroup-v2-metrics.patch
parent1a71e3afebb4b43be63949dcc8e882fe7643f13b (diff)
automatic import of iSuladopeneuler24.03_LTS
Diffstat (limited to '0027-feature-add-support-for-cgroup-v2-metrics.patch')
-rw-r--r--0027-feature-add-support-for-cgroup-v2-metrics.patch1084
1 files changed, 1084 insertions, 0 deletions
diff --git a/0027-feature-add-support-for-cgroup-v2-metrics.patch b/0027-feature-add-support-for-cgroup-v2-metrics.patch
new file mode 100644
index 0000000..f5b4073
--- /dev/null
+++ b/0027-feature-add-support-for-cgroup-v2-metrics.patch
@@ -0,0 +1,1084 @@
+From 7c7cd82619ed1f7e36d34da1afc2b417a90b3040 Mon Sep 17 00:00:00 2001
+From: zhongtao <zhongtao17@huawei.com>
+Date: Tue, 23 Jan 2024 17:18:51 +0800
+Subject: [PATCH 27/43] =?UTF-8?q?=E3=80=90feature=E3=80=91add=20support=20?=
+ =?UTF-8?q?for=20cgroup=20v2=20metrics?=
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: zhongtao <zhongtao17@huawei.com>
+---
+ src/daemon/common/cgroup.c | 237 ++--------
+ src/daemon/common/cgroup.h | 11 +-
+ src/daemon/common/cgroup_v1.c | 194 +++------
+ src/daemon/common/cgroup_v2.c | 406 ++++++++++++++++++
+ .../v1/v1_cri_pod_sandbox_manager_service.cc | 2 +-
+ .../cri_pod_sandbox_manager_service.cc | 2 +-
+ src/utils/cutils/utils_array.h | 6 +
+ 7 files changed, 506 insertions(+), 352 deletions(-)
+ create mode 100644 src/daemon/common/cgroup_v2.c
+
+diff --git a/src/daemon/common/cgroup.c b/src/daemon/common/cgroup.c
+index 2d1cabb2..3c58f7fa 100644
+--- a/src/daemon/common/cgroup.c
++++ b/src/daemon/common/cgroup.c
+@@ -29,32 +29,6 @@
+ #include "utils_array.h"
+ #include "sysinfo.h"
+
+-// Cgroup V2 Item Definition
+-#define CGROUP2_CPU_WEIGHT "cpu.weight"
+-#define CGROUP2_CPU_MAX "cpu.max"
+-#define CGROUP2_CPUSET_CPUS_EFFECTIVE "cpuset.cpus.effective"
+-#define CGROUP2_CPUSET_MEMS_EFFECTIVE "cpuset.mems.effective"
+-#define CGROUP2_CPUSET_CPUS "cpuset.cpus"
+-#define CGROUP2_CPUSET_MEMS "cpuset.mems"
+-#define CGROUP2_IO_WEIGHT "io.weight"
+-#define CGROUP2_IO_BFQ_WEIGHT "io.bfq.weight"
+-#define CGROUP2_IO_MAX "io.max"
+-#define CGROUP2_MEMORY_MAX "memory.max"
+-#define CGROUP2_MEMORY_LOW "memory.low"
+-#define CGROUP2_MEMORY_SWAP_MAX "memory.swap.max"
+-#define CGROUP2_HUGETLB_MAX "hugetlb.%s.max"
+-#define CGROUP2_PIDS_MAX "pids.max"
+-#define CGROUP2_FILES_LIMIT "files.limit"
+-
+-#define CGROUP2_CONTROLLERS_PATH CGROUP_MOUNTPOINT"/cgroup.controllers"
+-#define CGROUP2_SUBTREE_CONTROLLER_PATH CGROUP_MOUNTPOINT"/cgroup.subtree_control"
+-#define CGROUP2_CPUSET_CPUS_EFFECTIVE_PATH CGROUP_MOUNTPOINT"/cpuset.cpus.effective"
+-#define CGROUP2_CPUSET_MEMS_EFFECTIVE_PATH CGROUP_MOUNTPOINT"/cpuset.mems.effective"
+-
+-#ifndef CGROUP2_SUPER_MAGIC
+-#define CGROUP2_SUPER_MAGIC 0x63677270
+-#endif
+-
+ #ifndef CGROUP_SUPER_MAGIC
+ #define CGROUP_SUPER_MAGIC 0x27e0eb
+ #endif
+@@ -485,20 +459,6 @@ out:
+ return layers;
+ }
+
+-/* cgroup enabled */
+-static bool cgroup_enabled(const char *mountpoint, const char *name)
+-{
+- char path[PATH_MAX] = { 0 };
+- int nret;
+-
+- nret = snprintf(path, sizeof(path), "%s/%s", mountpoint, name);
+- if (nret < 0 || (size_t)nret >= sizeof(path)) {
+- ERROR("Path is too long");
+- return false;
+- }
+- return util_file_exists(path);
+-}
+-
+ char *common_find_cgroup_subsystem_mountpoint(const cgroup_layer_t *layers, const char *subsystem)
+ {
+ size_t i;
+@@ -607,188 +567,59 @@ int common_get_cgroup_version(void)
+ return CGROUP_VERSION_1;
+ }
+
+-static int cgroup2_enable_all()
++static int get_value_ull(const char *content, void *result)
+ {
+- int ret = 0;
+- int nret = 0;
+- int n = 0;
+- size_t i = 0;
+- const char *space = "";
+- char *controllers_str = NULL;
+- char *subtree_controller_str = NULL;
+- char **controllers = NULL;
+- char enable_controllers[PATH_MAX] = { 0 };
+-
+- controllers_str = util_read_content_from_file(CGROUP2_CONTROLLERS_PATH);
+- if (controllers_str == NULL || strlen(controllers_str) == 0 || strcmp(controllers_str, "\n") == 0) {
+- WARN("no cgroup controller found");
+- goto out;
+- }
+-
+- subtree_controller_str = util_read_content_from_file(CGROUP2_SUBTREE_CONTROLLER_PATH);
+- if (subtree_controller_str != NULL && strcmp(controllers_str, subtree_controller_str) == 0) {
+- goto out;
+- }
++ uint64_t ull_result = 0;
+
+- controllers = util_string_split(controllers_str, ' ');
+- if (controllers == NULL) {
+- ERROR("split %s failed", controllers_str);
+- ret = -1;
+- goto out;
+- }
+-
+- for (i = 0; i < util_array_len((const char **)controllers); i++) {
+- nret = snprintf(enable_controllers + n, PATH_MAX - n, "%s+%s", space, controllers[i]);
+- if (nret < 0 || (size_t)nret >= PATH_MAX - n) {
+- ERROR("Path is too long");
+- goto out;
+- }
+- n += nret;
+- space = " ";
+- }
+- ret = util_write_file(CGROUP2_SUBTREE_CONTROLLER_PATH, enable_controllers, strlen(enable_controllers),
+- DEFAULT_CGROUP_FILE_MODE);
+- if (ret != 0) {
+- SYSERROR("write %s to %s failed", enable_controllers, CGROUP2_SUBTREE_CONTROLLER_PATH);
+- goto out;
++ if (util_safe_uint64(content, &ull_result) != 0) {
++ ERROR("Failed to convert %s to uint64", content);
++ return -1;
+ }
+
+-out:
+- util_free_array(controllers);
+- free(controllers_str);
+- free(subtree_controller_str);
+-
+- return ret;
++ *(uint64_t *)result = ull_result;
++ return 0;
+ }
+
+-#if defined (__ANDROID__) || defined(__MUSL__)
+-static bool cgroup2_no_controller()
++int get_match_value_ull(const char *content, const char *match, void *result)
+ {
+- char *controllers_str = NULL;
++ __isula_auto_free char *llu_string = NULL;
++ __isula_auto_free char *match_with_space = NULL;
++ __isula_auto_array_t char **lines = NULL;
++ char **worker = NULL;
+
+- controllers_str = util_read_content_from_file(CGROUP2_CONTROLLERS_PATH);
+- if (controllers_str == NULL || strlen(controllers_str) == 0 || strcmp(controllers_str, "\n") == 0) {
+- free(controllers_str);
+- return true;
++ if (match == NULL) {
++ return get_value_ull(content, result);
+ }
+
+- free(controllers_str);
+- return false;
+-}
+-#endif
+-
+-static int make_sure_cgroup2_isulad_path_exist()
+-{
+- int ret = 0;
+-
+- if (util_dir_exists(CGROUP_ISULAD_PATH)) {
+- return 0;
++ // match full string
++ match_with_space = util_string_append(" ", match);
++ if (match_with_space == NULL) {
++ ERROR("Failed to append string");
++ return -1;
+ }
+
+- if (cgroup2_enable_all() != 0) {
++ lines = util_string_split(content, '\n');
++ if (lines == NULL) {
++ ERROR("Failed to split content %s", content);
+ return -1;
+ }
+
+-#if defined (__ANDROID__) || defined(__MUSL__)
+- if (cgroup2_no_controller()) {
+- DEBUG("no cgroup controller found");
+- return 0;
++ for (worker = lines; worker && *worker; worker++) {
++ if (util_has_prefix(*worker, match_with_space)) {
++ break;
++ }
+ }
+-#endif
+-
+- ret = mkdir(CGROUP_ISULAD_PATH, DEFAULT_CGROUP_DIR_MODE);
+- if (ret != 0 && (errno != EEXIST || !util_dir_exists(CGROUP_ISULAD_PATH))) {
++ if (*worker == NULL) {
++ ERROR("Cannot find match string %s", match);
+ return -1;
+ }
+
+- return ret;
+-}
+-
+-int common_get_cgroup_info_v2(cgroup_mem_info_t *meminfo, cgroup_cpu_info_t *cpuinfo,
+- cgroup_hugetlb_info_t *hugetlbinfo, cgroup_blkio_info_t *blkioinfo,
+- cgroup_cpuset_info_t *cpusetinfo, cgroup_pids_info_t *pidsinfo,
+- cgroup_files_info_t *filesinfo, bool quiet)
+-{
+- int ret = 0;
+- int nret = 0;
+- char *size = NULL;
+- char path[PATH_MAX] = { 0 };
+-
+- if (make_sure_cgroup2_isulad_path_exist() != 0) {
++ llu_string = util_sub_string(*worker, strlen(match_with_space), strlen(*worker) - strlen(match_with_space));
++ if (llu_string == NULL) {
++ ERROR("Failed to sub string");
+ return -1;
+ }
++ llu_string = util_trim_space(llu_string);
+
+- // cpu cgroup
+- cpuinfo->cpu_shares = cgroup_enabled(CGROUP_ISULAD_PATH, CGROUP2_CPU_WEIGHT);
+- common_cgroup_do_log(quiet, !(cpuinfo->cpu_shares), "Your kernel does not support cgroup2 cpu weight");
+-
+- cpuinfo->cpu_cfs_period = cgroup_enabled(CGROUP_ISULAD_PATH, CGROUP2_CPU_MAX);
+- cpuinfo->cpu_cfs_quota = cpuinfo->cpu_cfs_period;
+- common_cgroup_do_log(quiet, !(cpuinfo->cpu_cfs_period), "Your kernel does not support cgroup2 cpu max");
+-
+- cpusetinfo->cpuset = cgroup_enabled(CGROUP_ISULAD_PATH, CGROUP2_CPUSET_CPUS_EFFECTIVE) &&
+- cgroup_enabled(CGROUP_ISULAD_PATH, CGROUP2_CPUSET_CPUS) &&
+- cgroup_enabled(CGROUP_ISULAD_PATH, CGROUP2_CPUSET_MEMS_EFFECTIVE) &&
+- cgroup_enabled(CGROUP_ISULAD_PATH, CGROUP2_CPUSET_MEMS);
+- common_cgroup_do_log(quiet, !(cpusetinfo->cpuset), "Your kernel does not support cpuset");
+- if (cpusetinfo->cpuset) {
+- cpusetinfo->cpus = util_read_content_from_file(CGROUP2_CPUSET_CPUS_EFFECTIVE_PATH);
+- cpusetinfo->mems = util_read_content_from_file(CGROUP2_CPUSET_MEMS_EFFECTIVE_PATH);
+- if (cpusetinfo->cpus == NULL || cpusetinfo->mems == NULL) {
+- ERROR("read cpus or mems failed");
+- return -1;
+- }
+- cpusetinfo->cpus = util_trim_space(cpusetinfo->cpus);
+- cpusetinfo->mems = util_trim_space(cpusetinfo->mems);
+- }
+-
+- // io cgroup
+- blkioinfo->blkio_weight = cgroup_enabled(CGROUP_ISULAD_PATH, CGROUP2_IO_BFQ_WEIGHT) ||
+- cgroup_enabled(CGROUP_ISULAD_PATH, CGROUP2_IO_WEIGHT);
+- blkioinfo->blkio_weight_device = blkioinfo->blkio_weight;
+- common_cgroup_do_log(quiet, !(blkioinfo->blkio_weight), "Your kernel does not support cgroup2 io weight");
+-
+- blkioinfo->blkio_read_bps_device = cgroup_enabled(CGROUP_ISULAD_PATH, CGROUP2_IO_MAX);
+- blkioinfo->blkio_write_bps_device = blkioinfo->blkio_read_bps_device;
+- blkioinfo->blkio_read_iops_device = blkioinfo->blkio_read_bps_device;
+- blkioinfo->blkio_write_iops_device = blkioinfo->blkio_read_bps_device;
+- common_cgroup_do_log(quiet, !(blkioinfo->blkio_read_bps_device), "Your kernel does not support cgroup2 io max");
+-
+- // memory cgroup
+- meminfo->limit = cgroup_enabled(CGROUP_ISULAD_PATH, CGROUP2_MEMORY_MAX);
+- common_cgroup_do_log(quiet, !(meminfo->limit), "Your kernel does not support cgroup2 memory max");
+-
+- meminfo->reservation = cgroup_enabled(CGROUP_ISULAD_PATH, CGROUP2_MEMORY_LOW);
+- common_cgroup_do_log(quiet, !(meminfo->reservation), "Your kernel does not support cgroup2 memory low");
+-
+- meminfo->swap = cgroup_enabled(CGROUP_ISULAD_PATH, CGROUP2_MEMORY_SWAP_MAX);
+- common_cgroup_do_log(quiet, !(meminfo->swap), "Your kernel does not support cgroup2 memory swap max");
+-
+- // pids cgroup
+- pidsinfo->pidslimit = cgroup_enabled(CGROUP_ISULAD_PATH, CGROUP2_PIDS_MAX);
+- common_cgroup_do_log(quiet, !(pidsinfo->pidslimit), "Your kernel does not support cgroup2 pids max");
+-
+- // hugetlb cgroup
+- size = get_default_huge_page_size();
+- if (size != NULL) {
+- nret = snprintf(path, sizeof(path), CGROUP2_HUGETLB_MAX, size);
+- if (nret < 0 || (size_t)nret >= sizeof(path)) {
+- WARN("Failed to print hugetlb path");
+- ret = -1;
+- goto out;
+- }
+- hugetlbinfo->hugetlblimit = cgroup_enabled(CGROUP_ISULAD_PATH, path);
+- common_cgroup_do_log(quiet, !hugetlbinfo->hugetlblimit, "Your kernel does not support cgroup2 hugetlb limit");
+- } else {
+- WARN("Your kernel does not support cgroup2 hugetlb limit");
+- }
+-
+- // files cgroup
+- filesinfo->fileslimit = cgroup_enabled(CGROUP_ISULAD_PATH, CGROUP2_FILES_LIMIT);
+- common_cgroup_do_log(quiet, !(filesinfo->fileslimit), "Your kernel does not support cgroup2 files limit");
+-
+-out:
+- free(size);
+-
+- return ret;
+-}
++ return get_value_ull(llu_string, result);
++}
+\ No newline at end of file
+diff --git a/src/daemon/common/cgroup.h b/src/daemon/common/cgroup.h
+index fa20f42c..251e3a3d 100644
+--- a/src/daemon/common/cgroup.h
++++ b/src/daemon/common/cgroup.h
+@@ -31,6 +31,15 @@ extern "C" {
+ #define CGROUP_MOUNTPOINT "/sys/fs/cgroup"
+ #define CGROUP_ISULAD_PATH CGROUP_MOUNTPOINT"/isulad"
+
++struct cgfile_t {
++ char *name;
++ char *file;
++ char *match;
++ int (*get_value)(const char *content, const char *match, void *result);
++};
++
++int get_match_value_ull(const char *content, const char *match, void *result);
++
+ int common_get_cgroup_version(void);
+
+ int common_find_cgroup_mnt_and_root(const char *subsystem, char **mountpoint, char **root);
+@@ -42,7 +51,6 @@ static inline void common_cgroup_do_log(bool quiet, bool do_log, const char *msg
+ }
+ }
+
+-
+ typedef struct {
+ char **controllers;
+ char *mountpoint;
+@@ -140,6 +148,7 @@ typedef struct {
+ } cgroup_metrics_t;
+
+ int common_get_cgroup_v1_metrics(const char *cgroup_path, cgroup_metrics_t *cgroup_metrics);
++int common_get_cgroup_v2_metrics(const char *cgroup_path, cgroup_metrics_t *cgroup_metrics);
+
+ char *common_get_init_cgroup(const char *subsystem);
+
+diff --git a/src/daemon/common/cgroup_v1.c b/src/daemon/common/cgroup_v1.c
+index e38fc03e..e34100bc 100644
+--- a/src/daemon/common/cgroup_v1.c
++++ b/src/daemon/common/cgroup_v1.c
+@@ -23,20 +23,8 @@
+
+ #define CGROUP_HUGETLB_LIMIT "hugetlb.%s.limit_in_bytes"
+
+-typedef struct {
+- char *match;
+-} cgfile_callback_args_t;
+-
+-struct cgfile_t {
+- char *name;
+- char *file;
+- int (*get_value)(const char *content, const cgfile_callback_args_t *args, void *result);
+-};
+-
+-static int get_value_ll(const char *content, const cgfile_callback_args_t *args, void *result);
+-static int get_value_ull(const char *content, const cgfile_callback_args_t *args, void *result);
+-static int get_match_value_ull(const char *content, const cgfile_callback_args_t *args, void *result);
+-static int get_value_string(const char *content, const cgfile_callback_args_t *args, void *result);
++static int get_value_ll(const char *content, const char *match, void *result);
++static int get_value_string(const char *content, const char *match, void *result);
+
+ typedef enum {
+ // CPU subsystem
+@@ -63,46 +51,46 @@ typedef enum {
+
+ static struct cgfile_t g_cgroup_v1_files[] = {
+ // CPU subsystem
+- [CPU_RT_PERIOD] = {"cpu_rt_period", "cpu.rt_period_us", get_value_ull},
+- [CPU_RT_RUNTIME] = {"cpu_rt_runtime", "cpu.rt_runtime_us", get_value_ull},
+- [CPU_SHARES] = {"cpu_shares", "cpu.shares", get_value_ull},
+- [CPU_CFS_PERIOD] = {"cpu_cfs_period", "cpu.cfs_period_us", get_value_ull},
+- [CPU_CFS_QUOTA] = {"cpu_cfs_quota", "cpu.cfs_quota_us", get_value_ll},
++ [CPU_RT_PERIOD] = {"cpu_rt_period", "cpu.rt_period_us", NULL, get_match_value_ull},
++ [CPU_RT_RUNTIME] = {"cpu_rt_runtime", "cpu.rt_runtime_us", NULL, get_match_value_ull},
++ [CPU_SHARES] = {"cpu_shares", "cpu.shares", NULL, get_match_value_ull},
++ [CPU_CFS_PERIOD] = {"cpu_cfs_period", "cpu.cfs_period_us", NULL, get_match_value_ull},
++ [CPU_CFS_QUOTA] = {"cpu_cfs_quota", "cpu.cfs_quota_us", NULL, get_value_ll},
+ // CPUSET subsystem
+- [CPUSET_CPUS] = {"cpuset_cpus", "cpuset.cpus", get_value_string},
+- [CPUSET_MEMS] = {"cpuset_mems", "cpuset.mems", get_value_string},
++ [CPUSET_CPUS] = {"cpuset_cpus", "cpuset.cpus", NULL, get_value_string},
++ [CPUSET_MEMS] = {"cpuset_mems", "cpuset.mems", NULL, get_value_string},
+ // CPUACCT subsystem
+- [CPUACCT_USE_NANOS] = {"cpu_use_nanos", "cpuacct.usage", get_value_ull},
+- [CPUACCT_USE_USER] = {"cpu_use_user", "cpuacct.stat", get_match_value_ull},
+- [CPUACCT_USE_SYS] = {"cpu_use_sys", "cpuacct.stat", get_match_value_ull},
++ [CPUACCT_USE_NANOS] = {"cpu_use_nanos", "cpuacct.usage", NULL, get_match_value_ull},
++ [CPUACCT_USE_USER] = {"cpu_use_user", "cpuacct.stat", NULL, get_match_value_ull},
++ [CPUACCT_USE_SYS] = {"cpu_use_sys", "cpuacct.stat", NULL, get_match_value_ull},
+ // MEMORY subsystem
+- [MEMORY_LIMIT] = {"mem_limit", "memory.limit_in_bytes", get_value_ull},
+- [MEMORY_USAGE] = {"mem_usage", "memory.usage_in_bytes", get_value_ull},
+- [MEMORY_SOFT_LIMIT] = {"mem_soft_limit", "memory.soft_limit_in_bytes", get_value_ull},
+- [MEMORY_KMEM_LIMIT] = {"kmem_limit", "memory.kmem.limit_in_bytes", get_value_ull},
+- [MEMORY_KMEM_USAGE] = {"kmem_usage", "memory.kmem.usage_in_bytes", get_value_ull},
+- [MEMORY_SWAPPINESS] = {"swappiness", "memory.swappiness", NULL},
+- [MEMORY_SW_LIMIT] = {"memsw_limit", "memory.memsw.limit_in_bytes", get_value_ull},
+- [MEMORY_SW_USAGE] = {"memsw_usage", "memory.memsw.usage_in_bytes", get_value_ull},
+- [MEMORY_CACHE] = {"cache", "memory.stat", get_match_value_ull},
+- [MEMORY_CACHE_TOTAL] = {"cache_total", "memory.stat", get_match_value_ull},
+- [MEMORY_TOTAL_RSS] = {"total_rss", "memory.stat", get_match_value_ull},
+- [MEMORY_TOTAL_PGFAULT] = {"total_page_fault", "memory.stat", get_match_value_ull},
+- [MEMORY_TOTAL_PGMAJFAULT] = {"total_page_majfault", "memory.stat", get_match_value_ull},
+- [MEMORY_TOTAL_INACTIVE_FILE] = {"total_inactive_file", "memory.stat", get_match_value_ull},
+- [MEMORY_OOM_CONTROL] = {"oom_control", "memory.oom_control", NULL},
++ [MEMORY_LIMIT] = {"mem_limit", "memory.limit_in_bytes", NULL, get_match_value_ull},
++ [MEMORY_USAGE] = {"mem_usage", "memory.usage_in_bytes", NULL, get_match_value_ull},
++ [MEMORY_SOFT_LIMIT] = {"mem_soft_limit", "memory.soft_limit_in_bytes", NULL, get_match_value_ull},
++ [MEMORY_KMEM_LIMIT] = {"kmem_limit", "memory.kmem.limit_in_bytes", NULL, get_match_value_ull},
++ [MEMORY_KMEM_USAGE] = {"kmem_usage", "memory.kmem.usage_in_bytes", NULL, get_match_value_ull},
++ [MEMORY_SWAPPINESS] = {"swappiness", "memory.swappiness", NULL, NULL},
++ [MEMORY_SW_LIMIT] = {"memsw_limit", "memory.memsw.limit_in_bytes", NULL, get_match_value_ull},
++ [MEMORY_SW_USAGE] = {"memsw_usage", "memory.memsw.usage_in_bytes", NULL, get_match_value_ull},
++ [MEMORY_CACHE] = {"cache", "memory.stat", NULL, get_match_value_ull},
++ [MEMORY_CACHE_TOTAL] = {"cache_total", "memory.stat", NULL, get_match_value_ull},
++ [MEMORY_TOTAL_RSS] = {"total_rss", "memory.stat", "total_rss", get_match_value_ull},
++ [MEMORY_TOTAL_PGFAULT] = {"total_page_fault", "memory.stat", "total_pgfault", get_match_value_ull},
++ [MEMORY_TOTAL_PGMAJFAULT] = {"total_page_majfault", "memory.stat", "total_pgmajfault", get_match_value_ull},
++ [MEMORY_TOTAL_INACTIVE_FILE] = {"total_inactive_file", "memory.stat", "total_inactive_file", get_match_value_ull},
++ [MEMORY_OOM_CONTROL] = {"oom_control", "memory.oom_control", NULL, NULL},
+ // BLKIO subsystem
+- [BLKIO_WEIGTH] = {"blkio_weigth", "blkio.weight", NULL},
+- [BLKIO_WEIGTH_DEVICE] = {"blkio_weigth_device", "blkio.weight_device", NULL},
+- [BLKIO_READ_BPS] = {"blkio_read_bps", "blkio.throttle.read_bps_device", NULL},
+- [BLKIO_WRITE_BPS] = {"blkio_write_bps", "blkio.throttle.write_bps_device", NULL},
+- [BLKIO_READ_IOPS] = {"blkio_read_iops", "blkio.throttle.read_iops_device", NULL},
+- [BLKIO_WRITE_IOPS] = {"blkio_write_iops", "blkio.throttle.write_iops_device", NULL},
++ [BLKIO_WEIGTH] = {"blkio_weigth", "blkio.weight", NULL, NULL},
++ [BLKIO_WEIGTH_DEVICE] = {"blkio_weigth_device", "blkio.weight_device", NULL, NULL},
++ [BLKIO_READ_BPS] = {"blkio_read_bps", "blkio.throttle.read_bps_device", NULL, NULL},
++ [BLKIO_WRITE_BPS] = {"blkio_write_bps", "blkio.throttle.write_bps_device", NULL, NULL},
++ [BLKIO_READ_IOPS] = {"blkio_read_iops", "blkio.throttle.read_iops_device", NULL, NULL},
++ [BLKIO_WRITE_IOPS] = {"blkio_write_iops", "blkio.throttle.write_iops_device", NULL, NULL},
+ // PIDS subsystem
+- [PIDS_CURRENT] = {"pids_current", "pids.current", get_value_ull},
++ [PIDS_CURRENT] = {"pids_current", "pids.current", NULL, get_match_value_ull},
+ };
+
+-static int get_value_ll(const char *content, const cgfile_callback_args_t *args, void *result)
++static int get_value_ll(const char *content, const char *match, void *result)
+ {
+ long long ll_result = 0;
+
+@@ -115,81 +103,7 @@ static int get_value_ll(const char *content, const cgfile_callback_args_t *args,
+ return 0;
+ }
+
+-static int get_value_ull(const char *content, const cgfile_callback_args_t *args, void *result)
+-{
+- uint64_t ull_result = 0;
+-
+- if (util_safe_uint64(content, &ull_result) != 0) {
+- ERROR("Failed to convert %s to uint64", content);
+- return -1;
+- }
+-
+- *(uint64_t *)result = ull_result;
+- return 0;
+-}
+-
+-static int get_match_value_ull(const char *content, const cgfile_callback_args_t *args, void *result)
+-{
+- int ret = 0;
+- uint64_t llu_result = 0;
+- char *llu_string = NULL;
+- char *match_with_space = NULL;
+- char **lines = NULL;
+- char **worker = NULL;
+-
+- if (args == NULL || args->match == NULL || strlen(args->match) == 0) {
+- ERROR("Invalid arguments");
+- return -1;
+- }
+-
+- // match full string
+- match_with_space = util_string_append(" ", args->match);
+- if (match_with_space == NULL) {
+- ERROR("Failed to append string");
+- return -1;
+- }
+-
+- lines = util_string_split(content, '\n');
+- if (lines == NULL) {
+- ERROR("Failed to split content %s", content);
+- ret = -1;
+- goto out;
+- }
+-
+- for (worker = lines; worker && *worker; worker++) {
+- if (util_has_prefix(*worker, match_with_space)) {
+- break;
+- }
+- }
+- if (*worker == NULL) {
+- ERROR("Cannot find match string %s", args->match);
+- ret = -1;
+- goto out;
+- }
+-
+- llu_string = util_sub_string(*worker, strlen(match_with_space), strlen(*worker) - strlen(match_with_space));
+- if (llu_string == NULL) {
+- ERROR("Failed to sub string");
+- ret = -1;
+- goto out;
+- }
+- llu_string = util_trim_space(llu_string);
+-
+- ret = util_safe_uint64(llu_string, &llu_result);
+- if (ret != 0) {
+- ERROR("Failed to convert %s to uint64", llu_string);
+- } else {
+- *(uint64_t *)result = llu_result;
+- }
+-
+-out:
+- free(match_with_space);
+- free(llu_string);
+- util_free_array(lines);
+- return ret;
+-}
+-
+-static int get_value_string(const char *content, const cgfile_callback_args_t *args, void *result)
++static int get_value_string(const char *content, const char *match, void *result)
+ {
+ *(char **)result = util_strdup_s(content);
+ return 0;
+@@ -228,7 +142,7 @@ static bool check_cgroup_v1_helper(const char *mountpoint, const cgroup_v1_files
+ }
+
+ static int get_cgroup_v1_value_helper(const char *path, const cgroup_v1_files_index index,
+- const cgfile_callback_args_t *args, void *result)
++ void *result)
+ {
+ int nret = 0;
+ char file_path[PATH_MAX] = { 0 };
+@@ -265,7 +179,7 @@ static int get_cgroup_v1_value_helper(const char *path, const cgroup_v1_files_in
+ util_trim_newline(content);
+ content = util_trim_space(content);
+
+- nret = g_cgroup_v1_files[index].get_value(content, args, result);
++ nret = g_cgroup_v1_files[index].get_value(content, g_cgroup_v1_files[index].match, result);
+ if (nret != 0) {
+ ERROR("%s: failed to get value", g_cgroup_v1_files[index].name);
+ }
+@@ -308,11 +222,11 @@ static void check_cgroup_v1_cpuset(const cgroup_layer_t *layers, const bool quie
+ return;
+ }
+
+- if (get_cgroup_v1_value_helper(mountpoint, CPUSET_CPUS, NULL, (void *)&cpusetinfo->cpus) != 0) {
++ if (get_cgroup_v1_value_helper(mountpoint, CPUSET_CPUS, (void *)&cpusetinfo->cpus) != 0) {
+ ERROR("Failed to get cgroup cpuset.cpus data");
+ return;
+ }
+- if (get_cgroup_v1_value_helper(mountpoint, CPUSET_MEMS, NULL, (void *)&cpusetinfo->mems) != 0) {
++ if (get_cgroup_v1_value_helper(mountpoint, CPUSET_MEMS, (void *)&cpusetinfo->mems) != 0) {
+ free(cpusetinfo->cpus);
+ cpusetinfo->cpus = NULL;
+ ERROR("Failed to get cgroup cpuset.cpus data");
+@@ -463,7 +377,7 @@ static void get_cgroup_v1_metrics_cpu(const cgroup_layer_t *layers, const char *
+ return;
+ }
+
+- get_cgroup_v1_value_helper(path, CPUACCT_USE_NANOS, NULL, (void *)&cgroup_cpu_metrics->cpu_use_nanos);
++ get_cgroup_v1_value_helper(path, CPUACCT_USE_NANOS, (void *)&cgroup_cpu_metrics->cpu_use_nanos);
+ }
+
+ static void get_cgroup_v1_metrics_memory(const cgroup_layer_t *layers, const char *cgroup_path,
+@@ -472,18 +386,6 @@ static void get_cgroup_v1_metrics_memory(const cgroup_layer_t *layers, const cha
+ int nret = 0;
+ char *mountpoint = NULL;
+ char path[PATH_MAX] = { 0 };
+- const cgfile_callback_args_t total_inactive_file_arg = {
+- .match = "total_inactive_file",
+- };
+- const cgfile_callback_args_t total_rss_arg = {
+- .match = "total_rss",
+- };
+- const cgfile_callback_args_t total_pgfault_arg = {
+- .match = "total_pgfault",
+- };
+- const cgfile_callback_args_t total_pgmajfault_arg = {
+- .match = "total_pgmajfault",
+- };
+
+ mountpoint = common_find_cgroup_subsystem_mountpoint(layers, "memory");
+ if (mountpoint == NULL) {
+@@ -497,14 +399,14 @@ static void get_cgroup_v1_metrics_memory(const cgroup_layer_t *layers, const cha
+ return;
+ }
+
+- get_cgroup_v1_value_helper(path, MEMORY_LIMIT, NULL, (void *)&cgroup_mem_metrics->mem_limit);
+- get_cgroup_v1_value_helper(path, MEMORY_USAGE, NULL, (void *)&cgroup_mem_metrics->mem_used);
+- get_cgroup_v1_value_helper(path, MEMORY_TOTAL_RSS, &total_rss_arg, (void *)&cgroup_mem_metrics->total_rss);
+- get_cgroup_v1_value_helper(path, MEMORY_TOTAL_PGFAULT, &total_pgfault_arg,
++ get_cgroup_v1_value_helper(path, MEMORY_LIMIT, (void *)&cgroup_mem_metrics->mem_limit);
++ get_cgroup_v1_value_helper(path, MEMORY_USAGE, (void *)&cgroup_mem_metrics->mem_used);
++ get_cgroup_v1_value_helper(path, MEMORY_TOTAL_RSS, (void *)&cgroup_mem_metrics->total_rss);
++ get_cgroup_v1_value_helper(path, MEMORY_TOTAL_PGFAULT,
+ (void *)&cgroup_mem_metrics->total_pgfault);
+- get_cgroup_v1_value_helper(path, MEMORY_TOTAL_PGMAJFAULT, &total_pgmajfault_arg,
++ get_cgroup_v1_value_helper(path, MEMORY_TOTAL_PGMAJFAULT,
+ (void *)&cgroup_mem_metrics->total_pgmajfault);
+- get_cgroup_v1_value_helper(path, MEMORY_TOTAL_INACTIVE_FILE, &total_inactive_file_arg,
++ get_cgroup_v1_value_helper(path, MEMORY_TOTAL_INACTIVE_FILE,
+ (void *)&cgroup_mem_metrics->total_inactive_file);
+ }
+
+@@ -527,7 +429,7 @@ static void get_cgroup_v1_metrics_pid(const cgroup_layer_t *layers, const char *
+ return;
+ }
+
+- get_cgroup_v1_value_helper(path, PIDS_CURRENT, NULL, (void *)&cgroup_pids_metrics->pid_current);
++ get_cgroup_v1_value_helper(path, PIDS_CURRENT, (void *)&cgroup_pids_metrics->pid_current);
+ }
+
+ int common_get_cgroup_v1_metrics(const char *cgroup_path, cgroup_metrics_t *cgroup_metrics)
+diff --git a/src/daemon/common/cgroup_v2.c b/src/daemon/common/cgroup_v2.c
+new file mode 100644
+index 00000000..25509bda
+--- /dev/null
++++ b/src/daemon/common/cgroup_v2.c
+@@ -0,0 +1,406 @@
++/******************************************************************************
++ * Copyright (c) Huawei Technologies Co., Ltd. 2024. All rights reserved.
++ * iSulad licensed under the Mulan PSL v2.
++ * You can use this software according to the terms and conditions of the Mulan PSL v2.
++ * You may obtain a copy of Mulan PSL v2 at:
++ * http://license.coscl.org.cn/MulanPSL2
++ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
++ * PURPOSE.
++ * See the Mulan PSL v2 for more details.
++ * Author: zhongtao
++ * Create: 2024-01-16
++ * Description: provide cgroup v2 functions
++ ******************************************************************************/
++#include "cgroup.h"
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <sys/stat.h>
++
++#include <isula_libutils/auto_cleanup.h>
++
++#include "utils.h"
++#include "path.h"
++#include "sysinfo.h"
++
++// Cgroup V2 Item Definition
++#define CGROUP2_CPU_WEIGHT "cpu.weight"
++#define CGROUP2_CPU_MAX "cpu.max"
++#define CGROUP2_CPUSET_CPUS_EFFECTIVE "cpuset.cpus.effective"
++#define CGROUP2_CPUSET_MEMS_EFFECTIVE "cpuset.mems.effective"
++#define CGROUP2_CPUSET_CPUS "cpuset.cpus"
++#define CGROUP2_CPUSET_MEMS "cpuset.mems"
++#define CGROUP2_IO_WEIGHT "io.weight"
++#define CGROUP2_IO_BFQ_WEIGHT "io.bfq.weight"
++#define CGROUP2_IO_MAX "io.max"
++#define CGROUP2_MEMORY_MAX "memory.max"
++#define CGROUP2_MEMORY_LOW "memory.low"
++#define CGROUP2_MEMORY_SWAP_MAX "memory.swap.max"
++#define CGROUP2_HUGETLB_MAX "hugetlb.%s.max"
++#define CGROUP2_PIDS_MAX "pids.max"
++#define CGROUP2_FILES_LIMIT "files.limit"
++
++#define CGROUP2_CONTROLLERS_PATH CGROUP_MOUNTPOINT"/cgroup.controllers"
++#define CGROUP2_SUBTREE_CONTROLLER_PATH CGROUP_MOUNTPOINT"/cgroup.subtree_control"
++#define CGROUP2_CPUSET_CPUS_EFFECTIVE_PATH CGROUP_MOUNTPOINT"/cpuset.cpus.effective"
++#define CGROUP2_CPUSET_MEMS_EFFECTIVE_PATH CGROUP_MOUNTPOINT"/cpuset.mems.effective"
++
++#ifndef CGROUP2_SUPER_MAGIC
++#define CGROUP2_SUPER_MAGIC 0x63677270
++#endif
++
++static int get_value_ull_v2(const char *content, const char *match, void *result)
++{
++ uint64_t ull_result = 0;
++ __isula_auto_free char *tmp_str = util_strdup_s(content);
++
++ tmp_str = util_trim_space(tmp_str);
++ if (strcmp(tmp_str, "max") == 0) {
++ *(uint64_t *)result = UINT64_MAX;
++ return 0;
++ }
++
++ if (util_safe_uint64(content, &ull_result) != 0) {
++ ERROR("Failed to convert %s to uint64", content);
++ return -1;
++ }
++
++ *(uint64_t *)result = ull_result;
++ return 0;
++}
++
++typedef enum {
++ // cpu
++ CPUACCT_USE_USER, CPUACCT_USE_SYS, CPUACCT_USE_NANOS,
++ // MEMORY subsystem
++ MEMORY_USAGE, MEMORY_LIMIT, MEMORY_ANON,
++ MEMORY_TOTAL_PGFAULT, MEMORY_TOTAL_INACTIVE_FILE, MEMORY_TOTAL_PGMAJFAULT,
++ MEMORY_CACHE, MEMORY_CACHE_TOTAL,
++ // BLKIO subsystem
++ BLKIO_READ_BPS, BLKIO_WRITE_BPS, BLKIO_READ_IOPS, BLKIO_WRITE_IOPS,
++ // PIDS subsystem
++ PIDS_CURRENT,
++ // MAX
++ CGROUP_V2_FILES_INDEX_MAXS
++} cgroup_v2_files_index;
++
++static struct cgfile_t g_cgroup_v2_files[] = {
++ // cpu
++ [CPUACCT_USE_USER] = {"cpu_use_user", "cpu.stat", "user_usec", get_match_value_ull},
++ [CPUACCT_USE_SYS] = {"cpu_use_sys", "cpu.stat", "system_usec", get_match_value_ull},
++ [CPUACCT_USE_NANOS] = {"cpu_use_nanos", "cpu.stat", "usage_usec", get_match_value_ull},
++ // memory
++ [MEMORY_USAGE] = {"mem_usage", "memory.current", NULL, get_value_ull_v2},
++ [MEMORY_LIMIT] = {"mem_limit", "memory.max", NULL, get_value_ull_v2},
++ [MEMORY_ANON] = {"mem_anon", "memory.stat", "anon", get_match_value_ull},
++ [MEMORY_TOTAL_PGFAULT] = {"total_page_fault", "memory.stat", "pgfault", get_match_value_ull},
++ [MEMORY_TOTAL_PGMAJFAULT] = {"total_page_majfault", "memory.stat", "pgmajfault", get_match_value_ull},
++ [MEMORY_TOTAL_INACTIVE_FILE] = {"total_inactive_file", "memory.stat", "inactive_file", get_match_value_ull},
++ [MEMORY_CACHE] = {"cache", "memory.stat", "file", get_match_value_ull},
++ [MEMORY_CACHE_TOTAL] = {"cache_total", "memory.stat", "file", get_match_value_ull},
++ // pids
++ [PIDS_CURRENT] = {"pids_current", "pids.current", NULL, get_value_ull_v2},
++};
++
++static int get_cgroup_v2_value_helper(const char *path, const cgroup_v2_files_index index, void *result)
++{
++ int nret = 0;
++ char file_path[PATH_MAX] = { 0 };
++ char real_path[PATH_MAX] = { 0 };
++ char *content = NULL;
++
++ if (index >= CGROUP_V2_FILES_INDEX_MAXS) {
++ ERROR("Index out of range");
++ return false;
++ }
++
++ if (path == NULL || strlen(path) == 0 || result == NULL) {
++ ERROR("%s: Invalid arguments", g_cgroup_v2_files[index].name);
++ return -1;
++ }
++
++ nret = snprintf(file_path, sizeof(file_path), "%s/%s", path, g_cgroup_v2_files[index].file);
++ if (nret < 0 || (size_t)nret >= sizeof(file_path)) {
++ ERROR("%s: failed to snprintf", g_cgroup_v2_files[index].name);
++ return -1;
++ }
++
++ if (util_clean_path(file_path, real_path, sizeof(real_path)) == NULL) {
++ ERROR("%s: failed to clean path %s", g_cgroup_v2_files[index].name, file_path);
++ return -1;
++ }
++
++ content = util_read_content_from_file(real_path);
++ if (content == NULL) {
++ ERROR("%s: failed to read file %s", g_cgroup_v2_files[index].name, real_path);
++ return -1;
++ }
++
++ util_trim_newline(content);
++ content = util_trim_space(content);
++
++ nret = g_cgroup_v2_files[index].get_value(content, g_cgroup_v2_files[index].match, result);
++ if (nret != 0) {
++ ERROR("%s: failed to get value", g_cgroup_v2_files[index].name);
++ }
++
++ free(content);
++ return nret;
++}
++
++static void get_cgroup_v2_metrics_cpu(const char *cgroup_path, cgroup_cpu_metrics_t *cgroup_cpu_metrics)
++{
++ int nret = 0;
++ char path[PATH_MAX] = { 0 };
++
++ nret = snprintf(path, sizeof(path), "%s/%s", CGROUP_MOUNTPOINT, cgroup_path);
++ if (nret < 0 || (size_t)nret >= sizeof(path)) {
++ ERROR("Failed to snprintf");
++ return;
++ }
++
++ get_cgroup_v2_value_helper(path, CPUACCT_USE_NANOS, (void *)&cgroup_cpu_metrics->cpu_use_nanos);
++}
++
++static void get_cgroup_v2_metrics_memory(const char *cgroup_path, cgroup_mem_metrics_t *cgroup_mem_metrics)
++{
++ int nret = 0;
++ char path[PATH_MAX] = { 0 };
++
++ nret = snprintf(path, sizeof(path), "%s/%s", CGROUP_MOUNTPOINT, cgroup_path);
++ if (nret < 0 || (size_t)nret >= sizeof(path)) {
++ ERROR("Failed to snprintf");
++ return;
++ }
++
++ get_cgroup_v2_value_helper(path, MEMORY_LIMIT, (void *)&cgroup_mem_metrics->mem_limit);
++ get_cgroup_v2_value_helper(path, MEMORY_USAGE, (void *)&cgroup_mem_metrics->mem_used);
++ // Use Anon memory for RSS as cAdvisor on cgroupv2
++ // see https://github.com/google/cadvisor/blob/a9858972e75642c2b1914c8d5428e33e6392c08a/container/libcontainer/handler.go#L799
++ get_cgroup_v2_value_helper(path, MEMORY_ANON, (void *)&cgroup_mem_metrics->total_rss);
++ get_cgroup_v2_value_helper(path, MEMORY_TOTAL_PGFAULT,
++ (void *)&cgroup_mem_metrics->total_pgfault);
++ get_cgroup_v2_value_helper(path, MEMORY_TOTAL_PGMAJFAULT,
++ (void *)&cgroup_mem_metrics->total_pgmajfault);
++ get_cgroup_v2_value_helper(path, MEMORY_TOTAL_INACTIVE_FILE,
++ (void *)&cgroup_mem_metrics->total_inactive_file);
++}
++
++static void get_cgroup_v2_metrics_pid(const char *cgroup_path, cgroup_pids_metrics_t *cgroup_pids_metrics)
++{
++ int nret = 0;
++ char path[PATH_MAX] = { 0 };
++
++ nret = snprintf(path, sizeof(path), "%s/%s", CGROUP_MOUNTPOINT, cgroup_path);
++ if (nret < 0 || (size_t)nret >= sizeof(path)) {
++ ERROR("Failed to snprintf");
++ return;
++ }
++
++ get_cgroup_v2_value_helper(path, PIDS_CURRENT, (void *)&cgroup_pids_metrics->pid_current);
++}
++
++static int cgroup2_enable_all()
++{
++ int ret = 0;
++ int nret = 0;
++ int n = 0;
++ size_t i = 0;
++ const char *space = "";
++ __isula_auto_free char *controllers_str = NULL;
++ __isula_auto_free char *subtree_controller_str = NULL;
++ __isula_auto_array_t char **controllers = NULL;
++ char enable_controllers[PATH_MAX] = { 0 };
++
++ controllers_str = util_read_content_from_file(CGROUP2_CONTROLLERS_PATH);
++ if (controllers_str == NULL || strlen(controllers_str) == 0 || strcmp(controllers_str, "\n") == 0) {
++ WARN("no cgroup controller found");
++ return ret;
++ }
++
++ subtree_controller_str = util_read_content_from_file(CGROUP2_SUBTREE_CONTROLLER_PATH);
++ if (subtree_controller_str != NULL && strcmp(controllers_str, subtree_controller_str) == 0) {
++ return ret;
++ }
++
++ controllers = util_string_split(controllers_str, ' ');
++ if (controllers == NULL) {
++ ERROR("split %s failed", controllers_str);
++ return -1;
++ }
++
++ for (i = 0; i < util_array_len((const char **)controllers); i++) {
++ nret = snprintf(enable_controllers + n, PATH_MAX - n, "%s+%s", space, controllers[i]);
++ if (nret < 0 || (size_t)nret >= PATH_MAX - n) {
++ ERROR("Path is too long");
++ return -1;
++ }
++ n += nret;
++ space = " ";
++ }
++ ret = util_write_file(CGROUP2_SUBTREE_CONTROLLER_PATH, enable_controllers, strlen(enable_controllers),
++ DEFAULT_CGROUP_FILE_MODE);
++ if (ret != 0) {
++ SYSERROR("write %s to %s failed", enable_controllers, CGROUP2_SUBTREE_CONTROLLER_PATH);
++ return ret;
++ }
++
++ return ret;
++}
++
++#if defined (__ANDROID__) || defined(__MUSL__)
++static bool cgroup2_no_controller()
++{
++ char *controllers_str = NULL;
++
++ controllers_str = util_read_content_from_file(CGROUP2_CONTROLLERS_PATH);
++ if (controllers_str == NULL || strlen(controllers_str) == 0 || strcmp(controllers_str, "\n") == 0) {
++ free(controllers_str);
++ return true;
++ }
++
++ free(controllers_str);
++ return false;
++}
++#endif
++
++static int make_sure_cgroup2_isulad_path_exist()
++{
++ int ret = 0;
++
++ if (util_dir_exists(CGROUP_ISULAD_PATH)) {
++ return 0;
++ }
++
++ if (cgroup2_enable_all() != 0) {
++ return -1;
++ }
++
++#if defined (__ANDROID__) || defined(__MUSL__)
++ if (cgroup2_no_controller()) {
++ DEBUG("no cgroup controller found");
++ return 0;
++ }
++#endif
++
++ ret = mkdir(CGROUP_ISULAD_PATH, DEFAULT_CGROUP_DIR_MODE);
++ if (ret != 0 && (errno != EEXIST || !util_dir_exists(CGROUP_ISULAD_PATH))) {
++ return -1;
++ }
++
++ return ret;
++}
++
++/* cgroup enabled */
++static bool cgroup_v2_enabled(const char *mountpoint, const char *name)
++{
++ char path[PATH_MAX] = { 0 };
++ int nret;
++
++ nret = snprintf(path, sizeof(path), "%s/%s", mountpoint, name);
++ if (nret < 0 || (size_t)nret >= sizeof(path)) {
++ ERROR("Path is too long");
++ return false;
++ }
++ return util_file_exists(path);
++}
++
++int common_get_cgroup_info_v2(cgroup_mem_info_t *meminfo, cgroup_cpu_info_t *cpuinfo,
++ cgroup_hugetlb_info_t *hugetlbinfo, cgroup_blkio_info_t *blkioinfo,
++ cgroup_cpuset_info_t *cpusetinfo, cgroup_pids_info_t *pidsinfo,
++ cgroup_files_info_t *filesinfo, bool quiet)
++{
++ int ret = 0;
++ int nret = 0;
++ __isula_auto_free char *size = NULL;
++ char path[PATH_MAX] = { 0 };
++
++ if (make_sure_cgroup2_isulad_path_exist() != 0) {
++ return -1;
++ }
++
++ // cpu cgroup
++ cpuinfo->cpu_shares = cgroup_v2_enabled(CGROUP_ISULAD_PATH, CGROUP2_CPU_WEIGHT);
++ common_cgroup_do_log(quiet, !(cpuinfo->cpu_shares), "Your kernel does not support cgroup2 cpu weight");
++
++ cpuinfo->cpu_cfs_period = cgroup_v2_enabled(CGROUP_ISULAD_PATH, CGROUP2_CPU_MAX);
++ cpuinfo->cpu_cfs_quota = cpuinfo->cpu_cfs_period;
++ common_cgroup_do_log(quiet, !(cpuinfo->cpu_cfs_period), "Your kernel does not support cgroup2 cpu max");
++
++ cpusetinfo->cpuset = cgroup_v2_enabled(CGROUP_ISULAD_PATH, CGROUP2_CPUSET_CPUS_EFFECTIVE) &&
++ cgroup_v2_enabled(CGROUP_ISULAD_PATH, CGROUP2_CPUSET_CPUS) &&
++ cgroup_v2_enabled(CGROUP_ISULAD_PATH, CGROUP2_CPUSET_MEMS_EFFECTIVE) &&
++ cgroup_v2_enabled(CGROUP_ISULAD_PATH, CGROUP2_CPUSET_MEMS);
++ common_cgroup_do_log(quiet, !(cpusetinfo->cpuset), "Your kernel does not support cpuset");
++ if (cpusetinfo->cpuset) {
++ cpusetinfo->cpus = util_read_content_from_file(CGROUP2_CPUSET_CPUS_EFFECTIVE_PATH);
++ cpusetinfo->mems = util_read_content_from_file(CGROUP2_CPUSET_MEMS_EFFECTIVE_PATH);
++ if (cpusetinfo->cpus == NULL || cpusetinfo->mems == NULL) {
++ ERROR("read cpus or mems failed");
++ return -1;
++ }
++ cpusetinfo->cpus = util_trim_space(cpusetinfo->cpus);
++ cpusetinfo->mems = util_trim_space(cpusetinfo->mems);
++ }
++
++ // io cgroup
++ blkioinfo->blkio_weight = cgroup_v2_enabled(CGROUP_ISULAD_PATH, CGROUP2_IO_BFQ_WEIGHT) ||
++ cgroup_v2_enabled(CGROUP_ISULAD_PATH, CGROUP2_IO_WEIGHT);
++ blkioinfo->blkio_weight_device = blkioinfo->blkio_weight;
++ common_cgroup_do_log(quiet, !(blkioinfo->blkio_weight), "Your kernel does not support cgroup2 io weight");
++
++ blkioinfo->blkio_read_bps_device = cgroup_v2_enabled(CGROUP_ISULAD_PATH, CGROUP2_IO_MAX);
++ blkioinfo->blkio_write_bps_device = blkioinfo->blkio_read_bps_device;
++ blkioinfo->blkio_read_iops_device = blkioinfo->blkio_read_bps_device;
++ blkioinfo->blkio_write_iops_device = blkioinfo->blkio_read_bps_device;
++ common_cgroup_do_log(quiet, !(blkioinfo->blkio_read_bps_device), "Your kernel does not support cgroup2 io max");
++
++ // memory cgroup
++ meminfo->limit = cgroup_v2_enabled(CGROUP_ISULAD_PATH, CGROUP2_MEMORY_MAX);
++ common_cgroup_do_log(quiet, !(meminfo->limit), "Your kernel does not support cgroup2 memory max");
++
++ meminfo->reservation = cgroup_v2_enabled(CGROUP_ISULAD_PATH, CGROUP2_MEMORY_LOW);
++ common_cgroup_do_log(quiet, !(meminfo->reservation), "Your kernel does not support cgroup2 memory low");
++
++ meminfo->swap = cgroup_v2_enabled(CGROUP_ISULAD_PATH, CGROUP2_MEMORY_SWAP_MAX);
++ common_cgroup_do_log(quiet, !(meminfo->swap), "Your kernel does not support cgroup2 memory swap max");
++
++ // pids cgroup
++ pidsinfo->pidslimit = cgroup_v2_enabled(CGROUP_ISULAD_PATH, CGROUP2_PIDS_MAX);
++ common_cgroup_do_log(quiet, !(pidsinfo->pidslimit), "Your kernel does not support cgroup2 pids max");
++
++ // hugetlb cgroup
++ size = get_default_huge_page_size();
++ if (size != NULL) {
++ nret = snprintf(path, sizeof(path), CGROUP2_HUGETLB_MAX, size);
++ if (nret < 0 || (size_t)nret >= sizeof(path)) {
++ WARN("Failed to print hugetlb path");
++ return -1;
++ }
++ hugetlbinfo->hugetlblimit = cgroup_v2_enabled(CGROUP_ISULAD_PATH, path);
++ common_cgroup_do_log(quiet, !hugetlbinfo->hugetlblimit, "Your kernel does not support cgroup2 hugetlb limit");
++ } else {
++ WARN("Your kernel does not support cgroup2 hugetlb limit");
++ }
++
++ // files cgroup
++ filesinfo->fileslimit = cgroup_v2_enabled(CGROUP_ISULAD_PATH, CGROUP2_FILES_LIMIT);
++ common_cgroup_do_log(quiet, !(filesinfo->fileslimit), "Your kernel does not support cgroup2 files limit");
++
++ return ret;
++}
++
++int common_get_cgroup_v2_metrics(const char *cgroup_path, cgroup_metrics_t *cgroup_metrics)
++{
++ if (cgroup_path == NULL || strlen(cgroup_path) == 0 || cgroup_metrics == NULL) {
++ ERROR("Invalid arguments");
++ return -1;
++ }
++
++ get_cgroup_v2_metrics_cpu(cgroup_path, &cgroup_metrics->cgcpu_metrics);
++ get_cgroup_v2_metrics_memory(cgroup_path, &cgroup_metrics->cgmem_metrics);
++ get_cgroup_v2_metrics_pid(cgroup_path, &cgroup_metrics->cgpids_metrics);
++
++ return 0;
++}
+diff --git a/src/daemon/entry/cri/v1/v1_cri_pod_sandbox_manager_service.cc b/src/daemon/entry/cri/v1/v1_cri_pod_sandbox_manager_service.cc
+index 76fa17bc..3bdc3af8 100644
+--- a/src/daemon/entry/cri/v1/v1_cri_pod_sandbox_manager_service.cc
++++ b/src/daemon/entry/cri/v1/v1_cri_pod_sandbox_manager_service.cc
+@@ -881,7 +881,7 @@ void PodSandboxManagerService::GetPodSandboxCgroupMetrics(const std::string &cgr
+ if (cgroupVersion == CGROUP_VERSION_1) {
+ nret = common_get_cgroup_v1_metrics(cgroupParent.c_str(), &cgroupMetrics);
+ } else {
+- // todo: get cgroup v2 metrics
++ nret = common_get_cgroup_v2_metrics(cgroupParent.c_str(), &cgroupMetrics);
+ }
+
+ if (nret != 0) {
+diff --git a/src/daemon/entry/cri/v1alpha/cri_pod_sandbox_manager_service.cc b/src/daemon/entry/cri/v1alpha/cri_pod_sandbox_manager_service.cc
+index 4d1d19eb..49a7ca54 100644
+--- a/src/daemon/entry/cri/v1alpha/cri_pod_sandbox_manager_service.cc
++++ b/src/daemon/entry/cri/v1alpha/cri_pod_sandbox_manager_service.cc
+@@ -1337,7 +1337,7 @@ void PodSandboxManagerService::GetPodSandboxCgroupMetrics(const container_inspec
+ if (cgroupVersion == CGROUP_VERSION_1) {
+ nret = common_get_cgroup_v1_metrics(cgroupParent, &cgroupMetrics);
+ } else {
+- // todo: get cgroup v2 metrics
++ nret = common_get_cgroup_v2_metrics(cgroupParent, &cgroupMetrics);
+ }
+
+ if (nret != 0) {
+diff --git a/src/utils/cutils/utils_array.h b/src/utils/cutils/utils_array.h
+index 64f41496..1c084595 100644
+--- a/src/utils/cutils/utils_array.h
++++ b/src/utils/cutils/utils_array.h
+@@ -18,6 +18,7 @@
+
+ #include <stdbool.h>
+ #include <stddef.h>
++#include <isula_libutils/auto_cleanup.h>
+
+ #ifdef __cplusplus
+ extern "C" {
+@@ -57,6 +58,11 @@ void util_free_sensitive_array(char **array);
+
+ void util_free_sensitive_array_by_len(char **array, size_t len);
+
++// define auto free function callback for char *
++define_auto_cleanup_callback(util_free_array, char *);
++// define auto free macro for char *
++#define __isula_auto_array_t auto_cleanup_tag(util_free_array)
++
+ #ifdef __cplusplus
+ }
+ #endif
+--
+2.34.1
+