This copies heavily from qemuDomainSnapshotCreateSingleDiskActive(),
in order to set the SELinux label, obtain locking manager lease, 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 and labeled.
* src/qemu/qemu_driver.c (qemuDomainBlockCopy): Set up labeling.
---
v6: no real change from v8
src/qemu/qemu_driver.c | 69 +++++++++++++++++++++++++++++++++++++++++------
1 files changed, 60 insertions(+), 9 deletions(-)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index e3d3280..e78a73e 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -11968,6 +11968,11 @@ qemuDomainBlockCopy(virDomainPtr dom, const char *path,
int ret = -1;
int idx;
struct stat st;
+ bool need_unlink = false;
+ char *mirror = NULL;
+ char *mirrorFormat = NULL;
+ char *origsrc = NULL;
+ char *origdriver = NULL;
/* Preliminaries: find the disk we are editing, sanity checks */
virCheckFlags(VIR_DOMAIN_BLOCK_REBASE_SHALLOW |
@@ -12056,29 +12061,75 @@ 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 (virSecurityManagerSetImageLabel(driver->securityManager, vm->def,
+ disk) < 0) {
+ 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, flags);
+ virDomainAuditDisk(vm, NULL, dest, "mirror", ret >= 0);
if (ret == 0 && bandwidth != 0)
ret = qemuMonitorBlockJob(priv->mon, device, NULL, bandwidth, NULL,
BLOCK_JOB_SPEED_INTERNAL, true);
qemuDomainObjExitMonitorWithDriver(driver, vm);
+ if (ret < 0) {
+ 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;
--
1.7.7.6