[lxc-devel] Add support for /proc/swaps
Teemu Grönqvist
teemu.gronqvist at net9.fi
Mon Feb 8 09:00:29 UTC 2016
Hello,
I was asked to sign off this. Sign off is below.
Just signed on the mailing list so unfortunately I can't answer to the old thread.
----------------------------------------------------------
Built overhttps://github.com/tssge/lxcfs/commit/50b75e3
Example Output:
[root at lxc-dev <http://lists.linuxcontainers.org/listinfo/lxc-devel> ~]# lxc-attach -n ubuntuwily -- /bin/cat /proc/swaps
Filename Type Size Used Priority
none virtual 1048572 1048572 0
Signed-off-by: Teemu Grönqvist <teemu.gronqvist at net9.fi>
Signed-off-by: Nehal J Wani <nehaljw.kkd1 at gmail.com
<http://lists.linuxcontainers.org/listinfo/lxc-devel>>
---
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");
+
+ 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,
+ "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