return r;
}
+static int whitelist_major(const char *path, const char *name, char type, const char *acc) {
+ _cleanup_fclose_ FILE *f = NULL;
+ char line[LINE_MAX];
+ bool good = false;
+ int r;
+
+ assert(path);
+ assert(acc);
+ assert(type == 'b' || type == 'c');
+
+ f = fopen("/proc/devices", "re");
+ if (!f) {
+ log_warning("Cannot open /proc/devices to resolve %s (%c): %m", name, type);
+ return -errno;
+ }
+
+ FOREACH_LINE(line, f, goto fail) {
+ char buf[2+DECIMAL_STR_MAX(unsigned)+3+4], *p, *w;
+ unsigned maj;
+
+ truncate_nl(line);
+
+ if (type == 'c' && streq(line, "Character devices:")) {
+ good = true;
+ continue;
+ }
+
+ if (type == 'b' && streq(line, "Block devices:")) {
+ good = true;
+ continue;
+ }
+
+ if (isempty(line)) {
+ good = false;
+ continue;
+ }
+
+ if (!good)
+ continue;
+
+ p = strstrip(line);
+
+ w = strpbrk(p, WHITESPACE);
+ if (!w)
+ continue;
+ *w = 0;
+
+ r = safe_atou(p, &maj);
+ if (r < 0)
+ continue;
+ if (maj <= 0)
+ continue;
+
+ w++;
+ w += strspn(w, WHITESPACE);
+ if (!streq(w, name))
+ continue;
+
+ sprintf(buf,
+ "%c %u:* %s",
+ type,
+ maj,
+ acc);
+
+ r = cg_set_attribute("devices", path, "devices.allow", buf);
+ if (r < 0)
+ log_warning("Failed to set devices.allow on %s: %s", path, strerror(-r));
+ }
+
+ return 0;
+
+fail:
+ log_warning("Failed to read /proc/devices: %m");
+ return -errno;
+}
+
void cgroup_context_apply(CGroupContext *c, CGroupControllerMask mask, const char *path) {
int r;
continue;
acc[k++] = 0;
- whitelist_device(path, a->path, acc);
+
+ if (startswith(a->path, "/dev/"))
+ whitelist_device(path, a->path, acc);
+ else if (startswith(a->path, "block-"))
+ whitelist_major(path, a->path + 6, 'b', acc);
+ else if (startswith(a->path, "char-"))
+ whitelist_major(path, a->path + 5, 'c', acc);
+ else
+ log_debug("Ignoring device %s while writing cgroup attribute.", a->path);
}
}
}
if (member == u)
continue;
- if (UNIT_DEREF(member->slice) != u)
+ if (UNIT_DEREF(member->slice) != u)
continue;
u->cgroup_members_mask |=
}
}
+static const char *migrate_callback(CGroupControllerMask mask, void *userdata) {
+ Unit *u = userdata;
+
+ assert(mask != 0);
+ assert(u);
+
+ while (u) {
+ if (u->cgroup_path &&
+ u->cgroup_realized &&
+ (u->cgroup_realized_mask & mask) == mask)
+ return u->cgroup_path;
+
+ u = UNIT_DEREF(u->slice);
+ }
+
+ return NULL;
+}
+
static int unit_create_cgroups(Unit *u, CGroupControllerMask mask) {
- _cleanup_free_ char *path;
- bool was_in_hash = false;
+ _cleanup_free_ char *path = NULL;
int r;
assert(u);
return log_oom();
r = hashmap_put(u->manager->cgroup_unit, path, u);
- if (r == 0)
- was_in_hash = true;
- else if (r < 0) {
- log_error(r == -EEXIST ?
- "cgroup %s exists already: %s" : "hashmap_put failed for %s: %s",
- path, strerror(-r));
+ if (r < 0) {
+ log_error(r == -EEXIST ? "cgroup %s exists already: %s" : "hashmap_put failed for %s: %s", path, strerror(-r));
return r;
}
-
- /* First, create our own group */
- r = cg_create_everywhere(u->manager->cgroup_supported, mask, path);
- if (r < 0)
- log_error("Failed to create cgroup %s: %s", path, strerror(-r));
-
- /* Then, possibly move things over */
- if (u->cgroup_path) {
- r = cg_migrate_everywhere(u->manager->cgroup_supported, u->cgroup_path, path);
- if (r < 0)
- log_error("Failed to migrate cgroup from %s to %s: %s",
- u->cgroup_path, path, strerror(-r));
- }
-
- if (!was_in_hash) {
- /* Remember the new data */
- free(u->cgroup_path);
+ if (r > 0) {
u->cgroup_path = path;
path = NULL;
}
+ /* First, create our own group */
+ r = cg_create_everywhere(u->manager->cgroup_supported, mask, u->cgroup_path);
+ if (r < 0) {
+ log_error("Failed to create cgroup %s: %s", u->cgroup_path, strerror(-r));
+ return r;
+ }
+
+ /* Keep track that this is now realized */
u->cgroup_realized = true;
u->cgroup_realized_mask = mask;
+ /* Then, possibly move things over */
+ r = cg_migrate_everywhere(u->manager->cgroup_supported, u->cgroup_path, u->cgroup_path, migrate_callback, u);
+ if (r < 0)
+ log_warning("Failed to migrate cgroup from to %s: %s", u->cgroup_path, strerror(-r));
+
return 0;
}
* unit, we need to first create all parents, but there's more
* actually: for the weight-based controllers we also need to
* make sure that all our siblings (i.e. units that are in the
- * same slice as we are) have cgroups, too. Otherwise things
+ * same slice as we are) have cgroups, too. Otherwise, things
* would become very uneven as each of their processes would
* get as much resources as all our group together. This call
* will synchronously create the parent cgroups, but will