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@xxxxxxxxxxxxxx> > --- > 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 :| -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list