Add support for configuring cgroups and their settings on services

This patch adds support for modifying settings for the default cgroups;
init, user, and system, as well as adding up to a total of eight groups
for the system.

Services can now be assigned to a cgroup, with optional extra settings
for that particular process group.  The syntax is slightly contrivied
but follows the overall Finit syntax of prop:value,prop':value', e.g.

   cgroup maint cpu.weight:123,mem.max:10000

Starting with the introduction of rlimits, a group of services sharing
the same .conf file can share the same (locally "global") rlimits, and
now also the same cgroup, e.g.

    cgroup.maint
    service foo
    service bar cgroup:mem.max:1000

This puts foo and bar in the same top-level cgroup 'maint', with an
extra memory restriction on bar for max 1000 bytes memory.

NOTE: 'mem.' is a Finit extension, a shorthand for cgroups2 'memory.'

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
This commit is contained in:
Joachim Wiberg committed 2021-03-30 10:21:01 +02:00
1 parent 9e6e653c57
commit 665d212bd6
8 files changed
+282 -28

No files matched your search

+95 -3
View File
@@ -23,6 +23,7 @@
#include "config.h" /* Generated by configure script */
#include <ctype.h>
#include <dirent.h>
#include <string.h>
#include <sys/inotify.h>
@@ -50,6 +51,10 @@ int logfile_count_max = 5;
struct rlimit initial_rlimit[RLIMIT_NLIMITS];
struct rlimit global_rlimit[RLIMIT_NLIMITS];
struct cgroup cgroups[8];
size_t cgroups_num;
char cgroup_current[16]; /* cgroup.NAME sets current cgroup for a set of services */
struct conf_change {
TAILQ_ENTRY(conf_change) link;
char *name;
@@ -423,6 +428,67 @@ error:
logit(LOG_WARNING, "rlimit: parse error");
}
/* reset defaults */
static void init_cgroups(void)
{
struct cgroup init[3] = {
{ .name = "init", .cfg = "cpu.weight:100" },
{ .name = "user", .cfg = "cpu.weight:100" },
{ .name = "system", .cfg = "cpu.weight:9800" },
};
size_t i;
for (i = 0; i < NELEMS(init); i++)
memcpy(&cgroups[i], &init[i], sizeof(struct cgroup));
cgroups_num = i;
}
struct cgroup *conf_cgfind(char *name)
{
size_t i;
for (i = 0; i < cgroups_num; i++) {
if (strcmp(cgroups[i].name, name))
continue;
return &cgroups[i];
}
return NULL;
}
/* cgroup NAME ctrl.prop:value,ctrl.prop:value ... */
static void conf_parse_cgroup(char *line)
{
struct cgroup *cg;
char *ptr, *name;
name = strtok(line, " \t");
if (!name)
return;
cg = conf_cgfind(name);
if (!cg) {
if (strstr(name, "..") || strchr(name, '/'))
return; /* illegal */
if (cgroups_num + 1 == NELEMS(cgroups))
return; /* exhausted */
cg = &cgroups[cgroups_num++];
strlcpy(cg->name, name, sizeof(cg->name));
}
cg->cfg[0] = 0;
while ((ptr = strtok(NULL, " \t"))) {
if (cg->cfg[0])
strlcat(cg->cfg, ",", sizeof(cg->cfg));
strlcat(cg->cfg, ptr, sizeof(cg->cfg));
}
_d("cg->cfg: %s", cg->cfg);
}
static void parse_static(char *line, int is_rcsd)
{
char cmd[CMD_SIZE];
@@ -552,6 +618,18 @@ static void parse_dynamic(char *line, struct rlimit rlimit[], char *file)
return;
}
/* Read contrl group limits */
if (MATCH_CMD(line, "cgroup ", x)) {
conf_parse_cgroup(x);
return;
}
/* Set current cgroup for the following services/run/tasks */
if (MATCH_CMD(line, "cgroup.", x)) {
strlcpy(cgroup_current, x, sizeof(cgroup_current));
return;
}
/* Regular or serial TTYs to run getty */
if (MATCH_CMD(line, "tty ", x)) {
tty_register(strip_line(x), rlimit, file);
@@ -580,9 +658,11 @@ static int parse_conf(char *file, int is_rcsd)
if (!fp)
return 1;
/* Prepare default limits for each service in /etc/finit.d/ */
if (is_rcsd)
/* Prepare default limits and group for each service in /etc/finit.d/ */
if (is_rcsd) {
memcpy(rlimit, global_rlimit, sizeof(rlimit));
memset(cgroup_current, 0, sizeof(cgroup_current));
}
_d("*** Parsing %s", file);
while (!feof(fp)) {
@@ -630,6 +710,9 @@ int conf_reload(void)
*/
memcpy(global_rlimit, initial_rlimit, sizeof(global_rlimit));
/* Initialize default cgroups */
init_cgroups();
if (rescue) {
int rc;
char line[80] = "tty [12345] @console noclear nologin";
@@ -699,6 +782,9 @@ int conf_reload(void)
/* Mark any reverse deps as chenaged. */
service_update_rdeps();
/* Set up top-level cgroups */
cgroup_config(cgroups_num, cgroups);
done:
/* Drop record of all .conf changes */
drop_changes();
@@ -888,7 +974,7 @@ int conf_monitor(void)
}
/*
* Prepare .conf parser and load all .conf files
* Prepare .conf parser and load /etc/finit.conf for global settings
*/
int conf_init(uev_ctx_t *ctx)
{
@@ -911,6 +997,12 @@ int conf_init(uev_ctx_t *ctx)
/* Initialize global rlimits, e.g. for built-in services */
memcpy(global_rlimit, initial_rlimit, sizeof(global_rlimit));
/* Initialize default cgroups */
init_cgroups();
/* Read global rlimits and global cgroup setup from /etc/finit.conf */
parse_conf(FINIT_CONF, 0);
/* prepare /etc watcher */
fd = iwatch_init(&iw_conf);
if (fd < 0)