<div class="zcontentRow"> <p>Hi <span style="line-height: 21px;">Michal,</span></p><p><span style="line-height: 21px;">    This problem is triggerred by libvirt python's example event-test.py. the original examples has resouce leak issue</span></p><p>at the remove_handle and remove_timer. </p><p>    with "python -u <span style="line-height: 21px;">event-test.py</span>" run this example and "systemctl restart libvirtd.service" will trigger resource leak problem.</p><p>with lsof -p <event-test.pid> can see socket handler's number increased , after restart libvirtd.serivce each time.</p><p><span style="line-height: 21px;">    the reason is remove_handle and remove_timer do not return the remove handle information to libvirt-python's framework. </span></p><p>little patch was apply to this example, to fix this problem.</p><p>   Now, run this example again and restart libvirtd.service , call sequence <span style="line-height: 21px;">virNetSocketRemoveIOCallback-><span style="line-height: 21px;">virNetSocketEventFree </span></span></p><p><span style="line-height: 21px;"><span style="line-height: 21px;">can be observed , the no-recursive mutex, lock with recursive issue can be seen. </span></span></p><p><span style="line-height: 21px;"><span style="line-height: 21px;">    you can check the detail stack trace and our comments about the lock's issue in function <span style="line-height: 21px;">virNetSocketEventFree</span>  in the following.</span></span></p><p><span style="line-height: 21px;"><span style="line-height: 21px;"><br></span></span></p><p><span style="line-height: 21px;">  ====================================================================  </span></p><p> def add_timer(self, interval, cb, opaque):</p><p>        timerID = self.nextTimerID + 1</p><p>        self.nextTimerID = self.nextTimerID + 1</p><p><br></p><p>        h = self.virEventLoopPureTimer(timerID, interval, cb, opaque)</p><p>        self.timers.append(h)</p><p>-       self.timers_opaque[timerID] = opaque</p><p>        self.interrupt()</p><p><br></p><p>        debug("Add timer %d interval %d" % (timerID, interval))</p><p><br></p><p>        return timerID</p><p><span style="line-height: 21px;"></span><br></p><p><br></p><p>     def remove_handle(self, handleID):</p><p>         handles = []</p><p>-        opaque = None</p><p>         for h in self.handles:</p><p>             if h.get_id() == handleID:</p><p>                 self.poll.unregister(h.get_fd())</p><p>-                opaque = self.opaques[handleID]</p><p>-                del self.opaques[handleID]</p><p>                 debug("Remove handle %d fd %d" % (handleID, h.get_fd()))</p><p>             else:</p><p>                 handles.append(h)</p><p>         self.handles = handles</p><p>         self.interrupt()</p><p>-        return opaque</p><p><br></p><p>     # Stop firing the periodic timer</p><p>     def remove_timer(self, timerID):</p><p>         timers = []</p><p>-        opaque = None</p><p>         for h in self.timers:</p><p>             if h.get_id() != timerID:</p><p>                 timers.append(h)</p><p>-            else:</p><p>-                opaque = self.timers_opaque[timerID]</p><p>                 debug("Remove timer %d" % timerID)</p><p>         self.timers = timers</p><p>         self.interrupt()</p><p>-        return opaque</p><p><span style="line-height: 21px;">====================================================================================<br></span></p><p><span style="line-height: 21px;"><br></span></p><p>>>On 07/15/2017 05:00 PM, Peng Hao wrote:</p><p>>> virNetSocketRemoveIOCallback get sock's ObjectLock and will call</p><p>>> virNetSocketEventFree. virNetSocketEventFree may be free sock</p><p>>> object and virNetSocketRemoveIOCallback will access a null pointer</p><p>>> in release sock's ObjectLock.</p><p>>> </p><p>>> Signed-off-by: Liu Yun <liu.yunh@zte.com.cn></p><p>>> Signed-off-by: Peng Hao <peng.hao2@zte.com.cn></p><p>>> ---</p><p>>>  src/rpc/virnetsocket.c | 6 +++---</p><p>>>  1 file changed, 3 insertions(+), 3 deletions(-)</p><p>>> </p><p>></p><p>>I don't think this can work.</p><p>></p><p>>> diff --git a/src/rpc/virnetsocket.c b/src/rpc/virnetsocket.c</p><p>>> index d228c8a..8b550e8 100644</p><p>>> --- a/src/rpc/virnetsocket.c</p><p>>> +++ b/src/rpc/virnetsocket.c</p><p>>> @@ -2140,14 +2140,12 @@ static void virNetSocketEventFree(void *opaque)</p><p>>>      virFreeCallback ff;</p><p>>>      void *eopaque;</p><p>>>  </p><p>>> -    virObjectLock(sock);</p><p>>>      ff = sock->ff;</p><p>>>      eopaque = sock->opaque;</p><p>>>      sock->func = NULL;</p><p>>>      sock->ff = NULL;</p><p>>>      sock->opaque = NULL;</p><p>>> -    virObjectUnlock(sock);</p><p>></p><p>>I think we need the lock here. This function is called from the event</p><p>>loop thread. So even if virNetSocketUpdateIOCallback() locks the @socket</p><p>>this code can see it unlocked. Or locked. But the crucial part is it's</p><p>>modifying the object and thus should have lock held.</p><p>></p><p>   I have check the code , in default implementation of eventPoll, virEventPollRunOnce always dispatch and clear in one thread loop,</p><p>so, the lock in the <span style="line-height: 21px;">virNetSocketEventFree may be unnessary.</span></p><p><span style="line-height: 21px;"><br></span></p><p>>> -</p><p>>> +  </p><p>>>      if (ff)</p><p>>>          ff(eopaque);</p><p>>>  </p><p>>> @@ -2207,6 +2205,7 @@ void virNetSocketUpdateIOCallback(virNetSocketPtr sock,</p><p>>>  </p><p>>>  void virNetSocketRemoveIOCallback(virNetSocketPtr sock)</p><p>>>  {</p><p>>> +    virObjectRef(sock);</p><p><br></p><p>This should be mistake when generate the patch. The correct one is </p><p>     <span style="line-height: 21px;">+    virObjectUnref(sock);</span></p><p>>>      virObjectLock(sock);</p><p>></p><p>>I think this is what actually fixes your problem. However, I also think</p><p>>it introduces uneven ratio of ref:unref calls.</p><p>></p><p>>>  </p><p>>>      if (sock->watch < 0) {</p><p>>> @@ -2220,6 +2219,7 @@ void virNetSocketRemoveIOCallback(virNetSocketPtr sock)</p><p>>>      sock->watch = -1;</p><p>>>  </p><p>>>      virObjectUnlock(sock);</p><p>>> +    virObjectRef(sock);</p><p><br></p><p style="line-height: 21px; white-space: normal;">This should be mistake when generate the patch. The correct one is </p><p style="line-height: 21px; white-space: normal;">     <span style="line-height: 21px;">+    virObjectUnref(sock);</span></p><p>></p><p>>It definitely does so because you ref twice. Anyway, do you perhaps have</p><p>>a backtrace to share?</p><p>    </p><p>#0  __lll_lock_wait ()</p><p>    at ../nptl/sysdeps/unix/sysv/linux/x86_64/lowlevellock.S:135</p><p>#1  0x00007fde6207cd02 in _L_lock_791 () from /lib64/libpthread.so.0</p><p>#2  0x00007fde6207cc08 in __GI___pthread_mutex_lock (</p><p>    mutex=mutex@entry=0x119c3e0) at pthread_mutex_lock.c:64</p><p>#3  0x00007fde5a97ee15 in virMutexLock (m=m@entry=0x119c3e0)</p><p>    at util/virthread.c:89</p><p>#4  0x00007fde5a9608ae in virObjectLock (anyobj=anyobj@entry=0x119c3d0)</p><p>    at util/virobject.c:323</p><p>#5  0x00007fde5aaa752c in virNetSocketEventFree (opaque=0x119c3d0)</p><p>    at rpc/virnetsocket.c:2134</p><p>#6  0x00007fde5ae57f87 in libvirt_virEventRemoveHandleFunc (</p><p>    watch=<optimized out>) at libvirt-override.c:5496</p><p>#7  0x00007fde5aaaac69 in virNetSocketRemoveIOCallback (sock=0x119c3d0)</p><p>    at rpc/virnetsocket.c:2212</p><p>#8  0x00007fde5aa96d76 in virNetClientMarkClose (client=0x119c650, reason=0)</p><p>    at rpc/virnetclient.c:779</p><p>#9  0x00007fde5aa970eb in virNetClientIncomingEvent (sock=0x119c3d0, events=9,</p><p>    opaque=0x119c650) at rpc/virnetclient.c:1985</p><p>#10 0x00007fde5ae4b347 in libvirt_virEventInvokeHandleCallback (</p><p>    self=<optimized out>, args=<optimized out>) at libvirt-override.c:5718</p><p>#11 0x00007fde6236faa4 in PyEval_EvalFrameEx () from /lib64/libpython2.7.so.1.0</p><p>#12 0x00007fde623710bd in PyEval_EvalCodeEx () from /lib64/libpython2.7.so.1.0</p><p>---Type <return> to continue, or q <return> to quit---</p><p>#13 0x00007fde6236f76f in PyEval_EvalFrameEx () from /lib64/libpython2.7.so.1.0</p><p>#14 0x00007fde6236f860 in PyEval_EvalFrameEx () from /lib64/libpython2.7.so.1.0</p><p>#15 0x00007fde6236f860 in PyEval_EvalFrameEx () from /lib64/libpython2.7.so.1.0</p><p>#16 0x00007fde6236f860 in PyEval_EvalFrameEx () from /lib64/libpython2.7.so.1.0</p><p>#17 0x00007fde623710bd in PyEval_EvalCodeEx () from /lib64/libpython2.7.so.1.0</p><p>#18 0x00007fde622fe05d in function_call () from /lib64/libpython2.7.so.1.0</p><p>#19 0x00007fde622d90b3 in PyObject_Call () from /lib64/libpython2.7.so.1.0</p><p>#20 0x00007fde6236c2f7 in PyEval_EvalFrameEx () from /lib64/libpython2.7.so.1.0</p><p>#21 0x00007fde6236f860 in PyEval_EvalFrameEx () from /lib64/libpython2.7.so.1.0</p><p>#22 0x00007fde6236f860 in PyEval_EvalFrameEx () from /lib64/libpython2.7.so.1.0</p><p>#23 0x00007fde623710bd in PyEval_EvalCodeEx () from /lib64/libpython2.7.so.1.0</p><p>#24 0x00007fde622fdf68 in function_call () from /lib64/libpython2.7.so.1.0</p><p>#25 0x00007fde622d90b3 in PyObject_Call () from /lib64/libpython2.7.so.1.0</p><p>#26 0x00007fde622e80a5 in instancemethod_call ()</p><p><br></p><p>></p><p>>Michal</p><p><br></p><p><br></p><div class="zMailSign"><div><div><p>BestRegards</p><p>  LiuYun</p></div></div></div><div><div class="zhistoryRow" style="display:block"><div class="zhistoryDes" style="width: 100%; height: 28px; line-height: 28px; background-color: #E0E5E9; color: #1388FF; text-align: center;" language-data="HistoryOrgTxt">原始邮件</div><br></div></div> </div>