diff --git a/src/qemu/qemu_block.c b/src/qemu/qemu_block.c index a02c8160ebc6d03a86e4ae39d8cb93f5dca0f433..c555230e800df9300a6840dc7e61f6ab933a634a 100644 --- a/src/qemu/qemu_block.c +++ b/src/qemu/qemu_block.c @@ -48,20 +48,15 @@ qemuBlockNamedNodesArrayToHash(size_t pos ATTRIBUTE_UNUSED, static void qemuBlockNodeNameBackingChainDataFree(qemuBlockNodeNameBackingChainDataPtr data) { - size_t i; - if (!data) return; - for (i = 0; i < data->nelems; i++) - virJSONValueFree(data->elems[i]); - VIR_FREE(data->nodeformat); VIR_FREE(data->nodestorage); - VIR_FREE(data->nodebacking); VIR_FREE(data->qemufilename); - VIR_FREE(data->backingstore); + + qemuBlockNodeNameBackingChainDataFree(data->backing); VIR_FREE(data); } @@ -75,55 +70,10 @@ qemuBlockNodeNameBackingChainDataHashEntryFree(void *opaque, } -struct qemuBlockNodeNameGetBackingChainData { - virHashTablePtr table; - qemuBlockNodeNameBackingChainDataPtr *entries; - size_t nentries; -}; - - -static int -qemuBlockNodeNameDetectProcessByFilename(size_t pos ATTRIBUTE_UNUSED, - virJSONValuePtr item, - void *opaque) -{ - struct qemuBlockNodeNameGetBackingChainData *data = opaque; - qemuBlockNodeNameBackingChainDataPtr entry; - const char *file; - - if (!(file = virJSONValueObjectGetString(item, "file"))) - return 1; - - if (!(entry = virHashLookup(data->table, file))) { - if (VIR_ALLOC(entry) < 0) - return -1; - - if (VIR_APPEND_ELEMENT_COPY(data->entries, data->nentries, entry) < 0) { - VIR_FREE(entry); - return -1; - } - - if (VIR_STRDUP(entry->qemufilename, file) < 0) - return -1; - - if (virHashAddEntry(data->table, file, entry) < 0) - return -1; - } - - if (VIR_APPEND_ELEMENT(entry->elems, entry->nelems, item) < 0) - return -1; - - return 0; -} - - -static const char *qemuBlockDriversFormat[] = { - "qcow2", "raw", "qcow", "luks", "qed", "bochs", "cloop", "dmg", "parallels", - "vdi", "vhdx", "vmdk", "vpc", "vvfat", NULL}; -static const char *qemuBlockDriversStorage[] = { - "file", "iscsi", "nbd", "host_cdrom", "host_device", "ftp", "ftps", - "gluster", "http", "https", "nfs", "rbd", "sheepdog", "ssh", "tftp", NULL}; - +/* list of driver names of layers that qemu automatically adds into the + * backing chain */ +static const char *qemuBlockDriversBlockjob[] = { + "mirror_top", "commit_top", NULL }; static bool qemuBlockDriverMatch(const char *drvname, @@ -140,86 +90,110 @@ qemuBlockDriverMatch(const char *drvname, } +struct qemuBlockNodeNameGetBackingChainData { + virHashTablePtr nodenamestable; + virHashTablePtr disks; +}; + + static int -qemuBlockNodeNameDetectProcessExtract(qemuBlockNodeNameBackingChainDataPtr data) +qemuBlockNodeNameGetBackingChainBacking(virJSONValuePtr next, + virHashTablePtr nodenamestable, + qemuBlockNodeNameBackingChainDataPtr *nodenamedata) { - const char *drv; - const char *nodename; - const char *backingstore; - size_t i; + qemuBlockNodeNameBackingChainDataPtr data = NULL; + qemuBlockNodeNameBackingChainDataPtr backingdata = NULL; + virJSONValuePtr backing = virJSONValueObjectGetObject(next, "backing"); + virJSONValuePtr parent = virJSONValueObjectGetObject(next, "parent"); + virJSONValuePtr parentnodedata; + virJSONValuePtr nodedata; + const char *nodename = virJSONValueObjectGetString(next, "node-name"); + const char *drvname; + const char *parentnodename = NULL; + const char *filename = NULL; + int ret = -1; - /* Since the only way to construct the backing chain is to look up the files - * by file name, if two disks share a backing image we can't know which node - * belongs to which backing chain. Refuse to detect such chains. */ - if (data->nelems > 2) + if (!nodename) return 0; - for (i = 0; i < data->nelems; i++) { - drv = virJSONValueObjectGetString(data->elems[i], "drv"); - nodename = virJSONValueObjectGetString(data->elems[i], "node-name"); - backingstore = virJSONValueObjectGetString(data->elems[i], "backing_file"); + if ((nodedata = virHashLookup(nodenamestable, nodename)) && + (drvname = virJSONValueObjectGetString(nodedata, "drv"))) { + + /* qemu 2.9 reports layers in the backing chain which don't correspond + * to files. skip them */ + if (qemuBlockDriverMatch(drvname, qemuBlockDriversBlockjob)) { + if (backing) { + return qemuBlockNodeNameGetBackingChainBacking(backing, + nodenamestable, + nodenamedata); + } else { + return 0; + } + } + } - if (!drv || !nodename) - continue; + if (parent && + (parentnodename = virJSONValueObjectGetString(parent, "node-name"))) { + if ((parentnodedata = virHashLookup(nodenamestable, parentnodename))) + filename = virJSONValueObjectGetString(parentnodedata, "file"); + } - if (qemuBlockDriverMatch(drv, qemuBlockDriversFormat)) { - if (data->nodeformat) - continue; + if (VIR_ALLOC(data) < 0) + goto cleanup; - if (VIR_STRDUP(data->nodeformat, nodename) < 0) - return -1; + if (VIR_STRDUP(data->nodeformat, nodename) < 0 || + VIR_STRDUP(data->nodestorage, parentnodename) < 0 || + VIR_STRDUP(data->qemufilename, filename) < 0) + goto cleanup; - /* extract the backing store file name for the protocol layer */ - if (VIR_STRDUP(data->backingstore, backingstore) < 0) - return -1; - } else if (qemuBlockDriverMatch(drv, qemuBlockDriversStorage)) { - if (data->nodestorage) - continue; + if (backing && + qemuBlockNodeNameGetBackingChainBacking(backing, nodenamestable, + &backingdata) < 0) + goto cleanup; - if (VIR_STRDUP(data->nodestorage, nodename) < 0) - return -1; - } - } + VIR_STEAL_PTR(data->backing, backingdata); + VIR_STEAL_PTR(*nodenamedata, data); - return 0; + ret = 0; + + cleanup: + qemuBlockNodeNameBackingChainDataFree(data); + return ret; } static int -qemuBlockNodeNameDetectProcessLinkBacking(qemuBlockNodeNameBackingChainDataPtr data, - virHashTablePtr table) +qemuBlockNodeNameGetBackingChainDisk(size_t pos ATTRIBUTE_UNUSED, + virJSONValuePtr item, + void *opaque) { - qemuBlockNodeNameBackingChainDataPtr backing; - - if (!data->backingstore) - return 0; - - if (!(backing = virHashLookup(table, data->backingstore))) - return 0; - - if (VIR_STRDUP(data->nodebacking, backing->nodeformat) < 0) - return -1; + struct qemuBlockNodeNameGetBackingChainData *data = opaque; + const char *device = virJSONValueObjectGetString(item, "device"); + qemuBlockNodeNameBackingChainDataPtr devicedata = NULL; + int ret = -1; - return 0; -} + if (qemuBlockNodeNameGetBackingChainBacking(item, data->nodenamestable, + &devicedata) < 0) + goto cleanup; + if (devicedata && + virHashAddEntry(data->disks, device, devicedata) < 0) + goto cleanup; -static void -qemuBlockNodeNameGetBackingChainDataClearLookup(qemuBlockNodeNameBackingChainDataPtr data) -{ - size_t i; + devicedata = NULL; + ret = 1; /* we don't really want to steal @item */ - for (i = 0; i < data->nelems; i++) - virJSONValueFree(data->elems[i]); + cleanup: + qemuBlockNodeNameBackingChainDataFree(devicedata); - VIR_FREE(data->elems); - data->nelems = 0; + return ret; } /** * qemuBlockNodeNameGetBackingChain: - * @json: JSON array of data returned from 'query-named-block-nodes' + * @namednodes: JSON array of data returned from 'query-named-block-nodes' + * @blockstats: JSON array of data returned from 'query-blockstats' * * Tries to reconstruct the backing chain from @json to allow detection of * node names that were auto-assigned by qemu. This is a best-effort operation @@ -230,69 +204,40 @@ qemuBlockNodeNameGetBackingChainDataClearLookup(qemuBlockNodeNameBackingChainDat * Returns a hash table on success and NULL on failure. */ virHashTablePtr -qemuBlockNodeNameGetBackingChain(virJSONValuePtr json) +qemuBlockNodeNameGetBackingChain(virJSONValuePtr namednodes, + virJSONValuePtr blockstats) { struct qemuBlockNodeNameGetBackingChainData data; - virHashTablePtr nodetable = NULL; + virHashTablePtr namednodestable = NULL; + virHashTablePtr disks = NULL; virHashTablePtr ret = NULL; - size_t i; memset(&data, 0, sizeof(data)); - /* hash table keeps the entries accessible by the 'file' in qemu */ - if (!(data.table = virHashCreate(50, NULL))) + if (!(namednodestable = virHashCreate(50, virJSONValueHashFree))) goto cleanup; - /* first group the named entries by the 'file' field */ - if (virJSONValueArrayForeachSteal(json, - qemuBlockNodeNameDetectProcessByFilename, - &data) < 0) + if (virJSONValueArrayForeachSteal(namednodes, + qemuBlockNamedNodesArrayToHash, + namednodestable) < 0) goto cleanup; - /* extract the node names for the format and storage layer */ - for (i = 0; i < data.nentries; i++) { - if (qemuBlockNodeNameDetectProcessExtract(data.entries[i]) < 0) - goto cleanup; - } - - /* extract the node name for the backing file */ - for (i = 0; i < data.nentries; i++) { - if (qemuBlockNodeNameDetectProcessLinkBacking(data.entries[i], - data.table) < 0) - goto cleanup; - } - - /* clear JSON data necessary only for the lookup procedure */ - for (i = 0; i < data.nentries; i++) - qemuBlockNodeNameGetBackingChainDataClearLookup(data.entries[i]); - - /* create hash table hashed by the format node name */ - if (!(nodetable = virHashCreate(50, - qemuBlockNodeNameBackingChainDataHashEntryFree))) + if (!(disks = virHashCreate(50, qemuBlockNodeNameBackingChainDataHashEntryFree))) goto cleanup; - /* fill the entries */ - for (i = 0; i < data.nentries; i++) { - if (!data.entries[i]->nodeformat) - continue; - - if (virHashAddEntry(nodetable, data.entries[i]->nodeformat, - data.entries[i]) < 0) - goto cleanup; + data.nodenamestable = namednodestable; + data.disks = disks; - /* hash table steals the entry and then frees it by itself */ - data.entries[i] = NULL; - } + if (virJSONValueArrayForeachSteal(blockstats, + qemuBlockNodeNameGetBackingChainDisk, + &data) < 0) + goto cleanup; - VIR_STEAL_PTR(ret, nodetable); + VIR_STEAL_PTR(ret, disks); cleanup: - virHashFree(data.table); - virHashFree(nodetable); - for (i = 0; i < data.nentries; i++) - qemuBlockNodeNameBackingChainDataFree(data.entries[i]); - - VIR_FREE(data.entries); + virHashFree(namednodestable); + virHashFree(disks); return ret; } @@ -314,20 +259,19 @@ qemuBlockDiskClearDetectedNodes(virDomainDiskDefPtr disk) static int qemuBlockDiskDetectNodes(virDomainDiskDefPtr disk, - const char *parentnode, - virHashTablePtr table) + virHashTablePtr disktable) { 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->nodestorage) + if (!(entry = virHashLookup(disktable, disk->info.alias))) return 0; - while (src && parentnode) { - if (!(entry = virHashLookup(table, parentnode))) - break; + /* don't attempt the detection if the top level already has node names */ + if (src->nodeformat || src->nodestorage) + return 0; + while (src && entry) { if (src->nodeformat || src->nodestorage) { if (STRNEQ_NULLABLE(src->nodeformat, entry->nodeformat) || STRNEQ_NULLABLE(src->nodestorage, entry->nodestorage)) @@ -340,7 +284,7 @@ qemuBlockDiskDetectNodes(virDomainDiskDefPtr disk, goto error; } - parentnode = entry->nodebacking; + entry = entry->backing; src = src->backingStore; } @@ -359,10 +303,9 @@ qemuBlockNodeNamesDetect(virQEMUDriverPtr driver, { qemuDomainObjPrivatePtr priv = vm->privateData; virHashTablePtr disktable = NULL; - virHashTablePtr nodenametable = NULL; virJSONValuePtr data = NULL; + virJSONValuePtr blockstats = NULL; virDomainDiskDefPtr disk; - struct qemuDomainDiskInfo *info; size_t i; int ret = -1; @@ -372,22 +315,19 @@ qemuBlockNodeNamesDetect(virQEMUDriverPtr driver, if (qemuDomainObjEnterMonitorAsync(driver, vm, asyncJob) < 0) return -1; - disktable = qemuMonitorGetBlockInfo(qemuDomainGetMonitor(vm)); data = qemuMonitorQueryNamedBlockNodes(qemuDomainGetMonitor(vm)); + blockstats = qemuMonitorQueryBlockstats(qemuDomainGetMonitor(vm)); - if (qemuDomainObjExitMonitor(driver, vm) < 0 || !data || !disktable) + if (qemuDomainObjExitMonitor(driver, vm) < 0 || !data || !blockstats) goto cleanup; - if (!(nodenametable = qemuBlockNodeNameGetBackingChain(data))) + if (!(disktable = qemuBlockNodeNameGetBackingChain(data, blockstats))) 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) + if (qemuBlockDiskDetectNodes(disk, disktable) < 0) goto cleanup; } @@ -395,7 +335,7 @@ qemuBlockNodeNamesDetect(virQEMUDriverPtr driver, cleanup: virJSONValueFree(data); - virHashFree(nodenametable); + virJSONValueFree(blockstats); virHashFree(disktable); return ret; diff --git a/src/qemu/qemu_block.h b/src/qemu/qemu_block.h index 17dec799f8e5d9e159065fd372d5798aa0420336..5d21057a77964d13a1661de3a93f66fa8605d6ce 100644 --- a/src/qemu/qemu_block.h +++ b/src/qemu/qemu_block.h @@ -31,19 +31,15 @@ typedef struct qemuBlockNodeNameBackingChainData qemuBlockNodeNameBackingChainDa typedef qemuBlockNodeNameBackingChainData *qemuBlockNodeNameBackingChainDataPtr; struct qemuBlockNodeNameBackingChainData { char *qemufilename; /* name of the image from qemu */ - char *backingstore; char *nodeformat; /* node name of the format layer */ char *nodestorage; /* node name of the storage backing the format node */ - char *nodebacking; /* node name of the backing file format layer */ - - /* data necessary for detection of the node names from qemu */ - virJSONValuePtr *elems; - size_t nelems; + qemuBlockNodeNameBackingChainDataPtr backing; }; virHashTablePtr -qemuBlockNodeNameGetBackingChain(virJSONValuePtr data); +qemuBlockNodeNameGetBackingChain(virJSONValuePtr namednodesdata, + virJSONValuePtr blockstats); int qemuBlockNodeNamesDetect(virQEMUDriverPtr driver, diff --git a/tests/qemumonitorjsondata/qemumonitorjson-nodename-basic-blockstats.json b/tests/qemumonitorjsondata/qemumonitorjson-nodename-basic-blockstats.json new file mode 100644 index 0000000000000000000000000000000000000000..c3752b4cfe92ecd0ba5347898d2fd5ea644ef370 --- /dev/null +++ b/tests/qemumonitorjsondata/qemumonitorjson-nodename-basic-blockstats.json @@ -0,0 +1,166 @@ +[ + { + "device": "drive-virtio-disk0", + "parent": { + "stats": { + "flush_total_time_ns": 0, + "wr_highest_offset": 32899072, + "wr_total_time_ns": 0, + "failed_wr_operations": 0, + "failed_rd_operations": 0, + "wr_merged": 0, + "wr_bytes": 0, + "timed_stats": [ + + ], + "failed_flush_operations": 0, + "account_invalid": false, + "rd_total_time_ns": 0, + "flush_operations": 0, + "wr_operations": 0, + "rd_merged": 0, + "rd_bytes": 0, + "invalid_flush_operations": 0, + "account_failed": false, + "rd_operations": 0, + "invalid_wr_operations": 0, + "invalid_rd_operations": 0 + }, + "node-name": "#block033" + }, + "stats": { + "flush_total_time_ns": 452246313, + "wr_highest_offset": 8072282112, + "wr_total_time_ns": 4803102521, + "failed_wr_operations": 0, + "failed_rd_operations": 0, + "wr_merged": 8, + "wr_bytes": 6517248, + "timed_stats": [ + + ], + "failed_flush_operations": 0, + "account_invalid": true, + "rd_total_time_ns": 11065169148, + "flush_operations": 10, + "wr_operations": 129, + "rd_merged": 77, + "rd_bytes": 76399104, + "invalid_flush_operations": 0, + "account_failed": true, + "idle_time_ns": 22663656304, + "rd_operations": 4038, + "invalid_wr_operations": 0, + "invalid_rd_operations": 0 + }, + "backing": { + "parent": { + "stats": { + "flush_total_time_ns": 0, + "wr_highest_offset": 0, + "wr_total_time_ns": 0, + "failed_wr_operations": 0, + "failed_rd_operations": 0, + "wr_merged": 0, + "wr_bytes": 0, + "timed_stats": [ + + ], + "failed_flush_operations": 0, + "account_invalid": false, + "rd_total_time_ns": 0, + "flush_operations": 0, + "wr_operations": 0, + "rd_merged": 0, + "rd_bytes": 0, + "invalid_flush_operations": 0, + "account_failed": false, + "rd_operations": 0, + "invalid_wr_operations": 0, + "invalid_rd_operations": 0 + }, + "node-name": "#block220" + }, + "stats": { + "flush_total_time_ns": 0, + "wr_highest_offset": 0, + "wr_total_time_ns": 0, + "failed_wr_operations": 0, + "failed_rd_operations": 0, + "wr_merged": 0, + "wr_bytes": 0, + "timed_stats": [ + + ], + "failed_flush_operations": 0, + "account_invalid": false, + "rd_total_time_ns": 0, + "flush_operations": 0, + "wr_operations": 0, + "rd_merged": 0, + "rd_bytes": 0, + "invalid_flush_operations": 0, + "account_failed": false, + "rd_operations": 0, + "invalid_wr_operations": 0, + "invalid_rd_operations": 0 + }, + "backing": { + "parent": { + "stats": { + "flush_total_time_ns": 0, + "wr_highest_offset": 0, + "wr_total_time_ns": 0, + "failed_wr_operations": 0, + "failed_rd_operations": 0, + "wr_merged": 0, + "wr_bytes": 0, + "timed_stats": [ + + ], + "failed_flush_operations": 0, + "account_invalid": false, + "rd_total_time_ns": 0, + "flush_operations": 0, + "wr_operations": 0, + "rd_merged": 0, + "rd_bytes": 0, + "invalid_flush_operations": 0, + "account_failed": false, + "rd_operations": 0, + "invalid_wr_operations": 0, + "invalid_rd_operations": 0 + }, + "node-name": "#block481" + }, + "stats": { + "flush_total_time_ns": 0, + "wr_highest_offset": 0, + "wr_total_time_ns": 0, + "failed_wr_operations": 0, + "failed_rd_operations": 0, + "wr_merged": 0, + "wr_bytes": 0, + "timed_stats": [ + + ], + "failed_flush_operations": 0, + "account_invalid": false, + "rd_total_time_ns": 0, + "flush_operations": 0, + "wr_operations": 0, + "rd_merged": 0, + "rd_bytes": 0, + "invalid_flush_operations": 0, + "account_failed": false, + "rd_operations": 0, + "invalid_wr_operations": 0, + "invalid_rd_operations": 0 + }, + "node-name": "#block558" + }, + "node-name": "#block306" + }, + "node-name": "#block187" + } +] diff --git a/tests/qemumonitorjsondata/qemumonitorjson-nodename-basic-named-nodes.json b/tests/qemumonitorjsondata/qemumonitorjson-nodename-basic-named-nodes.json index fe2f32176e25994ebd0c295345b35737b80e0295..ce8fdae70ff66c97bf3ff3a5ecd85dafe1fb5f03 100644 --- a/tests/qemumonitorjsondata/qemumonitorjson-nodename-basic-named-nodes.json +++ b/tests/qemumonitorjsondata/qemumonitorjson-nodename-basic-named-nodes.json @@ -21,7 +21,7 @@ }, "iops_wr": 0, "ro": true, - "node-name": "#block567", + "node-name": "#block558", "backing_file_depth": 0, "drv": "qcow2", "iops": 0, @@ -50,7 +50,7 @@ }, "iops_wr": 0, "ro": true, - "node-name": "#block424", + "node-name": "#block481", "backing_file_depth": 0, "drv": "file", "iops": 0, @@ -109,7 +109,7 @@ }, "iops_wr": 0, "ro": true, - "node-name": "#block331", + "node-name": "#block306", "backing_file_depth": 1, "drv": "qcow2", "iops": 0, @@ -139,7 +139,7 @@ }, "iops_wr": 0, "ro": true, - "node-name": "#block281", + "node-name": "#block220", "backing_file_depth": 0, "drv": "file", "iops": 0, @@ -202,7 +202,7 @@ "filename": "/var/lib/libvirt/images/rhel7.3.1483545313", "cluster-size": 65536, "format": "qcow2", - "actual-size": 32968704, + "actual-size": 33165312, "format-specific": { "type": "qcow2", "data": { @@ -218,7 +218,7 @@ }, "iops_wr": 0, "ro": false, - "node-name": "#block118", + "node-name": "#block187", "backing_file_depth": 2, "drv": "qcow2", "iops": 0, @@ -240,15 +240,15 @@ "iops_rd": 0, "detect_zeroes": "off", "image": { - "virtual-size": 33030144, + "virtual-size": 33226752, "filename": "/var/lib/libvirt/images/rhel7.3.1483545313", "format": "file", - "actual-size": 32968704, + "actual-size": 33165312, "dirty-flag": false }, "iops_wr": 0, "ro": false, - "node-name": "#block078", + "node-name": "#block033", "backing_file_depth": 0, "drv": "file", "iops": 0, diff --git a/tests/qemumonitorjsondata/qemumonitorjson-nodename-basic.result b/tests/qemumonitorjsondata/qemumonitorjson-nodename-basic.result index 992fc5165e9d81faf3201fcbd486aae73726d06b..09e0b36acf61d4ceb2d592fb76b585d6dee2e52e 100644 --- a/tests/qemumonitorjsondata/qemumonitorjson-nodename-basic.result +++ b/tests/qemumonitorjsondata/qemumonitorjson-nodename-basic.result @@ -1,9 +1,9 @@ filename : '/var/lib/libvirt/images/rhel7.3.1483545313' -format node : '#block118' -storage node: '#block078' +format node : '#block187' +storage node: '#block033' filename : '/var/lib/libvirt/images/rhel7.3.1483536402' - format node : '#block331' - storage node: '#block281' + format node : '#block306' + storage node: '#block220' filename : '/var/lib/libvirt/images/rhel7.3.qcow2' - format node : '#block567' - storage node: '#block424' + format node : '#block558' + storage node: '#block481' diff --git a/tests/qemumonitorjsontest.c b/tests/qemumonitorjsontest.c index c3e86419d1f65931cdb664e1a1148949a47c89f0..cb7a7dbdb7a8153399ed9ae537f4a404d62ad727 100644 --- a/tests/qemumonitorjsontest.c +++ b/tests/qemumonitorjsontest.c @@ -2704,18 +2704,17 @@ struct testBlockNodeNameDetectData { static void testBlockNodeNameDetectFormat(virBufferPtr buf, - const char *basenode, + const char *diskalias, virHashTablePtr nodedata) { qemuBlockNodeNameBackingChainDataPtr entry = NULL; - const char *node = basenode; virBufferSetIndent(buf, 0); - while (node) { - if (!(entry = virHashLookup(nodedata, node))) - break; + if (!(entry = virHashLookup(nodedata, diskalias))) + return; + while (entry) { virBufferAsprintf(buf, "filename : '%s'\n", entry->qemufilename); virBufferAsprintf(buf, "format node : '%s'\n", NULLSTR(entry->nodeformat)); @@ -2724,7 +2723,7 @@ testBlockNodeNameDetectFormat(virBufferPtr buf, virBufferAdjustIndent(buf, 2); - node = entry->nodebacking; + entry = entry->backing; } virBufferSetIndent(buf, 0); @@ -2742,6 +2741,7 @@ testBlockNodeNameDetect(const void *opaque) char **nodenames = NULL; char **next; virJSONValuePtr namedNodesJson = NULL; + virJSONValuePtr blockstatsJson = NULL; virHashTablePtr nodedata = NULL; virBuffer buf = VIR_BUFFER_INITIALIZER; int ret = -1; @@ -2757,7 +2757,12 @@ testBlockNodeNameDetect(const void *opaque) "-named-nodes.json", NULL))) goto cleanup; - if (!(nodedata = qemuBlockNodeNameGetBackingChain(namedNodesJson))) + if (!(blockstatsJson = virTestLoadFileJSON(pathprefix, data->name, + "-blockstats.json", NULL))) + goto cleanup; + + if (!(nodedata = qemuBlockNodeNameGetBackingChain(namedNodesJson, + blockstatsJson))) goto cleanup; for (next = nodenames; *next; next++) @@ -2781,6 +2786,7 @@ testBlockNodeNameDetect(const void *opaque) virHashFree(nodedata); virStringListFree(nodenames); virJSONValueFree(namedNodesJson); + virJSONValueFree(blockstatsJson); return ret; } @@ -2929,7 +2935,7 @@ mymain(void) ret = -1; \ } while (0) - DO_TEST_BLOCK_NODE_DETECT("basic", "#block118"); + DO_TEST_BLOCK_NODE_DETECT("basic", "drive-virtio-disk0"); /* DO_TEST_BLOCK_NODE_DETECT("same-backing", "#block170,#block574"); */ /* DO_TEST_BLOCK_NODE_DETECT("relative", "#block153,#block1177"); */ /* DO_TEST_BLOCK_NODE_DETECT("gluster", "#block1008"); */