[libvirt] [PATCH 3/5] rpc: invoke the message dispatch callback with client unlocked
Daniel P. Berrangé
berrange at redhat.com
Thu Mar 8 10:10:58 UTC 2018
On Wed, Mar 07, 2018 at 06:48:25PM -0500, John Ferlan wrote:
>
>
> On 03/06/2018 12:58 PM, Daniel P. Berrangé wrote:
> > Currently if the virNetServer instance is created with max_workers==0 to
> > request a non-threaded dispatch process, we deadlock during dispatch
> >
> > #0 0x00007fb845f6f42d in __lll_lock_wait () from /lib64/libpthread.so.0
> > #1 0x00007fb845f681d3 in pthread_mutex_lock () from /lib64/libpthread.so.0
> > #2 0x000055a6628bb305 in virMutexLock (m=<optimized out>) at util/virthread.c:89
> > #3 0x000055a6628a984b in virObjectLock (anyobj=<optimized out>) at util/virobject.c:435
> > #4 0x000055a66286fcde in virNetServerClientIsAuthenticated (client=client at entry=0x55a663a7b960)
> > at rpc/virnetserverclient.c:1565
> > #5 0x000055a66286cc17 in virNetServerProgramDispatchCall (msg=0x55a663a7bc50, client=0x55a663a7b960,
> > server=0x55a663a77550, prog=0x55a663a78020) at rpc/virnetserverprogram.c:407
> > #6 virNetServerProgramDispatch (prog=prog at entry=0x55a663a78020, server=server at entry=0x55a663a77550,
> > client=client at entry=0x55a663a7b960, msg=msg at entry=0x55a663a7bc50) at rpc/virnetserverprogram.c:307
> > #7 0x000055a662871d56 in virNetServerProcessMsg (msg=0x55a663a7bc50, prog=0x55a663a78020, client=0x55a663a7b960,
> > srv=0x55a663a77550) at rpc/virnetserver.c:148
> > #8 virNetServerDispatchNewMessage (client=0x55a663a7b960, msg=0x55a663a7bc50, opaque=0x55a663a77550)
> > at rpc/virnetserver.c:227
> > #9 0x000055a66286e4c0 in virNetServerClientDispatchRead (client=client at entry=0x55a663a7b960)
> > at rpc/virnetserverclient.c:1322
> > #10 0x000055a66286e813 in virNetServerClientDispatchEvent (sock=<optimized out>, events=1, opaque=0x55a663a7b960)
> > at rpc/virnetserverclient.c:1507
> > #11 0x000055a662899be0 in virEventPollDispatchHandles (fds=0x55a663a7bdc0, nfds=<optimized out>)
> > at util/vireventpoll.c:508
> > #12 virEventPollRunOnce () at util/vireventpoll.c:657
> > #13 0x000055a6628982f1 in virEventRunDefaultImpl () at util/virevent.c:327
> > #14 0x000055a6628716d5 in virNetDaemonRun (dmn=0x55a663a771b0) at rpc/virnetdaemon.c:858
> > #15 0x000055a662864c1d in main (argc=<optimized out>, argv=0x7ffd105b4838) at logging/log_daemon.c:1235
> >
> > Signed-off-by: Daniel P. Berrangé <berrange at redhat.com>
> > ---
> > src/rpc/virnetserverclient.c | 79 ++++++++++++++++++++++++++++++--------------
> > 1 file changed, 55 insertions(+), 24 deletions(-)
> >
>
> I had the same syntax-check notes that Jim had.
>
> Beyond that since both callers Unlock prior to calling
> virNetServerClientDispatchMessage and the code relocks right away, would
> calling with client lock'd still be prudent/possible? Callers would
> then be able to
>
> if (msg)
> virNetServerClientDispatchMessage(...)
> else
> Unlock(client)
>
> Once we get to virNetServerProgramDispatch it expects an unlocked
> client. Maybe we should comment some of the other callers in the path to
> indicate whether server/client need to be locked. Not required though -
> only helpful for future spelunkers of this code.
I generally like to avoid situations where one method locks the object and
then calls another method which unlocks it. IMHO, it leads to harder to
understand code where the lock/unlock calls are spread out.
Since we own the reference on client, I think unlocking & locking again
is harmless here.
> > @@ -1313,16 +1347,6 @@ static void virNetServerClientDispatchRead(virNetServerClientPtr client)
> > }
> > }
> >
> > - /* Send off to for normal dispatch to workers */
> > - if (msg) {
> > - if (!client->dispatchFunc) {
> > - virNetMessageFree(msg);
> > - client->wantClose = true;
> > - } else {
> > - client->dispatchFunc(client, msg, client->dispatchOpaque);
> > - }
> > - }
> > -
>
> I thought about the order change here w/r/t the following code being run
> before the dispatch options above; however, that would perhaps more of a
> concern for the path where we have no workers. If we have a worker, then
> it gets queued and the following would then occur first anyway, right?
> So, IOW, I think the reordering here is fine. It would happen before the
> worker got around to handling the client and moving it around to
> virNetServerClientDispatchMessage could get ugly w/r/t locks.
Yeah, that was my rationale too - since worker threads are asynchronous
we're effectively running the second block first regardless, so the
ordering should be harmless.
>
> Reviewed-by: John Ferlan <jferlan at redhat.com>
>
> John
>
>
> > /* Possibly need to create another receive buffer */
> > if (client->nrequests < client->nrequests_max) {
> > if (!(client->rx = virNetMessageNew(true))) {
> > @@ -1338,6 +1362,8 @@ static void virNetServerClientDispatchRead(virNetServerClientPtr client)
> > }
> > }
> > virNetServerClientUpdateEvent(client);
> > +
> > + return msg;
> > }
> > }
> >
>
> [...]
Regards,
Daniel
--
|: https://berrange.com -o- https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org -o- https://fstop138.berrange.com :|
|: https://entangle-photo.org -o- https://www.instagram.com/dberrange :|
More information about the libvir-list
mailing list