*/
char *get_cpuset(const char *cg)
{
- char *answer;
+ char *value = NULL;
+ int ret;
- if (!cgroup_ops->get(cgroup_ops, "cpuset", cg, "cpuset.cpus", &answer))
+ ret = cgroup_ops->get_cpuset_cpus(cgroup_ops, cg, &value);
+ if (ret < 0)
return NULL;
- return answer;
+
+ return value;
}
bool cpu_in_cpuset(int cpu, const char *cpuset);
return cgfsng_get_memory(ops, cgroup, "memory.stat", value);
}
+static char *readat_cpuset(int cgroup_fd)
+{
+ __do_free char *val = NULL;
+
+ val = readat_file(cgroup_fd, "cpuset.cpus");
+ if (val && strcmp(val, "") != 0)
+ return move_ptr(val);
+
+ free_disarm(val);
+ val = readat_file(cgroup_fd, "cpuset.cpus.effective");
+ if (val && strcmp(val, "") != 0)
+ return move_ptr(val);
+
+ return NULL;
+}
+
+static int cgfsng_get_cpuset_cpus(struct cgroup_ops *ops, const char *cgroup,
+ char **value)
+{
+ __do_close_prot_errno int cgroup_fd = -EBADF;
+ __do_free char *path = NULL;
+ char *v;
+ struct hierarchy *h;
+ int ret;
+
+ h = ops->get_hierarchy(ops, "cpuset");
+ if (!h)
+ return -1;
+
+ if (!is_unified_hierarchy(h))
+ ret = CGROUP_SUPER_MAGIC;
+ else
+ ret = CGROUP2_SUPER_MAGIC;
+
+ *value = NULL;
+ path = must_make_path(*cgroup == '/' ? "." : "", cgroup, NULL);
+ cgroup_fd = openat_safe(h->fd, path);
+ if (cgroup_fd < 0) {
+ return -1;
+ }
+ v = readat_cpuset(cgroup_fd);
+ if (v) {
+ *value = v;
+ return ret;
+ }
+
+ /*
+ * cpuset.cpus and cpuset.cpus.effective are empty so we need to look
+ * the nearest ancestor with a non-empty cpuset.cpus{.effective} file.
+ */
+ for (;;) {
+ int fd;
+
+ fd = openat_safe(cgroup_fd, "../");
+ if (fd < 0 || !is_cgroup_fd(fd)) {
+ fprintf(stderr, "2222: %s\n", strerror(errno));
+ return -1;
+ }
+
+ close_prot_errno_replace(cgroup_fd, fd);
+
+ v = readat_cpuset(fd);
+ if (v) {
+ *value = v;
+ return ret;
+ }
+ }
+
+ return -1;
+}
+
/* At startup, parse_hierarchies finds all the info we need about cgroup
* mountpoints and current cgroups, and stores it in @d.
*/
cgfsng_ops->mount = cgfsng_mount;
cgfsng_ops->nrtasks = cgfsng_nrtasks;
-
/* memory */
cgfsng_ops->get_memory_stats = cgfsng_get_memory_stats;
cgfsng_ops->get_memory_max = cgfsng_get_memory_max;
cgfsng_ops->get_memory_current = cgfsng_get_memory_current;
cgfsng_ops->get_memory_swap_current = cgfsng_get_memory_swap_current;
+ /* cpuset */
+ cgfsng_ops->get_cpuset_cpus = cgfsng_get_cpuset_cpus;
+
return move_ptr(cgfsng_ops);
}
const char *controller, int type);
extern char *cg_legacy_get_current_cgroup(pid_t pid, const char *controller);
extern bool mkdir_p(const char *dir, mode_t mode);
+extern bool is_cgroup_fd(int fd);
+
+static inline int openat_safe(int fd, const char *path)
+{
+ return openat(fd, path, O_DIRECTORY | O_RDONLY | O_CLOEXEC | O_NOFOLLOW);
+}
#endif /* __LXC_CGROUP_UTILS_H */