[libvirt] [PATCH] util: fix domain object leaks on closecallbacks

Wang King king.wang at huawei.com
Tue Jan 10 01:46:48 UTC 2017


Thanks for your valuable comments and suggestions, I will separate it to 
three patches and send later.

On 2017/1/5 8:35, John Ferlan wrote:
>
>
> Going through some older on list patches with no activity...  There were
> two which appeared to be the same thing, so I chose the later one.
> Pardon the delay in processing this...
>
> On 11/23/2016 11:29 PM, Wang King wrote:
>> From: wangjing <king.wang at huawei.com>
>>
>> The virCloseCallbacksSet method increase object reference for
>> VM, and decrease object reference in virCloseCallbacksUnset.
>> But VM UUID will be deleted from closecallbacks list in
>> virCloseCallbacksRun when connection disconnected, and then
>> object reference cannot be decreased by virCloseCallbacksUnset
>> in callback functions.
>>
>> Signed-off-by: Wang King <king.wang at huawei.com>
>> ---
>>  src/util/virclosecallbacks.c | 29 +++++++++++++++++------------
>>  1 file changed, 17 insertions(+), 12 deletions(-)
>>
>
> It seems there may be multiple things being fixed - if so then they
> should each be separate patches.
>
> Of the following paths (consumers of close callbacks), which was causing
> the refcnt issue?  Do you have a backtrace?  How reproducible?
>
> 1. bhyveProcessAutoDestroy will destroy the transient vm, return NULL
> 2. lxcProcessAutoDestroy will destroy the transient vm, return NULL
> 3. qemuMigrationCleanup will not destroy the vm
> 4. qemuProcessAutoDestroy will call qemuDomainRemoveInactive which looks
> to destroy the transient vm... if it does then last virDomainObjEndAPI
> will cause the return to be NULL
>
>
>> diff --git a/src/util/virclosecallbacks.c b/src/util/virclosecallbacks.c
>> index 891a92b..26d5075 100644
>> --- a/src/util/virclosecallbacks.c
>> +++ b/src/util/virclosecallbacks.c
>> @@ -300,7 +300,9 @@ virCloseCallbacksGetForConn(virCloseCallbacksPtr closeCallbacks,
>>      data.list = list;
>>      data.oom = false;
>>
>> +    virObjectLock(closeCallbacks);
>>      virHashForEach(closeCallbacks->list, virCloseCallbacksGetOne, &data);
>> +    virObjectUnlock(closeCallbacks);
>
> So this seems to be "a" bugfix for [1]
>
>>
>>      if (data.oom) {
>>          VIR_FREE(list->entries);
>> @@ -329,22 +331,15 @@ virCloseCallbacksRun(virCloseCallbacksPtr closeCallbacks,
>>       * them all from the hash. At that point we can release
>>       * the lock and run the callbacks safely. */
>>
>> -    virObjectLock(closeCallbacks);
>>      list = virCloseCallbacksGetForConn(closeCallbacks, conn);
>>      if (!list)
>>          return;
>
> [1]
> Considering the former code, this return would return with the
> closeCallbacks locked - so that's "one" bug...
>
>>
>>      for (i = 0; i < list->nentries; i++) {
>> -        char uuidstr[VIR_UUID_STRING_BUFLEN];
>> -        virUUIDFormat(list->entries[i].uuid, uuidstr);
>> -        virHashRemoveEntry(closeCallbacks->list, uuidstr);
>> -    }
>
> I'm trying to figure out why this hunk of code moved below. Is that a
> separate issue?  I would think the process in the comment is what is
> desired...  With a lock, grab all the callback entries into a local
> structure by UUID and callback function, then clear out the callbacks
> from the hash, then call the callback functions.
>
> My concern is this change could have some other timing issue as this
> path is called during/from a <driver>ConnectClose() function (bhyve,
> qemu, lxc)
>
>> -    virObjectUnlock(closeCallbacks);
>> -
>> -    for (i = 0; i < list->nentries; i++) {
>>          virDomainObjPtr vm;
>> +        virDomainObjPtr dom;
>>
>> -        if (!(vm = virDomainObjListFindByUUID(domains,
>> +        if (!(vm = virDomainObjListFindByUUIDRef(domains,
>>                                                list->entries[i].uuid))) {
>
> The second line needs to move 3 spaces to line up under domains... I
> think this is the "second" bug fix. In this case, the bug fix is that we
> don't want the callback function to remove our reference.
>
>
>>              char uuidstr[VIR_UUID_STRING_BUFLEN];
>>              virUUIDFormat(list->entries[i].uuid, uuidstr);
>> @@ -352,10 +347,20 @@ virCloseCallbacksRun(virCloseCallbacksPtr closeCallbacks,
>>              continue;
>>          }
>>
>> -        vm = list->entries[i].callback(vm, conn, opaque);
>> -        if (vm)
>> -            virObjectUnlock(vm);
>> +        dom = list->entries[i].callback(vm, conn, opaque);
>> +        if (dom)
>> +            virObjectUnlock(dom);
>> +        virObjectUnref(vm);
>
> and the corollary for the Ref which probably causes 'vm' to be disposed.
> This is more than likely what the issue is - calling something which
> causes vm to ref down to 0.
>
> John
>
>>      }
>> +
>> +    virObjectLock(closeCallbacks);
>> +    for (i = 0; i < list->nentries; i++) {
>> +        char uuidstr[VIR_UUID_STRING_BUFLEN];
>> +        virUUIDFormat(list->entries[i].uuid, uuidstr);
>> +        virHashRemoveEntry(closeCallbacks->list, uuidstr);
>> +    }
>> +    virObjectUnlock(closeCallbacks);
>> +
>>      VIR_FREE(list->entries);
>>      VIR_FREE(list);
>>  }
>>
>
> .
>




More information about the libvir-list mailing list