From: Feng Sun Date: Thu, 10 Dec 2020 09:30:54 +0000 (+0800) Subject: proc_fuse: add /proc/slabinfo with slab accounting memcg X-Git-Tag: lxcfs-5.0.0~38^2 X-Git-Url: https://git.proxmox.com/?a=commitdiff_plain;h=6cc153e698cc2f8e7cd356d0e6da1f89e8fa984e;p=mirror_lxcfs.git proc_fuse: add /proc/slabinfo with slab accounting memcg Signed-off-by: Feng Sun --- diff --git a/README.md b/README.md index 3c638c3..54d3eab 100644 --- 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 ``` diff --git a/src/api_extensions.h b/src/api_extensions.h index a4ee0c1..9ee55da 100644 --- a/src/api_extensions.h +++ b/src/api_extensions.h @@ -22,6 +22,7 @@ static char *api_extensions[] = { "proc_stat", "proc_swaps", "proc_uptime", + "proc_slabinfo", "shared_pidns", "cpuview_daemon", "loadavg_daemon", diff --git a/src/bindings.h b/src/bindings.h index e260902..dc0c23e 100644 --- a/src/bindings.h +++ b/src/bindings.h @@ -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, diff --git a/src/cgroups/cgfsng.c b/src/cgroups/cgfsng.c index d772f25..f80785f 100644 --- a/src/cgroups/cgfsng.c +++ b/src/cgroups/cgfsng.c @@ -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 */ diff --git a/src/cgroups/cgroup.h b/src/cgroups/cgroup.h index f4b5d19..c9ea370 100644 --- a/src/cgroups/cgroup.h +++ b/src/cgroups/cgroup.h @@ -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 */ diff --git a/src/proc_fuse.c b/src/proc_fuse.c index 9bf963b..3cee526 100644 --- a/src/proc_fuse.c +++ b/src/proc_fuse.c @@ -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;