.imm = 0 \
})
-enum pakfire_cgroup_controllers {
- PAKFIRE_CGROUP_CONTROLLER_CPU = (1 << 0),
- PAKFIRE_CGROUP_CONTROLLER_MEMORY = (1 << 1),
- PAKFIRE_CGROUP_CONTROLLER_PIDS = (1 << 2),
- PAKFIRE_CGROUP_CONTROLLER_IO = (1 << 3),
-};
-
-static const enum pakfire_cgroup_controllers pakfire_cgroup_accounting_controllers =
- PAKFIRE_CGROUP_CONTROLLER_CPU |
- PAKFIRE_CGROUP_CONTROLLER_MEMORY |
- PAKFIRE_CGROUP_CONTROLLER_PIDS |
- PAKFIRE_CGROUP_CONTROLLER_IO;
-
struct pakfire_cgroup {
struct pakfire_ctx* ctx;
int nrefs;
return !*cgroup->path;
}
-static int pakfire_cgroup_has_flag(struct pakfire_cgroup* cgroup, int flag) {
- return cgroup->flags & flag;
-}
-
static int pakfire_cgroup_set_root(struct pakfire_cgroup* cgroup) {
int r;
return cgroup->path;
}
-static const char* pakfire_cgroup_controller_name(
- enum pakfire_cgroup_controllers controller) {
- switch (controller) {
- case PAKFIRE_CGROUP_CONTROLLER_CPU:
- return "cpu";
-
- case PAKFIRE_CGROUP_CONTROLLER_MEMORY:
- return "memory";
-
- case PAKFIRE_CGROUP_CONTROLLER_PIDS:
- return "pids";
-
- case PAKFIRE_CGROUP_CONTROLLER_IO:
- return "io";
- }
-
- return NULL;
-}
-
-static enum pakfire_cgroup_controllers pakfire_cgroup_find_controller_by_name(
- const char* name) {
- const char* n = NULL;
-
- // Walk through the bitmap
- for (unsigned int i = 1; i; i <<= 1) {
- n = pakfire_cgroup_controller_name(i);
- if (!n)
- break;
-
- // Match
- if (strcmp(name, n) == 0)
- return i;
- }
-
- // Nothing found
- return 0;
-}
-
static struct pakfire_cgroup* pakfire_cgroup_parent(struct pakfire_cgroup* cgroup) {
struct pakfire_cgroup* parent = NULL;
char path[PATH_MAX];
if (fd < 0) {
DEBUG(cgroup->ctx, "Could not open %s/%s for writing: %m\n",
pakfire_cgroup_name(cgroup), path);
- return 1;
+ return -errno;
}
// Write buffer
if (bytes_written < 0) {
DEBUG(cgroup->ctx, "Could not write to %s/%s: %m\n",
pakfire_cgroup_name(cgroup), path);
- r = 1;
+ r = -errno;
}
// Close fd
return r;
}
-static int pakfire_cgroup_read_controllers(
- struct pakfire_cgroup* cgroup, const char* name) {
- char buffer[BUFFER_SIZE];
- char* p = NULL;
-
- // Discovered controllers
- int controllers = 0;
-
- // Read cgroup.controllers file
- ssize_t bytes_read = pakfire_cgroup_read(cgroup, name, buffer, sizeof(buffer));
- if (bytes_read < 0)
- return -1;
-
- // If the file was empty, there is nothing more to do
- if (bytes_read == 0)
- return 0;
-
- char* token = strtok_r(buffer, " \n", &p);
-
- while (token) {
- DEBUG(cgroup->ctx, "Found controller '%s'\n", token);
-
- // Try finding this controller
- int controller = pakfire_cgroup_find_controller_by_name(token);
- if (controller)
- controllers |= controller;
-
- // Move on to next token
- token = strtok_r(NULL, " \n", &p);
- }
-
- // Return discovered controllers
- return controllers;
-}
-
/*
- Returns a bitmap of all available controllers
+ Enables a cgroup controller.
*/
-static int pakfire_cgroup_available_controllers(struct pakfire_cgroup* cgroup) {
- return pakfire_cgroup_read_controllers(cgroup, "cgroup.controllers");
-}
+static int pakfire_cgroup_enable_controller(struct pakfire_cgroup* cgroup, const char* name) {
+ int r;
-/*
- Returns a bitmap of all enabled controllers
-*/
-static int pakfire_cgroup_enabled_controllers(struct pakfire_cgroup* cgroup) {
- return pakfire_cgroup_read_controllers(cgroup, "cgroup.subtree_control");
+ // Try to enable the controller
+ r = pakfire_cgroup_write(cgroup, "cgroup.subtree_control", "+%s", name);
+ if (r < 0)
+ ERROR(cgroup->ctx, "Could not enable controller '%s': %s\n", name, strerror(-r));
+
+ return r;
}
/*
- This function takes a bitmap of controllers that should be enabled.
+ Enables all controllers that we need.
*/
-static int pakfire_cgroup_enable_controllers(struct pakfire_cgroup* cgroup,
- enum pakfire_cgroup_controllers controllers) {
- struct pakfire_cgroup* parent = NULL;
- int r = 1;
-
- // Find all enabled controllers
- const int enabled_controllers = pakfire_cgroup_enabled_controllers(cgroup);
- if (enabled_controllers < 0) {
- ERROR(cgroup->ctx, "Could not fetch enabled controllers: %m\n");
- goto ERROR;
- }
-
- // Filter out anything that is already enabled
- controllers = (controllers & ~enabled_controllers);
-
- // Exit if everything is already enabled
- if (!controllers) {
- DEBUG(cgroup->ctx, "All controllers are already enabled\n");
- return 0;
- }
-
- // Find all available controllers
- const int available_controllers = pakfire_cgroup_available_controllers(cgroup);
- if (available_controllers < 0) {
- ERROR(cgroup->ctx, "Could not fetch available controllers: %m\n");
- goto ERROR;
- }
-
- // Are all controllers we need available, yet?
- if (controllers & ~available_controllers) {
- DEBUG(cgroup->ctx, "Not all controllers are available, yet\n");
-
- parent = pakfire_cgroup_parent(cgroup);
-
- // Enable everything we need on the parent group
- if (parent) {
- r = pakfire_cgroup_enable_controllers(parent, controllers);
- if (r)
- goto ERROR;
- }
- }
-
- // Determine how many iterations we will need
- const int iterations = 1 << (sizeof(controllers) * 8 - __builtin_clz(controllers));
-
- // Iterate over all known controllers
- for (int controller = 1; controller < iterations; controller <<= 1) {
- // Skip enabling this controller if not requested
- if (!(controller & controllers))
- continue;
-
- // Fetch name
- const char* name = pakfire_cgroup_controller_name(controller);
-
- DEBUG(cgroup->ctx, "Enabling controller %s in cgroup %s\n",
- name, pakfire_cgroup_name(cgroup));
+static int pakfire_cgroup_enable_controllers(struct pakfire_cgroup* cgroup) {
+ static const char* controllers[] = {
+ "cpu", "memory", "pids", "io", NULL,
+ };
+ int r;
- // Try enabling the controller (this will succeed if it already is enabled)
- r = pakfire_cgroup_write(cgroup, "cgroup.subtree_control", "+%s\n", name);
- if (r) {
- ERROR(cgroup->ctx, "Could not enable controller %s in cgroup %s\n",
- name, pakfire_cgroup_name(cgroup));
- goto ERROR;
- }
+ // Enable all controllers
+ for (const char** controller = controllers; *controller; controller++) {
+ r = pakfire_cgroup_enable_controller(cgroup, *controller);
+ if (r < 0)
+ return r;
}
-ERROR:
- if (parent)
- pakfire_cgroup_unref(parent);
-
- return r;
-}
-
-static int pakfire_cgroup_enable_accounting(struct pakfire_cgroup* cgroup) {
- // Enable all accounting controllers
- return pakfire_cgroup_enable_controllers(cgroup,
- pakfire_cgroup_accounting_controllers);
+ return 0;
}
/*
goto ERROR;
}
- // Enable accounting if requested
- if (pakfire_cgroup_has_flag(c, PAKFIRE_CGROUP_ENABLE_ACCOUNTING)) {
- r = pakfire_cgroup_enable_accounting(c);
- if (r)
- goto ERROR;
- }
+ // Enable all controllers
+ r = pakfire_cgroup_enable_controllers(c);
+ if (r < 0)
+ goto ERROR;
// Setup the devices filter
r = pakfire_cgroup_setup_devices(c);
int pakfire_cgroup_set_guaranteed_memory(struct pakfire_cgroup* cgroup, size_t mem) {
int r;
- // Enable memory controller
- r = pakfire_cgroup_enable_controllers(cgroup, PAKFIRE_CGROUP_CONTROLLER_MEMORY);
- if (r)
- return r;
-
DEBUG(cgroup->ctx, "%s: Setting guaranteed memory to %zu byte(s)\n",
pakfire_cgroup_name(cgroup), mem);
int pakfire_cgroup_set_memory_limit(struct pakfire_cgroup* cgroup, size_t mem) {
int r;
- // Enable memory controller
- r = pakfire_cgroup_enable_controllers(cgroup, PAKFIRE_CGROUP_CONTROLLER_MEMORY);
- if (r)
- return r;
-
DEBUG(cgroup->ctx, "%s: Setting memory limit to %zu byte(s)\n",
pakfire_cgroup_name(cgroup), mem);
int pakfire_cgroup_set_pid_limit(struct pakfire_cgroup* cgroup, size_t limit) {
int r;
- // Enable PID controller
- r = pakfire_cgroup_enable_controllers(cgroup, PAKFIRE_CGROUP_CONTROLLER_PIDS);
- if (r)
- return r;
-
DEBUG(cgroup->ctx, "%s: Setting PID limit to %zu\n",
pakfire_cgroup_name(cgroup), limit);