]> git.proxmox.com Git - mirror_lxcfs.git/commitdiff
proc_fuse: add /proc/slabinfo with slab accounting memcg
authorFeng Sun <loyou85@gmail.com>
Thu, 10 Dec 2020 09:30:54 +0000 (17:30 +0800)
committerFeng Sun <loyou85@gmail.com>
Thu, 10 Dec 2020 10:50:48 +0000 (18:50 +0800)
Signed-off-by: Feng Sun <loyou85@gmail.com>
README.md
src/api_extensions.h
src/bindings.h
src/cgroups/cgfsng.c
src/cgroups/cgroup.h
src/proc_fuse.c

index 3c638c381f9d9a2dd9b5ad0b2ca5d4e13f06d44e..54d3eabfcaf572172ccaa61087937b9523759411 100644 (file)
--- a/README.md
+++ b/README.md
@@ -15,6 +15,7 @@ such as:
 /proc/stat
 /proc/swaps
 /proc/uptime
+/proc/slabinfo
 /sys/devices/system/cpu/online
 ```
 
@@ -98,6 +99,7 @@ docker run -it -m 256m --memory-swap 256m \
       -v /var/lib/lxcfs/proc/stat:/proc/stat:rw \
       -v /var/lib/lxcfs/proc/swaps:/proc/swaps:rw \
       -v /var/lib/lxcfs/proc/uptime:/proc/uptime:rw \
+      -v /var/lib/lxcfs/proc/slabinfo:/proc/slabinfo:rw \
       ubuntu:18.04 /bin/bash
  ```
 
