mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-12-23 06:05:27 +00:00
qemu: Implement the qemu driver for virDomainGetFSInfo
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@hds.com>
This commit is contained in:
parent
ee3dc4f19b
commit
5c9cfa4976
@ -11172,6 +11172,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)
|
||||
@ -11461,6 +11515,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)
|
||||
{
|
||||
|
@ -2476,6 +2476,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);
|
||||
@ -2545,6 +2549,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,
|
||||
|
@ -234,6 +234,7 @@ virDomainDiskGetDriver;
|
||||
virDomainDiskGetFormat;
|
||||
virDomainDiskGetSource;
|
||||
virDomainDiskGetType;
|
||||
virDomainDiskIndexByAddress;
|
||||
virDomainDiskIndexByName;
|
||||
virDomainDiskInsert;
|
||||
virDomainDiskInsertPreAlloced;
|
||||
|
@ -1777,3 +1777,179 @@ 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",
|
||||
_("guest-get-fsinfo reply was missing return data"));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (data->type != VIR_JSON_TYPE_ARRAY) {
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
||||
_("guest-get-fsinfo return information was not "
|
||||
"an array"));
|
||||
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 return data"),
|
||||
i, ndata);
|
||||
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",
|
||||
_("'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",
|
||||
_("'name' missing in reply of guest-get-fsinfo"));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (VIR_STRDUP(info_ret[i]->fstype,
|
||||
virJSONValueObjectGetString(entry, "type")) < 0) {
|
||||
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",
|
||||
_("'disk' missing in reply of guest-get-fsinfo"));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (entry->type != VIR_JSON_TYPE_ARRAY) {
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
||||
_("guest-get-fsinfo 'disk' data was not an array"));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ndisk = virJSONValueArraySize(entry);
|
||||
if (!ndisk)
|
||||
continue;
|
||||
if (VIR_ALLOC_N(info_ret[i]->devAlias, ndisk) < 0)
|
||||
goto cleanup;
|
||||
|
||||
alias = info_ret[i]->devAlias;
|
||||
info_ret[i]->ndevAlias = 0;
|
||||
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 'disk' data"),
|
||||
j, ndisk);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (!(pci = virJSONValueObjectGet(disk, "pci-controller"))) {
|
||||
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
||||
_("'pci-controller' missing in guest-get-fsinfo "
|
||||
"'disk' data"));
|
||||
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_ret[i]->ndevAlias++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -18832,6 +18832,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_QUERY) < 0)
|
||||
goto cleanup;
|
||||
|
||||
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,
|
||||
@ -19032,6 +19079,7 @@ static virHypervisorDriver qemuDriver = {
|
||||
.connectGetDomainCapabilities = qemuConnectGetDomainCapabilities, /* 1.2.7 */
|
||||
.connectGetAllDomainStats = qemuConnectGetAllDomainStats, /* 1.2.8 */
|
||||
.nodeAllocPages = qemuNodeAllocPages, /* 1.2.9 */
|
||||
.domainGetFSInfo = qemuDomainGetFSInfo, /* 1.2.11 */
|
||||
};
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user