]> git.proxmox.com Git - mirror_lxcfs.git/commitdiff
bindings: port cpuset to new cgroup getters and implement cgroup2 support
authorChristian Brauner <christian.brauner@ubuntu.com>
Mon, 24 Feb 2020 09:35:50 +0000 (10:35 +0100)
committerChristian Brauner <christian.brauner@ubuntu.com>
Mon, 24 Feb 2020 09:56:10 +0000 (10:56 +0100)
Signed-off-by: Christian Brauner <christian.brauner@ubuntu.com>
bindings.c
cgroups/cgfsng.c
cgroups/cgroup.h
cgroups/cgroup_utils.c
cgroups/cgroup_utils.h
memory_utils.h

index 52fbb8718ce8f9bceb6525d9899965ebd5b5ed34..35c1e426cfba84417afec1ab403b450f912a0bbd 100644 (file)
@@ -3543,11 +3543,14 @@ static int proc_meminfo_read(char *buf, size_t size, off_t offset,
  */
 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);
index 426ad8ab0c5598a9b32262edc4d7e71585828bcf..558f0f5615aa82f1f261ea13895ac6ceb9ec8c40 100644 (file)
@@ -666,6 +666,77 @@ static int cgfsng_get_memory_stats(struct cgroup_ops *ops, const char *cgroup,
        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.
  */
@@ -862,7 +933,6 @@ struct cgroup_ops *cgfsng_ops_init(void)
        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;
@@ -870,5 +940,8 @@ struct cgroup_ops *cgfsng_ops_init(void)
        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);
 }
index e367aff1adada0cb2d01a7c82ecbfdbef51965a3..29fe5ba7977b102f021d539a1d1af0788b50a621 100644 (file)
@@ -134,6 +134,10 @@ struct cgroup_ops {
                              char **value);
        int (*get_memory_swap_max)(struct cgroup_ops *ops, const char *cgroup,
                                   char **value);
+
+       /* cpuset */
+       int (*get_cpuset_cpus)(struct cgroup_ops *ops, const char *cgroup,
+                              char **value);
 };
 
 extern struct cgroup_ops *cgroup_init(void);
index e5b27070aa24f890b4394b62c1c10a6791b965da..b167cf73c832259afc4209ccaa97488741fd7094 100644 (file)
@@ -62,6 +62,23 @@ int unified_cgroup_hierarchy(void)
        return 0;
 }
 
+bool is_cgroup_fd(int fd)
+{
+
+       int ret;
+       struct statfs fs;
+
+       ret = fstatfs(fd, &fs);
+       if (ret)
+               return false;
+
+       if (is_fs_type(&fs, CGROUP2_SUPER_MAGIC) ||
+           is_fs_type(&fs, CGROUP_SUPER_MAGIC))
+               return true;
+
+       return false;
+}
+
 void *must_realloc(void *orig, size_t sz)
 {
        void *ret;
index 1db8a57daf6aa82dc894488452900ca3d311cc29..74b20cba7716f2e41e4dee05ead7d0821f642719 100644 (file)
@@ -69,5 +69,11 @@ extern char *cg_hybrid_get_current_cgroup(char *basecginfo,
                                          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 */
index ac00b10edf6ef89b6c599401ec4ec5854be4a680..a97c243284050c5cfa9e5196e63af740f3bde54d 100644 (file)
@@ -37,6 +37,14 @@ static inline void __auto_closedir__(DIR **d)
                fd = -EBADF;        \
        }
 
+#define close_prot_errno_replace(fd, new_fd) \
+       if (fd >= 0) {                       \
+               int _e_ = errno;             \
+               close(fd);                   \
+               errno = _e_;                 \
+               fd = new_fd;                 \
+       }
+
 #define free_disarm(ptr)       \
        ({                     \
                free(ptr);     \