[libvirt] [RFC] [PATCH v3 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 | 35 +++++++++++++++++++++++++++++++++++ libvirt.spec.in | 9 +++++++++ 2 files changed, 44 insertions(+), 0 deletions(-) diff --git a/configure.ac b/configure.ac index 47a72b9..cc7de9d 100644 --- a/configure.ac +++ b/configure.ac @@ -1847,6 +1847,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], + [with_fuse=yes], [ + if test "x$with_fuse" = "xcheck" ; then + with_fuse=no + else + AC_MSG_ERROR( + [You must install fuse-devel 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]) @@ -3103,6 +3133,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 8c4c08d..a63999c 100644 --- a/libvirt.spec.in +++ b/libvirt.spec.in @@ -92,6 +92,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} @@ -490,6 +491,9 @@ BuildRequires: numactl-devel %if %{with_capng} BuildRequires: libcap-ng-devel >= 0.5.0 %endif +%if %{with_fuse} +BuildRequires: fuse-devel +%endif %if %{with_phyp} BuildRequires: libssh2-devel %endif @@ -1157,6 +1161,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 @@ -1261,6 +1269,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 | 10 +++ src/lxc/lxc_fuse.c | 151 ++++++++++++++++++++++++++++++++++++++++++++++ src/lxc/lxc_fuse.h | 40 ++++++++++++ src/lxc/lxc_process.c | 3 +- 6 files changed, 211 insertions(+), 3 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 7a91eb4..f8244a0 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -47,6 +47,7 @@ src/libvirt-qemu.c src/locking/lock_driver_sanlock.c src/locking/lock_manager.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 9f27fcf..c4ac35b 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -409,6 +409,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 = \ @@ -417,6 +418,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 = \ @@ -893,8 +895,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) @@ -1637,6 +1640,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 \ @@ -1655,7 +1659,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 e5aea11..c5f4951 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" @@ -1471,6 +1472,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[] = { @@ -1657,6 +1659,14 @@ 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..868a698 --- /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 *DomainDef) +{ + int argc = 4; + char *argv[argc]; + char *path = NULL; + char *name = NULL; + virDomainDefPtr def = (virDomainDefPtr) DomainDef; + + if (virAsprintf(&name, "Lxc-%s-fuse", def->name) < 0) { + virReportOOMError(); + goto cleanup; + } + + if (virAsprintf(&path, "%s/%s/", LXC_STATE_DIR, def->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, def) < 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 *DomainDef 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..d60c238 --- /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 *DomainDef); +extern void lxcUnregisterFuse(virDomainDefPtr def); +#endif diff --git a/src/lxc/lxc_process.c b/src/lxc/lxc_process.c index bcd59cb..d5e1822 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" @@ -232,7 +233,7 @@ static void virLXCProcessCleanup(virLXCDriverPtr driver, NULL, xml, NULL); VIR_FREE(xml); } - + lxcUnregisterFuse(vm->def); /* Stop autodestroy in case guest is restarted */ virLXCProcessAutoDestroyRemove(driver, vm); -- 1.7.7.6

