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

Daniel P. Berrange berrange at redhat.com
Tue Sep 25 18:45:02 UTC 2012


On Tue, Sep 11, 2012 at 10:54:51AM +0800, Gao feng wrote:
> 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_cgroup.c |  151 +++++++++++++++++++++++++++++++++++
>  src/lxc/lxc_cgroup.h |    1 +
>  src/lxc/lxc_fuse.c   |  216 +++++++++++++++++++++++++++++++++++++++++++++++--
>  src/lxc/lxc_fuse.h   |   14 +++
>  4 files changed, 373 insertions(+), 9 deletions(-)
> 
> diff --git a/src/lxc/lxc_cgroup.c b/src/lxc/lxc_cgroup.c
> index aca6309..2fd1b10 100644
> --- a/src/lxc/lxc_cgroup.c
> +++ b/src/lxc/lxc_cgroup.c
> @@ -23,6 +23,8 @@
>  
>  #include "lxc_cgroup.h"
>  #include "lxc_container.h"
> +#include "lxc_fuse.h"
> +#include "virfile.h"
>  #include "virterror_internal.h"
>  #include "logging.h"
>  #include "memory.h"
> @@ -138,6 +140,155 @@ cleanup:
>  }
>  
>  
> +static int virLXCCgroupGetMemSwapUsage(virCgroupPtr cgroup,
> +                                       unsigned long long *usage)
> +{
> +    return virCgroupGetMemSwapUsage(cgroup, usage);
> +}
> +
> +
> +static int virLXCCgroupGetMemSwapTotal(virCgroupPtr cgroup,
> +                                       unsigned long long *total)
> +{
> +    return virCgroupGetMemSwapHardLimit(cgroup, total);
> +}
> +
> +
> +static int virLXCCgroupGetMemUsage(virCgroupPtr cgroup,
> +                                   unsigned long long *usage)
> +{
> +    int ret;
> +    unsigned long memUsage;
> +
> +    ret = virCgroupGetMemoryUsage(cgroup, &memUsage);
> +    *usage = (unsigned long long) memUsage;
> +
> +    return ret;
> +}
> +
> +
> +static int virLXCCgroupGetMemTotal(virCgroupPtr cgroup,
> +                                   unsigned long long *total)
> +{
> +    return virCgroupGetMemoryHardLimit(cgroup, total);
> +}
> +
> +
> +static int virLXCCgroupGetMemStat(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 ((ret = virStrToLong_ull(value + 1, NULL, 10, &stat_value)) < 0)
> +            goto out;
> +
> +        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;
> +out:
> +    VIR_FORCE_FCLOSE(statfd);
> +out_free:
> +    VIR_FREE(statFile);
> +    return ret;
> +}
> +
> +
> +int virLXCCgroupGetMeminfo(unsigned long long *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 out;
> +    }
> +
> +    ret = virLXCCgroupGetMemTotal(cgroup, &meminfo[MEMTOTAL]);
> +    if (ret < 0) {
> +        virReportSystemError(-ret, "%s",
> +                             _("Unable to get memory cgroup total"));
> +        goto out;
> +    }
> +
> +    ret = virLXCCgroupGetMemUsage(cgroup, &meminfo[MEMUSAGE]);
> +    if (ret < 0) {
> +        virReportSystemError(-ret, "%s",
> +                             _("Unable to get memory cgroup stat usage"));
> +        goto out;
> +    }
> +
> +    ret = virLXCCgroupGetMemSwapTotal(cgroup, &meminfo[SWAPTOTAL]);
> +    if (ret < 0) {
> +        virReportSystemError(-ret, "%s",
> +                             _("Unable to get memory cgroup stat swaptotal"));
> +        goto out;
> +    }
> +
> +    ret = virLXCCgroupGetMemSwapUsage(cgroup, &meminfo[SWAPUSAGE]);
> +    if (ret < 0) {
> +        virReportSystemError(-ret, "%s",
> +                             _("Unable to get memory cgroup stat swapusage"));
> +        goto out;
> +    }
> +
> +    ret = 0;
> +out:
> +    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 8ff1015..eccdcba 100644
> --- a/src/lxc/lxc_cgroup.h
> +++ b/src/lxc/lxc_cgroup.h
> @@ -25,5 +25,6 @@
>  # include "domain_conf.h"
>  
>  int virLXCCgroupSetup(virDomainDefPtr def);
> +int virLXCCgroupGetMeminfo(unsigned long long *meminfo);
>  
>  #endif /* __VIR_LXC_CGROUP_H__ */
> diff --git a/src/lxc/lxc_fuse.c b/src/lxc/lxc_fuse.c
> index 868a698..a073e30 100644
> --- a/src/lxc/lxc_fuse.c
> +++ b/src/lxc/lxc_fuse.c
> @@ -29,25 +29,48 @@
>  #include <sys/mount.h>
>  
>  #include "lxc_fuse.h"
> +#include "lxc_cgroup.h"
>  #include "virterror_internal.h"
> +#include "virfile.h"
>  
>  #define VIR_FROM_THIS VIR_FROM_LXC
>  
>  #if HAVE_FUSE
>  
> +static const char *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 ((res = virAsprintf(&mempath, "/proc/%s", path)) < 0) {
> +        virReportOOMError();
> +        return res;
> +    }
> +
> +    res = 0;
>  
>      if (STREQ(path, "/")) {
>          stbuf->st_mode = S_IFDIR | 0755;
>          stbuf->st_nlink = 2;
> +    } else if (STREQ(path, meminfo_path)) {
> +        stat(mempath, &sb);
> +        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;
>      }
>  
> +    VIR_FREE(mempath);
>      return res;
>  }
>  
> @@ -61,23 +84,198 @@ 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 (!STREQ(path, 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)
>  {
> -    return -ENOENT;
> +    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;
> +
> +    VIR_FORCE_CLOSE(fd);
> +    return res;
>  }
>  
> -static int lxcProcRead(const char *path ATTRIBUTE_UNUSED,
> -                       char *buf ATTRIBUTE_UNUSED,
> -                       size_t size ATTRIBUTE_UNUSED,
> -                       off_t offset ATTRIBUTE_UNUSED,
> +static int lxcProcReadMeminfo(char *hostpath, virDomainDefPtr def,
> +                              char *buf, size_t size, off_t offset)
> +{
> +    int copied = 0;
> +    int res = 0;
> +    FILE *fd = NULL;
> +    char line[1024];
> +    unsigned long long meminfo[MEMMAX];
> +    memset(meminfo, 0, sizeof(meminfo));
> +
> +    if ((res = virLXCCgroupGetMeminfo(meminfo)) < 0)
> +        return res;
> +
> +    fd = fopen(hostpath, "r");
> +    if (fd == NULL) {
> +        virReportSystemError(errno, _("Cannot open %s"), hostpath);
> +        res = -errno;
> +        goto out;
> +    }
> +
> +    fseek(fd, offset, SEEK_SET);
> +
> +    while (copied < 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 (STREQ(line, "MemTotal") &&
> +                (def->mem.hard_limit || def->mem.max_balloon)) {
> +                if ((res = virAsprintf(&new_line, "MemTotal:       %8llu KB\n",
> +                                       meminfo[MEMTOTAL])) < 0) {
> +                    goto out_oom;
> +                }
> +            } else if (STREQ(line, "MemFree") &&
> +                       (def->mem.hard_limit || def->mem.max_balloon)) {
> +                if ((res = virAsprintf(&new_line, "MemFree:        %8llu KB\n",
> +                                (meminfo[MEMTOTAL] - meminfo[MEMUSAGE]))) < 0) {
> +                    goto out_oom;
> +                }
> +            } else if (STREQ(line, "Buffers")) {
> +                if ((res = virAsprintf(&new_line, "Buffers:        %8d KB\n", 0)) < 0) {
> +                    goto out_oom;
> +                }
> +            } else if (STREQ(line, "Cached")) {
> +                if ((res = virAsprintf(&new_line, "Cached:         %8llu KB\n",
> +                                       meminfo[CACHED])) < 0) {
> +                    goto out_oom;
> +                }
> +            } else if (STREQ(line, "Active")) {
> +                if ((res = virAsprintf(&new_line, "Active:         %8llu KB\n",
> +                                (meminfo[ACTIVE_ANON] + meminfo[ACTIVE_FILE]))) < 0) {
> +                    goto out_oom;
> +                }
> +            } else if (STREQ(line, "Inactive")) {
> +                if ((res = virAsprintf(&new_line, "Inactive:       %8llu KB\n",
> +                                (meminfo[INACTIVE_ANON] + meminfo[INACTIVE_FILE]))) < 0) {
> +                    goto out_oom;
> +                }
> +            } else if (STREQ(line, "Active(anon)")) {
> +                if ((res = virAsprintf(&new_line, "Active(anon):   %8llu KB\n",
> +                                       meminfo[ACTIVE_ANON])) < 0) {
> +                    goto out_oom;
> +                }
> +            } else if (STREQ(line, "Inactive(anon)")) {
> +                if ((res = virAsprintf(&new_line, "Inactive(anon): %8llu KB\n",
> +                                       meminfo[INACTIVE_ANON])) < 0) {
> +                    goto out_oom;
> +                }
> +            } else if (STREQ(line, "Active(file)")) {
> +                if ((res = virAsprintf(&new_line, "Active(file):   %8llu KB\n",
> +                                       meminfo[ACTIVE_FILE])) < 0) {
> +                    goto out_oom;
> +                }
> +            } else if (STREQ(line, "Inactive(file)")) {
> +                if ((res = virAsprintf(&new_line, "Inactive(file): %8llu KB\n",
> +                                       meminfo[INACTIVE_FILE])) < 0) {
> +                    goto out_oom;
> +                }
> +            } else if (STREQ(line, "Unevictable")) {
> +                if ((res = virAsprintf(&new_line, "Unevictable:    %8llu KB\n",
> +                                       meminfo[UNEVICTABLE])) < 0) {
> +                    goto out_oom;
> +                }
> +            } else if (STREQ(line, "SwapTotal") && def->mem.swap_hard_limit) {
> +                if ((res = virAsprintf(&new_line, "SwapTotal:      %8llu KB\n",
> +                                (meminfo[SWAPTOTAL] - meminfo[MEMTOTAL]))) < 0){
> +                    goto out_oom;
> +                }
> +            } else if (STREQ(line, "SwapFree") && def->mem.swap_hard_limit) {
> +                if ((res = virAsprintf(&new_line, "SwapFree:       %8llu KB\n",
> +                            (meminfo[SWAPTOTAL] - meminfo[MEMTOTAL] -
> +                            meminfo[SWAPUSAGE] + meminfo[MEMUSAGE]))) < 0) {
> +                    goto out_oom;
> +                }
> +            }
> +            *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;
> +
> +out:
> +    VIR_FORCE_FCLOSE(fd);
> +    return res;
> +
> +out_oom:
> +    virReportOOMError();
> +    goto out;
> +}
> +
> +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) {
> +        virReportOOMError();
> +        return res;
> +    }
> +
> +    context = fuse_get_context();
> +    def = (virDomainDefPtr)context->private_data;
> +
> +    if (STREQ(path, meminfo_path)) {
> +        res = lxcProcReadMeminfo(hostpath, def, buf, size, offset);
> +    } else {
> +        res = -ENOENT;
> +        goto out;
> +    }

The second branch suggests that we should be returning errno values
upon failure. At least one code path in lxcProcReadMeminfo instead
returns simply -1. This code should all use normal libvirt error
reporting APIs and return -1 on error. Then right at the end of this
method, if res == -1, then use virGetLastError() to fetch any
virErrorPtr object. If the code == VIR_ERR_SYSTEM_ERROR then you
can get the errno value from the 'int1' field in virErrorPtr.
Otherwise you can just use EIO

> +
> +    if (res < 0) {
> +        if((res = lxcProcHostRead(hostpath, buf, size, offset)) < 0)
> +            virReportSystemError(errno, "%s",
> +                                 _("failed to show host's meminfo"));
> +    }
> +
> +out:
> +    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 d60c238..7db534b 100644
> --- a/src/lxc/lxc_fuse.h
> +++ b/src/lxc/lxc_fuse.h
> @@ -35,6 +35,20 @@
>  #include "util.h"
>  #include "memory.h"
>  
> +enum {
> +    MEMTOTAL,
> +    MEMUSAGE,
> +    CACHED,
> +    ACTIVE_ANON,
> +    INACTIVE_ANON,
> +    ACTIVE_FILE,
> +    INACTIVE_FILE,
> +    UNEVICTABLE,
> +    SWAPTOTAL,
> +    SWAPUSAGE,
> +    MEMMAX,
> +};

Please use a prefix on any constants, ie  VIR_LXC_FUSE_MEMTOTAL

Daniel
-- 
|: http://berrange.com      -o-    http://www.flickr.com/photos/dberrange/ :|
|: http://libvirt.org              -o-             http://virt-manager.org :|
|: http://autobuild.org       -o-         http://search.cpan.org/~danberr/ :|
|: http://entangle-photo.org       -o-       http://live.gnome.org/gtk-vnc :|




More information about the libvir-list mailing list