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:
Tomoki Sekiyama 2014-11-21 20:27:38 -05:00 committed by John Ferlan
parent ee3dc4f19b
commit 5c9cfa4976
6 changed files with 304 additions and 0 deletions

View File

@ -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)
{

View File

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

View File

@ -234,6 +234,7 @@ virDomainDiskGetDriver;
virDomainDiskGetFormat;
virDomainDiskGetSource;
virDomainDiskGetType;
virDomainDiskIndexByAddress;
virDomainDiskIndexByName;
virDomainDiskInsert;
virDomainDiskInsertPreAlloced;

View File

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

View File

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

View File

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