mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-07-31 22:17:17 +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;
|
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
|
int
|
||||||
virDomainDiskIndexByName(virDomainDefPtr def, const char *name,
|
virDomainDiskIndexByName(virDomainDefPtr def, const char *name,
|
||||||
bool allow_ambiguous)
|
bool allow_ambiguous)
|
||||||
@ -11461,6 +11515,23 @@ virDomainControllerFind(virDomainDefPtr def,
|
|||||||
return -1;
|
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
|
virDomainControllerDefPtr
|
||||||
virDomainControllerRemove(virDomainDefPtr def, size_t i)
|
virDomainControllerRemove(virDomainDefPtr def, size_t i)
|
||||||
{
|
{
|
||||||
|
@ -2476,6 +2476,10 @@ int virDomainEmulatorPinDel(virDomainDefPtr def);
|
|||||||
|
|
||||||
void virDomainRNGDefFree(virDomainRNGDefPtr 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,
|
int virDomainDiskIndexByName(virDomainDefPtr def, const char *name,
|
||||||
bool allow_ambiguous);
|
bool allow_ambiguous);
|
||||||
const char *virDomainDiskPathByName(virDomainDefPtr, const char *name);
|
const char *virDomainDiskPathByName(virDomainDefPtr, const char *name);
|
||||||
@ -2545,6 +2549,8 @@ int virDomainControllerInsert(virDomainDefPtr def,
|
|||||||
void virDomainControllerInsertPreAlloced(virDomainDefPtr def,
|
void virDomainControllerInsertPreAlloced(virDomainDefPtr def,
|
||||||
virDomainControllerDefPtr controller);
|
virDomainControllerDefPtr controller);
|
||||||
int virDomainControllerFind(virDomainDefPtr def, int type, int idx);
|
int virDomainControllerFind(virDomainDefPtr def, int type, int idx);
|
||||||
|
int virDomainControllerFindByPCIAddress(virDomainDefPtr def,
|
||||||
|
virDevicePCIAddressPtr addr);
|
||||||
virDomainControllerDefPtr virDomainControllerRemove(virDomainDefPtr def, size_t i);
|
virDomainControllerDefPtr virDomainControllerRemove(virDomainDefPtr def, size_t i);
|
||||||
|
|
||||||
int virDomainLeaseIndex(virDomainDefPtr def,
|
int virDomainLeaseIndex(virDomainDefPtr def,
|
||||||
|
@ -234,6 +234,7 @@ virDomainDiskGetDriver;
|
|||||||
virDomainDiskGetFormat;
|
virDomainDiskGetFormat;
|
||||||
virDomainDiskGetSource;
|
virDomainDiskGetSource;
|
||||||
virDomainDiskGetType;
|
virDomainDiskGetType;
|
||||||
|
virDomainDiskIndexByAddress;
|
||||||
virDomainDiskIndexByName;
|
virDomainDiskIndexByName;
|
||||||
virDomainDiskInsert;
|
virDomainDiskInsert;
|
||||||
virDomainDiskInsertPreAlloced;
|
virDomainDiskInsertPreAlloced;
|
||||||
|
@ -1777,3 +1777,179 @@ qemuAgentSetTime(qemuAgentPtr mon,
|
|||||||
virJSONValueFree(reply);
|
virJSONValueFree(reply);
|
||||||
return ret;
|
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,
|
int qemuAgentFSFreeze(qemuAgentPtr mon,
|
||||||
const char **mountpoints, unsigned int nmountpoints);
|
const char **mountpoints, unsigned int nmountpoints);
|
||||||
int qemuAgentFSThaw(qemuAgentPtr mon);
|
int qemuAgentFSThaw(qemuAgentPtr mon);
|
||||||
|
int qemuAgentGetFSInfo(qemuAgentPtr mon, virDomainFSInfoPtr **info,
|
||||||
|
virDomainDefPtr vmdef);
|
||||||
|
|
||||||
int qemuAgentSuspend(qemuAgentPtr mon,
|
int qemuAgentSuspend(qemuAgentPtr mon,
|
||||||
unsigned int target);
|
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 = {
|
static virHypervisorDriver qemuDriver = {
|
||||||
.no = VIR_DRV_QEMU,
|
.no = VIR_DRV_QEMU,
|
||||||
.name = QEMU_DRIVER_NAME,
|
.name = QEMU_DRIVER_NAME,
|
||||||
@ -19032,6 +19079,7 @@ static virHypervisorDriver qemuDriver = {
|
|||||||
.connectGetDomainCapabilities = qemuConnectGetDomainCapabilities, /* 1.2.7 */
|
.connectGetDomainCapabilities = qemuConnectGetDomainCapabilities, /* 1.2.7 */
|
||||||
.connectGetAllDomainStats = qemuConnectGetAllDomainStats, /* 1.2.8 */
|
.connectGetAllDomainStats = qemuConnectGetAllDomainStats, /* 1.2.8 */
|
||||||
.nodeAllocPages = qemuNodeAllocPages, /* 1.2.9 */
|
.nodeAllocPages = qemuNodeAllocPages, /* 1.2.9 */
|
||||||
|
.domainGetFSInfo = qemuDomainGetFSInfo, /* 1.2.11 */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user