[libvirt] [RFC] [PATCH v3 5/6] make /proc/meminfo isolate with host through fuse
Gao feng
gaofeng at cn.fujitsu.com
Mon Oct 8 00:58:08 UTC 2012
于 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 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
>
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.
More information about the libvir-list
mailing list