]> git.ipfire.org Git - pakfire.git/commitdiff
cgroups: Try to create some recursive dependency chain
authorMichael Tremer <michael.tremer@ipfire.org>
Tue, 10 Dec 2024 15:14:07 +0000 (15:14 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Tue, 10 Dec 2024 15:14:07 +0000 (15:14 +0000)
This should help us to operate on cgroups since every group now has a
reference to its parent group.

Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
src/libpakfire/build.c
src/libpakfire/cgroup.c
src/libpakfire/daemon.c
src/libpakfire/include/pakfire/cgroup.h
src/libpakfire/jail.c
tests/libpakfire/cgroup.c

index 6476f9f932c1100736995a35385e8abc11b4436e..2cb498db9b8e67f9d3cee6a19a184f26a99e1501 100644 (file)
@@ -1348,7 +1348,7 @@ static int pakfire_build_setup_cgroup(struct pakfire_build* build) {
        }
 
        // Create a new cgroup
-       r = pakfire_cgroup_create(&build->cgroup, build->ctx, path, 0);
+       r = pakfire_cgroup_create(&build->cgroup, build->ctx, NULL, path, 0);
        if (r) {
                ERROR(build->ctx, "Could not create cgroup for build %s: %m\n", build->_id);
                goto ERROR;
index 06758f7fc8b237b38e1bca3c9011c75f50cd04f8..45941a677b34540b0bee6f61a5583a75469db3e6 100644 (file)
@@ -67,8 +67,8 @@ struct pakfire_cgroup {
        // Flags
        int flags;
 
-       // Store the path
-       char path[PATH_MAX];
+       // Store the name
+       char name[PATH_MAX];
 
        // File descriptor to cgroup
        int fd;
@@ -81,26 +81,7 @@ static const char* pakfire_cgroup_name(struct pakfire_cgroup* cgroup) {
        if (!cgroup->parent)
                return "(root)";
 
-       return cgroup->path;
-}
-
-static int pakfire_cgroup_parent(struct pakfire_cgroup* cgroup, struct pakfire_cgroup** parent) {
-       char path[PATH_MAX];
-       int r;
-
-       // If there is no path left, we have reached the root
-       if (!*cgroup->path)
-               return 0;
-
-       // Determine the path of the parent
-       r = pakfire_path_dirname(path, cgroup->path);
-       if (r < 0) {
-               ERROR(cgroup->ctx, "Could not determine path for parent cgroup: %s\n", strerror(-r));
-               return r;
-       }
-
-       // Open the cgroup
-       return pakfire_cgroup_create(parent, cgroup->ctx, path, 0);
+       return cgroup->name;
 }
 
 static int pakfire_cgroup_setup_devices(struct pakfire_cgroup* cgroup) {
@@ -161,8 +142,7 @@ static int pakfire_cgroup_open_root(struct pakfire_cgroup* cgroup) {
 
        This function returns a negative value on error.
 */
-static int pakfire_cgroup_open(struct pakfire_cgroup* cgroup) {
-       char basename[NAME_MAX];
+static int __pakfire_cgroup_open(struct pakfire_cgroup* cgroup) {
        int fd = -EBADF;
        int r;
 
@@ -170,27 +150,22 @@ static int pakfire_cgroup_open(struct pakfire_cgroup* cgroup) {
        if (!cgroup->parent)
                return pakfire_cgroup_open_root(cgroup);
 
-       // Get the basename
-       r = pakfire_path_basename(basename, cgroup->path);
-       if (r < 0)
-               return r;
-
        // Try to open the cgroup
-       fd = openat(cgroup->parent->fd, basename, O_DIRECTORY|O_PATH|O_CLOEXEC);
+       fd = openat(cgroup->parent->fd, cgroup->name, O_DIRECTORY|O_PATH|O_CLOEXEC);
        if (fd < 0) {
                switch (errno) {
                        case ENOENT:
-                               r = mkdirat(cgroup->parent->fd, basename, 0755);
+                               r = mkdirat(cgroup->parent->fd, cgroup->name, 0755);
                                if (r < 0) {
-                                       ERROR(cgroup->ctx, "Could not create cgroup '%s': %m\n", basename);
+                                       ERROR(cgroup->ctx, "Could not create cgroup '%s': %m\n", cgroup->name);
                                        return -errno;
                                }
 
                                // Try opening it again
-                               return pakfire_cgroup_open(cgroup);
+                               return __pakfire_cgroup_open(cgroup);
 
                        default:
-                               ERROR(cgroup->ctx, "Could not open cgroup '%s': %m\n", basename);
+                               ERROR(cgroup->ctx, "Could not open cgroup '%s': %m\n", cgroup->name);
                                return -errno;
                }
        }
@@ -284,39 +259,24 @@ ERROR:
        Enables a cgroup controller.
 */
 static int pakfire_cgroup_enable_controller(struct pakfire_cgroup* cgroup, const char* name) {
-       struct pakfire_cgroup* parent = NULL;
        int r;
 
+       // Ensure this controller is enabled on the parent, too
+       if (cgroup->parent) {
+               r = pakfire_cgroup_enable_controller(cgroup->parent, name);
+               if (r < 0)
+                       return r;
+       }
+
        // Try to enable the controller
        r = pakfire_cgroup_write(cgroup, "cgroup.subtree_control", "+%s", name);
        if (r < 0) {
-               switch (-r) {
-                       case ENOENT:
-                               // Fetch the parent group
-                               r = pakfire_cgroup_parent(cgroup, &parent);
-                               if (r < 0)
-                                       return r;
-
-                               // When we have reached root, we cannot continue
-                               if (!parent)
-                                       return -ENOTSUP;
-
-                               // Ensure it is enabled there
-                               r = pakfire_cgroup_enable_controller(parent, name);
-                               if (r < 0)
-                                       return 0;
-
-                               // Once that was successful, try again
-                               return pakfire_cgroup_enable_controller(cgroup, name);
-
-                       default:
-                               ERROR(cgroup->ctx, "Could not enable controller '%s': %s\n",
-                                       name, strerror(-r));
-                               break;
-               }
+               ERROR(cgroup->ctx, "Could not enable controller '%s': %s\n",
+                       name, strerror(-r));
+               return r;
        }
 
-       return r;
+       return 0;
 }
 
 /*
@@ -343,8 +303,8 @@ static int pakfire_cgroup_enable_controllers(struct pakfire_cgroup* cgroup) {
 
        If the cgroup doesn't exist, it will be created including any parent cgroups.
 */
-int pakfire_cgroup_create(struct pakfire_cgroup** cgroup,
-               struct pakfire_ctx* ctx, const char* path, int flags) {
+static int pakfire_cgroup_open(struct pakfire_cgroup** cgroup,
+               struct pakfire_ctx* ctx, struct pakfire_cgroup* parent, const char* name, int flags) {
        struct pakfire_cgroup* c = NULL;
        int r;
 
@@ -362,21 +322,20 @@ int pakfire_cgroup_create(struct pakfire_cgroup** cgroup,
        // Initialize file descriptors
        c->fd = c->devicesfd = -EBADF;
 
-       // Copy path
-       r = pakfire_string_set(c->path, path);
+       // Store the parent
+       if (parent)
+               c->parent = pakfire_cgroup_ref(parent);
+
+       // Store name
+       r = pakfire_string_set(c->name, name);
        if (r < 0)
                goto ERROR;
 
        // Copy flags
        c->flags = flags;
 
-       // Find the parent cgroup
-       r = pakfire_cgroup_parent(c, &c->parent);
-       if (r < 0)
-               goto ERROR;
-
        // Open a file descriptor
-       c->fd = r = pakfire_cgroup_open(c);
+       c->fd = r = __pakfire_cgroup_open(c);
        if (r < 0)
                goto ERROR;
 
@@ -402,6 +361,76 @@ ERROR:
        return r;
 }
 
+static int pakfire_cgroup_create_recursive(struct pakfire_cgroup** cgroup,
+               struct pakfire_ctx* ctx, struct pakfire_cgroup* parent, const char* path, int flags) {
+       struct pakfire_cgroup* child = NULL;
+       char buffer[PATH_MAX];
+       char* name = NULL;
+       char* p = NULL;
+       int r;
+
+       // Copy the path to the buffer
+       r = pakfire_string_set(buffer, path);
+       if (r < 0)
+               goto ERROR;
+
+       // Split the path by /
+       name = strtok_r(buffer, "/", &p);
+
+       // Walk through all elements of the path
+       while (name) {
+               r = pakfire_cgroup_open(&child, parent->ctx, parent, name, flags);
+               if (r < 0)
+                       goto ERROR;
+
+               // Move on to the next round...
+               pakfire_cgroup_unref(parent);
+               parent = child; child = NULL;
+
+               name = strtok_r(NULL, "/", &p);
+       }
+
+       // Return the pointer
+       *cgroup = pakfire_cgroup_ref(parent);
+
+ERROR:
+       // XXX We may free the passed parent here if we did zero iterations of the while loop
+       if (parent)
+               pakfire_cgroup_unref(parent);
+
+       return r;
+}
+
+int pakfire_cgroup_create(struct pakfire_cgroup** cgroup,
+               struct pakfire_ctx* ctx, struct pakfire_cgroup* parent, const char* name, int flags) {
+       struct pakfire_cgroup* root = NULL;
+       int r;
+
+       // If parent is NULL, but name is set, we will create the root group and use it as parent
+       if (name && !parent) {
+               r = pakfire_cgroup_open(&root, ctx, NULL, NULL, 0);
+               if (r < 0)
+                       return r;
+
+               parent = root;
+       }
+
+       // Recursively create the new cgroup
+       //r = pakfire_cgroup_create_recursive(cgroup, ctx, parent, name, flags);
+       r = pakfire_cgroup_open(cgroup, ctx, parent, name, flags);
+
+       // Cleanup
+       if (root)
+               pakfire_cgroup_unref(root);
+
+       return r;
+}
+
+int pakfire_cgroup_create_root(
+               struct pakfire_cgroup** cgroup, struct pakfire_ctx* ctx, int flags) {
+       return pakfire_cgroup_open(cgroup, ctx, NULL, NULL, flags);
+}
+
 static void pakfire_cgroup_free(struct pakfire_cgroup* cgroup) {
        if (cgroup->fd >= 0)
                close(cgroup->fd);
@@ -428,25 +457,6 @@ struct pakfire_cgroup* pakfire_cgroup_unref(struct pakfire_cgroup* cgroup) {
        return NULL;
 }
 
-// Open a child cgroup
-int pakfire_cgroup_child(struct pakfire_cgroup** child,
-               struct pakfire_cgroup* cgroup, const char* path, int flags) {
-       char p[PATH_MAX];
-       int r;
-
-       // Check input
-       if (!path)
-               return -EINVAL;
-
-       // Join paths
-       r = pakfire_path_append(p, cgroup->path, path);
-       if (r < 0)
-               return r;
-
-       // Open the child group
-       return pakfire_cgroup_create(child, cgroup->ctx, p, flags);
-}
-
 /*
        Immediately kills all processes in this cgroup
 */
@@ -479,19 +489,11 @@ int pakfire_cgroup_destroy(struct pakfire_cgroup* cgroup) {
                cgroup->fd = -EBADF;
        }
 
-       // Open the root directory
-       int fd = pakfire_cgroup_open_root(cgroup);
-       if (fd < 0)
-               return 1;
-
        // Delete the directory
-       r = unlinkat(fd, cgroup->path, AT_REMOVEDIR);
+       r = unlinkat(cgroup->parent->fd, cgroup->name, AT_REMOVEDIR);
        if (r)
                ERROR(cgroup->ctx, "Could not destroy cgroup: %m\n");
 
-       // Close fd
-       close(fd);
-
        return r;
 }
 
index f7f2b099e008adfbb615665ef2ae3c1d591d4952..2363d4c4a3c6b4cf9efd34ebec1b0121b1a306e5 100644 (file)
@@ -721,7 +721,7 @@ int pakfire_daemon_create(struct pakfire_daemon** daemon, struct pakfire_ctx* ct
                goto ERROR;
 
        // Create the cgroup
-       r = pakfire_cgroup_create(&d->cgroup, d->ctx, "pakfire-daemon", 0);
+       r = pakfire_cgroup_create(&d->cgroup, d->ctx, NULL, "pakfire-daemon", 0);
        if (r < 0)
                goto ERROR;
 
index 05023312e5b71760496e8324853135a569ae6595..b4100a48ba115492686e2bace2e6cc7e0648649d 100644 (file)
@@ -196,7 +196,10 @@ struct pakfire_cgroup_stats {
 };
 
 int pakfire_cgroup_create(struct pakfire_cgroup** cgroup,
-       struct pakfire_ctx* ctx, const char* path, int flags);
+       struct pakfire_ctx* ctx, struct pakfire_cgroup* parent, const char* name, int flags);
+
+int pakfire_cgroup_create_root(
+       struct pakfire_cgroup** cgroup, struct pakfire_ctx* ctx, int flags);
 
 struct pakfire_cgroup* pakfire_cgroup_ref(struct pakfire_cgroup* cgroup);
 struct pakfire_cgroup* pakfire_cgroup_unref(struct pakfire_cgroup* cgroup);
index 31cee655d04ff416806931423b40ec8a261da15a..1260dd779d5f7be7ea5797371257e8571916945e 100644 (file)
@@ -1506,9 +1506,9 @@ static int __pakfire_jail_exec(struct pakfire_jail* jail,
                const char* uuid = pakfire_jail_uuid(jail);
 
                // Create a temporary cgroup
-               r = pakfire_cgroup_child(&ctx.cgroup, jail->cgroup, uuid, 0);
-               if (r) {
-                       ERROR(jail->ctx, "Could not create cgroup for jail: %m\n");
+               r = pakfire_cgroup_create(&ctx.cgroup, jail->ctx, jail->cgroup, uuid, 0);
+               if (r < 0) {
+                       ERROR(jail->ctx, "Could not create cgroup for jail: %s\n", strerror(-r));
                        goto ERROR;
                }
 
index 3e99e055811a022253b6835ca16cae464aba6ba7..549f899901a94e43c0539361117dfd26686fc56d 100644 (file)
@@ -30,7 +30,7 @@ static int test_create_and_destroy(const struct test* t) {
        int r = EXIT_FAILURE;
 
        // Open a new cgroup
-       ASSERT_SUCCESS(pakfire_cgroup_create(&cgroup, t->ctx, "pakfire-test", 0));
+       ASSERT_SUCCESS(pakfire_cgroup_create(&cgroup, t->ctx, NULL, "pakfire-test", 0));
 
        // Destroy the cgroup again
        ASSERT_SUCCESS(pakfire_cgroup_destroy(cgroup));
@@ -57,7 +57,7 @@ static int test_stats(const struct test* t) {
        };
 
        // Open the cgroup
-       ASSERT_SUCCESS(pakfire_cgroup_create(&cgroup, t->ctx, "pakfire-test", 0));
+       ASSERT_SUCCESS(pakfire_cgroup_create(&cgroup, t->ctx, NULL, "pakfire-test", 0));
 
        // Create a new jail
        ASSERT_SUCCESS(pakfire_jail_create(&jail, t->pakfire));