'top' handling basically requires two changes: besides the obvious adjustments to the code that fixes our backing chains (for both active and inactive configuration) after a pull, we need to make the top image read-only again if it's not identical with the active layer (it had to be made writable before submitting QMP block-stream to allow QEMU to fix the backing chain in top's qcow2). Signed-off-by: Pavel Mores <pmores@xxxxxxxxxx> --- src/qemu/qemu_blockjob.c | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/src/qemu/qemu_blockjob.c b/src/qemu/qemu_blockjob.c index e19a2ad76b..2e53821d43 100644 --- a/src/qemu/qemu_blockjob.c +++ b/src/qemu/qemu_blockjob.c @@ -962,6 +962,7 @@ qemuBlockJobProcessEventCompletedPull(virQEMUDriverPtr driver, virDomainDiskDefPtr cfgdisk = NULL; virStorageSourcePtr cfgbase = NULL; virStorageSourcePtr cfgbaseparent = NULL; + virStorageSourcePtr cfgtop = NULL; virStorageSourcePtr n; virStorageSourcePtr tmp; @@ -994,16 +995,40 @@ qemuBlockJobProcessEventCompletedPull(virQEMUDriverPtr driver, } } - tmp = job->disk->src->backingStore; - job->disk->src->backingStore = job->data.pull.base; + if (job->data.pull.top) { + cfgtop = cfgdisk->src->backingStore; + for (n = job->disk->src->backingStore; n && n != job->data.pull.top; n = n->backingStore) { + if (cfgtop) + cfgtop = cfgtop->backingStore; + } + } + + if (job->data.pull.top && job->data.pull.top != job->disk->src) { + if (qemuDomainStorageSourceAccessAllow(driver, vm, job->data.pull.top, true, false) < 0) { + virReportError(VIR_ERR_ACCESS_DENIED, "can't reset 'top' to read-only"); + } + } + + if (job->data.pull.top) { + tmp = job->data.pull.top->backingStore; + job->data.pull.top->backingStore = job->data.pull.base; + } else { + tmp = job->disk->src->backingStore; + job->disk->src->backingStore = job->data.pull.base; + } if (baseparent) baseparent->backingStore = NULL; qemuBlockJobEventProcessConcludedRemoveChain(driver, vm, asyncJob, tmp); virObjectUnref(tmp); if (cfgdisk) { - tmp = cfgdisk->src->backingStore; - cfgdisk->src->backingStore = cfgbase; + if (job->data.pull.top) { + tmp = cfgtop->backingStore; + cfgtop->backingStore = cfgbase; + } else { + tmp = cfgdisk->src->backingStore; + cfgdisk->src->backingStore = cfgbase; + } if (cfgbaseparent) cfgbaseparent->backingStore = NULL; virObjectUnref(tmp); -- 2.24.1