This copies heavily from qemuDomainSnapshotCreateSingleDiskActive(),
in order to set the SELinux label, obtain locking manager lease,
permit a block device through cgroups, and audit the fact that we
hand a new file over to qemu. Alas, releasing the lease and label
at the end of the mirroring is a trickier prospect (we would have to
know the backing chain of both source and destination, and be sure
not to revoke rights to any part of the chain that is shared), so
for now, virDomainBlockJobAbort still leaves things locked by the
manager, open to cgroups, and labeled by SELinux.
* src/qemu/qemu_driver.c (qemuDomainBlockCopy): Set up labeling.
---
src/qemu/qemu_driver.c | 88 ++++++++++++++++++++++++++++++++++++++++++++------
1 file changed, 79 insertions(+), 9 deletions(-)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 0afb1c8..b9014c3 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -12936,6 +12936,12 @@ qemuDomainBlockCopy(virDomainPtr dom, const char *path,
int idx;
bool reopen;
struct stat st;
+ bool need_unlink = false;
+ char *mirror = NULL;
+ char *mirrorFormat = NULL;
+ char *origsrc = NULL;
+ char *origdriver = NULL;
+ virCgroupPtr cgroup = NULL;
/* Preliminaries: find the disk we are editing, sanity checks */
virCheckFlags(VIR_DOMAIN_BLOCK_REBASE_SHALLOW |
@@ -12954,6 +12960,13 @@ qemuDomainBlockCopy(virDomainPtr dom, const char *path,
_("domain is not running"));
goto cleanup;
}
+ if (qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_DEVICES) &&
+ virCgroupForDomain(driver->cgroup, vm->def->name, &cgroup, 0)) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Unable to find cgroup for %s"),
+ vm->def->name);
+ goto cleanup;
+ }
device = qemuDiskPathToAlias(vm, path, &idx);
if (!device) {
@@ -13027,33 +13040,90 @@ qemuDomainBlockCopy(virDomainPtr dom, const char *path,
goto endjob;
}
- /* XXX We also need to add security labeling, lock manager lease,
- * and auditing of those events. */
- if (!format && !(flags & VIR_DOMAIN_BLOCK_REBASE_REUSE_EXT))
- format = disk->driverType;
- if ((format && !(disk->mirrorFormat = strdup(format))) ||
- !(disk->mirror = strdup(dest))) {
+ if (!(flags & VIR_DOMAIN_BLOCK_REBASE_REUSE_EXT)) {
+ int fd = qemuOpenFile(driver, dest, O_WRONLY | O_TRUNC | O_CREAT,
+ &need_unlink, NULL);
+ if (fd < 0)
+ goto endjob;
+ VIR_FORCE_CLOSE(fd);
+ if (!format)
+ format = disk->driverType;
+ }
+ if ((format && !(mirrorFormat = strdup(format))) ||
+ !(mirror = strdup(dest))) {
virReportOOMError();
goto endjob;
}
+ /* Manipulate disk in place, in a way that can be reverted on
+ * failure, in order to set up labeling and locking. */
+ origsrc = disk->src;
+ disk->src = (char *) dest;
+ origdriver = disk->driverType;
+ disk->driverType = (char *) "raw"; /* Don't want to probe backing
files */
+
+ if (virDomainLockDiskAttach(driver->lockManager, vm, disk) < 0)
+ goto endjob;
+ if (cgroup && qemuSetupDiskCgroup(driver, vm, cgroup, disk) < 0) {
+ if (virDomainLockDiskDetach(driver->lockManager, vm, disk) < 0)
+ VIR_WARN("Unable to release lock on %s", dest);
+ goto cleanup;
+ }
+ if (virSecurityManagerSetImageLabel(driver->securityManager, vm->def,
+ disk) < 0) {
+ if (cgroup && qemuTeardownDiskCgroup(driver, vm, cgroup, disk) < 0)
+ VIR_WARN("Failed to teardown cgroup for disk path %s", dest);
+ if (virDomainLockDiskDetach(driver->lockManager, vm, disk) < 0)
+ VIR_WARN("Unable to release lock on %s", dest);
+ goto endjob;
+ }
+
/* Actually start the mirroring */
qemuDomainObjEnterMonitorWithDriver(driver, vm);
ret = qemuMonitorDriveMirror(priv->mon, device, dest, format, bandwidth,
reopen, flags);
+ virDomainAuditDisk(vm, NULL, dest, "mirror", ret >= 0);
qemuDomainObjExitMonitorWithDriver(driver, vm);
+ if (ret < 0) {
+ if (cgroup && qemuTeardownDiskCgroup(driver, vm, cgroup, disk) < 0)
+ VIR_WARN("Failed to teardown cgroup for disk path %s", dest);
+ if (virSecurityManagerRestoreImageLabel(driver->securityManager,
+ vm->def, disk) < 0)
+ VIR_WARN("Unable to restore security label on %s", dest);
+ if (virDomainLockDiskDetach(driver->lockManager, vm, disk) < 0)
+ VIR_WARN("Unable to release lock on %s", dest);
+ goto endjob;
+ }
+
+ disk->src = origsrc;
+ origsrc = NULL;
+ disk->driverType = origdriver;
+ origdriver = NULL;
+
+ /* Update vm in place to match changes. */
+ need_unlink = false;
+ disk->mirror = mirror;
+ disk->mirrorFormat = mirrorFormat;
+ mirror = NULL;
+ mirrorFormat = NULL;
endjob:
- if (ret < 0) {
- VIR_FREE(disk->mirror);
- VIR_FREE(disk->mirrorFormat);
+ if (origsrc) {
+ disk->src = origsrc;
+ disk->driverType = origdriver;
}
+ if (need_unlink && unlink(dest))
+ VIR_WARN("unable to unlink just-created %s", dest);
+ VIR_FREE(mirror);
+ VIR_FREE(mirrorFormat);
if (qemuDomainObjEndJob(driver, vm) == 0) {
vm = NULL;
goto cleanup;
}
cleanup:
+ if (cgroup)
+ virCgroupFree(&cgroup);
VIR_FREE(device);
if (vm)
virDomainObjUnlock(vm);
--
1.7.11.4