summaryrefslogtreecommitdiff
path: root/src/cgroup-util.c
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2010-07-11 00:50:49 +0200
committerLennart Poettering <lennart@poettering.net>2010-07-11 00:50:49 +0200
commitc6c18be35bb1d300d0b62a568783cc1c477f7151 (patch)
treee4bad2452f20b6d1d6df9714d6abe72cdc56599c /src/cgroup-util.c
parent55096547212928b0ba83fca2595cae0d66d3c0b0 (diff)
cgroup: kill processes, not tasks and other cgroup changes
Diffstat (limited to 'src/cgroup-util.c')
-rw-r--r--src/cgroup-util.c374
1 files changed, 231 insertions, 143 deletions
diff --git a/src/cgroup-util.c b/src/cgroup-util.c
index 002c131f7f..0b8678c012 100644
--- a/src/cgroup-util.c
+++ b/src/cgroup-util.c
@@ -33,6 +33,15 @@
#include "macro.h"
#include "util.h"
+/*
+ Currently, the only remaining functionality from libcgroup we call
+ here is:
+
+ - cgroup_get_subsys_mount_point()
+ - cgroup_walk_tree_begin()/cgroup_walk_tree_next()
+ - cgroup_delete_cgroup_ext()
+ */
+
int cg_translate_error(int error, int _errno) {
switch (error) {
@@ -73,11 +82,78 @@ static struct cgroup* cg_new(const char *controller, const char *path) {
return cgroup;
}
+int cg_enumerate_processes(const char *controller, const char *path, FILE **_f) {
+ char *fs;
+ int r;
+ FILE *f;
+
+ assert(controller);
+ assert(path);
+ assert(_f);
+
+ if ((r = cg_get_path(controller, path, "cgroup.procs", &fs)) < 0)
+ return r;
+
+ f = fopen(fs, "re");
+ free(fs);
+
+ if (!f)
+ return -errno;
+
+ *_f = f;
+ return 0;
+}
+
+int cg_enumerate_tasks(const char *controller, const char *path, FILE **_f) {
+ char *fs;
+ int r;
+ FILE *f;
+
+ assert(controller);
+ assert(path);
+ assert(_f);
+
+ if ((r = cg_get_path(controller, path, "tasks", &fs)) < 0)
+ return r;
+
+ f = fopen(fs, "re");
+ free(fs);
+
+ if (!f)
+ return -errno;
+
+ *_f = f;
+ return 0;
+}
+
+int cg_read_pid(FILE *f, pid_t *_pid) {
+ unsigned long ul;
+
+ /* Note that the cgroup.procs might contain duplicates! See
+ * cgroups.txt for details. */
+
+ errno = 0;
+ if (fscanf(f, "%lu", &ul) != 1) {
+
+ if (feof(f))
+ return 0;
+
+ return errno ? -errno : -EIO;
+ }
+
+ if (ul <= 0)
+ return -EIO;
+
+ *_pid = (pid_t) ul;
+ return 1;
+}
+
int cg_kill(const char *controller, const char *path, int sig, bool ignore_self) {
bool killed = false, done = false;
Set *s;
pid_t my_pid;
int r, ret = 0;
+ FILE *f = NULL;
assert(controller);
assert(path);
@@ -93,23 +169,22 @@ int cg_kill(const char *controller, const char *path, int sig, bool ignore_self)
my_pid = getpid();
do {
- void *iterator = NULL;
- pid_t pid = 0;
-
+ pid_t pid;
done = true;
- r = cgroup_get_task_begin(path, controller, &iterator, &pid);
- while (r == 0) {
+ if ((r = cg_enumerate_processes(controller, path, &f)) < 0)
+ goto finish;
+
+ while ((r = cg_read_pid(f, &pid)) > 0) {
if (pid == my_pid && ignore_self)
- goto next;
+ continue;
- if (set_get(s, INT_TO_PTR(pid)) == INT_TO_PTR(pid))
- goto next;
+ if (set_get(s, LONG_TO_PTR(pid)) == LONG_TO_PTR(pid))
+ continue;
/* If we haven't killed this process yet, kill
* it */
-
if (kill(pid, sig) < 0 && errno != ESRCH) {
if (ret == 0)
ret = -errno;
@@ -118,22 +193,12 @@ int cg_kill(const char *controller, const char *path, int sig, bool ignore_self)
killed = true;
done = false;
- if ((r = set_put(s, INT_TO_PTR(pid))) < 0)
- goto loop_exit;
-
- next:
- r = cgroup_get_task_next(&iterator, &pid);
+ if ((r = set_put(s, LONG_TO_PTR(pid))) < 0)
+ break;
}
- if (r == 0 || r == ECGEOF)
- r = 0;
- else if (r == ECGOTHER && errno == ENOENT)
- r = -ESRCH;
- else
- r = cg_translate_error(r, errno);
-
- loop_exit:
- assert_se(cgroup_get_task_end(&iterator) == 0);
+ fclose(f);
+ f = NULL;
/* To avoid racing against processes which fork
* quicker than we can kill them we repeat this until
@@ -141,14 +206,18 @@ int cg_kill(const char *controller, const char *path, int sig, bool ignore_self)
} while (!done && r >= 0);
+finish:
set_free(s);
- if (ret < 0)
- return ret;
+ if (f)
+ fclose(f);
if (r < 0)
return r;
+ if (ret < 0)
+ return ret;
+
return !!killed;
}
@@ -237,63 +306,53 @@ int cg_kill_recursive_and_wait(const char *controller, const char *path) {
int cg_migrate(const char *controller, const char *from, const char *to, bool ignore_self) {
bool migrated = false, done = false;
- struct cgroup *dest;
int r, ret = 0;
pid_t my_pid;
+ FILE *f = NULL;
assert(controller);
assert(from);
assert(to);
- if (!(dest = cg_new(controller, to)))
- return -ENOMEM;
-
my_pid = getpid();
do {
- void *iterator = NULL;
- pid_t pid = 0;
-
+ pid_t pid;
done = true;
- r = cgroup_get_task_begin(from, controller, &iterator, &pid);
- while (r == 0) {
+ if ((r = cg_enumerate_tasks(controller, from, &f)) < 0)
+ goto finish;
+
+ while ((r = cg_read_pid(f, &pid)) > 0) {
if (pid == my_pid && ignore_self)
- goto next;
+ continue;
- if ((r = cgroup_attach_task_pid(dest, pid)) != 0) {
+ if ((r = cg_attach(controller, to, pid)) < 0) {
if (ret == 0)
- r = cg_translate_error(r, errno);
+ ret = -r;
}
migrated = true;
done = false;
-
- next:
-
- r = cgroup_get_task_next(&iterator, &pid);
}
- if (r == 0 || r == ECGEOF)
- r = 0;
- else if (r == ECGOTHER && errno == ENOENT)
- r = -ESRCH;
- else
- r = cg_translate_error(r, errno);
-
- assert_se(cgroup_get_task_end(&iterator) == 0);
+ fclose(f);
+ f = NULL;
} while (!done && r >= 0);
- cgroup_free(&dest);
+finish:
- if (ret < 0)
- return ret;
+ if (f)
+ fclose(f);
if (r < 0)
return r;
+ if (ret < 0)
+ return ret;
+
return !!migrated;
}
@@ -354,18 +413,24 @@ int cg_get_path(const char *controller, const char *path, const char *suffix, ch
int r;
assert(controller);
- assert(path);
if ((r = cgroup_get_subsys_mount_point(controller, &mp)) != 0)
return cg_translate_error(r, errno);
- if (suffix)
+ if (path && suffix)
r = asprintf(fs, "%s/%s/%s", mp, path, suffix);
- else
+ else if (path)
r = asprintf(fs, "%s/%s", mp, path);
+ else if (suffix)
+ r = asprintf(fs, "%s/%s", mp, suffix);
+ else {
+ path_kill_slashes(mp);
+ *fs = mp;
+ return 0;
+ }
free(mp);
-
+ path_kill_slashes(*fs);
return r < 0 ? -ENOMEM : 0;
}
@@ -409,83 +474,59 @@ finish:
}
int cg_create(const char *controller, const char *path) {
- struct cgroup *cg;
+ char *fs;
int r;
assert(controller);
assert(path);
- if (!(cg = cg_new(controller, path)))
- return -ENOMEM;
-
- if ((r = cgroup_create_cgroup(cg, 1)) != 0) {
- r = cg_translate_error(r, errno);
- goto finish;
- }
-
- r = 0;
+ if ((r = cg_get_path(controller, path, NULL, &fs)) < 0)
+ return r;
-finish:
- cgroup_free(&cg);
+ r = mkdir_p(fs, 0755);
+ free(fs);
return r;
}
int cg_attach(const char *controller, const char *path, pid_t pid) {
- struct cgroup *cg;
+ char *fs;
int r;
+ char c[32];
assert(controller);
assert(path);
assert(pid >= 0);
- if (!(cg = cg_new(controller, path)))
- return -ENOMEM;
+ if ((r = cg_get_path(controller, path, "tasks", &fs)) < 0)
+ return r;
if (pid == 0)
pid = getpid();
- if ((r = cgroup_attach_task_pid(cg, pid))) {
- r = cg_translate_error(r, errno);
- goto finish;
- }
-
- r = 0;
+ snprintf(c, sizeof(c), "%lu\n", (unsigned long) pid);
+ char_array_0(c);
-finish:
- cgroup_free(&cg);
+ r = write_one_line_file(fs, c);
+ free(fs);
return r;
}
int cg_create_and_attach(const char *controller, const char *path, pid_t pid) {
- struct cgroup *cg;
int r;
assert(controller);
assert(path);
assert(pid >= 0);
- if (!(cg = cg_new(controller, path)))
- return -ENOMEM;
-
- if ((r = cgroup_create_cgroup(cg, 1)) != 0) {
- r = cg_translate_error(r, errno);
- goto finish;
- }
-
- if (pid == 0)
- pid = getpid();
-
- if ((r = cgroup_attach_task_pid(cg, pid))) {
- r = cg_translate_error(r, errno);
- goto finish;
- }
+ if ((r = cg_create(controller, path)) < 0)
+ return r;
- r = 0;
+ if ((r = cg_attach(controller, path, pid)) < 0)
+ return r;
-finish:
- cgroup_free(&cg);
+ /* This does not remove the cgroup on failure */
return r;
}
@@ -525,40 +566,82 @@ int cg_set_task_access(const char *controller, const char *path, mode_t mode, ui
int cg_get_by_pid(const char *controller, pid_t pid, char **path) {
int r;
char *p = NULL;
+ FILE *f;
+ char *fs;
+ size_t cs;
assert(controller);
- assert(pid > 0);
assert(path);
+ assert(pid >= 0);
- if ((r = cgroup_get_current_controller_path(pid, controller, &p)) != 0)
- return cg_translate_error(r, errno);
+ if (pid == 0)
+ pid = getpid();
- assert(p);
+ if (asprintf(&fs, "/proc/%lu/cgroup", (unsigned long) pid) < 0)
+ return -ENOMEM;
- *path = p;
- return 0;
+ f = fopen(fs, "re");
+ free(fs);
+
+ cs = strlen(controller);
+
+ while (!feof(f)) {
+ char line[LINE_MAX];
+ char *l;
+
+ errno = 0;
+ if (!(fgets(line, sizeof(line), f))) {
+ if (feof(f))
+ break;
+
+ r = errno ? -errno : -EIO;
+ goto finish;
+ }
+
+ truncate_nl(line);
+
+ if (!(l = strchr(line, ':')))
+ continue;
+
+ l++;
+ if (strncmp(l, controller, cs) != 0)
+ continue;
+
+ if (l[cs] != ':')
+ continue;
+
+ if (!(p = strdup(l + cs + 1))) {
+ r = -ENOMEM;
+ goto finish;
+ }
+
+ *path = p;
+ r = 0;
+ goto finish;
+ }
+
+ r = -ENOENT;
+
+finish:
+ fclose(f);
+
+ return r;
}
int cg_install_release_agent(const char *controller, const char *agent) {
- char *mp = NULL, *path = NULL, *contents = NULL, *line = NULL, *sc;
+ char *fs = NULL, *contents = NULL, *line = NULL, *sc;
int r;
assert(controller);
assert(agent);
- if ((r = cgroup_get_subsys_mount_point(controller, &mp)) != 0)
- return cg_translate_error(r, errno);
-
- if (asprintf(&path, "%s/release_agent", mp) < 0) {
- r = -ENOMEM;
- goto finish;
- }
+ if ((r = cg_get_path(controller, NULL, "release_agent", &fs)) < 0)
+ return r;
- if ((r = read_one_line_file(path, &contents)) < 0)
+ if ((r = read_one_line_file(fs, &contents)) < 0)
goto finish;
sc = strstrip(contents);
-
if (sc[0] == 0) {
if (asprintf(&line, "%s\n", agent) < 0) {
@@ -566,7 +649,7 @@ int cg_install_release_agent(const char *controller, const char *agent) {
goto finish;
}
- if ((r = write_one_line_file(path, line)) < 0)
+ if ((r = write_one_line_file(fs, line)) < 0)
goto finish;
} else if (!streq(sc, agent)) {
@@ -574,33 +657,33 @@ int cg_install_release_agent(const char *controller, const char *agent) {
goto finish;
}
- free(path);
- path = NULL;
- if (asprintf(&path, "%s/notify_on_release", mp) < 0) {
+ free(fs);
+ fs = NULL;
+ if ((r = cg_get_path(controller, NULL, "notify_on_release", &fs)) < 0) {
r = -ENOMEM;
goto finish;
}
free(contents);
contents = NULL;
- if ((r = read_one_line_file(path, &contents)) < 0)
+ if ((r = read_one_line_file(fs, &contents)) < 0)
goto finish;
sc = strstrip(contents);
if (streq(sc, "0")) {
- if ((r = write_one_line_file(path, "1\n")) < 0)
+ if ((r = write_one_line_file(fs, "1\n")) < 0)
goto finish;
+
+ r = 1;
} else if (!streq(sc, "1")) {
r = -EIO;
goto finish;
- }
-
- r = 0;
+ } else
+ r = 0;
finish:
- free(mp);
- free(path);
+ free(fs);
free(contents);
free(line);
@@ -608,36 +691,32 @@ finish:
}
int cg_is_empty(const char *controller, const char *path, bool ignore_self) {
- void *iterator = NULL;
- pid_t pid = 0;
+ pid_t pid;
int r;
+ FILE *f;
+ bool found = false;
assert(controller);
assert(path);
- r = cgroup_get_task_begin(path, controller, &iterator, &pid);
- while (r == 0) {
+ if ((r = cg_enumerate_tasks(controller, path, &f)) < 0)
+ return r;
- if (ignore_self&& pid == getpid())
- goto next;
+ while ((r = cg_read_pid(f, &pid)) > 0) {
- break;
+ if (ignore_self && pid == getpid())
+ continue;
- next:
- r = cgroup_get_task_next(&iterator, &pid);
+ found = true;
+ break;
}
+ fclose(f);
- if (r == ECGEOF)
- r = 1;
- else if (r != 0)
- r = cg_translate_error(r, errno);
- else
- r = 0;
-
- assert_se(cgroup_get_task_end(&iterator) == 0);
+ if (r < 0)
+ return r;
- return r;
+ return !found;
}
int cg_is_empty_recursive(const char *controller, const char *path, bool ignore_self) {
@@ -692,3 +771,12 @@ int cg_is_empty_recursive(const char *controller, const char *path, bool ignore_
return ret;
}
+
+int cg_init(void) {
+ int r;
+
+ if ((r = cgroup_init()) != 0)
+ return cg_translate_error(r, errno);
+
+ return 0;
+}