On Tue, Sep 11, 2012 at 10:54:48AM +0800, Gao feng wrote:
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>
diff --git a/src/lxc/lxc_controller.c b/src/lxc/lxc_controller.c index e5aea11..c5f4951 100644 --- a/src/lxc/lxc_controller.c +++ b/src/lxc/lxc_controller.c @@ -1657,6 +1659,14 @@ 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; + } +
This is the wrong place to start FUSE. At this point the LXC controller is still sharing its mount namespace with the host OS. This causes the FUSE mount for each container to become visible in the host, which is not what we want. We must only start FUSE, after, we have done the unshare() call while setting up /dev/pts.
+void lxcRegisterFuse(void *DomainDef)
More conventional naming would be 'void *opaque'
+{ + int argc = 4; + char *argv[argc]; + char *path = NULL; + char *name = NULL; + virDomainDefPtr def = (virDomainDefPtr) DomainDef; + + if (virAsprintf(&name, "Lxc-%s-fuse", def->name) < 0) { + virReportOOMError(); + goto cleanup; + } + + if (virAsprintf(&path, "%s/%s/", LXC_STATE_DIR, def->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, def) < 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 *DomainDef ATTRIBUTE_UNUSED) +{ +} + +void lxcUnregisterFuse(virDomainDefPtr def ATTRIBUTE_UNUSED) +{ +} +#endif
diff --git a/src/lxc/lxc_process.c b/src/lxc/lxc_process.c index bcd59cb..d5e1822 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" @@ -232,7 +233,7 @@ static void virLXCProcessCleanup(virLXCDriverPtr driver, NULL, xml, NULL); VIR_FREE(xml); } - + lxcUnregisterFuse(vm->def); /* Stop autodestroy in case guest is restarted */ virLXCProcessAutoDestroyRemove(driver, vm);
If you delayed starting FUSE until after we do unshare(), then the mount point will automatically go away when the LXC controller process exits, so we won't need any manual unmount in lxcUnregisterFuse() Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

于 2012年09月26日 02:37, Daniel P. Berrange 写道:
On Tue, Sep 11, 2012 at 10:54:48AM +0800, Gao feng wrote:
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>
diff --git a/src/lxc/lxc_controller.c b/src/lxc/lxc_controller.c index e5aea11..c5f4951 100644 --- a/src/lxc/lxc_controller.c +++ b/src/lxc/lxc_controller.c @@ -1657,6 +1659,14 @@ 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; + } +
This is the wrong place to start FUSE. At this point the LXC controller is still sharing its mount namespace with the host OS. This causes the FUSE mount for each container to become visible in the host, which is not what we want. sorry for the delay.
I think it's correct,because host can see container's meminfo through cgroup too.NOW the container's cgroup can be seen and modified in container too,I don't know why this is necessary?
We must only start FUSE, after, we have done the unshare() call while setting up /dev/pts.
+void lxcRegisterFuse(void *DomainDef)
More conventional naming would be 'void *opaque'
will fix this.
+{ + int argc = 4; + char *argv[argc]; + char *path = NULL; + char *name = NULL; + virDomainDefPtr def = (virDomainDefPtr) DomainDef; + + if (virAsprintf(&name, "Lxc-%s-fuse", def->name) < 0) { + virReportOOMError(); + goto cleanup; + } + + if (virAsprintf(&path, "%s/%s/", LXC_STATE_DIR, def->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, def) < 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 *DomainDef ATTRIBUTE_UNUSED) +{ +} + +void lxcUnregisterFuse(virDomainDefPtr def ATTRIBUTE_UNUSED) +{ +} +#endif
diff --git a/src/lxc/lxc_process.c b/src/lxc/lxc_process.c index bcd59cb..d5e1822 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" @@ -232,7 +233,7 @@ static void virLXCProcessCleanup(virLXCDriverPtr driver, NULL, xml, NULL); VIR_FREE(xml); } - + lxcUnregisterFuse(vm->def); /* Stop autodestroy in case guest is restarted */ virLXCProcessAutoDestroyRemove(driver, vm);
If you delayed starting FUSE until after we do unshare(), then the mount point will automatically go away when the LXC controller process exits, so we won't need any manual unmount in lxcUnregisterFuse()
Daniel

于 2012年10月08日 08:43, Gao feng 写道:
于 2012年09月26日 02:37, Daniel P. Berrange 写道:
On Tue, Sep 11, 2012 at 10:54:48AM +0800, Gao feng wrote:
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>
diff --git a/src/lxc/lxc_controller.c b/src/lxc/lxc_controller.c index e5aea11..c5f4951 100644 --- a/src/lxc/lxc_controller.c +++ b/src/lxc/lxc_controller.c @@ -1657,6 +1659,14 @@ 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; + } +
This is the wrong place to start FUSE. At this point the LXC controller is still sharing its mount namespace with the host OS. This causes the FUSE mount for each container to become visible in the host, which is not what we want. sorry for the delay.
I think it's correct,because host can see container's meminfo through cgroup too.NOW the container's cgroup can be seen and modified in container too,I don't know why this is necessary?
Hi Daniel Can you give me some comments? Thanks! Gao

