// Flags
int flags;
- // Store the path
- char path[PATH_MAX];
+ // Store the name
+ char name[PATH_MAX];
// File descriptor to cgroup
int fd;
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) {
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;
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;
}
}
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;
}
/*
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;
// 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;
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);
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
*/
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;
}