mirror of
https://github.com/troglobit/finit.git
synced 2026-11-06 15:51:03 +00:00
Fix #188: support without cgroups v2 support
This patch adds support for detecting if the Linux kernel Fint runs on
has support for cgroups v2. The probe is done very early, in runlevel
S, when attempting to mount /sys/fs/cgroup. Meaning, the log message
may be lost on systems that do not run sysklogd[1].
Here's the relevant logs from a system running myLinux on a kernel
that has cgroups v2 support disabled:
Jan 10 20:19:40 anarchy finit[1]: myLinux 2021.11-696-g8fddaf36ed, entering runlevel S
Jan 10 20:19:40 anarchy finit[1]: Kernel does not support cgroups v2, disabling.
Jan 10 20:19:41 anarchy finit[1]: myLinux 2021.11-696-g8fddaf36ed, entering runlevel 2
All code paths that attempt to set or query kernel cgroups config has
been short circuited when this happens. However, this does not apply
to any cgroup related config in the Finit .conf files -- which may of
course be omitted. Yet, if configuration directives exist, they will
be parsed and may cause error.
Also, the initctl tool checks if /sys/fs/cgroup is mounted at runtime
and disables all status output and commands that rely on the feature.
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
This commit is contained in:
1 parent
d331b72dfd
commit
a37037ded4
4 files changed
+108
-53
No files matched your search
+30
-1
@@ -56,6 +56,7 @@ static char controllers[256];
|
|||||||
|
|
||||||
static struct iwatch iw_cgroup;
|
static struct iwatch iw_cgroup;
|
||||||
static uev_t cgw;
|
static uev_t cgw;
|
||||||
|
static int avail;
|
||||||
|
|
||||||
|
|
||||||
static void cgset(const char *path, char *ctrl, char *prop)
|
static void cgset(const char *path, char *ctrl, char *prop)
|
||||||
@@ -164,6 +165,9 @@ static int cgroup_leaf_init(char *group, char *name, int pid, const char *cfg)
|
|||||||
|
|
||||||
int cgroup_user(char *name, int pid)
|
int cgroup_user(char *name, int pid)
|
||||||
{
|
{
|
||||||
|
if (!avail)
|
||||||
|
return 0;
|
||||||
|
|
||||||
return cgroup_leaf_init("user", name, pid, NULL);
|
return cgroup_leaf_init("user", name, pid, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -171,6 +175,9 @@ int cgroup_service(char *name, int pid, struct cgroup *cg)
|
|||||||
{
|
{
|
||||||
char *group = "system";
|
char *group = "system";
|
||||||
|
|
||||||
|
if (!avail)
|
||||||
|
return 0;
|
||||||
|
|
||||||
if (cg && cg->name[0]) {
|
if (cg && cg->name[0]) {
|
||||||
char path[256];
|
char path[256];
|
||||||
|
|
||||||
@@ -307,6 +314,9 @@ void cgroup_mark_all(void)
|
|||||||
{
|
{
|
||||||
struct cg *cg;
|
struct cg *cg;
|
||||||
|
|
||||||
|
if (!avail)
|
||||||
|
return;
|
||||||
|
|
||||||
TAILQ_FOREACH(cg, &cgroups, link) {
|
TAILQ_FOREACH(cg, &cgroups, link) {
|
||||||
if (cg->is_protected)
|
if (cg->is_protected)
|
||||||
continue;
|
continue;
|
||||||
@@ -323,6 +333,9 @@ void cgroup_cleanup(void)
|
|||||||
struct cg *cg, *tmp;
|
struct cg *cg, *tmp;
|
||||||
char path[256];
|
char path[256];
|
||||||
|
|
||||||
|
if (!avail)
|
||||||
|
return;
|
||||||
|
|
||||||
TAILQ_FOREACH_SAFE(cg, &cgroups, link, tmp) {
|
TAILQ_FOREACH_SAFE(cg, &cgroups, link, tmp) {
|
||||||
if (cg->active)
|
if (cg->active)
|
||||||
continue;
|
continue;
|
||||||
@@ -339,6 +352,9 @@ int cgroup_add(char *name, char *cfg, int is_protected)
|
|||||||
{
|
{
|
||||||
struct cg *cg;
|
struct cg *cg;
|
||||||
|
|
||||||
|
if (!avail)
|
||||||
|
return 0;
|
||||||
|
|
||||||
if (!name)
|
if (!name)
|
||||||
return -1;
|
return -1;
|
||||||
if (!cfg)
|
if (!cfg)
|
||||||
@@ -383,6 +399,9 @@ int cgroup_del(char *dir)
|
|||||||
struct cg *cg;
|
struct cg *cg;
|
||||||
char path[256];
|
char path[256];
|
||||||
|
|
||||||
|
if (!avail)
|
||||||
|
return 0;
|
||||||
|
|
||||||
TAILQ_FOREACH(cg, &cgroups, link) {
|
TAILQ_FOREACH(cg, &cgroups, link) {
|
||||||
snprintf(path, sizeof(path), FINIT_CGPATH "/%s", cg->name);
|
snprintf(path, sizeof(path), FINIT_CGPATH "/%s", cg->name);
|
||||||
if (strcmp(path, dir))
|
if (strcmp(path, dir))
|
||||||
@@ -414,6 +433,9 @@ void cgroup_config(void)
|
|||||||
{
|
{
|
||||||
struct cg *cg;
|
struct cg *cg;
|
||||||
|
|
||||||
|
if (!avail)
|
||||||
|
return;
|
||||||
|
|
||||||
TAILQ_FOREACH(cg, &cgroups, link) {
|
TAILQ_FOREACH(cg, &cgroups, link) {
|
||||||
char path[256];
|
char path[256];
|
||||||
int leaf = 0;
|
int leaf = 0;
|
||||||
@@ -442,14 +464,21 @@ void cgroup_init(uev_ctx_t *ctx)
|
|||||||
int fd;
|
int fd;
|
||||||
|
|
||||||
if (mount("none", FINIT_CGPATH, "cgroup2", opts, NULL)) {
|
if (mount("none", FINIT_CGPATH, "cgroup2", opts, NULL)) {
|
||||||
_pe("Failed mounting cgroup v2");
|
if (errno == ENOENT)
|
||||||
|
logit(LOG_NOTICE, "Kernel does not support cgroups v2, disabling.");
|
||||||
|
else
|
||||||
|
_pe("Failed mounting cgroup v2, disabling.");
|
||||||
|
avail = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
avail = 1;
|
||||||
|
|
||||||
/* Find available controllers */
|
/* Find available controllers */
|
||||||
fp = fopen(FINIT_CGPATH "/cgroup.controllers", "r");
|
fp = fopen(FINIT_CGPATH "/cgroup.controllers", "r");
|
||||||
if (!fp) {
|
if (!fp) {
|
||||||
_pe("Failed opening %s", FINIT_CGPATH "/cgroup.controllers");
|
_pe("Failed opening %s", FINIT_CGPATH "/cgroup.controllers");
|
||||||
|
umount(FINIT_CGPATH);
|
||||||
|
avail = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -53,6 +53,10 @@ uint64_t total_ram; /* From sysinfo() */
|
|||||||
struct cg dummy; /* empty result "NULL" */
|
struct cg dummy; /* empty result "NULL" */
|
||||||
struct cg *list;
|
struct cg *list;
|
||||||
|
|
||||||
|
int cgroup_avail(void)
|
||||||
|
{
|
||||||
|
return fismnt(FINIT_CGPATH);
|
||||||
|
}
|
||||||
|
|
||||||
char *pid_cmdline(int pid, char *buf, size_t len)
|
char *pid_cmdline(int pid, char *buf, size_t len)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -52,6 +52,8 @@ struct cg {
|
|||||||
} cg_cpu;
|
} cg_cpu;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
int cgroup_avail(void);
|
||||||
|
|
||||||
char *pid_cmdline (int pid, char *buf, size_t len);
|
char *pid_cmdline (int pid, char *buf, size_t len);
|
||||||
char *pid_comm (int pid, char *buf, size_t len);
|
char *pid_comm (int pid, char *buf, size_t len);
|
||||||
char *pid_cgroup (int pid, char *buf, size_t len);
|
char *pid_cgroup (int pid, char *buf, size_t len);
|
||||||
|
|||||||
+72
-52
@@ -51,6 +51,7 @@ struct cmd {
|
|||||||
char *cmd;
|
char *cmd;
|
||||||
struct cmd *ctx;
|
struct cmd *ctx;
|
||||||
int (*cb)(char *arg);
|
int (*cb)(char *arg);
|
||||||
|
int *cond;
|
||||||
};
|
};
|
||||||
|
|
||||||
int icreate = 0;
|
int icreate = 0;
|
||||||
@@ -62,6 +63,8 @@ int verbose = 0;
|
|||||||
int plain = 0;
|
int plain = 0;
|
||||||
int quiet = 0;
|
int quiet = 0;
|
||||||
int runlevel = 0;
|
int runlevel = 0;
|
||||||
|
int cgrp = 0;
|
||||||
|
|
||||||
int iw, pw;
|
int iw, pw;
|
||||||
|
|
||||||
extern int reboot_main(int argc, char *argv[]);
|
extern int reboot_main(int argc, char *argv[]);
|
||||||
@@ -711,11 +714,7 @@ static int show_status(char *arg)
|
|||||||
while (arg && arg[0]) {
|
while (arg && arg[0]) {
|
||||||
long now = jiffies();
|
long now = jiffies();
|
||||||
char uptm[42] = "N/A";
|
char uptm[42] = "N/A";
|
||||||
char grbuf[128];
|
|
||||||
char path[256];
|
|
||||||
struct cg *cg;
|
|
||||||
int exact = 0;
|
int exact = 0;
|
||||||
char *group;
|
|
||||||
|
|
||||||
for (svc = client_svc_iterator(1); svc; svc = client_svc_iterator(0)) {
|
for (svc = client_svc_iterator(1); svc; svc = client_svc_iterator(0)) {
|
||||||
svc_ident(svc, ident, sizeof(ident));
|
svc_ident(svc, ident, sizeof(ident));
|
||||||
@@ -735,10 +734,6 @@ static int show_status(char *arg)
|
|||||||
if (quiet)
|
if (quiet)
|
||||||
return svc->state != SVC_RUNNING_STATE;
|
return svc->state != SVC_RUNNING_STATE;
|
||||||
|
|
||||||
group = pid_cgroup(svc->pid, grbuf, sizeof(grbuf));
|
|
||||||
snprintf(path, sizeof(path), "%s/%s", FINIT_CGPATH, group);
|
|
||||||
cg = cg_conf(path);
|
|
||||||
|
|
||||||
printf(" Status : %s\n", status(svc, 1));
|
printf(" Status : %s\n", status(svc, 1));
|
||||||
printf(" Identity : %s\n", svc_ident(svc, ident, sizeof(ident)));
|
printf(" Identity : %s\n", svc_ident(svc, ident, sizeof(ident)));
|
||||||
printf("Description : %s\n", svc->desc);
|
printf("Description : %s\n", svc->desc);
|
||||||
@@ -752,7 +747,16 @@ static int show_status(char *arg)
|
|||||||
printf(" Group : %s\n", svc->group);
|
printf(" Group : %s\n", svc->group);
|
||||||
printf(" Uptime : %s\n", svc->pid ? uptime(now - svc->start_time, uptm, sizeof(uptm)) : uptm);
|
printf(" Uptime : %s\n", svc->pid ? uptime(now - svc->start_time, uptm, sizeof(uptm)) : uptm);
|
||||||
printf(" Runlevels : %s\n", runlevel_string(runlevel, svc->runlevels));
|
printf(" Runlevels : %s\n", runlevel_string(runlevel, svc->runlevels));
|
||||||
if (svc->pid > 1) {
|
if (cgrp && svc->pid > 1) {
|
||||||
|
char grbuf[128];
|
||||||
|
char path[256];
|
||||||
|
struct cg *cg;
|
||||||
|
char *group;
|
||||||
|
|
||||||
|
group = pid_cgroup(svc->pid, grbuf, sizeof(grbuf));
|
||||||
|
snprintf(path, sizeof(path), "%s/%s", FINIT_CGPATH, group);
|
||||||
|
cg = cg_conf(path);
|
||||||
|
|
||||||
printf(" Memory : %s\n", memsz(cgroup_memory(group), uptm, sizeof(uptm)));
|
printf(" Memory : %s\n", memsz(cgroup_memory(group), uptm, sizeof(uptm)));
|
||||||
printf(" CGroup : %s cpu %s [%s, %s] mem [%s, %s]\n",
|
printf(" CGroup : %s cpu %s [%s, %s] mem [%s, %s]\n",
|
||||||
group, cg->cg_cpu.set, cg->cg_cpu.weight, cg->cg_cpu.max,
|
group, cg->cg_cpu.set, cg->cg_cpu.weight, cg->cg_cpu.max,
|
||||||
@@ -925,11 +929,14 @@ static int usage(int rc)
|
|||||||
" restart <NAME>[:ID] Restart (stop/start) service by name\n"
|
" restart <NAME>[:ID] Restart (stop/start) service by name\n"
|
||||||
" ident [NAME] Show matching identities for NAME, or all\n"
|
" ident [NAME] Show matching identities for NAME, or all\n"
|
||||||
" status <NAME>[:ID] Show service status, by name\n"
|
" status <NAME>[:ID] Show service status, by name\n"
|
||||||
" status Show status of services, default command\n"
|
" status Show status of services, default command\n");
|
||||||
"\n"
|
if (cgrp)
|
||||||
" cgroup List cgroup config overview\n"
|
fprintf(stderr,
|
||||||
" ps List processes based on cgroups\n"
|
"\n"
|
||||||
" top Show top-like listing based on cgroups\n"
|
" cgroup List cgroup config overview\n"
|
||||||
|
" ps List processes based on cgroups\n"
|
||||||
|
" top Show top-like listing based on cgroups\n");
|
||||||
|
fprintf(stderr,
|
||||||
"\n"
|
"\n"
|
||||||
" runlevel [0-9] Show or set runlevel: 0 halt, 6 reboot\n"
|
" runlevel [0-9] Show or set runlevel: 0 halt, 6 reboot\n"
|
||||||
" reboot Reboot system\n"
|
" reboot Reboot system\n"
|
||||||
@@ -962,11 +969,22 @@ static int do_help(char *arg)
|
|||||||
return usage(0);
|
return usage(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int cmd_cond(struct cmd *cmd)
|
||||||
|
{
|
||||||
|
if (!cmd || !cmd->cond)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return *cmd->cond;
|
||||||
|
}
|
||||||
|
|
||||||
static int cmd_parse(int argc, char *argv[], struct cmd *command)
|
static int cmd_parse(int argc, char *argv[], struct cmd *command)
|
||||||
{
|
{
|
||||||
int i, j;
|
int i, j;
|
||||||
|
|
||||||
for (i = 0; argc > 0 && command[i].cmd; i++) {
|
for (i = 0; argc > 0 && command[i].cmd; i++) {
|
||||||
|
if (!cmd_cond(&command[i]))
|
||||||
|
continue;
|
||||||
|
|
||||||
if (!string_match(command[i].cmd, argv[0]))
|
if (!string_match(command[i].cmd, argv[0]))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@@ -991,7 +1009,6 @@ static int cmd_parse(int argc, char *argv[], struct cmd *command)
|
|||||||
|
|
||||||
return command[0].cb(NULL); /* default cmd */
|
return command[0].cb(NULL); /* default cmd */
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
struct option long_options[] = {
|
struct option long_options[] = {
|
||||||
@@ -1008,58 +1025,61 @@ int main(int argc, char *argv[])
|
|||||||
{ NULL, 0, NULL, 0 }
|
{ NULL, 0, NULL, 0 }
|
||||||
};
|
};
|
||||||
struct cmd cond[] = {
|
struct cmd cond[] = {
|
||||||
{ "status", NULL, do_cond_show }, /* default cmd */
|
{ "status", NULL, do_cond_show, NULL }, /* default cmd */
|
||||||
{ "dump", NULL, do_cond_dump },
|
{ "dump", NULL, do_cond_dump, NULL },
|
||||||
{ "set", NULL, do_cond_set },
|
{ "set", NULL, do_cond_set, NULL },
|
||||||
{ "clr", NULL, do_cond_clr },
|
{ "clr", NULL, do_cond_clr, NULL },
|
||||||
{ "clear", NULL, do_cond_clr },
|
{ "clear", NULL, do_cond_clr, NULL },
|
||||||
{ NULL, NULL, NULL }
|
{ NULL, NULL, NULL, NULL }
|
||||||
};
|
};
|
||||||
struct cmd command[] = {
|
struct cmd command[] = {
|
||||||
{ "status", NULL, show_status }, /* default cmd */
|
{ "status", NULL, show_status, NULL }, /* default cmd */
|
||||||
{ "ident", NULL, show_ident },
|
{ "ident", NULL, show_ident, NULL },
|
||||||
|
|
||||||
{ "debug", NULL, toggle_debug },
|
{ "debug", NULL, toggle_debug, NULL },
|
||||||
{ "devel", NULL, do_devel },
|
{ "devel", NULL, do_devel, NULL },
|
||||||
{ "help", NULL, do_help },
|
{ "help", NULL, do_help, NULL },
|
||||||
{ "version", NULL, show_version },
|
{ "version", NULL, show_version, NULL },
|
||||||
|
|
||||||
{ "list", NULL, serv_list },
|
{ "list", NULL, serv_list, NULL },
|
||||||
{ "ls", NULL, serv_list },
|
{ "ls", NULL, serv_list, NULL },
|
||||||
{ "enable", NULL, serv_enable },
|
{ "enable", NULL, serv_enable, NULL },
|
||||||
{ "disable", NULL, serv_disable },
|
{ "disable", NULL, serv_disable, NULL },
|
||||||
{ "touch", NULL, serv_touch },
|
{ "touch", NULL, serv_touch, NULL },
|
||||||
{ "show", NULL, serv_show },
|
{ "show", NULL, serv_show, NULL },
|
||||||
{ "edit", NULL, serv_edit },
|
{ "edit", NULL, serv_edit, NULL },
|
||||||
{ "create", NULL, serv_creat },
|
{ "create", NULL, serv_creat, NULL },
|
||||||
{ "delete", NULL, serv_delete },
|
{ "delete", NULL, serv_delete, NULL },
|
||||||
{ "reload", NULL, do_reload },
|
{ "reload", NULL, do_reload, NULL },
|
||||||
|
|
||||||
{ "cond", cond, NULL },
|
{ "cond", cond, NULL, NULL },
|
||||||
|
|
||||||
{ "log", NULL, do_log },
|
{ "log", NULL, do_log, NULL },
|
||||||
{ "start", NULL, do_start },
|
{ "start", NULL, do_start, NULL },
|
||||||
{ "stop", NULL, do_stop },
|
{ "stop", NULL, do_stop, NULL },
|
||||||
{ "restart", NULL, do_restart },
|
{ "restart", NULL, do_restart, NULL },
|
||||||
|
|
||||||
{ "cgroup", NULL, show_cgroup },
|
{ "cgroup", NULL, show_cgroup, &cgrp },
|
||||||
{ "ps", NULL, show_cgps },
|
{ "ps", NULL, show_cgps, &cgrp },
|
||||||
{ "top", NULL, show_cgtop },
|
{ "top", NULL, show_cgtop, &cgrp },
|
||||||
|
|
||||||
{ "runlevel", NULL, do_runlevel },
|
{ "runlevel", NULL, do_runlevel, NULL },
|
||||||
{ "reboot", NULL, do_reboot },
|
{ "reboot", NULL, do_reboot, NULL },
|
||||||
{ "halt", NULL, do_halt },
|
{ "halt", NULL, do_halt, NULL },
|
||||||
{ "poweroff", NULL, do_poweroff },
|
{ "poweroff", NULL, do_poweroff, NULL },
|
||||||
{ "suspend", NULL, do_suspend },
|
{ "suspend", NULL, do_suspend, NULL },
|
||||||
|
|
||||||
{ "utmp", NULL, do_utmp },
|
{ "utmp", NULL, do_utmp, NULL },
|
||||||
{ NULL, NULL, NULL }
|
{ NULL, NULL, NULL, NULL }
|
||||||
};
|
};
|
||||||
int interactive = 1, c;
|
int interactive = 1, c;
|
||||||
|
|
||||||
if (transform(progname(argv[0])))
|
if (transform(progname(argv[0])))
|
||||||
return reboot_main(argc, argv);
|
return reboot_main(argc, argv);
|
||||||
|
|
||||||
|
/* Enable some functionality if kernel supports cgroups v2 */
|
||||||
|
cgrp = cgroup_avail();
|
||||||
|
|
||||||
while ((c = getopt_long(argc, argv, "1bcdfh?pqtv", long_options, NULL)) != EOF) {
|
while ((c = getopt_long(argc, argv, "1bcdfh?pqtv", long_options, NULL)) != EOF) {
|
||||||
switch(c) {
|
switch(c) {
|
||||||
case '1':
|
case '1':
|
||||||
|
|||||||
Reference in new issue
Block a user