于 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(a)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!