[libvirt] [PATCH v3 15/16] Add an API for re-mounting cgroups, to isolate the process location

Daniel P. Berrange berrange at redhat.com
Wed Apr 10 10:08:24 UTC 2013


From: "Daniel P. Berrange" <berrange at redhat.com>

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 at redhat.com>
---
 configure.ac                |   2 +-
 include/libvirt/virterror.h |   1 +
 src/libvirt_private.syms    |   1 +
 src/util/vircgroup.c        | 127 ++++++++++++++++++++++++++++++++++++++++++++
 src/util/vircgroup.h        |   4 ++
 src/util/virerror.c         |   1 +
 6 files changed, 135 insertions(+), 1 deletion(-)

diff --git a/configure.ac b/configure.ac
index 11b332f..529d979 100644
--- a/configure.ac
+++ b/configure.ac
@@ -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>]])
 
diff --git a/include/libvirt/virterror.h b/include/libvirt/virterror.h
index 4cd9256..3864a31 100644
--- a/include/libvirt/virterror.h
+++ b/include/libvirt/virterror.h
@@ -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
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 52c3bcb..8014ea1 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -1113,6 +1113,7 @@ virCgroupGetMemoryUsage;
 virCgroupGetMemSwapHardLimit;
 virCgroupGetMemSwapUsage;
 virCgroupHasController;
+virCgroupIsolateMount;
 virCgroupKill;
 virCgroupKillPainfully;
 virCgroupKillRecursive;
diff --git a/src/util/vircgroup.c b/src/util/vircgroup.c
index 14af16e..e8abc70 100644
--- a/src/util/vircgroup.c
+++ b/src/util/vircgroup.c
@@ -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");
@@ -2382,3 +2388,124 @@ int virCgroupKillPainfully(virCgroupPtr group ATTRIBUTE_UNUSED)
     return -ENOSYS;
 }
 #endif /* HAVE_KILL, HAVE_MNTENT_H, HAVE_GETMNTENT_R */
+
+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;
+}
diff --git a/src/util/vircgroup.h b/src/util/vircgroup.h
index 936e09b..61e6f91 100644
--- a/src/util/vircgroup.h
+++ b/src/util/vircgroup.h
@@ -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__ */
diff --git a/src/util/virerror.c b/src/util/virerror.c
index c30642a..8a329a9 100644
--- a/src/util/virerror.c
+++ b/src/util/virerror.c
@@ -119,6 +119,7 @@ VIR_ENUM_IMPL(virErrorDomain, VIR_ERR_DOMAIN_LAST,
               "Lock Space",
               "Init control",
               "Identity",
+              "Cgroup",
     )
 
 
-- 
1.8.1.4




More information about the libvir-list mailing list