On 10/13/2012 06:00 PM, Eric Blake wrote:
Now that we can crawl the chain of backing files, we can do
argument validation and implement the 'shallow' flag. In
testing this, I discovered that it can be handy to pass the
shallow flag and an explicit base, as a means of validating
that the base is indeed the file we expected.
* src/qemu/qemu_driver.c (qemuDomainBlockCommit): Crawl through
chain to implement shallow flag.
* src/libvirt.c (virDomainBlockCommit): Relax API.
---
src/libvirt.c | 2 --
src/qemu/qemu_driver.c | 59 ++++++++++++++++++++++++++++++++++++++++----------
2 files changed, 47 insertions(+), 14 deletions(-)
diff --git a/src/libvirt.c b/src/libvirt.c
index 3c6d67d..9d27240 100644
--- a/src/libvirt.c
+++ b/src/libvirt.c
@@ -19378,8 +19378,6 @@ int virDomainBlockCommit(virDomainPtr dom, const char *disk,
}
virCheckNonNullArgGoto(disk, error);
- if (flags & VIR_DOMAIN_BLOCK_COMMIT_SHALLOW)
- virCheckNullArgGoto(base, error);
if (conn->driver->domainBlockCommit) {
int ret;
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index a9fd93a..e9bc215 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -12553,8 +12553,12 @@ qemuDomainBlockCommit(virDomainPtr dom, const char *path, const
char *base,
int ret = -1;
int idx;
virDomainDiskDefPtr disk;
+ const char *top_canon = NULL;
+ virStorageFileMetadataPtr top_meta = NULL;
+ const char *top_parent = NULL;
+ const char *base_canon = NULL;
- virCheckFlags(0, -1);
+ virCheckFlags(VIR_DOMAIN_BLOCK_COMMIT_SHALLOW, -1);
if (!(vm = qemuDomObjFromDomain(dom)))
goto cleanup;
@@ -12585,20 +12589,51 @@ qemuDomainBlockCommit(virDomainPtr dom, const char *path, const
char *base,
disk->dst);
goto endjob;
}
+ if (qemuDomainDetermineDiskChain(driver, disk, false) < 0)
+ goto endjob;
- if (!top)
- top = disk->src;
+ if (!top) {
+ top_canon = disk->src;
+ top_meta = disk->chain;
+ } else if (!(top_canon = virStorageFileChainLookup(disk->chain, disk->src,
+ top, &top_meta,
+ &top_parent))) {
+ virReportError(VIR_ERR_INVALID_ARG,
+ _("could not find top '%s' in chain for
'%s'"),
+ top, path);
+ goto endjob;
+ }
+ if (!top_meta || !top_meta->backingStore) {
+ virReportError(VIR_ERR_INVALID_ARG,
+ _("top '%s' in chain for '%s' has no backing
file"),
+ top, path);
+ goto endjob;
+ }
+ if (!base && (flags & VIR_DOMAIN_BLOCK_COMMIT_SHALLOW)) {
+ base_canon = top_meta->backingStore;
+ } else if (!(base_canon = virStorageFileChainLookup(top_meta, top_canon,
+ base, NULL, NULL))) {
+ virReportError(VIR_ERR_INVALID_ARG,
+ _("could not find base '%s' below '%s' in
chain "
+ "for '%s'"),
+ base ? base : "(default)", top_canon, path);
+ goto endjob;
+ }
+ if ((flags & VIR_DOMAIN_BLOCK_COMMIT_SHALLOW) &&
+ base_canon != top_meta->backingStore) {
+ virReportError(VIR_ERR_INVALID_ARG,
+ _("base '%s' is not immediately below '%s'
in chain "
+ "for '%s'"),
+ base, top_canon, path);
+ goto endjob;
+ }
- /* XXX For now, we are relying on qemu to check that 'top' and
- * 'base' resolve to members of the backing chain in correct
- * order; but if we ever get more paranoid and track the backing
- * chain ourself, we should be pre-validating the data rather than
- * relying on qemu. For that matter, we need to be changing the
- * SELinux label on both 'base' and the parent of 'top', so that
- * qemu can open(O_RDWR) those files for the duration of the
- * commit. */
+ /* XXX We need to be changing the SELinux label on both 'base' and
+ * the parent of 'top', so that qemu can open(O_RDWR) those files
+ * for the duration of the commit. */
qemuDomainObjEnterMonitor(driver, vm);
- ret = qemuMonitorBlockCommit(priv->mon, device, top, base, bandwidth);
+ ret = qemuMonitorBlockCommit(priv->mon, device, top_canon, base_canon,
+ bandwidth);
qemuDomainObjExitMonitor(driver, vm);
endjob:
Looks reasonable. ACK.