[libvirt] [PATCH v2 3/5] qemu: Implement the qemu driver for virDomainGetFSInfo
John Ferlan
jferlan at redhat.com
Wed Nov 19 22:51:47 UTC 2014
On 11/17/2014 06:27 PM, Tomoki Sekiyama wrote:
> Get mounted filesystems list, which contains hardware info of disks and its
> controllers, from QEMU guest agent 2.2+. Then, convert the hardware info
> to corresponding device aliases for the disks.
>
> Signed-off-by: Tomoki Sekiyama <tomoki.sekiyama at hds.com>
> ---
> src/conf/domain_conf.c | 71 ++++++++++++++++++
> src/conf/domain_conf.h | 6 ++
> src/libvirt_private.syms | 1
> src/qemu/qemu_agent.c | 178 ++++++++++++++++++++++++++++++++++++++++++++++
> src/qemu/qemu_agent.h | 2 +
> src/qemu/qemu_driver.c | 48 ++++++++++++
> 6 files changed, 306 insertions(+)
>
> diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
> index 5f4b9f6..5972d7a 100644
> --- a/src/conf/domain_conf.c
> +++ b/src/conf/domain_conf.c
> @@ -11114,6 +11114,60 @@ virDomainHostdevFind(virDomainDefPtr def,
> return *found ? i : -1;
> }
>
> +static bool
> +virDomainDiskControllerMatch(int controller_type, int disk_bus)
> +{
> + if (controller_type == VIR_DOMAIN_CONTROLLER_TYPE_SCSI &&
> + disk_bus == VIR_DOMAIN_DISK_BUS_SCSI)
> + return true;
> +
> + if (controller_type == VIR_DOMAIN_CONTROLLER_TYPE_FDC &&
> + disk_bus == VIR_DOMAIN_DISK_BUS_FDC)
> + return true;
> +
> + if (controller_type == VIR_DOMAIN_CONTROLLER_TYPE_IDE &&
> + disk_bus == VIR_DOMAIN_DISK_BUS_IDE)
> + return true;
> +
> + if (controller_type == VIR_DOMAIN_CONTROLLER_TYPE_SATA &&
> + disk_bus == VIR_DOMAIN_DISK_BUS_SATA)
> + return true;
> +
> + return false;
> +}
> +
> +int
> +virDomainDiskIndexByAddress(virDomainDefPtr def,
> + virDevicePCIAddressPtr pci_address,
> + unsigned int bus, unsigned int target,
> + unsigned int unit)
> +{
> + virDomainDiskDefPtr vdisk;
> + virDomainControllerDefPtr controller = NULL;
> + size_t i;
> + int cidx;
> +
> + if ((cidx = virDomainControllerFindByPCIAddress(def, pci_address)) >= 0)
> + controller = def->controllers[cidx];
> +
> + for (i = 0; i < def->ndisks; i++) {
> + vdisk = def->disks[i];
> + if (vdisk->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI &&
> + virDevicePCIAddressEqual(&vdisk->info.addr.pci, pci_address))
> + return i;
> + if (vdisk->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_DRIVE) {
> + virDomainDeviceDriveAddressPtr drive = &vdisk->info.addr.drive;
> + if (controller &&
> + virDomainDiskControllerMatch(controller->type, vdisk->bus) &&
> + drive->controller == controller->idx &&
> + drive->bus == bus && drive->target == target &&
> + drive->unit == unit)
> + return i;
> + }
> + }
> + return -1;
> +}
> +
> int
> virDomainDiskIndexByName(virDomainDefPtr def, const char *name,
> bool allow_ambiguous)
> @@ -11403,6 +11457,23 @@ virDomainControllerFind(virDomainDefPtr def,
> return -1;
> }
>
> +int
> +virDomainControllerFindByPCIAddress(virDomainDefPtr def,
> + virDevicePCIAddressPtr addr)
> +{
> + size_t i;
> +
> + for (i = 0; i < def->ncontrollers; i++) {
> + virDomainDeviceInfoPtr info = &def->controllers[i]->info;
> +
> + if (info->type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI &&
> + virDevicePCIAddressEqual(&info->addr.pci, addr))
> + return i;
> + }
> +
> + return -1;
> +}
> +
> virDomainControllerDefPtr
> virDomainControllerRemove(virDomainDefPtr def, size_t i)
> {
> diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
> index 530a3ca..6164588 100644
> --- a/src/conf/domain_conf.h
> +++ b/src/conf/domain_conf.h
> @@ -2461,6 +2461,10 @@ int virDomainEmulatorPinDel(virDomainDefPtr def);
>
> void virDomainRNGDefFree(virDomainRNGDefPtr def);
>
> +int virDomainDiskIndexByAddress(virDomainDefPtr def,
> + virDevicePCIAddressPtr pci_controller,
> + unsigned int bus, unsigned int target,
> + unsigned int unit);
> int virDomainDiskIndexByName(virDomainDefPtr def, const char *name,
> bool allow_ambiguous);
> const char *virDomainDiskPathByName(virDomainDefPtr, const char *name);
> @@ -2529,6 +2533,8 @@ int virDomainControllerInsert(virDomainDefPtr def,
> void virDomainControllerInsertPreAlloced(virDomainDefPtr def,
> virDomainControllerDefPtr controller);
> int virDomainControllerFind(virDomainDefPtr def, int type, int idx);
> +int virDomainControllerFindByPCIAddress(virDomainDefPtr def,
> + virDevicePCIAddressPtr addr);
> virDomainControllerDefPtr virDomainControllerRemove(virDomainDefPtr def, size_t i);
>
> int virDomainLeaseIndex(virDomainDefPtr def,
> diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
> index 0864618..16d4311 100644
> --- a/src/libvirt_private.syms
> +++ b/src/libvirt_private.syms
> @@ -234,6 +234,7 @@ virDomainDiskGetDriver;
> virDomainDiskGetFormat;
> virDomainDiskGetSource;
> virDomainDiskGetType;
> +virDomainDiskIndexByAddress;
> virDomainDiskIndexByName;
> virDomainDiskInsert;
> virDomainDiskInsertPreAlloced;
> diff --git a/src/qemu/qemu_agent.c b/src/qemu/qemu_agent.c
> index 8df1330..f6432cc 100644
> --- a/src/qemu/qemu_agent.c
> +++ b/src/qemu/qemu_agent.c
> @@ -1777,3 +1777,181 @@ qemuAgentSetTime(qemuAgentPtr mon,
> virJSONValueFree(reply);
> return ret;
> }
> +
> +
> +int
> +qemuAgentGetFSInfo(qemuAgentPtr mon, virDomainFSInfoPtr **info,
> + virDomainDefPtr vmdef)
> +{
> + size_t i, j, k;
> + int ret = -1;
> + int ndata = 0, ndisk;
> + char **alias;
> + virJSONValuePtr cmd;
> + virJSONValuePtr reply = NULL;
> + virJSONValuePtr data;
> + virDomainFSInfoPtr *info_ret = NULL;
> + virDevicePCIAddress pci_address;
> +
> + cmd = qemuAgentMakeCommand("guest-get-fsinfo", NULL);
> + if (!cmd)
> + return ret;
> +
> + if (qemuAgentCommand(mon, cmd, &reply, true,
> + VIR_DOMAIN_QEMU_AGENT_COMMAND_BLOCK) < 0)
> + goto cleanup;
> +
> + if (!(data = virJSONValueObjectGet(reply, "return"))) {
> + virReportError(VIR_ERR_INTERNAL_ERROR,
> + _("'%s' missing in reply of guest-get-fsinfo"),
> + "return");
Not exactly what I had in mind, but I'll fix these... There's also
an indent issue here (cut-n-paste from some other error message I assume)
There was also a check-syntax error or two with those multiline messages...
> + goto cleanup;
> + }
> +
> + if (data->type != VIR_JSON_TYPE_ARRAY) {
> + virReportError(VIR_ERR_INTERNAL_ERROR,
> + _("guest-get-fsinfo '%s' data was not an array"),
> + "return");
> + goto cleanup;
> + }
> +
> + ndata = virJSONValueArraySize(data);
> + if (!ndata) {
> + ret = 0;
> + goto cleanup;
> + }
> + if (VIR_ALLOC_N(info_ret, ndata) < 0)
> + goto cleanup;
> +
> + for (i = 0; i < ndata; i++) {
> + /* Reverse the order to arrange in mount order */
> + virJSONValuePtr entry = virJSONValueArrayGet(data, ndata - 1 - i);
> +
> + if (!entry) {
> + virReportError(VIR_ERR_INTERNAL_ERROR,
> + _("array element '%zd' of '%d' missing in"
> + "guest-get-fsinfo '%s' data"),
> + i, ndata, "return");
> + goto cleanup;
> + }
> +
> + if (VIR_ALLOC(info_ret[i]) < 0)
> + goto cleanup;
> +
> + if (VIR_STRDUP(info_ret[i]->mountpoint,
> + virJSONValueObjectGetString(entry, "mountpoint")) < 0) {
> + virReportError(VIR_ERR_INTERNAL_ERROR,
> + _("'%s' missing in reply of guest-get-fsinfo"),
> + "mountpoint");
> + goto cleanup;
> + }
> +
> + if (VIR_STRDUP(info_ret[i]->name,
> + virJSONValueObjectGetString(entry, "name")) < 0) {
> + virReportError(VIR_ERR_INTERNAL_ERROR,
> + _("'%s' missing in reply of guest-get-fsinfo"),
> + "name");
> + goto cleanup;
> + }
> +
> + if (VIR_STRDUP(info_ret[i]->type,
> + virJSONValueObjectGetString(entry, "type")) < 0) {
> + virReportError(VIR_ERR_INTERNAL_ERROR,
> + _("'%s' missing in reply of guest-get-fsinfo"),
> + "type");
> + goto cleanup;
> + }
> +
> + if (!(entry = virJSONValueObjectGet(entry, "disk"))) {
> + virReportError(VIR_ERR_INTERNAL_ERROR,
> + _("'%s' missing in reply of guest-get-fsinfo"),
> + "disk");
> + goto cleanup;
> + }
> +
> + if (entry->type != VIR_JSON_TYPE_ARRAY) {
> + virReportError(VIR_ERR_INTERNAL_ERROR,
> + _("guest-get-fsinfo '%s' data was not an array"),
> + "disk");
> + goto cleanup;
> + }
> +
> + ndisk = virJSONValueArraySize(entry);
> + if (!ndisk)
> + continue;
> + if (VIR_ALLOC_N(info_ret[i]->devAlias, ndisk + 1) < 0)
> + goto cleanup;
> +
> + alias = info_ret[i]->devAlias;
> + for (j = 0; j < ndisk; j++) {
> + virJSONValuePtr disk = virJSONValueArrayGet(entry, j);
> + virJSONValuePtr pci;
> + int diskaddr[3], pciaddr[4], idx;
> + const char *diskaddr_comp[] = {"bus", "target", "unit"};
> + const char *pciaddr_comp[] = {"domain", "bus", "slot", "function"};
> +
> + if (!disk) {
> + virReportError(VIR_ERR_INTERNAL_ERROR,
> + _("array element '%zd' of '%d' missing in"
> + "guest-get-fsinfo '%s' data"),
> + j, ndisk, "disk");
> + goto cleanup;
> + }
> +
> + if (!(pci = virJSONValueObjectGet(disk, "pci-controller"))) {
> + virReportError(VIR_ERR_INTERNAL_ERROR,
> + _("'%s' missing in guest-get-fsinfo "
> + "'disk' data"), "pci-controller");
> + goto cleanup;
> + }
> +
> + for (k = 0; k < 3; k++) {
> + if (virJSONValueObjectGetNumberInt(
> + disk, diskaddr_comp[k], &diskaddr[k]) < 0) {
> + virReportError(VIR_ERR_INTERNAL_ERROR,
> + _("'%s' missing in guest-get-fsinfo "
> + "'disk' data"), diskaddr_comp[k]);
> + goto cleanup;
> + }
> + }
> + for (k = 0; k < 4; k++) {
> + if (virJSONValueObjectGetNumberInt(
> + pci, pciaddr_comp[k], &pciaddr[k]) < 0) {
> + virReportError(VIR_ERR_INTERNAL_ERROR,
> + _("'%s' missing in guest-get-fsinfo "
> + "'pci-address' data"), pciaddr_comp[k]);
> + goto cleanup;
> + }
> + }
> +
> + pci_address.domain = pciaddr[0];
> + pci_address.bus = pciaddr[1];
> + pci_address.slot = pciaddr[2];
> + pci_address.function = pciaddr[3];
> + if ((idx = virDomainDiskIndexByAddress(
> + vmdef, &pci_address,
> + diskaddr[0], diskaddr[1], diskaddr[2])) < 0)
> + continue;
> +
> + if (VIR_STRDUP(*alias, vmdef->disks[idx]->dst) < 0)
> + goto cleanup;
> +
> + if (*alias)
> + alias++;
> + }
> + }
> +
> + *info = info_ret;
> + info_ret = NULL;
> + ret = ndata;
> +
> + cleanup:
> + if (info_ret) {
> + for (i = 0; i < ndata; i++)
> + virDomainFSInfoFree(info_ret[i]);
> + VIR_FREE(info_ret);
> + }
> + virJSONValueFree(cmd);
> + virJSONValueFree(reply);
> + return ret;
> +}
I'll squash the following in (hopefully I got the cut-n-paste right):
diff --git a/src/qemu/qemu_agent.c b/src/qemu/qemu_agent.c
index f6432cc..dcbeee8 100644
--- a/src/qemu/qemu_agent.c
+++ b/src/qemu/qemu_agent.c
@@ -1802,16 +1802,15 @@ qemuAgentGetFSInfo(qemuAgentPtr mon, virDomainFSInfoPtr
goto cleanup;
if (!(data = virJSONValueObjectGet(reply, "return"))) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("'%s' missing in reply of guest-get-fsinfo"),
- "return");
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("guest-get-fsinfo reply was missing return data"))
goto cleanup;
}
if (data->type != VIR_JSON_TYPE_ARRAY) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("guest-get-fsinfo '%s' data was not an array"),
- "return");
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("guest-get-fsinfo return information was not "
+ "an array"));
goto cleanup;
}
@@ -1830,8 +1829,8 @@ qemuAgentGetFSInfo(qemuAgentPtr mon, virDomainFSInfoPtr **
if (!entry) {
virReportError(VIR_ERR_INTERNAL_ERROR,
- _("array element '%zd' of '%d' missing in"
- "guest-get-fsinfo '%s' data"),
- i, ndata, "return");
+ _("array element '%zd' of '%d' missing in "
+ "guest-get-fsinfo return data"),
+ i, ndata);
goto cleanup;
}
@@ -1840,39 +1839,35 @@ qemuAgentGetFSInfo(qemuAgentPtr mon, virDomainFSInfoPtr
if (VIR_STRDUP(info_ret[i]->mountpoint,
virJSONValueObjectGetString(entry, "mountpoint")) < 0) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("'%s' missing in reply of guest-get-fsinfo"),
- "mountpoint");
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("'mountpoint' missing in reply of "
+ "guest-get-fsinfo"));
goto cleanup;
}
if (VIR_STRDUP(info_ret[i]->name,
virJSONValueObjectGetString(entry, "name")) < 0) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("'%s' missing in reply of guest-get-fsinfo"),
- "name");
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("'name' missing in reply of guest-get-fsinfo"));
goto cleanup;
}
if (VIR_STRDUP(info_ret[i]->type,
virJSONValueObjectGetString(entry, "type")) < 0) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("'%s' missing in reply of guest-get-fsinfo"),
- "type");
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("'type' missing in reply of guest-get-fsinfo"));
goto cleanup;
}
if (!(entry = virJSONValueObjectGet(entry, "disk"))) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("'%s' missing in reply of guest-get-fsinfo"),
- "disk");
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("'disk' missing in reply of guest-get-fsinfo"));
goto cleanup;
}
if (entry->type != VIR_JSON_TYPE_ARRAY) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("guest-get-fsinfo '%s' data was not an array"),
- "disk");
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("guest-get-fsinfo 'disk' data was not an array"));
goto cleanup;
}
@@ -1893,15 +1888,15 @@ qemuAgentGetFSInfo(qemuAgentPtr mon, virDomainFSInfoPtr
if (!disk) {
virReportError(VIR_ERR_INTERNAL_ERROR,
- _("array element '%zd' of '%d' missing in"
- "guest-get-fsinfo '%s' data"),
- j, ndisk, "disk");
+ _("array element '%zd' of '%d' missing in "
+ "guest-get-fsinfo 'disk' data"),
+ j, ndisk);
goto cleanup;
}
if (!(pci = virJSONValueObjectGet(disk, "pci-controller"))) {
- virReportError(VIR_ERR_INTERNAL_ERROR,
- _("'%s' missing in guest-get-fsinfo "
- "'disk' data"), "pci-controller");
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("'pci-controller' missing in guest-get-fsinfo
+ "'disk' data"));
goto cleanup;
}
> diff --git a/src/qemu/qemu_agent.h b/src/qemu/qemu_agent.h
> index 6cd6b49..c983828 100644
> --- a/src/qemu/qemu_agent.h
> +++ b/src/qemu/qemu_agent.h
> @@ -73,6 +73,8 @@ int qemuAgentShutdown(qemuAgentPtr mon,
> int qemuAgentFSFreeze(qemuAgentPtr mon,
> const char **mountpoints, unsigned int nmountpoints);
> int qemuAgentFSThaw(qemuAgentPtr mon);
> +int qemuAgentGetFSInfo(qemuAgentPtr mon, virDomainFSInfoPtr **info,
> + virDomainDefPtr vmdef);
>
> int qemuAgentSuspend(qemuAgentPtr mon,
> unsigned int target);
> diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
> index a84fd47..f655302 100644
> --- a/src/qemu/qemu_driver.c
> +++ b/src/qemu/qemu_driver.c
> @@ -18767,6 +18767,53 @@ qemuNodeAllocPages(virConnectPtr conn,
> }
>
>
> +static int
> +qemuDomainGetFSInfo(virDomainPtr dom,
> + virDomainFSInfoPtr **info,
> + unsigned int flags)
> +{
> + virQEMUDriverPtr driver = dom->conn->privateData;
> + qemuDomainObjPrivatePtr priv;
> + virDomainObjPtr vm;
> + int ret = -1;
> +
> + virCheckFlags(0, ret);
> +
> + if (!(vm = qemuDomObjFromDomain(dom)))
> + return ret;
> +
> + if (virDomainGetFSInfoEnsureACL(dom->conn, vm->def) < 0)
> + goto cleanup;
> +
> + priv = vm->privateData;
> +
> + if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
> + goto cleanup;
Again - this is a QUERY not a MODIFY as far as I understand things, correct?
remote_protocol.x has:
+ /**
+ * @generate: none
+ * @acl: domain:read
+ */
+ REMOTE_PROC_DOMAIN_GET_FSINFO = 348
Although everything that happens here is not my specialty, so hopefully
someone else reads this review and can comment...
> +
> + if (!virDomainObjIsActive(vm)) {
> + virReportError(VIR_ERR_OPERATION_INVALID,
> + "%s", _("domain is not running"));
> + goto endjob;
> + }
> +
> + if (!qemuDomainAgentAvailable(priv, true))
> + goto endjob;
> +
> + qemuDomainObjEnterAgent(vm);
> + ret = qemuAgentGetFSInfo(priv->agent, info, vm->def);
> + qemuDomainObjExitAgent(vm);
> +
> + endjob:
> + if (!qemuDomainObjEndJob(driver, vm))
> + vm = NULL;
> +
> + cleanup:
> + if (vm)
> + virObjectUnlock(vm);
> + return ret;
> +}
> +
> +
> static virHypervisorDriver qemuDriver = {
> .no = VIR_DRV_QEMU,
> .name = QEMU_DRIVER_NAME,
> @@ -18967,6 +19014,7 @@ static virHypervisorDriver qemuDriver = {
> .connectGetDomainCapabilities = qemuConnectGetDomainCapabilities, /* 1.2.7 */
> .connectGetAllDomainStats = qemuConnectGetAllDomainStats, /* 1.2.8 */
> .nodeAllocPages = qemuNodeAllocPages, /* 1.2.9 */
> + .domainGetFSInfo = qemuDomainGetFSInfo, /* 1.2.11 */
> };
>
>
>
I'll squash the following in:
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 9f7d951..2263b59 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -18787,7 +18787,7 @@ qemuDomainGetFSInfo(virDomainPtr dom,
priv = vm->privateData;
- if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
+ if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_QUERY) < 0)
goto cleanup;
if (!virDomainObjIsActive(vm)) {
More information about the libvir-list
mailing list