[libvirt] [PATCH v4 1/6] add a configure option --with-fuse to prepare introduction of fuse support for libvirt lxc

add a configure option --with-fuse to prepare introduction of fuse support for libvirt lxc. With help from Daniel Signed-off-by: Gao feng <gaofeng@cn.fujitsu.com> --- configure.ac | 36 ++++++++++++++++++++++++++++++++++++ libvirt.spec.in | 9 +++++++++ 2 files changed, 45 insertions(+), 0 deletions(-) diff --git a/configure.ac b/configure.ac index 08dc63d..0bd0297 100644 --- a/configure.ac +++ b/configure.ac @@ -115,6 +115,7 @@ LIBSSH2_REQUIRED="1.0" LIBSSH2_TRANSPORT_REQUIRED="1.3" LIBBLKID_REQUIRED="2.17" DBUS_REQUIRED="1.0.0" +FUSE_REQUIRED="2.8.6" dnl Checks for C compiler. AC_PROG_CC @@ -1850,6 +1851,36 @@ AC_SUBST([CAPNG_CFLAGS]) AC_SUBST([CAPNG_LIBS]) +dnl libfuse +AC_ARG_WITH([fuse], + AC_HELP_STRING([--with-fuse], [use libfuse to proivde fuse filesystem support for libvirt lxc]), + [], + [with_fuse=check]) +dnl +dnl This check looks for 'fuse' +dnl +FUSE_CFLAGS= +FUSE_LIBS= +if test "x$with_fuse" != "xno"; then + PKG_CHECK_MODULES([FUSE], [fuse >= $FUSE_REQUIRED], + [with_fuse=yes], [ + if test "x$with_fuse" = "xcheck" ; then + with_fuse=no + else + AC_MSG_ERROR( + [You must install fuse Library to compile libvirt]) + fi + ]) + if test "x$with_fuse" = "xyes" ; then + FUSE_LIBS="-lfuse" + FUSE_CFLAGS="-D_FILE_OFFSET_BITS=64" + AC_DEFINE_UNQUOTED([HAVE_FUSE], 1, [whether fuse is available for libvirt lxc]) + fi +fi +AM_CONDITIONAL([HAVE_FUSE], [test "x$with_fuse" = "xyes"]) +AC_SUBST([FUSE_CFLAGS]) +AC_SUBST([FUSE_LIBS]) + dnl virsh libraries AC_CHECK_HEADERS([readline/readline.h]) @@ -3154,6 +3185,11 @@ AC_MSG_NOTICE([ capng: $CAPNG_CFLAGS $CAPNG_LIBS]) else AC_MSG_NOTICE([ capng: no]) fi +if test "$with_fuse" = "yes" ; then +AC_MSG_NOTICE([ fuse: $FUSE_CFLAGS $FUSE_LIBS]) +else +AC_MSG_NOTICE([ fuse: no]) +fi if test "$with_xen" = "yes" ; then AC_MSG_NOTICE([ xen: $XEN_CFLAGS $XEN_LIBS]) else diff --git a/libvirt.spec.in b/libvirt.spec.in index 75623eb..157825b 100644 --- a/libvirt.spec.in +++ b/libvirt.spec.in @@ -93,6 +93,7 @@ # A few optional bits off by default, we enable later %define with_polkit 0%{!?_without_polkit:0} %define with_capng 0%{!?_without_capng:0} +%define with_fuse 0%{!?_without_fuse:0} %define with_netcf 0%{!?_without_netcf:0} %define with_udev 0%{!?_without_udev:0} %define with_hal 0%{!?_without_hal:0} @@ -497,6 +498,9 @@ BuildRequires: numactl-devel %if %{with_capng} BuildRequires: libcap-ng-devel >= 0.5.0 %endif +%if %{with_fuse} +BuildRequires: fuse-devel >= 2.8.6 +%endif %if %{with_phyp} || %{with_libssh2_transport} %if %{with_libssh2_transport} BuildRequires: libssh2-devel >= 1.3.0 @@ -1172,6 +1176,10 @@ of recent versions of Linux (and other OSes). %define _without_capng --without-capng %endif +%if ! %{with_fuse} +%define _without_fuse --without-fuse +%endif + %if ! %{with_netcf} %define _without_netcf --without-netcf %endif @@ -1275,6 +1283,7 @@ autoreconf -if %{?_without_numactl} \ %{?_without_numad} \ %{?_without_capng} \ + %{?_without_fuse} \ %{?_without_netcf} \ %{?_without_selinux} \ %{?_with_selinux_mount} \ -- 1.7.7.6

