[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

[libvirt] [PATCH V8 5/6] make /proc/meminfo isolate with host through fuse



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 cn fujitsu com>
---
 src/lxc/lxc_cgroup.c |  143 ++++++++++++++++++++++++++++++++++++
 src/lxc/lxc_cgroup.h |    3 +-
 src/lxc/lxc_fuse.c   |  195 ++++++++++++++++++++++++++++++++++++++++++++++++--
 src/lxc/lxc_fuse.h   |   14 ++++
 4 files changed, 349 insertions(+), 6 deletions(-)

diff --git a/src/lxc/lxc_cgroup.c b/src/lxc/lxc_cgroup.c
index 9a5ba1a..4c32368 100644
--- a/src/lxc/lxc_cgroup.c
+++ b/src/lxc/lxc_cgroup.c
@@ -23,6 +23,7 @@
 
 #include "lxc_cgroup.h"
 #include "lxc_container.h"
+#include "virfile.h"
 #include "virterror_internal.h"
 #include "logging.h"
 #include "memory.h"
@@ -138,6 +139,148 @@ cleanup:
 }
 
 
+static int virLXCCgroupGetMemSwapUsage(virCgroupPtr cgroup,
+                                       virLXCMeminfoPtr meminfo)
+{
+    return virCgroupGetMemSwapUsage(cgroup, &meminfo->swapusage);
+}
+
+
+static int virLXCCgroupGetMemSwapTotal(virCgroupPtr cgroup,
+                                       virLXCMeminfoPtr meminfo)
+{
+    return virCgroupGetMemSwapHardLimit(cgroup, &meminfo->swaptotal);
+}
+
+
+static int virLXCCgroupGetMemUsage(virCgroupPtr cgroup,
+                                   virLXCMeminfoPtr meminfo)
+{
+    int ret;
+    unsigned long memUsage;
+
+    ret = virCgroupGetMemoryUsage(cgroup, &memUsage);
+    meminfo->memusage = (unsigned long long) memUsage;
+
+    return ret;
+}
+
+
+static int virLXCCgroupGetMemTotal(virCgroupPtr cgroup,
+                                   virLXCMeminfoPtr meminfo)
+{
+    return virCgroupGetMemoryHardLimit(cgroup, &meminfo->memtotal);
+}
+
+
+static int virLXCCgroupGetMemStat(virCgroupPtr cgroup,
+                                  virLXCMeminfoPtr meminfo)
+{
+    int ret = 0;
+    FILE *statfd = NULL;
+    char *statFile = NULL;
+    char *line = NULL;
+    size_t n;
+
+    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 = -errno;
+        goto cleanup;
+    }
+
+    while (getline(&line, &n, statfd) > 0) {
+
+        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 (virStrToLong_ull(value + 1, NULL, 10, &stat_value) < 0) {
+            ret = -EINVAL;
+            goto cleanup;
+        }
+        if (STREQ(line, "cache"))
+            meminfo->cached = stat_value >> 10;
+        else if (STREQ(line, "inactive_anon"))
+            meminfo->inactive_anon = stat_value >> 10;
+        else if (STREQ(line, "active_anon"))
+            meminfo->active_anon = stat_value >> 10;
+        else if (STREQ(line, "inactive_file"))
+            meminfo->inactive_file = stat_value >> 10;
+        else if (STREQ(line, "active_file"))
+            meminfo->active_file = stat_value >> 10;
+        else if (STREQ(line, "unevictable"))
+            meminfo->unevictable = stat_value >> 10;
+    }
+    ret = 0;
+
+cleanup:
+    VIR_FREE(line);
+    VIR_FREE(statFile);
+    VIR_FORCE_FCLOSE(statfd);
+    return ret;
+}
+
+
+int virLXCCgroupGetMeminfo(virLXCMeminfoPtr meminfo)
+{
+    int ret;
+    virCgroupPtr cgroup;
+
+    ret = virCgroupGetAppRoot(&cgroup);
+    if (ret < 0) {
+        virReportSystemError(-ret, "%s",
+                             _("Unable to get cgroup for container"));
+        return ret;
+    }
+
+    ret = virLXCCgroupGetMemStat(cgroup, meminfo);
+    if (ret < 0) {
+        virReportSystemError(-ret, "%s",
+                             _("Unable to get memory cgroup stat info"));
+        goto cleanup;
+    }
+
+    ret = virLXCCgroupGetMemTotal(cgroup, meminfo);
+    if (ret < 0) {
+        virReportSystemError(-ret, "%s",
+                             _("Unable to get memory cgroup total"));
+        goto cleanup;
+    }
+
+    ret = virLXCCgroupGetMemUsage(cgroup, meminfo);
+    if (ret < 0) {
+        virReportSystemError(-ret, "%s",
+                             _("Unable to get memory cgroup stat usage"));
+        goto cleanup;
+    }
+
+    virLXCCgroupGetMemSwapTotal(cgroup, meminfo);
+    virLXCCgroupGetMemSwapUsage(cgroup, meminfo);
+
+    ret = 0;
+cleanup:
+    virCgroupFree(&cgroup);
+    return ret;
+}
+
+
+
 typedef struct _virLXCCgroupDevicePolicy virLXCCgroupDevicePolicy;
 typedef virLXCCgroupDevicePolicy *virLXCCgroupDevicePolicyPtr;
 
