[lxc-devel] [lxcfs/master] bindings: port memory to new cgroup getters and support cgroup2

brauner on Github lxc-bot at linuxcontainers.org
Fri Feb 21 14:40:09 UTC 2020


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 367 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20200221/4e522768/attachment.bin>
-------------- next part --------------
From cfb72d52826919885019a3170cc28b4da3641d13 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at 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.brauner at 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.brauner at 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.brauner at 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


More information about the lxc-devel mailing list