The following pull request was submitted through Github. It can be accessed and reviewed at: https://github.com/lxc/lxcfs/pull/320
This e-mail was sent by the LXC bot, direct replies will not reach the author unless they happen to be subscribed to this list. === Description (from pull-request) === Signed-off-by: Christian Brauner <christian.brau...@ubuntu.com>
From cfb72d52826919885019a3170cc28b4da3641d13 Mon Sep 17 00:00:00 2001 From: Christian Brauner <christian.brau...@ubuntu.com> Date: Fri, 21 Feb 2020 14:05:56 +0100 Subject: [PATCH 1/2] bindings: rework proc meminfo helpers Signed-off-by: Christian Brauner <christian.brau...@ubuntu.com> --- bindings.c | 114 ++++++++++++++++++++++++++++------------------------- 1 file changed, 61 insertions(+), 53 deletions(-) diff --git a/bindings.c b/bindings.c index 9d8cc33..31c4ccc 100644 --- a/bindings.c +++ b/bindings.c @@ -3285,22 +3285,22 @@ int read_file_fuse(const char *path, char *buf, size_t size, struct file_info *d static unsigned long get_memlimit(const char *cgroup, const char *file) { - char *memlimit_str = NULL; + __do_free char *memlimit_str = NULL; unsigned long memlimit = -1; if (cgroup_ops->get(cgroup_ops, "memory", cgroup, file, &memlimit_str)) memlimit = strtoul(memlimit_str, NULL, 10); - free(memlimit_str); - return memlimit; } static unsigned long get_min_memlimit(const char *cgroup, const char *file) { - char *copy = strdupa(cgroup); - unsigned long memlimit = 0, retlimit; + __do_free char *copy = NULL; + unsigned long memlimit = 0; + unsigned long retlimit; + copy = strdupa(cgroup); retlimit = get_memlimit(copy, file); while (strcmp(copy, "/") != 0) { @@ -3314,57 +3314,70 @@ static unsigned long get_min_memlimit(const char *cgroup, const char *file) } static int proc_meminfo_read(char *buf, size_t size, off_t offset, - struct fuse_file_info *fi) + struct fuse_file_info *fi) { + __do_free char *current_cgroup = NULL, *line = NULL, + *memusage_str = NULL, *memstat_str = NULL, + *memswlimit_str = NULL, *memswusage_str = NULL; + __do_fclose FILE *f = NULL; struct fuse_context *fc = fuse_get_context(); struct lxcfs_opts *opts = (struct lxcfs_opts *) fuse_get_context()->private_data; struct file_info *d = (struct file_info *)fi->fh; - char *cg; - char *memusage_str = NULL, *memstat_str = NULL, - *memswlimit_str = NULL, *memswusage_str = NULL; - unsigned long memlimit = 0, memusage = 0, memswlimit = 0, memswusage = 0, - cached = 0, hosttotal = 0, active_anon = 0, inactive_anon = 0, - active_file = 0, inactive_file = 0, unevictable = 0, shmem = 0, - hostswtotal = 0; - char *line = NULL; + unsigned long memlimit = 0, memusage = 0, memswlimit = 0, + memswusage = 0, cached = 0, hosttotal = 0, active_anon = 0, + inactive_anon = 0, active_file = 0, inactive_file = 0, + unevictable = 0, shmem = 0, hostswtotal = 0; size_t linelen = 0, total_len = 0, rv = 0; char *cache = d->buf; size_t cache_size = d->buflen; - FILE *f = NULL; - if (offset){ + if (offset) { + int left; + if (offset > d->size) return -EINVAL; + if (!d->cached) return 0; - int left = d->size - offset; - total_len = left > size ? size: left; + + left = d->size - offset; + total_len = left > size ? size : left; memcpy(buf, cache + offset, total_len); + return total_len; } pid_t initpid = lookup_initpid_in_store(fc->pid); if (initpid <= 1 || is_shared_pidns(initpid)) initpid = fc->pid; - cg = get_pid_cgroup(initpid, "memory"); - if (!cg) + + current_cgroup = get_pid_cgroup(initpid, "memory"); + if (!current_cgroup) return read_file_fuse("/proc/meminfo", buf, size, d); - prune_init_slice(cg); - memlimit = get_min_memlimit(cg, "memory.limit_in_bytes"); - if (!cgroup_ops->get(cgroup_ops, "memory", cg, "memory.usage_in_bytes", &memusage_str)) - goto err; - if (!cgroup_ops->get(cgroup_ops, "memory", cg, "memory.stat", &memstat_str)) - goto err; + prune_init_slice(current_cgroup); - // Following values are allowed to fail, because swapaccount might be turned - // off for current kernel - if(cgroup_ops->get(cgroup_ops, "memory", cg, "memory.memsw.limit_in_bytes", &memswlimit_str) && - cgroup_ops->get(cgroup_ops, "memory", cg, "memory.memsw.usage_in_bytes", &memswusage_str)) - { - memswlimit = get_min_memlimit(cg, "memory.memsw.limit_in_bytes"); - memswusage = strtoul(memswusage_str, NULL, 10); + memlimit = get_min_memlimit(current_cgroup, "memory.limit_in_bytes"); + + if (!cgroup_ops->get(cgroup_ops, "memory", current_cgroup, + "memory.usage_in_bytes", &memusage_str)) + return 0; + if (!cgroup_ops->get(cgroup_ops, "memory", current_cgroup, + "memory.stat", &memstat_str)) + return 0; + + /* + * Following values are allowed to fail, because swapaccount might be + * turned off for current kernel. + */ + if (cgroup_ops->get(cgroup_ops, "memory", current_cgroup, + "memory.memsw.limit_in_bytes", &memswlimit_str) && + cgroup_ops->get(cgroup_ops, "memory", current_cgroup, + "memory.memsw.usage_in_bytes", &memswusage_str)) { + memswlimit = get_min_memlimit(current_cgroup, + "memory.memsw.limit_in_bytes"); + memswusage = strtoul(memswusage_str, NULL, 10); memswlimit = memswlimit / 1024; memswusage = memswusage / 1024; } @@ -3373,13 +3386,12 @@ static int proc_meminfo_read(char *buf, size_t size, off_t offset, memlimit /= 1024; memusage /= 1024; - parse_memstat(memstat_str, &cached, &active_anon, - &inactive_anon, &active_file, &inactive_file, - &unevictable, &shmem); + parse_memstat(memstat_str, &cached, &active_anon, &inactive_anon, + &active_file, &inactive_file, &unevictable, &shmem); f = fopen("/proc/meminfo", "r"); if (!f) - goto err; + return 0; while (getline(&line, &linelen, f) != -1) { ssize_t l; @@ -3398,7 +3410,8 @@ static int proc_meminfo_read(char *buf, size_t size, off_t offset, } else if (startswith(line, "MemAvailable:")) { snprintf(lbuf, 100, "MemAvailable: %8lu kB\n", memlimit - memusage + cached); printme = lbuf; - } else if (startswith(line, "SwapTotal:") && memswlimit > 0 && opts && opts->swap_off == false) { + } else if (startswith(line, "SwapTotal:") && memswlimit > 0 && + opts && opts->swap_off == false) { sscanf(line+sizeof("SwapTotal:")-1, "%lu", &hostswtotal); if (hostswtotal < memswlimit) memswlimit = hostswtotal; @@ -3407,10 +3420,15 @@ static int proc_meminfo_read(char *buf, size_t size, off_t offset, } else if (startswith(line, "SwapTotal:") && opts && opts->swap_off == true) { snprintf(lbuf, 100, "SwapTotal: %8lu kB\n", 0UL); printme = lbuf; - } else if (startswith(line, "SwapFree:") && memswlimit > 0 && memswusage > 0 && opts && opts->swap_off == false) { + } else if (startswith(line, "SwapFree:") && memswlimit > 0 && + memswusage > 0 && opts && opts->swap_off == false) { unsigned long swaptotal = memswlimit, - swapusage = memusage > memswusage ? 0 : memswusage - memusage, - swapfree = swapusage < swaptotal ? swaptotal - swapusage : 0; + swapusage = memusage > memswusage + ? 0 + : memswusage - memusage, + swapfree = swapusage < swaptotal + ? swaptotal - swapusage + : 0; snprintf(lbuf, 100, "SwapFree: %8lu kB\n", swapfree); printme = lbuf; } else if (startswith(line, "SwapFree:") && opts && opts->swap_off == true) { @@ -3472,14 +3490,12 @@ static int proc_meminfo_read(char *buf, size_t size, off_t offset, l = snprintf(cache, cache_size, "%s", printme); if (l < 0) { perror("Error writing to cache"); - rv = 0; - goto err; + return 0; } if (l >= cache_size) { lxcfs_error("%s\n", "Internal error: truncated write to cache."); - rv = 0; - goto err; + return 0; } cache += l; @@ -3494,14 +3510,6 @@ static int proc_meminfo_read(char *buf, size_t size, off_t offset, rv = total_len; err: - if (f) - fclose(f); - free(line); - free(cg); - free(memusage_str); - free(memswlimit_str); - free(memswusage_str); - free(memstat_str); return rv; } From 66c5e84848ba9b93f2ebdf06c34b41ea675124bc Mon Sep 17 00:00:00 2001 From: Christian Brauner <christian.brau...@ubuntu.com> Date: Fri, 21 Feb 2020 15:19:08 +0100 Subject: [PATCH 2/2] bindings: port memory to new cgroup getters and implement cgroup2 support Signed-off-by: Christian Brauner <christian.brau...@ubuntu.com> --- bindings.c | 169 ++++++++++++++++++++++++++--------------------- cgroups/cgfsng.c | 71 ++++++++++++++++++++ cgroups/cgroup.h | 17 +++++ 3 files changed, 183 insertions(+), 74 deletions(-) diff --git a/bindings.c b/bindings.c index 31c4ccc..52fbb87 100644 --- a/bindings.c +++ b/bindings.c @@ -3177,33 +3177,53 @@ static bool startswith(const char *line, const char *pref) return false; } -static void parse_memstat(char *memstat, unsigned long *cached, - unsigned long *active_anon, unsigned long *inactive_anon, - unsigned long *active_file, unsigned long *inactive_file, - unsigned long *unevictable, unsigned long *shmem) +/* Note that "memory.stat" in cgroup2 is hierarchical by default. */ +static void parse_memstat(int version, + char *memstat, + unsigned long *cached, + unsigned long *active_anon, + unsigned long *inactive_anon, + unsigned long *active_file, + unsigned long *inactive_file, + unsigned long *unevictable, + unsigned long *shmem) { char *eol; while (*memstat) { - if (startswith(memstat, "total_cache")) { + if (startswith(memstat, is_unified_controller(version) + ? "cache" + : "total_cache")) { sscanf(memstat + 11, "%lu", cached); *cached /= 1024; - } else if (startswith(memstat, "total_active_anon")) { + } else if (startswith(memstat, is_unified_controller(version) + ? "active_anon" + : "total_active_anon")) { sscanf(memstat + 17, "%lu", active_anon); *active_anon /= 1024; - } else if (startswith(memstat, "total_inactive_anon")) { + } else if (startswith(memstat, is_unified_controller(version) + ? "inactive_anon" + : "total_inactive_anon")) { sscanf(memstat + 19, "%lu", inactive_anon); *inactive_anon /= 1024; - } else if (startswith(memstat, "total_active_file")) { + } else if (startswith(memstat, is_unified_controller(version) + ? "active_file" + : "total_active_file")) { sscanf(memstat + 17, "%lu", active_file); *active_file /= 1024; - } else if (startswith(memstat, "total_inactive_file")) { + } else if (startswith(memstat, is_unified_controller(version) + ? "inactive_file" + : "total_inactive_file")) { sscanf(memstat + 19, "%lu", inactive_file); *inactive_file /= 1024; - } else if (startswith(memstat, "total_unevictable")) { + } else if (startswith(memstat, is_unified_controller(version) + ? "unevictable" + : "total_unevictable")) { sscanf(memstat + 17, "%lu", unevictable); *unevictable /= 1024; - } else if (startswith(memstat, "total_shmem")) { + } else if (startswith(memstat, is_unified_controller(version) + ? "shmem" + : "total_shmem")) { sscanf(memstat + 11, "%lu", shmem); *shmem /= 1024; } @@ -3283,29 +3303,36 @@ int read_file_fuse(const char *path, char *buf, size_t size, struct file_info *d * FUSE ops for /proc */ -static unsigned long get_memlimit(const char *cgroup, const char *file) +static unsigned long get_memlimit(const char *cgroup, bool swap) { + int ret; __do_free char *memlimit_str = NULL; unsigned long memlimit = -1; - if (cgroup_ops->get(cgroup_ops, "memory", cgroup, file, &memlimit_str)) + if (swap) + ret = cgroup_ops->get_memory_swap_max(cgroup_ops, cgroup, &memlimit_str); + else + ret = cgroup_ops->get_memory_max(cgroup_ops, cgroup, &memlimit_str); + if (ret > 0) memlimit = strtoul(memlimit_str, NULL, 10); return memlimit; } -static unsigned long get_min_memlimit(const char *cgroup, const char *file) +static unsigned long get_min_memlimit(const char *cgroup, bool swap) { __do_free char *copy = NULL; unsigned long memlimit = 0; unsigned long retlimit; - copy = strdupa(cgroup); - retlimit = get_memlimit(copy, file); + copy = strdup(cgroup); + retlimit = get_memlimit(copy, swap); while (strcmp(copy, "/") != 0) { - copy = dirname(copy); - memlimit = get_memlimit(copy, file); + char *it = copy; + + it = dirname(it); + memlimit = get_memlimit(it, swap); if (memlimit != -1 && memlimit < retlimit) retlimit = memlimit; }; @@ -3316,7 +3343,7 @@ static unsigned long get_min_memlimit(const char *cgroup, const char *file) static int proc_meminfo_read(char *buf, size_t size, off_t offset, struct fuse_file_info *fi) { - __do_free char *current_cgroup = NULL, *line = NULL, + __do_free char *cgroup = NULL, *line = NULL, *memusage_str = NULL, *memstat_str = NULL, *memswlimit_str = NULL, *memswusage_str = NULL; __do_fclose FILE *f = NULL; @@ -3327,9 +3354,10 @@ static int proc_meminfo_read(char *buf, size_t size, off_t offset, memswusage = 0, cached = 0, hosttotal = 0, active_anon = 0, inactive_anon = 0, active_file = 0, inactive_file = 0, unevictable = 0, shmem = 0, hostswtotal = 0; - size_t linelen = 0, total_len = 0, rv = 0; + size_t linelen = 0, total_len = 0; char *cache = d->buf; size_t cache_size = d->buflen; + int ret; if (offset) { int left; @@ -3351,32 +3379,33 @@ static int proc_meminfo_read(char *buf, size_t size, off_t offset, if (initpid <= 1 || is_shared_pidns(initpid)) initpid = fc->pid; - current_cgroup = get_pid_cgroup(initpid, "memory"); - if (!current_cgroup) + cgroup = get_pid_cgroup(initpid, "memory"); + if (!cgroup) return read_file_fuse("/proc/meminfo", buf, size, d); - prune_init_slice(current_cgroup); + prune_init_slice(cgroup); - memlimit = get_min_memlimit(current_cgroup, "memory.limit_in_bytes"); + memlimit = get_min_memlimit(cgroup, false); - if (!cgroup_ops->get(cgroup_ops, "memory", current_cgroup, - "memory.usage_in_bytes", &memusage_str)) + ret = cgroup_ops->get_memory_current(cgroup_ops, cgroup, &memusage_str); + if (ret < 0) return 0; - if (!cgroup_ops->get(cgroup_ops, "memory", current_cgroup, - "memory.stat", &memstat_str)) + ret = cgroup_ops->get_memory_stats(cgroup_ops, cgroup, &memstat_str); + if (ret < 0) return 0; + parse_memstat(ret, memstat_str, &cached, &active_anon, &inactive_anon, + &active_file, &inactive_file, &unevictable, &shmem); /* * Following values are allowed to fail, because swapaccount might be * turned off for current kernel. */ - if (cgroup_ops->get(cgroup_ops, "memory", current_cgroup, - "memory.memsw.limit_in_bytes", &memswlimit_str) && - cgroup_ops->get(cgroup_ops, "memory", current_cgroup, - "memory.memsw.usage_in_bytes", &memswusage_str)) { - memswlimit = get_min_memlimit(current_cgroup, - "memory.memsw.limit_in_bytes"); + ret = cgroup_ops->get_memory_swap_max(cgroup_ops, cgroup, &memswlimit_str); + if (ret >= 0) + ret = cgroup_ops->get_memory_swap_current(cgroup_ops, cgroup, &memswusage_str); + if (ret >= 0) { + memswlimit = get_min_memlimit(cgroup, true); memswusage = strtoul(memswusage_str, NULL, 10); memswlimit = memswlimit / 1024; memswusage = memswusage / 1024; @@ -3386,9 +3415,6 @@ static int proc_meminfo_read(char *buf, size_t size, off_t offset, memlimit /= 1024; memusage /= 1024; - parse_memstat(memstat_str, &cached, &active_anon, &inactive_anon, - &active_file, &inactive_file, &unevictable, &shmem); - f = fopen("/proc/meminfo", "r"); if (!f) return 0; @@ -3508,9 +3534,7 @@ static int proc_meminfo_read(char *buf, size_t size, off_t offset, if (total_len > size ) total_len = size; memcpy(buf, d->buf, total_len); - rv = total_len; -err: - return rv; + return total_len; } /* @@ -5245,25 +5269,32 @@ static int proc_diskstats_read(char *buf, size_t size, off_t offset, } static int proc_swaps_read(char *buf, size_t size, off_t offset, - struct fuse_file_info *fi) + struct fuse_file_info *fi) { + __do_free char *cg = NULL, *memswlimit_str = NULL, *memusage_str = NULL, + *memswusage_str = NULL; struct fuse_context *fc = fuse_get_context(); struct file_info *d = (struct file_info *)fi->fh; - char *cg = NULL; - char *memswlimit_str = NULL, *memlimit_str = NULL, *memusage_str = NULL, *memswusage_str = NULL; - unsigned long memswlimit = 0, memlimit = 0, memusage = 0, memswusage = 0, swap_total = 0, swap_free = 0; - ssize_t total_len = 0, rv = 0; + unsigned long memswlimit = 0, memlimit = 0, memusage = 0, + memswusage = 0, swap_total = 0, swap_free = 0; + ssize_t total_len = 0; ssize_t l = 0; char *cache = d->buf; + int ret; if (offset) { + int left; + if (offset > d->size) return -EINVAL; + if (!d->cached) return 0; - int left = d->size - offset; + + left = d->size - offset; total_len = left > size ? size: left; memcpy(buf, cache + offset, total_len); + return total_len; } @@ -5275,19 +5306,20 @@ static int proc_swaps_read(char *buf, size_t size, off_t offset, return read_file_fuse("/proc/swaps", buf, size, d); prune_init_slice(cg); - memlimit = get_min_memlimit(cg, "memory.limit_in_bytes"); + memlimit = get_min_memlimit(cg, false); - if (!cgroup_ops->get(cgroup_ops, "memory", cg, "memory.usage_in_bytes", &memusage_str)) - goto err; + ret = cgroup_ops->get_memory_current(cgroup_ops, cg, &memusage_str); + if (ret < 0) + return 0; memusage = strtoul(memusage_str, NULL, 10); - if (cgroup_ops->get(cgroup_ops, "memory", cg, "memory.memsw.usage_in_bytes", &memswusage_str) && - cgroup_ops->get(cgroup_ops, "memory", cg, "memory.memsw.limit_in_bytes", &memswlimit_str)) { - - memswlimit = get_min_memlimit(cg, "memory.memsw.limit_in_bytes"); + ret = cgroup_ops->get_memory_swap_max(cgroup_ops, cg, &memswlimit_str); + if (ret >= 0) + ret = cgroup_ops->get_memory_swap_current(cgroup_ops, cg, &memswusage_str); + if (ret >= 0) { + memswlimit = get_min_memlimit(cg, true); memswusage = strtoul(memswusage_str, NULL, 10); - swap_total = (memswlimit - memlimit) / 1024; swap_free = (memswusage - memusage) / 1024; } @@ -5296,23 +5328,20 @@ static int proc_swaps_read(char *buf, size_t size, off_t offset, /* When no mem + swap limit is specified or swapaccount=0*/ if (!memswlimit) { - char *line = NULL; + __do_free char *line = NULL; + __do_fclose FILE *f = NULL; size_t linelen = 0; - FILE *f = fopen("/proc/meminfo", "r"); + f = fopen("/proc/meminfo", "r"); if (!f) - goto err; + return 0; while (getline(&line, &linelen, f) != -1) { - if (startswith(line, "SwapTotal:")) { + if (startswith(line, "SwapTotal:")) sscanf(line, "SwapTotal: %8lu kB", &swap_total); - } else if (startswith(line, "SwapFree:")) { + else if (startswith(line, "SwapFree:")) sscanf(line, "SwapFree: %8lu kB", &swap_free); - } } - - free(line); - fclose(f); } if (swap_total > 0) { @@ -5324,8 +5353,7 @@ static int proc_swaps_read(char *buf, size_t size, off_t offset, if (total_len < 0 || l < 0) { perror("Error writing to cache"); - rv = 0; - goto err; + return 0; } d->cached = 1; @@ -5333,16 +5361,9 @@ static int proc_swaps_read(char *buf, size_t size, off_t offset, if (total_len > size) total_len = size; memcpy(buf, d->buf, total_len); - rv = total_len; - -err: - free(cg); - free(memswlimit_str); - free(memlimit_str); - free(memusage_str); - free(memswusage_str); - return rv; + return total_len; } + /* * Find the process pid from cgroup path. * eg:from /sys/fs/cgroup/cpu/docker/containerid/cgroup.procs to find the process pid. diff --git a/cgroups/cgfsng.c b/cgroups/cgfsng.c index c1a6f7e..426ad8a 100644 --- a/cgroups/cgfsng.c +++ b/cgroups/cgfsng.c @@ -603,6 +603,69 @@ static bool cgfsng_get(struct cgroup_ops *ops, const char *controller, return *value != NULL; } +static int cgfsng_get_memory(struct cgroup_ops *ops, const char *cgroup, + const char *file, char **value) +{ + __do_free char *path = NULL; + struct hierarchy *h; + int ret; + + h = ops->get_hierarchy(ops, "memory"); + if (!h) + return -1; + + if (!is_unified_hierarchy(h)) { + if (strcmp(file, "memory.max") == 0) + file = "memory.limit_in_bytes"; + else if (strcmp(file, "memory.swap.max") == 0) + file = "memory.memsw.limit_in_bytes"; + else if (strcmp(file, "memory.swap.current") == 0) + file = "memory.memsw.usage_in_bytes"; + else if (strcmp(file, "memory.current") == 0) + file = "memory.usage_in_bytes"; + ret = CGROUP_SUPER_MAGIC; + } else { + ret = CGROUP2_SUPER_MAGIC; + } + + path = must_make_path(*cgroup == '/' ? "." : "", cgroup, file, NULL); + *value = readat_file(h->fd, path); + if (!*value) + ret = -1; + + return ret; +} + +static int cgfsng_get_memory_current(struct cgroup_ops *ops, const char *cgroup, + char **value) +{ + return cgfsng_get_memory(ops, cgroup, "memory.current", value); +} + +static int cgfsng_get_memory_swap_current(struct cgroup_ops *ops, + const char *cgroup, char **value) +{ + return cgfsng_get_memory(ops, cgroup, "memory.swap.current", value); +} + +static int cgfsng_get_memory_max(struct cgroup_ops *ops, const char *cgroup, + char **value) +{ + return cgfsng_get_memory(ops, cgroup, "memory.max", value); +} + +static int cgfsng_get_memory_swap_max(struct cgroup_ops *ops, + const char *cgroup, char **value) +{ + return cgfsng_get_memory(ops, cgroup, "memory.swap.max", value); +} + +static int cgfsng_get_memory_stats(struct cgroup_ops *ops, const char *cgroup, + char **value) +{ + return cgfsng_get_memory(ops, cgroup, "memory.stat", value); +} + /* At startup, parse_hierarchies finds all the info we need about cgroup * mountpoints and current cgroups, and stores it in @d. */ @@ -799,5 +862,13 @@ struct cgroup_ops *cgfsng_ops_init(void) cgfsng_ops->mount = cgfsng_mount; cgfsng_ops->nrtasks = cgfsng_nrtasks; + + /* memory */ + cgfsng_ops->get_memory_stats = cgfsng_get_memory_stats; + cgfsng_ops->get_memory_max = cgfsng_get_memory_max; + cgfsng_ops->get_memory_swap_max = cgfsng_get_memory_swap_max; + cgfsng_ops->get_memory_current = cgfsng_get_memory_current; + cgfsng_ops->get_memory_swap_current = cgfsng_get_memory_swap_current; + return move_ptr(cgfsng_ops); } diff --git a/cgroups/cgroup.h b/cgroups/cgroup.h index 808e5d0..e367aff 100644 --- a/cgroups/cgroup.h +++ b/cgroups/cgroup.h @@ -122,6 +122,18 @@ struct cgroup_ops { const char *controller); bool (*get)(struct cgroup_ops *ops, const char *controller, const char *cgroup, const char *file, char **value); + + /* memory */ + int (*get_memory_stats)(struct cgroup_ops *ops, const char *cgroup, + char **value); + int (*get_memory_current)(struct cgroup_ops *ops, const char *cgroup, + char **value); + int (*get_memory_swap_current)(struct cgroup_ops *ops, + const char *cgroup, char **value); + int (*get_memory_max)(struct cgroup_ops *ops, const char *cgroup, + char **value); + int (*get_memory_swap_max)(struct cgroup_ops *ops, const char *cgroup, + char **value); }; extern struct cgroup_ops *cgroup_init(void); @@ -149,4 +161,9 @@ static inline bool is_unified_hierarchy(const struct hierarchy *h) return h->version == CGROUP2_SUPER_MAGIC; } +static inline bool is_unified_controller(int version) +{ + return version == CGROUP2_SUPER_MAGIC; +} + #endif
_______________________________________________ lxc-devel mailing list lxc-devel@lists.linuxcontainers.org http://lists.linuxcontainers.org/listinfo/lxc-devel