mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-01-03 11:35:19 +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
|
static void
|
||||||
qemuBlockNodeNameBackingChainDataFree(qemuBlockNodeNameBackingChainDataPtr data)
|
qemuBlockNodeNameBackingChainDataFree(qemuBlockNodeNameBackingChainDataPtr data)
|
||||||
{
|
{
|
||||||
size_t i;
|
|
||||||
|
|
||||||
if (!data)
|
if (!data)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for (i = 0; i < data->nelems; i++)
|
|
||||||
virJSONValueFree(data->elems[i]);
|
|
||||||
|
|
||||||
VIR_FREE(data->nodeformat);
|
VIR_FREE(data->nodeformat);
|
||||||
VIR_FREE(data->nodestorage);
|
VIR_FREE(data->nodestorage);
|
||||||
VIR_FREE(data->nodebacking);
|
|
||||||
|
|
||||||
VIR_FREE(data->qemufilename);
|
VIR_FREE(data->qemufilename);
|
||||||
VIR_FREE(data->backingstore);
|
|
||||||
|
qemuBlockNodeNameBackingChainDataFree(data->backing);
|
||||||
|
|
||||||
VIR_FREE(data);
|
VIR_FREE(data);
|
||||||
}
|
}
|
||||||
@ -75,55 +70,10 @@ qemuBlockNodeNameBackingChainDataHashEntryFree(void *opaque,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
struct qemuBlockNodeNameGetBackingChainData {
|
/* list of driver names of layers that qemu automatically adds into the
|
||||||
virHashTablePtr table;
|
* backing chain */
|
||||||
qemuBlockNodeNameBackingChainDataPtr *entries;
|
static const char *qemuBlockDriversBlockjob[] = {
|
||||||
size_t nentries;
|
"mirror_top", "commit_top", NULL };
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
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};
|
|
||||||
|
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
qemuBlockDriverMatch(const char *drvname,
|
qemuBlockDriverMatch(const char *drvname,
|
||||||
@ -140,86 +90,110 @@ qemuBlockDriverMatch(const char *drvname,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct qemuBlockNodeNameGetBackingChainData {
|
||||||
|
virHashTablePtr nodenamestable;
|
||||||
|
virHashTablePtr disks;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
qemuBlockNodeNameDetectProcessExtract(qemuBlockNodeNameBackingChainDataPtr data)
|
qemuBlockNodeNameGetBackingChainBacking(virJSONValuePtr next,
|
||||||
|
virHashTablePtr nodenamestable,
|
||||||
|
qemuBlockNodeNameBackingChainDataPtr *nodenamedata)
|
||||||
{
|
{
|
||||||
const char *drv;
|
qemuBlockNodeNameBackingChainDataPtr data = NULL;
|
||||||
const char *nodename;
|
qemuBlockNodeNameBackingChainDataPtr backingdata = NULL;
|
||||||
const char *backingstore;
|
virJSONValuePtr backing = virJSONValueObjectGetObject(next, "backing");
|
||||||
size_t i;
|
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
|
if (!nodename)
|
||||||
* 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)
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
for (i = 0; i < data->nelems; i++) {
|
if ((nodedata = virHashLookup(nodenamestable, nodename)) &&
|
||||||
drv = virJSONValueObjectGetString(data->elems[i], "drv");
|
(drvname = virJSONValueObjectGetString(nodedata, "drv"))) {
|
||||||
nodename = virJSONValueObjectGetString(data->elems[i], "node-name");
|
|
||||||
backingstore = virJSONValueObjectGetString(data->elems[i], "backing_file");
|
|
||||||
|
|
||||||
if (!drv || !nodename)
|
/* qemu 2.9 reports layers in the backing chain which don't correspond
|
||||||
continue;
|
* to files. skip them */
|
||||||
|
if (qemuBlockDriverMatch(drvname, qemuBlockDriversBlockjob)) {
|
||||||
if (qemuBlockDriverMatch(drv, qemuBlockDriversFormat)) {
|
if (backing) {
|
||||||
if (data->nodeformat)
|
return qemuBlockNodeNameGetBackingChainBacking(backing,
|
||||||
continue;
|
nodenamestable,
|
||||||
|
nodenamedata);
|
||||||
if (VIR_STRDUP(data->nodeformat, nodename) < 0)
|
} else {
|
||||||
return -1;
|
return 0;
|
||||||
|
}
|
||||||
/* 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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
static int
|
||||||
qemuBlockNodeNameDetectProcessLinkBacking(qemuBlockNodeNameBackingChainDataPtr data,
|
qemuBlockNodeNameGetBackingChainDisk(size_t pos ATTRIBUTE_UNUSED,
|
||||||
virHashTablePtr table)
|
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)
|
if (qemuBlockNodeNameGetBackingChainBacking(item, data->nodenamestable,
|
||||||
return 0;
|
&devicedata) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
if (!(backing = virHashLookup(table, data->backingstore)))
|
if (devicedata &&
|
||||||
return 0;
|
virHashAddEntry(data->disks, device, devicedata) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
if (VIR_STRDUP(data->nodebacking, backing->nodeformat) < 0)
|
devicedata = NULL;
|
||||||
return -1;
|
ret = 1; /* we don't really want to steal @item */
|
||||||
|
|
||||||
return 0;
|
cleanup:
|
||||||
}
|
qemuBlockNodeNameBackingChainDataFree(devicedata);
|
||||||
|
|
||||||
|
return ret;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* qemuBlockNodeNameGetBackingChain:
|
* 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
|
* 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
|
* 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.
|
* Returns a hash table on success and NULL on failure.
|
||||||
*/
|
*/
|
||||||
virHashTablePtr
|
virHashTablePtr
|
||||||
qemuBlockNodeNameGetBackingChain(virJSONValuePtr json)
|
qemuBlockNodeNameGetBackingChain(virJSONValuePtr namednodes,
|
||||||
|
virJSONValuePtr blockstats)
|
||||||
{
|
{
|
||||||
struct qemuBlockNodeNameGetBackingChainData data;
|
struct qemuBlockNodeNameGetBackingChainData data;
|
||||||
virHashTablePtr nodetable = NULL;
|
virHashTablePtr namednodestable = NULL;
|
||||||
|
virHashTablePtr disks = NULL;
|
||||||
virHashTablePtr ret = NULL;
|
virHashTablePtr ret = NULL;
|
||||||
size_t i;
|
|
||||||
|
|
||||||
memset(&data, 0, sizeof(data));
|
memset(&data, 0, sizeof(data));
|
||||||
|
|
||||||
/* hash table keeps the entries accessible by the 'file' in qemu */
|
if (!(namednodestable = virHashCreate(50, virJSONValueHashFree)))
|
||||||
if (!(data.table = virHashCreate(50, NULL)))
|
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
/* first group the named entries by the 'file' field */
|
if (virJSONValueArrayForeachSteal(namednodes,
|
||||||
if (virJSONValueArrayForeachSteal(json,
|
qemuBlockNamedNodesArrayToHash,
|
||||||
qemuBlockNodeNameDetectProcessByFilename,
|
namednodestable) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
if (!(disks = virHashCreate(50, qemuBlockNodeNameBackingChainDataHashEntryFree)))
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
data.nodenamestable = namednodestable;
|
||||||
|
data.disks = disks;
|
||||||
|
|
||||||
|
if (virJSONValueArrayForeachSteal(blockstats,
|
||||||
|
qemuBlockNodeNameGetBackingChainDisk,
|
||||||
&data) < 0)
|
&data) < 0)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
/* extract the node names for the format and storage layer */
|
VIR_STEAL_PTR(ret, disks);
|
||||||
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);
|
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
virHashFree(data.table);
|
virHashFree(namednodestable);
|
||||||
virHashFree(nodetable);
|
virHashFree(disks);
|
||||||
for (i = 0; i < data.nentries; i++)
|
|
||||||
qemuBlockNodeNameBackingChainDataFree(data.entries[i]);
|
|
||||||
|
|
||||||
VIR_FREE(data.entries);
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -314,20 +259,19 @@ qemuBlockDiskClearDetectedNodes(virDomainDiskDefPtr disk)
|
|||||||
|
|
||||||
static int
|
static int
|
||||||
qemuBlockDiskDetectNodes(virDomainDiskDefPtr disk,
|
qemuBlockDiskDetectNodes(virDomainDiskDefPtr disk,
|
||||||
const char *parentnode,
|
virHashTablePtr disktable)
|
||||||
virHashTablePtr table)
|
|
||||||
{
|
{
|
||||||
qemuBlockNodeNameBackingChainDataPtr entry = NULL;
|
qemuBlockNodeNameBackingChainDataPtr entry = NULL;
|
||||||
virStorageSourcePtr src = disk->src;
|
virStorageSourcePtr src = disk->src;
|
||||||
|
|
||||||
/* don't attempt the detection if the top level already has node names */
|
if (!(entry = virHashLookup(disktable, disk->info.alias)))
|
||||||
if (!parentnode || src->nodeformat || src->nodestorage)
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
while (src && parentnode) {
|
/* don't attempt the detection if the top level already has node names */
|
||||||
if (!(entry = virHashLookup(table, parentnode)))
|
if (src->nodeformat || src->nodestorage)
|
||||||
break;
|
return 0;
|
||||||
|
|
||||||
|
while (src && entry) {
|
||||||
if (src->nodeformat || src->nodestorage) {
|
if (src->nodeformat || src->nodestorage) {
|
||||||
if (STRNEQ_NULLABLE(src->nodeformat, entry->nodeformat) ||
|
if (STRNEQ_NULLABLE(src->nodeformat, entry->nodeformat) ||
|
||||||
STRNEQ_NULLABLE(src->nodestorage, entry->nodestorage))
|
STRNEQ_NULLABLE(src->nodestorage, entry->nodestorage))
|
||||||
@ -340,7 +284,7 @@ qemuBlockDiskDetectNodes(virDomainDiskDefPtr disk,
|
|||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
parentnode = entry->nodebacking;
|
entry = entry->backing;
|
||||||
src = src->backingStore;
|
src = src->backingStore;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -359,10 +303,9 @@ qemuBlockNodeNamesDetect(virQEMUDriverPtr driver,
|
|||||||
{
|
{
|
||||||
qemuDomainObjPrivatePtr priv = vm->privateData;
|
qemuDomainObjPrivatePtr priv = vm->privateData;
|
||||||
virHashTablePtr disktable = NULL;
|
virHashTablePtr disktable = NULL;
|
||||||
virHashTablePtr nodenametable = NULL;
|
|
||||||
virJSONValuePtr data = NULL;
|
virJSONValuePtr data = NULL;
|
||||||
|
virJSONValuePtr blockstats = NULL;
|
||||||
virDomainDiskDefPtr disk;
|
virDomainDiskDefPtr disk;
|
||||||
struct qemuDomainDiskInfo *info;
|
|
||||||
size_t i;
|
size_t i;
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
|
|
||||||
@ -372,22 +315,19 @@ qemuBlockNodeNamesDetect(virQEMUDriverPtr driver,
|
|||||||
if (qemuDomainObjEnterMonitorAsync(driver, vm, asyncJob) < 0)
|
if (qemuDomainObjEnterMonitorAsync(driver, vm, asyncJob) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
disktable = qemuMonitorGetBlockInfo(qemuDomainGetMonitor(vm));
|
|
||||||
data = qemuMonitorQueryNamedBlockNodes(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;
|
goto cleanup;
|
||||||
|
|
||||||
if (!(nodenametable = qemuBlockNodeNameGetBackingChain(data)))
|
if (!(disktable = qemuBlockNodeNameGetBackingChain(data, blockstats)))
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
for (i = 0; i < vm->def->ndisks; i++) {
|
for (i = 0; i < vm->def->ndisks; i++) {
|
||||||
disk = vm->def->disks[i];
|
disk = vm->def->disks[i];
|
||||||
|
|
||||||
if (!(info = virHashLookup(disktable, disk->info.alias)))
|
if (qemuBlockDiskDetectNodes(disk, disktable) < 0)
|
||||||
continue;
|
|
||||||
|
|
||||||
if (qemuBlockDiskDetectNodes(disk, info->nodename, nodenametable) < 0)
|
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -395,7 +335,7 @@ qemuBlockNodeNamesDetect(virQEMUDriverPtr driver,
|
|||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
virJSONValueFree(data);
|
virJSONValueFree(data);
|
||||||
virHashFree(nodenametable);
|
virJSONValueFree(blockstats);
|
||||||
virHashFree(disktable);
|
virHashFree(disktable);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -31,19 +31,15 @@ typedef struct qemuBlockNodeNameBackingChainData qemuBlockNodeNameBackingChainDa
|
|||||||
typedef qemuBlockNodeNameBackingChainData *qemuBlockNodeNameBackingChainDataPtr;
|
typedef qemuBlockNodeNameBackingChainData *qemuBlockNodeNameBackingChainDataPtr;
|
||||||
struct qemuBlockNodeNameBackingChainData {
|
struct qemuBlockNodeNameBackingChainData {
|
||||||
char *qemufilename; /* name of the image from qemu */
|
char *qemufilename; /* name of the image from qemu */
|
||||||
char *backingstore;
|
|
||||||
char *nodeformat; /* node name of the format layer */
|
char *nodeformat; /* node name of the format layer */
|
||||||
char *nodestorage; /* node name of the storage backing the format node */
|
char *nodestorage; /* node name of the storage backing the format node */
|
||||||
|
|
||||||
char *nodebacking; /* node name of the backing file format layer */
|
qemuBlockNodeNameBackingChainDataPtr backing;
|
||||||
|
|
||||||
/* data necessary for detection of the node names from qemu */
|
|
||||||
virJSONValuePtr *elems;
|
|
||||||
size_t nelems;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
virHashTablePtr
|
virHashTablePtr
|
||||||
qemuBlockNodeNameGetBackingChain(virJSONValuePtr data);
|
qemuBlockNodeNameGetBackingChain(virJSONValuePtr namednodesdata,
|
||||||
|
virJSONValuePtr blockstats);
|
||||||
|
|
||||||
int
|
int
|
||||||
qemuBlockNodeNamesDetect(virQEMUDriverPtr driver,
|
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,
|
"iops_wr": 0,
|
||||||
"ro": true,
|
"ro": true,
|
||||||
"node-name": "#block567",
|
"node-name": "#block558",
|
||||||
"backing_file_depth": 0,
|
"backing_file_depth": 0,
|
||||||
"drv": "qcow2",
|
"drv": "qcow2",
|
||||||
"iops": 0,
|
"iops": 0,
|
||||||
@ -50,7 +50,7 @@
|
|||||||
},
|
},
|
||||||
"iops_wr": 0,
|
"iops_wr": 0,
|
||||||
"ro": true,
|
"ro": true,
|
||||||
"node-name": "#block424",
|
"node-name": "#block481",
|
||||||
"backing_file_depth": 0,
|
"backing_file_depth": 0,
|
||||||
"drv": "file",
|
"drv": "file",
|
||||||
"iops": 0,
|
"iops": 0,
|
||||||
@ -109,7 +109,7 @@
|
|||||||
},
|
},
|
||||||
"iops_wr": 0,
|
"iops_wr": 0,
|
||||||
"ro": true,
|
"ro": true,
|
||||||
"node-name": "#block331",
|
"node-name": "#block306",
|
||||||
"backing_file_depth": 1,
|
"backing_file_depth": 1,
|
||||||
"drv": "qcow2",
|
"drv": "qcow2",
|
||||||
"iops": 0,
|
"iops": 0,
|
||||||
@ -139,7 +139,7 @@
|
|||||||
},
|
},
|
||||||
"iops_wr": 0,
|
"iops_wr": 0,
|
||||||
"ro": true,
|
"ro": true,
|
||||||
"node-name": "#block281",
|
"node-name": "#block220",
|
||||||
"backing_file_depth": 0,
|
"backing_file_depth": 0,
|
||||||
"drv": "file",
|
"drv": "file",
|
||||||
"iops": 0,
|
"iops": 0,
|
||||||
@ -202,7 +202,7 @@
|
|||||||
"filename": "/var/lib/libvirt/images/rhel7.3.1483545313",
|
"filename": "/var/lib/libvirt/images/rhel7.3.1483545313",
|
||||||
"cluster-size": 65536,
|
"cluster-size": 65536,
|
||||||
"format": "qcow2",
|
"format": "qcow2",
|
||||||
"actual-size": 32968704,
|
"actual-size": 33165312,
|
||||||
"format-specific": {
|
"format-specific": {
|
||||||
"type": "qcow2",
|
"type": "qcow2",
|
||||||
"data": {
|
"data": {
|
||||||
@ -218,7 +218,7 @@
|
|||||||
},
|
},
|
||||||
"iops_wr": 0,
|
"iops_wr": 0,
|
||||||
"ro": false,
|
"ro": false,
|
||||||
"node-name": "#block118",
|
"node-name": "#block187",
|
||||||
"backing_file_depth": 2,
|
"backing_file_depth": 2,
|
||||||
"drv": "qcow2",
|
"drv": "qcow2",
|
||||||
"iops": 0,
|
"iops": 0,
|
||||||
@ -240,15 +240,15 @@
|
|||||||
"iops_rd": 0,
|
"iops_rd": 0,
|
||||||
"detect_zeroes": "off",
|
"detect_zeroes": "off",
|
||||||
"image": {
|
"image": {
|
||||||
"virtual-size": 33030144,
|
"virtual-size": 33226752,
|
||||||
"filename": "/var/lib/libvirt/images/rhel7.3.1483545313",
|
"filename": "/var/lib/libvirt/images/rhel7.3.1483545313",
|
||||||
"format": "file",
|
"format": "file",
|
||||||
"actual-size": 32968704,
|
"actual-size": 33165312,
|
||||||
"dirty-flag": false
|
"dirty-flag": false
|
||||||
},
|
},
|
||||||
"iops_wr": 0,
|
"iops_wr": 0,
|
||||||
"ro": false,
|
"ro": false,
|
||||||
"node-name": "#block078",
|
"node-name": "#block033",
|
||||||
"backing_file_depth": 0,
|
"backing_file_depth": 0,
|
||||||
"drv": "file",
|
"drv": "file",
|
||||||
"iops": 0,
|
"iops": 0,
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
filename : '/var/lib/libvirt/images/rhel7.3.1483545313'
|
filename : '/var/lib/libvirt/images/rhel7.3.1483545313'
|
||||||
format node : '#block118'
|
format node : '#block187'
|
||||||
storage node: '#block078'
|
storage node: '#block033'
|
||||||
filename : '/var/lib/libvirt/images/rhel7.3.1483536402'
|
filename : '/var/lib/libvirt/images/rhel7.3.1483536402'
|
||||||
format node : '#block331'
|
format node : '#block306'
|
||||||
storage node: '#block281'
|
storage node: '#block220'
|
||||||
filename : '/var/lib/libvirt/images/rhel7.3.qcow2'
|
filename : '/var/lib/libvirt/images/rhel7.3.qcow2'
|
||||||
format node : '#block567'
|
format node : '#block558'
|
||||||
storage node: '#block424'
|
storage node: '#block481'
|
||||||
|
@ -2704,18 +2704,17 @@ struct testBlockNodeNameDetectData {
|
|||||||
|
|
||||||
static void
|
static void
|
||||||
testBlockNodeNameDetectFormat(virBufferPtr buf,
|
testBlockNodeNameDetectFormat(virBufferPtr buf,
|
||||||
const char *basenode,
|
const char *diskalias,
|
||||||
virHashTablePtr nodedata)
|
virHashTablePtr nodedata)
|
||||||
{
|
{
|
||||||
qemuBlockNodeNameBackingChainDataPtr entry = NULL;
|
qemuBlockNodeNameBackingChainDataPtr entry = NULL;
|
||||||
const char *node = basenode;
|
|
||||||
|
|
||||||
virBufferSetIndent(buf, 0);
|
virBufferSetIndent(buf, 0);
|
||||||
|
|
||||||
while (node) {
|
if (!(entry = virHashLookup(nodedata, diskalias)))
|
||||||
if (!(entry = virHashLookup(nodedata, node)))
|
return;
|
||||||
break;
|
|
||||||
|
|
||||||
|
while (entry) {
|
||||||
virBufferAsprintf(buf, "filename : '%s'\n", entry->qemufilename);
|
virBufferAsprintf(buf, "filename : '%s'\n", entry->qemufilename);
|
||||||
virBufferAsprintf(buf, "format node : '%s'\n",
|
virBufferAsprintf(buf, "format node : '%s'\n",
|
||||||
NULLSTR(entry->nodeformat));
|
NULLSTR(entry->nodeformat));
|
||||||
@ -2724,7 +2723,7 @@ testBlockNodeNameDetectFormat(virBufferPtr buf,
|
|||||||
|
|
||||||
virBufferAdjustIndent(buf, 2);
|
virBufferAdjustIndent(buf, 2);
|
||||||
|
|
||||||
node = entry->nodebacking;
|
entry = entry->backing;
|
||||||
}
|
}
|
||||||
|
|
||||||
virBufferSetIndent(buf, 0);
|
virBufferSetIndent(buf, 0);
|
||||||
@ -2742,6 +2741,7 @@ testBlockNodeNameDetect(const void *opaque)
|
|||||||
char **nodenames = NULL;
|
char **nodenames = NULL;
|
||||||
char **next;
|
char **next;
|
||||||
virJSONValuePtr namedNodesJson = NULL;
|
virJSONValuePtr namedNodesJson = NULL;
|
||||||
|
virJSONValuePtr blockstatsJson = NULL;
|
||||||
virHashTablePtr nodedata = NULL;
|
virHashTablePtr nodedata = NULL;
|
||||||
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
@ -2757,7 +2757,12 @@ testBlockNodeNameDetect(const void *opaque)
|
|||||||
"-named-nodes.json", NULL)))
|
"-named-nodes.json", NULL)))
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
if (!(nodedata = qemuBlockNodeNameGetBackingChain(namedNodesJson)))
|
if (!(blockstatsJson = virTestLoadFileJSON(pathprefix, data->name,
|
||||||
|
"-blockstats.json", NULL)))
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
if (!(nodedata = qemuBlockNodeNameGetBackingChain(namedNodesJson,
|
||||||
|
blockstatsJson)))
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
for (next = nodenames; *next; next++)
|
for (next = nodenames; *next; next++)
|
||||||
@ -2781,6 +2786,7 @@ testBlockNodeNameDetect(const void *opaque)
|
|||||||
virHashFree(nodedata);
|
virHashFree(nodedata);
|
||||||
virStringListFree(nodenames);
|
virStringListFree(nodenames);
|
||||||
virJSONValueFree(namedNodesJson);
|
virJSONValueFree(namedNodesJson);
|
||||||
|
virJSONValueFree(blockstatsJson);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -2929,7 +2935,7 @@ mymain(void)
|
|||||||
ret = -1; \
|
ret = -1; \
|
||||||
} while (0)
|
} 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("same-backing", "#block170,#block574"); */
|
||||||
/* DO_TEST_BLOCK_NODE_DETECT("relative", "#block153,#block1177"); */
|
/* DO_TEST_BLOCK_NODE_DETECT("relative", "#block153,#block1177"); */
|
||||||
/* DO_TEST_BLOCK_NODE_DETECT("gluster", "#block1008"); */
|
/* DO_TEST_BLOCK_NODE_DETECT("gluster", "#block1008"); */
|
||||||
|
Loading…
Reference in New Issue
Block a user