|
|
9119d9 |
From 31f55c6f1cbe6ed6ac9891ea47c3823ed18f1921 Mon Sep 17 00:00:00 2001
|
|
|
9119d9 |
Message-Id: <31f55c6f1cbe6ed6ac9891ea47c3823ed18f1921@dist-git>
|
|
|
9119d9 |
From: Martin Kletzander <mkletzan@redhat.com>
|
|
|
9119d9 |
Date: Wed, 17 Sep 2014 17:11:04 +0200
|
|
|
9119d9 |
Subject: [PATCH] rpc: make daemon spawning a bit more intelligent
|
|
|
9119d9 |
|
|
|
9119d9 |
This way it behaves more like the daemon itself does (acquiring a
|
|
|
9119d9 |
pidfile, deleting the socket before binding, etc.).
|
|
|
9119d9 |
|
|
|
9119d9 |
Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=927369
|
|
|
9119d9 |
Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1138604
|
|
|
9119d9 |
|
|
|
9119d9 |
Signed-off-by: Martin Kletzander <mkletzan@redhat.com>
|
|
|
9119d9 |
(cherry picked from commit bd9ad91a4036649645fffb1598213339263478de)
|
|
|
9119d9 |
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
|
|
|
9119d9 |
---
|
|
|
9119d9 |
src/rpc/virnetsocket.c | 67 ++++++++++++++++++++++++++++++++++++++++++++------
|
|
|
9119d9 |
1 file changed, 59 insertions(+), 8 deletions(-)
|
|
|
9119d9 |
|
|
|
9119d9 |
diff --git a/src/rpc/virnetsocket.c b/src/rpc/virnetsocket.c
|
|
|
9119d9 |
index 306c9ea..5feccf6 100644
|
|
|
9119d9 |
--- a/src/rpc/virnetsocket.c
|
|
|
9119d9 |
+++ b/src/rpc/virnetsocket.c
|
|
|
9119d9 |
@@ -51,9 +51,11 @@
|
|
|
9119d9 |
#include "virlog.h"
|
|
|
9119d9 |
#include "virfile.h"
|
|
|
9119d9 |
#include "virthread.h"
|
|
|
9119d9 |
+#include "virpidfile.h"
|
|
|
9119d9 |
#include "virprobe.h"
|
|
|
9119d9 |
#include "virprocess.h"
|
|
|
9119d9 |
#include "virstring.h"
|
|
|
9119d9 |
+#include "dirname.h"
|
|
|
9119d9 |
#include "passfd.h"
|
|
|
9119d9 |
|
|
|
9119d9 |
#if WITH_SSH2
|
|
|
9119d9 |
@@ -544,7 +546,10 @@ int virNetSocketNewConnectUNIX(const char *path,
|
|
|
9119d9 |
const char *binary,
|
|
|
9119d9 |
virNetSocketPtr *retsock)
|
|
|
9119d9 |
{
|
|
|
9119d9 |
+ char *binname = NULL;
|
|
|
9119d9 |
+ char *pidpath = NULL;
|
|
|
9119d9 |
int fd, passfd = -1;
|
|
|
9119d9 |
+ int pidfd = -1;
|
|
|
9119d9 |
virSocketAddr localAddr;
|
|
|
9119d9 |
virSocketAddr remoteAddr;
|
|
|
9119d9 |
|
|
|
9119d9 |
@@ -583,16 +588,46 @@ int virNetSocketNewConnectUNIX(const char *path,
|
|
|
9119d9 |
goto error;
|
|
|
9119d9 |
}
|
|
|
9119d9 |
|
|
|
9119d9 |
+ if (!(binname = last_component(binary)) || binname[0] == '\0') {
|
|
|
9119d9 |
+ virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
9119d9 |
+ _("Cannot determine basename for binary '%s'"),
|
|
|
9119d9 |
+ binary);
|
|
|
9119d9 |
+ goto error;
|
|
|
9119d9 |
+ }
|
|
|
9119d9 |
+
|
|
|
9119d9 |
+ if (virPidFileConstructPath(false, NULL, binname, &pidpath) < 0)
|
|
|
9119d9 |
+ goto error;
|
|
|
9119d9 |
+
|
|
|
9119d9 |
+ pidfd = virPidFileAcquirePath(pidpath, false, getpid());
|
|
|
9119d9 |
+ if (pidfd < 0) {
|
|
|
9119d9 |
+ /*
|
|
|
9119d9 |
+ * This can happen in a very rare case of two clients spawning two
|
|
|
9119d9 |
+ * daemons at the same time, and the error in the logs that gets
|
|
|
9119d9 |
+ * reset here can be a clue to some future debugging.
|
|
|
9119d9 |
+ */
|
|
|
9119d9 |
+ virResetLastError();
|
|
|
9119d9 |
+ spawnDaemon = false;
|
|
|
9119d9 |
+ goto retry;
|
|
|
9119d9 |
+ }
|
|
|
9119d9 |
+
|
|
|
9119d9 |
if ((passfd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
|
|
|
9119d9 |
virReportSystemError(errno, "%s", _("Failed to create socket"));
|
|
|
9119d9 |
goto error;
|
|
|
9119d9 |
}
|
|
|
9119d9 |
|
|
|
9119d9 |
/*
|
|
|
9119d9 |
- * We have to fork() here, because umask() is set
|
|
|
9119d9 |
- * per-process, chmod() is racy and fchmod() has undefined
|
|
|
9119d9 |
- * behaviour on sockets according to POSIX, so it doesn't
|
|
|
9119d9 |
- * work outside Linux.
|
|
|
9119d9 |
+ * We already even acquired the pidfile, so no one else should be using
|
|
|
9119d9 |
+ * @path right now. So we're OK to unlink it and paying attention to
|
|
|
9119d9 |
+ * the return value makes no real sense here. Only if it's not an
|
|
|
9119d9 |
+ * abstract socket, of course.
|
|
|
9119d9 |
+ */
|
|
|
9119d9 |
+ if (path[0] != '@')
|
|
|
9119d9 |
+ unlink(path);
|
|
|
9119d9 |
+
|
|
|
9119d9 |
+ /*
|
|
|
9119d9 |
+ * We have to fork() here, because umask() is set per-process, chmod()
|
|
|
9119d9 |
+ * is racy and fchmod() has undefined behaviour on sockets according to
|
|
|
9119d9 |
+ * POSIX, so it doesn't work outside Linux.
|
|
|
9119d9 |
*/
|
|
|
9119d9 |
if ((pid = virFork()) < 0)
|
|
|
9119d9 |
goto error;
|
|
|
9119d9 |
@@ -610,12 +645,16 @@ int virNetSocketNewConnectUNIX(const char *path,
|
|
|
9119d9 |
|
|
|
9119d9 |
if (status != EXIT_SUCCESS) {
|
|
|
9119d9 |
/*
|
|
|
9119d9 |
- * OK, so the subprocces failed to bind() the socket. This may mean
|
|
|
9119d9 |
- * that another daemon was starting at the same time and succeeded
|
|
|
9119d9 |
- * with its bind(). So we'll try connecting again, but this time
|
|
|
9119d9 |
- * without spawning the daemon.
|
|
|
9119d9 |
+ * OK, so the child failed to bind() the socket. This may mean that
|
|
|
9119d9 |
+ * another daemon was starting at the same time and succeeded with
|
|
|
9119d9 |
+ * its bind() (even though it should not happen because we using a
|
|
|
9119d9 |
+ * pidfile for the race). So we'll try connecting again, but this
|
|
|
9119d9 |
+ * time without spawning the daemon.
|
|
|
9119d9 |
*/
|
|
|
9119d9 |
spawnDaemon = false;
|
|
|
9119d9 |
+ virPidFileDeletePath(pidpath);
|
|
|
9119d9 |
+ VIR_FORCE_CLOSE(pidfd);
|
|
|
9119d9 |
+ VIR_FORCE_CLOSE(passfd);
|
|
|
9119d9 |
goto retry;
|
|
|
9119d9 |
}
|
|
|
9119d9 |
|
|
|
9119d9 |
@@ -632,6 +671,12 @@ int virNetSocketNewConnectUNIX(const char *path,
|
|
|
9119d9 |
goto error;
|
|
|
9119d9 |
}
|
|
|
9119d9 |
|
|
|
9119d9 |
+ /*
|
|
|
9119d9 |
+ * Do we need to eliminate the super-rare race here any more? It would
|
|
|
9119d9 |
+ * need incorporating the following VIR_FORCE_CLOSE() into a
|
|
|
9119d9 |
+ * virCommandHook inside a virNetSocketForkDaemon().
|
|
|
9119d9 |
+ */
|
|
|
9119d9 |
+ VIR_FORCE_CLOSE(pidfd);
|
|
|
9119d9 |
if (virNetSocketForkDaemon(binary, passfd) < 0)
|
|
|
9119d9 |
goto error;
|
|
|
9119d9 |
}
|
|
|
9119d9 |
@@ -645,11 +690,17 @@ int virNetSocketNewConnectUNIX(const char *path,
|
|
|
9119d9 |
if (!(*retsock = virNetSocketNew(&localAddr, &remoteAddr, true, fd, -1, 0)))
|
|
|
9119d9 |
goto error;
|
|
|
9119d9 |
|
|
|
9119d9 |
+ VIR_FREE(pidpath);
|
|
|
9119d9 |
+
|
|
|
9119d9 |
return 0;
|
|
|
9119d9 |
|
|
|
9119d9 |
error:
|
|
|
9119d9 |
+ if (pidfd >= 0)
|
|
|
9119d9 |
+ virPidFileDeletePath(pidpath);
|
|
|
9119d9 |
+ VIR_FREE(pidpath);
|
|
|
9119d9 |
VIR_FORCE_CLOSE(fd);
|
|
|
9119d9 |
VIR_FORCE_CLOSE(passfd);
|
|
|
9119d9 |
+ VIR_FORCE_CLOSE(pidfd);
|
|
|
9119d9 |
if (spawnDaemon)
|
|
|
9119d9 |
unlink(path);
|
|
|
9119d9 |
return -1;
|
|
|
9119d9 |
--
|
|
|
9119d9 |
2.1.0
|
|
|
9119d9 |
|