[libvirt] [RFC] [PATCH 4/5] make /proc/meminfo isolate with host through fuse

Gao feng gaofeng at cn.fujitsu.com
Wed Jul 11 07:58:22 UTC 2012


with this patch,container's meminfo will be shown based on
containers' mem cgroup.

Right now,it's impossible to virtualize all values in meminfo,
I collect some values such as MemTotal,MemFree,Cached,Active,
Inactive,Active(anon),Inactive(anon),Active(file),Inactive(anon),
Active(file),Inactive(file),Unevictable,SwapTotal,SwapFree.

if I miss something, please let me know.

Signed-off-by: Gao feng <gaofeng at cn.fujitsu.com>
---
 src/lxc/lxc_fuse.c |  340 ++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 files changed, 332 insertions(+), 8 deletions(-)

diff --git a/src/lxc/lxc_fuse.c b/src/lxc/lxc_fuse.c
index 5fdacab..69b4f2e 100644
--- a/src/lxc/lxc_fuse.c
+++ b/src/lxc/lxc_fuse.c
@@ -32,22 +32,52 @@
 #include "lxc_fuse.h"
 #include "util.h"
 #include "memory.h"
+#include "virfile.h"
 
 #define VIR_FROM_THIS VIR_FROM_LXC
 
 #if HAVE_FUSE
+enum {
+    MEMTOTAL,
+    MEMUSAGE,
+    CACHED,
+    ACTIVE_ANON,
+    INACTIVE_ANON,
+    ACTIVE_FILE,
+    INACTIVE_FILE,
+    UNEVICTABLE,
+    SWAPTOTAL,
+    SWAPUSAGE,
+    MEMMAX,
+};
+
+static const char *meminfo_path = "/meminfo";
 
 static int lxcProcGetattr(const char *path, struct stat *stbuf)
 {
     int res = 0;
+    char *mempath = NULL;
+    struct stat sb;
+    virAsprintf(&mempath, "/proc/%s",path);
 
     memset(stbuf, 0, sizeof(struct stat));
     if (strcmp(path, "/") == 0) {
         stbuf->st_mode = S_IFDIR | 0755;
         stbuf->st_nlink = 2;
+    } else if (strcmp(path, meminfo_path) == 0) {
+        stat(mempath, &sb);
+        stbuf->st_mode = S_IFREG | 0444;
+        stbuf->st_nlink = 1;
+        stbuf->st_blksize = sb.st_blksize;
+        stbuf->st_blocks = sb.st_blocks;
+        stbuf->st_size = sb.st_size;
+        stbuf->st_atime = sb.st_atime;
+        stbuf->st_ctime = sb.st_ctime;
+        stbuf->st_mtime = sb.st_mtime;
     } else
         res = -ENOENT;
 
+    VIR_FREE(mempath);
     return res;
 }
 
@@ -61,23 +91,317 @@ static int lxcProcReaddir(const char *path, void *buf,
 
     filler(buf, ".", NULL, 0);
     filler(buf, "..", NULL, 0);
+    filler(buf, meminfo_path + 1, NULL, 0);
 
     return 0;
 }
 
-static int lxcProcOpen(const char *path ATTRIBUTE_UNUSED,
-                       struct fuse_file_info *fi ATTRIBUTE_UNUSED)
+static int lxcProcOpen(const char *path,
+                       struct fuse_file_info *fi)
+{
+    if (strcmp(path, meminfo_path) != 0)
+        return -ENOENT;
+
+    if ((fi->flags & 3) != O_RDONLY)
+        return -EACCES;
+
+    return 0;
+}
+
+static int lxcGetMemCgroupSwapUsage(virCgroupPtr cgroup, unsigned long long *usage)
+{
+    return virCgroupGetMemSwapUsage(cgroup, usage);
+}
+
+static int lxcGetMemCgroupSwapTotal(virCgroupPtr cgroup, unsigned long long *total)
+{
+    return virCgroupGetMemSwapHardLimit(cgroup, total);
+}
+
+static int lxcGetMemCgroupMemUsage(virCgroupPtr cgroup, unsigned long long *usage)
+{
+    int ret;
+    unsigned long memUsage;
+
+    ret = virCgroupGetMemoryUsage(cgroup, &memUsage);
+    *usage = (unsigned long long) memUsage;
+
+    return ret;
+}
+
+static int lxcGetMemCgroupMemTotal(virCgroupPtr cgroup, unsigned long long *total)
 {
-    return -ENOENT;
+    return virCgroupGetMemoryHardLimit(cgroup, total);
 }
 
