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 | 106 +++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 133 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..0d60434 100644 --- a/src/lxc/lxc_fuse.c +++ b/src/lxc/lxc_fuse.c @@ -42,6 +42,58 @@ #if WITH_FUSE static const char *fuse_meminfo_path = "/meminfo"; +static const char *fuse_cpuinfo_path = "/cpuinfo"; + +static virBufferPtr lxcProcComputeCpuinfo(void) { + 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 +102,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 +129,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 +173,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 +181,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 +313,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 +355,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); -- 2.1.4 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list