<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>