]> git.ipfire.org Git - pakfire.git/commitdiff
cgroups: Keep a reference to the parent group
authorMichael Tremer <michael.tremer@ipfire.org>
Mon, 9 Dec 2024 17:20:07 +0000 (17:20 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Mon, 9 Dec 2024 17:20:07 +0000 (17:20 +0000)
Since so many operations are recursive, this might be easier to handle.

Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
src/libpakfire/cgroup.c

index e2679ecf3b0495ab932466c74a9ad17c2ff7a38d..75647be480d46fc28d3c6778e68ae167c3c0b1af 100644 (file)
@@ -61,6 +61,9 @@ struct pakfire_cgroup {
        struct pakfire_ctx* ctx;
        int nrefs;
 
+       // The parent group
+       struct pakfire_cgroup* parent;
+
        // Store the root path
        char root[PATH_MAX];
 
@@ -77,11 +80,6 @@ struct pakfire_cgroup {
        int devicesfd;
 };
 
-// Returns true if this is the root cgroup
-static int pakfire_cgroup_is_root(struct pakfire_cgroup* cgroup) {
-       return !*cgroup->path;
-}
-
 static int pakfire_cgroup_set_root(struct pakfire_cgroup* cgroup) {
        int r;
 
@@ -108,21 +106,19 @@ static int pakfire_cgroup_set_root(struct pakfire_cgroup* cgroup) {
 }
 
 static const char* pakfire_cgroup_name(struct pakfire_cgroup* cgroup) {
-       if (pakfire_cgroup_is_root(cgroup))
+       if (!cgroup->parent)
                return "(root)";
 
        return cgroup->path;
 }
 
-static int pakfire_cgroup_parent(struct pakfire_cgroup* cgroup,  struct pakfire_cgroup** parent) {
+static int pakfire_cgroup_parent(struct pakfire_cgroup* cgroup, struct pakfire_cgroup** parent) {
        char path[PATH_MAX];
        int r;
 
-       // Cannot return parent for root group
-       if (pakfire_cgroup_is_root(cgroup)) {
-               *parent = NULL;
+       // 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);
@@ -176,27 +172,12 @@ static int pakfire_cgroup_open_root(struct pakfire_cgroup* cgroup) {
        int fd = open(cgroup->root, O_DIRECTORY|O_PATH|O_CLOEXEC);
        if (fd < 0) {
                ERROR(cgroup->ctx, "Could not open %s: %m\n", cgroup->root);
-               return -1;
+               return -errno;
        }
 
        return fd;
 }
 
-static int __pakfire_cgroup_create(struct pakfire_cgroup* cgroup) {
-       char path[PATH_MAX];
-       int r;
-
-       DEBUG(cgroup->ctx, "Trying to create cgroup %s\n", pakfire_cgroup_name(cgroup));
-
-       // Compose the absolute path
-       r = pakfire_path_append(path, cgroup->root, cgroup->path);
-       if (r)
-               return 1;
-
-       // Try creating the directory
-       return pakfire_mkdir(path, 0755);
-}
-
 /*
        Opens the cgroup and returns a file descriptor.
 
@@ -204,44 +185,40 @@ static int __pakfire_cgroup_create(struct pakfire_cgroup* cgroup) {
 
        This function returns a negative value on error.
 */
-static int __pakfire_cgroup_open(struct pakfire_cgroup* cgroup) {
+static int pakfire_cgroup_open(struct pakfire_cgroup* cgroup) {
+       char basename[NAME_MAX];
        int fd = -EBADF;
        int r;
 
-       // Open file descriptor of the cgroup root
-       int rootfd = pakfire_cgroup_open_root(cgroup);
-       if (rootfd < 0)
-               return rootfd;
+       // Open the root cgroup
+       if (!cgroup->parent)
+               return pakfire_cgroup_open_root(cgroup);
 
-       // Return the rootfd for the root group
-       if (pakfire_cgroup_is_root(cgroup))
-               return rootfd;
+       // Get the basename
+       r = pakfire_path_basename(basename, cgroup->path);
+       if (r < 0)
+               return r;
 
-RETRY:
-       fd = openat(rootfd, cgroup->path, O_DIRECTORY|O_PATH|O_CLOEXEC);
+       // Try to open the cgroup
+       fd = openat(cgroup->parent->fd, basename, O_DIRECTORY|O_PATH|O_CLOEXEC);
        if (fd < 0) {
                switch (errno) {
-                       // If the cgroup doesn't exist yet, try to create it
                        case ENOENT:
-                               r = __pakfire_cgroup_create(cgroup);
-                               if (r)
-                                       goto ERROR;
+                               r = mkdirat(cgroup->parent->fd, basename, 0755);
+                               if (r < 0) {
+                                       ERROR(cgroup->ctx, "Could not create cgroup '%s': %m\n", basename);
+                                       return -errno;
+                               }
 
-                               // Retry open after successful creation
-                               goto RETRY;
+                               // Try opening it again
+                               return pakfire_cgroup_open(cgroup);
 
-                       // Exit on all other errors
                        default:
-                               ERROR(cgroup->ctx, "Could not open cgroup %s: %m\n",
-                                       pakfire_cgroup_name(cgroup));
-                               goto ERROR;
+                               ERROR(cgroup->ctx, "Could not open cgroup '%s': %m\n", basename);
+                               return -errno;
                }
        }
 
-ERROR:
-       if (rootfd > 0)
-               close(rootfd);
-
        return fd;
 }
 
@@ -422,22 +399,27 @@ int pakfire_cgroup_create(struct pakfire_cgroup** cgroup,
        // 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 = __pakfire_cgroup_open(c);
-       if (c->fd < 0) {
-               r = 1;
+       c->fd = r = pakfire_cgroup_open(c);
+       if (r < 0)
                goto ERROR;
-       }
 
        // Enable all controllers
        r = pakfire_cgroup_enable_controllers(c);
        if (r < 0)
                goto ERROR;
 
+#if 0
        // Setup the devices filter
        r = pakfire_cgroup_setup_devices(c);
        if (r)
                goto ERROR;
+#endif
 
        // Return the pointer
        *cgroup = pakfire_cgroup_ref(c);
@@ -454,6 +436,8 @@ static void pakfire_cgroup_free(struct pakfire_cgroup* cgroup) {
                close(cgroup->fd);
        if (cgroup->devicesfd >= 0)
                close(cgroup->devicesfd);
+       if (cgroup->parent)
+               pakfire_cgroup_unref(cgroup->parent);
        if (cgroup->ctx)
                pakfire_ctx_unref(cgroup->ctx);
        free(cgroup);
@@ -508,10 +492,8 @@ int pakfire_cgroup_destroy(struct pakfire_cgroup* cgroup) {
        int r;
 
        // Cannot call this for the root group
-       if (pakfire_cgroup_is_root(cgroup)) {
-               errno = EPERM;
-               return 1;
-       }
+       if (!cgroup->parent)
+               return -EPERM;
 
        DEBUG(cgroup->ctx, "Destroying cgroup %s\n", pakfire_cgroup_name(cgroup));