diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 77f51d9a03074d09b9e33fe91fa65d6ae5d3862a..e0b672357f3075e4e564a5e76cb2763eb77e4c1d 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -16278,9 +16278,6 @@ qemuDomainBlockJobImpl(virDomainObjPtr vm, goto endjob; if (baseSource) { - if (qemuGetDriveSourceString(baseSource, NULL, &basePath) < 0) - goto endjob; - if (flags & VIR_DOMAIN_BLOCK_REBASE_RELATIVE) { if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_CHANGE_BACKING_FILE)) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", @@ -16318,8 +16315,12 @@ qemuDomainBlockJobImpl(virDomainObjPtr vm, } qemuDomainObjEnterMonitor(driver, vm); - ret = qemuMonitorBlockJob(priv->mon, device, basePath, backingPath, - speed, mode, async); + if (baseSource) + basePath = qemuMonitorDiskNameLookup(priv->mon, device, disk->src, + baseSource); + if (!baseSource || basePath) + ret = qemuMonitorBlockJob(priv->mon, device, basePath, backingPath, + speed, mode, async); if (qemuDomainObjExitMonitor(driver, vm) < 0) ret = -1; if (ret < 0) { @@ -17045,12 +17046,6 @@ qemuDomainBlockCommit(virDomainPtr dom, VIR_DISK_CHAIN_READ_WRITE) < 0)) goto endjob; - if (qemuGetDriveSourceString(topSource, NULL, &topPath) < 0) - goto endjob; - - if (qemuGetDriveSourceString(baseSource, NULL, &basePath) < 0) - goto endjob; - if (flags & VIR_DOMAIN_BLOCK_COMMIT_RELATIVE && topSource != disk->src) { if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_CHANGE_BACKING_FILE)) { @@ -17081,9 +17076,14 @@ qemuDomainBlockCommit(virDomainPtr dom, disk->mirrorJob = VIR_DOMAIN_BLOCK_JOB_TYPE_ACTIVE_COMMIT; } qemuDomainObjEnterMonitor(driver, vm); - ret = qemuMonitorBlockCommit(priv->mon, device, - topPath, basePath, backingPath, - speed); + basePath = qemuMonitorDiskNameLookup(priv->mon, device, disk->src, + baseSource); + topPath = qemuMonitorDiskNameLookup(priv->mon, device, disk->src, + topSource); + if (basePath && topPath) + ret = qemuMonitorBlockCommit(priv->mon, device, + topPath, basePath, backingPath, + speed); if (qemuDomainObjExitMonitor(driver, vm) < 0) { ret = -1; goto endjob; diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index 18f866fa7ed8dfe9aa9927df1ea1da495b824f18..e0a9fe9b3a989af67c81b9617ee5cd88f2687636 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -3471,6 +3471,24 @@ qemuMonitorSupportsActiveCommit(qemuMonitorPtr mon) } +/* Determine the name that qemu is using for tracking the backing + * element TARGET within the chain starting at TOP. */ +char * +qemuMonitorDiskNameLookup(qemuMonitorPtr mon, + const char *device, + virStorageSourcePtr top, + virStorageSourcePtr target) +{ + if (!mon->json) { + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", + _("JSON monitor is required")); + return NULL; + } + + return qemuMonitorJSONDiskNameLookup(mon, device, top, target); +} + + /* Use the block-job-complete monitor command to pivot a block copy * job. */ int diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h index b30da34c4ebe699d2c5ac163b562a195e7a6fbe8..e67d80098ec8021d52c2d91259a94ed66bbc841a 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -1,7 +1,7 @@ /* * qemu_monitor.h: interaction with QEMU monitor console * - * Copyright (C) 2006-2014 Red Hat, Inc. + * Copyright (C) 2006-2015 Red Hat, Inc. * Copyright (C) 2006 Daniel P. Berrange * * This library is free software; you can redistribute it and/or @@ -734,6 +734,12 @@ int qemuMonitorBlockCommit(qemuMonitorPtr mon, ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3) ATTRIBUTE_NONNULL(4); bool qemuMonitorSupportsActiveCommit(qemuMonitorPtr mon); +char *qemuMonitorDiskNameLookup(qemuMonitorPtr mon, + const char *device, + virStorageSourcePtr top, + virStorageSourcePtr target) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3) + ATTRIBUTE_NONNULL(4); int qemuMonitorArbitraryCommand(qemuMonitorPtr mon, const char *cmd, diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index c16f3caeb338ac01d93c98228fc18d89d7281601..8994d5a30867535e8c1fc1f650c86478837eb2c8 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -1,7 +1,7 @@ /* * qemu_monitor_json.c: interaction with QEMU monitor console * - * Copyright (C) 2006-2014 Red Hat, Inc. + * Copyright (C) 2006-2015 Red Hat, Inc. * Copyright (C) 2006 Daniel P. Berrange * * This library is free software; you can redistribute it and/or @@ -3883,6 +3883,106 @@ qemuMonitorJSONDrivePivot(qemuMonitorPtr mon, const char *device, } +static char * +qemuMonitorJSONDiskNameLookupOne(virJSONValuePtr image, + virStorageSourcePtr top, + virStorageSourcePtr target) +{ + virJSONValuePtr backing; + char *ret; + + /* The caller will report a generic message if we return NULL + * without an error; but in some cases we can improve by reporting + * a more specific message. */ + if (!top || !image) + return NULL; + if (top != target) { + backing = virJSONValueObjectGet(image, "backing-image"); + return qemuMonitorJSONDiskNameLookupOne(backing, top->backingStore, + target); + } + if (VIR_STRDUP(ret, virJSONValueObjectGetString(image, "filename")) < 0) + return NULL; + /* Sanity check - the name qemu gave us should resolve to the same + file tracked by our target description. */ + if (virStorageSourceIsLocalStorage(target) && + STRNEQ(ret, target->path) && + !virFileLinkPointsTo(ret, target->path)) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("qemu block name '%s' doesn't match expected '%s'"), + ret, target->path); + VIR_FREE(ret); + } + return ret; +} + + +char * +qemuMonitorJSONDiskNameLookup(qemuMonitorPtr mon, + const char *device, + virStorageSourcePtr top, + virStorageSourcePtr target) +{ + char *ret = NULL; + virJSONValuePtr cmd = NULL; + virJSONValuePtr reply = NULL; + virJSONValuePtr devices; + size_t i; + + cmd = qemuMonitorJSONMakeCommand("query-block", NULL); + if (!cmd) + return NULL; + if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0) + goto cleanup; + + devices = virJSONValueObjectGet(reply, "return"); + if (!devices || devices->type != VIR_JSON_TYPE_ARRAY) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("block info reply was missing device list")); + goto cleanup; + } + + for (i = 0; i < virJSONValueArraySize(devices); i++) { + virJSONValuePtr dev = virJSONValueArrayGet(devices, i); + virJSONValuePtr inserted; + virJSONValuePtr image; + const char *thisdev; + + if (!dev || dev->type != VIR_JSON_TYPE_OBJECT) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("block info device entry was not in expected format")); + goto cleanup; + } + + if (!(thisdev = virJSONValueObjectGetString(dev, "device"))) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("block info device entry was not in expected format")); + goto cleanup; + } + + if (STREQ(thisdev, device)) { + if ((inserted = virJSONValueObjectGet(dev, "inserted")) && + (image = virJSONValueObjectGet(inserted, "image"))) { + ret = qemuMonitorJSONDiskNameLookupOne(image, top, target); + } + break; + } + } + /* Guarantee an error when returning NULL, but don't override a + * more specific error if one was already generated. */ + if (!ret && !virGetLastError()) + virReportError(VIR_ERR_INTERNAL_ERROR, + _("unable to find backing name for device %s"), + device); + + cleanup: + virJSONValueFree(cmd); + virJSONValueFree(reply); + + return ret; +} + + int qemuMonitorJSONArbitraryCommand(qemuMonitorPtr mon, const char *cmd_str, char **reply_str, diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h index 8ceea8a1889a1dfce16dcf207a637026dfdaf6ed..49392b61e8ed1074f6603dc3bb9ae0a39693421b 100644 --- a/src/qemu/qemu_monitor_json.h +++ b/src/qemu/qemu_monitor_json.h @@ -1,7 +1,7 @@ /* * qemu_monitor_json.h: interaction with QEMU monitor console * - * Copyright (C) 2006-2009, 2011-2014 Red Hat, Inc. + * Copyright (C) 2006-2009, 2011-2015 Red Hat, Inc. * Copyright (C) 2006 Daniel P. Berrange * * This library is free software; you can redistribute it and/or @@ -277,6 +277,13 @@ int qemuMonitorJSONBlockCommit(qemuMonitorPtr mon, unsigned long long bandwidth) ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); +char *qemuMonitorJSONDiskNameLookup(qemuMonitorPtr mon, + const char *device, + virStorageSourcePtr top, + virStorageSourcePtr target) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3) + ATTRIBUTE_NONNULL(4); + int qemuMonitorJSONArbitraryCommand(qemuMonitorPtr mon, const char *cmd_str, char **reply_str,