On Mon, Oct 08, 2012 at 08:43:28AM +0800, Gao feng wrote:
于 2012年09月26日 02:37, Daniel P. Berrange 写道:
On Tue, Sep 11, 2012 at 10:54:48AM +0800, Gao feng wrote:
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>
diff --git a/src/lxc/lxc_controller.c b/src/lxc/lxc_controller.c index e5aea11..c5f4951 100644 --- a/src/lxc/lxc_controller.c +++ b/src/lxc/lxc_controller.c @@ -1657,6 +1659,14 @@ 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; + } +
This is the wrong place to start FUSE. At this point the LXC controller is still sharing its mount namespace with the host OS. This causes the FUSE mount for each container to become visible in the host, which is not what we want. sorry for the delay.
I think it's correct,because host can see container's meminfo through cgroup too.NOW the container's cgroup can be seen and modified in container too,I don't know why this is necessary?
The key point is that if you do 'cat /proc/mounts' with your current patch, you see all the LXC container FUSE mounts. These mounts should *not* be visible on the host. Only the libvirt_lxc process and the container itself shoudl see the mounts. This is why you must not start FUSE until after the unshare() call in libvirt_lxc. This also ensures that the FUSE mount is automatically destroyed when libvirt_lxc dies, without you needing to unregister or unmount it.
We must only start FUSE, after, we have done the unshare() call while setting up /dev/pts.
Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

于 2012年10月16日 20:23, Daniel P. Berrange 写道:
On Mon, Oct 08, 2012 at 08:43:28AM +0800, Gao feng wrote:
于 2012年09月26日 02:37, Daniel P. Berrange 写道:
On Tue, Sep 11, 2012 at 10:54:48AM +0800, Gao feng wrote:
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>
diff --git a/src/lxc/lxc_controller.c b/src/lxc/lxc_controller.c index e5aea11..c5f4951 100644 --- a/src/lxc/lxc_controller.c +++ b/src/lxc/lxc_controller.c @@ -1657,6 +1659,14 @@ 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; + } +
This is the wrong place to start FUSE. At this point the LXC controller is still sharing its mount namespace with the host OS. This causes the FUSE mount for each container to become visible in the host, which is not what we want. sorry for the delay.
I think it's correct,because host can see container's meminfo through cgroup too.NOW the container's cgroup can be seen and modified in container too,I don't know why this is necessary?
The key point is that if you do 'cat /proc/mounts' with your current patch, you see all the LXC container FUSE mounts. These mounts should *not* be visible on the host. Only the libvirt_lxc process and the container itself shoudl see the mounts. This is why you must not start FUSE until after the unshare() call in libvirt_lxc. This also ensures that the FUSE mount is automatically destroyed when libvirt_lxc dies, without you needing to unregister or unmount it.
If we start FUSE after the unshare() call in libvirt_lxc,the fuse will work in container's environment. and the cgroup is set in the host. Can we get host's information in container? I think this is incorrect. I regard the FUSE as a service on host,it provides host's cgroup info for the container. I am wrong? Thanks Gao
We must only start FUSE, after, we have done the unshare() call while setting up /dev/pts.
Daniel

Hi I will rebase and send this patchset as I think you all agree with me. Thanks! Gao

