mirror of
https://github.com/troglobit/finit.git
synced 2026-11-02 13:20:32 +00:00
cgroup: refactor, use a unified hierarchy for finit
As of now, the default finit cgroup behavior is to use a unified hierarchy of controllers under /sys/fs/cgroup/finit. We mount cpu,cpuacct,cpuset,memory (if available) and gain the ability to control our three major groups: init, system, user. The default CPU share setup is ~10% for init and user, and 90% for system. These are guaranteed CPU shares to ensure we do not starve PID 1 or user processes. Support for configuring these limits will be added in a later commit. Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
This commit is contained in:
1 parent
4e84ecae89
commit
5428dea5bf
5 files changed
+113
-20
No files matched your search
+2
-2
@@ -2,10 +2,10 @@
|
|||||||
# Called by kernel when last child in cgroup exists
|
# Called by kernel when last child in cgroup exists
|
||||||
|
|
||||||
BASE=/sys/fs/cgroup/finit
|
BASE=/sys/fs/cgroup/finit
|
||||||
PROC=`basename $1`
|
PROC=$(basename "$1")
|
||||||
DIR="$BASE$1"
|
DIR="$BASE$1"
|
||||||
|
|
||||||
#/libexec/finit/logit -p daemon.info -t finit "$PROC stopped, cleaning up control group $DIR"
|
#/libexec/finit/logit -p daemon.info -t finit "$PROC stopped, cleaning up control group $DIR"
|
||||||
rmdir $DIR
|
rmdir "$DIR"
|
||||||
|
|
||||||
exit 0
|
exit 0
|
||||||
+81
-13
@@ -26,19 +26,61 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <lite/lite.h>
|
#include <lite/lite.h>
|
||||||
#include <sys/mount.h>
|
#include <sys/mount.h>
|
||||||
|
#include <sys/sysinfo.h>
|
||||||
|
|
||||||
#include "finit.h"
|
#include "finit.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
|
static char controllers[256] = "none";
|
||||||
|
|
||||||
|
static void group_init(char *path, char *nproc, int share)
|
||||||
|
{
|
||||||
|
char file[strlen(path) + 64];
|
||||||
|
|
||||||
|
paste(file, sizeof(file), path, "cgroup.clone_children");
|
||||||
|
echo(file, 0, "1");
|
||||||
|
|
||||||
|
paste(file, sizeof(file), path, "cpuset.cpus");
|
||||||
|
echo(file, 0, nproc);
|
||||||
|
|
||||||
|
paste(file, sizeof(file), path, "cpuset.mems");
|
||||||
|
echo(file, 0, "0");
|
||||||
|
|
||||||
|
echo(FINIT_CGPATH "/init/cpu.shares", 0, "%d", share);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void append_ctrl(char *ctrl)
|
||||||
|
{
|
||||||
|
char *wanted[] = {
|
||||||
|
"cpu",
|
||||||
|
"cpuacct",
|
||||||
|
"cpuset",
|
||||||
|
"memory"
|
||||||
|
};
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
for (i = 0; i < NELEMS(wanted); i++) {
|
||||||
|
if (strcmp(wanted[i], ctrl))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (strcmp(controllers, "none"))
|
||||||
|
strlcat(controllers, ",", sizeof(controllers));
|
||||||
|
else
|
||||||
|
strlcpy(controllers, "", sizeof(controllers));
|
||||||
|
|
||||||
|
strlcat(controllers, ctrl, sizeof(controllers));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Called by Finit at early boot to mount initial cgroups
|
* Called by Finit at early boot to mount initial cgroups
|
||||||
*/
|
*/
|
||||||
void cgroup_init(void)
|
void cgroup_init(void)
|
||||||
{
|
{
|
||||||
FILE *fp;
|
|
||||||
char buf[80];
|
|
||||||
int opts = MS_NODEV | MS_NOEXEC | MS_NOSUID;
|
int opts = MS_NODEV | MS_NOEXEC | MS_NOSUID;
|
||||||
|
char buf[80];
|
||||||
|
FILE *fp;
|
||||||
|
|
||||||
fp = fopen("/proc/cgroups", "r");
|
fp = fopen("/proc/cgroups", "r");
|
||||||
if (!fp) {
|
if (!fp) {
|
||||||
@@ -53,25 +95,40 @@ void cgroup_init(void)
|
|||||||
|
|
||||||
/* Skip first line, header */
|
/* Skip first line, header */
|
||||||
(void)fgets(buf, sizeof(buf), fp);
|
(void)fgets(buf, sizeof(buf), fp);
|
||||||
|
|
||||||
|
/* Create and mount traditional cgroups v1 hier */
|
||||||
while (fgets(buf, sizeof(buf), fp)) {
|
while (fgets(buf, sizeof(buf), fp)) {
|
||||||
char *cgroup;
|
char *cgroup;
|
||||||
|
#if 0
|
||||||
char rc[80];
|
char rc[80];
|
||||||
|
#endif
|
||||||
|
|
||||||
cgroup = strtok(buf, "\t ");
|
cgroup = strtok(buf, "\t ");
|
||||||
if (!cgroup)
|
if (!cgroup)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
#if 0
|
||||||
snprintf(rc, sizeof(rc), "/sys/fs/cgroup/%s", cgroup);
|
snprintf(rc, sizeof(rc), "/sys/fs/cgroup/%s", cgroup);
|
||||||
if (mkdir(rc, 0755) && EEXIST != errno)
|
if (mkdir(rc, 0755) && EEXIST != errno)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (mount("cgroup", rc, "cgroup", opts, cgroup))
|
if (mount("cgroup", rc, "cgroup", opts, cgroup))
|
||||||
_d("Failed mounting %s cgroup on %s", cgroup, rc);
|
_d("Failed mounting %s cgroup on %s", cgroup, rc);
|
||||||
|
#else
|
||||||
|
append_ctrl(cgroup);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Default cgroups for process monitoring */
|
/* Finit default cgroups for process monitoring */
|
||||||
if (mkdir(FINIT_CGPATH, 0755) && EEXIST != errno)
|
if (mkdir(FINIT_CGPATH, 0755) && EEXIST != errno)
|
||||||
goto fail;
|
goto fail;
|
||||||
if (mount("none", FINIT_CGPATH, "cgroup", opts, "none,name=finit")) {
|
|
||||||
|
#if 0
|
||||||
|
strlcpy(controllers, "none,name=finit", sizeof(controllers));
|
||||||
|
#else
|
||||||
|
strlcat(controllers, ",name=finit", sizeof(controllers));
|
||||||
|
#endif
|
||||||
|
if (mount("none", FINIT_CGPATH, "cgroup", opts, controllers)) {
|
||||||
_pe("Failed mounting Finit cgroup hierarchy");
|
_pe("Failed mounting Finit cgroup hierarchy");
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
@@ -88,6 +145,21 @@ void cgroup_init(void)
|
|||||||
if (mkdir(FINIT_CGPATH "/user", 0755) && EEXIST != errno)
|
if (mkdir(FINIT_CGPATH "/user", 0755) && EEXIST != errno)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set up basic limits for our groups. Finit optimized defaults
|
||||||
|
* for embedded and server systems include limiting the groups
|
||||||
|
* init and user to a single CPU with 10% share, the system
|
||||||
|
* group gets the rest. Override this from finit.conf
|
||||||
|
*/
|
||||||
|
#if 0
|
||||||
|
#else
|
||||||
|
snprintf(buf, sizeof(buf), "0-%d", get_nprocs_conf() - 1);
|
||||||
|
|
||||||
|
group_init(FINIT_CGPATH "/init", "0", 50);
|
||||||
|
group_init(FINIT_CGPATH "/user", "0", 75);
|
||||||
|
group_init(FINIT_CGPATH "/system", buf, 900);
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Move ourselves to init */
|
/* Move ourselves to init */
|
||||||
echo(FINIT_CGPATH "/init/cgroup.procs", 0, "1");
|
echo(FINIT_CGPATH "/init/cgroup.procs", 0, "1");
|
||||||
|
|
||||||
@@ -95,15 +167,11 @@ fail:
|
|||||||
fclose(fp);
|
fclose(fp);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int move_pid(char *group, char *name, char *id, int pid)
|
static int move_pid(char *group, char *name, int pid)
|
||||||
{
|
{
|
||||||
char path[256];
|
char path[256];
|
||||||
|
|
||||||
snprintf(path, sizeof(path), "/sys/fs/cgroup/%s/%s", group, name);
|
snprintf(path, sizeof(path), "/sys/fs/cgroup/%s/%s", group, name);
|
||||||
if (id && strlen(id)) {
|
|
||||||
strlcat(path, ":", sizeof(path));
|
|
||||||
strlcat(path, id, sizeof(path));
|
|
||||||
}
|
|
||||||
if (mkdir(path, 0755) && errno != EEXIST)
|
if (mkdir(path, 0755) && errno != EEXIST)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
@@ -112,19 +180,19 @@ static int move_pid(char *group, char *name, char *id, int pid)
|
|||||||
return echo(path, 0, "%d", pid);
|
return echo(path, 0, "%d", pid);
|
||||||
}
|
}
|
||||||
|
|
||||||
int cgroup_user(char *name)
|
int cgroup_user(char *name, int pid)
|
||||||
{
|
{
|
||||||
return move_pid("finit/user", name, NULL, getpid());
|
return move_pid("finit/user", name, pid);
|
||||||
}
|
}
|
||||||
|
|
||||||
int cgroup_service(char *nm, char *id, int pid)
|
int cgroup_service(char *name, int pid)
|
||||||
{
|
{
|
||||||
if (pid <= 0) {
|
if (pid <= 0) {
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return move_pid("finit/system", nm, id, pid);
|
return move_pid("finit/system", name, pid);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+2
-2
@@ -26,7 +26,7 @@
|
|||||||
|
|
||||||
void cgroup_init (void);
|
void cgroup_init (void);
|
||||||
|
|
||||||
int cgroup_user (char *name);
|
int cgroup_user (char *name, int pid);
|
||||||
int cgroup_service (char *cmd, char *id, int pid);
|
int cgroup_service (char *name, int pid);
|
||||||
|
|
||||||
#endif /* FINIT_CGROUP_H_ */
|
#endif /* FINIT_CGROUP_H_ */
|
||||||
+1
-1
@@ -186,7 +186,7 @@ static int do_login(char *name)
|
|||||||
{
|
{
|
||||||
struct stat st;
|
struct stat st;
|
||||||
|
|
||||||
cgroup_user(name);
|
cgroup_user(name, getpid());
|
||||||
execl(_PATH_LOGIN, _PATH_LOGIN, name, NULL);
|
execl(_PATH_LOGIN, _PATH_LOGIN, name, NULL);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
+27
-2
@@ -351,6 +351,30 @@ static int is_norespawn(void)
|
|||||||
fexist("/tmp/norespawn");
|
fexist("/tmp/norespawn");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* used for process group name, derived from originating filename,
|
||||||
|
* so to group multiple services, place them in the same .conf
|
||||||
|
*/
|
||||||
|
static char *group_name(svc_t *svc, char *buf, size_t len)
|
||||||
|
{
|
||||||
|
char *ptr;
|
||||||
|
|
||||||
|
if (!svc->file[0])
|
||||||
|
return svc_ident(svc, buf, len);
|
||||||
|
|
||||||
|
ptr = strrchr(svc->file, '/');
|
||||||
|
if (ptr)
|
||||||
|
ptr++;
|
||||||
|
else
|
||||||
|
ptr = svc->file;
|
||||||
|
|
||||||
|
strlcpy(buf, ptr, len);
|
||||||
|
ptr = strstr(buf, ".conf");
|
||||||
|
if (ptr)
|
||||||
|
*ptr = 0;
|
||||||
|
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* service_start - Start service
|
* service_start - Start service
|
||||||
* @svc: Service to start
|
* @svc: Service to start
|
||||||
@@ -362,6 +386,7 @@ static int service_start(svc_t *svc)
|
|||||||
{
|
{
|
||||||
int result = 0, do_progress = 1;
|
int result = 0, do_progress = 1;
|
||||||
sigset_t nmask, omask;
|
sigset_t nmask, omask;
|
||||||
|
char grnam[80];
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
@@ -408,8 +433,6 @@ static int service_start(svc_t *svc)
|
|||||||
sigprocmask(SIG_BLOCK, &nmask, &omask);
|
sigprocmask(SIG_BLOCK, &nmask, &omask);
|
||||||
|
|
||||||
pid = fork();
|
pid = fork();
|
||||||
cgroup_service(svc->name, svc->id, pid);
|
|
||||||
|
|
||||||
if (pid == 0) {
|
if (pid == 0) {
|
||||||
int status;
|
int status;
|
||||||
char *home = NULL;
|
char *home = NULL;
|
||||||
@@ -547,6 +570,8 @@ static int service_start(svc_t *svc)
|
|||||||
_d("Starting %s %s", svc->cmd, buf);
|
_d("Starting %s %s", svc->cmd, buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cgroup_service(group_name(svc, grnam, sizeof(grnam)), pid);
|
||||||
|
|
||||||
logit(LOG_CONSOLE | LOG_NOTICE, "Starting %s[%d]", svc_ident(svc, NULL, 0), pid);
|
logit(LOG_CONSOLE | LOG_NOTICE, "Starting %s[%d]", svc_ident(svc, NULL, 0), pid);
|
||||||
|
|
||||||
svc->pid = pid;
|
svc->pid = pid;
|
||||||
|
|||||||
Reference in new issue
Block a user