Replace LXC cgroup mount code with call to virCgroupIsolateMount

The LXC driver currently has code to detect cgroups mounts
and then re-mount them inside the new root filesystem. Replace
this fragile code with a call to virCgroupIsolateMount.

Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
This commit is contained in:
Daniel P. Berrange 2013-04-05 12:50:27 +01:00
parent 1da631ecf3
commit ff66b45e2b

View File

@ -35,7 +35,6 @@
#include <sys/stat.h>
#include <unistd.h>
#include <mntent.h>
#include <dirent.h>
#include <sys/reboot.h>
#include <linux/reboot.h>
@ -1735,227 +1734,6 @@ static int lxcContainerSetupAllHostdevs(virDomainDefPtr vmDef,
}
struct lxcContainerCGroup {
const char *dir;
const char *linkDest;
};
static void lxcContainerCGroupFree(struct lxcContainerCGroup *mounts,
size_t nmounts)
{
size_t i;
if (!mounts)
return;
for (i = 0 ; i < nmounts ; i++) {
VIR_FREE(mounts[i].dir);
VIR_FREE(mounts[i].linkDest);
}
VIR_FREE(mounts);
}
static int lxcContainerIdentifyCGroups(struct lxcContainerCGroup **mountsret,
size_t *nmountsret,
char **root)
{
FILE *procmnt = NULL;
struct mntent mntent;
struct dirent *dent;
char mntbuf[1024];
int ret = -1;
struct lxcContainerCGroup *mounts = NULL;
size_t nmounts = 0;
DIR *dh = NULL;
char *path = NULL;
*mountsret = NULL;
*nmountsret = 0;
*root = NULL;
VIR_DEBUG("Finding cgroups mount points of type cgroup");
if (!(procmnt = setmntent("/proc/mounts", "r"))) {
virReportSystemError(errno, "%s",
_("Failed to read /proc/mounts"));
return -1;
}
while (getmntent_r(procmnt, &mntent, mntbuf, sizeof(mntbuf)) != NULL) {
VIR_DEBUG("Got %s", mntent.mnt_dir);
if (STRNEQ(mntent.mnt_type, "cgroup"))
continue;
if (!*root) {
char *tmp;
if (!(*root = strdup(mntent.mnt_dir))) {
virReportOOMError();
goto cleanup;
}
tmp = strrchr(*root, '/');
*tmp = '\0';
} else if (!STRPREFIX(mntent.mnt_dir, *root)) {
virReportError(VIR_ERR_INTERNAL_ERROR,
_("Cgroup %s is not mounted under %s"),
mntent.mnt_dir, *root);
goto cleanup;
}
/* Skip named mounts with no controller since they're
* for application use only ie systemd */
if (strstr(mntent.mnt_opts, "name="))
continue;
if (VIR_EXPAND_N(mounts, nmounts, 1) < 0) {
virReportOOMError();
goto cleanup;
}
if (!(mounts[nmounts-1].dir = strdup(mntent.mnt_dir))) {
virReportOOMError();
goto cleanup;
}
VIR_DEBUG("Grabbed '%s'", mntent.mnt_dir);
}
if (!*root) {
VIR_DEBUG("No mounted cgroups found");
ret = 0;
goto cleanup;
}
VIR_DEBUG("Checking for symlinks in %s", *root);
if (!(dh = opendir(*root))) {
virReportSystemError(errno,
_("Unable to read directory %s"),
*root);
goto cleanup;
}
while ((dent = readdir(dh)) != NULL) {
ssize_t rv;
/* The cgroups links are just relative to the local
* dir so we don't need a large buf */
char linkbuf[100];
if (dent->d_name[0] == '.')
continue;
VIR_DEBUG("Checking entry %s", dent->d_name);
if (virAsprintf(&path, "%s/%s", *root, dent->d_name) < 0) {
virReportOOMError();
goto cleanup;
}
if ((rv = readlink(path, linkbuf, sizeof(linkbuf)-1)) < 0) {
if (errno != EINVAL) {
virReportSystemError(errno,
_("Unable to resolve link %s"),
path);
VIR_FREE(path);
goto cleanup;
}
/* Ok not a link */
VIR_FREE(path);
} else {
linkbuf[rv] = '\0';
VIR_DEBUG("Got a link %s to %s", path, linkbuf);
if (VIR_EXPAND_N(mounts, nmounts, 1) < 0) {
virReportOOMError();
goto cleanup;
}
if (!(mounts[nmounts-1].linkDest = strdup(linkbuf))) {
virReportOOMError();
goto cleanup;
}
mounts[nmounts-1].dir = path;
path = NULL;
}
}
*mountsret = mounts;
*nmountsret = nmounts;
ret = 0;
cleanup:
closedir(dh);
endmntent(procmnt);
VIR_FREE(path);
if (ret < 0) {
lxcContainerCGroupFree(mounts, nmounts);
VIR_FREE(*root);
}
return ret;
}
static int lxcContainerMountCGroups(struct lxcContainerCGroup *mounts,
size_t nmounts,
const char *root,
char *sec_mount_options)
{
size_t i;
char *opts = NULL;
VIR_DEBUG("Mounting cgroups at '%s'", root);
if (virFileMakePath(root) < 0) {
virReportSystemError(errno,
_("Unable to create directory %s"),
root);
return -1;
}
if (virAsprintf(&opts,
"mode=755,size=65536%s", sec_mount_options) < 0) {
virReportOOMError();
return -1;
}
if (mount("tmpfs", root, "tmpfs", MS_NOSUID|MS_NODEV|MS_NOEXEC, opts) < 0) {
VIR_FREE(opts);
virReportSystemError(errno,
_("Failed to mount %s on %s type %s"),
"tmpfs", root, "tmpfs");
return -1;
}
VIR_FREE(opts);
for (i = 0 ; i < nmounts ; i++) {
if (mounts[i].linkDest) {
VIR_DEBUG("Link mount point '%s' to '%s'",
mounts[i].dir, mounts[i].linkDest);
if (symlink(mounts[i].linkDest, mounts[i].dir) < 0) {
virReportSystemError(errno,
_("Unable to symlink directory %s to %s"),
mounts[i].dir, mounts[i].linkDest);
return -1;
}
} else {
VIR_DEBUG("Create mount point '%s'", mounts[i].dir);
if (virFileMakePath(mounts[i].dir) < 0) {
virReportSystemError(errno,
_("Unable to create directory %s"),
mounts[i].dir);
return -1;
}
if (mount("cgroup", mounts[i].dir, "cgroup",
0, mounts[i].dir + strlen(root) + 1) < 0) {
virReportSystemError(errno,
_("Failed to mount cgroup on '%s'"),
mounts[i].dir);
return -1;
}
}
}
return 0;
}
/* Got a FS mapped to /, we're going the pivot_root
* approach to do a better-chroot-than-chroot
* this is based on this thread http://lkml.org/lkml/2008/3/5/29
@ -1966,10 +1744,9 @@ static int lxcContainerSetupPivotRoot(virDomainDefPtr vmDef,
size_t nttyPaths,
virSecurityManagerPtr securityDriver)
{
struct lxcContainerCGroup *mounts = NULL;
size_t nmounts = 0;
virCgroupPtr cgroup = NULL;
int rc;
int ret = -1;
char *cgroupRoot = NULL;
char *sec_mount_options;
if (!(sec_mount_options = virSecurityManagerGetMountOptions(securityDriver, vmDef)))
@ -1977,8 +1754,11 @@ static int lxcContainerSetupPivotRoot(virDomainDefPtr vmDef,
/* Before pivoting we need to identify any
* cgroups controllers that are mounted */
if (lxcContainerIdentifyCGroups(&mounts, &nmounts, &cgroupRoot) < 0)
if ((rc = virCgroupNewSelf(&cgroup)) != 0) {
virReportSystemError(-rc, "%s",
_("Cannot identify cgroup placement"));
goto cleanup;
}
/* Ensure the root filesystem is mounted */
if (lxcContainerPrepareRoot(vmDef, root) < 0)
@ -2017,8 +1797,7 @@ static int lxcContainerSetupPivotRoot(virDomainDefPtr vmDef,
/* Now we can re-mount the cgroups controllers in the
* same configuration as before */
if (lxcContainerMountCGroups(mounts, nmounts,
cgroupRoot, sec_mount_options) < 0)
if (virCgroupIsolateMount(cgroup, "/.oldroot/", sec_mount_options) < 0)
goto cleanup;
/* Mounts /dev/pts */
@ -2048,8 +1827,7 @@ static int lxcContainerSetupPivotRoot(virDomainDefPtr vmDef,
ret = 0;
cleanup:
lxcContainerCGroupFree(mounts, nmounts);
VIR_FREE(cgroupRoot);
virCgroupFree(&cgroup);
VIR_FREE(sec_mount_options);
return ret;
}