[libvirt] [PATCH 2/3] qemu: don't use vmdef without domain lock
John Ferlan
jferlan at redhat.com
Fri Dec 9 14:42:32 UTC 2016
On 12/09/2016 03:37 AM, Nikolay Shirokovskiy wrote:
>
>
> On 08.12.2016 19:40, John Ferlan wrote:
>>
>>
>> On 11/24/2016 04:19 AM, Nikolay Shirokovskiy wrote:
>>> Current call to qemuAgentGetFSInfo in qemuDomainGetFSInfo is
>>> unsafe. Domain lock is dropped and we use vm->def. To fix that
>>> let's fill in intermediate qemuAgentFsInfo structure in
>>> qemuAgentGetFSInfo and use vm->def to convert result later when
>>> lock is hold.
>>> ---
>>> src/qemu/qemu_agent.c | 52 +++++++++++--------
>>> src/qemu/qemu_agent.h | 25 ++++++++-
>>> src/qemu/qemu_driver.c | 88 +++++++++++++++++++++++++++++++-
>>> tests/Makefile.am | 1 -
>>> tests/qemuagentdata/qemuagent-fsinfo.xml | 39 --------------
>>> tests/qemuagenttest.c | 47 +++++++----------
>>> 6 files changed, 159 insertions(+), 93 deletions(-)
>>> delete mode 100644 tests/qemuagentdata/qemuagent-fsinfo.xml
>>>
>>
>> This failed to compile for me as 'num' wasn't initialized in
>> qemuDomainGetFSInfo
>
> Well I'll just set it to zero then...
>
Right the adjustment was obvious, but nonetheless ironic given patch 1.
>>
>>> diff --git a/src/qemu/qemu_agent.c b/src/qemu/qemu_agent.c
>>> index c5cf403..5230cbc 100644
>>> --- a/src/qemu/qemu_agent.c
>>> +++ b/src/qemu/qemu_agent.c
>>> @@ -1835,18 +1835,15 @@ qemuAgentSetTime(qemuAgentPtr mon,
>>>
>>>
>>> int
>>> -qemuAgentGetFSInfo(qemuAgentPtr mon, virDomainFSInfoPtr **info,
>>> - virDomainDefPtr vmdef)
>>> +qemuAgentGetFSInfo(qemuAgentPtr mon, qemuAgentFsInfoPtr **info)
>>> {
>>> size_t i, j, k;
>>> int ret = -1;
>>> ssize_t ndata = 0, ndisk;
>>> - char **alias;
>>> virJSONValuePtr cmd;
>>> virJSONValuePtr reply = NULL;
>>> virJSONValuePtr data;
>>> - virDomainFSInfoPtr *info_ret = NULL;
>>> - virPCIDeviceAddress pci_address;
>>> + qemuAgentFsInfoPtr *info_ret = NULL;
>>>
>>> cmd = qemuAgentMakeCommand("guest-get-fsinfo", NULL);
>>> if (!cmd)
>>> @@ -1879,6 +1876,8 @@ qemuAgentGetFSInfo(qemuAgentPtr mon, virDomainFSInfoPtr **info,
>>> goto cleanup;
>>>
>>> for (i = 0; i < ndata; i++) {
>>> + qemuAgentFsDiskAliasPtr alias;
>>> +
>>> /* Reverse the order to arrange in mount order */
>>> virJSONValuePtr entry = virJSONValueArrayGet(data, ndata - 1 - i);
>>>
>>> @@ -1941,7 +1940,6 @@ qemuAgentGetFSInfo(qemuAgentPtr mon, virDomainFSInfoPtr **info,
>>> int diskaddr[3], pciaddr[4];
>>> const char *diskaddr_comp[] = {"bus", "target", "unit"};
>>> const char *pciaddr_comp[] = {"domain", "bus", "slot", "function"};
>>> - virDomainDiskDefPtr diskDef;
>>>
>>> if (!disk) {
>>> virReportError(VIR_ERR_INTERNAL_ERROR,
>>> @@ -1967,6 +1965,11 @@ qemuAgentGetFSInfo(qemuAgentPtr mon, virDomainFSInfoPtr **info,
>>> goto cleanup;
>>> }
>>> }
>>> +
>>> + alias->bus = diskaddr[0];
>>> + alias->target = diskaddr[1];
>>> + alias->unit = diskaddr[2];
>>> +
>>> for (k = 0; k < 4; k++) {
>>> if (virJSONValueObjectGetNumberInt(
>>> pci, pciaddr_comp[k], &pciaddr[k]) < 0) {
>>> @@ -1977,22 +1980,13 @@ qemuAgentGetFSInfo(qemuAgentPtr mon, virDomainFSInfoPtr **info,
>>> }
>>> }
>>>
>>> - pci_address.domain = pciaddr[0];
>>> - pci_address.bus = pciaddr[1];
>>> - pci_address.slot = pciaddr[2];
>>> - pci_address.function = pciaddr[3];
>>> - if (!(diskDef = virDomainDiskByAddress(
>>> - vmdef, &pci_address,
>>> - diskaddr[0], diskaddr[1], diskaddr[2])))
>>> - continue;
>>> + alias->address.domain = pciaddr[0];
>>> + alias->address.bus = pciaddr[1];
>>> + alias->address.slot = pciaddr[2];
>>> + alias->address.function = pciaddr[3];
>>>
>>> - if (VIR_STRDUP(*alias, diskDef->dst) < 0)
>>> - goto cleanup;
>>> -
>>> - if (*alias) {
>>> - alias++;
>>> - info_ret[i]->ndevAlias++;
>>> - }
>>> + alias++;
>>> + info_ret[i]->ndevAlias++;
>>> }
>>> }
>>>
>>> @@ -2003,7 +1997,7 @@ qemuAgentGetFSInfo(qemuAgentPtr mon, virDomainFSInfoPtr **info,
>>> cleanup:
>>> if (info_ret) {
>>> for (i = 0; i < ndata; i++)
>>> - virDomainFSInfoFree(info_ret[i]);
>>> + qemuAgentFsInfoFree(info_ret[i]);
>>> VIR_FREE(info_ret);
>>> }
>>> virJSONValueFree(cmd);
>>> @@ -2242,3 +2236,17 @@ qemuAgentSetUserPassword(qemuAgentPtr mon,
>>> VIR_FREE(password64);
>>> return ret;
>>> }
>>> +
>>> +void
>>> +qemuAgentFsInfoFree(qemuAgentFsInfoPtr info)
>>> +{
>>> + if (!info)
>>> + return;
>>> +
>>> + VIR_FREE(info->mountpoint);
>>> + VIR_FREE(info->name);
>>> + VIR_FREE(info->fstype);
>>> + VIR_FREE(info->devAlias);
>>
>> You'd have to free each 'ndevAlias' here.
>
> Why? _qemuAgentFsDiskAlias does not have anything to be freed.
> and devAlias itself is an array of elements not array of pointers.
>
Perhaps it's because I read those VIR_*_N macros and I think you have an
array of strings... When I see defs that have:
size_t ndevAlias; /* number of elements in devAlias */
qemuAgentFsDiskAliasPtr devAlias; /* array of disk device aliases */
I'm thinking devAlias is an array of qemuAgentFsDiskAliasPtr - where
each entry in the array is allocated, thus the entries and the array
need to be freed.
Although I think in this case you have one hunk of memory which isn't an
array, but rather a ndevAlias elems in which pointer arithmetic is used
to get the offset into devAlias for each element. It's the optical/mind
illusion.
In any case, I think my suggestion of using virDomainDefCopy will make
this a moot point.
>>
>>> +
>>> + VIR_FREE(info);
>>> +}
>>> diff --git a/src/qemu/qemu_agent.h b/src/qemu/qemu_agent.h
>>> index 6dd9c70..4b2277c 100644
>>> --- a/src/qemu/qemu_agent.h
>>> +++ b/src/qemu/qemu_agent.h
>>> @@ -75,8 +75,29 @@ 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);
>>> +
>>> +typedef struct _qemuAgentFsDiskAlias qemuAgentFsDiskAlias;
>>> +typedef qemuAgentFsDiskAlias *qemuAgentFsDiskAliasPtr;
>>> +struct _qemuAgentFsDiskAlias {
>>> + virPCIDeviceAddress address;
>>> + unsigned int bus;
>>> + unsigned int target;
>>> + unsigned int unit;
>>> +};
>>> +
>>> +typedef struct _qemuAgentFsInfo qemuAgentFsInfo;
>>> +typedef qemuAgentFsInfo *qemuAgentFsInfoPtr;
>>> +struct _qemuAgentFsInfo {
>>> + char *mountpoint; /* path to mount point */
>>> + char *name; /* device name in the guest (e.g. "sda1") */
>>> + char *fstype; /* filesystem type */
>>> + size_t ndevAlias; /* number of elements in devAlias */
>>> + qemuAgentFsDiskAliasPtr devAlias; /* array of disk device aliases */
>>> +};
>>> +
>>> +void qemuAgentFsInfoFree(qemuAgentFsInfoPtr info);
>>> +
>>> +int qemuAgentGetFSInfo(qemuAgentPtr mon, qemuAgentFsInfoPtr **info);
>>>
>>> int qemuAgentSuspend(qemuAgentPtr mon,
>>> unsigned int target);
>>> diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
>>> index fdfe912..1bc5dc6 100644
>>> --- a/src/qemu/qemu_driver.c
>>> +++ b/src/qemu/qemu_driver.c
>>> @@ -19672,14 +19672,89 @@ qemuNodeAllocPages(virConnectPtr conn,
>>>
>>>
>>> static int
>>> +qemuDomainConvertFsInfo(qemuAgentFsInfoPtr *agent_info, int num,
>>> + virDomainDefPtr def,
>>> + virDomainFSInfoPtr **info)
>>
>> qemuDomainFsInfoConvert
>>
>>> +{
>>> + int ret = -1;
>>> + size_t i;
>>> + virDomainFSInfoPtr *info_ret = NULL;
>>> +
>>> + if (num == 0) {
>>> + *info = NULL;
>>> + return 0;
>>> + }
>>> +
>>> + if (VIR_ALLOC_N(info_ret, num) < 0)
>>> + return -1;
>>> +
>>> + for (i = 0; i < num; i++) {
>>> + size_t j;
>>> + int devnum;
>>> +
>>> + if (VIR_ALLOC(info_ret[i]) < 0)
>>> + goto cleanup;
>>> +
>>> + if (VIR_STRDUP(info_ret[i]->mountpoint, agent_info[i]->mountpoint) < 0 ||
>>> + VIR_STRDUP(info_ret[i]->name, agent_info[i]->name) < 0 ||
>>> + VIR_STRDUP(info_ret[i]->fstype, agent_info[i]->fstype) < 0)
>>> + goto cleanup;
>>
>> I think you could certainly make use of VIR_STEAL_PTR here
>
> Well it saves a few cpu cycles. But we definetely need to change function name then.
> Like qemuDomainFsInfoSteal or something to reflect the disruptive changes to the arguments.
>
>>
>>> +
>>> + if (agent_info[i]->ndevAlias == 0)
>>> + continue;
>>> +
>>> + if (VIR_EXPAND_N(info_ret[i]->devAlias,
>>> + info_ret[i]->ndevAlias,
>>> + agent_info[i]->ndevAlias) < 0)
>>> + goto cleanup;
>>
>> Not sure EXPAND/SHRINK will be necessary
>
> Well yes, expand does not give here much of its benefits. I can just
> use alloc, but what wrong with shrink? The loop below can skip elements
> so to keep memory tight shrink is useful.
>
>>
>>> +
>>> + devnum = 0;
>>> + for (j = 0; j < agent_info[i]->ndevAlias; j++) {
>>> + virDomainDiskDefPtr diskDef;
>>> + qemuAgentFsDiskAliasPtr alias = &agent_info[i]->devAlias[j];
>>> +
>>> + if (!(diskDef = virDomainDiskByAddress(def, &alias->address,
>>> + alias->bus, alias->target,
>>> + alias->unit)))
>>> + continue;
>>> +
>>> + if (VIR_STRDUP(info_ret[i]->devAlias[devnum++], diskDef->dst) < 0)
>>> + goto cleanup;
>>
>> Would it be possible to use something like VIR_APPEND_ELEMENT of a
>> VIR_STEAL_PTR on diskDef->dst; ?
>
> VIR_APPEND_ELEMENT reallocates on every append...
>
> Well I don't think stealing from domain config is a good idea))
>
>>
>>
>>> + }
>>> +
>>> + if (devnum < info_ret[i]->ndevAlias)
>>> + VIR_SHRINK_N(info_ret[i]->devAlias,
>>> + info_ret[i]->ndevAlias,
>>> + info_ret[i]->ndevAlias - devnum);
>>> + }
>>> +
>>> + *info = info_ret;
>>> + info_ret = NULL;
>>> + ret = num;
>>> +
>>> + cleanup:
>>> + if (info_ret) {
>>> + for (i = 0; i < num; i++)
>>> + virDomainFSInfoFree(info_ret[i]);
>>> + VIR_FREE(info_ret);
>>> + }
>>> +
>>> + return ret;
>>> +}
>>> +
>>> +
>>> +static int
>>> qemuDomainGetFSInfo(virDomainPtr dom,
>>> virDomainFSInfoPtr **info,
>>> unsigned int flags)
>>> {
>>> virQEMUDriverPtr driver = dom->conn->privateData;
>>> + qemuAgentFsInfoPtr *agent_info = NULL;
>>> virDomainObjPtr vm;
>>> qemuAgentPtr agent;
>>> int ret = -1;
>>> + int num;
>>
>> num needs to be initialized since we can jump to cleanup without setting it.
>>
>>> + size_t i;
>>>
>>> virCheckFlags(0, ret);
>>>
>>> @@ -19702,13 +19777,24 @@ qemuDomainGetFSInfo(virDomainPtr dom,
>>> goto endjob;
>>>
>>> agent = qemuDomainObjEnterAgent(vm);
>>> - ret = qemuAgentGetFSInfo(agent, info, vm->def);
>>> + num = qemuAgentGetFSInfo(agent, &agent_info);
>>> qemuDomainObjExitAgent(vm, agent);
>>>
>>
>> Wouldn't it be possible to pass a copy (eg virDomainDefCopy prior to
>> dropping the vm lock) of the vm->def that virDomainDiskByAddress is
>> going to need?
>>
>> In the long run all it's using the data for is a frozen view in time.
>
> I have no objections in general to such approach and it would take much
> less changes too. But I guess qemuAgentGetFSInfo is the only function in monitor
> that takes domain configuration into account and odd for this reason.
> I mean look at the tests - there is no more stub configurations to test monitor
> except for this function.
>
I think this would be better too... I was trying to think if there'd be
any issues if the agent or domain crashed in the mean time, but didn't
come up with any.
I think it's just cleaner. I don't think you want to be mucking with
making just a virDomainDeviceDefCopy and modifying the existing
virDomainDisk*ByAddress code to handle using that instead either.
John
>>
>>
>>> + if (num < 0)
>>> + goto endjob;
>>> +
>>> + ret = qemuDomainConvertFsInfo(agent_info, num, vm->def, info);
>>> +
>>> endjob:
>>> qemuDomainObjEndJob(driver, vm);
>>>
>>> cleanup:
>>> + if (agent_info) {
>>> + for (i = 0; i < num; i++)
>>> + qemuAgentFsInfoFree(agent_info[i]);
>>> + VIR_FREE(agent_info);
>>> + }
>>> +
>>> virDomainObjEndAPI(&vm);
>>> return ret;
>>> }
>>
>>
>> Depending on the above, could mean changes below, so I'll leave it for
>> now...
>>
>> John
>>
>>> diff --git a/tests/Makefile.am b/tests/Makefile.am
>>> index 924029a..d34cc95 100644
>>> --- a/tests/Makefile.am
>>> +++ b/tests/Makefile.am
>>> @@ -116,7 +116,6 @@ EXTRA_DIST = \
>>> nwfilterxml2xmlin \
>>> nwfilterxml2xmlout \
>>> oomtrace.pl \
>>> - qemuagentdata \
>>> qemuargv2xmldata \
>>> qemucapabilitiesdata \
>>> qemucaps2xmldata \
>>> diff --git a/tests/qemuagentdata/qemuagent-fsinfo.xml b/tests/qemuagentdata/qemuagent-fsinfo.xml
>>> deleted file mode 100644
>>> index 9638feb..0000000
>>> --- a/tests/qemuagentdata/qemuagent-fsinfo.xml
>>> +++ /dev/null
>>> @@ -1,39 +0,0 @@
>>> -<domain type='qemu'>
>>> - <name>QEMUGuest1</name>
>>> - <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
>>> - <memory unit='KiB'>219136</memory>
>>> - <currentMemory unit='KiB'>219136</currentMemory>
>>> - <vcpu placement='static'>1</vcpu>
>>> - <os>
>>> - <type arch='i686' machine='pc'>hvm</type>
>>> - <boot dev='hd'/>
>>> - </os>
>>> - <clock offset='utc'/>
>>> - <on_poweroff>destroy</on_poweroff>
>>> - <on_reboot>restart</on_reboot>
>>> - <on_crash>destroy</on_crash>
>>> - <devices>
>>> - <emulator>/usr/bin/qemu</emulator>
>>> - <disk type='file' device='disk'>
>>> - <source file='/tmp/idedisk.img'/>
>>> - <target dev='hdc' bus='ide'/>
>>> - <address type='drive' controller='0' bus='1' target='0' unit='0'/>
>>> - </disk>
>>> - <disk type='file' device='disk'>
>>> - <driver name='qemu' type='qcow2'/>
>>> - <source file='/tmp/virtio-blk1.qcow2'/>
>>> - <target dev='vda' bus='virtio'/>
>>> - <address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0'/>
>>> - </disk>
>>> - <disk type='file' device='disk'>
>>> - <driver name='qemu' type='qcow2'/>
>>> - <source file='/tmp/virtio-blk2.qcow2'/>
>>> - <target dev='vdb' bus='virtio'/>
>>> - <address type='pci' domain='0x0000' bus='0x00' slot='0x07' function='0x0'/>
>>> - </disk>
>>> - <controller type='ide' index='0'>
>>> - <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/>
>>> - </controller>
>>> - <memballoon model='virtio'/>
>>> - </devices>
>>> -</domain>
>>> diff --git a/tests/qemuagenttest.c b/tests/qemuagenttest.c
>>> index 5dfa58e..97f340c 100644
>>> --- a/tests/qemuagenttest.c
>>> +++ b/tests/qemuagenttest.c
>>> @@ -169,22 +169,16 @@ testQemuAgentGetFSInfo(const void *data)
>>> virDomainXMLOptionPtr xmlopt = (virDomainXMLOptionPtr)data;
>>> virCapsPtr caps = testQemuCapsInit();
>>> qemuMonitorTestPtr test = qemuMonitorTestNewAgent(xmlopt);
>>> - char *domain_filename = NULL;
>>> - virDomainDefPtr def = NULL;
>>> - virDomainFSInfoPtr *info = NULL;
>>> + qemuAgentFsInfoPtr *info = NULL;
>>> int ret = -1, ninfo = 0, i;
>>>
>>> + qemuAgentFsDiskAlias alias_sda1 = { { 0, 0, 1, 1, 0 }, 1, 0, 0 };
>>> + qemuAgentFsDiskAlias alias_vda = { { 0, 0, 6, 0, 0 }, 0, 0, 0 };
>>> + qemuAgentFsDiskAlias alias_vdb = { { 0, 0, 7, 0, 0 }, 0, 0, 0 };
>>> +
>>> if (!test)
>>> return -1;
>>>
>>> - if (virAsprintf(&domain_filename, "%s/qemuagentdata/qemuagent-fsinfo.xml",
>>> - abs_srcdir) < 0)
>>> - goto cleanup;
>>> -
>>> - if (!(def = virDomainDefParseFile(domain_filename, caps, xmlopt,
>>> - NULL, VIR_DOMAIN_DEF_PARSE_INACTIVE)))
>>> - goto cleanup;
>>> -
>>> if (qemuMonitorTestAddAgentSyncResponse(test) < 0)
>>> goto cleanup;
>>>
>>> @@ -220,8 +214,7 @@ testQemuAgentGetFSInfo(const void *data)
>>> " \"disk\": [], \"type\": \"xfs\"}]}") < 0)
>>> goto cleanup;
>>>
>>> - if ((ninfo = qemuAgentGetFSInfo(qemuMonitorTestGetAgent(test),
>>> - &info, def)) < 0)
>>> + if ((ninfo = qemuAgentGetFSInfo(qemuMonitorTestGetAgent(test), &info)) < 0)
>>> goto cleanup;
>>>
>>> if (ninfo != 3) {
>>> @@ -234,11 +227,11 @@ testQemuAgentGetFSInfo(const void *data)
>>> STRNEQ(info[2]->mountpoint, "/") ||
>>> STRNEQ(info[2]->fstype, "ext4") ||
>>> info[2]->ndevAlias != 1 ||
>>> - !info[2]->devAlias || !info[2]->devAlias[0] ||
>>> - STRNEQ(info[2]->devAlias[0], "hdc")) {
>>> + !info[2]->devAlias ||
>>> + memcmp(&info[2]->devAlias[0], &alias_sda1, sizeof(alias_sda1)) != 0) {
>>> virReportError(VIR_ERR_INTERNAL_ERROR,
>>> - "unexpected filesystems information returned for sda1 (%s,%s)",
>>> - info[2]->name, info[2]->devAlias ? info[2]->devAlias[0] : "null");
>>> + "unexpected filesystems information returned for sda1 (%s)",
>>> + info[2]->name);
>>> ret = -1;
>>> goto cleanup;
>>> }
>>> @@ -246,12 +239,12 @@ testQemuAgentGetFSInfo(const void *data)
>>> STRNEQ(info[1]->mountpoint, "/opt") ||
>>> STRNEQ(info[1]->fstype, "vfat") ||
>>> info[1]->ndevAlias != 2 ||
>>> - !info[1]->devAlias || !info[1]->devAlias[0] || !info[1]->devAlias[1] ||
>>> - STRNEQ(info[1]->devAlias[0], "vda") ||
>>> - STRNEQ(info[1]->devAlias[1], "vdb")) {
>>> + !info[1]->devAlias ||
>>> + memcmp(&info[1]->devAlias[0], &alias_vda, sizeof(alias_vda)) != 0 ||
>>> + memcmp(&info[1]->devAlias[1], &alias_vdb, sizeof(alias_vdb)) != 0) {
>>> virReportError(VIR_ERR_INTERNAL_ERROR,
>>> - "unexpected filesystems information returned for dm-1 (%s,%s)",
>>> - info[0]->name, info[0]->devAlias ? info[0]->devAlias[0] : "null");
>>> + "unexpected filesystems information returned for dm-1 (%s)",
>>> + info[0]->name);
>>> ret = -1;
>>> goto cleanup;
>>> }
>>> @@ -260,8 +253,8 @@ testQemuAgentGetFSInfo(const void *data)
>>> STRNEQ(info[0]->fstype, "xfs") ||
>>> info[0]->ndevAlias != 0 || info[0]->devAlias) {
>>> virReportError(VIR_ERR_INTERNAL_ERROR,
>>> - "unexpected filesystems information returned for sdb1 (%s,%s)",
>>> - info[0]->name, info[0]->devAlias ? info[0]->devAlias[0] : "null");
>>> + "unexpected filesystems information returned for sdb1 (%s)",
>>> + info[0]->name);
>>> ret = -1;
>>> goto cleanup;
>>> }
>>> @@ -280,7 +273,7 @@ testQemuAgentGetFSInfo(const void *data)
>>> "}") < 0)
>>> goto cleanup;
>>>
>>> - if (qemuAgentGetFSInfo(qemuMonitorTestGetAgent(test), &info, def) != -1) {
>>> + if (qemuAgentGetFSInfo(qemuMonitorTestGetAgent(test), &info) != -1) {
>>> virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
>>> "agent get-fsinfo command should have failed");
>>> goto cleanup;
>>> @@ -290,11 +283,9 @@ testQemuAgentGetFSInfo(const void *data)
>>>
>>> cleanup:
>>> for (i = 0; i < ninfo; i++)
>>> - virDomainFSInfoFree(info[i]);
>>> + qemuAgentFsInfoFree(info[i]);
>>> VIR_FREE(info);
>>> - VIR_FREE(domain_filename);
>>> virObjectUnref(caps);
>>> - virDomainDefFree(def);
>>> qemuMonitorTestFree(test);
>>> return ret;
>>> }
>>>
More information about the libvir-list
mailing list