On Thu, Oct 18, 2012 at 01:25:30PM +0800, Gao feng wrote:
于 2012年10月16日 20:23, Daniel P. Berrange 写道:
On Mon, Oct 08, 2012 at 08:43:28AM +0800, Gao feng wrote:
于 2012年09月26日 02:37, Daniel P. Berrange 写道:
On Tue, Sep 11, 2012 at 10:54:48AM +0800, Gao feng wrote:
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>
diff --git a/src/lxc/lxc_controller.c b/src/lxc/lxc_controller.c index e5aea11..c5f4951 100644 --- a/src/lxc/lxc_controller.c +++ b/src/lxc/lxc_controller.c @@ -1657,6 +1659,14 @@ 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; + } +
This is the wrong place to start FUSE. At this point the LXC controller is still sharing its mount namespace with the host OS. This causes the FUSE mount for each container to become visible in the host, which is not what we want. sorry for the delay.
I think it's correct,because host can see container's meminfo through cgroup too.NOW the container's cgroup can be seen and modified in container too,I don't know why this is necessary?
The key point is that if you do 'cat /proc/mounts' with your current patch, you see all the LXC container FUSE mounts. These mounts should *not* be visible on the host. Only the libvirt_lxc process and the container itself shoudl see the mounts. This is why you must not start FUSE until after the unshare() call in libvirt_lxc. This also ensures that the FUSE mount is automatically destroyed when libvirt_lxc dies, without you needing to unregister or unmount it.
If we start FUSE after the unshare() call in libvirt_lxc,the fuse will work in container's environment. and the cgroup is set in the host. Can we get host's information in container? I think this is incorrect.
The 'libvirt_lxc' process is not actually running inside the container. It is running in the host context, but with a slightly customized filesystem mount namespace, so that it can view /dev from both the host and container at once.
I regard the FUSE as a service on host,it provides host's cgroup info for the container.
Yes it is a host service, but that is exactly what libvirt_lxc is. All I am saying is that we must not pollute the host OS' mount table - keep the mounts hidden in the libvirt_lxc process & container processes only. Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

于 2012年10月23日 23:37, Daniel P. Berrange 写道:
On Thu, Oct 18, 2012 at 01:25:30PM +0800, Gao feng wrote:
于 2012年10月16日 20:23, Daniel P. Berrange 写道:
On Mon, Oct 08, 2012 at 08:43:28AM +0800, Gao feng wrote:
于 2012年09月26日 02:37, Daniel P. Berrange 写道:
On Tue, Sep 11, 2012 at 10:54:48AM +0800, Gao feng wrote:
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>
diff --git a/src/lxc/lxc_controller.c b/src/lxc/lxc_controller.c index e5aea11..c5f4951 100644 --- a/src/lxc/lxc_controller.c +++ b/src/lxc/lxc_controller.c @@ -1657,6 +1659,14 @@ 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; + } +
This is the wrong place to start FUSE. At this point the LXC controller is still sharing its mount namespace with the host OS. This causes the FUSE mount for each container to become visible in the host, which is not what we want. sorry for the delay.
I think it's correct,because host can see container's meminfo through cgroup too.NOW the container's cgroup can be seen and modified in container too,I don't know why this is necessary?
The key point is that if you do 'cat /proc/mounts' with your current patch, you see all the LXC container FUSE mounts. These mounts should *not* be visible on the host. Only the libvirt_lxc process and the container itself shoudl see the mounts. This is why you must not start FUSE until after the unshare() call in libvirt_lxc. This also ensures that the FUSE mount is automatically destroyed when libvirt_lxc dies, without you needing to unregister or unmount it.
If we start FUSE after the unshare() call in libvirt_lxc,the fuse will work in container's environment. and the cgroup is set in the host. Can we get host's information in container? I think this is incorrect.
The 'libvirt_lxc' process is not actually running inside the container. It is running in the host context, but with a slightly customized filesystem mount namespace, so that it can view /dev from both the host and container at once.
Yes,you are right,I will change this patchset. There are some strange error when I start FUSE after unshare(), So I need some time to resolve these things.
I regard the FUSE as a service on host,it provides host's cgroup info for the container.
Yes it is a host service, but that is exactly what libvirt_lxc is. All I am saying is that we must not pollute the host OS' mount table - keep the mounts hidden in the libvirt_lxc process & container processes only.
Get it,thanks for teaching me this. :)

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 10af063..666bec2 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -85,6 +85,7 @@ virCgroupGetCpuacctUsage; virCgroupGetCpusetCpus; virCgroupGetCpusetMems; virCgroupGetFreezerState; +virCgroupGetMemSwapUsage; virCgroupGetMemSwapHardLimit; virCgroupGetMemoryHardLimit; virCgroupGetMemorySoftLimit; diff --git a/src/util/cgroup.c b/src/util/cgroup.c index 5dc0764..b702f53 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 bb12b40..3d7ddbb 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 666bec2..33375df 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -72,6 +72,7 @@ virCgroupDenyDeviceMajor; virCgroupDenyDevicePath; virCgroupForDomain; virCgroupForDriver; +virCgroupGetAppRoot; virCgroupForEmulator; virCgroupForVcpu; virCgroupFree; diff --git a/src/util/cgroup.c b/src/util/cgroup.c index b702f53..d2c6120 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 3d7ddbb..9f28a5a 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 | 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; + } + + 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, +}; + extern void lxcRegisterFuse(void *DomainDef); extern void lxcUnregisterFuse(virDomainDefPtr def); #endif -- 1.7.7.6

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@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
+ + 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 Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

