[lxc-devel] [lxc/master] cgroup: add command to retrieve cgroup2 fd and rework cgroup2 attach

brauner on Github lxc-bot at linuxcontainers.org
Wed Dec 4 01:55:13 UTC 2019


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 364 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20191203/34c404bd/attachment.bin>
-------------- next part --------------
From 6900ebfa2d983c924116c74d9012e0439c2f155c Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Wed, 4 Dec 2019 00:55:42 +0100
Subject: [PATCH 1/2] cgroups/devices: do not log error when bpf device feature
 is not available

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 src/lxc/cgroups/cgroup2_devices.c | 13 +++++--------
 1 file changed, 5 insertions(+), 8 deletions(-)

diff --git a/src/lxc/cgroups/cgroup2_devices.c b/src/lxc/cgroups/cgroup2_devices.c
index e72cffc1c6..cb6f76abc1 100644
--- a/src/lxc/cgroups/cgroup2_devices.c
+++ b/src/lxc/cgroups/cgroup2_devices.c
@@ -511,23 +511,20 @@ bool bpf_devices_cgroup_supported(void)
 	int ret;
 
 	if (geteuid() != 0)
-		return log_error_errno(false,
-				       EINVAL, "The bpf device cgroup requires real root");
+		return log_trace(false,
+				 "The bpf device cgroup requires real root");
 
 	prog = bpf_program_new(BPF_PROG_TYPE_CGROUP_DEVICE);
 	if (prog < 0)
-		return log_error_errno(false,
-				       errno, "Failed to allocate new bpf device cgroup program");
+		return log_trace(false, "Failed to allocate new bpf device cgroup program");
 
 	ret = bpf_program_add_instructions(prog, dummy, ARRAY_SIZE(dummy));
 	if (ret < 0)
-		return log_error_errno(false,
-				       errno, "Failed to add new instructions to bpf device cgroup program");
+		return log_trace(false, "Failed to add new instructions to bpf device cgroup program");
 
 	ret = bpf_program_load_kernel(prog, NULL, 0);
 	if (ret < 0)
-		return log_error_errno(false,
-				       errno, "Failed to load new bpf device cgroup program");
+		return log_trace(false, "Failed to load new bpf device cgroup program");
 
 	return log_trace(true, "The bpf device cgroup is supported");
 }

From 6d899a0b2ba8fbbee34b4a57aea3dd454264ce9f Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Wed, 4 Dec 2019 01:39:20 +0100
Subject: [PATCH 2/2] cgfsng: rework cgroup2 attach

On pure unified systemd we can use a single file descriptor to interact with
the cgroup filesystem. Add a method to retrieve it and as a start use it in our
unified attach codepath.

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 src/lxc/cgroups/cgfsng.c | 103 +++++++++++++++++++++++++--------------
 src/lxc/cgroups/cgroup.c |   3 ++
 src/lxc/cgroups/cgroup.h |   2 +
 src/lxc/commands.c       |  43 ++++++++++++++++
 src/lxc/commands.h       |   2 +
 src/lxc/file_utils.c     |  16 ++++++
 src/lxc/file_utils.h     |   2 +
 7 files changed, 135 insertions(+), 36 deletions(-)

