[lxc-devel] [RFC] Add support for /proc/swaps
Serge Hallyn
serge.hallyn at ubuntu.com
Tue Jan 26 18:45:45 UTC 2016
Quoting Nehal J Wani (nehaljw.kkd1 at gmail.com):
> Built over https://github.com/tssge/lxcfs/commit/50b75e3
>
> Example Output:
>
> [root at lxc-dev ~]# lxc-attach -n ubuntuwily -- /bin/cat /proc/swaps
> Filename Type Size Used Priority
> none virtual 1048572 1048572 0
>
>
> Signed-off-by: Nehal J Wani <nehaljw.kkd1 at gmail.com>
Thanks. I've not had a chance to test this, but will aim to do so this
week. Two comments below, if you like I can fix them up myself when I
apply after I test.
> ---
> lxcfs.c | 118 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
> 1 file changed, 116 insertions(+), 2 deletions(-)
>
> diff --git a/lxcfs.c b/lxcfs.c
> index a561882..9c52862 100644
> --- a/lxcfs.c
> +++ b/lxcfs.c
> @@ -43,6 +43,7 @@ enum {
> LXC_TYPE_PROC_UPTIME,
> LXC_TYPE_PROC_STAT,
> LXC_TYPE_PROC_DISKSTATS,
> + LXC_TYPE_PROC_SWAPS,
> };
>
> struct file_info {
> @@ -2394,6 +2395,113 @@ err:
> return rv;
> }
>
> +static int proc_swaps_read(char *buf, size_t size, off_t offset,
> + struct fuse_file_info *fi)
> +{
> + struct fuse_context *fc = fuse_get_context();
> + struct file_info *d = (struct file_info *)fi->fh;
> + char *cg;
> + char *memswlimit_str = NULL, *memlimit_str = NULL, *memusage_str = NULL, *memswusage_str = NULL,
> + *memswlimit_default_str = NULL, *memswusage_default_str = NULL;
> + unsigned long memswlimit = 0, memlimit = 0, memusage = 0, memswusage = 0, swap_total = 0, swap_free = 0;
> + size_t total_len = 0, rv = 0, linelen = 0;
> + char *cache = d->buf;
> + char *line = NULL;
> + FILE *f = NULL;
> +
> + if (offset) {
> + if (offset > d->size)
> + return -EINVAL;
> + if (!d->cached)
> + return 0;
> + int left = d->size - offset;
> + total_len = left > size ? size: left;
> + memcpy(buf, cache + offset, total_len);
> + return total_len;
> + }
> +
> + cg = get_pid_cgroup(fc->pid, "memory");
This should now find and use the initpid.
> + if (!cg)
> + return read_file("/proc/swaps", buf, size, d);
> +
> + if (!cgfs_get_value("memory", cg, "memory.limit_in_bytes", &memlimit_str))
> + goto err;
> +
> + if (!cgfs_get_value("memory", cg, "memory.usage_in_bytes", &memusage_str))
> + goto err;
> +
> + memlimit = strtoul(memlimit_str, NULL, 10);
> + memusage = strtoul(memusage_str, NULL, 10);
> +
> + if (cgfs_get_value("memory", cg, "memory.memsw.usage_in_bytes", &memswusage_str) &&
> + cgfs_get_value("memory", cg, "memory.memsw.limit_in_bytes", &memswlimit_str)) {
> +
> + /* If swap accounting is turned on, then default value is assumed to be that of cgroup / */
> + if (!cgfs_get_value("memory", "/", "memory.memsw.limit_in_bytes", &memswlimit_default_str))
> + goto err;
> + if (!cgfs_get_value("memory", "/", "memory.memsw.usage_in_bytes", &memswusage_default_str))
> + goto err;
> +
> + memswlimit = strtoul(memswlimit_str, NULL, 10);
> + memswusage = strtoul(memswusage_str, NULL, 10);
> +
> + if (!strcmp(memswlimit_str, memswlimit_default_str))
> + memswlimit = 0;
> + if (!strcmp(memswusage_str, memswusage_default_str))
> + memswusage = 0;
> +
> + swap_total = (memswlimit - memlimit) / 1024;
> + swap_free = (memswusage - memusage) / 1024;
> + }
> +
> + total_len = snprintf(d->buf, d->size, "Filename\t\t\t\tType\t\tSize\tUsed\tPriority\n");
> +
> + /* When no mem + swap limit is specified or swapaccount=0*/
> + if (!memswlimit) {
> + f = fopen("/proc/meminfo", "r");
> + if (!f)
> + goto err;
> +
> + while (getline(&line, &linelen, f) != -1) {
> + if (startswith(line, "SwapTotal:")) {
> + sscanf(line, "SwapTotal: %8lu kB", &swap_total);
> + } else if (startswith(line, "SwapFree:")) {
> + sscanf(line, "SwapFree: %8lu kB", &swap_free);
> + }
> + }
> + }
> +
> + if (swap_total > 0) {
> + total_len += snprintf(d->buf + total_len, d->size,
Shouldn't this be "d->size - total_len" ?
> + "none%*svirtual\t\t%lu\t%lu\t0\n", 36, " ",
> + swap_total, swap_free);
> + }
> +
> + if (total_len < 0) {
> + perror("Error writing to cache");
> + rv = 0;
> + goto err;
> + }
> +
> + d->cached = 1;
> + d->size = (int)total_len;
> +
> + if (total_len > size) total_len = size;
> + memcpy(buf, d->buf, total_len);
> + rv = total_len;
> +
> +err:
> + free(cg);
> + free(memswlimit_str);
> + free(memlimit_str);
> + free(memusage_str);
> + free(memswusage_str);
> + free(memswusage_default_str);
> + free(memswlimit_default_str);
> + return rv;
> +}
> +
> /*
> * Read the cpuset.cpus for cg
> * Return the answer in a newly allocated string which must be freed
> @@ -2956,7 +3064,8 @@ static int proc_getattr(const char *path, struct stat *sb)
> strcmp(path, "/proc/cpuinfo") == 0 ||
> strcmp(path, "/proc/uptime") == 0 ||
> strcmp(path, "/proc/stat") == 0 ||
> - strcmp(path, "/proc/diskstats") == 0) {
> + strcmp(path, "/proc/diskstats") == 0 ||
> + strcmp(path, "/proc/swaps") == 0) {
> sb->st_size = 0;
> sb->st_mode = S_IFREG | 00444;
> sb->st_nlink = 1;
> @@ -2973,7 +3082,8 @@ static int proc_readdir(const char *path, void *buf, fuse_fill_dir_t filler, off
> filler(buf, "meminfo", NULL, 0) != 0 ||
> filler(buf, "stat", NULL, 0) != 0 ||
> filler(buf, "uptime", NULL, 0) != 0 ||
> - filler(buf, "diskstats", NULL, 0) != 0)
> + filler(buf, "diskstats", NULL, 0) != 0 ||
> + filler(buf, "swaps", NULL, 0) != 0)
> return -EINVAL;
> return 0;
> }
> @@ -2993,6 +3103,8 @@ static int proc_open(const char *path, struct fuse_file_info *fi)
> type = LXC_TYPE_PROC_STAT;
> else if (strcmp(path, "/proc/diskstats") == 0)
> type = LXC_TYPE_PROC_DISKSTATS;
> + else if (strcmp(path, "/proc/swaps") == 0)
> + type = LXC_TYPE_PROC_SWAPS;
> if (type == -1)
> return -ENOENT;
>
> @@ -3039,6 +3151,8 @@ static int proc_read(const char *path, char *buf, size_t size, off_t offset,
> return proc_stat_read(buf, size, offset, fi);
> case LXC_TYPE_PROC_DISKSTATS:
> return proc_diskstats_read(buf, size, offset, fi);
> + case LXC_TYPE_PROC_SWAPS:
> + return proc_swaps_read(buf, size, offset, fi);
> default:
> return -EINVAL;
> }
> --
> 2.5.0
>
More information about the lxc-devel
mailing list