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(a)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)) {