From 9ba230d4f2f031e2fda2b6aa98a290394c2ddaaf Mon Sep 17 00:00:00 2001 From: Ian Main Date: Thu, 5 Sep 2013 12:04:33 +0100 Subject: [PATCH] Use loop-control to allocate loop device. This patch changes virFileLoopDeviceOpen() to use the new loop-control device to allocate a new loop device. If this behavior is unsupported we fall back to the previous method of searching /dev for a free device. With this patch you can start as many image based LXC domains as you like (well almost). Fixes bug https://bugzilla.redhat.com/show_bug.cgi?id=995543 --- configure.ac | 12 ++++++++ src/util/virfile.c | 70 +++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 81 insertions(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index f853e03034..63075559d2 100644 --- a/configure.ac +++ b/configure.ac @@ -921,6 +921,18 @@ if test "$with_lxc" = "yes" || test "$with_lxc" = "check"; then AC_MSG_ERROR([Required kernel features for LXC were not found]) fi ]) + AC_LINK_IFELSE([AC_LANG_PROGRAM( + [[ + #include + #include + #include + ]], [[ + unshare(!(LOOP_CTL_GET_FREE)); + ]])], [ + AC_DEFINE([HAVE_DECL_LOOP_CTL_GET_FREE], [1], + [Define to 1 if you have the declaration of `LOOP_CTL_GET_FREE', + and to 0 if you don't.]) + ]) fi if test "$with_lxc" = "yes" ; then AC_DEFINE_UNQUOTED([WITH_LXC], 1, [whether LXC driver is enabled]) diff --git a/src/util/virfile.c b/src/util/virfile.c index 7af0843f45..feac3c98e1 100644 --- a/src/util/virfile.c +++ b/src/util/virfile.c @@ -528,7 +528,56 @@ int virFileUpdatePerm(const char *path, #if defined(__linux__) && HAVE_DECL_LO_FLAGS_AUTOCLEAR -static int virFileLoopDeviceOpen(char **dev_name) + +# if HAVE_DECL_LOOP_CTL_GET_FREE + +/* virFileLoopDeviceOpenLoopCtl() returns -1 when a real failure has occured + * while in the process of allocating or opening the loop device. On success + * we return 0 and modify the fd to the appropriate file descriptor. + * If /dev/loop-control does not exist, we return 0 and do not set fd. */ + +static int virFileLoopDeviceOpenLoopCtl(char **dev_name, int *fd) +{ + int devnr; + int ctl_fd; + char *looppath = NULL; + + VIR_DEBUG("Opening loop-control device"); + if ((ctl_fd = open("/dev/loop-control", O_RDWR)) < 0) { + if (errno == ENOENT) + return 0; + + virReportSystemError(errno, "%s", + _("Unable to open /dev/loop-control")); + return -1; + } + + if ((devnr = ioctl(ctl_fd, LOOP_CTL_GET_FREE)) < 0) { + virReportSystemError(errno, "%s", + _("Unable to get free loop device via ioctl")); + close(ctl_fd); + return -1; + } + close(ctl_fd); + + VIR_DEBUG("Found free loop device number %i", devnr); + + if (virAsprintf(&looppath, "/dev/loop%i", devnr) < 0) + return -1; + + if ((*fd = open(looppath, O_RDWR)) < 0) { + virReportSystemError(errno, + _("Unable to open %s"), looppath); + VIR_FREE(looppath); + return -1; + } + + *dev_name = looppath; + return 0; +} +# endif /* HAVE_DECL_LOOP_CTL_GET_FREE */ + +static int virFileLoopDeviceOpenSearch(char **dev_name) { int fd = -1; DIR *dh = NULL; @@ -601,6 +650,25 @@ cleanup: return fd; } +static int virFileLoopDeviceOpen(char **dev_name) +{ + int loop_fd = -1; + +# if HAVE_DECL_LOOP_CTL_GET_FREE + if (virFileLoopDeviceOpenLoopCtl(dev_name, &loop_fd) < 0) + return -1; + + VIR_DEBUG("Return from loop-control got fd %d\n", loop_fd); + + if (loop_fd >= 0) + return loop_fd; +# endif /* HAVE_DECL_LOOP_CTL_GET_FREE */ + + /* Without the loop control device we just use the old technique. */ + loop_fd = virFileLoopDeviceOpenSearch(dev_name); + + return loop_fd; +} int virFileLoopDeviceAssociate(const char *file, char **dev)