[lxc-devel] [lxcfs/master] bindings: port cpuset to new cgroup getters and implement cgroup2 sup…

brauner on Github lxc-bot at linuxcontainers.org
Mon Feb 24 09:36:51 UTC 2020


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 376 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20200224/f168d2d1/attachment.bin>
-------------- next part --------------
From 560712b0c8d976e05f787e0a4166128edf6553ce Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Mon, 24 Feb 2020 10:35:50 +0100
Subject: [PATCH] bindings: port cpuset to new cgroup getters and implement
 cgroup2 support

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 bindings.c             |  9 +++--
 cgroups/cgfsng.c       | 75 +++++++++++++++++++++++++++++++++++++++++-
 cgroups/cgroup.h       |  4 +++
 cgroups/cgroup_utils.c | 53 +++++++++++++++++++++++++++++
 cgroups/cgroup_utils.h |  7 ++++
 memory_utils.h         |  8 +++++
 6 files changed, 152 insertions(+), 4 deletions(-)

diff --git a/bindings.c b/bindings.c
index 52fbb87..35c1e42 100644
--- a/bindings.c
+++ b/bindings.c
@@ -3543,11 +3543,14 @@ static int proc_meminfo_read(char *buf, size_t size, off_t offset,
  */
 char *get_cpuset(const char *cg)
 {
-	char *answer;
+	char *value = NULL;
+	int ret;
 
-	if (!cgroup_ops->get(cgroup_ops, "cpuset", cg, "cpuset.cpus", &answer))
+	ret = cgroup_ops->get_cpuset_cpus(cgroup_ops, cg, &value);
+	if (ret < 0)
 		return NULL;
-	return answer;
+
+	return value;
 }
 
 bool cpu_in_cpuset(int cpu, const char *cpuset);
diff --git a/cgroups/cgfsng.c b/cgroups/cgfsng.c
index 426ad8a..558f0f5 100644
--- a/cgroups/cgfsng.c
+++ b/cgroups/cgfsng.c
@@ -666,6 +666,77 @@ static int cgfsng_get_memory_stats(struct cgroup_ops *ops, const char *cgroup,
 	return cgfsng_get_memory(ops, cgroup, "memory.stat", value);
 }
 
+static char *readat_cpuset(int cgroup_fd)
+{
+	__do_free char *val = NULL;
+
+	val = readat_file(cgroup_fd, "cpuset.cpus");
+	if (val && strcmp(val, "") != 0)
+		return move_ptr(val);
+
+	free_disarm(val);
+	val = readat_file(cgroup_fd, "cpuset.cpus.effective");
+	if (val && strcmp(val, "") != 0)
+		return move_ptr(val);
+
+	return NULL;
+}
+
+static int cgfsng_get_cpuset_cpus(struct cgroup_ops *ops, const char *cgroup,
+				  char **value)
+{
+	__do_close_prot_errno int cgroup_fd = -EBADF;
+	__do_free char *path = NULL;
+	char *v;
+	struct hierarchy *h;
+	int ret;
+
+	h = ops->get_hierarchy(ops, "cpuset");
+	if (!h)
+		return -1;
+
+	if (!is_unified_hierarchy(h))
+		ret = CGROUP_SUPER_MAGIC;
+	else
+		ret = CGROUP2_SUPER_MAGIC;
+
+	*value = NULL;
+	path = must_make_path(*cgroup == '/' ? "." : "", cgroup, NULL);
+	cgroup_fd = openat_safe(h->fd, path);
+	if (cgroup_fd < 0) {
+		return -1;
+	}
+	v = readat_cpuset(cgroup_fd);
+	if (v) {
+		*value = v;
+		return ret;
+	}
+
+	/*
+	 * cpuset.cpus and cpuset.cpus.effective are empty so we need to look
+	 * the nearest ancestor with a non-empty cpuset.cpus{.effective} file.
+	 */
+	for (;;) {
+		int fd;
+
+		fd = openat_safe(cgroup_fd, "../");
+		if (fd < 0 || !is_cgroup_fd(fd)) {
+			fprintf(stderr, "2222: %s\n", strerror(errno));
+			return -1;
+		}
+
+		close_prot_errno_replace(cgroup_fd, fd);
+
+		v = readat_cpuset(fd);
+		if (v) {
+			*value = v;
+			return ret;
+		}
+	}
+
+	return -1;
+}
+
 /* At startup, parse_hierarchies finds all the info we need about cgroup
  * mountpoints and current cgroups, and stores it in @d.
  */
@@ -862,7 +933,6 @@ 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;
@@ -870,5 +940,8 @@ struct cgroup_ops *cgfsng_ops_init(void)
 	cgfsng_ops->get_memory_current = cgfsng_get_memory_current;
 	cgfsng_ops->get_memory_swap_current = cgfsng_get_memory_swap_current;
 
+	/* cpuset */
+	cgfsng_ops->get_cpuset_cpus = cgfsng_get_cpuset_cpus;
+
 	return move_ptr(cgfsng_ops);
 }