diff --git a/src/lxc/lxc_cgroup.h b/src/lxc/lxc_cgroup.h
index 6fc68df..6961943 100644
--- a/src/lxc/lxc_cgroup.h
+++ b/src/lxc/lxc_cgroup.h
@@ -23,7 +23,8 @@
 # define __VIR_LXC_CGROUP_H__
 
 # include "domain_conf.h"
+# include "lxc_fuse.h"
 
 int virLXCCgroupSetup(virDomainDefPtr def);
-
+int virLXCCgroupGetMeminfo(virLXCMeminfoPtr meminfo);
 #endif /* __VIR_LXC_CGROUP_H__ */
diff --git a/src/lxc/lxc_fuse.c b/src/lxc/lxc_fuse.c
index 6d621ee..f667900 100644
--- a/src/lxc/lxc_fuse.c
+++ b/src/lxc/lxc_fuse.c
@@ -30,26 +30,53 @@
 #include <mntent.h>
 
 #include "lxc_fuse.h"
+#include "lxc_cgroup.h"
 #include "virterror_internal.h"
 #include "logging.h"
+#include "virfile.h"
 
 #define VIR_FROM_THIS VIR_FROM_LXC
 
 #if HAVE_FUSE
 
+static const char *fuse_meminfo_path = "/meminfo";
+
 static int lxcProcGetattr(const char *path, struct stat *stbuf)
 {
-    int res = 0;
+    int res;
+    char *mempath = NULL;
+    struct stat sb;
 
     memset(stbuf, 0, sizeof(struct stat));
+    if (virAsprintf(&mempath, "/proc/%s", path) < 0) {
+        virReportOOMError();
+        return -errno;
+    }
+
+    res = 0;
 
     if (STREQ(path, "/")) {
         stbuf->st_mode = S_IFDIR | 0755;
         stbuf->st_nlink = 2;
-    } else {
+    } else if (STREQ(path, fuse_meminfo_path)) {
+        if (stat(mempath, &sb) < 0) {
+            res = -errno;
+            goto cleanup;
+        }
+
+        stbuf->st_mode = sb.st_mode;
+        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;
-    }
 
+cleanup:
+    VIR_FREE(mempath);
     return res;
 }
 
@@ -63,6 +90,7 @@ static int lxcProcReaddir(const char *path, void *buf,
 
     filler(buf, ".", NULL, 0);
     filler(buf, "..", NULL, 0);
+    filler(buf, fuse_meminfo_path + 1, NULL, 0);
 
     return 0;
 }
