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

Gao feng gaofeng at cn.fujitsu.com
Tue Nov 13 05:52:03 UTC 2012


于 2012年11月12日 20:05, Richard W.M. Jones 写道:
> On Mon, Nov 12, 2012 at 07:52:01PM +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 |  143 ++++++++++++++++++++++++++++++++++++++++
>>  src/lxc/lxc_cgroup.h |    3 +-
>>  src/lxc/lxc_fuse.c   |  178 ++++++++++++++++++++++++++++++++++++++++++++++++--
>>  src/lxc/lxc_fuse.h   |   14 ++++
>>  4 files changed, 332 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..5a514d6 100644
>> --- a/src/lxc/lxc_fuse.c
>> +++ b/src/lxc/lxc_fuse.c
>> @@ -30,26 +30,54 @@
>>  #include <mntent.h>
>>  
>>  #include "lxc_fuse.h"
>> +#include "lxc_cgroup.h"
>>  #include "virterror_internal.h"
>>  #include "logging.h"
>> +#include "virfile.h"
>> +#include "buf.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 +91,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 +99,127 @@ 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;
>> +    virBuffer buffer = VIR_BUFFER_INITIALIZER;
>> +    virBufferPtr new_meminfo = &buffer;
>> +
>> +    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;
>> +    }
>> +
>> +    res = -1;
>> +    while (copied < size && getline(&line, &n, fd) > 0) {
>> +        char *ptr = strchr(line, ':');
>> +        if (ptr) {
>> +            *ptr = '\0';
>> +
>> +            if (STREQ(line, "MemTotal") &&
>> +                (def->mem.hard_limit || def->mem.max_balloon))
>> +                virBufferAsprintf(new_meminfo, "MemTotal:       %8llu KB\n",
>> +                                  meminfo.memtotal);
>> +            else if (STREQ(line, "MemFree") &&
>> +                       (def->mem.hard_limit || def->mem.max_balloon))
>> +                virBufferAsprintf(new_meminfo, "MemFree:        %8llu KB\n",
>> +                                  (meminfo.memtotal - meminfo.memusage));
>> +            else if (STREQ(line, "Buffers"))
>> +                virBufferAsprintf(new_meminfo, "Buffers:        %8d KB\n", 0);
>> +            else if (STREQ(line, "Cached"))
>> +                virBufferAsprintf(new_meminfo, "Cached:         %8llu KB\n",
>> +                                  meminfo.cached);
>> +            else if (STREQ(line, "Active"))
>> +                virBufferAsprintf(new_meminfo, "Active:         %8llu KB\n",
>> +                                  (meminfo.active_anon + meminfo.active_file));
>> +            else if (STREQ(line, "Inactive"))
>> +                virBufferAsprintf(new_meminfo, "Inactive:       %8llu KB\n",
>> +                                  (meminfo.inactive_anon + meminfo.inactive_file));
>> +            else if (STREQ(line, "Active(anon)"))
>> +                virBufferAsprintf(new_meminfo, "Active(anon):   %8llu KB\n",
>> +                                  meminfo.active_anon);
>> +            else if (STREQ(line, "Inactive(anon)"))
>> +                virBufferAsprintf(new_meminfo, "Inactive(anon): %8llu KB\n",
>> +                                  meminfo.inactive_anon);
>> +            else if (STREQ(line, "Active(file)"))
>> +                virBufferAsprintf(new_meminfo, "Active(file):   %8llu KB\n",
>> +                                  meminfo.active_file);
>> +            else if (STREQ(line, "Inactive(file)"))
>> +                virBufferAsprintf(new_meminfo, "Inactive(file): %8llu KB\n",
>> +                                  meminfo.inactive_file);
>> +            else if (STREQ(line, "Unevictable"))
>> +                virBufferAsprintf(new_meminfo, "Unevictable:    %8llu KB\n",
>> +                                  meminfo.unevictable);
>> +            else if (STREQ(line, "SwapTotal") && def->mem.swap_hard_limit)
>> +                virBufferAsprintf(new_meminfo, "SwapTotal:      %8llu KB\n",
>> +                                  (meminfo.swaptotal - meminfo.memtotal));
>> +            else if (STREQ(line, "SwapFree") && def->mem.swap_hard_limit)
>> +                virBufferAsprintf(new_meminfo, "SwapFree:       %8llu KB\n",
>> +                                  (meminfo.swaptotal - meminfo.memtotal -
>> +                                   meminfo.swapusage + meminfo.memusage));
>> +            else {
>> +                *ptr = ':';
>> +                virBufferAdd(new_meminfo, line, -1);
>> +            }
>> +
>> +            if (virBufferError(new_meminfo))
>> +                goto cleanup;
>> +
>> +            copied += strlen(line);
>> +            if (copied > size)
>> +                copied = size;
>> +        }
>> +    }
>> +    res = copied;
>> +    memcpy(buf, virBufferCurrentContent(new_meminfo), copied);
>> +
>> +cleanup:
>> +    VIR_FREE(line);
>> +    virBufferFreeAndReset(new_meminfo);
>> +    VIR_FORCE_FCLOSE(fd);
>> +    return res;
>>  }
>>  
>>  static int lxcProcRead(const char *path ATTRIBUTE_UNUSED,
>> @@ -79,7 +228,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
> 
> This seems better from a pure coding point of view.  I can't
> really comment on whether the code actually works since I'm
> not using LXC over here.
>

Hi Rich

thanks for your help :). with my test,it works well.

without this patchset,in container, the free shows:

sh-4.2# free -l
             total       used       free     shared    buffers     cached
Mem:       5947936    4514904    1433032          0     112688    1931716
Low:       5947936    4514904    1433032
High:            0          0          0
-/+ buffers/cache:    2470500    3477436
Swap:      8191996     273436    7918560

with this patchset applied,in container,the free shows:

sh-4.2# free -l
             total       used       free     shared    buffers     cached
Mem:        102400       4820      97580          0          0       4036
Low:        102400       4820      97580
High:            0          0          0
-/+ buffers/cache:        784     101616
Swap:      8191996     263480    7928516

It works just like what we expect.

Thanks!




More information about the libvir-list mailing list