<div class="gmail_quote">2009/9/1 Daniel Lezcano <span dir="ltr"><<a href="mailto:daniel.lezcano@free.fr">daniel.lezcano@free.fr</a>></span><br><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
This patch allows to display information related to the cgroup<br>
in /proc/meminfo.<br>
<br>
It is a first try, there is certainly a clever way to do that but<br>
it is just to play with it.<br>
<br>
Compile with:<br>
<br>
make lxcfs CFLAGS="-D_FILE_OFFSET_BITS=64 -DFUSE_USE_VERSION=27" LDFLAGS="-lfuse"<br>
<br>
Launch a container as root with:<br>
<br>
lxc-execute -n foo /bin/bash<br>
<br>
Set 256MB of memory:<br>
<br>
echo 268435456 > /cgroup/foo/memory.limit_in_bytes<br>
<br>
And finally mount /proc/meminfo:<br>
<br>
./lxcfs -odirect_io /proc/meminfo<br>
<br>
And the results are:<br>
<br>
cat /proc/meminfo:<br>
==================<br>
<br>
MemTotal: 262144 kB<br>
MemFree: 255991 kB<br>
<br>
top:<br>
====<br>
<br>
top - 23:52:17 up 2:43, 2 users, load average: 0.00, 0.00, 0.00<br>
Tasks: 6 total, 1 running, 5 sleeping, 0 stopped, 0 zombie<br>
Cpu(s): 0.0%us, 0.3%sy, 0.0%ni, 99.0%id, 0.0%wa, 0.0%hi, 0.7%si, 0.0<br>
Mem: 262144k total, 6153k used, 255991k free, 0k buffers<br>
Swap: 0k total, 0k used, 0k free, 0k cached<br>
<br>
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND<br>
1 dlezcano 20 0 8136 484 408 S 0.0 0.2 0:00.00 lxc-init<br>
2 dlezcano 20 0 90112 1764 1304 S 0.0 0.7 0:00.08 bash<br>
29 root 20 0 121m 1392 1128 S 0.0 0.5 0:00.05 su<br>
30 root 20 0 89984 1696 1328 S 0.0 0.6 0:00.05 bash<br>
68 root 20 0 37628 888 544 S 0.0 0.3 0:00.00 lxcfs<br>
74 root 20 0 14748 1040 868 R 0.0 0.4 0:00.02 top<br>
<br>
free:<br>
=====<br>
<br>
total used free shared buffers cached<br>
Mem: 262144 6153 255991 0 0 0<br>
-/+ buffers/cache: 6153 255991<br>
<br>
<br>
To be extended ...<br>
<br>
Signed-off-by: Daniel Lezcano <<a href="mailto:daniel.lezcano@free.fr">daniel.lezcano@free.fr</a>><br>
---<br>
lxcfs.c | 217 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++<br>
1 file changed, 217 insertions(+)<br>
<br>
Index: lxcfs/lxcfs.c<br>
===================================================================<br>
--- /dev/null<br>
+++ lxcfs/lxcfs.c<br>
@@ -0,0 +1,217 @@<br>
+#include <fuse.h><br>
+#include <stdio.h><br>
+#include <stdlib.h><br>
+#include <string.h><br>
+#include <errno.h><br>
+#include <mntent.h><br>
+#include <limits.h><br>
+#include <sys/param.h><br>
+<br>
+#define PAGE_SIZE 4096<br>
+#define BUFFER_SIZE 2*PAGE_SIZE<br>
+<br>
+struct cginfo {<br>
+ char *cgpath;<br>
+ char buffer[BUFFER_SIZE];<br>
+ size_t buflen;<br>
+};<br>
+<br>
+struct lxcfs_info {<br>
+ char *name;<br>
+ struct cginfo cginfo;<br>
+};<br>
+<br>
+#ifndef LLONG_MAX<br>
+#define LLONG_MAX 9223372036854775807LL<br>
+#endif<br>
+<br>
+static int lxcfs_getattr(const char *path, struct stat *stbuf)<br>
+{<br>
+ struct fuse_context *context = fuse_get_context();<br>
+<br>
+ memset(stbuf, 0, sizeof(*stbuf));<br>
+<br>
+ stbuf->st_mode = S_IFREG | 0755;<br>
+ stbuf->st_nlink = 2;<br>
+ stbuf->st_uid = context->uid;<br>
+ stbuf->st_gid = context->gid;<br>
+<br>
+ return 0;<br>
+}<br>
+<br>
+static int lxcfs_open(const char *path, struct fuse_file_info *fi)<br>
+{<br>
+ struct fuse_context *context = fuse_get_context();<br>
+ struct lxcfs_info *lxcfs_info = context->private_data;<br>
+ struct cginfo *cginfo = &lxcfs_info->cginfo;<br>
+ char limit_in_bytes[MAXPATHLEN];<br>
+ char usage_in_bytes[MAXPATHLEN];<br>
+<br>
+ FILE *limit_file, *usage_file;<br>
+ long long limit, usage;<br>
+<br>
+ int err;<br>
+<br>
+ snprintf(limit_in_bytes, MAXPATHLEN, "%s/%s/memory.limit_in_bytes",<br>
+ cginfo->cgpath, lxcfs_info->name);<br>
+<br>
+ snprintf(usage_in_bytes, MAXPATHLEN, "%s/%s/memory.usage_in_bytes",<br>
+ cginfo->cgpath, lxcfs_info->name);<br>
+<br>
+ limit_file = fopen(limit_in_bytes, "r");<br>
+ if (!limit_file)<br>
+ return -errno;<br>
+<br>
+ fscanf(limit_file, "%lld", &limit);<br>
+ if (limit == LLONG_MAX)<br>
+ return 0;<br>
+<br>
+ usage_file = fopen(usage_in_bytes, "r");<br>
+ if (!usage_file)<br>
+ goto out_close_limit;<br>
+<br>
+ fscanf(limit_file, "%lld", &limit);<br>
+<br>
+ cginfo->buflen = 0;<br>
+ cginfo->buflen += sprintf(cginfo->buffer, "MemTotal: %lld kB\n", limit >> 10);<br>
+ cginfo->buflen += sprintf(cginfo->buffer + cginfo->buflen,<br>
+ "MemFree: %lld kB\n", (limit - usage) >> 10);<br>
+<br>
+ err = 0;<br>
+out:<br>
+<br>
+ fclose(limit_file);<br>
+ fclose(usage_file);<br>
+<br>
+ return err;<br>
+<br>
+out_close_limit:<br>
+ err = -errno;<br>
+ fclose(limit_file);<br>
+ goto out;<br>
+}<br>
+<br>
+static int lxcfs_read(const char *path, char *buf, size_t size,<br>
+ off_t offset, struct fuse_file_info *fi)<br>
+{<br>
+ struct fuse_context *context = fuse_get_context();<br>
+ struct lxcfs_info *lxcfs_info = context->private_data;<br>
+ struct cginfo *cginfo = &lxcfs_info->cginfo;<br>
+<br>
+ size_t wrote = offset + size > cginfo->buflen ? cginfo->buflen - offset : size;<br>
+<br>
+ memcpy(buf, cginfo->buffer + offset, wrote);<br>
+<br>
+ return wrote;<br>
+}<br>
+<br>
+static int lxcfs_release(const char *path, struct fuse_file_info *fi)<br>
+{<br>
+ return 0;<br>
+}<br>
+<br>
+static int get_cgroup_mount(const char *mtab, char *mnt)<br>
+{<br>
+ struct mntent *mntent;<br>
+ FILE *file = NULL;<br>
+ int err = -1;<br>
+<br>
+ file = setmntent(mtab, "r");<br>
+ if (!file)<br>
+ goto out;<br>
+<br>
+ while ((mntent = getmntent(file))) {<br>
+<br>
+ /* there is a cgroup mounted named "lxc" */<br>
+ if (!strcmp(mntent->mnt_fsname, "lxc") &&<br>
+ !strcmp(mntent->mnt_type, "cgroup")) {<br>
+ strcpy(mnt, mntent->mnt_dir);<br>
+ err = 0;<br>
+ break;<br>
+ }<br>
+<br>
+ /* fallback to the first non-lxc cgroup found */<br>
+ if (!strcmp(mntent->mnt_type, "cgroup") && err) {<br>
+ strcpy(mnt, mntent->mnt_dir);<br>
+ err = 0;<br>
+ }<br>
+ };<br>
+<br>
+ fclose(file);<br>
+out:<br>
+ return err;<br>
+}<br>
+<br>
+static char *cgroup_name(void)<br>
+{<br>
+ char *path = "/proc/self/cgroup", *name;<br>
+ char line[MAXPATHLEN];<br>
+ FILE *file;<br>
+<br>
+ file = fopen(path, "r");<br>
+ if (!file)<br>
+ return NULL;<br>
+<br>
+ fscanf(file, "%s", line);<br>
+<br>
+ strtok(line, ":");<br>
+ strtok(NULL, ":");<br>
+ name = strtok(NULL, ":");<br>
+ name = strtok(name, "/");<br>
+<br>
+ return strdup(name);<br>
+}<br>
+<br>
+static void *lxcfs_init(struct fuse_conn_info *conn)<br>
+{<br>
+ struct lxcfs_info *lxcfs_info;<br>
+<br>
+ lxcfs_info = malloc(sizeof(*lxcfs_info));<br>
+ if (!lxcfs_info)<br>
+ return NULL;<br>
+<br>
+ lxcfs_info->cginfo.cgpath = malloc(MAXPATHLEN);<br>
+ if (!lxcfs_info->cginfo.cgpath)<br>
+ goto out_free_info;<br>
+<br>
+ if (get_cgroup_mount("/etc/mtab", lxcfs_info->cginfo.cgpath))<br>
+ if (get_cgroup_mount("/proc/mounts", lxcfs_info->cginfo.cgpath))<br>
+ goto out_free_cgroup;<br>
+<br>
+ lxcfs_info->name = cgroup_name();<br>
+ if (!lxcfs_info->name)<br>
+ goto out_free_cgroup;<br>
+<br>
+out:<br>
+ return lxcfs_info;<br>
+<br>
+out_free_cgroup:<br>
+ free(lxcfs_info->cginfo.cgpath);<br>
+out_free_info:<br>
+ free(lxcfs_info);<br>
+ lxcfs_info = NULL;<br>
+ goto out;<br>
+}<br>
+<br>
+static void lxcfs_destroy(void *private_data)<br>
+{<br>
+ struct lxcfs_info *lxcfs_info = private_data;<br>
+<br>
+ free(lxcfs_info->cginfo.cgpath);<br>
+ free(lxcfs_info->name);<br>
+ free(lxcfs_info);<br>
+}<br>
+<br>
+static struct fuse_operations lxcfs_ops = {<br>
+ .getattr = lxcfs_getattr,<br>
+ .open = lxcfs_open,<br>
+ .read = lxcfs_read,<br>
+ .release = lxcfs_release,<br>
+ .init = lxcfs_init,<br>
+ .destroy = lxcfs_destroy,<br>
+};<br>
+<br>
+int main(int argc, char *argv[])<br>
+{<br>
+ return fuse_main(argc, argv, &lxcfs_ops, NULL);<br>
+}<br>
<br>
</blockquote></div><br>Great. Let me see.<br>Oh, forgot about memsw? "swap in use" is: memory.memsw.usage_in_bytes - memory.usage_in_bytes. "available swap" is: memory.memsw.limit_in_bytes - memory.limit_in_bytes because memsw is memory + swap.<br>
<br>-- <br>Krzysztof Taraszka<br><br>