qemu: block: Add code to detect node names when necessary

Detect the node names when setting block threshold and when reconnecting
or when they are cleared when a block job finishes. This operation will
become a no-op once we fully support node names.
This commit is contained in:
Peter Krempa 2017-03-15 13:03:21 +01:00
parent 2780bcd9f8
commit 0feebab2c4
5 changed files with 117 additions and 0 deletions

View File

@ -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;
}

View File

@ -44,4 +44,8 @@ struct qemuBlockNodeNameBackingChainData {
virHashTablePtr
qemuBlockNodeNameGetBackingChain(virJSONValuePtr data);
int
qemuBlockNodeNamesDetect(virQEMUDriverPtr driver,
virDomainObjPtr vm);
#endif /* __QEMU_BLOCK_H__ */

View File

@ -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;

View File

@ -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'"),

View File

@ -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;