@@ -70,7 +98,145 @@ static int lxcProcReaddir(const char *path, void *buf,
 static int lxcProcOpen(const char *path ATTRIBUTE_UNUSED,
                        struct fuse_file_info *fi ATTRIBUTE_UNUSED)
 {
-    return -ENOENT;
+    if (!STREQ(path, fuse_meminfo_path))
+        return -ENOENT;
+
+    if ((fi->flags & 3) != O_RDONLY)
+        return -EACCES;
+
+    return 0;
+}
+
+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;
+
+    if ((res = pread(fd, buf, size, offset)) < 0)
+        res = -errno;
+
+    VIR_FORCE_CLOSE(fd);
+    return res;
+}
+
+static int lxcProcReadMeminfo(char *hostpath, virDomainDefPtr def,
+                              char *buf, size_t size, off_t offset)
+{
+    int copied = 0;
+    int res;
+    FILE *fd = NULL;
+    char *line = NULL;
+    size_t n;
+    struct virLXCMeminfo meminfo;
+
+    if ((res = virLXCCgroupGetMeminfo(&meminfo)) < 0)
+        return res;
+
+    fd = fopen(hostpath, "r");
+    if (fd == NULL) {
+        virReportSystemError(errno, _("Cannot open %s"), hostpath);
+        res = errno;
+        goto cleanup;
+    }
+
+    if (fseek(fd, offset, SEEK_SET) < 0) {
+        virReportSystemError(errno, "%s", _("fseek failed"));
+        res = -errno;
+        goto cleanup;
+    }
+
+    while (copied < size && getline(&line, &n, fd) > 0) {
+        int len = 0;
+        char *new_line = NULL;
+        char *ptr = strchr(line, ':');
+        if (ptr) {
+            *ptr = '\0';
+
+            if (STREQ(line, "MemTotal") &&
+                (def->mem.hard_limit || def->mem.max_balloon)) {
+                if (virAsprintf(&new_line, "MemTotal:       %8llu KB\n",
+                                meminfo.memtotal) < 0)
+                    goto no_memory;
+            } else if (STREQ(line, "MemFree") &&
+                       (def->mem.hard_limit || def->mem.max_balloon)) {
+                if (virAsprintf(&new_line, "MemFree:        %8llu KB\n",
+                                (meminfo.memtotal - meminfo.memusage)) < 0)
+                    goto no_memory;
+            } else if (STREQ(line, "Buffers")) {
+                if (virAsprintf(&new_line, "Buffers:        %8d KB\n", 0) < 0)
+                    goto no_memory;
+            } else if (STREQ(line, "Cached")) {
+                if (virAsprintf(&new_line, "Cached:         %8llu KB\n",
+                                meminfo.cached) < 0)
+                    goto no_memory;
+            } else if (STREQ(line, "Active")) {
+                if (virAsprintf(&new_line, "Active:         %8llu KB\n",
+                                (meminfo.active_anon + meminfo.active_file)) < 0)
+                    goto no_memory;
+            } else if (STREQ(line, "Inactive")) {
+                if (virAsprintf(&new_line, "Inactive:       %8llu KB\n",
+                                (meminfo.inactive_anon + meminfo.inactive_file)) < 0)
+                    goto no_memory;
+            } else if (STREQ(line, "Active(anon)")) {
+                if (virAsprintf(&new_line, "Active(anon):   %8llu KB\n",
+                                meminfo.active_anon) < 0)
+                    goto no_memory;
+            } else if (STREQ(line, "Inactive(anon)")) {
+                if (virAsprintf(&new_line, "Inactive(anon): %8llu KB\n",
+                                meminfo.inactive_anon) < 0)
+                    goto no_memory;
+            } else if (STREQ(line, "Active(file)")) {
+                if (virAsprintf(&new_line, "Active(file):   %8llu KB\n",
+                                meminfo.active_file) < 0)
+                    goto no_memory;
+            } else if (STREQ(line, "Inactive(file)")) {
+                if (virAsprintf(&new_line, "Inactive(file): %8llu KB\n",
+                                meminfo.inactive_file) < 0)
+                    goto no_memory;
+            } else if (STREQ(line, "Unevictable")) {
+                if (virAsprintf(&new_line, "Unevictable:    %8llu KB\n",
+                                meminfo.unevictable) < 0)
+                    goto no_memory;
+            } else if (STREQ(line, "SwapTotal") && def->mem.swap_hard_limit) {
+                if (virAsprintf(&new_line, "SwapTotal:      %8llu KB\n",
+                                (meminfo.swaptotal - meminfo.memtotal)) < 0)
+                    goto no_memory;
+            } else if (STREQ(line, "SwapFree") && def->mem.swap_hard_limit) {
+                if (virAsprintf(&new_line, "SwapFree:       %8llu KB\n",
+                                (meminfo.swaptotal - meminfo.memtotal -
+                                meminfo.swapusage + meminfo.memusage)) < 0)
+                    goto no_memory;
+            } else
+                new_line = line;
+
+            *ptr=':';
+        }
+
+        len = strlen(new_line);
+
+        if (copied + len > size)
+            len = size - copied;
+
+        memcpy(buf + copied, new_line, len);
+        copied += len;
+        memset(line, 0, sizeof(line));
+        if (new_line != line)
+            VIR_FREE(new_line);
+    }
+    res = copied;
+
+cleanup:
+    VIR_FORCE_FCLOSE(fd);
+    return res;
+
+no_memory:
+    virReportOOMError();
+    res = -errno;
+    goto cleanup;
 }
 
 static int lxcProcRead(const char *path ATTRIBUTE_UNUSED,
@@ -79,7 +245,26 @@ static int lxcProcRead(const char *path ATTRIBUTE_UNUSED,
                        off_t offset ATTRIBUTE_UNUSED,
                        struct fuse_file_info *fi ATTRIBUTE_UNUSED)
 {
-    return -ENOENT;
+    int res = -ENOENT;
+    char *hostpath = NULL;
+    struct fuse_context *context = NULL;
+    virDomainDefPtr def = NULL;
+
+    if (virAsprintf(&hostpath, "/proc/%s", path) < 0) {
+        virReportOOMError();
+        return -errno;
+    }
+
+    context = fuse_get_context();
+    def = (virDomainDefPtr)context->private_data;
+
+    if (STREQ(path, fuse_meminfo_path)) {
+        if ((res = lxcProcReadMeminfo(hostpath, def, buf, size, offset)) < 0)
+            res = lxcProcHostRead(hostpath, buf, size, offset);
+    }
+
+    VIR_FREE(hostpath);
+    return res;
 }
 
 static struct fuse_operations lxcProcOper = {
diff --git a/src/lxc/lxc_fuse.h b/src/lxc/lxc_fuse.h
index f2d2cbb..93a5373 100644
--- a/src/lxc/lxc_fuse.h
+++ b/src/lxc/lxc_fuse.h
@@ -35,6 +35,20 @@
 #include "util.h"
 #include "memory.h"
 
+struct virLXCMeminfo {
+    unsigned long long memtotal;
+    unsigned long long memusage;
+    unsigned long long cached;
+    unsigned long long active_anon;
+    unsigned long long inactive_anon;
+    unsigned long long active_file;
+    unsigned long long inactive_file;
+    unsigned long long unevictable;
+    unsigned long long swaptotal;
+    unsigned long long swapusage;
+};
+typedef struct virLXCMeminfo *virLXCMeminfoPtr;
+
 struct virLXCFuse {
     virDomainDefPtr def;
     virThread thread;
-- 
1.7.7.6


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]