mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-02-22 11:22:23 +00:00
Add support for disks with LXC
Currently LXC guests can be given arbitrary pre-mounted filesystems, however, for some usecases it is more appropriate to provide block devices which the container can mount itself. This first impl only allows for <disk type='block'>, in other words exposing a host disk device to a container. Since LXC does not have device namespace virtualization, we are cheating a little bit. If the XML specifies /dev/sdc4 to be given to the container as /dev/sda1, when we do the mknod /dev/sda1 in the container's /dev, we actually use the major:minor number of /dev/sdc4, not /dev/sda1. Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
This commit is contained in:
parent
a6cbdd7b81
commit
368e341ac1
@ -332,6 +332,24 @@ static int virLXCCgroupSetupDeviceACL(virDomainDefPtr def,
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0 ; i < def->ndisks ; i++) {
|
||||
if (def->disks[i]->type != VIR_DOMAIN_DISK_TYPE_BLOCK)
|
||||
continue;
|
||||
|
||||
rc = virCgroupAllowDevicePath(cgroup,
|
||||
def->disks[i]->src,
|
||||
(def->disks[i]->readonly ?
|
||||
VIR_CGROUP_DEVICE_READ :
|
||||
VIR_CGROUP_DEVICE_RW) |
|
||||
VIR_CGROUP_DEVICE_MKNOD);
|
||||
if (rc != 0) {
|
||||
virReportSystemError(-rc,
|
||||
_("Unable to allow device %s for domain %s"),
|
||||
def->disks[i]->src, def->name);
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0 ; i < def->nfss ; i++) {
|
||||
if (def->fss[i]->type != VIR_DOMAIN_FS_TYPE_BLOCK)
|
||||
continue;
|
||||
|
@ -1211,6 +1211,106 @@ static int lxcContainerMountAllFS(virDomainDefPtr vmDef,
|
||||
}
|
||||
|
||||
|
||||
static int lxcContainerSetupDisk(virDomainDefPtr vmDef,
|
||||
virDomainDiskDefPtr def,
|
||||
const char *dstprefix,
|
||||
virSecurityManagerPtr securityDriver)
|
||||
{
|
||||
char *src = NULL;
|
||||
char *dst = NULL;
|
||||
int ret = -1;
|
||||
struct stat sb;
|
||||
mode_t mode;
|
||||
char *tmpsrc = def->src;
|
||||
|
||||
if (def->type != VIR_DOMAIN_DISK_TYPE_BLOCK) {
|
||||
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
||||
_("Can't setup disk for non-block device"));
|
||||
goto cleanup;
|
||||
}
|
||||
if (def->src == NULL) {
|
||||
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
||||
_("Can't setup disk without media"));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (virAsprintf(&src, "%s/%s", dstprefix, def->src) < 0) {
|
||||
virReportOOMError();
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (virAsprintf(&dst, "/dev/%s", def->dst) < 0) {
|
||||
virReportOOMError();
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (stat(src, &sb) < 0) {
|
||||
virReportSystemError(errno,
|
||||
_("Unable to access %s"), def->src);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (!S_ISCHR(sb.st_mode) && !S_ISBLK(sb.st_mode)) {
|
||||
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
||||
_("Disk source %s must be a character/block device"),
|
||||
def->src);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
mode = 0700;
|
||||
if (S_ISCHR(sb.st_mode))
|
||||
mode |= S_IFCHR;
|
||||
else
|
||||
mode |= S_IFBLK;
|
||||
|
||||
/* Yes, the device name we're creating may not
|
||||
* actually correspond to the major:minor number
|
||||
* we're using, but we've no other option at this
|
||||
* time. Just have to hope that containerized apps
|
||||
* don't get upset that the major:minor is different
|
||||
* to that normally implied by the device name
|
||||
*/
|
||||
VIR_DEBUG("Creating dev %s (%d,%d) from %s",
|
||||
dst, major(sb.st_rdev), minor(sb.st_rdev), src);
|
||||
if (mknod(dst, mode, sb.st_rdev) < 0) {
|
||||
virReportSystemError(errno,
|
||||
_("Unable to create device %s"),
|
||||
dst);
|
||||
goto cleanup;
|
||||
}
|
||||
/* Labelling normally operates on src, but we need
|
||||
* to actally label the dst here, so hack the config */
|
||||
def->src = dst;
|
||||
if (virSecurityManagerSetImageLabel(securityDriver, vmDef, def) < 0)
|
||||
goto cleanup;
|
||||
|
||||
ret = 0;
|
||||
|
||||
cleanup:
|
||||
def->src = tmpsrc;
|
||||
VIR_FREE(src);
|
||||
VIR_FREE(dst);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int lxcContainerSetupAllDisks(virDomainDefPtr vmDef,
|
||||
const char *dstprefix,
|
||||
virSecurityManagerPtr securityDriver)
|
||||
{
|
||||
size_t i;
|
||||
VIR_DEBUG("Setting up disks %s", dstprefix);
|
||||
|
||||
for (i = 0 ; i < vmDef->ndisks ; i++) {
|
||||
if (lxcContainerSetupDisk(vmDef, vmDef->disks[i],
|
||||
dstprefix, securityDriver) < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
VIR_DEBUG("Setup all disks");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int lxcContainerGetSubtree(const char *prefix,
|
||||
char ***mountsret,
|
||||
size_t *nmountsret)
|
||||
@ -1606,6 +1706,10 @@ static int lxcContainerSetupPivotRoot(virDomainDefPtr vmDef,
|
||||
if (lxcContainerMountAllFS(vmDef, "/.oldroot", true, sec_mount_options) < 0)
|
||||
goto cleanup;
|
||||
|
||||
/* Sets up any extra disks from guest config */
|
||||
if (lxcContainerSetupAllDisks(vmDef, "/.oldroot", securityDriver) < 0)
|
||||
goto cleanup;
|
||||
|
||||
/* Gets rid of all remaining mounts from host OS, including /.oldroot itself */
|
||||
if (lxcContainerUnmountSubtree("/.oldroot", true) < 0)
|
||||
goto cleanup;
|
||||
|
Loading…
x
Reference in New Issue
Block a user