[libvirt] [PATCH v7 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 and Richard. Signed-off-by: Gao feng <gaofeng@cn.fujitsu.com> --- configure.ac | 29 +++++++++++++++++++++++++++++ libvirt.spec.in | 9 +++++++++ 2 files changed, 38 insertions(+), 0 deletions(-) diff --git a/configure.ac b/configure.ac index 9108ea8..495cbfa 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 @@ -1859,6 +1860,29 @@ 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 +AS_IF([test "x$with_fuse" != "xno"], + [PKG_CHECK_MODULES([FUSE], [fuse >= $FUSE_REQUIRED], + [with_fuse=yes + AC_SUBST([FUSE_CFLAGS]) + AC_SUBST([FUSE_LIBS]) + AC_DEFINE_UNQUOTED([HAVE_FUSE], 1, [whether fuse is available for libvirt lxc]) + ], + [if test "x$with_fuse" = "xyes" ; then + AC_MSG_ERROR([You must install fuse library to compile libvirt]) + else + with_fuse=no + fi + ]) + ]) +AM_CONDITIONAL([HAVE_FUSE], [test "x$with_fuse" = "xyes"]) dnl virsh libraries AC_CHECK_HEADERS([readline/readline.h]) @@ -3163,6 +3187,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 b6ded04..55408b6 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} @@ -503,6 +504,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 @@ -1186,6 +1190,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 @@ -1289,6 +1297,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 libvirt,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_cgroup.c | 1 + src/lxc/lxc_container.h | 3 + src/lxc/lxc_controller.c | 26 ++++++++ src/lxc/lxc_fuse.c | 157 ++++++++++++++++++++++++++++++++++++++++++++++ src/lxc/lxc_fuse.h | 40 ++++++++++++ src/lxc/lxc_process.c | 1 + 8 files changed, 236 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 9768528..0199d6f 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -50,6 +50,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 1f32263..4b8e6c0 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -413,6 +413,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 = \ @@ -421,6 +422,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 = \ @@ -911,8 +913,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) @@ -1678,6 +1681,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 \ @@ -1696,7 +1700,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_cgroup.c b/src/lxc/lxc_cgroup.c index bdfaa54..9a5ba1a 100644 --- a/src/lxc/lxc_cgroup.c +++ b/src/lxc/lxc_cgroup.c @@ -163,6 +163,7 @@ static int virLXCCgroupSetupDeviceACL(virDomainDefPtr def, {'c', LXC_DEV_MAJ_MEMORY, LXC_DEV_MIN_URANDOM}, {'c', LXC_DEV_MAJ_TTY, LXC_DEV_MIN_TTY}, {'c', LXC_DEV_MAJ_TTY, LXC_DEV_MIN_PTMX}, + {'c', LXC_DEV_MAJ_FUSE, LXC_DEV_MIN_FUSE}, {0, 0, 0}}; rc = virCgroupDenyAllDevices(cgroup); diff --git a/src/lxc/lxc_container.h b/src/lxc/lxc_container.h index b1adacb..c8c70e0 100644 --- a/src/lxc/lxc_container.h +++ b/src/lxc/lxc_container.h @@ -46,6 +46,9 @@ enum { # define LXC_DEV_MAJ_PTY 136 +# define LXC_DEV_MAJ_FUSE 10 +# define LXC_DEV_MIN_FUSE 229 + int lxcContainerSendContinue(int control); int lxcContainerWaitForContinue(int control); diff --git a/src/lxc/lxc_controller.c b/src/lxc/lxc_controller.c index a41c903..f0d28f8 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" @@ -1245,6 +1246,28 @@ cleanup: return ret; } +static int +virLXCControllerSetupFuse(virLXCControllerPtr ctrl) +{ + int try = 0; + virThread thread; + if (virThreadCreate(&thread, true, lxcRegisterFuse, + (void *)ctrl->def) < 0) + return -1; + /* + * because libvirt_lxc may use fuse filesystem before fuse being + * mounted by the thread. so wait 3 seconds in libvirt_lxc. if fuse + * is not mounted in 3 seconds, libvirt_lxc will exit. + */ + while (try++ < 2) { + if (lxcRegisterFuseSuccess()) + return 0; + + sleep(1); + } + + return -1; +} static int virLXCControllerSetupConsoles(virLXCControllerPtr ctrl, @@ -1388,6 +1411,9 @@ virLXCControllerRun(virLXCControllerPtr ctrl) if (virLXCControllerSetupDevPTS(ctrl) < 0) goto cleanup; + if (virLXCControllerSetupFuse(ctrl) < 0) + goto cleanup; + if (virLXCControllerSetupConsoles(ctrl, containerTTYPaths) < 0) goto cleanup; diff --git a/src/lxc/lxc_fuse.c b/src/lxc/lxc_fuse.c new file mode 100644 index 0000000..42107d7 --- /dev/null +++ b/src/lxc/lxc_fuse.c @@ -0,0 +1,157 @@ +/* + * 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, see + * <http://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <fcntl.h> +#include <stdio.h> +#include <errno.h> +#include <string.h> +#include <sys/mount.h> +#include <mntent.h> + +#include "lxc_fuse.h" +#include "virterror_internal.h" +#include "logging.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; + virDomainDefPtr def = opaque; + + 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] = (char *)"libvirt"; + 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(path); + return; +} + +int lxcRegisterFuseSuccess(void) +{ + FILE *procmnt = NULL; + struct mntent mntent; + char mntbuf[1024]; + int ret = 0; + + if (!(procmnt = setmntent("/proc/mounts", "r"))) { + virReportSystemError(errno, "%s", + _("Failed to read /proc/mounts")); + return ret; + } + + while (getmntent_r(procmnt, &mntent, mntbuf, sizeof(mntbuf)) != NULL) { + VIR_DEBUG("Got %s\n",mntent.mnt_fsname); + if (STRNEQ(mntent.mnt_fsname, "libvirt")) + continue; + + ret = 1; + break; + } + + endmntent(procmnt); + return ret; +} + +#else +void lxcRegisterFuse(void *opaque ATTRIBUTE_UNUSED) +{ +} + +int lxcRegisterFuseSuccess(void) +{ + return 1; +} +#endif diff --git a/src/lxc/lxc_fuse.h b/src/lxc/lxc_fuse.h new file mode 100644 index 0000000..5b3689e --- /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, see + * <http://www.gnu.org/licenses/>. + */ + +#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 int lxcRegisterFuseSuccess(void); +#endif diff --git a/src/lxc/lxc_process.c b/src/lxc/lxc_process.c index 079bc3a..a9a0984 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" -- 1.7.7.6

On Tue, Nov 06, 2012 at 02:07:18PM +0800, Gao feng wrote:
+static int +virLXCControllerSetupFuse(virLXCControllerPtr ctrl) +{ + int try = 0; + virThread thread; + if (virThreadCreate(&thread, true, lxcRegisterFuse, + (void *)ctrl->def) < 0) + return -1; + /* + * because libvirt_lxc may use fuse filesystem before fuse being + * mounted by the thread. so wait 3 seconds in libvirt_lxc. if fuse + * is not mounted in 3 seconds, libvirt_lxc will exit. + */ + while (try++ < 2) { + if (lxcRegisterFuseSuccess()) + return 0; + + sleep(1); + } + + return -1; +}
This code seems like it is bound to cause trouble. Can you explain why the arbitrary wait is required here?
diff --git a/src/lxc/lxc_fuse.c b/src/lxc/lxc_fuse.c new file mode 100644 index 0000000..42107d7 --- /dev/null +++ b/src/lxc/lxc_fuse.c @@ -0,0 +1,157 @@ +/* + * Copyright (C) 2012 Fujitsu Limited. + * + * lxc_fuse.c: fuse filesystem support for libvirt lxc [...]
The basic empty directory fuse filesystem seems fine. I see that patch 5/6 adds one(?) file to this directory, also fine. Rich. -- Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones virt-top is 'top' for virtual machines. Tiny program with many powerful monitoring features, net stats, disk stats, logging, etc. http://et.redhat.com/~rjones/virt-top

于 2012年11月06日 16:34, Richard W.M. Jones 写道:
On Tue, Nov 06, 2012 at 02:07:18PM +0800, Gao feng wrote:
+static int +virLXCControllerSetupFuse(virLXCControllerPtr ctrl) +{ + int try = 0; + virThread thread; + if (virThreadCreate(&thread, true, lxcRegisterFuse, + (void *)ctrl->def) < 0) + return -1; + /* + * because libvirt_lxc may use fuse filesystem before fuse being + * mounted by the thread. so wait 3 seconds in libvirt_lxc. if fuse + * is not mounted in 3 seconds, libvirt_lxc will exit. + */ + while (try++ < 2) { + if (lxcRegisterFuseSuccess()) + return 0; + + sleep(1); + } + + return -1; +}
This code seems like it is bound to cause trouble. Can you explain why the arbitrary wait is required here?
Because libvirt_lxc create a thread to mount fuse filesystem. and then libvirt_lxc will try to access the fuse filesystem. Without waiting,libvirt_lxc may access fuse before it is mounted. And I can't find a better way to make accessing fuse after the fuse being mounted,because fuse_main will return until fuse being unmounted,so I don't know how to pass message to tell libvirt_lxc whether the fuse is mounted success.
diff --git a/src/lxc/lxc_fuse.c b/src/lxc/lxc_fuse.c new file mode 100644 index 0000000..42107d7 --- /dev/null +++ b/src/lxc/lxc_fuse.c @@ -0,0 +1,157 @@ +/* + * Copyright (C) 2012 Fujitsu Limited. + * + * lxc_fuse.c: fuse filesystem support for libvirt lxc [...]
The basic empty directory fuse filesystem seems fine. I see that patch 5/6 adds one(?) file to this directory, also fine.
Thanks for your review. Gao

On Tue, Nov 06, 2012 at 04:54:59PM +0800, Gao feng wrote:
Because libvirt_lxc create a thread to mount fuse filesystem. and then libvirt_lxc will try to access the fuse filesystem.
Without waiting,libvirt_lxc may access fuse before it is mounted.
And I can't find a better way to make accessing fuse after the fuse being mounted,because fuse_main will return until fuse being unmounted,so I don't know how to pass message to tell libvirt_lxc whether the fuse is mounted success.
Oh I see. This is solvable, but I believe that you cannot use fuse_main. You have to look at the fuse sources (quite complex!) and do the individual fuse operations. Have a look at how libguestfs does it ... https://github.com/libguestfs/libguestfs/blob/master/src/fuse.c#L911 http://libguestfs.org/guestfs.3.html#mount-local Rich. -- Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones virt-top is 'top' for virtual machines. Tiny program with many powerful monitoring features, net stats, disk stats, logging, etc. http://et.redhat.com/~rjones/virt-top

于 2012年11月06日 17:11, Richard W.M. Jones 写道:
On Tue, Nov 06, 2012 at 04:54:59PM +0800, Gao feng wrote:
Because libvirt_lxc create a thread to mount fuse filesystem. and then libvirt_lxc will try to access the fuse filesystem.
Without waiting,libvirt_lxc may access fuse before it is mounted.
And I can't find a better way to make accessing fuse after the fuse being mounted,because fuse_main will return until fuse being unmounted,so I don't know how to pass message to tell libvirt_lxc whether the fuse is mounted success.
Oh I see. This is solvable, but I believe that you cannot use fuse_main. You have to look at the fuse sources (quite complex!) and do the individual fuse operations.
Have a look at how libguestfs does it ...
https://github.com/libguestfs/libguestfs/blob/master/src/fuse.c#L911 http://libguestfs.org/guestfs.3.html#mount-local
Thanks for the information. Can fuse_mount & fuse_new & fuse_loop avoid the waiting? It seems has the same problem. Thanks Gao

On Tue, Nov 06, 2012 at 07:50:33PM +0800, Gao feng wrote:
于 2012年11月06日 17:11, Richard W.M. Jones 写道:
On Tue, Nov 06, 2012 at 04:54:59PM +0800, Gao feng wrote:
Because libvirt_lxc create a thread to mount fuse filesystem. and then libvirt_lxc will try to access the fuse filesystem.
Without waiting,libvirt_lxc may access fuse before it is mounted.
And I can't find a better way to make accessing fuse after the fuse being mounted,because fuse_main will return until fuse being unmounted,so I don't know how to pass message to tell libvirt_lxc whether the fuse is mounted success.
Oh I see. This is solvable, but I believe that you cannot use fuse_main. You have to look at the fuse sources (quite complex!) and do the individual fuse operations.
Have a look at how libguestfs does it ...
https://github.com/libguestfs/libguestfs/blob/master/src/fuse.c#L911 http://libguestfs.org/guestfs.3.html#mount-local
Thanks for the information.
Can fuse_mount & fuse_new & fuse_loop avoid the waiting?
It seems has the same problem.
It waits, but it doesn't busy wait in a loop. The first access to the filesystem hangs until the thread which is handling the filesystem is listening for requests. Rich. -- Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones New in Fedora 11: Fedora Windows cross-compiler. Compile Windows programs, test, and build Windows installers. Over 70 libraries supprt'd http://fedoraproject.org/wiki/MinGW http://www.annexia.org/fedora_mingw

于 2012年11月06日 20:55, Richard W.M. Jones 写道:
On Tue, Nov 06, 2012 at 07:50:33PM +0800, Gao feng wrote:
于 2012年11月06日 17:11, Richard W.M. Jones 写道:
On Tue, Nov 06, 2012 at 04:54:59PM +0800, Gao feng wrote:
Because libvirt_lxc create a thread to mount fuse filesystem. and then libvirt_lxc will try to access the fuse filesystem.
Without waiting,libvirt_lxc may access fuse before it is mounted.
And I can't find a better way to make accessing fuse after the fuse being mounted,because fuse_main will return until fuse being unmounted,so I don't know how to pass message to tell libvirt_lxc whether the fuse is mounted success.
Oh I see. This is solvable, but I believe that you cannot use fuse_main. You have to look at the fuse sources (quite complex!) and do the individual fuse operations.
Have a look at how libguestfs does it ...
https://github.com/libguestfs/libguestfs/blob/master/src/fuse.c#L911 http://libguestfs.org/guestfs.3.html#mount-local
Thanks for the information.
Can fuse_mount & fuse_new & fuse_loop avoid the waiting?
It seems has the same problem.
It waits, but it doesn't busy wait in a loop. The first access to the filesystem hangs until the thread which is handling the filesystem is listening for requests.
I will look at the fuse sources,and find if there is a better way to handle this problem. Thanks!

于 2012年11月06日 20:55, Richard W.M. Jones 写道:
On Tue, Nov 06, 2012 at 07:50:33PM +0800, Gao feng wrote:
于 2012年11月06日 17:11, Richard W.M. Jones 写道:
On Tue, Nov 06, 2012 at 04:54:59PM +0800, Gao feng wrote:
Because libvirt_lxc create a thread to mount fuse filesystem. and then libvirt_lxc will try to access the fuse filesystem.
Without waiting,libvirt_lxc may access fuse before it is mounted.
And I can't find a better way to make accessing fuse after the fuse being mounted,because fuse_main will return until fuse being unmounted,so I don't know how to pass message to tell libvirt_lxc whether the fuse is mounted success.
Oh I see. This is solvable, but I believe that you cannot use fuse_main. You have to look at the fuse sources (quite complex!) and do the individual fuse operations.
Have a look at how libguestfs does it ...
https://github.com/libguestfs/libguestfs/blob/master/src/fuse.c#L911 http://libguestfs.org/guestfs.3.html#mount-local
Thanks for the information.
Can fuse_mount & fuse_new & fuse_loop avoid the waiting?
It seems has the same problem.
It waits, but it doesn't busy wait in a loop. The first access to the filesystem hangs until the thread which is handling the filesystem is listening for requests.
It makes me confuse. There are two threads(A and B). thread A mounts fuse filesystem on mountpoint /mnt/fuse. thread B try to access file /mnt/fuse/meminfo. and we don't know which thread will execute first. The information I got from your comment is that because thread A doesn't mount fuse to /mnt/fuse, when thread B access to the /mnt/fuse/meminfo,it will hang. I am right? If I am right,I don't think this can be implemented by fuse. because the access of fuse file will make a fuse session message, if thread A doesn't call fuse_session_receive_buf to receive this message, The access of the fuse file will failed,not hang. Maybe I misunderstand something. Can you explain this for me? Thanks!

On 11/07/2012 11:54 AM, Gao feng wrote:
于 2012年11月06日 20:55, Richard W.M. Jones 写道:
On Tue, Nov 06, 2012 at 07:50:33PM +0800, Gao feng wrote:
于 2012年11月06日 17:11, Richard W.M. Jones 写道:
On Tue, Nov 06, 2012 at 04:54:59PM +0800, Gao feng wrote:
Because libvirt_lxc create a thread to mount fuse filesystem. and then libvirt_lxc will try to access the fuse filesystem.
Without waiting,libvirt_lxc may access fuse before it is mounted.
And I can't find a better way to make accessing fuse after the fuse being mounted,because fuse_main will return until fuse being unmounted,so I don't know how to pass message to tell libvirt_lxc whether the fuse is mounted success.
Oh I see. This is solvable, but I believe that you cannot use fuse_main. You have to look at the fuse sources (quite complex!) and do the individual fuse operations.
Have a look at how libguestfs does it ...
https://github.com/libguestfs/libguestfs/blob/master/src/fuse.c#L911 http://libguestfs.org/guestfs.3.html#mount-local
Thanks for the information.
Can fuse_mount & fuse_new & fuse_loop avoid the waiting?
It seems has the same problem.
It waits, but it doesn't busy wait in a loop. The first access to the filesystem hangs until the thread which is handling the filesystem is listening for requests.
It makes me confuse.
There are two threads(A and B). thread A mounts fuse filesystem on mountpoint /mnt/fuse. thread B try to access file /mnt/fuse/meminfo. and we don't know which thread will execute first.
The information I got from your comment is that because thread A doesn't mount fuse to /mnt/fuse, when thread B access to the /mnt/fuse/meminfo,it will hang. I am right?
If I'm not wrong, I think Rich means that you should create the mountpoint and the operations using fuse_mount and fuse_new before you create the thread B, then make another thread A using fuse_loop to loop behind. Then if thread B try to access the mountpoint before thread A runs, B will hang until thread A runs into the loop. Thanks, Wanlong Gao
If I am right,I don't think this can be implemented by fuse. because the access of fuse file will make a fuse session message, if thread A doesn't call fuse_session_receive_buf to receive this message, The access of the fuse file will failed,not hang.
Maybe I misunderstand something. Can you explain this for me?
Thanks!
-- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list

On Wed, Nov 07, 2012 at 01:45:27PM +0800, Wanlong Gao wrote:
On 11/07/2012 11:54 AM, Gao feng wrote:
于 2012年11月06日 20:55, Richard W.M. Jones 写道:
On Tue, Nov 06, 2012 at 07:50:33PM +0800, Gao feng wrote:
于 2012年11月06日 17:11, Richard W.M. Jones 写道:
On Tue, Nov 06, 2012 at 04:54:59PM +0800, Gao feng wrote:
Because libvirt_lxc create a thread to mount fuse filesystem. and then libvirt_lxc will try to access the fuse filesystem.
Without waiting,libvirt_lxc may access fuse before it is mounted.
And I can't find a better way to make accessing fuse after the fuse being mounted,because fuse_main will return until fuse being unmounted,so I don't know how to pass message to tell libvirt_lxc whether the fuse is mounted success.
Oh I see. This is solvable, but I believe that you cannot use fuse_main. You have to look at the fuse sources (quite complex!) and do the individual fuse operations.
Have a look at how libguestfs does it ...
https://github.com/libguestfs/libguestfs/blob/master/src/fuse.c#L911 http://libguestfs.org/guestfs.3.html#mount-local
Thanks for the information.
Can fuse_mount & fuse_new & fuse_loop avoid the waiting?
It seems has the same problem.
It waits, but it doesn't busy wait in a loop. The first access to the filesystem hangs until the thread which is handling the filesystem is listening for requests.
It makes me confuse.
There are two threads(A and B). thread A mounts fuse filesystem on mountpoint /mnt/fuse. thread B try to access file /mnt/fuse/meminfo. and we don't know which thread will execute first.
The information I got from your comment is that because thread A doesn't mount fuse to /mnt/fuse, when thread B access to the /mnt/fuse/meminfo,it will hang. I am right?
If I'm not wrong, I think Rich means that you should create the mountpoint and the operations using fuse_mount and fuse_new before you create the thread B, then make another thread A using fuse_loop to loop behind. Then if thread B try to access the mountpoint before thread A runs, B will hang until thread A runs into the loop.
This is right. Rich. -- Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones New in Fedora 11: Fedora Windows cross-compiler. Compile Windows programs, test, and build Windows installers. Over 70 libraries supprt'd http://fedoraproject.org/wiki/MinGW http://www.annexia.org/fedora_mingw

于 2012年11月07日 16:50, Richard W.M. Jones 写道:
On Wed, Nov 07, 2012 at 01:45:27PM +0800, Wanlong Gao wrote:
On 11/07/2012 11:54 AM, Gao feng wrote:
于 2012年11月06日 20:55, Richard W.M. Jones 写道:
On Tue, Nov 06, 2012 at 07:50:33PM +0800, Gao feng wrote:
于 2012年11月06日 17:11, Richard W.M. Jones 写道:
On Tue, Nov 06, 2012 at 04:54:59PM +0800, Gao feng wrote: > Because libvirt_lxc create a thread to mount fuse filesystem. > and then libvirt_lxc will try to access the fuse filesystem. > > Without waiting,libvirt_lxc may access fuse before it is mounted. > > And I can't find a better way to make accessing fuse after the fuse > being mounted,because fuse_main will return until fuse being unmounted,so > I don't know how to pass message to tell libvirt_lxc whether the fuse is > mounted success.
Oh I see. This is solvable, but I believe that you cannot use fuse_main. You have to look at the fuse sources (quite complex!) and do the individual fuse operations.
Have a look at how libguestfs does it ...
https://github.com/libguestfs/libguestfs/blob/master/src/fuse.c#L911 http://libguestfs.org/guestfs.3.html#mount-local
Thanks for the information.
Can fuse_mount & fuse_new & fuse_loop avoid the waiting?
It seems has the same problem.
It waits, but it doesn't busy wait in a loop. The first access to the filesystem hangs until the thread which is handling the filesystem is listening for requests.
It makes me confuse.
There are two threads(A and B). thread A mounts fuse filesystem on mountpoint /mnt/fuse. thread B try to access file /mnt/fuse/meminfo. and we don't know which thread will execute first.
The information I got from your comment is that because thread A doesn't mount fuse to /mnt/fuse, when thread B access to the /mnt/fuse/meminfo,it will hang. I am right?
If I'm not wrong, I think Rich means that you should create the mountpoint and the operations using fuse_mount and fuse_new before you create the thread B, then make another thread A using fuse_loop to loop behind. Then if thread B try to access the mountpoint before thread A runs, B will hang until thread A runs into the loop.
This is right.
With my test and reading fuse source,the thread B will return with error ENOTCONN. Thanks Gao

On Wed, Nov 07, 2012 at 04:55:44PM +0800, Gao feng wrote:
With my test and reading fuse source,the thread B will return with error ENOTCONN.
I think this is because you've not called one of fuse_mount or fuse_new. If you have, thread B should block instead of failing. RIch. -- Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones virt-df lists disk usage of guests without needing to install any software inside the virtual machine. Supports Linux and Windows. http://et.redhat.com/~rjones/virt-df/

于 2012年11月07日 16:59, Richard W.M. Jones 写道:
On Wed, Nov 07, 2012 at 04:55:44PM +0800, Gao feng wrote:
With my test and reading fuse source,the thread B will return with error ENOTCONN.
I think this is because you've not called one of fuse_mount or fuse_new. If you have, thread B should block instead of failing.
Yes,you are right.I make a stupid mistake. :( Thanks again!

More specifically, this is how the libguestfs API works: Main thread Other thread ----------------------------- --------------------- guestfs_mount_local (g, "/mntpoint"); calls: fuse_mount fuse_chan_fd fuse_new fork () or pthread_create () --creates--> Start to access the /mntpoint; blocks until main thread calls fuse_loop guestfs_mount_local_run (g); calls: fuse_loop starts to process Unblocks and starts running requests Note that there is a problem with SELinux and extended attributes: https://bugzilla.redhat.com/show_bug.cgi?id=691389 https://bugzilla.redhat.com/show_bug.cgi?id=811217 Rich. -- Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones libguestfs lets you edit virtual machines. Supports shell scripting, bindings from many languages. http://libguestfs.org

于 2012年11月07日 16:58, Richard W.M. Jones 写道:
More specifically, this is how the libguestfs API works:
Main thread Other thread ----------------------------- ---------------------
guestfs_mount_local (g, "/mntpoint");
calls: fuse_mount fuse_chan_fd fuse_new
fork () or pthread_create () --creates--> Start to access the /mntpoint; blocks until main thread calls fuse_loop
I don't know how the blocking thread is implemented? by fuse self or libguestfs?
guestfs_mount_local_run (g);
calls: fuse_loop starts to process Unblocks and starts running requests
Note that there is a problem with SELinux and extended attributes:
https://bugzilla.redhat.com/show_bug.cgi?id=691389 https://bugzilla.redhat.com/show_bug.cgi?id=811217
Thanks,it's helpful for me. Gao

On Wed, Nov 07, 2012 at 05:12:59PM +0800, Gao feng wrote:
于 2012年11月07日 16:58, Richard W.M. Jones 写道:
More specifically, this is how the libguestfs API works:
Main thread Other thread ----------------------------- ---------------------
guestfs_mount_local (g, "/mntpoint");
calls: fuse_mount fuse_chan_fd fuse_new
fork () or pthread_create () --creates--> Start to access the /mntpoint; blocks until main thread calls fuse_loop
I don't know how the blocking thread is implemented? by fuse self or libguestfs?
The system calls block until FUSE is ready to handle them, so in other words, FUSE/kernel handles it. Rich. -- Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones Read my programming blog: http://rwmj.wordpress.com Fedora now supports 80 OCaml packages (the OPEN alternative to F#) http://cocan.org/getting_started_with_ocaml_on_red_hat_and_fedora

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 e94b478..2608072 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -98,6 +98,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

On Tue, Nov 06, 2012 at 02:07:19PM +0800, Gao feng wrote:
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 e94b478..2608072 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -98,6 +98,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
ACK. Rich. -- Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones New in Fedora 11: Fedora Windows cross-compiler. Compile Windows programs, test, and build Windows installers. Over 70 libraries supprt'd http://fedoraproject.org/wiki/MinGW http://www.annexia.org/fedora_mingw

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 2608072..dd7ede2 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -85,6 +85,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 | 2 +- src/lxc/lxc_fuse.c | 190 ++++++++++++++++++++++++++++++++++++++++++++++++-- src/lxc/lxc_fuse.h | 14 ++++ 4 files changed, 339 insertions(+), 6 deletions(-) diff --git a/src/lxc/lxc_cgroup.c b/src/lxc/lxc_cgroup.c index 9a5ba1a..debbb38 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 cleanup; + } + + 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 cleanup; + } + 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; + +cleanup: + VIR_FREE(statFile); + VIR_FORCE_FCLOSE(statfd); + 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 cleanup; + } + + ret = virLXCCgroupGetMemTotal(cgroup, &meminfo[VIR_LXC_FUSE_MEMTOTAL]); + if (ret < 0) { + virReportSystemError(-ret, "%s", + _("Unable to get memory cgroup total")); + goto cleanup; + } + + ret = virLXCCgroupGetMemUsage(cgroup, &meminfo[VIR_LXC_FUSE_MEMUSAGE]); + if (ret < 0) { + virReportSystemError(-ret, "%s", + _("Unable to get memory cgroup stat usage")); + goto cleanup; + } + + virLXCCgroupGetMemSwapTotal(cgroup, &meminfo[VIR_LXC_FUSE_SWAPTOTAL]); + virLXCCgroupGetMemSwapUsage(cgroup, &meminfo[VIR_LXC_FUSE_SWAPUSAGE]); + + ret = 0; +cleanup: + virCgroupFree(&cgroup); + + return ret; +} typedef struct _virLXCCgroupDevicePolicy virLXCCgroupDevicePolicy; typedef virLXCCgroupDevicePolicy *virLXCCgroupDevicePolicyPtr; diff --git a/src/lxc/lxc_cgroup.h b/src/lxc/lxc_cgroup.h index 6fc68df..29d0aed 100644 --- a/src/lxc/lxc_cgroup.h +++ b/src/lxc/lxc_cgroup.h @@ -25,5 +25,5 @@ # 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 42107d7..ebebb32 100644 --- a/src/lxc/lxc_fuse.c +++ b/src/lxc/lxc_fuse.c @@ -30,26 +30,54 @@ #include <mntent.h> #include "lxc_fuse.h" +#include "lxc_cgroup.h" #include "virterror_internal.h" #include "logging.h" +#include "virfile.h" #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)) { + if (stat(mempath, &sb) < 0) { + res = -errno; + goto cleanup; + } + + stbuf->st_mode = sb.st_mode; + stbuf->st_nlink = 1; + stbuf->st_blksize = sb.st_blksize; + stbuf->st_blocks = sb.st_blocks; + stbuf->st_size = sb.st_size; + stbuf->st_atime = sb.st_atime; + stbuf->st_ctime = sb.st_ctime; + stbuf->st_mtime = sb.st_mtime; } else { res = -ENOENT; } +cleanup: + VIR_FREE(mempath); return res; } @@ -63,14 +91,147 @@ 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) { - return -ENOENT; + int fd; + int res; + + fd = open(path, O_RDONLY); + if (fd == -1) + return -errno; + + if ((res = pread(fd, buf, size, offset)) < 0) + res = -errno; + + VIR_FORCE_CLOSE(fd); + return res; +} + +static int lxcProcReadMeminfo(char *hostpath, virDomainDefPtr def, + char *buf, size_t size, off_t offset) +{ + int copied = 0; + int res; + FILE *fd = NULL; + char line[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 cleanup; + } + + 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 no_memory; + } 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 no_memory; + } else if (STREQ(line, "Buffers")) { + if (virAsprintf(&new_line, "Buffers: %8d KB\n", 0) < 0) + goto no_memory; + } else if (STREQ(line, "Cached")) { + if (virAsprintf(&new_line, "Cached: %8llu KB\n", + meminfo[VIR_LXC_FUSE_CACHED]) < 0) + goto no_memory; + } 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 no_memory; + } 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 no_memory; + } else if (STREQ(line, "Active(anon)")) { + if (virAsprintf(&new_line, "Active(anon): %8llu KB\n", + meminfo[VIR_LXC_FUSE_ACTIVE_ANON]) < 0) + goto no_memory; + } else if (STREQ(line, "Inactive(anon)")) { + if (virAsprintf(&new_line, "Inactive(anon): %8llu KB\n", + meminfo[VIR_LXC_FUSE_INACTIVE_ANON]) < 0) + goto no_memory; + } else if (STREQ(line, "Active(file)")) { + if (virAsprintf(&new_line, "Active(file): %8llu KB\n", + meminfo[VIR_LXC_FUSE_ACTIVE_FILE]) < 0) + goto no_memory; + } else if (STREQ(line, "Inactive(file)")) { + if (virAsprintf(&new_line, "Inactive(file): %8llu KB\n", + meminfo[VIR_LXC_FUSE_INACTIVE_FILE]) < 0) + goto no_memory; + } else if (STREQ(line, "Unevictable")) { + if (virAsprintf(&new_line, "Unevictable: %8llu KB\n", + meminfo[VIR_LXC_FUSE_UNEVICTABLE]) < 0) + goto no_memory; + } 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 no_memory; + } 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 no_memory; + } + *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; + +cleanup: + VIR_FORCE_FCLOSE(fd); + return res; + +no_memory: + virReportOOMError(); + res = -errno; + goto cleanup; } static int lxcProcRead(const char *path ATTRIBUTE_UNUSED, @@ -79,7 +240,26 @@ static int lxcProcRead(const char *path ATTRIBUTE_UNUSED, off_t offset ATTRIBUTE_UNUSED, struct fuse_file_info *fi ATTRIBUTE_UNUSED) { - return -ENOENT; + int res = -ENOENT; + char *hostpath = NULL; + struct fuse_context *context = NULL; + virDomainDefPtr def = NULL; + + if (virAsprintf(&hostpath, "/proc/%s", path) < 0) { + virReportOOMError(); + return -errno; + } + + context = fuse_get_context(); + def = (virDomainDefPtr)context->private_data; + + if (STREQ(path, fuse_meminfo_path)) { + if ((res = lxcProcReadMeminfo(hostpath, def, buf, size, offset)) < 0) + res = lxcProcHostRead(hostpath, buf, size, offset); + } + + VIR_FREE(hostpath); + return res; } static struct fuse_operations lxcProcOper = { diff --git a/src/lxc/lxc_fuse.h b/src/lxc/lxc_fuse.h index 5b3689e..813ae06 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 int lxcRegisterFuseSuccess(void); #endif -- 1.7.7.6

On Tue, Nov 06, 2012 at 02:07:21PM +0800, Gao feng wrote:
+ while (fgets(line, sizeof(line), statfd) != NULL) {
I wonder if libvirt prefers the getline API instead of fgets? Rich. -- Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones Read my programming blog: http://rwmj.wordpress.com Fedora now supports 80 OCaml packages (the OPEN alternative to F#) http://cocan.org/getting_started_with_ocaml_on_red_hat_and_fedora

On Tue, Nov 06, 2012 at 09:00:36AM +0000, Richard W.M. Jones wrote:
On Tue, Nov 06, 2012 at 02:07:21PM +0800, Gao feng wrote:
+ while (fgets(line, sizeof(line), statfd) != NULL) {
I wonder if libvirt prefers the getline API instead of fgets?
I don't think we have a documented policy for this, but getline is a nicer API IMHO 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 Tue, Nov 06, 2012 at 02:07:21PM +0800, Gao feng wrote:
+ unsigned long long meminfo[VIR_LXC_FUSE_MEMMAX]; +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, +};
Any particular reason not to use a struct here? Rich. -- Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones New in Fedora 11: Fedora Windows cross-compiler. Compile Windows programs, test, and build Windows installers. Over 70 libraries supprt'd http://fedoraproject.org/wiki/MinGW http://www.annexia.org/fedora_mingw

于 2012年11月06日 17:04, Richard W.M. Jones 写道:
On Tue, Nov 06, 2012 at 02:07:21PM +0800, Gao feng wrote:
+ unsigned long long meminfo[VIR_LXC_FUSE_MEMMAX]; +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, +};
Any particular reason not to use a struct here?
Rich.
Sorry,can you show me the example? I don't know why we need struct here.

On Tue, Nov 06, 2012 at 05:47:41PM +0800, Gao feng wrote:
于 2012年11月06日 17:04, Richard W.M. Jones 写道:
On Tue, Nov 06, 2012 at 02:07:21PM +0800, Gao feng wrote:
+ unsigned long long meminfo[VIR_LXC_FUSE_MEMMAX]; +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, +};
Any particular reason not to use a struct here?
Rich.
Sorry,can you show me the example? I don't know why we need struct here.
It's not needed, but I was wondering why you didn't use a struct like: struct virLXCMeminfo { unsigned long long memtotal; unsigned long long memusage; // etc }; typedef struct virLXCMeminfo *virLXCMeminfoPtr; Rich. -- Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones New in Fedora 11: Fedora Windows cross-compiler. Compile Windows programs, test, and build Windows installers. Over 70 libraries supprt'd http://fedoraproject.org/wiki/MinGW http://www.annexia.org/fedora_mingw

于 2012年11月06日 17:55, Richard W.M. Jones 写道:
On Tue, Nov 06, 2012 at 05:47:41PM +0800, Gao feng wrote:
于 2012年11月06日 17:04, Richard W.M. Jones 写道:
On Tue, Nov 06, 2012 at 02:07:21PM +0800, Gao feng wrote:
+ unsigned long long meminfo[VIR_LXC_FUSE_MEMMAX]; +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, +};
Any particular reason not to use a struct here?
Rich.
Sorry,can you show me the example? I don't know why we need struct here.
It's not needed, but I was wondering why you didn't use a struct like:
struct virLXCMeminfo { unsigned long long memtotal; unsigned long long memusage; // etc }; typedef struct virLXCMeminfo *virLXCMeminfoPtr;
Ok,it looks better,I will change the codes. Thanks! Gao

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 db1f6ed..02e071d 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

On Tue, Nov 06, 2012 at 02:07:22PM +0800, Gao feng wrote:
+ int ret = 0;
In this case, it's better NOT to initialize 'ret'. Rich. -- Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones Read my programming blog: http://rwmj.wordpress.com Fedora now supports 80 OCaml packages (the OPEN alternative to F#) http://cocan.org/getting_started_with_ocaml_on_red_hat_and_fedora

On Tue, Nov 06, 2012 at 02:07:17PM +0800, Gao feng wrote:
add a configure option --with-fuse to prepare introduction of fuse support for libvirt lxc.
With help from Daniel and Richard.
Signed-off-by: Gao feng <gaofeng@cn.fujitsu.com> --- configure.ac | 29 +++++++++++++++++++++++++++++ libvirt.spec.in | 9 +++++++++ 2 files changed, 38 insertions(+), 0 deletions(-)
diff --git a/configure.ac b/configure.ac index 9108ea8..495cbfa 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 @@ -1859,6 +1860,29 @@ 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 +AS_IF([test "x$with_fuse" != "xno"], + [PKG_CHECK_MODULES([FUSE], [fuse >= $FUSE_REQUIRED], + [with_fuse=yes + AC_SUBST([FUSE_CFLAGS]) + AC_SUBST([FUSE_LIBS]) + AC_DEFINE_UNQUOTED([HAVE_FUSE], 1, [whether fuse is available for libvirt lxc]) + ], + [if test "x$with_fuse" = "xyes" ; then + AC_MSG_ERROR([You must install fuse library to compile libvirt]) + else + with_fuse=no + fi + ]) + ]) +AM_CONDITIONAL([HAVE_FUSE], [test "x$with_fuse" = "xyes"])
dnl virsh libraries AC_CHECK_HEADERS([readline/readline.h]) @@ -3163,6 +3187,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 b6ded04..55408b6 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} @@ -503,6 +504,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 @@ -1186,6 +1190,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 @@ -1289,6 +1297,7 @@ autoreconf -if %{?_without_numactl} \ %{?_without_numad} \ %{?_without_capng} \ + %{?_without_fuse} \ %{?_without_netcf} \ %{?_without_selinux} \ %{?_with_selinux_mount} \ -- 1.7.7.6
Look OK here, ACK. Rich. -- Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones virt-df lists disk usage of guests without needing to install any software inside the virtual machine. Supports Linux and Windows. http://et.redhat.com/~rjones/virt-df/
participants (4)
-
Daniel P. Berrange
-
Gao feng
-
Richard W.M. Jones
-
Wanlong Gao