]> git.ipfire.org Git - thirdparty/lxc.git/commitdiff
cgfsng: rework cgroup2 attach 3205/head
authorChristian Brauner <christian.brauner@ubuntu.com>
Wed, 4 Dec 2019 00:39:20 +0000 (01:39 +0100)
committerChristian Brauner <christian.brauner@ubuntu.com>
Wed, 4 Dec 2019 01:56:25 +0000 (02:56 +0100)
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@ubuntu.com>
src/lxc/cgroups/cgfsng.c
src/lxc/cgroups/cgroup.c
src/lxc/cgroups/cgroup.h
src/lxc/commands.c
src/lxc/commands.h
src/lxc/file_utils.c
src/lxc/file_utils.h

index 66ff9bbf87334cfc31081eb18b32fb8580e52ac8..d2e1ecf6f537ecf1a5fc70880d952a2d9bd39c82 100644 (file)
@@ -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,64 @@ 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;
-
-on_error:
-       return fret;
+       return -1;
 }
 
 __cgfsng_ops static bool cgfsng_attach(struct cgroup_ops *ops, const char *name,
@@ -3145,6 +3158,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;
index b6244241fe4c75a20b84b15d3ff1b3ddd696a55f..ac324299dde7109114a87bc7ef068a7233694b6c 100644 (file)
@@ -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;
 
index edc8258fb39294ab902729ad086fe6ef420aaafe..91519fbe9c59752bd81b7b62f5281f32edc3c23d 100644 (file)
@@ -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
index fb40039d3c68dc7e37c6078270acb358dc1d14e2..f397d3c61d916208563d69d9bfbba8faa6e9e94c 100644 (file)
@@ -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) {
index 4346d86b5b8cd2ae38cf75b1dba02e0bb314985b..29b448c3c1ebe1f8faf3727fb7d7f5735dfced19 100644 (file)
@@ -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 */
index 9cbe6c2753b6908c5f930b3d7d14ecfc79e75117..2f0ac299226e8b94bac3bb81680cd5e934a709aa 100644 (file)
 #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)
 {
index a087147e112a1c977c95566ae5e0100cfcf73dc0..3c458a0fa38095d4f8d8559a138e469e9619e460 100644 (file)
@@ -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 */