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

+36 -3
View File
@@ -570,7 +570,7 @@ static int service_start(svc_t *svc)
_d("Starting %s %s", svc->cmd, buf);
}
cgroup_service(group_name(svc, grnam, sizeof(grnam)), pid);
cgroup_service(group_name(svc, grnam, sizeof(grnam)), pid, &svc->cgroup);
logit(LOG_CONSOLE | LOG_NOTICE, "Starting %s[%d]", svc_ident(svc, NULL, 0), pid);
@@ -857,6 +857,30 @@ static void parse_env(svc_t *svc, char *env)
strlcpy(svc->env, env, sizeof(svc->env));
}
static void parse_cgroup(svc_t *svc, char *cgroup)
{
char *ptr = cgroup;
if (!cgroup)
return;
if (cgroup[0] == '.') {
ptr = strchr(cgroup, ':');
if (ptr)
*ptr++ = 0;
strlcpy(svc->cgroup.name, &cgroup[1], sizeof(svc->cgroup.name));
if (!ptr)
return;
}
if (strlen(ptr) >= sizeof(svc->cgroup)) {
_e("%s: cgroup settings too long (>%d chars)", svc->cmd, sizeof(svc->cgroup));
return;
}
strlcpy(svc->cgroup.cfg, ptr, sizeof(svc->cgroup.cfg));
}
static void parse_sighalt(svc_t *svc, char *arg)
{
int signo;
@@ -1026,7 +1050,7 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
char *cmd, *desc, *runlevels = NULL, *cond = NULL;
char *username = NULL, *log = NULL, *pid = NULL;
char *name = NULL, *halt = NULL, *delay = NULL;
char *id = NULL, *env = NULL;
char *id = NULL, *env = NULL, *cgroup = NULL;
int levels = 0;
int manual = 0;
char *line;
@@ -1090,6 +1114,10 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
delay = &cmd[5];
else if (!strncasecmp(cmd, "env:", 4))
env = &cmd[4];
else if (!strncasecmp(cmd, "cgroup:", 7))
cgroup = &cmd[7]; /* only settings */
else if (!strncasecmp(cmd, "cgroup.", 7))
cgroup = &cmd[6]; /* with group */
else
break;
@@ -1148,7 +1176,7 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
parse_cmdline_args(svc, cmd);
svc->runlevels = levels;
_d("Service %s runlevel 0x%2x", svc->cmd, svc->runlevels);
_d("Service %s runlevel 0x%02x", svc->cmd, svc->runlevels);
conf_parse_cond(svc, cond);
@@ -1169,6 +1197,11 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
/* Set configured limits */
memcpy(svc->rlimit, rlimit, sizeof(svc->rlimit));
/* Seed with currently active group, may be empty */
strlcpy(svc->cgroup.name, cgroup_current, sizeof(svc->cgroup.name));
if (cgroup)
parse_cgroup(svc, cgroup);
/* New, recently modified or unchanged ... used on reload. */
if ((file && conf_changed(file)) || conf_changed(svc_getenv(svc)))
svc_mark_dirty(svc);