于 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@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.

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@cn.fujitsu.com> +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; + }
When I tested these patches on a 3.4 kernel, these last two calls always fail because the corresponding cgroup file does not exist. I had to remove them to make this work at all.
+ + ret = 0; +out: + virCgroupFree(&cgroup); + + return ret; +}
Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

于 2012年09月26日 02:46, 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@cn.fujitsu.com> +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; + }
When I tested these patches on a 3.4 kernel, these last two calls always fail because the corresponding cgroup file does not exist. I had to remove them to make this work at all.
Yes,it shouldn't return error when the swap cgroup file doesn't exist. I will fix this. thanks!

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 9bc5610..6a0850d 100644 --- a/src/lxc/lxc_container.c +++ b/src/lxc/lxc_container.c @@ -593,6 +593,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) { @@ -1537,6 +1567,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, @@ -1619,6 +1653,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

On 09/24/2012 06:36 AM, Gao feng wrote:
于 2012年09月17日 13:04, Gao feng 写道:
于 2012年09月11日 10:54, Gao feng 写道:
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> ---
ping...
Any comments?
Well, since this is mostly libvirt code, I really don't feel comfortable commenting on it.

On 09/23/2012 08:36 PM, Gao feng wrote:
于 2012年09月17日 13:04, Gao feng 写道:
于 2012年09月11日 10:54, Gao feng 写道:
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> ---
ping...
Any comments?
It came in a bit late for inclusion for 0.10.2, but now that the release is out, we will have plenty of time to review it before 0.10.3. At a first glance, the idea of using FUSE in LXC makes sense, although I'm probably not as fluent with what LXC needs to do as danpb. -- Eric Blake eblake@redhat.com +1-919-301-3266 Libvirt virtualization library http://libvirt.org

On Mon, Sep 24, 2012 at 10:36:16AM +0800, Gao feng wrote:
于 2012年09月17日 13:04, Gao feng 写道:
于 2012年09月11日 10:54, Gao feng 写道:
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> ---
ping...
Any comments?
Sorry for the delay, I am about to actually try it out locally. Assuming all goes well, I'll aim to send review comments today or tomorrow. Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

On Mon, Sep 10, 2012 at 9:54 PM, Gao feng <gaofeng@cn.fujitsu.com> wrote:
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 | 35 +++++++++++++++++++++++++++++++++++ libvirt.spec.in | 9 +++++++++ 2 files changed, 44 insertions(+), 0 deletions(-)
diff --git a/configure.ac b/configure.ac index 47a72b9..cc7de9d 100644 --- a/configure.ac +++ b/configure.ac @@ -1847,6 +1847,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],
Probably want to figure out your minimum supported version and check for at least that or newer.
+ [with_fuse=yes], [ + if test "x$with_fuse" = "xcheck" ; then + with_fuse=no + else + AC_MSG_ERROR( + [You must install fuse-devel to compile libvirt])
Very Fedora/RHEL-y message. Probably better to be a bit more abstract. See other messages in confugure.ac for an example.
+ 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]) @@ -3103,6 +3133,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 8c4c08d..a63999c 100644 --- a/libvirt.spec.in +++ b/libvirt.spec.in @@ -92,6 +92,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} @@ -490,6 +491,9 @@ BuildRequires: numactl-devel %if %{with_capng} BuildRequires: libcap-ng-devel >= 0.5.0 %endif +%if %{with_fuse} +BuildRequires: fuse-devel +%endif %if %{with_phyp} BuildRequires: libssh2-devel %endif @@ -1157,6 +1161,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 @@ -1261,6 +1269,7 @@ autoreconf -if %{?_without_numactl} \ %{?_without_numad} \ %{?_without_capng} \ + %{?_without_fuse} \ %{?_without_netcf} \ %{?_without_selinux} \ %{?_with_selinux_mount} \ -- 1.7.7.6
-- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list
Other than the 2 small comments, it looks fine. -- Doug Goldstein

