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@xxxxxxxxxxxxxx> > --- > 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. Rich. -- Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones libguestfs lets you edit virtual machines. Supports shell scripting, bindings from many languages. http://libguestfs.org -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list