[libvirt] [PATCH 5/5] rpc: make daemon spawning a bit more intelligent
Cole Robinson
crobinso at redhat.com
Mon Sep 15 18:22:02 UTC 2014
On 09/08/2014 01:46 AM, Martin Kletzander wrote:
> This way it behaves more like the daemon itself does (acquiring a
> pidfile, deleting the socket before binding, etc.).
>
> Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=927369
> Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1138604
>
> Signed-off-by: Martin Kletzander <mkletzan at redhat.com>
> ---
> src/rpc/virnetsocket.c | 57 ++++++++++++++++++++++++++++++++++++++++++++------
> 1 file changed, 51 insertions(+), 6 deletions(-)
>
> diff --git a/src/rpc/virnetsocket.c b/src/rpc/virnetsocket.c
> index 42184bd..18a5a8f 100644
> --- a/src/rpc/virnetsocket.c
> +++ b/src/rpc/virnetsocket.c
> @@ -51,9 +51,11 @@
> #include "virlog.h"
> #include "virfile.h"
> #include "virthread.h"
> +#include "virpidfile.h"
> #include "virprobe.h"
> #include "virprocess.h"
> #include "virstring.h"
> +#include "dirname.h"
> #include "passfd.h"
>
> #if WITH_SSH2
> @@ -544,7 +546,10 @@ int virNetSocketNewConnectUNIX(const char *path,
> const char *binary,
> virNetSocketPtr *retsock)
> {
> + char *binname = NULL;
> + char *pidpath = NULL;
> int fd, passfd = -1;
> + int pidfd = -1;
> virSocketAddr localAddr;
> virSocketAddr remoteAddr;
>
> @@ -583,16 +588,45 @@ int virNetSocketNewConnectUNIX(const char *path,
> goto error;
> }
>
> + if (!(binname = last_component(binary)) || binname[0] == '\0') {
> + virReportError(VIR_ERR_INTERNAL_ERROR,
> + _("Cannot determine basename for binary '%s'"),
> + binary);
> + goto error;
> + }
> +
> + if (virPidFileConstructPath(false, NULL, binname, &pidpath) < 0)
> + goto error;
> +
> + if ((pidfd = virPidFileAcquirePath(pidpath, false, getpid())) < 0) {
> + /*
> + * This can happen in a very rare case of two clients spawning two
> + * daemons at the same time, and the error in the logs that gets
> + * reset here can be a clue to some future debugging.
> + */
> + virResetLastError();
> + spawnDaemon = false;
> + goto retry;
> + }
> +
> if ((passfd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
> virReportSystemError(errno, "%s", _("Failed to create socket"));
> goto error;
> }
>
> /*
> - * We have to fork() here, because umask() is set
> - * per-process, chmod() is racy and fchmod() has undefined
> - * behaviour on sockets according to POSIX, so it doesn't
> - * work outside Linux.
> + * We already even acquired the pidfile, so noone else should be using
> + * @path right now. So we're OK to unlink it and paying attention to
> + * the return value makes no real sense here. Only if it's not an
> + * abstract socket, of course.
> + */
> + if (path[0] != '@')
> + unlink(path);
> +
> + /*
> + * We have to fork() here, because umask() is set per-process, chmod()
> + * is racy and fchmod() has undefined behaviour on sockets according to
> + * POSIX, so it doesn't work outside Linux.
> */
> if ((pid = virFork()) < 0)
> goto error;
> @@ -612,8 +646,9 @@ int virNetSocketNewConnectUNIX(const char *path,
> /*
> * OK, so the subprocces failed to bind() the socket. This may mean
> * that another daemon was starting at the same time and succeeded
> - * with its bind(). So we'll try connecting again, but this time
> - * without spawning the daemon.
> + * with its bind() (even though it should not happen because we
> + * using a pidfile for the race). So we'll try connecting again,
> + * but this time without spawning the daemon.
> */
> spawnDaemon = false;
> goto retry;
> @@ -632,6 +667,12 @@ int virNetSocketNewConnectUNIX(const char *path,
> goto error;
> }
>
> + /*
> + * Do we need to eliminate the super-rare race here any more? It would
> + * need incorporating the following VIR_FORCE_CLOSE() into a
> + * virCommandHook inside a virNetSocketForkDaemon().
> + */
> + VIR_FORCE_CLOSE(pidfd);
> if (virNetSocketForkDaemon(binary, passfd) < 0)
> goto error;
> }
> @@ -648,8 +689,12 @@ int virNetSocketNewConnectUNIX(const char *path,
> return 0;
>
> error:
> + if (pidfd > 0)
> + virPidFileDeletePath(pidpath);
> + VIR_FREE(pidpath);
> VIR_FORCE_CLOSE(fd);
> VIR_FORCE_CLOSE(passfd);
> + VIR_FORCE_CLOSE(pidfd);
> if (spawnDaemon)
> unlink(path);
> return -1;
>
Tested this, fixes the issue for me as well.
Patch looks fine AFAICT, matches similar code stanzas in daemon/libvirtd.c. So
ACK from me
- Cole
More information about the libvir-list
mailing list