-static int lxcProcRead(const char *path ATTRIBUTE_UNUSED,
-                       char *buf ATTRIBUTE_UNUSED,
-                       size_t size ATTRIBUTE_UNUSED,
-                       off_t offset ATTRIBUTE_UNUSED,
+static int lxcGetMemCgroupStat(virCgroupPtr cgroup, unsigned long long *meminfo)
+{
+    int ret = 0;
+    FILE *statfd = NULL;
+    char *statFile = NULL;
+    char line[1024];
+
+    ret = virCgroupPathOfController(cgroup, VIR_CGROUP_CONTROLLER_MEMORY,
+                                    "memory.stat", &statFile);
+    if (ret < 0 ) {
+        virReportSystemError(-ret, "%s",
+                             _("cannot get the path of MEMORY cgroup controller"));
+        return ret;
+    }
+
+    statfd = fopen(statFile, "r");
+    if (statfd == NULL) {
+        ret = -ENOENT;
+        goto out_free;
+    }
+
+    while (fgets(line, sizeof(line), statfd) != NULL) {
+        char *value = strchr(line, ' ');
+        char *nl = value ? strchr(line, '\n') : NULL;
+        unsigned long long stat_value;
+
+        if (!value)
+            continue;
+
+        if (nl)
+            *nl = '\0';
+
+        *value = '\0';
+        if (strcmp(line, "cache") == 0) {
+            if ((ret = virStrToLong_ull(value + 1, NULL, 10, &stat_value)) < 0)
+                goto out;
+            meminfo[CACHED] = stat_value >> 10;
+        } else if (strcmp(line, "inactive_anon") == 0) {
+            if ((ret = virStrToLong_ull(value + 1, NULL, 10, &stat_value)) < 0)
+                goto out;
+            meminfo[INACTIVE_ANON] = stat_value >> 10;
+        } else if (strcmp(line, "active_anon") == 0) {
+            if ((ret = virStrToLong_ull(value + 1, NULL, 10, &stat_value)) < 0)
+                goto out;
+            meminfo[ACTIVE_ANON] = stat_value >> 10;
+        } else if (strcmp(line, "inactive_file") == 0) {
+            if ((ret = virStrToLong_ull(value + 1, NULL, 10, &stat_value)) < 0)
+                goto out;
+            meminfo[INACTIVE_FILE] = stat_value >> 10;
+        } else if (strcmp(line, "active_file") == 0) {
+            if ((ret = virStrToLong_ull(value + 1, NULL, 10, &stat_value)) < 0)
+                goto out;
+            meminfo[ACTIVE_FILE] = stat_value >> 10;
+        } else if (strcmp(line, "unevictable") == 0) {
+            if ((ret = virStrToLong_ull(value + 1, NULL, 10, &stat_value)) < 0)
+                goto out;
+            meminfo[UNEVICTABLE] = stat_value >> 10;
+        }
+    }
+    ret = 0;
+out:
+    pclose(statfd);
+out_free:
+    VIR_FREE(statFile);
+    return ret;
+}
+
+static int lxcGetMeminfo(virDomainDefPtr def, unsigned long long *meminfo)
+{
+    int ret;
+    virCgroupPtr driver;
+    virCgroupPtr cgroup;
+
+    ret = virCgroupForDriver("lxc", &driver, 1, 0);
+    if (ret < 0) {
+        virReportSystemError(-ret, "%s",
+                             _("Unable to get cgroup for driver"));
+        return ret;
+    }
+
+    ret = virCgroupForDomain(driver, def->name, &cgroup, 0);
+    if (ret < 0) {
+        virReportSystemError(-ret, "%s",
+                             _("Unable to get cgroup for domain"));
+        goto out_driver;
+    }
+
+    ret = lxcGetMemCgroupStat(cgroup, meminfo);
+    if (ret < 0) {
+        virReportSystemError(-ret, "%s",
+                             _("Unable to get memory cgroup stat info\n"));
+        goto out;
+    }
+
+    ret = lxcGetMemCgroupMemTotal(cgroup, &meminfo[MEMTOTAL]);
+    if (ret < 0) {
+        virReportSystemError(-ret, "%s",
+                             _("Unable to get memory cgroup total\n"));
+        goto out;
+    }
+
+    ret = lxcGetMemCgroupMemUsage(cgroup, &meminfo[MEMUSAGE]);
+    if (ret < 0) {
+        virReportSystemError(-ret, "%s",
+                             _("Unable to get memory cgroup stat usage\n"));
+        goto out;
+    }
+
+    ret = lxcGetMemCgroupSwapTotal(cgroup, &meminfo[SWAPTOTAL]);
+    if (ret < 0) {
+        virReportSystemError(-ret, "%s",
+                             _("Unable to get memory cgroup stat swaptotal\n"));
+        goto out;
+    }
+
+    ret = lxcGetMemCgroupSwapUsage(cgroup, &meminfo[SWAPUSAGE]);
+    if (ret < 0) {
+        virReportSystemError(-ret, "%s",
+                             _("Unable to get memory cgroup stat swapusage\n"));
+        goto out;
+    }
+
+    ret = 0;
+out:
+    virCgroupFree(&cgroup);
+
+out_driver:
+    virCgroupFree(&driver);
+
+    return ret;
+}
+
+static int lxcProcReadMeminfo(char *hostpath, virDomainDefPtr def,
+                              char *buf, size_t size, off_t offset)
+{
+    int res;
+    FILE *fd = NULL;
+    char line[1024];
+    unsigned long long meminfo[MEMMAX];
+
+    if ((res = lxcGetMeminfo(def, meminfo)) < 0) {
+        virReportSystemError(errno, "%s", _("Get Memory Cgroup info failed\n"));
+        return res;
+    }
+
+    fd = fopen(hostpath, "r");
+    if (fd == NULL) {
+        virReportSystemError(errno, "Cannot fopen %s\n", hostpath);
+        res = -errno;
+        goto out;
+    }
+
+    fseek(fd, offset, SEEK_SET);
+
+    while (res < size && fgets(line, sizeof(line), fd) != NULL) {
+        int len = 0;
+        char *new_line = NULL;
+        char *ptr = strchr(line, ':');
+        if (ptr) {
+            *ptr = '\0';
+            new_line = line;
+
+            if (strcmp(line, "MemTotal") == 0  &&
+                (def->mem.hard_limit || def->mem.max_balloon)) {
+                virAsprintf(&new_line, "MemTotal:       %8llu KB\n",
+                            meminfo[MEMTOTAL]);
+            } else if (strcmp(line, "MemFree") == 0 &&
+                       (def->mem.hard_limit || def->mem.max_balloon)) {
+                virAsprintf(&new_line, "MemFree:        %8llu KB\n",
+                            (meminfo[MEMTOTAL] - meminfo[MEMUSAGE]));
+            } else if (strcmp(line, "Buffers") == 0) {
+                virAsprintf(&new_line, "Buffers:        %8d KB\n", 0);
+            } else if (strcmp(line, "Cached") == 0 && meminfo[CACHED]) {
+                virAsprintf(&new_line, "Cached:         %8llu KB\n",
+                            meminfo[CACHED]);
+            } else if (strcmp(line, "Active") == 0 && meminfo[ACTIVE_ANON]) {
+                virAsprintf(&new_line, "Active:         %8llu KB\n",
+                            (meminfo[ACTIVE_ANON] + meminfo[ACTIVE_FILE]));
+            } else if (strcmp(line, "Inactive") == 0 && meminfo[INACTIVE_ANON]) {
+                virAsprintf(&new_line, "Inactive:       %8llu KB\n",
+                            (meminfo[INACTIVE_ANON] + meminfo[INACTIVE_FILE]));
+            } else if (strcmp(line, "Active(anon)") == 0 && meminfo[ACTIVE_ANON]) {
+                virAsprintf(&new_line, "Active(anon):   %8llu KB\n",
+                            meminfo[ACTIVE_ANON]);
+            } else if (strcmp(line, "Inactive(anon)") == 0 && meminfo[INACTIVE_ANON]) {
+                virAsprintf(&new_line, "Inactive(anon): %8llu KB\n",
+                            meminfo[INACTIVE_ANON]);
+            } else if (strcmp(line, "Active(file)") == 0 && meminfo[ACTIVE_FILE]) {
+                virAsprintf(&new_line, "Active(file):   %8llu KB\n",
+                            meminfo[ACTIVE_FILE]);
+            } else if (strcmp(line, "Inactive(file)") == 0 && meminfo[INACTIVE_FILE]) {
+                virAsprintf(&new_line, "Inactive(file): %8llu KB\n",
+                            meminfo[INACTIVE_FILE]);
+            } else if (strcmp(line, "Unevictable") == 0 && meminfo[UNEVICTABLE]) {
+                virAsprintf(&new_line, "Unevictable:    %8llu KB\n",
+                            meminfo[UNEVICTABLE]);
+            } else if (strcmp(line, "SwapTotal") == 0 && def->mem.swap_hard_limit) {
+                virAsprintf(&new_line, "SwapTotal:      %8llu KB\n",
+                            (meminfo[SWAPTOTAL] - meminfo[MEMTOTAL]));
+            } else if (strcmp(line, "SwapFree") == 0 && def->mem.swap_hard_limit) {
+                virAsprintf(&new_line, "SwapFree:       %8llu KB\n",
+                            (meminfo[SWAPTOTAL] - meminfo[MEMTOTAL]
+                            - meminfo[SWAPUSAGE] + meminfo[MEMUSAGE]));
+            }
+            *ptr=':';
+        }
+
+        len = strlen(new_line);
+
+        if (res + len > size)
+            len = size - res;
+
+        memcpy(buf + res, new_line, len);
+        res += len;
+        memset(line, 0, sizeof(line));
+        if (new_line != line)
+            VIR_FREE(new_line);
+    }
+out:
+    VIR_FORCE_FCLOSE(fd);
+    return res;
+}
+
+static int lxcProcHostRead(char *path, char *buf, size_t size, off_t offset)
+{
+    int fd;
+    int res;
+    fd = open(path, O_RDONLY);
+    if (fd == -1)
+        return -errno;
+
+    res = pread(fd, buf, size, offset);
+    if (res == -1)
+        res = -errno;
+    close(fd);
+    return res;
+}
+
+static int lxcProcRead(const char *path,
+                       char *buf,
+                       size_t size,
+                       off_t offset,
                        struct fuse_file_info *fi ATTRIBUTE_UNUSED)
 {
-    return -ENOENT;
+    int res = 0;
+    char *hostpath = NULL;
+    struct fuse_context *context = NULL;
+    virDomainDefPtr def = NULL;
+
+    if ((res = virAsprintf(&hostpath, "/proc/%s", path)) < 0) {
+        virReportSystemError(errno, "%s", _("Cannot get host path\n"));
+        return res;
+    }
+
+    context = fuse_get_context();
+    def = (virDomainDefPtr)context->private_data;
+
+    if (strcmp(path, meminfo_path) == 0) {
+        res = lxcProcReadMeminfo(hostpath, def, buf, size, offset);
+    } else
+        return -ENOENT;
+
+    if (res < 0) {
+        if((res = lxcProcHostRead(hostpath, buf, size, offset)) < 0)
+            virReportSystemError(errno, "%s", _("failed to show host's meminfo\n"));
+    }
+    VIR_FREE(hostpath);
+    return res;
 }
 
 static struct fuse_operations lxcProcOper = {
-- 
1.7.7.6




More information about the libvir-list mailing list