qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Eric Blake <eblake@redhat.com>
To: Stefan Hajnoczi <stefanha@redhat.com>, qemu-devel@nongnu.org
Cc: Paolo Bonzini <pbonzini@redhat.com>,
	Gerd Hoffmann <kraxel@redhat.com>,
	Daniel Berrange <berrange@redhat.com>
Subject: Re: [Qemu-devel] [PATCH] socket: add atomic QEMU_SOCK_NONBLOCK flag
Date: Fri, 7 Oct 2016 10:55:55 -0500	[thread overview]
Message-ID: <b2cc4889-6255-f96e-1a36-af47d797b2c1@redhat.com> (raw)
In-Reply-To: <1475848458-1285-1-git-send-email-stefanha@redhat.com>

[-- Attachment #1: Type: text/plain, Size: 5577 bytes --]

On 10/07/2016 08:54 AM, Stefan Hajnoczi wrote:
> The socket(2) and accept(2) syscalls have been extended to take flags
> that affect the socket atomically at creation time.  This not only
> avoids the overhead of additional system calls but also closes the race
> condition with forking threads.
> 
> This patch adds support for the SOCK_NONBLOCK flag.  QEMU already
> implements the SOCK_CLOEXEC flag.

Atomic where supported by the OS, racy fallback on older systems, but
not the end of the world (and our already-existing fallback is already
racy, where the SOCK_CLOEXEC race is more likely to affect a
multithreaded forking app, while SOCK_NONBLOCK is just there for
convenience).

> 
> All qemu_socket() and qemu_accept() callers are updated to pass the new
> flags argument.  Callers that later use qemu_set_nonblock() are
> refactored as follows:
> 
>   fd = qemu_socket(...) or qemu_accept(...);
>   ...
>   qemu_set_nonblock(fd);
> 
> Becomes:
> 
>   fd = qemu_socket(..., QEMU_SOCK_NONBLOCK) or
>        qemu_accept(..., QEMU_SOCK_NONBLOCK);
> 
> For full details on SOCK_NONBLOCK in the POSIX spec see:
> http://austingroupbugs.net/view.php?id=411

/me that looks strangely familiar... :)

> 
> Note that slirp code violates the coding style with a mix of tabs and
> space indentation.  This patch passes checkpatch.pl but the diff may
> appear odd due to the mixed indentation in slirp code.
> 
> Suggested-by: Eric Blake <eblake@redhat.com>
> Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
> ---

> +++ b/include/qemu/sockets.h
> @@ -11,9 +11,14 @@ int inet_aton(const char *cp, struct in_addr *ia);
>  
>  #include "qapi-types.h"
>  
> +typedef enum {
> +    QEMU_SOCK_NONBLOCK = 1,
> +} QemuSockFlags;

Good, since we can't rely on SOCK_NONBLOCK being defined everywhere yet.

> --- a/slirp/misc.c
> +++ b/slirp/misc.c

> @@ -184,13 +185,13 @@ fork_exec(struct socket *so, const char *ex, int do_pty)
>                   * of connect() fail in the child process
>                   */
>                  do {
> -                    so->s = accept(s, (struct sockaddr *)&addr, &addrlen);
> +                    so->s = qemu_accept(s, (struct sockaddr *)&addr, &addrlen,
> +                                        QEMU_SOCK_NONBLOCK);

Silent bug fix here and elsewhere that we now set CLOEXEC where we
previously didn't.  Probably worth mentioning in the commit message that
you fixed a couple of places that used accept() instead of the proper
qemu_accept().

> +++ b/util/osdep.c
> @@ -267,12 +267,21 @@ ssize_t qemu_write_full(int fd, const void *buf, size_t count)
>  /*
>   * Opens a socket with FD_CLOEXEC set
>   */
> -int qemu_socket(int domain, int type, int protocol)
> +int qemu_socket(int domain, int type, int protocol, QemuSockFlags flags)
>  {
>      int ret;
>  
> -#ifdef SOCK_CLOEXEC
> -    ret = socket(domain, type | SOCK_CLOEXEC, protocol);
> +    /* Require both SOCK_CLOEXEC and SOCK_NONBLOCK to avoid additional cases
> +     * with only one defined.  Both were added to POSIX in Austin Group #411 so
> +     * chances are good they come in a pair.

Indeed.

> @@ -288,12 +300,17 @@ int qemu_socket(int domain, int type, int protocol)
>  /*
>   * Accept a connection and set FD_CLOEXEC
>   */
> -int qemu_accept(int s, struct sockaddr *addr, socklen_t *addrlen)
> +int qemu_accept(int s, struct sockaddr *addr, socklen_t *addrlen,
> +                QemuSockFlags flags)
>  {
>      int ret;
>  
>  #ifdef CONFIG_ACCEPT4
> -    ret = accept4(s, addr, addrlen, SOCK_CLOEXEC);
> +    int accept_flags = SOCK_CLOEXEC;
> +    if (flags & QEMU_SOCK_NONBLOCK) {
> +        accept_flags |= SOCK_NONBLOCK;
> +    }

You're also (implicitly) assuming that CONFIG_ACCEPT4 implies both
SOCK_CLOEXEC and SOCK_NONBLOCK; again likely to be true.

> @@ -317,18 +318,20 @@ static int inet_connect_addr(struct addrinfo *addr, bool *in_progress,
>                               ConnectState *connect_state, Error **errp)
>  {
>      int sock, rc;
> +    QemuSockFlags flags = 0;
>  
>      *in_progress = false;
>  
> -    sock = qemu_socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
> -    if (sock < 0) {
> -        error_setg_errno(errp, errno, "Failed to create socket");
> -        return -1;
> -    }
> -    socket_set_fast_reuse(sock);
>      if (connect_state != NULL) {
> -        qemu_set_nonblock(sock);
> +        flags = QEMU_SOCK_NONBLOCK;

Use |= here? ...


> @@ -732,16 +737,16 @@ static int unix_connect_saddr(UnixSocketAddress *saddr, Error **errp,
>          return -1;
>      }
>  
> -    sock = qemu_socket(PF_UNIX, SOCK_STREAM, 0);
> -    if (sock < 0) {
> -        error_setg_errno(errp, errno, "Failed to create socket");
> -        return -1;
> -    }
>      if (callback != NULL) {
>          connect_state = g_malloc0(sizeof(*connect_state));
>          connect_state->callback = callback;
>          connect_state->opaque = opaque;
> -        qemu_set_nonblock(sock);
> +        flags |= QEMU_SOCK_NONBLOCK;
> +    }

...to match how you did it here?  (No current semantic difference, but
might lead to future maintenance problems if further additions aren't
careful.)

I found a minor nit and some suggested commit message improvements, but
the patch itself is sane enough that I'm okay if you add:
Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

  reply	other threads:[~2016-10-07 15:56 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-10-07 13:54 [Qemu-devel] [PATCH] socket: add atomic QEMU_SOCK_NONBLOCK flag Stefan Hajnoczi
2016-10-07 15:55 ` Eric Blake [this message]
2016-10-12 15:11   ` Stefan Hajnoczi
2016-10-10 19:05 ` no-reply

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=b2cc4889-6255-f96e-1a36-af47d797b2c1@redhat.com \
    --to=eblake@redhat.com \
    --cc=berrange@redhat.com \
    --cc=kraxel@redhat.com \
    --cc=pbonzini@redhat.com \
    --cc=qemu-devel@nongnu.org \
    --cc=stefanha@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).