]> git.ipfire.org Git - thirdparty/libvirt.git/commitdiff
Add an API for re-mounting cgroups, to isolate the process location
authorDaniel P. Berrange <berrange@redhat.com>
Fri, 5 Apr 2013 11:48:47 +0000 (12:48 +0100)
committerDaniel P. Berrange <berrange@redhat.com>
Mon, 15 Apr 2013 16:35:32 +0000 (17:35 +0100)
Add a virCgroupIsolateMount method which looks at where the
current process is place in the cgroups (eg /system/demo.lxc.libvirt)
and then remounts the cgroups such that this sub-directory
becomes the root directory from the current process' POV.

Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
configure.ac
include/libvirt/virterror.h
src/libvirt_private.syms
src/util/vircgroup.c
src/util/vircgroup.h
src/util/virerror.c

index 789d1c9cfdf555f655767e41d80426a61a8e62e9..89dae3def33275b15297098433d8dbf985ad454b 100644 (file)
@@ -208,7 +208,7 @@ dnl Availability of various common headers (non-fatal if missing).
 AC_CHECK_HEADERS([pwd.h paths.h regex.h sys/un.h \
   sys/poll.h syslog.h mntent.h net/ethernet.h linux/magic.h \
   sys/un.h sys/syscall.h netinet/tcp.h ifaddrs.h libtasn1.h \
-  sys/ucred.h])
+  sys/ucred.h sys/mount.h])
 dnl Check whether endian provides handy macros.
 AC_CHECK_DECLS([htole64], [], [], [[#include <endian.h>]])
 
index 4cd9256c66b3bd3a86e120568410d567447cc500..3864a31b31af968be535657c8dc1710176fea537 100644 (file)
@@ -116,6 +116,7 @@ typedef enum {
     VIR_FROM_LOCKSPACE = 51,    /* Error from lockspace */
     VIR_FROM_INITCTL = 52,      /* Error from initctl device communication */
     VIR_FROM_IDENTITY = 53,     /* Error from identity code */
+    VIR_FROM_CGROUP = 54,       /* Error from cgroups */
 
 # ifdef VIR_ENUM_SENTINELS
     VIR_ERR_DOMAIN_LAST
index a8e2cb6ad4fb79494fdd0bde38c2c12fc4719d14..30fdcd72d884a2274173d14d5a8b8829e7a01e09 100644 (file)
@@ -1118,6 +1118,7 @@ virCgroupGetMemoryUsage;
 virCgroupGetMemSwapHardLimit;
 virCgroupGetMemSwapUsage;
 virCgroupHasController;
+virCgroupIsolateMount;
 virCgroupKill;
 virCgroupKillPainfully;
 virCgroupKillRecursive;
index f2919e8836f801de1d901daa0daf05f8226c78b5..84131475572c6692b9225ce845fc0ca9d7b5b06f 100644 (file)
@@ -27,6 +27,9 @@
 #if defined HAVE_MNTENT_H && defined HAVE_GETMNTENT_R
 # include <mntent.h>
 #endif
+#if defined HAVE_SYS_MOUNT_H
+# include <sys/mount.h>
+#endif
 #include <fcntl.h>
 #include <string.h>
 #include <errno.h>
@@ -42,6 +45,7 @@
 
 #include "virutil.h"
 #include "viralloc.h"
+#include "virerror.h"
 #include "virlog.h"
 #include "virfile.h"
 #include "virhash.h"
@@ -49,6 +53,8 @@
 
 #define CGROUP_MAX_VAL 512
 
+#define VIR_FROM_THIS VIR_FROM_CGROUP
+
 VIR_ENUM_IMPL(virCgroupController, VIR_CGROUP_CONTROLLER_LAST,
               "cpu", "cpuacct", "cpuset", "memory", "devices",
               "freezer", "blkio");
@@ -2385,3 +2391,133 @@ int virCgroupKillPainfully(virCgroupPtr group ATTRIBUTE_UNUSED)
     return -ENOSYS;
 }
 #endif /* HAVE_KILL, HAVE_MNTENT_H, HAVE_GETMNTENT_R */
+
+#ifdef __linux__
+static char *virCgroupIdentifyRoot(virCgroupPtr group)
+{
+    char *ret = NULL;
+    size_t i;
+
+    for (i = 0 ; i < VIR_CGROUP_CONTROLLER_LAST ; i++) {
+        char *tmp;
+        if (!group->controllers[i].mountPoint)
+            continue;
+        if (!(tmp = strrchr(group->controllers[i].mountPoint, '/'))) {
+            virReportError(VIR_ERR_INTERNAL_ERROR,
+                           _("Could not find directory separator in %s"),
+                           group->controllers[i].mountPoint);
+            return NULL;
+        }
+
+        tmp[0] = '\0';
+        ret = strdup(group->controllers[i].mountPoint);
+        tmp[0] = '/';
+        if (!ret) {
+            virReportOOMError();
+            return NULL;
+        }
+        return ret;
+    }
+
+    virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                   _("Could not find any mounted controllers"));
+    return NULL;
+}
+
+
+int virCgroupIsolateMount(virCgroupPtr group, const char *oldroot,
+                          const char *mountopts)
+{
+    int ret = -1;
+    size_t i;
+    char *opts = NULL;
+    char *root = NULL;
+
+    if (!(root = virCgroupIdentifyRoot(group)))
+        return -1;
+
+    VIR_DEBUG("Mounting cgroups at '%s'", root);
+
+    if (virFileMakePath(root) < 0) {
+        virReportSystemError(errno,
+                             _("Unable to create directory %s"),
+                             root);
+        goto cleanup;
+    }
+
+    if (virAsprintf(&opts,
+                    "mode=755,size=65536%s", mountopts) < 0) {
+        virReportOOMError();
+        goto cleanup;
+    }
+
+    if (mount("tmpfs", root, "tmpfs", MS_NOSUID|MS_NODEV|MS_NOEXEC, opts) < 0) {
+        virReportSystemError(errno,
+                             _("Failed to mount %s on %s type %s"),
+                             "tmpfs", root, "tmpfs");
+        goto cleanup;
+    }
+
+    for (i = 0 ; i < VIR_CGROUP_CONTROLLER_LAST ; i++) {
+        if (!group->controllers[i].mountPoint)
+            continue;
+
+        if (!virFileExists(group->controllers[i].mountPoint)) {
+            char *src;
+            if (virAsprintf(&src, "%s%s%s",
+                            oldroot,
+                            group->controllers[i].mountPoint,
+                            group->controllers[i].placement) < 0) {
+                virReportOOMError();
+                goto cleanup;
+            }
+
+            VIR_DEBUG("Create mount point '%s'", group->controllers[i].mountPoint);
+            if (virFileMakePath(group->controllers[i].mountPoint) < 0) {
+                virReportSystemError(errno,
+                                     _("Unable to create directory %s"),
+                                     group->controllers[i].mountPoint);
+                VIR_FREE(src);
+                goto cleanup;
+            }
+
+            if (mount(src, group->controllers[i].mountPoint, NULL, MS_BIND, NULL) < 0) {
+                virReportSystemError(errno,
+                                     _("Failed to bind cgroup '%s' on '%s'"),
+                                     src, group->controllers[i].mountPoint);
+            VIR_FREE(src);
+                goto cleanup;
+            }
+
+            VIR_FREE(src);
+        }
+
+        if (group->controllers[i].linkPoint) {
+            VIR_DEBUG("Link mount point '%s' to '%s'",
+                      group->controllers[i].mountPoint,
+                      group->controllers[i].linkPoint);
+            if (symlink(group->controllers[i].mountPoint,
+                        group->controllers[i].linkPoint) < 0) {
+                virReportSystemError(errno,
+                                     _("Unable to symlink directory %s to %s"),
+                                     group->controllers[i].mountPoint,
+                                     group->controllers[i].linkPoint);
+                return -1;
+            }
+        }
+    }
+    ret = 0;
+
+cleanup:
+    VIR_FREE(root);
+    VIR_FREE(opts);
+    return ret;
+}
+#else /* __linux__ */
+int virCgroupIsolateMount(virCgroupPtr group ATTRIBUTE_UNUSED,
+                          const char *oldroot ATTRIBUTE_UNUSED,
+                          const char *mountopts ATTRIBUTE_UNUSED)
+{
+    return -ENOSYS;
+}
+#endif /* __linux__ */
index 936e09b73ebb8a9cd90fcbb25cee8055d5e6bcbf..61e6f9129ac520e9b3fb80cdf12a8b546838a8c6 100644 (file)
@@ -183,4 +183,8 @@ int virCgroupKill(virCgroupPtr group, int signum);
 int virCgroupKillRecursive(virCgroupPtr group, int signum);
 int virCgroupKillPainfully(virCgroupPtr group);
 
+int virCgroupIsolateMount(virCgroupPtr group,
+                          const char *oldroot,
+                          const char *mountopts);
+
 #endif /* __VIR_CGROUP_H__ */
index c30642aca6a0c2851e1eee5fde7469ad510e1619..8a329a98258c5b9019a20096e83ee0eae6a0b81e 100644 (file)
@@ -119,6 +119,7 @@ VIR_ENUM_IMPL(virErrorDomain, VIR_ERR_DOMAIN_LAST,
               "Lock Space",
               "Init control",
               "Identity",
+              "Cgroup",
     )