index a4ee0c1d07fafd4a7740f370a97de89920ae2def..9ee55dafc2d79b95e73b294c4b887eb37a803dce 100644 (file)
@@ -22,6 +22,7 @@ static char *api_extensions[] = {
        "proc_stat",
        "proc_swaps",
        "proc_uptime",
+       "proc_slabinfo",
        "shared_pidns",
        "cpuview_daemon",
        "loadavg_daemon",
index e26090296e22a87be3c4eceda935caf359e7ce5a..dc0c23e1a5d1f84df01045f43d8ec10eddda71e2 100644 (file)
@@ -62,6 +62,9 @@ enum lxcfs_virt_t {
        LXC_TYPE_PROC_LOADAVG,
 #define LXC_TYPE_PROC_LOADAVG_PATH "/proc/loadavg"
 
+       LXC_TYPE_PROC_SLABINFO,
+#define LXC_TYPE_PROC_SLABINFO_PATH "/proc/slabinfo"
+
        LXC_TYPE_SYS_DEVICES,
        LXC_TYPE_SYS_DEVICES_SYSTEM,
        LXC_TYPE_SYS_DEVICES_SYSTEM_CPU,
index d772f257182a909ec1e3fdd2f3e6b2ec5e311a52..f80785f9848f400347390be40182661467550a56 100644 (file)
@@ -632,6 +632,22 @@ static int cgfsng_get_memory_swap_max(struct cgroup_ops *ops,
        return cgfsng_get_memory(ops, cgroup, "memory.swap.max", value);
 }
 
+static int cgfsng_get_memory_slabinfo_fd(struct cgroup_ops *ops, const char *cgroup)
+{
+       __do_free char *path = NULL;
+       struct hierarchy *h;
+
+       h = ops->get_hierarchy(ops, "memory");
+       if (!h)
+               return -1;
+
+       if (faccessat(h->fd, "memory.kmem.slabinfo", F_OK, 0))
+               return -1;
+
+       path = must_make_path_relative(cgroup, "memory.kmem.slabinfo", NULL);
+       return openat(h->fd, path, O_RDONLY | O_CLOEXEC | O_NOFOLLOW);
+}
+
 static bool cgfsng_can_use_swap(struct cgroup_ops *ops)
 {
        bool has_swap = false;
@@ -1021,6 +1037,7 @@ struct cgroup_ops *cgfsng_ops_init(void)
        cgfsng_ops->get_memory_swap_max = cgfsng_get_memory_swap_max;
        cgfsng_ops->get_memory_current = cgfsng_get_memory_current;
        cgfsng_ops->get_memory_swap_current = cgfsng_get_memory_swap_current;
+       cgfsng_ops->get_memory_slabinfo_fd = cgfsng_get_memory_slabinfo_fd;
        cgfsng_ops->can_use_swap = cgfsng_can_use_swap;
 
        /* cpuset */
index f4b5d197b438f3a774b55f247b5386022ab857ca..c9ea370079c2bf3e9cbe0958ec771471f97b48d6 100644 (file)
@@ -152,9 +152,11 @@ struct cgroup_ops {
        int (*get_memory_max)(struct cgroup_ops *ops, const char *cgroup,
                              char **value);
        int (*get_memory_swappiness)(struct cgroup_ops *ops, const char *cgroup,
-                             char **value);
+                                    char **value);
        int (*get_memory_swap_max)(struct cgroup_ops *ops, const char *cgroup,
                                   char **value);
+       int (*get_memory_slabinfo_fd)(struct cgroup_ops *ops,
+                                     const char *cgroup);
        bool (*can_use_swap)(struct cgroup_ops *ops);
 
        /* cpuset */
index 9bf963b78e970b68689253758f5bda075b91dd3f..3cee5260244e725e080ff50e52f18f961825b80c 100644 (file)
@@ -102,7 +102,8 @@ __lxcfs_fuse_ops int proc_getattr(const char *path, struct stat *sb)
            strcmp(path, "/proc/stat")          == 0 ||
            strcmp(path, "/proc/diskstats")     == 0 ||
            strcmp(path, "/proc/swaps")         == 0 ||
-           strcmp(path, "/proc/loadavg")       == 0) {
+           strcmp(path, "/proc/loadavg")       == 0 ||
+           strcmp(path, "/proc/slabinfo")      == 0) {
                sb->st_size = 4096;
                sb->st_mode = S_IFREG | 00444;
                sb->st_nlink = 1;
@@ -124,7 +125,8 @@ __lxcfs_fuse_ops int proc_readdir(const char *path, void *buf,
            DIR_FILLER(filler, buf, "uptime",   NULL, 0) != 0 ||
            DIR_FILLER(filler, buf, "diskstats",        NULL, 0) != 0 ||
            DIR_FILLER(filler, buf, "swaps",    NULL, 0) != 0 ||
-           DIR_FILLER(filler, buf, "loadavg",  NULL, 0) != 0)
+           DIR_FILLER(filler, buf, "loadavg",  NULL, 0) != 0 ||
+           DIR_FILLER(filler, buf, "slabinfo", NULL, 0) != 0)
                return -EINVAL;
 
        return 0;
@@ -166,6 +168,8 @@ __lxcfs_fuse_ops int proc_open(const char *path, struct fuse_file_info *fi)
                type = LXC_TYPE_PROC_SWAPS;
        else if (strcmp(path, "/proc/loadavg") == 0)
                type = LXC_TYPE_PROC_LOADAVG;
+       else if (strcmp(path, "/proc/slabinfo") == 0)
+               type = LXC_TYPE_PROC_SLABINFO;
        if (type == -1)
                return -ENOENT;
 
@@ -1397,6 +1401,75 @@ static int proc_meminfo_read(char *buf, size_t size, off_t offset,
        return total_len;
 }
 
+static int proc_slabinfo_read(char *buf, size_t size, off_t offset,
+                             struct fuse_file_info *fi)
+{
+       __do_free char *cgroup = NULL, *line = NULL;
+       __do_free void *fopen_cache = NULL;
+       __do_fclose FILE *f = NULL;
+       __do_close int fd = -EBADF;
+       struct fuse_context *fc = fuse_get_context();
+       struct file_info *d = INTTYPE_TO_PTR(fi->fh);
+       size_t linelen = 0, total_len = 0;
+       char *cache = d->buf;
+       size_t cache_size = d->buflen;
+       pid_t initpid;
+
+       if (offset) {
+               int left;
+
+               if (offset > d->size)
+                       return -EINVAL;
+
+               if (!d->cached)
+                       return 0;
+
+               left = d->size - offset;
+               total_len = left > size ? size : left;
+               memcpy(buf, cache + offset, total_len);
+
+               return total_len;
+       }
+
+       initpid = lookup_initpid_in_store(fc->pid);
+       if (initpid <= 1 || is_shared_pidns(initpid))
+               initpid = fc->pid;
+
+       cgroup = get_pid_cgroup(initpid, "memory");
+       if (!cgroup)
+               return read_file_fuse("/proc/slabinfo", buf, size, d);
+
+       prune_init_slice(cgroup);
+
+       fd = cgroup_ops->get_memory_slabinfo_fd(cgroup_ops, cgroup);
+       if (fd < 0)
+               return read_file_fuse("/proc/slabinfo", buf, size, d);
+
+       f = fdopen_cached(fd, "re", &fopen_cache);
+       if (!f)
+               return read_file_fuse("/proc/slabinfo", buf, size, d);
+
+       while (getline(&line, &linelen, f) != -1) {
+               ssize_t l = snprintf(cache, cache_size, "%s", line);
+               if (l < 0)
+                       return log_error(0, "Failed to write cache");
+               if (l >= cache_size)
+                       return log_error(0, "Write to cache was truncated");
+
+               cache += l;
+               cache_size -= l;
+               total_len += l;
+       }
+
+       d->cached = 1;
+       d->size = total_len;
+       if (total_len > size)
+               total_len = size;
+       memcpy(buf, d->buf, total_len);
+
+       return total_len;
+}
+
 __lxcfs_fuse_ops int proc_read(const char *path, char *buf, size_t size,
                               off_t offset, struct fuse_file_info *fi)
 {
@@ -1445,6 +1518,12 @@ __lxcfs_fuse_ops int proc_read(const char *path, char *buf, size_t size,
 
                return read_file_fuse_with_offset(LXC_TYPE_PROC_LOADAVG_PATH,
                                                  buf, size, offset, f);
+       case LXC_TYPE_PROC_SLABINFO:
+               if (liblxcfs_functional())
+                       return proc_slabinfo_read(buf, size, offset, fi);
+
+               return read_file_fuse_with_offset(LXC_TYPE_PROC_SLABINFO_PATH,
+                                                 buf, size, offset, f);
        }
 
        return -EINVAL;