this patch addes fuse support for libvirt lxc. we can use fuse filesystem to generate sysinfo dynamically, So we can isolate /proc/meminfo,cpuinfo and so on through fuse filesystem. we mount fuse filesystem for every container.the mount name is Lxc-containename-fuse,mount point is localstatedir/run/libvirt/lxc/containername. Signed-off-by: Gao feng <gaofeng@cn.fujitsu.com> --- po/POTFILES.in | 1 + src/Makefile.am | 9 ++- src/lxc/lxc_controller.c | 11 ++++ src/lxc/lxc_fuse.c | 151 ++++++++++++++++++++++++++++++++++++++++++++++ src/lxc/lxc_fuse.h | 40 ++++++++++++ src/lxc/lxc_process.c | 2 + 6 files changed, 212 insertions(+), 2 deletions(-) create mode 100644 src/lxc/lxc_fuse.c create mode 100644 src/lxc/lxc_fuse.h diff --git a/po/POTFILES.in b/po/POTFILES.in index 815e992..35b54c0 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -49,6 +49,7 @@ src/locking/lock_driver_sanlock.c src/locking/lock_manager.c src/locking/sanlock_helper.c src/lxc/lxc_cgroup.c +src/lxc/lxc_fuse.c src/lxc/lxc_container.c src/lxc/lxc_conf.c src/lxc/lxc_controller.c diff --git a/src/Makefile.am b/src/Makefile.am index 4f19bcf..bd2b73c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -412,6 +412,7 @@ LXC_DRIVER_SOURCES = \ lxc/lxc_domain.c lxc/lxc_domain.h \ lxc/lxc_monitor.c lxc/lxc_monitor.h \ lxc/lxc_process.c lxc/lxc_process.h \ + lxc/lxc_fuse.c lxc/lxc_fuse.h \ lxc/lxc_driver.c lxc/lxc_driver.h LXC_CONTROLLER_SOURCES = \ @@ -420,6 +421,7 @@ LXC_CONTROLLER_SOURCES = \ lxc/lxc_conf.c lxc/lxc_conf.h \ lxc/lxc_container.c lxc/lxc_container.h \ lxc/lxc_cgroup.c lxc/lxc_cgroup.h \ + lxc/lxc_fuse.c lxc/lxc_fuse.h \ lxc/lxc_controller.c SECURITY_DRIVER_APPARMOR_HELPER_SOURCES = \ @@ -910,8 +912,9 @@ endif libvirt_driver_lxc_impl_la_CFLAGS = \ $(LIBNL_CFLAGS) \ + $(FUSE_CFLAGS) \ -I$(top_srcdir)/src/conf $(AM_CFLAGS) -libvirt_driver_lxc_impl_la_LIBADD = $(CAPNG_LIBS) $(LIBNL_LIBS) +libvirt_driver_lxc_impl_la_LIBADD = $(CAPNG_LIBS) $(LIBNL_LIBS) $(FUSE_LIBS) if HAVE_LIBBLKID libvirt_driver_lxc_impl_la_CFLAGS += $(BLKID_CFLAGS) libvirt_driver_lxc_impl_la_LIBADD += $(BLKID_LIBS) @@ -1671,6 +1674,7 @@ libvirt_lxc_SOURCES = \ libvirt_lxc_LDFLAGS = $(WARN_CFLAGS) $(AM_LDFLAGS) libvirt_lxc_LDADD = \ $(NUMACTL_LIBS) \ + $(FUSE_LIBS) \ libvirt-net-rpc-server.la \ libvirt-net-rpc.la \ libvirt_security_manager.la \ @@ -1689,7 +1693,8 @@ endif libvirt_lxc_CFLAGS = \ -I$(top_srcdir)/src/conf \ $(AM_CFLAGS) \ - $(LIBNL_CFLAGS) + $(LIBNL_CFLAGS) \ + $(FUSE_CFLAGS) if HAVE_LIBBLKID libvirt_lxc_CFLAGS += $(BLKID_CFLAGS) libvirt_lxc_LDADD += $(BLKID_LIBS) diff --git a/src/lxc/lxc_controller.c b/src/lxc/lxc_controller.c index 68f857a..85ad90a 100644 --- a/src/lxc/lxc_controller.c +++ b/src/lxc/lxc_controller.c @@ -60,6 +60,7 @@ #include "lxc_container.h" #include "lxc_cgroup.h" #include "lxc_protocol.h" +#include "lxc_fuse.h" #include "virnetdev.h" #include "virnetdevveth.h" #include "memory.h" @@ -1464,6 +1465,7 @@ int main(int argc, char *argv[]) char *name = NULL; size_t nveths = 0; char **veths = NULL; + virThread thread; int handshakeFd = -1; int bg = 0; const struct option options[] = { @@ -1650,6 +1652,15 @@ int main(int argc, char *argv[]) } } + rc = virThreadCreate(&thread, true, lxcRegisterFuse, + (void *)ctrl->def); + if (rc < 0) { + virReportSystemError(-rc, "%s", + _("Create Fuse filesystem failed")); + goto cleanup; + } + + rc = virLXCControllerRun(ctrl); cleanup: diff --git a/src/lxc/lxc_fuse.c b/src/lxc/lxc_fuse.c new file mode 100644 index 0000000..164897e --- /dev/null +++ b/src/lxc/lxc_fuse.c @@ -0,0 +1,151 @@ +/* + * Copyright (C) 2012 Fujitsu Limited. + * + * lxc_fuse.c: fuse filesystem support for libvirt lxc + * + * Authors: + * Gao feng <gaofeng at cn.fujitsu.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <config.h> +#include <fcntl.h> +#include <stdio.h> +#include <errno.h> +#include <string.h> +#include <sys/mount.h> + +#include "lxc_fuse.h" +#include "virterror_internal.h" + +#define VIR_FROM_THIS VIR_FROM_LXC + +#if HAVE_FUSE + +static int lxcProcGetattr(const char *path, struct stat *stbuf) +{ + int res = 0; + + memset(stbuf, 0, sizeof(struct stat)); + + if (STREQ(path, "/")) { + stbuf->st_mode = S_IFDIR | 0755; + stbuf->st_nlink = 2; + } else { + res = -ENOENT; + } + + return res; +} + +static int lxcProcReaddir(const char *path, void *buf, + fuse_fill_dir_t filler, + off_t offset ATTRIBUTE_UNUSED, + struct fuse_file_info *fi ATTRIBUTE_UNUSED) +{ + if (!STREQ(path, "/")) + return -ENOENT; + + filler(buf, ".", NULL, 0); + filler(buf, "..", NULL, 0); + + return 0; +} + +static int lxcProcOpen(const char *path ATTRIBUTE_UNUSED, + struct fuse_file_info *fi ATTRIBUTE_UNUSED) +{ + return -ENOENT; +} + +static int lxcProcRead(const char *path ATTRIBUTE_UNUSED, + char *buf ATTRIBUTE_UNUSED, + size_t size ATTRIBUTE_UNUSED, + off_t offset ATTRIBUTE_UNUSED, + struct fuse_file_info *fi ATTRIBUTE_UNUSED) +{ + return -ENOENT; +} + +static struct fuse_operations lxcProcOper = { + .getattr = lxcProcGetattr, + .readdir = lxcProcReaddir, + .open = lxcProcOpen, + .read = lxcProcRead, +}; + +void lxcRegisterFuse(void *opaque) +{ + int argc = 4; + char *argv[argc]; + char *path = NULL; + char *name = NULL; + virDomainDefPtr DomainDef = (virDomainDefPtr) opaque; + + if (virAsprintf(&name, "Lxc-%s-fuse", DomainDef->name) < 0) { + virReportOOMError(); + goto cleanup; + } + + if (virAsprintf(&path, "%s/%s/", LXC_STATE_DIR, DomainDef->name) < 0) { + virReportOOMError(); + goto cleanup; + } + + if (virFileMakePath(path) < 0) { + virReportSystemError(errno, _("Cannot create %s"), path); + goto cleanup; + } + + argv[0] = name; + argv[1] = path; + argv[2] = (char *)"-odirect_io"; + argv[3] = (char *)"-f"; + + if (fuse_main(argc, argv, &lxcProcOper, DomainDef) < 0) + virReportSystemError(errno, "%s", _("Cannot start fuse")); + +cleanup: + VIR_FREE(name); + VIR_FREE(path); + return; +} + +void lxcUnregisterFuse(virDomainDefPtr def) +{ + char *path = NULL; + + if (virAsprintf(&path, "%s/%s/", LXC_STATE_DIR, def->name) < 0) { + virReportOOMError(); + return; + } + + if (umount(path) < 0) + virReportSystemError(errno, "%s", + _("umount fuse filesystem failed")); + + VIR_FREE(path); +} + +#else +void lxcRegisterFuse(void *opaque ATTRIBUTE_UNUSED) +{ +} + +void lxcUnregisterFuse(virDomainDefPtr def ATTRIBUTE_UNUSED) +{ +} +#endif diff --git a/src/lxc/lxc_fuse.h b/src/lxc/lxc_fuse.h new file mode 100644 index 0000000..d188190 --- /dev/null +++ b/src/lxc/lxc_fuse.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2012 Fujitsu Limited. + * + * lxc_fuse.c: fuse filesystem support for libvirt lxc + * + * Authors: + * Gao feng <gaofeng at cn.fujitsu.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef LXC_FUSE_H +#define LXC_FUSE_H + +#define FUSE_USE_VERSION 26 + +#include <config.h> +#if HAVE_FUSE +#include <fuse.h> +#endif + +#include "lxc_conf.h" +#include "util.h" +#include "memory.h" + +extern void lxcRegisterFuse(void *opaque); +extern void lxcUnregisterFuse(virDomainDefPtr def); +#endif diff --git a/src/lxc/lxc_process.c b/src/lxc/lxc_process.c index 079bc3a..1e972fb 100644 --- a/src/lxc/lxc_process.c +++ b/src/lxc/lxc_process.c @@ -28,6 +28,7 @@ #include "lxc_process.h" #include "lxc_domain.h" #include "lxc_container.h" +#include "lxc_fuse.h" #include "datatypes.h" #include "virfile.h" #include "virpidfile.h" @@ -235,6 +236,7 @@ static void virLXCProcessCleanup(virLXCDriverPtr driver, VIR_FREE(xml); } + lxcUnregisterFuse(vm->def); /* Stop autodestroy in case guest is restarted */ virLXCProcessAutoDestroyRemove(driver, vm); -- 1.7.7.6

