[libvirt] [PATCH] lxc: fuse mount for /proc/cpuinfo
Cedric Bosdonnat
cbosdonnat at suse.com
Wed Sep 2 16:00:20 UTC 2015
Ignore that one, I'll resend another version: I forgot to commit a few
fixes for make check and make syntax-check
--
Cedric
On Wed, 2015-09-02 at 09:54 +0200, Cédric Bosdonnat wrote:
> We already have a fuse mount to reflect the cgroup memory restrictions
> in the container. This commit adds the same for the number of available
> CPUs. Only the CPUs listed by virProcessGetAffinity are shown in the
> container's cpuinfo.
> ---
> src/lxc/lxc_container.c | 42 ++++++++++++-------
> src/lxc/lxc_fuse.c | 109 +++++++++++++++++++++++++++++++++++++++++++++++-
> 2 files changed, 136 insertions(+), 15 deletions(-)
>
> diff --git a/src/lxc/lxc_container.c b/src/lxc/lxc_container.c
> index a433552..7ae13a8 100644
> --- a/src/lxc/lxc_container.c
> +++ b/src/lxc/lxc_container.c
> @@ -1055,24 +1055,38 @@ static int lxcContainerMountProcFuse(virDomainDefPtr def,
> const char *stateDir)
> {
> int ret;
> - char *meminfo_path = NULL;
> + char *src_path = NULL;
> + char *dst_path = NULL;
> + const char *paths[] = {"meminfo", "cpuinfo"};
> + size_t i;
>
> - VIR_DEBUG("Mount /proc/meminfo stateDir=%s", stateDir);
> + for (i = 0; i < 2; i++) {
> + VIR_DEBUG("Mount /proc/%s stateDir=%s", paths[i], stateDir);
> +
> + if ((ret = virAsprintf(&src_path,
> + "/.oldroot/%s/%s.fuse/%s",
> + stateDir,
> + def->name,
> + paths[i])) < 0)
> + return ret;
> +
> + if ((ret = virAsprintf(&dst_path,
> + "/proc/%s",
> + paths[i])) < 0) {
> + VIR_FREE(src_path);
> + return ret;
> + }
>
> - if ((ret = virAsprintf(&meminfo_path,
> - "/.oldroot/%s/%s.fuse/meminfo",
> - stateDir,
> - def->name)) < 0)
> - return ret;
> + if ((ret = mount(src_path, dst_path,
> + NULL, MS_BIND, NULL)) < 0) {
> + virReportSystemError(errno,
> + _("Failed to mount %s on %s"),
> + src_path, dst_path);
> + }
>
> - if ((ret = mount(meminfo_path, "/proc/meminfo",
> - NULL, MS_BIND, NULL)) < 0) {
> - virReportSystemError(errno,
> - _("Failed to mount %s on /proc/meminfo"),
> - meminfo_path);
> + VIR_FREE(src_path);
> + VIR_FREE(dst_path);
> }
> -
> - VIR_FREE(meminfo_path);
> return ret;
> }
> #else
> diff --git a/src/lxc/lxc_fuse.c b/src/lxc/lxc_fuse.c
> index 34a69cc..9c88147 100644
> --- a/src/lxc/lxc_fuse.c
> +++ b/src/lxc/lxc_fuse.c
> @@ -42,6 +42,61 @@
> #if WITH_FUSE
>
> static const char *fuse_meminfo_path = "/meminfo";
> +static const char *fuse_cpuinfo_path = "/cpuinfo";
> +
> +static virBufferPtr lxcProcComputeCpuinfo() {
> + FILE *fd = NULL;
> + char *line = NULL;
> + size_t n;
> + bool writeProc = false;
> + virBuffer buffer = VIR_BUFFER_INITIALIZER;
> + virBufferPtr new_cpuinfo = &buffer;
> + pid_t pid;
> + virBitmapPtr cpuAffinity = NULL;
> +
> + fd = fopen("/proc/cpuinfo", "r");
> + if (fd == NULL) {
> + virReportSystemError(errno, _("%s"), "Cannot open /proc/cpuinfo");
> + goto error;
> + }
> +
> + pid = getpid();
> + if (!(cpuAffinity = virProcessGetAffinity(pid)))
> + goto error;
> +
> + while (getline(&line, &n, fd) > 0) {
> + if (STRPREFIX(line, "processor\t:")) {
> + unsigned long cpuid = 0;
> + char *suffix = NULL;
> + if (virStrToLong_ul(line + 12, &suffix, 10, &cpuid) < 0) {
> + goto error;
> + }
> +
> + if (virBitmapGetBit(cpuAffinity, cpuid, &writeProc) < 0) {
> + goto error;
> + }
> + }
> +
> + if (writeProc) {
> + virBufferAdd(new_cpuinfo, line, -1);
> +
> + if (virBufferCheckError(new_cpuinfo) < 0) {
> + goto error;
> + }
> + }
> + }
> +
> + cleanup:
> + VIR_FREE(line);
> + VIR_FORCE_FCLOSE(fd);
> + virBitmapFree(cpuAffinity);
> + return new_cpuinfo;
> +
> + error:
> + virBufferFreeAndReset(new_cpuinfo);
> + new_cpuinfo = NULL;
> + goto cleanup;
> +}
>
> static int lxcProcGetattr(const char *path, struct stat *stbuf)
> {
> @@ -50,6 +105,7 @@ static int lxcProcGetattr(const char *path, struct stat *stbuf)
> struct stat sb;
> struct fuse_context *context = fuse_get_context();
> virDomainDefPtr def = (virDomainDefPtr)context->private_data;
> + virBufferPtr cpuinfo = NULL;
>
> memset(stbuf, 0, sizeof(struct stat));
> if (virAsprintf(&mempath, "/proc/%s", path) < 0)
> @@ -76,12 +132,36 @@ static int lxcProcGetattr(const char *path, struct stat *stbuf)
> stbuf->st_atime = sb.st_atime;
> stbuf->st_ctime = sb.st_ctime;
> stbuf->st_mtime = sb.st_mtime;
> + } else if (STREQ(path, fuse_cpuinfo_path)) {
> + if (!(cpuinfo = lxcProcComputeCpuinfo())) {
> + res = -EIO;
> + goto cleanup;
> + }
> +
> + if (stat(mempath, &sb) < 0) {
> + res = -errno;
> + goto cleanup;
> + }
> +
> + stbuf->st_uid = def->idmap.uidmap ? def->idmap.uidmap[0].target : 0;
> + stbuf->st_gid = def->idmap.gidmap ? def->idmap.gidmap[0].target : 0;
> + stbuf->st_mode = sb.st_mode;
> + stbuf->st_nlink = 1;
> + stbuf->st_blksize = sb.st_blksize;
> + stbuf->st_size = virBufferUse(cpuinfo);
> + stbuf->st_blocks = stbuf->st_size / 512;
> + if (stbuf->st_size % 512 != 0)
> + stbuf->st_blocks++;
> + 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);
> + virBufferFreeAndReset(cpuinfo);
> return res;
> }
>
> @@ -96,6 +176,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);
> + filler(buf, fuse_cpuinfo_path + 1, NULL, 0);
>
> return 0;
> }
> @@ -103,7 +184,8 @@ static int lxcProcReaddir(const char *path, void *buf,
> static int lxcProcOpen(const char *path ATTRIBUTE_UNUSED,
> struct fuse_file_info *fi ATTRIBUTE_UNUSED)
> {
> - if (!STREQ(path, fuse_meminfo_path))
> + if (!STREQ(path, fuse_meminfo_path) &&
> + !STREQ(path, fuse_cpuinfo_path))
> return -ENOENT;
>
> if ((fi->flags & 3) != O_RDONLY)
> @@ -234,6 +316,28 @@ static int lxcProcReadMeminfo(char *hostpath, virDomainDefPtr def,
> return res;
> }
>
> +static int lxcProcReadCpuinfo(char *buf, size_t size, off_t offset)
> +{
> + virBufferPtr new_cpuinfo = lxcProcComputeCpuinfo();
> + int new_size = -1;
> + int copied = -1;
> +
> + if (!new_cpuinfo)
> + goto error;
> +
> + copied = size;
> + new_size = virBufferUse(new_cpuinfo);
> +
> + if ((new_size - offset) < size)
> + copied = new_size - offset;
> +
> + memcpy(buf, virBufferCurrentContent(new_cpuinfo) + offset, copied);
> +
> + error:
> + virBufferFreeAndReset(new_cpuinfo);
> + return copied;
> +}
> +
> static int lxcProcRead(const char *path ATTRIBUTE_UNUSED,
> char *buf ATTRIBUTE_UNUSED,
> size_t size ATTRIBUTE_UNUSED,
> @@ -254,6 +358,9 @@ static int lxcProcRead(const char *path ATTRIBUTE_UNUSED,
> if (STREQ(path, fuse_meminfo_path)) {
> if ((res = lxcProcReadMeminfo(hostpath, def, buf, size, offset)) < 0)
> res = lxcProcHostRead(hostpath, buf, size, offset);
> + } else if (STREQ(path, fuse_cpuinfo_path)) {
> + if ((res = lxcProcReadCpuinfo(buf, size, offset)) < 0)
> + res = lxcProcHostRead(hostpath, buf, size, offset);
> }
>
> VIR_FREE(hostpath);
More information about the libvir-list
mailing list