于 2012年09月26日 02:45, Daniel P. Berrange 写道: > 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 > Get it,thanks for thanks for telling me this. :) >> + >> + 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 will fix this. -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list