virCgroupGetMemSwapUsage is used to get container's swap usage, with this interface,we can get swap usage in fuse filesystem. Signed-off-by: Gao feng <gaofeng@cn.fujitsu.com> --- src/libvirt_private.syms | 1 + src/util/cgroup.c | 20 ++++++++++++++++++++ src/util/cgroup.h | 1 + 3 files changed, 22 insertions(+), 0 deletions(-) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 0bd5a12..cfec5ed 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -97,6 +97,7 @@ virCgroupGetCpuacctUsage; virCgroupGetCpusetCpus; virCgroupGetCpusetMems; virCgroupGetFreezerState; +virCgroupGetMemSwapUsage; virCgroupGetMemSwapHardLimit; virCgroupGetMemoryHardLimit; virCgroupGetMemorySoftLimit; diff --git a/src/util/cgroup.c b/src/util/cgroup.c index 3f7b5f7..4aae70d 100644 --- a/src/util/cgroup.c +++ b/src/util/cgroup.c @@ -1371,6 +1371,26 @@ int virCgroupGetMemSwapHardLimit(virCgroupPtr group, unsigned long long *kb) } /** + * virCgroupGetMemSwapUsage: + * + * @group: The cgroup to get mem+swap usage for + * @kb: The mem+swap amount in kilobytes + * + * Returns: 0 on success + */ +int virCgroupGetMemSwapUsage(virCgroupPtr group, unsigned long long *kb) +{ + long long unsigned int usage_in_bytes; + int ret; + ret = virCgroupGetValueU64(group, + VIR_CGROUP_CONTROLLER_MEMORY, + "memory.memsw.usage_in_bytes", &usage_in_bytes); + if (ret == 0) + *kb = usage_in_bytes >> 10; + return ret; +} + +/** * virCgroupSetCpusetMems: * * @group: The cgroup to set cpuset.mems for diff --git a/src/util/cgroup.h b/src/util/cgroup.h index 38fa4b7..0c11eb1 100644 --- a/src/util/cgroup.h +++ b/src/util/cgroup.h @@ -92,6 +92,7 @@ int virCgroupSetMemorySoftLimit(virCgroupPtr group, unsigned long long kb); int virCgroupGetMemorySoftLimit(virCgroupPtr group, unsigned long long *kb); int virCgroupSetMemSwapHardLimit(virCgroupPtr group, unsigned long long kb); int virCgroupGetMemSwapHardLimit(virCgroupPtr group, unsigned long long *kb); +int virCgroupGetMemSwapUsage(virCgroupPtr group, unsigned long long *kb); enum { VIR_CGROUP_DEVICE_READ = 1, -- 1.7.7.6

