qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [PATCH] docs: show how to spawn qemu-storage-daemon with fd passing


From: Stefan Hajnoczi
Subject: Re: [PATCH] docs: show how to spawn qemu-storage-daemon with fd passing
Date: Mon, 1 Mar 2021 16:50:14 +0000

On Mon, Mar 01, 2021 at 03:44:42PM +0000, Daniel P. Berrangé wrote:
> On Mon, Mar 01, 2021 at 03:39:06PM +0000, Richard W.M. Jones wrote:
> > On Mon, Mar 01, 2021 at 03:31:59PM +0000, Stefan Hajnoczi wrote:
> > > The QMP monitor, NBD server, and vhost-user-blk export all support file
> > > descriptor passing. This is a useful technique because it allows the
> > > parent process to spawn and wait for qemu-storage-daemon without busy
> > > waiting, which may delay startup due to arbitrary sleep() calls.
> > > 
> > > This Python example is inspired by the test case written for libnbd by
> > > Richard W.M. Jones <rjones@redhat.com>:
> > > https://gitlab.com/nbdkit/libnbd/-/commit/89113f484effb0e6c322314ba75c1cbe07a04543
> > > 
> > > Thanks to Daniel P. Berrangé <berrange@redhat.com> for suggestions on
> > > how to get this working. Now let's document it!
> > > 
> > > Reported-by: Richard W.M. Jones <rjones@redhat.com>
> > > Cc: Kevin Wolf <kwolf@redhat.com>
> > > Cc: Daniel P. Berrangé <berrange@redhat.com>
> > > Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
> > > ---
> > >  docs/tools/qemu-storage-daemon.rst | 38 ++++++++++++++++++++++++++++--
> > >  1 file changed, 36 insertions(+), 2 deletions(-)
> > > 
> > > diff --git a/docs/tools/qemu-storage-daemon.rst 
> > > b/docs/tools/qemu-storage-daemon.rst
> > > index f63627eaf6..45854c131e 100644
> > > --- a/docs/tools/qemu-storage-daemon.rst
> > > +++ b/docs/tools/qemu-storage-daemon.rst
> > > @@ -101,10 +101,12 @@ Standard options:
> > >  
> > >  .. option:: --nbd-server 
> > > addr.type=inet,addr.host=<host>,addr.port=<port>[,tls-creds=<id>][,tls-authz=<id>][,max-connections=<n>]
> > >    --nbd-server 
> > > addr.type=unix,addr.path=<path>[,tls-creds=<id>][,tls-authz=<id>][,max-connections=<n>]
> > > +  --nbd-server 
> > > addr.type=fd,addr.str=<fd>[,tls-creds=<id>][,tls-authz=<id>][,max-connections=<n>]
> > >  
> > >    is a server for NBD exports. Both TCP and UNIX domain sockets are 
> > > supported.
> > > -  TLS encryption can be configured using ``--object`` tls-creds-* and 
> > > authz-*
> > > -  secrets (see below).
> > > +  A listen socket can be provided via file descriptor passing (see 
> > > Examples
> > > +  below). TLS encryption can be configured using ``--object`` 
> > > tls-creds-* and
> > > +  authz-* secrets (see below).
> > >  
> > >    To configure an NBD server on UNIX domain socket path 
> > > ``/tmp/nbd.sock``::
> > >  
> > > @@ -127,6 +129,38 @@ QMP commands::
> > >        --chardev socket,path=qmp.sock,server,nowait,id=char1 \
> > >        --monitor chardev=char1
> > >  
> > > +Launch the daemon from Python with a QMP monitor socket using file 
> > > descriptor
> > > +passing so there is no need to busy wait for the QMP monitor to become
> > > +available::
> > > +
> > > +  #!/usr/bin/env python3
> > > +  import os
> > > +  import subprocess
> > > +  import socket
> > > +
> > > +  sock_path = '/tmp/qmp-{}.sock'.format(os.getpid())
> > 
> > Not sure how much you worry about the insecure / easily guessable tmp
> > path here.  I notice that there's already one in the surrounding
> > documentation (/tmp/nbd.sock) so maybe it's not a problem :-)
> > 
> > > +  with socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) as listen_sock:
> > > +      listen_sock.bind(sock_path)
> > > +      listen_sock.listen()
> > > +
> > > +      fd = listen_sock.fileno()
> > > +
> > > +      subprocess.Popen(
> > > +          ['qemu-storage-daemon',
> > > +           '--chardev', f'socket,fd={fd},server=on,id=char1',
> > > +           '--monitor', 'chardev=char1'],
> > > +          pass_fds=[fd],
> > > +      )
> > > +
> > > +  qmp_sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
> > > +  qmp_sock.connect(sock_path)
> > 
> > A note that the order of opening the sockets is slightly different
> > from how I did it in the interop test.  But I believe it makes no
> > difference, as long as you don't connect to the socket until it's in
> > the listening state, which is what you're doing here.  So it should be
> > fine.
> 
> Nothing here is closing listen_sock in the parent though.
> 
> The trick of passing the listener FD into the child relies on the
> listener being closed in the parent, so that the parent can get
> a socket error if the child exits abnormally during startup. Keeping
> the listen socket open means the parent will wait forever for an
> accept() that never comes.

The listen socket is closed by the context manager at the end of the
'with' statement. This is the modern Python approach for resource
acquisition that also handles exceptions automatically. It's like RAII
in C++.

https://www.python.org/dev/peps/pep-0343/#specification-the-with-statement

Stefan

Attachment: signature.asc
Description: PGP signature


reply via email to

[Prev in Thread] Current Thread [Next in Thread]