The following pull request was submitted through Github. It can be accessed and reviewed at: https://github.com/lxc/lxc/pull/3205
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 6900ebfa2d983c924116c74d9012e0439c2f155c Mon Sep 17 00:00:00 2001 From: Christian Brauner <christian.brau...@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.brau...@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.brau...@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.brau...@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 */
_______________________________________________ lxc-devel mailing list lxc-devel@lists.linuxcontainers.org http://lists.linuxcontainers.org/listinfo/lxc-devel