mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-12-22 05:35:25 +00:00
qemu: block: Refactor node name detection code
Remove the complex and unreliable code which inferred the node name hierarchy only from data returned by 'query-named-block-nodes'. It turns out that query-blockstats contain the full hierarchy of nodes as perceived by qemu so the inference code is not necessary. In query blockstats, the 'parent' object corresponds to the storage behind a storage volume and 'backing' corresponds to the lower level of backing chain. Since all have node names this data can be really easily used to detect node names. In addition to the code refactoring the one remaining test case needed to be fixed along. Reviewed-by: Eric Blake <eblake@redhat.com>
This commit is contained in:
parent
c61d169327
commit
0175dc6ea0
@ -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,
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
qemuBlockNodeNameDetectProcessExtract(qemuBlockNodeNameBackingChainDataPtr data)
|
||||
{
|
||||
const char *drv;
|
||||
const char *nodename;
|
||||
const char *backingstore;
|
||||
size_t i;
|
||||
struct qemuBlockNodeNameGetBackingChainData {
|
||||
virHashTablePtr nodenamestable;
|
||||
virHashTablePtr disks;
|
||||
};
|
||||
|
||||
/* 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)
|
||||
|
||||
static int
|
||||
qemuBlockNodeNameGetBackingChainBacking(virJSONValuePtr next,
|
||||
virHashTablePtr nodenamestable,
|
||||
qemuBlockNodeNameBackingChainDataPtr *nodenamedata)
|
||||
{
|
||||
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;
|
||||
|
||||
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"))) {
|
||||
|
||||
if (!drv || !nodename)
|
||||
continue;
|
||||
|
||||
if (qemuBlockDriverMatch(drv, qemuBlockDriversFormat)) {
|
||||
if (data->nodeformat)
|
||||
continue;
|
||||
|
||||
if (VIR_STRDUP(data->nodeformat, nodename) < 0)
|
||||
return -1;
|
||||
|
||||
/* 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 (VIR_STRDUP(data->nodestorage, nodename) < 0)
|
||||
return -1;
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
if (parent &&
|
||||
(parentnodename = virJSONValueObjectGetString(parent, "node-name"))) {
|
||||
if ((parentnodedata = virHashLookup(nodenamestable, parentnodename)))
|
||||
filename = virJSONValueObjectGetString(parentnodedata, "file");
|
||||
}
|
||||
|
||||
if (VIR_ALLOC(data) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (VIR_STRDUP(data->nodeformat, nodename) < 0 ||
|
||||
VIR_STRDUP(data->nodestorage, parentnodename) < 0 ||
|
||||
VIR_STRDUP(data->qemufilename, filename) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (backing &&
|
||||
qemuBlockNodeNameGetBackingChainBacking(backing, nodenamestable,
|
||||
&backingdata) < 0)
|
||||
goto cleanup;
|
||||
|
||||
VIR_STEAL_PTR(data->backing, backingdata);
|
||||
VIR_STEAL_PTR(*nodenamedata, data);
|
||||
|
||||
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;
|
||||
struct qemuBlockNodeNameGetBackingChainData *data = opaque;
|
||||
const char *device = virJSONValueObjectGetString(item, "device");
|
||||
qemuBlockNodeNameBackingChainDataPtr devicedata = NULL;
|
||||
int ret = -1;
|
||||
|
||||
if (!data->backingstore)
|
||||
return 0;
|
||||
if (qemuBlockNodeNameGetBackingChainBacking(item, data->nodenamestable,
|
||||
&devicedata) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (!(backing = virHashLookup(table, data->backingstore)))
|
||||
return 0;
|
||||
if (devicedata &&
|
||||
virHashAddEntry(data->disks, device, devicedata) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (VIR_STRDUP(data->nodebacking, backing->nodeformat) < 0)
|
||||
return -1;
|
||||
devicedata = NULL;
|
||||
ret = 1; /* we don't really want to steal @item */
|
||||
|
||||
return 0;
|
||||
}
|
||||
cleanup:
|
||||
qemuBlockNodeNameBackingChainDataFree(devicedata);
|
||||
|
||||
|
||||
static void
|
||||
qemuBlockNodeNameGetBackingChainDataClearLookup(qemuBlockNodeNameBackingChainDataPtr data)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < data->nelems; i++)
|
||||
virJSONValueFree(data->elems[i]);
|
||||
|
||||
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,
|
||||
if (virJSONValueArrayForeachSteal(namednodes,
|
||||
qemuBlockNamedNodesArrayToHash,
|
||||
namednodestable) < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (!(disks = virHashCreate(50, qemuBlockNodeNameBackingChainDataHashEntryFree)))
|
||||
goto cleanup;
|
||||
|
||||
data.nodenamestable = namednodestable;
|
||||
data.disks = disks;
|
||||
|
||||
if (virJSONValueArrayForeachSteal(blockstats,
|
||||
qemuBlockNodeNameGetBackingChainDisk,
|
||||
&data) < 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)))
|
||||
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;
|
||||
|
||||
/* hash table steals the entry and then frees it by itself */
|
||||
data.entries[i] = NULL;
|
||||
}
|
||||
|
||||
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;
|
||||
|
@ -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,
|
||||
|
@ -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"
|
||||
}
|
||||
]
|
@ -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,
|
||||
|
@ -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'
|
||||
|
@ -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"); */
|
||||
|
Loading…
Reference in New Issue
Block a user