conf: make cgroup delegate and leaf name first-class keys

parse_cgroup() takes two arguments that are not cgroupfs files: the
leaf directory to place the service in, and whether to hand the subtree
over to it.  The block format could express neither.  'name' happened
to work, because a free-form key is emitted as name:VALUE and that is
what the parser looks for, but 'delegate' came out as delegate:true and
was filed as a cgroup setting, so it silently did nothing.

Declare both, and emit delegate as the bare flag the parser expects.
Neither means anything on a top-level group definition, so say so there
rather than emitting something that would be written to cgroupfs.

    service podman {
        cgroup containers { name = "podman"  delegate = true }
        ...
    }

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
This commit is contained in:
Joachim Wiberg committed 2026-07-30 15:21:30 +02:00
1 parent ddaef0600f
commit ecac1e58e3
2 files changed
+46 -3

No files matched your search

+29 -3
View File
@@ -136,6 +136,14 @@ static TAILQ_HEAD(, conf_change) conf_change_list = TAILQ_HEAD_INITIALIZER(conf_
* cfg_error_cb() buffers it and only a failed parse is reported. * cfg_error_cb() buffers it and only a failed parse is reported.
*/ */
static cfg_opt_t cgroup_opts[] = { static cfg_opt_t cgroup_opts[] = {
/*
* Not cgroupfs files but arguments to parse_cgroup(): the leaf
* directory to place the service in, and whether to hand the
* subtree over to it. Only meaningful inside a service block.
*/
CFG_STR ("name", NULL, CFGF_NODEFAULT),
CFG_BOOL("delegate", cfg_false, CFGF_NODEFAULT),
CFG_STR("cpu.weight", NULL, CFGF_NODEFAULT), CFG_STR("cpu.weight", NULL, CFGF_NODEFAULT),
CFG_STR("cpu.weight.nice", NULL, CFGF_NODEFAULT), CFG_STR("cpu.weight.nice", NULL, CFGF_NODEFAULT),
CFG_STR("cpu.max", NULL, CFGF_NODEFAULT), CFG_STR("cpu.max", NULL, CFGF_NODEFAULT),
@@ -1079,11 +1087,27 @@ static void addopt(char *line, size_t len, const char *opt, const char *val)
* cgroup NAME { key = val ... } -> "NAME" + "key:val,key:val" * cgroup NAME { key = val ... } -> "NAME" + "key:val,key:val"
* Free-form (KEYSTRVAL) and declared options enumerate the same way. * Free-form (KEYSTRVAL) and declared options enumerate the same way.
*/ */
static char *cgroup_settings(cfg_t *cg, char *buf, size_t len) static char *cgroup_settings(cfg_t *cg, char *buf, size_t len, char *file, int svc)
{ {
cfg_opt_t *opt; cfg_opt_t *opt;
buf[0] = 0; buf[0] = 0;
/*
* delegate is a flag, so it carries no value, and a top-level
* group has nothing to delegate to.
*/
if (cfg_size(cg, "delegate")) {
if (!svc)
logit(LOG_WARNING, "%s: cgroup %s: delegate only applies"
" inside a service, ignoring", file, cfg_title(cg));
else if (cfg_getbool(cg, "delegate") == cfg_true)
strlcat(buf, "delegate", len);
}
if (!svc && cfg_size(cg, "name"))
logit(LOG_WARNING, "%s: cgroup %s: name only applies inside a"
" service, ignoring", file, cfg_title(cg));
for (opt = cg->opts; opt && opt->name; opt++) { for (opt = cg->opts; opt && opt->name; opt++) {
const char *val; const char *val;
@@ -1093,6 +1117,8 @@ static char *cgroup_settings(cfg_t *cg, char *buf, size_t len)
val = cfg_opt_getnstr(opt, 0); val = cfg_opt_getnstr(opt, 0);
if (!val) if (!val)
continue; continue;
if (!svc && !strcmp(opt->name, "name"))
continue;
if (buf[0]) if (buf[0])
strlcat(buf, ",", len); strlcat(buf, ",", len);
@@ -1394,7 +1420,7 @@ static void svc_translate(cfg_t *sec, int type, struct rlimit rlimit[], char *fi
" using '%s'", file, cfg_title(sec), cnt, " using '%s'", file, cfg_title(sec), cnt,
cfg_title(cg)); cfg_title(cg));
cgroup_settings(cg, buf, sizeof(buf)); cgroup_settings(cg, buf, sizeof(buf), file, 1);
if (buf[0]) if (buf[0])
addtok(line, sizeof(line), "cgroup.%s,%s", cfg_title(cg), buf); addtok(line, sizeof(line), "cgroup.%s,%s", cfg_title(cg), buf);
else else
@@ -1666,7 +1692,7 @@ static int conf_parse_cfg(cfg_t *cfg, char *file, int is_rcsd)
char buf[512]; char buf[512];
cgroup_add((char *)cfg_title(cg), cgroup_add((char *)cfg_title(cg),
cgroup_settings(cg, buf, sizeof(buf)), 0); cgroup_settings(cg, buf, sizeof(buf), file, 0), 0);
} }
/* file-scope resource limits, applies to all services in file */ /* file-scope resource limits, applies to all services in file */
+17
View File
@@ -257,3 +257,20 @@ for key in manual-start manual; do
run "initctl stop service.sh" run "initctl stop service.sh"
retry 'assert_num_children 0 service.sh' retry 'assert_num_children 0 service.sh'
done done
# delegate is a flag to parse_cgroup(), not a cgroupfs file, and the
# cgroup leaf name is an argument too. Both must come out of the
# translator in the comma-separated form that parser expects.
say 'cgroup delegate and name translate as parse_cgroup arguments'
run "echo 'service service.sh {' > $FINIT_CONF"
run "echo ' description = \"Delegated\"' >> $FINIT_CONF"
run "echo ' cgroup system {' >> $FINIT_CONF"
run "echo ' name = \"mysvc\"' >> $FINIT_CONF"
run "echo ' delegate = true' >> $FINIT_CONF"
run "echo ' cpu.weight = 250' >> $FINIT_CONF"
run "echo ' }' >> $FINIT_CONF"
run "echo ' command = \"service.sh\"' >> $FINIT_CONF"
run "echo '}' >> $FINIT_CONF"
run "initctl reload"
retry 'assert_desc "Delegated" service.sh'