Add an API for re-mounting cgroups, to isolate the process location

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>
This commit is contained in:
Daniel P. Berrange 2013-04-05 12:48:47 +01:00
parent 83336118db
commit 1da631ecf3
6 changed files with 144 additions and 1 deletions

View 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>]])

View 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

View File

@ -1118,6 +1118,7 @@ virCgroupGetMemoryUsage;
virCgroupGetMemSwapHardLimit;
virCgroupGetMemSwapUsage;
virCgroupHasController;
virCgroupIsolateMount;
virCgroupKill;
virCgroupKillPainfully;
virCgroupKillRecursive;

View 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__ */

View 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__ */

View File

@ -119,6 +119,7 @@ VIR_ENUM_IMPL(virErrorDomain, VIR_ERR_DOMAIN_LAST,
"Lock Space",
"Init control",
"Identity",
"Cgroup",
)