diff --git a/cgroups/cgroup.h b/cgroups/cgroup.h
index e367aff..29fe5ba 100644
--- a/cgroups/cgroup.h
+++ b/cgroups/cgroup.h
@@ -134,6 +134,10 @@ struct cgroup_ops {
 			      char **value);
 	int (*get_memory_swap_max)(struct cgroup_ops *ops, const char *cgroup,
 				   char **value);
+
+	/* cpuset */
+	int (*get_cpuset_cpus)(struct cgroup_ops *ops, const char *cgroup,
+			       char **value);
 };
 
 extern struct cgroup_ops *cgroup_init(void);
diff --git a/cgroups/cgroup_utils.c b/cgroups/cgroup_utils.c
index e5b2707..957d2e1 100644
--- a/cgroups/cgroup_utils.c
+++ b/cgroups/cgroup_utils.c
@@ -62,6 +62,23 @@ int unified_cgroup_hierarchy(void)
 	return 0;
 }
 
+bool is_cgroup_fd(int fd)
+{
+
+	int ret;
+	struct statfs fs;
+
+	ret = fstatfs(fd, &fs);
+	if (ret)
+		return false;
+
+	if (is_fs_type(&fs, CGROUP2_SUPER_MAGIC) ||
+	    is_fs_type(&fs, CGROUP_SUPER_MAGIC))
+		return true;
+
+	return false;
+}
+
 void *must_realloc(void *orig, size_t sz)
 {
 	void *ret;
@@ -724,3 +741,39 @@ bool mkdir_p(const char *dir, mode_t mode)
 
 	return true;
 }
+
+char *must_append_path(char *first, ...)
+{
+	char *cur;
+	size_t full_len;
+	va_list args;
+	char *dest = first;
+	size_t buf_len;
+	size_t cur_len;
+
+	full_len = strlen(first);
+	cur_len = full_len;
+
+	va_start(args, first);
+	while ((cur = va_arg(args, char *)) != NULL) {
+		buf_len = strlen(cur);
+
+		full_len += buf_len;
+		if (cur[0] != '/')
+			full_len++;
+
+		dest = must_realloc(dest, full_len + 1);
+
+		if (cur[0] != '/') {
+			memcpy(dest + cur_len, "/", 1);
+			cur_len++;
+		}
+
+		memcpy(dest + cur_len, cur, buf_len);
+		cur_len += buf_len;
+	}
+	va_end(args);
+
+	dest[cur_len] = '\0';
+	return dest;
+}
diff --git a/cgroups/cgroup_utils.h b/cgroups/cgroup_utils.h
index 1db8a57..2a4cc17 100644
--- a/cgroups/cgroup_utils.h
+++ b/cgroups/cgroup_utils.h
@@ -69,5 +69,12 @@ extern char *cg_hybrid_get_current_cgroup(char *basecginfo,
 					  const char *controller, int type);
 extern char *cg_legacy_get_current_cgroup(pid_t pid, const char *controller);
 extern bool mkdir_p(const char *dir, mode_t mode);
+extern char *must_append_path(char *first, ...);
+extern bool is_cgroup_fd(int fd);
+
+static inline int openat_safe(int fd, const char *path)
+{
+	return openat(fd, path, O_DIRECTORY | O_RDONLY | O_CLOEXEC | O_NOFOLLOW);
+}
 
 #endif /* __LXC_CGROUP_UTILS_H */
diff --git a/memory_utils.h b/memory_utils.h
index ac00b10..a97c243 100644
--- a/memory_utils.h
+++ b/memory_utils.h
@@ -37,6 +37,14 @@ static inline void __auto_closedir__(DIR **d)
 		fd = -EBADF;        \
 	}
 
+#define close_prot_errno_replace(fd, new_fd) \
+	if (fd >= 0) {                       \
+		int _e_ = errno;             \
+		close(fd);                   \
+		errno = _e_;                 \
+		fd = new_fd;                 \
+	}
+
 #define free_disarm(ptr)       \
 	({                     \
 		free(ptr);     \


More information about the lxc-devel mailing list