diff --git a/src/lxc/cgroups/cgfsng.c b/src/lxc/cgroups/cgfsng.c
index 66ff9bbf87..37456623d1 100644
--- a/src/lxc/cgroups/cgfsng.c
+++ b/src/lxc/cgroups/cgfsng.c
@@ -1432,7 +1432,7 @@ __cgfsng_ops static inline bool cgfsng_payload_create(struct cgroup_ops *ops,
 							struct lxc_handler *handler)
 {
 	__do_free char *container_cgroup = NULL, *tmp = NULL;
-	int i;
+	int i, ret;
 	size_t len;
 	char *offset;
 	int idx = 0;
@@ -1463,7 +1463,7 @@ __cgfsng_ops static inline bool cgfsng_payload_create(struct cgroup_ops *ops,
 
 	do {
 		if (idx) {
-			int ret = snprintf(offset, 5, "-%d", idx);
+			ret = snprintf(offset, 5, "-%d", idx);
 			if (ret < 0 || (size_t)ret >= 5)
 				return false;
 		}
@@ -1488,6 +1488,16 @@ __cgfsng_ops static inline bool cgfsng_payload_create(struct cgroup_ops *ops,
 
 	INFO("The container process uses \"%s\" as cgroup", container_cgroup);
 	ops->container_cgroup = move_ptr(container_cgroup);
+
+	if (ops->unified && ops->unified->container_full_path) {
+		ret = open(ops->unified->container_full_path,
+			   O_DIRECTORY | O_RDONLY | O_CLOEXEC);
+		if (ret < 0)
+			return log_error_errno(false,
+					       errno, "Failed to open file descriptor for unified hierarchy");
+		ops->unified_fd = ret;
+	}
+
 	return true;
 }
 
@@ -2205,61 +2215,80 @@ static int __cg_unified_attach(const struct hierarchy *h, const char *name,
 			       const char *lxcpath, const char *pidstr,
 			       size_t pidstr_len, const char *controller)
 {
-	__do_free char *base_path = NULL, *container_cgroup = NULL,
-		       *full_path = NULL;
+	__do_close_prot_errno int unified_fd = -EBADF;
+	int idx = 0;
 	int ret;
-	size_t len;
-	int fret = -1, idx = 0;
 
-	container_cgroup = lxc_cmd_get_cgroup_path(name, lxcpath, controller);
-	/* not running */
-	if (!container_cgroup)
-		return 0;
+	unified_fd = lxc_cmd_get_cgroup2_fd(name, lxcpath);
+	if (unified_fd < 0) {
+		__do_free char *base_path = NULL, *container_cgroup = NULL;
 
-	base_path = must_make_path(h->mountpoint, container_cgroup, NULL);
-	full_path = must_make_path(base_path, "cgroup.procs", NULL);
-	/* cgroup is populated */
-	ret = lxc_write_to_file(full_path, pidstr, pidstr_len, false, 0666);
-	if (ret < 0 && errno != EBUSY)
-		goto on_error;
+		container_cgroup = lxc_cmd_get_cgroup_path(name, lxcpath, controller);
+		/* not running */
+		if (!container_cgroup)
+			return 0;
 
+		base_path = must_make_path(h->mountpoint, container_cgroup, NULL);
+		unified_fd = open(base_path, O_DIRECTORY | O_RDONLY | O_CLOEXEC);
+	}
+	if (unified_fd < 0)
+		return -1;
+
+	ret = lxc_writeat(unified_fd, "cgroup.procs", pidstr, pidstr_len);
 	if (ret == 0)
-		goto on_success;
+		return 0;
+	/* this is a non-leaf node */
+	if (errno != EBUSY)
+		return error_log_errno(errno, "Failed to attach to unified cgroup");
 
-	len = strlen(base_path) + STRLITERALLEN("/lxc-1000") +
-	      STRLITERALLEN("/cgroup-procs");
-	full_path = must_realloc(NULL, len + 1);
 	do {
+		char *slash;
+		char attach_cgroup[STRLITERALLEN("lxc-1000/cgroup.procs") + 1];
+
 		if (idx)
-			ret = snprintf(full_path, len + 1, "%s/lxc-%d",
-				       base_path, idx);
+			ret = snprintf(attach_cgroup, sizeof(attach_cgroup),
+				       "lxc-%d/cgroup.procs", idx);
 		else
-			ret = snprintf(full_path, len + 1, "%s/lxc", base_path);
-		if (ret < 0 || (size_t)ret >= len + 1)
-			goto on_error;
+			ret = snprintf(attach_cgroup, sizeof(attach_cgroup),
+				       "lxc/cgroup.procs");
+		if (ret < 0 || (size_t)ret >= sizeof(attach_cgroup))
+			return -1;
 
-		ret = mkdir_p(full_path, 0755);
+		slash = &attach_cgroup[ret] - STRLITERALLEN("/cgroup.procs");
+		*slash = '\0';
+		ret = mkdirat(unified_fd, attach_cgroup, 0755);
 		if (ret < 0 && errno != EEXIST)
-			goto on_error;
+			return error_log_errno(errno, "Failed to create cgroup %s", attach_cgroup);
 
-		(void)strlcat(full_path, "/cgroup.procs", len + 1);
-		ret = lxc_write_to_file(full_path, pidstr, len, false, 0666);
+		*slash = '/';
+		ret = lxc_writeat(unified_fd, attach_cgroup, pidstr, pidstr_len);
 		if (ret == 0)
-			goto on_success;
+			return 0;
 
 		/* this is a non-leaf node */
 		if (errno != EBUSY)
-			goto on_error;
+			return error_log_errno(errno, "Failed to attach to unified cgroup");
 
 		idx++;
 	} while (idx < 1000);
 
-on_success:
-	if (idx < 1000)
-		fret = 0;
+	return -1;
+}
 
-on_error:
-	return fret;
+static int funified_cgroup_hierarchy(int fd)
+{
+
+	int ret;
+	struct statfs fs;
+
+	ret = fstatfs(fd, &fs);
+	if (ret < 0)
+		return -ENOMEDIUM;
+
+	if (is_fs_type(&fs, CGROUP2_SUPER_MAGIC))
+		return CGROUP2_SUPER_MAGIC;
+
+	return 0;
 }
 
 __cgfsng_ops static bool cgfsng_attach(struct cgroup_ops *ops, const char *name,
@@ -3145,6 +3174,8 @@ struct cgroup_ops *cgfsng_ops_init(struct lxc_conf *conf)
 	if (!cg_init(cgfsng_ops, conf))
 		return NULL;
 
+	cgfsng_ops->unified_fd = -EBADF;
+
 	cgfsng_ops->data_init = cgfsng_data_init;
 	cgfsng_ops->payload_destroy = cgfsng_payload_destroy;
 	cgfsng_ops->monitor_destroy = cgfsng_monitor_destroy;
diff --git a/src/lxc/cgroups/cgroup.c b/src/lxc/cgroups/cgroup.c
index b6244241fe..ac324299dd 100644
--- a/src/lxc/cgroups/cgroup.c
+++ b/src/lxc/cgroups/cgroup.c
@@ -90,6 +90,9 @@ void cgroup_exit(struct cgroup_ops *ops)
 	if (ops->cgroup2_devices)
 		bpf_program_free(ops->cgroup2_devices);
 
+	if (ops->unified_fd >= 0)
+		close(ops->unified_fd);
+
 	for (it = ops->hierarchies; it && *it; it++) {
 		char **p;
 
diff --git a/src/lxc/cgroups/cgroup.h b/src/lxc/cgroups/cgroup.h
index edc8258fb3..91519fbe9c 100644
--- a/src/lxc/cgroups/cgroup.h
+++ b/src/lxc/cgroups/cgroup.h
@@ -121,6 +121,8 @@ struct cgroup_ops {
 	struct hierarchy **hierarchies;
 	/* Pointer to the unified hierarchy. Do not free! */
 	struct hierarchy *unified;
+	/* File descriptor to the container's cgroup. */
+	int unified_fd;
 
 	/*
 	 * @cgroup2_devices
diff --git a/src/lxc/commands.c b/src/lxc/commands.c
index fb40039d3c..f397d3c61d 100644
--- a/src/lxc/commands.c
+++ b/src/lxc/commands.c
@@ -103,6 +103,7 @@ static const char *lxc_cmd_str(lxc_cmd_t cmd)
 		[LXC_CMD_ADD_BPF_DEVICE_CGROUP]		= "add_bpf_device_cgroup",
 		[LXC_CMD_FREEZE]			= "freeze",
 		[LXC_CMD_UNFREEZE]			= "unfreeze",
+		[LXC_CMD_GET_CGROUP2_FD]		= "get_cgroup2_fd",
 	};
 
 	if (cmd >= LXC_CMD_MAX)
@@ -167,6 +168,9 @@ static int lxc_cmd_rsp_recv(int sock, struct lxc_cmd_rr *cmd)
 		rsp->data = rspdata;
 	}
 
+	if (cmd->req.cmd == LXC_CMD_GET_CGROUP2_FD)
+		rsp->data = INT_TO_PTR(rspfd);
+
 	if (rsp->datalen == 0) {
 		DEBUG("Response data length for command \"%s\" is 0",
 		      lxc_cmd_str(cmd->req.cmd));
@@ -1291,6 +1295,44 @@ static int lxc_cmd_unfreeze_callback(int fd, struct lxc_cmd_req *req,
 	return lxc_cmd_rsp_send(fd, &rsp);
 }
 
+int lxc_cmd_get_cgroup2_fd(const char *name, const char *lxcpath)
+{
+	int ret, stopped;
+	struct lxc_cmd_rr cmd = {
+		.req = {
+			.cmd = LXC_CMD_GET_CGROUP2_FD,
+		},
+	};
+
+	ret = lxc_cmd(name, &cmd, &stopped, lxcpath, NULL);
+	if (ret <= 0 || cmd.rsp.ret < 0)
+		return error_log_errno(errno, "Failed to retrieve cgroup2 fd");
+
+	return PTR_TO_INT(cmd.rsp.data);
+}
+
+static int lxc_cmd_get_cgroup2_fd_callback(int fd, struct lxc_cmd_req *req,
+					   struct lxc_handler *handler,
+					   struct lxc_epoll_descr *descr)
+{
+	struct lxc_cmd_rsp rsp = {
+		.ret = -EINVAL,
+	};
+	struct cgroup_ops *ops = handler->cgroup_ops;
+	int ret;
+
+	if (ops->cgroup_layout != CGROUP_LAYOUT_UNIFIED)
+		return lxc_cmd_rsp_send(fd, &rsp);
+
+	rsp.ret = 0;
+	ret = lxc_abstract_unix_send_fds(fd, &ops->unified_fd, 1, &rsp,
+					 sizeof(rsp));
+	if (ret < 0)
+		return log_error(1, "Failed to send cgroup2 fd");
+
+	return 0;
+}
+
 static int lxc_cmd_process(int fd, struct lxc_cmd_req *req,
 			   struct lxc_handler *handler,
 			   struct lxc_epoll_descr *descr)
@@ -1316,6 +1358,7 @@ static int lxc_cmd_process(int fd, struct lxc_cmd_req *req,
 		[LXC_CMD_ADD_BPF_DEVICE_CGROUP]		= lxc_cmd_add_bpf_device_cgroup_callback,
 		[LXC_CMD_FREEZE]			= lxc_cmd_freeze_callback,
 		[LXC_CMD_UNFREEZE]			= lxc_cmd_unfreeze_callback,
+		[LXC_CMD_GET_CGROUP2_FD]		= lxc_cmd_get_cgroup2_fd_callback,
 	};
 
 	if (req->cmd >= LXC_CMD_MAX) {
diff --git a/src/lxc/commands.h b/src/lxc/commands.h
index 4346d86b5b..29b448c3c1 100644
--- a/src/lxc/commands.h
+++ b/src/lxc/commands.h
@@ -50,6 +50,7 @@ typedef enum {
 	LXC_CMD_ADD_BPF_DEVICE_CGROUP,
 	LXC_CMD_FREEZE,
 	LXC_CMD_UNFREEZE,
+	LXC_CMD_GET_CGROUP2_FD,
 	LXC_CMD_MAX,
 } lxc_cmd_t;
 
@@ -139,5 +140,6 @@ extern int lxc_cmd_add_bpf_device_cgroup(const char *name, const char *lxcpath,
 					 struct device_item *device);
 extern int lxc_cmd_freeze(const char *name, const char *lxcpath, int timeout);
 extern int lxc_cmd_unfreeze(const char *name, const char *lxcpath, int timeout);
+extern int lxc_cmd_get_cgroup2_fd(const char *name, const char *lxcpath);
 
 #endif /* __commands_h */
diff --git a/src/lxc/file_utils.c b/src/lxc/file_utils.c
index 9cbe6c2753..2f0ac29922 100644
--- a/src/lxc/file_utils.c
+++ b/src/lxc/file_utils.c
@@ -36,6 +36,22 @@
 #include "string_utils.h"
 #include "utils.h"
 
+int lxc_writeat(int dirfd, const char *filename, const void *buf, size_t count)
+{
+	__do_close_prot_errno int fd = -EBADF;
+	ssize_t ret;
+
+	fd = openat(dirfd, filename, O_WRONLY | O_CLOEXEC);
+	if (fd < 0)
+		return -1;
+
+	ret = lxc_write_nointr(fd, buf, count);
+	if (ret < 0 || (size_t)ret != count)
+		return -1;
+
+	return 0;
+}
+
 int lxc_write_to_file(const char *filename, const void *buf, size_t count,
 		      bool add_newline, mode_t mode)
 {
diff --git a/src/lxc/file_utils.h b/src/lxc/file_utils.h
index a087147e11..3c458a0fa3 100644
--- a/src/lxc/file_utils.h
+++ b/src/lxc/file_utils.h
@@ -33,6 +33,8 @@
 /* read and write whole files */
 extern int lxc_write_to_file(const char *filename, const void *buf,
 			     size_t count, bool add_newline, mode_t mode);
+extern int lxc_writeat(int dirfd, const char *filename, const void *buf,
+		       size_t count);
 extern int lxc_read_from_file(const char *filename, void *buf, size_t count);
 
 /* send and receive buffers completely */


More information about the lxc-devel mailing list