On 09/24/2012 12:24 PM, Doug Goldstein wrote:
On Mon, Sep 10, 2012 at 9:54 PM, Gao feng <gaofeng@cn.fujitsu.com> wrote:
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> ---
Other than the 2 small comments, it looks fine.
Also, Daniel recently posted a proposal for unifying various library configure checks; it may be worth rebasing this on top of his work: https://www.redhat.com/archives/libvir-list/2012-September/msg01444.html -- Eric Blake eblake@redhat.com +1-919-301-3266 Libvirt virtualization library http://libvirt.org

于 2012年09月25日 02:43, Eric Blake 写道:
On 09/24/2012 12:24 PM, Doug Goldstein wrote:
On Mon, Sep 10, 2012 at 9:54 PM, Gao feng <gaofeng@cn.fujitsu.com> wrote:
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> ---
Other than the 2 small comments, it looks fine.
Also, Daniel recently posted a proposal for unifying various library configure checks; it may be worth rebasing this on top of his work: https://www.redhat.com/archives/libvir-list/2012-September/msg01444.html
It's good, I will rebase this patch base on this improvement. Thanks.

On Mon, Sep 24, 2012 at 12:43:42PM -0600, Eric Blake wrote:
On 09/24/2012 12:24 PM, Doug Goldstein wrote:
On Mon, Sep 10, 2012 at 9:54 PM, Gao feng <gaofeng@cn.fujitsu.com> wrote:
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> ---
Other than the 2 small comments, it looks fine.
Also, Daniel recently posted a proposal for unifying various library configure checks; it may be worth rebasing this on top of his work: https://www.redhat.com/archives/libvir-list/2012-September/msg01444.html
Nah, don't worry about rebasing for that. I'll take care of any configure.ac changes other patches introduce myself. Daniel -- |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :| |: http://libvirt.org -o- http://virt-manager.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: http://entangle-photo.org -o- http://live.gnome.org/gtk-vnc :|

于 2012年09月25日 02:24, Doug Goldstein 写道:
On Mon, Sep 10, 2012 at 9:54 PM, Gao feng <gaofeng@cn.fujitsu.com> wrote:
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 | 35 +++++++++++++++++++++++++++++++++++ libvirt.spec.in | 9 +++++++++ 2 files changed, 44 insertions(+), 0 deletions(-)
diff --git a/configure.ac b/configure.ac index 47a72b9..cc7de9d 100644 --- a/configure.ac +++ b/configure.ac @@ -1847,6 +1847,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],
Probably want to figure out your minimum supported version and check for at least that or newer.
Thanks,I will check this.
+ [with_fuse=yes], [ + if test "x$with_fuse" = "xcheck" ; then + with_fuse=no + else + AC_MSG_ERROR( + [You must install fuse-devel to compile libvirt])
Very Fedora/RHEL-y message. Probably better to be a bit more abstract. See other messages in confugure.ac for an example.
Get it,will modify it.
Other than the 2 small comments, it looks fine.
Thanks for your comments!
participants (5)
-
Daniel P. Berrange
-
Doug Goldstein
-
Eric Blake
-
Gao feng
-
Glauber Costa