LXC: Creating devices for container on host side

user namespace doesn't allow to create devices in
uninit userns. We should create devices on host side.

We first mount tmpfs on dev directroy under state dir
of container. then create devices under this dev dir.

Finally in container, mount the dev directroy created
on host to the /dev/ directroy of container.

Signed-off-by: Gao feng <gaofeng@cn.fujitsu.com>
This commit is contained in:
Gao feng 2013-06-07 15:12:22 +08:00 committed by Daniel P. Berrange
parent 9a085a228c
commit e1d32bb955
2 changed files with 134 additions and 52 deletions

View File

@ -683,7 +683,7 @@ err:
}
static int lxcContainerMountBasicFS(char *sec_mount_options)
static int lxcContainerMountBasicFS(void)
{
const struct {
const char *src;
@ -709,9 +709,8 @@ static int lxcContainerMountBasicFS(char *sec_mount_options)
#endif
};
int i, rc = -1;
char *opts = NULL;
VIR_DEBUG("Mounting basic filesystems sec_mount_options=%s", sec_mount_options);
VIR_DEBUG("Mounting basic filesystems");
for (i = 0; i < ARRAY_CARDINALITY(mnts); i++) {
const char *srcpath = NULL;
@ -750,31 +749,10 @@ static int lxcContainerMountBasicFS(char *sec_mount_options)
}
}
/*
* tmpfs is limited to 64kb, since we only have device nodes in there
* and don't want to DOS the entire OS RAM usage
*/
if (virAsprintf(&opts,
"mode=755,size=65536%s", sec_mount_options) < 0) {
virReportOOMError();
goto cleanup;
}
VIR_DEBUG("Mount devfs on /dev type=tmpfs flags=%x, opts=%s",
MS_NOSUID, opts);
if (mount("devfs", "/dev", "tmpfs", MS_NOSUID, opts) < 0) {
virReportSystemError(errno,
_("Failed to mount %s on %s type %s (%s)"),
"devfs", "/dev", "tmpfs", opts);
goto cleanup;
}
rc = 0;
cleanup:
VIR_DEBUG("rc=%d", rc);
VIR_FREE(opts);
return rc;
}
@ -811,6 +789,30 @@ static int lxcContainerMountProcFuse(virDomainDefPtr def ATTRIBUTE_UNUSED,
}
#endif
static int lxcContainerMountFSDev(virDomainDefPtr def,
const char *stateDir)
{
int ret;
char *path = NULL;
VIR_DEBUG("Mount /dev/ stateDir=%s", stateDir);
if ((ret = virAsprintf(&path, "/.oldroot/%s/%s.dev",
stateDir, def->name)) < 0)
return ret;
VIR_DEBUG("Tring to move %s to /dev", path);
if ((ret = mount(path, "/dev", NULL, MS_MOVE, NULL)) < 0) {
virReportSystemError(errno,
_("Failed to mount %s on /dev"),
path);
}
VIR_FREE(path);
return ret;
}
static int lxcContainerMountFSDevPTS(virDomainDefPtr def,
const char *stateDir)
{
@ -847,21 +849,9 @@ cleanup:
return ret;
}
static int lxcContainerPopulateDevices(char **ttyPaths, size_t nttyPaths)
static int lxcContainerSetupDevices(char **ttyPaths, size_t nttyPaths)
{
size_t i;
const struct {
int maj;
int min;
mode_t mode;
const char *path;
} devs[] = {
{ LXC_DEV_MAJ_MEMORY, LXC_DEV_MIN_NULL, 0666, "/dev/null" },
{ LXC_DEV_MAJ_MEMORY, LXC_DEV_MIN_ZERO, 0666, "/dev/zero" },
{ LXC_DEV_MAJ_MEMORY, LXC_DEV_MIN_FULL, 0666, "/dev/full" },
{ LXC_DEV_MAJ_MEMORY, LXC_DEV_MIN_RANDOM, 0666, "/dev/random" },
{ LXC_DEV_MAJ_MEMORY, LXC_DEV_MIN_URANDOM, 0666, "/dev/urandom" },
};
const struct {
const char *src;
const char *dst;
@ -872,18 +862,6 @@ static int lxcContainerPopulateDevices(char **ttyPaths, size_t nttyPaths)
{ "/proc/self/fd", "/dev/fd" },
};
/* Populate /dev/ with a few important bits */
for (i = 0; i < ARRAY_CARDINALITY(devs); i++) {
dev_t dev = makedev(devs[i].maj, devs[i].min);
if (mknod(devs[i].path, S_IFCHR, dev) < 0 ||
chmod(devs[i].path, devs[i].mode)) {
virReportSystemError(errno,
_("Failed to make device %s"),
devs[i].path);
return -1;
}
}
for (i = 0; i < ARRAY_CARDINALITY(links); i++) {
if (symlink(links[i].src, links[i].dst) < 0) {
virReportSystemError(errno,
@ -1802,7 +1780,7 @@ static int lxcContainerSetupPivotRoot(virDomainDefPtr vmDef,
goto cleanup;
/* Mounts the core /proc, /sys, etc filesystems */
if (lxcContainerMountBasicFS(sec_mount_options) < 0)
if (lxcContainerMountBasicFS() < 0)
goto cleanup;
/* Mounts /proc/meminfo etc sysinfo */
@ -1814,12 +1792,16 @@ static int lxcContainerSetupPivotRoot(virDomainDefPtr vmDef,
if (virCgroupIsolateMount(cgroup, "/.oldroot/", sec_mount_options) < 0)
goto cleanup;
/* Mounts /dev */
if (lxcContainerMountFSDev(vmDef, stateDir) < 0)
goto cleanup;
/* Mounts /dev/pts */
if (lxcContainerMountFSDevPTS(vmDef, stateDir) < 0)
goto cleanup;
/* Populates device nodes in /dev/ */
if (lxcContainerPopulateDevices(ttyPaths, nttyPaths) < 0)
/* Setup device nodes in /dev/ */
if (lxcContainerSetupDevices(ttyPaths, nttyPaths) < 0)
goto cleanup;
/* Sets up any non-root mounts from guest config */

View File

@ -1192,6 +1192,103 @@ cleanup:
return ret;
}
static int virLXCControllerSetupDev(virLXCControllerPtr ctrl)
{
char *mount_options = NULL;
char *opts = NULL;
char *dev = NULL;
int ret = -1;
VIR_DEBUG("Setting up /dev/ for container");
mount_options = virSecurityManagerGetMountOptions(ctrl->securityManager,
ctrl->def);
if (virAsprintf(&dev, "/%s/%s.dev",
LXC_STATE_DIR, ctrl->def->name) < 0) {
virReportOOMError();
goto cleanup;
}
if (virFileMakePath(dev) < 0) {
virReportSystemError(errno,
_("Failed to make path %s"), dev);
goto cleanup;
}
/*
* tmpfs is limited to 64kb, since we only have device nodes in there
* and don't want to DOS the entire OS RAM usage
*/
if (virAsprintf(&opts,
"mode=755,size=65536%s", mount_options) < 0) {
virReportOOMError();
goto cleanup;
}
VIR_DEBUG("Mount devfs on %s type=tmpfs flags=%x, opts=%s",
dev, MS_NOSUID, opts);
if (mount("devfs", dev, "tmpfs", MS_NOSUID, opts) < 0) {
virReportSystemError(errno,
_("Failed to mount devfs on %s type %s (%s)"),
dev, "tmpfs", opts);
goto cleanup;
}
ret = 0;
cleanup:
VIR_FREE(opts);
VIR_FREE(mount_options);
VIR_FREE(dev);
return ret;
}
static int virLXCControllerPopulateDevices(virLXCControllerPtr ctrl)
{
size_t i;
int ret = -1;
char *path = NULL;
const struct {
int maj;
int min;
mode_t mode;
const char *path;
} devs[] = {
{ LXC_DEV_MAJ_MEMORY, LXC_DEV_MIN_NULL, 0666, "/null" },
{ LXC_DEV_MAJ_MEMORY, LXC_DEV_MIN_ZERO, 0666, "/zero" },
{ LXC_DEV_MAJ_MEMORY, LXC_DEV_MIN_FULL, 0666, "/full" },
{ LXC_DEV_MAJ_MEMORY, LXC_DEV_MIN_RANDOM, 0666, "/random" },
{ LXC_DEV_MAJ_MEMORY, LXC_DEV_MIN_URANDOM, 0666, "/urandom" },
};
if (virLXCControllerSetupDev(ctrl) < 0)
goto cleanup;
/* Populate /dev/ with a few important bits */
for (i = 0; i < ARRAY_CARDINALITY(devs); i++) {
if (virAsprintf(&path, "/%s/%s.dev/%s",
LXC_STATE_DIR, ctrl->def->name, devs[i].path) < 0) {
virReportOOMError();
goto cleanup;
}
dev_t dev = makedev(devs[i].maj, devs[i].min);
if (mknod(path, S_IFCHR, dev) < 0 ||
chmod(path, devs[i].mode)) {
virReportSystemError(errno,
_("Failed to make device %s"),
path);
goto cleanup;
}
VIR_FREE(path);
}
ret = 0;
cleanup:
VIR_FREE(path);
return ret;
}
/**
@ -1594,6 +1691,9 @@ virLXCControllerRun(virLXCControllerPtr ctrl)
if (virLXCControllerSetupDevPTS(ctrl) < 0)
goto cleanup;
if (virLXCControllerPopulateDevices(ctrl) < 0)
goto cleanup;
if (virLXCControllerSetupFuse(ctrl) < 0)
goto cleanup;