because libvirt_lxc's cgroup mountpoint is what it shown in /proc/self/cgroup. we can get container's cgroup through virCgroupNew("/", &group), add interface virCgroupGetAppRoot to help container to get it's cgroup. Signed-off-by: Gao feng <gaofeng@cn.fujitsu.com> --- src/libvirt_private.syms | 1 + src/util/cgroup.c | 15 +++++++++++++++ src/util/cgroup.h | 2 ++ 3 files changed, 18 insertions(+), 0 deletions(-) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index cfec5ed..1b5437c 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -84,6 +84,7 @@ virCgroupDenyDeviceMajor; virCgroupDenyDevicePath; virCgroupForDomain; virCgroupForDriver; +virCgroupGetAppRoot; virCgroupForEmulator; virCgroupForVcpu; virCgroupFree; diff --git a/src/util/cgroup.c b/src/util/cgroup.c index 4aae70d..9777ad5 100644 --- a/src/util/cgroup.c +++ b/src/util/cgroup.c @@ -965,6 +965,21 @@ int virCgroupForDriver(const char *name ATTRIBUTE_UNUSED, } #endif +/** +* virCgroupGetAppRoot: +* +* @group: Pointer to returned virCgroupPtr +* +* Returns 0 on success +*/ +int virCgroupGetAppRoot(virCgroupPtr *group) +{ +#if defined HAVE_MNTENT_H && defined HAVE_GETMNTENT_R + return virCgroupNew("/", group); +#else + return -ENXIO; +#endif +} /** * virCgroupForDomain: diff --git a/src/util/cgroup.h b/src/util/cgroup.h index 0c11eb1..e26f65f 100644 --- a/src/util/cgroup.h +++ b/src/util/cgroup.h @@ -47,6 +47,8 @@ int virCgroupForDriver(const char *name, int privileged, int create); +int virCgroupGetAppRoot(virCgroupPtr *group); + int virCgroupForDomain(virCgroupPtr driver, const char *name, virCgroupPtr *group, -- 1.7.7.6

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@cn.fujitsu.com> --- src/lxc/lxc_cgroup.c | 139 +++++++++++++++++++++++++++++++++ src/lxc/lxc_cgroup.h | 1 + src/lxc/lxc_fuse.c | 209 +++++++++++++++++++++++++++++++++++++++++++++++-- src/lxc/lxc_fuse.h | 14 ++++ 4 files changed, 354 insertions(+), 9 deletions(-) diff --git a/src/lxc/lxc_cgroup.c b/src/lxc/lxc_cgroup.c index bdfaa54..1e3a318 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" @@ -137,6 +139,143 @@ cleanup: return ret; } +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 = -errno; + 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 (virStrToLong_ull(value + 1, NULL, 10, &stat_value) < 0) { + ret = -EINVAL; + goto out; + } + if (STREQ(line, "cache")) + meminfo[VIR_LXC_FUSE_CACHED] = stat_value >> 10; + else if (STREQ(line, "inactive_anon")) + meminfo[VIR_LXC_FUSE_INACTIVE_ANON] = stat_value >> 10; + else if (STREQ(line, "active_anon")) + meminfo[VIR_LXC_FUSE_ACTIVE_ANON] = stat_value >> 10; + else if (STREQ(line, "inactive_file")) + meminfo[VIR_LXC_FUSE_INACTIVE_FILE] = stat_value >> 10; + else if (STREQ(line, "active_file")) + meminfo[VIR_LXC_FUSE_ACTIVE_FILE] = stat_value >> 10; + else if (STREQ(line, "unevictable")) + meminfo[VIR_LXC_FUSE_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[VIR_LXC_FUSE_MEMTOTAL]); + if (ret < 0) { + virReportSystemError(-ret, "%s", + _("Unable to get memory cgroup total")); + goto out; + } + + ret = virLXCCgroupGetMemUsage(cgroup, &meminfo[VIR_LXC_FUSE_MEMUSAGE]); + if (ret < 0) { + virReportSystemError(-ret, "%s", + _("Unable to get memory cgroup stat usage")); + goto out; + } + + virLXCCgroupGetMemSwapTotal(cgroup, &meminfo[VIR_LXC_FUSE_SWAPTOTAL]); + virLXCCgroupGetMemSwapUsage(cgroup, &meminfo[VIR_LXC_FUSE_SWAPUSAGE]); + + 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 6fc68df..c549d6c 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 164897e..0deaf57 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 *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 if (STREQ(path, fuse_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,191 @@ 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; } -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, 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) { - return -ENOENT; + int copied = 0; + int res; + FILE *fd = NULL; + char line[1024]; + unsigned long long meminfo[VIR_LXC_FUSE_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 (virAsprintf(&new_line, "MemTotal: %8llu KB\n", + meminfo[VIR_LXC_FUSE_MEMTOTAL]) < 0) { + goto out_oom; + } + } else if (STREQ(line, "MemFree") && + (def->mem.hard_limit || def->mem.max_balloon)) { + if (virAsprintf(&new_line, "MemFree: %8llu KB\n", + (meminfo[VIR_LXC_FUSE_MEMTOTAL] - meminfo[VIR_LXC_FUSE_MEMUSAGE])) < 0) { + goto out_oom; + } + } else if (STREQ(line, "Buffers")) { + if (virAsprintf(&new_line, "Buffers: %8d KB\n", 0) < 0) { + goto out_oom; + } + } else if (STREQ(line, "Cached")) { + if (virAsprintf(&new_line, "Cached: %8llu KB\n", + meminfo[VIR_LXC_FUSE_CACHED]) < 0) { + goto out_oom; + } + } else if (STREQ(line, "Active")) { + if (virAsprintf(&new_line, "Active: %8llu KB\n", + (meminfo[VIR_LXC_FUSE_ACTIVE_ANON] + meminfo[VIR_LXC_FUSE_ACTIVE_FILE])) < 0) { + goto out_oom; + } + } else if (STREQ(line, "Inactive")) { + if (virAsprintf(&new_line, "Inactive: %8llu KB\n", + (meminfo[VIR_LXC_FUSE_INACTIVE_ANON] + meminfo[VIR_LXC_FUSE_INACTIVE_FILE])) < 0) { + goto out_oom; + } + } else if (STREQ(line, "Active(anon)")) { + if (virAsprintf(&new_line, "Active(anon): %8llu KB\n", + meminfo[VIR_LXC_FUSE_ACTIVE_ANON]) < 0) { + goto out_oom; + } + } else if (STREQ(line, "Inactive(anon)")) { + if (virAsprintf(&new_line, "Inactive(anon): %8llu KB\n", + meminfo[VIR_LXC_FUSE_INACTIVE_ANON]) < 0) { + goto out_oom; + } + } else if (STREQ(line, "Active(file)")) { + if (virAsprintf(&new_line, "Active(file): %8llu KB\n", + meminfo[VIR_LXC_FUSE_ACTIVE_FILE]) < 0) { + goto out_oom; + } + } else if (STREQ(line, "Inactive(file)")) { + if (virAsprintf(&new_line, "Inactive(file): %8llu KB\n", + meminfo[VIR_LXC_FUSE_INACTIVE_FILE]) < 0) { + goto out_oom; + } + } else if (STREQ(line, "Unevictable")) { + if (virAsprintf(&new_line, "Unevictable: %8llu KB\n", + meminfo[VIR_LXC_FUSE_UNEVICTABLE]) < 0) { + goto out_oom; + } + } else if (STREQ(line, "SwapTotal") && def->mem.swap_hard_limit) { + if (virAsprintf(&new_line, "SwapTotal: %8llu KB\n", + (meminfo[VIR_LXC_FUSE_SWAPTOTAL] - meminfo[VIR_LXC_FUSE_MEMTOTAL])) < 0) { + goto out_oom; + } + } else if (STREQ(line, "SwapFree") && def->mem.swap_hard_limit) { + if (virAsprintf(&new_line, "SwapFree: %8llu KB\n", + (meminfo[VIR_LXC_FUSE_SWAPTOTAL] - meminfo[VIR_LXC_FUSE_MEMTOTAL] - + meminfo[VIR_LXC_FUSE_SWAPUSAGE] + meminfo[VIR_LXC_FUSE_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(); + res = -errno; + goto out; } -static int lxcProcRead(const char *path ATTRIBUTE_UNUSED, - char *buf ATTRIBUTE_UNUSED, - size_t size ATTRIBUTE_UNUSED, - off_t offset ATTRIBUTE_UNUSED, +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 = -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)) < 0)) + goto out; + } + +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 d188190..0a036f8 100644 --- a/src/lxc/lxc_fuse.h +++ b/src/lxc/lxc_fuse.h @@ -35,6 +35,20 @@ #include "util.h" #include "memory.h" +enum { + VIR_LXC_FUSE_MEMTOTAL, + VIR_LXC_FUSE_MEMUSAGE, + VIR_LXC_FUSE_CACHED, + VIR_LXC_FUSE_ACTIVE_ANON, + VIR_LXC_FUSE_INACTIVE_ANON, + VIR_LXC_FUSE_ACTIVE_FILE, + VIR_LXC_FUSE_INACTIVE_FILE, + VIR_LXC_FUSE_UNEVICTABLE, + VIR_LXC_FUSE_SWAPTOTAL, + VIR_LXC_FUSE_SWAPUSAGE, + VIR_LXC_FUSE_MEMMAX, +}; + extern void lxcRegisterFuse(void *opaque); extern void lxcUnregisterFuse(virDomainDefPtr def); #endif -- 1.7.7.6

