Re: [libvirt] [PATCH] add lock priv->lock protection in remoteClientCloseFunc()

2019-12-04 Thread Lance Liu
Hi:
Need any more informations about my patch?

LanceLiu  于2019年12月2日周一 上午11:16写道:

> sometimes, virsh console session may closed by virsh console existed
> session(when virsh console client
>  exit) and new virsh console --force session simutaneously. So in one
> thread(Job worker), it calls
> daemonStreamEvent() and referencing stream, and in another thread(main
> thread), virNetServerClientClose()
> was called, and the callback remoteClientCloseFunc() was called, without
> protect by priv->lock in
> remoteClientCloseFunc(), it may lead to daemonStreamEvent reference stream
> released by remoteClientCloseFunc(),
> and also need change virNetServerClientClose() to be
> virNetServerClientImmediateClose() in daemonStreamEvent(),
> or it lead to libvirt daemon deadlock by double lock priv->lock in
> daemonStreamEvent()
> ---
>  src/remote/remote_daemon_dispatch.c |  2 ++
>  src/remote/remote_daemon_stream.c   | 14 +++---
>  2 files changed, 9 insertions(+), 7 deletions(-)
>
> diff --git a/src/remote/remote_daemon_dispatch.c
> b/src/remote/remote_daemon_dispatch.c
> index f369ffb..b0982b7 100644
> --- a/src/remote/remote_daemon_dispatch.c
> +++ b/src/remote/remote_daemon_dispatch.c
> @@ -1724,7 +1724,9 @@ static void
> remoteClientCloseFunc(virNetServerClientPtr client)
>  {
>  struct daemonClientPrivate *priv =
> virNetServerClientGetPrivateData(client);
>
> +virMutexLock(>lock);
>  daemonRemoveAllClientStreams(priv->streams);
> +virMutexUnlock(>lock);
>
>  remoteClientFreePrivateCallbacks(priv);
>  }
> diff --git a/src/remote/remote_daemon_stream.c
> b/src/remote/remote_daemon_stream.c
> index 73e4d7b..6a84fdf 100644
> --- a/src/remote/remote_daemon_stream.c
> +++ b/src/remote/remote_daemon_stream.c
> @@ -141,7 +141,7 @@ daemonStreamEvent(virStreamPtr st, int events, void
> *opaque)
>  (events & VIR_STREAM_EVENT_WRITABLE)) {
>  if (daemonStreamHandleWrite(client, stream) < 0) {
>  daemonRemoveClientStream(client, stream);
> -virNetServerClientClose(client);
> +virNetServerClientImmediateClose(client);
>  goto cleanup;
>  }
>  }
> @@ -151,7 +151,7 @@ daemonStreamEvent(virStreamPtr st, int events, void
> *opaque)
>  events = events & ~(VIR_STREAM_EVENT_READABLE);
>  if (daemonStreamHandleRead(client, stream) < 0) {
>  daemonRemoveClientStream(client, stream);
> -virNetServerClientClose(client);
> +virNetServerClientImmediateClose(client);
>  goto cleanup;
>  }
>  /* If we detected EOF during read processing,
> @@ -176,7 +176,7 @@ daemonStreamEvent(virStreamPtr st, int events, void
> *opaque)
>  if (daemonStreamHandleFinish(client, stream, msg) < 0) {
>  virNetMessageFree(msg);
>  daemonRemoveClientStream(client, stream);
> -virNetServerClientClose(client);
> +virNetServerClientImmediateClose(client);
>  goto cleanup;
>  }
>  break;
> @@ -186,7 +186,7 @@ daemonStreamEvent(virStreamPtr st, int events, void
> *opaque)
>  if (daemonStreamHandleAbort(client, stream, msg) < 0) {
>  virNetMessageFree(msg);
>  daemonRemoveClientStream(client, stream);
> -virNetServerClientClose(client);
> +virNetServerClientImmediateClose(client);
>  goto cleanup;
>  }
>  break;
> @@ -205,7 +205,7 @@ daemonStreamEvent(virStreamPtr st, int events, void
> *opaque)
>  stream->recvEOF = true;
>  if (!(msg = virNetMessageNew(false))) {
>  daemonRemoveClientStream(client, stream);
> -virNetServerClientClose(client);
> +virNetServerClientImmediateClose(client);
>  goto cleanup;
>  }
>  msg->cb = daemonStreamMessageFinished;
> @@ -219,7 +219,7 @@ daemonStreamEvent(virStreamPtr st, int events, void
> *opaque)
>"", 0) < 0) {
>  virNetMessageFree(msg);
>  daemonRemoveClientStream(client, stream);
> -virNetServerClientClose(client);
> +virNetServerClientImmediateClose(client);
>  goto cleanup;
>  }
>  }
> @@ -262,7 +262,7 @@ daemonStreamEvent(virStreamPtr st, int events, void
> *opaque)
>  }
>  daemonRemoveClientStream(client, stream);
>  if (ret < 0)
> -virNetServerClientClose(client);
> +   virNetServerClientImmediateClose(client);
>  goto cleanup;
>  }
>
> --
> 1.8.3.1
>
>
--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list

Re: [libvirt] [PATCH] remote_daemon_stream: Hold an extra reference to stream in daemonStreamFilter

2019-11-28 Thread Lance Liu
Michal Privoznik
下午5:58 (1小时前)
发送至 我、 libvir-list
On 11/28/19 4:09 AM, Lance Liu wrote:
> Hi, Michal:
>  I think  the daemonFreeClientStream(NULL, stream);  in your patch
> should line above  virMutexUnlock(>priv->lock), or else there
> is issue WAW.

I'm sorry, I don't know what WAW is.

write after write, daemonFreeClientStream() outside stream->priv->lock
may lead to two threads call daemonFreeClientStream() simultaneously

> That is two threads may sub stream->
>
> Lance Liu mailto:liu.lance...@gmail.com>> 于
> 2019年11月26日周二 下午1:54写道:
>
> Yeah, your patch is perfectly fine for stream freed problem.
> But I have reviewed code in daemonStreamEvent() and
> daemonStreamFilter() again, and I think there still two issue need
> to be reconsidered:
> 1. stream->ref only ++ in daemonStreamFilter, except for error
> occurred call daemonRemoveClientStream() lead to ref--, like code as
> follow. Though code won't be executed because of
> no VIR_STREAM_EVENT_HANGUP event taken place,
> but it is not good code:

Do you perhaps mean daemonStreamEvent() instead of daemonStreamFilter()?
Because in daemonStreamFilter() we do both ref & unref - the unref is
hidden in daemonFreeClientStream().
Again, the unref is hidden in daemonStreamMessageFinished() which calls
daemonFreeClientStream(). The msg->cb is guaranteed to be called
eventually upon successful return from
virNetServerProgramSendStreamData(). That's why you don't see the direct
unref in the success path.

Yeah, got it.  I missed that!
>  }
> 2. call virNetServerClientClose() is still inappropriate in  because
> the it may free the client resource which other threads need ref,
> may be replace it with virNetServerClientImmediateClose() is better,
> the daemon can process client resource release unified

I've seen the patch you send, but it was without any commit message so
no one had any idea why the change is needed.
I understand your argument here, but I'm having hard time finding
practical example in the code. I mean, have you seen such issue in real?

> 3. Segmentfault may still exists when another thread
> call remoteClientCloseFunc in virNetServerClientClose()(for example,
> when new force console session break down existed console session,
> and existed console session
> 's client close the session simutaneously, but remoteClientCloseFunc
> not lock(priv->lock), so the resource maybe released when
> daemonStreamEvent ref)

Again, sounds plausible, but this is a subset of the previous problem
since remoteClientCloseFunc() is called from
virNetServerClientCloseLocked() which is called from
virNetServerClientClose().

I'll show you how to get the bug。Use gdb attach the libvirt daemon
and break in the middle of daemonStreamEvent()(with event == 4,
called by new force console break down existed console session),
then exit from the previous virsh console client, so libvirt daemon can
percent console client connection fd closed, then call the
virNetServerClientClose()
in main thread, because the callback remote remoteClientCloseFunc() downes
not
lock priv->lock, so it will release stream directly, regardless anther
thread reference it
in daemonStreamEvent()




Michal Privoznik  于2019年11月28日周四 下午5:58写道:

> On 11/28/19 4:09 AM, Lance Liu wrote:
> > Hi, Michal:
> >  I think  the daemonFreeClientStream(NULL, stream);  in your patch
> > should line above  virMutexUnlock(>priv->lock), or else there
> > is issue WAW.
>
> I'm sorry, I don't know what WAW is.
>
> > That is two threads may sub stream->
> >
> > Lance Liu mailto:liu.lance...@gmail.com>> 于
> > 2019年11月26日周二 下午1:54写道:
> >
> > Yeah, your patch is perfectly fine for stream freed problem.
> > But I have reviewed code in daemonStreamEvent() and
> > daemonStreamFilter() again, and I think there still two issue need
> > to be reconsidered:
> > 1. stream->ref only ++ in daemonStreamFilter, except for error
> > occurred call daemonRemoveClientStream() lead to ref--, like code as
> > follow. Though code won't be executed because of
> > no VIR_STREAM_EVENT_HANGUP event taken place,
> > but it is not good code:
>
> Do you perhaps mean daemonStreamEvent() instead of daemonStreamFilter()?
> Because in daemonStreamFilter() we do both ref & unref - the unref is
> hidden in daemonFreeClientStream().
>
> > /* If we got HANGUP, we need to only send an empty
> >   * packet so the client sees an EOF and cleans up
> >   */
> >  if (!stream->closed && !stream->recvEOF &&
> >  (events & VIR_STREAM_EVENT_HANGUP)) {
>

Re: [libvirt] [PATCH] Fix bug libvirt daemon segfault when new force console vm session break down existed console session. When force console vm command arrived, libvirtd will break down existed cons

2019-11-28 Thread Lance Liu
Ok, thanks.

Michal Privoznik  于2019年11月28日周四 下午5:21写道:

> On 11/28/19 4:03 AM, Lance Liu wrote:
> > Ok, I'll check it out.
> >
> > Look like your patch is still not in master branch。May you commit it?
> > I'll check out it and test for force console case
>
> Unfortunately, it did not receive any ACK from a contributor with commit
> rights (which is required for any patch that we want to merge). I will
> try to get somebody to review it.
>
> Michal
>
>
--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list

Re: [libvirt] [PATCH] remote_daemon_stream: Hold an extra reference to stream in daemonStreamFilter

2019-11-27 Thread Lance Liu
Hi, Michal:
I think  the daemonFreeClientStream(NULL, stream);  in your patch
should line above   virMutexUnlock(>priv->lock), or else there is
issue WAW. That is two threads may sub stream->

Lance Liu  于2019年11月26日周二 下午1:54写道:

> Yeah, your patch is perfectly fine for stream freed problem.
> But I have reviewed code in daemonStreamEvent() and daemonStreamFilter()
> again, and I think there still two issue need to be reconsidered:
> 1. stream->ref only ++ in daemonStreamFilter, except for error
> occurred call daemonRemoveClientStream() lead to ref--, like code as
> follow. Though code won't be executed because of no VIR_STREAM_EVENT_HANGUP
> event taken place,
> but it is not good code:
> /* If we got HANGUP, we need to only send an empty
>  * packet so the client sees an EOF and cleans up
>  */
> if (!stream->closed && !stream->recvEOF &&
> (events & VIR_STREAM_EVENT_HANGUP)) {
> virNetMessagePtr msg;
> events &= ~(VIR_STREAM_EVENT_HANGUP);
> stream->tx = false;
> stream->recvEOF = true;
> if (!(msg = virNetMessageNew(false))) {
> daemonRemoveClientStream(client, stream);
> virNetServerClientClose(client);
> goto cleanup;
> }
> msg->cb = daemonStreamMessageFinished;
> msg->opaque = stream;
> stream->refs++;
> if (virNetServerProgramSendStreamData(stream->prog,
>   client,
>   msg,
>   stream->procedure,
>   stream->serial,
>   "", 0) < 0) {
> virNetMessageFree(msg);
> daemonRemoveClientStream(client, stream);
> virNetServerClientClose(client);
> goto cleanup;
> }
> }
> 2. call virNetServerClientClose() is still inappropriate in  because the
> it may free the client resource which other threads need ref, may be
> replace it with virNetServerClientImmediateClose() is better,
> the daemon can process client resource release unified
> 3. Segmentfault may still exists when another thread
> call remoteClientCloseFunc in virNetServerClientClose()(for example, when
> new force console session break down existed console session, and existed
> console session
> 's client close the session simutaneously, but remoteClientCloseFunc not
> lock(priv->lock), so the resource maybe released when daemonStreamEvent ref)
>
> How do you see it?
>
>
> Best Regards!
>
>
>
>
> Michal Privoznik  于2019年11月26日周二 上午12:49写道:
>
>> In v5.9.0-273-g8ecab214de I've tried to fix a lock ordering
>> problem, but introduced a crasher. Problem is that because the
>> client lock is unlocked (in order to honour lock ordering) the
>> stream we are currently checking in daemonStreamFilter() might be
>> freed and thus stream->priv might not even exist when the control
>> get to virMutexLock() call.
>>
>> To resolve this, grab an extra reference to the stream and handle
>> its cleanup should the refcounter reach zero after the deref.
>> If that's the case and we are the only ones holding a reference
>> to the stream, we MUST return a positive value to make
>> virNetServerClientDispatchRead() break its loop where it iterates
>> over filters. The problem is, if we did not do so, then
>> "filter = filter->next" line will read from a memory that was
>> just freed (freeing a stream also unregisters its filter).
>>
>> Signed-off-by: Michal Privoznik 
>> ---
>>
>> Reproducing this issue is very easy:
>>
>> 1) put sleep(5) right after virObjectUnlock(client) in the fist hunk,
>> 2) virsh console --force $dom   and type something so that the stream
>>has some data to process
>> 3) while 2) is still running, run the same command from another terminal
>> 4) observe libvirtd crash
>>
>>  src/remote/remote_daemon_stream.c | 19 +++
>>  1 file changed, 19 insertions(+)
>>
>> diff --git a/src/remote/remote_daemon_stream.c
>> b/src/remote/remote_daemon_stream.c
>> index 82cadb67ac..73e4d7befb 100644
>> --- a/src/remote/remote_daemon_stream.c
>> +++ b/src/remote/remote_daemon_stream.c
>> @@ -293,10 +293,25 @@ daemonStreamFilter(virNetServerClientPtr client,
>>  daemonClientStream *stream = opaque;
>>  int ret = 0;
>>
>> +/* We must honour lock ordering here. Client private data lock must
>> + * be acquired

Re: [libvirt] [PATCH] Fix bug libvirt daemon segfault when new force console vm session break down existed console session. When force console vm command arrived, libvirtd will break down existed cons

2019-11-27 Thread Lance Liu
Ok, I'll check it out.

Look like your patch is still not in master branch。May you commit it? I'll
check out it and test for force console case

Michal Privoznik  于2019年11月25日周一 下午10:12写道:

> On 11/25/19 11:53 AM, Lance Liu wrote:
> > We first produce this bug in rhel7.4's libvir daemon。For easily
> > produce the bug, the step can be as follows: 1. add sleep(3)  in
> > daemonStreamFilter() pre virMutexLock(>priv->lock), then
> > build libvirtd bin executable, then restart libvirtd 2. use virsh
> > console open one vm's console, for this console(the vm's kernel need
> > console=ttyS0 boot parameter,then just  input from keyboard on and on
> > 3. use virsh console --force to break the previous console session,
> > than you will get libvirt daemon deadlock。
> >
> > And for the problem client->privData to be released problem, only
> > virNetServerClientClose() will free client->privData and client, I
> > think this can be fixed by remove virNetServerClientClose() from
> > daemonStreamEvent(), and replace with
> > virNetServerClientImmediateClose(), so virNetServerProcessClients()
> > will test the session would be closed。
>
> RHEL-7.4 you say? That's libvirt-3.2.0 which is far from what we have on
> the master. Also, RHEL-7.4 itself is kind of old as RHEL-7.7 was
> released during summer. At least that explains why your original patch
> was against older libvirt.
>
> When I revert your patch I can see the deadlock still happening:
>
> Thread 5 (Thread 0x7feac8936700 (LWP 162328)):
> #0  0x7feacd1d6f6c in __lll_lock_wait () at /lib64/libpthread.so.0
> #1  0x7feacd1cf194 in pthread_mutex_lock () at /lib64/libpthread.so.0
> #2  0x7feacdc78a9e in virMutexLock (m=0x565030303700) at
> ../../src/util/virthread.c:79
> #3  0x7feacdc488a2 in virObjectLock (anyobj=0x5650303036f0) at
> ../../src/util/virobject.c:433
> #4  0x7feacdd9f8bc in virNetServerClientSendMessage
> (client=0x5650303036f0, msg=0x7feab40281e0) at
> ../../src/rpc/virnetserverclient.c:1532
> #5  0x7feacdd9ac27 in virNetServerProgramSendError
> (program=536903814, version=1, client=0x5650303036f0,
> msg=0x7feab40281e0, rerr=0x7feac8935730, procedure=201, type=3,
> serial=16) at ../../src/rpc/virnetserverprogram.c:168
> #6  0x7feacdd9ad52 in virNetServerProgramSendStreamError
> (prog=0x5650302ccb70, client=0x5650303036f0, msg=0x7feab40281e0,
> rerr=0x7feac8935730, procedure=201, serial=16) at
> ../../src/rpc/virnetserverprogram.c:217
> #7  0x56502e9bbd24 in daemonStreamEvent (st=0x7feac40022a0,
> events=4, opaque=0x5650303036f0) at
> ../../src/remote/remote_daemon_stream.c:256
> #8  0x7feacdc01648 in virFDStreamCloseInt (st=0x7feac40022a0,
> streamAbort=true) at ../../src/util/virfdstream.c:715
> #9  0x7feacdc017d1 in virFDStreamAbort (st=0x7feac40022a0) at
> ../../src/util/virfdstream.c:759
> #10 0x7feacded9e1d in virStreamAbort (stream=0x7feac40022a0) at
> ../../src/libvirt-stream.c:1237
> #11 0x7feacdd456e3 in virChrdevOpen (devs=0x7fea740cae00,
> source=0x7fea740d26a0, st=0x7feab402f220, force=true) at
> ../../src/conf/virchrdev.c:387
> #12 0x7feab3f722e7 in qemuDomainOpenConsole (dom=0x7feab40329b0,
> dev_name=0x0, st=0x7feab402f220, flags=1) at
> ../../src/qemu/qemu_driver.c:17309
> #13 0x7feacdeb375f in virDomainOpenConsole (dom=0x7feab40329b0,
> dev_name=0x0, st=0x7feab402f220, flags=1) at
> ../../src/libvirt-domain.c:9662
> #14 0x56502e999894 in remoteDispatchDomainOpenConsole
> (server=0x56503027fc30, client=0x56503031ad70, msg=0x565030304eb0,
> rerr=0x7feac8935ad0, args=0x7feab402cd70) at
> ./remote/remote_daemon_dispatch_stubs.h:9211
> #15 0x56502e99976f in remoteDispatchDomainOpenConsoleHelper
> (server=0x56503027fc30, client=0x56503031ad70, msg=0x565030304eb0,
> rerr=0x7feac8935ad0, args=0x7feab402cd70, ret=0x0) at
> ./remote/remote_daemon_dispatch_stubs.h:9178
> #16 0x7feacdd9b4b1 in virNetServerProgramDispatchCall
> (prog=0x5650302ccb70, server=0x56503027fc30, client=0x56503031ad70,
> msg=0x565030304eb0) at ../../src/rpc/virnetserverprogram.c:430
> #17 0x7feacdd9b026 in virNetServerProgramDispatch
> (prog=0x5650302ccb70, server=0x56503027fc30, client=0x56503031ad70,
> msg=0x565030304eb0) at ../../src/rpc/virnetserverprogram.c:302
> #18 0x7feacdda1e34 in virNetServerProcessMsg (srv=0x56503027fc30,
> client=0x56503031ad70, prog=0x5650302ccb70, msg=0x565030304eb0) at
> ../../src/rpc/virnetserver.c:136
> #19 0x7feacdda1ef4 in virNetServerHandleJob
> (jobOpaque=0x565030336ea0, opaque=0x56503027fc30) at
> ../../src/rpc/virnetserver.c:153
> #20 0x7feacdc79800 in virThreadPoolWorker (opaque=0x56503028a1f0) at
> ../../src/util/virthreadpool.c:163
>

Re: [libvirt] [PATCH] remote_daemon_stream: Hold an extra reference to stream in daemonStreamFilter

2019-11-25 Thread Lance Liu
Yeah, your patch is perfectly fine for stream freed problem.
But I have reviewed code in daemonStreamEvent() and daemonStreamFilter()
again, and I think there still two issue need to be reconsidered:
1. stream->ref only ++ in daemonStreamFilter, except for error
occurred call daemonRemoveClientStream() lead to ref--, like code as
follow. Though code won't be executed because of no VIR_STREAM_EVENT_HANGUP
event taken place,
but it is not good code:
/* If we got HANGUP, we need to only send an empty
 * packet so the client sees an EOF and cleans up
 */
if (!stream->closed && !stream->recvEOF &&
(events & VIR_STREAM_EVENT_HANGUP)) {
virNetMessagePtr msg;
events &= ~(VIR_STREAM_EVENT_HANGUP);
stream->tx = false;
stream->recvEOF = true;
if (!(msg = virNetMessageNew(false))) {
daemonRemoveClientStream(client, stream);
virNetServerClientClose(client);
goto cleanup;
}
msg->cb = daemonStreamMessageFinished;
msg->opaque = stream;
stream->refs++;
if (virNetServerProgramSendStreamData(stream->prog,
  client,
  msg,
  stream->procedure,
  stream->serial,
  "", 0) < 0) {
virNetMessageFree(msg);
daemonRemoveClientStream(client, stream);
virNetServerClientClose(client);
goto cleanup;
}
}
2. call virNetServerClientClose() is still inappropriate in  because the it
may free the client resource which other threads need ref, may be replace
it with virNetServerClientImmediateClose() is better,
the daemon can process client resource release unified
3. Segmentfault may still exists when another thread
call remoteClientCloseFunc in virNetServerClientClose()(for example, when
new force console session break down existed console session, and existed
console session
's client close the session simutaneously, but remoteClientCloseFunc not
lock(priv->lock), so the resource maybe released when daemonStreamEvent ref)

How do you see it?


Best Regards!




Michal Privoznik  于2019年11月26日周二 上午12:49写道:

> In v5.9.0-273-g8ecab214de I've tried to fix a lock ordering
> problem, but introduced a crasher. Problem is that because the
> client lock is unlocked (in order to honour lock ordering) the
> stream we are currently checking in daemonStreamFilter() might be
> freed and thus stream->priv might not even exist when the control
> get to virMutexLock() call.
>
> To resolve this, grab an extra reference to the stream and handle
> its cleanup should the refcounter reach zero after the deref.
> If that's the case and we are the only ones holding a reference
> to the stream, we MUST return a positive value to make
> virNetServerClientDispatchRead() break its loop where it iterates
> over filters. The problem is, if we did not do so, then
> "filter = filter->next" line will read from a memory that was
> just freed (freeing a stream also unregisters its filter).
>
> Signed-off-by: Michal Privoznik 
> ---
>
> Reproducing this issue is very easy:
>
> 1) put sleep(5) right after virObjectUnlock(client) in the fist hunk,
> 2) virsh console --force $dom   and type something so that the stream
>has some data to process
> 3) while 2) is still running, run the same command from another terminal
> 4) observe libvirtd crash
>
>  src/remote/remote_daemon_stream.c | 19 +++
>  1 file changed, 19 insertions(+)
>
> diff --git a/src/remote/remote_daemon_stream.c
> b/src/remote/remote_daemon_stream.c
> index 82cadb67ac..73e4d7befb 100644
> --- a/src/remote/remote_daemon_stream.c
> +++ b/src/remote/remote_daemon_stream.c
> @@ -293,10 +293,25 @@ daemonStreamFilter(virNetServerClientPtr client,
>  daemonClientStream *stream = opaque;
>  int ret = 0;
>
> +/* We must honour lock ordering here. Client private data lock must
> + * be acquired before client lock. Bu we are already called with
> + * client locked. To avoid stream disappearing while we unlock
> + * everything, let's increase its refcounter. This has some
> + * implications though. */
> +stream->refs++;
>  virObjectUnlock(client);
>  virMutexLock(>priv->lock);
>  virObjectLock(client);
>
> +if (stream->refs == 1) {
> +/* So we are the only ones holding the reference to the stream.
> + * Return 1 to signal to the caller that we've processed the
> + * message. And to "process" means free. */
> +virNetMessageFree(msg);
> +ret = 1;
> +goto cleanup;
> +}
> +
>  if (msg->header.type != VIR_NET_STREAM &&
>  msg->header.type != VIR_NET_STREAM_HOLE)
>  goto cleanup;
> @@ -318,6 +333,10 @@ daemonStreamFilter(virNetServerClientPtr client,
>
>   cleanup:
>  

Re: [libvirt] [PATCH] Use virNetServerClientImmediateClose() rather than virNetServerClientClose()

2019-11-25 Thread Lance Liu
As I mentioned, I think add this patch will solve the problem you worried
about

LanceLiu  于2019年11月25日周一 下午7:23写道:

> ---
>  src/remote/remote_daemon_stream.c | 14 +++---
>  1 file changed, 7 insertions(+), 7 deletions(-)
>
> diff --git a/src/remote/remote_daemon_stream.c
> b/src/remote/remote_daemon_stream.c
> index de0dca3..d206d12 100644
> --- a/src/remote/remote_daemon_stream.c
> +++ b/src/remote/remote_daemon_stream.c
> @@ -141,7 +141,7 @@ daemonStreamEvent(virStreamPtr st, int events, void
> *opaque)
>  (events & VIR_STREAM_EVENT_WRITABLE)) {
>  if (daemonStreamHandleWrite(client, stream) < 0) {
>  daemonRemoveClientStream(client, stream);
> -virNetServerClientClose(client);
> +virNetServerClientImmediateClose(client);
>  goto cleanup;
>  }
>  }
> @@ -151,7 +151,7 @@ daemonStreamEvent(virStreamPtr st, int events, void
> *opaque)
>  events = events & ~(VIR_STREAM_EVENT_READABLE);
>  if (daemonStreamHandleRead(client, stream) < 0) {
>  daemonRemoveClientStream(client, stream);
> -virNetServerClientClose(client);
> +virNetServerClientImmediateClose(client);
>  goto cleanup;
>  }
>  /* If we detected EOF during read processing,
> @@ -176,7 +176,7 @@ daemonStreamEvent(virStreamPtr st, int events, void
> *opaque)
>  if (daemonStreamHandleFinish(client, stream, msg) < 0) {
>  virNetMessageFree(msg);
>  daemonRemoveClientStream(client, stream);
> -virNetServerClientClose(client);
> +virNetServerClientImmediateClose(client);
>  goto cleanup;
>  }
>  break;
> @@ -186,7 +186,7 @@ daemonStreamEvent(virStreamPtr st, int events, void
> *opaque)
>  if (daemonStreamHandleAbort(client, stream, msg) < 0) {
>  virNetMessageFree(msg);
>  daemonRemoveClientStream(client, stream);
> -virNetServerClientClose(client);
> +virNetServerClientImmediateClose(client);
>  goto cleanup;
>  }
>  break;
> @@ -205,7 +205,7 @@ daemonStreamEvent(virStreamPtr st, int events, void
> *opaque)
>  stream->recvEOF = true;
>  if (!(msg = virNetMessageNew(false))) {
>  daemonRemoveClientStream(client, stream);
> -virNetServerClientClose(client);
> +virNetServerClientImmediateClose(client);
>  goto cleanup;
>  }
>  msg->cb = daemonStreamMessageFinished;
> @@ -219,7 +219,7 @@ daemonStreamEvent(virStreamPtr st, int events, void
> *opaque)
>"", 0) < 0) {
>  virNetMessageFree(msg);
>  daemonRemoveClientStream(client, stream);
> -virNetServerClientClose(client);
> +virNetServerClientImmediateClose(client);
>  goto cleanup;
>  }
>  }
> @@ -262,7 +262,7 @@ daemonStreamEvent(virStreamPtr st, int events, void
> *opaque)
>  }
>  daemonRemoveClientStream(client, stream);
>  if (ret < 0)
> -virNetServerClientClose(client);
> +   virNetServerClientImmediateClose(client);
>  goto cleanup;
>  }
>
> --
> 1.8.3.1
>
>
--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list

Re: [libvirt] [PATCH] Fix bug libvirt daemon segfault when new force console vm session break down existed console session. When force console vm command arrived, libvirtd will break down existed cons

2019-11-25 Thread Lance Liu
We first produce this bug in rhel7.4's libvir daemon。For easily produce the
bug, the step can be as follows:
1. add sleep(3)  in daemonStreamFilter() pre
virMutexLock(>priv->lock), then build libvirtd bin executable, then
restart libvirtd
2. use virsh console open one vm's console, for this console(the vm's
kernel need console=ttyS0 boot parameter,then just  input from keyboard on
and on
3. use virsh console --force to break the previous console session,  than
you will get libvirt daemon deadlock。

And for the problem client->privData to be released problem, only
virNetServerClientClose() will free client->privData and client, I think
this can be fixed by remove virNetServerClientClose()
from daemonStreamEvent(),
and replace with virNetServerClientImmediateClose(),
so virNetServerProcessClients() will test the session would be closed。



Michal Privoznik  于2019年11月25日周一 下午5:38写道:

> On 11/25/19 8:34 AM, LanceLiu wrote:
> > ---
> >   src/libvirt_remote.syms   |  1 +
> >   src/remote/remote_daemon_stream.c | 10 +-
> >   src/rpc/virnetserverclient.c  | 12 
> >   src/rpc/virnetserverclient.h  |  2 ++
> >   4 files changed, 24 insertions(+), 1 deletion(-)
>
> Please format commit messages following title + message format (look at
> git log how other messages are formatted).
>
> >
> > diff --git a/src/libvirt_remote.syms b/src/libvirt_remote.syms
> > index 0493467..c32e234 100644
> > --- a/src/libvirt_remote.syms
> > +++ b/src/libvirt_remote.syms
> > @@ -173,6 +173,7 @@ virNetServerClientPreExecRestart;
> >   virNetServerClientRemoteAddrStringSASL;
> >   virNetServerClientRemoteAddrStringURI;
> >   virNetServerClientRemoveFilter;
> > +virNetServerClientCheckFilterExist;
> >   virNetServerClientSendMessage;
> >   virNetServerClientSetAuthLocked;
> >   virNetServerClientSetAuthPendingLocked;
> > diff --git a/src/remote/remote_daemon_stream.c
> b/src/remote/remote_daemon_stream.c
> > index 82cadb6..de0dca3 100644
> > --- a/src/remote/remote_daemon_stream.c
> > +++ b/src/remote/remote_daemon_stream.c
> > @@ -292,10 +292,18 @@ daemonStreamFilter(virNetServerClientPtr client,
> >   {
> >   daemonClientStream *stream = opaque;
> >   int ret = 0;
> > +daemonClientPrivatePtr priv = NULL;
> > +int filter_id = stream->filterID;
> >
> >   virObjectUnlock(client);
> > +priv = virNetServerClientGetPrivateData(client);
>
> This is not needed.
>
> >   virMutexLock(>priv->lock);
> >   virObjectLock(client);
> > +if (!virNetServerClientCheckFilterExist(client, filter_id)) {
> > +VIR_WARN("this daemon stream filter: %d have been deleted!",
> filter_id);
> > +ret = -1;
> > +goto cleanup;
> > +}
> >
> >   if (msg->header.type != VIR_NET_STREAM &&
> >   msg->header.type != VIR_NET_STREAM_HOLE)
> > @@ -317,7 +325,7 @@ daemonStreamFilter(virNetServerClientPtr client,
> >   ret = 1;
> >
> >cleanup:
> > -virMutexUnlock(>priv->lock);
> > +virMutexUnlock(>lock);
>
> This is not needed: stream->priv and priv are the same structure.
>
> >   return ret;
> >   }
> >
>
> Anyway, this still doesn't work. Problem is, that if a stream is
> removed, the private data might be removed too and hence
> virMutexLock(>priv->lock) will do something undefined (besides
> accessing freed memory). In my testing the daemon deadlocks because it's
> trying to lock stream-priv->lock which is locked.
>
> As I said in the other thread - we need to re-evaluate the first commit.
> Do you have a reproducer for the original problem please?
>
> Michal
>
>
--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list

Re: [libvirt] [PATCH] Fix bug libvirt daemon segfault when new force console vm session break down existed console session. When force console vm command arrived, libvirtd will break down existed cons

2019-11-24 Thread Lance Liu
Previous patch can not pass build because of
missing virNetServerClientCheckFilterExist stated in libvirt_remote.syms

LanceLiu  于2019年11月25日周一 下午3:34写道:

> ---
>  src/libvirt_remote.syms   |  1 +
>  src/remote/remote_daemon_stream.c | 10 +-
>  src/rpc/virnetserverclient.c  | 12 
>  src/rpc/virnetserverclient.h  |  2 ++
>  4 files changed, 24 insertions(+), 1 deletion(-)
>
> diff --git a/src/libvirt_remote.syms b/src/libvirt_remote.syms
> index 0493467..c32e234 100644
> --- a/src/libvirt_remote.syms
> +++ b/src/libvirt_remote.syms
> @@ -173,6 +173,7 @@ virNetServerClientPreExecRestart;
>  virNetServerClientRemoteAddrStringSASL;
>  virNetServerClientRemoteAddrStringURI;
>  virNetServerClientRemoveFilter;
> +virNetServerClientCheckFilterExist;
>  virNetServerClientSendMessage;
>  virNetServerClientSetAuthLocked;
>  virNetServerClientSetAuthPendingLocked;
> diff --git a/src/remote/remote_daemon_stream.c
> b/src/remote/remote_daemon_stream.c
> index 82cadb6..de0dca3 100644
> --- a/src/remote/remote_daemon_stream.c
> +++ b/src/remote/remote_daemon_stream.c
> @@ -292,10 +292,18 @@ daemonStreamFilter(virNetServerClientPtr client,
>  {
>  daemonClientStream *stream = opaque;
>  int ret = 0;
> +daemonClientPrivatePtr priv = NULL;
> +int filter_id = stream->filterID;
>
>  virObjectUnlock(client);
> +priv = virNetServerClientGetPrivateData(client);
>  virMutexLock(>priv->lock);
>  virObjectLock(client);
> +if (!virNetServerClientCheckFilterExist(client, filter_id)) {
> +VIR_WARN("this daemon stream filter: %d have been deleted!",
> filter_id);
> +ret = -1;
> +goto cleanup;
> +}
>
>  if (msg->header.type != VIR_NET_STREAM &&
>  msg->header.type != VIR_NET_STREAM_HOLE)
> @@ -317,7 +325,7 @@ daemonStreamFilter(virNetServerClientPtr client,
>  ret = 1;
>
>   cleanup:
> -virMutexUnlock(>priv->lock);
> +virMutexUnlock(>lock);
>  return ret;
>  }
>
> diff --git a/src/rpc/virnetserverclient.c b/src/rpc/virnetserverclient.c
> index 67b3bf9..f80f493 100644
> --- a/src/rpc/virnetserverclient.c
> +++ b/src/rpc/virnetserverclient.c
> @@ -287,6 +287,18 @@ void
> virNetServerClientRemoveFilter(virNetServerClientPtr client,
>  virObjectUnlock(client);
>  }
>
> +int virNetServerClientCheckFilterExist(virNetServerClientPtr client,
> +   int filterID)
> +{
> +virNetServerClientFilterPtr tmp;
> +
> +tmp = client->filters;
> +while(tmp && tmp->id != filterID) {
> +tmp = tmp->next;
> +}
> +
> +return (tmp != NULL);
> +}
>
>  /* Check the client's access. */
>  static int
> diff --git a/src/rpc/virnetserverclient.h b/src/rpc/virnetserverclient.h
> index 7a3061d..85fda39 100644
> --- a/src/rpc/virnetserverclient.h
> +++ b/src/rpc/virnetserverclient.h
> @@ -93,6 +93,8 @@ int virNetServerClientAddFilter(virNetServerClientPtr
> client,
>
>  void virNetServerClientRemoveFilter(virNetServerClientPtr client,
>  int filterID);
> +int virNetServerClientCheckFilterExist(virNetServerClientPtr client,
> +   int filterID);
>
>  int virNetServerClientGetAuth(virNetServerClientPtr client);
>  void virNetServerClientSetAuthLocked(virNetServerClientPtr client, int
> auth);
> --
> 1.8.3.1
>
>
--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list

Re: [libvirt] [PATCH] fix bug libvirt daemon deadlock when another force console break down an existed console client when this deadlock hanppened, libvirtd backtrace as follow, a typical ABBA deadloc

2019-11-22 Thread Lance Liu
Thank you!
But it looks like libvirtd daemon stream module still has bug lead to
process segfault if applied this patch(if not, it will lead libvirtd
deadlock).I have got the cause, but it seems difficult to fix it with
present codes。
Bug reproduce:
1. add sleep(3) in daemonStreamFilter() so it is easily to get the point,
as follows
  static int
daemonStreamFilter(virNetServerClientPtr client,
   virNetMessagePtr msg,
   void *opaque)
{
daemonClientStream *stream = opaque;
int ret = 0;
static int first = 1;

//if (first) {
//notify_force_console();
//VIR_ERROR("notify force console to break this client down!client:
%p", client);
//sleep(30);
//VIR_ERROR("sleep 10 finished");
//}
VIR_ERROR("stream: %p, filter_id: %d", stream, stream->filterID);
virObjectUnlock(client);
sleep(3);
virMutexLock(>priv->lock);
virObjectLock(client);
2. build the libvirtd with new code, then replace the libvirtd
3. use virsh console to open a vm's console tty, then just input many chars
in the console
4. open new terminal, then use virsh console --force to break the previous
client, then you'll got libvirtd segfault

it looks because when daemonStreamEvent() with para events
as VIR_STREAM_EVENT_ERROR  is called, it will remove stream and free stream,
but daemonStreamFilter still waiting stream->priv->lock mutex, thus cause
invalid memory access

To fix this, I think the most effective and clean way is to drop
client->priv->lock elements, just use client object lock。But for current
code, it's not easy to do that。
also, a workaroud scheme is  to add a big lock, but is ugly and low
efficient。

Any good ideas?




Michal Privoznik  于2019年11月19日周二 下午11:41写道:

> On 11/19/19 12:39 PM, LanceLiu wrote:
> > (gdb) thread 23
> > [Switching to thread 23 (Thread 0x7fbb54810700 (LWP 296966))]
> > (gdb) bt
> >  at rpc/virnetserverclient.c:1503
> >  client=client@entry=0x5641d20e20a0, msg=0x7fbb08003ab0,
> rerr=rerr@entry=0x7fbb5480f7b0, procedure=201,
> >  type=type@entry=3, serial=9) at rpc/virnetserverprogram.c:173
> >  msg=, rerr=rerr@entry=0x7fbb5480f7b0,
> procedure=, serial=)
> >  at rpc/virnetserverprogram.c:222
> >  opaque=opaque@entry=0x5641d20e20a0) at stream.c:246
> >  force=force@entry=true) at conf/virchrdev.c:386
> >  at qemu/qemu_driver.c:16188
> >  st=st@entry=0x7fbb08008fc0, flags=1) at libvirt-domain.c:9363
> >  rerr=0x7fbb5480fc10, msg=, client=0x5641d20e4e80) at
> remote_dispatch.h:8540
> >  rerr=0x7fbb5480fc10, args=0x7fbb08005eb0, ret=) at
> remote_dispatch.h:8505
> >  server=0x5641d20be420, prog=0x5641d20da580) at
> rpc/virnetserverprogram.c:437
> >  msg=0x5641d20e9a20) at rpc/virnetserverprogram.c:307
> >  srv=0x5641d20be420) at rpc/virnetserver.c:148
> > ---Type  to continue, or q  to quit---
> >
> > (gdb) thread 26
> > [Switching to thread 26 (Thread 0x7fbb87a378c0 (LWP 295636))]
> > (gdb) bt
> >  at stream.c:286
> >  at rpc/virnetserverclient.c:1247
> >  at rpc/virnetserverclient.c:1457
> >  at util/vireventpoll.c:508
> >
> > Signed-off-by: LanceLiu 
> > ---
> >   src/remote/remote_daemon_stream.c | 4 +++-
> >   1 file changed, 3 insertions(+), 1 deletion(-)
> >
> > diff --git a/src/remote/remote_daemon_stream.c
> b/src/remote/remote_daemon_stream.c
> > index 1f6e783..b27348f 100644
> > --- a/src/remote/remote_daemon_stream.c
> > +++ b/src/remote/remote_daemon_stream.c
> > @@ -284,14 +284,16 @@ daemonStreamEvent(virStreamPtr st, int events,
> void *opaque)
> >* -1 on fatal client error
> >*/
> >   static int
> > -daemonStreamFilter(virNetServerClientPtr client ATTRIBUTE_UNUSED,
> > +daemonStreamFilter(virNetServerClientPtr client,
>
> This does not look rebased onto current git HEAD ;-) "Luckily", the
> problem you're fixing is still there.
>
> >  virNetMessagePtr msg,
> >  void *opaque)
> >   {
> >   daemonClientStream *stream = opaque;
> >   int ret = 0;
> >
> > +virObjectUnlock(client);
> >   virMutexLock(>priv->lock);
> > +virObjectLock(client);
> >
> >   if (msg->header.type != VIR_NET_STREAM &&
> >   msg->header.type != VIR_NET_STREAM_HOLE)
> >
>
> I've reworded the commit message, put a comment to
> virNetServerClientFilterFunc() typedef, ACKed and pushed.
>
> Congratulations on your first libvirt contribution!
>
> Michal
>
>
--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list