]> git.tuebingen.mpg.de Git - paraslash.git/commitdiff
server: Fix race condition in afs startup.
authorAndre Noll <maan@tuebingen.mpg.de>
Tue, 23 Aug 2016 20:58:46 +0000 (22:58 +0200)
committerAndre Noll <maan@tuebingen.mpg.de>
Tue, 4 Oct 2016 10:21:15 +0000 (12:21 +0200)
After server_init() returns, the server accepts connections on the
TCP command socket. If an afs command arrives on the command socket,
the server process forks and the resulting child process (the command
handler) connects to the local afs socket. However, this socket is
created by the afs process which was forked from the server process
in server_init(). It is therefore possible that the command handler
connects before the afs process started to listen on the local afs
socket. In this case, the connection, hence the command fails.

This commit fixes the race condition by letting the parent process
block on read(2) on the afs socket. The afs process writes a byte
to the other end of the socket after it has completed its setup,
causing the parent process to resume.

For this to work, we need a connection-mode byte stream for the
communication between the server and the afs process, rather
than the connectionless datagram socket we have now. There is no
particular reason to prefer a datagram socket here, so let's switch
to SOCK_STREAM.

afs.c
server.c

diff --git a/afs.c b/afs.c
index 0accc45108f7c6ba0c2a3a89595d957d8a566920..071f657ce69c79812d29a982f69cc5c0bbf8f8b7 100644 (file)
--- a/afs.c
+++ b/afs.c
@@ -1024,6 +1024,13 @@ __noreturn void afs_init(uint32_t cookie, int socket_fd)
        register_command_task(cookie, &s);
        s.default_timeout.tv_sec = 0;
        s.default_timeout.tv_usec = 999 * 1000;
+       ret = write(socket_fd, "\0", 1);
+       if (ret != 1) {
+               if (ret == 0)
+                       errno = EINVAL;
+               ret = -ERRNO_TO_PARA_ERROR(errno);
+               goto out_close;
+       }
        ret = schedule(&s);
        sched_shutdown(&s);
 out_close:
index ae8848b6856732ae7d1d7fb034953f64b682aad1..ca71c4d8860e49224ffd0f2203ed76a7253a1a01 100644 (file)
--- a/server.c
+++ b/server.c
@@ -411,8 +411,9 @@ static int init_afs(int argc, char **argv)
 {
        int ret, afs_server_socket[2];
        pid_t afs_pid;
+       char c;
 
-       ret = socketpair(PF_UNIX, SOCK_DGRAM, 0, afs_server_socket);
+       ret = socketpair(PF_UNIX, SOCK_STREAM, 0, afs_server_socket);
        if (ret < 0)
                exit(EXIT_FAILURE);
        get_random_bytes_or_die((unsigned char *)&afs_socket_cookie,
@@ -422,6 +423,7 @@ static int init_afs(int argc, char **argv)
                exit(EXIT_FAILURE);
        if (afs_pid == 0) { /* child (afs) */
                int i;
+
                for (i = argc - 1; i >= 0; i--)
                        memset(argv[i], 0, strlen(argv[i]));
                sprintf(argv[0], "para_server (afs)");
@@ -430,6 +432,10 @@ static int init_afs(int argc, char **argv)
        }
        mmd->afs_pid = afs_pid;
        close(afs_server_socket[1]);
+       if (read(afs_server_socket[0], &c, 1) <= 0) {
+               PARA_EMERG_LOG("early afs exit\n");
+               exit(EXIT_FAILURE);
+       }
        ret = mark_fd_nonblocking(afs_server_socket[0]);
        if (ret < 0)
                exit(EXIT_FAILURE);