we already have virtualize meminfo for container through fuse filesystem, add function lxcContainerMountProcFuse to mount this meminfo file to the container's /proc/meminfo. So we can isolate container's /proc/meminfo from host now. Signed-off-by: Gao feng <gaofeng@cn.fujitsu.com> --- src/lxc/lxc_container.c | 38 ++++++++++++++++++++++++++++++++++++++ 1 files changed, 38 insertions(+), 0 deletions(-) diff --git a/src/lxc/lxc_container.c b/src/lxc/lxc_container.c index 2789c17..e8fdb37 100644 --- a/src/lxc/lxc_container.c +++ b/src/lxc/lxc_container.c @@ -595,6 +595,36 @@ cleanup: return rc; } +#if HAVE_FUSE +static int lxcContainerMountProcFuse(virDomainDefPtr def, + const char *srcprefix) +{ + int ret = 0; + char *meminfo_path = NULL; + + if ((ret = virAsprintf(&meminfo_path, + "%s/%s/%s/meminfo", + srcprefix, LXC_STATE_DIR, + def->name)) < 0) + return ret; + + 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(meminfo_path); + return ret; +} +#else +static int lxcContainerMountProcFuse(virDomainDefPtr def ATTRIBUTE_UNUSED, + const char *srcprefix ATTRIBUTE_UNUSED) +{ + return 0; +} +#endif static int lxcContainerMountFSDevPTS(virDomainFSDefPtr root) { @@ -1550,6 +1580,10 @@ static int lxcContainerSetupPivotRoot(virDomainDefPtr vmDef, if (lxcContainerMountBasicFS(true, sec_mount_options) < 0) goto cleanup; + /* Mounts /proc/meminfo etc sysinfo */ + if (lxcContainerMountProcFuse(vmDef, "/.oldroot") < 0) + goto cleanup; + /* Now we can re-mount the cgroups controllers in the * same configuration as before */ if (lxcContainerMountCGroups(mounts, nmounts, @@ -1640,6 +1674,10 @@ static int lxcContainerSetupExtraMounts(virDomainDefPtr vmDef, if (lxcContainerMountBasicFS(false, sec_mount_options) < 0) goto cleanup; + /* Mounts /proc/meminfo etc sysinfo */ + if (lxcContainerMountProcFuse(vmDef, "/.oldroot") < 0) + goto cleanup; + /* Now we can re-mount the cgroups controllers in the * same configuration as before */ if (lxcContainerMountCGroups(mounts, nmounts, -- 1.7.7.6
participants (1)
-
Gao feng