diff --git a/src/qemu/qemu_block.c b/src/qemu/qemu_block.c index 91c04ab7f233429f13a808a1d0cdb5f7d14bc0bb..e3190784212d5f43aee9bd859e82820bcd0b39ff 100644 --- a/src/qemu/qemu_block.c +++ b/src/qemu/qemu_block.c @@ -278,3 +278,105 @@ qemuBlockNodeNameGetBackingChain(virJSONValuePtr json) return ret; } + + +static void +qemuBlockDiskClearDetectedNodes(virDomainDiskDefPtr disk) +{ + virStorageSourcePtr next = disk->src; + + while (next) { + VIR_FREE(next->nodeformat); + VIR_FREE(next->nodebacking); + + next = next->backingStore; + } +} + + +static int +qemuBlockDiskDetectNodes(virDomainDiskDefPtr disk, + const char *parentnode, + virHashTablePtr table) +{ + qemuBlockNodeNameBackingChainDataPtr entry = NULL; + virStorageSourcePtr src = disk->src; + + /* don't attempt the detection if the top level already has node names */ + if (!parentnode || src->nodeformat || src->nodebacking) + return 0; + + while (src && parentnode) { + if (!(entry = virHashLookup(table, parentnode))) + break; + + if (src->nodeformat || src->nodebacking) { + if (STRNEQ_NULLABLE(src->nodeformat, entry->nodeformat) || + STRNEQ_NULLABLE(src->nodebacking, entry->nodestorage)) + goto error; + + break; + } else { + if (VIR_STRDUP(src->nodeformat, entry->nodeformat) < 0 || + VIR_STRDUP(src->nodebacking, entry->nodestorage) < 0) + goto error; + } + + parentnode = entry->nodebacking; + src = src->backingStore; + } + + return 0; + + error: + qemuBlockDiskClearDetectedNodes(disk); + return -1; +} + + +int +qemuBlockNodeNamesDetect(virQEMUDriverPtr driver, + virDomainObjPtr vm) +{ + qemuDomainObjPrivatePtr priv = vm->privateData; + virHashTablePtr disktable = NULL; + virHashTablePtr nodenametable = NULL; + virJSONValuePtr data = NULL; + virDomainDiskDefPtr disk; + struct qemuDomainDiskInfo *info; + size_t i; + int ret = -1; + + if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_QUERY_NAMED_BLOCK_NODES)) + return 0; + + qemuDomainObjEnterMonitor(driver, vm); + + disktable = qemuMonitorGetBlockInfo(qemuDomainGetMonitor(vm)); + data = qemuMonitorQueryNamedBlockNodes(qemuDomainGetMonitor(vm)); + + if (qemuDomainObjExitMonitor(driver, vm) < 0 || !data || !disktable) + goto cleanup; + + if (!(nodenametable = qemuBlockNodeNameGetBackingChain(data))) + goto cleanup; + + for (i = 0; i < vm->def->ndisks; i++) { + disk = vm->def->disks[i]; + + if (!(info = virHashLookup(disktable, disk->info.alias))) + continue; + + if (qemuBlockDiskDetectNodes(disk, info->nodename, nodenametable) < 0) + goto cleanup; + } + + ret = 0; + + cleanup: + virJSONValueFree(data); + virHashFree(nodenametable); + virHashFree(disktable); + + return ret; +} diff --git a/src/qemu/qemu_block.h b/src/qemu/qemu_block.h index 26f5ae06255d1273c5e78dce17116bd26b6d37f0..56f4a74dd913fc864373f3720d75b401a2f48854 100644 --- a/src/qemu/qemu_block.h +++ b/src/qemu/qemu_block.h @@ -44,4 +44,8 @@ struct qemuBlockNodeNameBackingChainData { virHashTablePtr qemuBlockNodeNameGetBackingChain(virJSONValuePtr data); +int +qemuBlockNodeNamesDetect(virQEMUDriverPtr driver, + virDomainObjPtr vm); + #endif /* __QEMU_BLOCK_H__ */ diff --git a/src/qemu/qemu_blockjob.c b/src/qemu/qemu_blockjob.c index 985fae1e96ebf2aee5da7927cfda1431fa86af4c..0601e68da852b78ae8bf7061aa42c39de1dfc25d 100644 --- a/src/qemu/qemu_blockjob.c +++ b/src/qemu/qemu_blockjob.c @@ -24,6 +24,7 @@ #include "internal.h" #include "qemu_blockjob.h" +#include "qemu_block.h" #include "qemu_domain.h" #include "conf/domain_conf.h" @@ -166,6 +167,7 @@ qemuBlockJobEventProcess(virQEMUDriverPtr driver, disk->mirrorJob = VIR_DOMAIN_BLOCK_JOB_TYPE_UNKNOWN; ignore_value(qemuDomainDetermineDiskChain(driver, vm, disk, true, true)); + ignore_value(qemuBlockNodeNamesDetect(driver, vm)); diskPriv->blockjob = false; break; diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index f6403e43c1070c788f366cf9230d1fd0c5f60c5d..2c2041912409bf3751c64266c6b229fdb2ebae35 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -46,6 +46,7 @@ #include "qemu_driver.h" #include "qemu_agent.h" #include "qemu_alias.h" +#include "qemu_block.h" #include "qemu_conf.h" #include "qemu_capabilities.h" #include "qemu_command.h" @@ -20354,6 +20355,10 @@ qemuDomainSetBlockThreshold(virDomainPtr dom, if (!(src = qemuDomainGetStorageSourceByDevstr(dev, vm->def))) goto endjob; + if (!src->nodebacking && + qemuBlockNodeNamesDetect(driver, vm) < 0) + goto endjob; + if (!src->nodebacking) { virReportError(VIR_ERR_OPERATION_UNSUPPORTED, _("threshold currently can't be set for block device '%s'"), diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index 6f72fb4d791dfd841f4c533b182465da8beb1fa1..b0e3e90964bfe7b44c7631a4284f1185dcf80b2c 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -35,6 +35,7 @@ #include "qemu_process.h" #include "qemu_processpriv.h" #include "qemu_alias.h" +#include "qemu_block.h" #include "qemu_domain.h" #include "qemu_domain_address.h" #include "qemu_cgroup.h" @@ -3486,6 +3487,9 @@ qemuProcessReconnect(void *opaque) if (qemuProcessRefreshDisks(driver, obj, QEMU_ASYNC_JOB_NONE) < 0) goto error; + if (qemuBlockNodeNamesDetect(driver, obj) < 0) + goto error; + if (qemuRefreshVirtioChannelState(driver, obj, QEMU_ASYNC_JOB_NONE) < 0) goto error;