803fb7
From 6d1ef1fb841a0b3b4c53b560892f3570b3379dc9 Mon Sep 17 00:00:00 2001
803fb7
From: Lennart Poettering <lennart@poettering.net>
803fb7
Date: Wed, 10 Jun 2015 19:24:58 +0200
803fb7
Subject: [PATCH] journald: don't employ inner loop for reading from incoming
803fb7
 sockets
803fb7
803fb7
Otherwise, if the socket is constantly busy we will never return to the
803fb7
event loop, but we really need to to dispatch other (possibly more
803fb7
high-priority) events too. Hence, return after dispatching one message
803fb7
to the event handler, and rely on the event loop calling us back
803fb7
right-away.
803fb7
803fb7
Fixes #125
803fb7
803fb7
Related: #1318994
803fb7
Cherry-picked from: a315ac4e076c4ce7ce3e5c95792cf916d5e918c5
803fb7
---
803fb7
 src/journal/journald-server.c | 204 +++++++++++++++++++++---------------------
803fb7
 1 file changed, 100 insertions(+), 104 deletions(-)
803fb7
803fb7
diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c
803fb7
index 1eb1394d1..275224dc9 100644
803fb7
--- a/src/journal/journald-server.c
803fb7
+++ b/src/journal/journald-server.c
803fb7
@@ -1103,6 +1103,42 @@ finish:
803fb7
 
803fb7
 int server_process_datagram(sd_event_source *es, int fd, uint32_t revents, void *userdata) {
803fb7
         Server *s = userdata;
803fb7
+        struct ucred *ucred = NULL;
803fb7
+        struct timeval *tv = NULL;
803fb7
+        struct cmsghdr *cmsg;
803fb7
+        char *label = NULL;
803fb7
+        size_t label_len = 0, m;
803fb7
+        struct iovec iovec;
803fb7
+        ssize_t n;
803fb7
+        int *fds = NULL, v = 0;
803fb7
+        unsigned n_fds = 0;
803fb7
+
803fb7
+        union {
803fb7
+                struct cmsghdr cmsghdr;
803fb7
+
803fb7
+                /* We use NAME_MAX space for the SELinux label
803fb7
+                 * here. The kernel currently enforces no
803fb7
+                 * limit, but according to suggestions from
803fb7
+                 * the SELinux people this will change and it
803fb7
+                 * will probably be identical to NAME_MAX. For
803fb7
+                 * now we use that, but this should be updated
803fb7
+                 * one day when the final limit is known. */
803fb7
+                uint8_t buf[CMSG_SPACE(sizeof(struct ucred)) +
803fb7
+                            CMSG_SPACE(sizeof(struct timeval)) +
803fb7
+                            CMSG_SPACE(sizeof(int)) + /* fd */
803fb7
+                            CMSG_SPACE(NAME_MAX)]; /* selinux label */
803fb7
+        } control = {};
803fb7
+
803fb7
+        union sockaddr_union sa = {};
803fb7
+
803fb7
+        struct msghdr msghdr = {
803fb7
+                .msg_iov = &iovec,
803fb7
+                .msg_iovlen = 1,
803fb7
+                .msg_control = &control,
803fb7
+                .msg_controllen = sizeof(control),
803fb7
+                .msg_name = &sa,
803fb7
+                .msg_namelen = sizeof(sa),
803fb7
+        };
803fb7
 
803fb7
         assert(s);
803fb7
         assert(fd == s->native_fd || fd == s->syslog_fd || fd == s->audit_fd);
803fb7
@@ -1112,119 +1148,79 @@ int server_process_datagram(sd_event_source *es, int fd, uint32_t revents, void
803fb7
                 return -EIO;
803fb7
         }
803fb7
 
803fb7
-        for (;;) {
803fb7
-                struct ucred *ucred = NULL;
803fb7
-                struct timeval *tv = NULL;
803fb7
-                struct cmsghdr *cmsg;
803fb7
-                char *label = NULL;
803fb7
-                size_t label_len = 0;
803fb7
-                struct iovec iovec;
803fb7
-
803fb7
-                union {
803fb7
-                        struct cmsghdr cmsghdr;
803fb7
-
803fb7
-                        /* We use NAME_MAX space for the SELinux label
803fb7
-                         * here. The kernel currently enforces no
803fb7
-                         * limit, but according to suggestions from
803fb7
-                         * the SELinux people this will change and it
803fb7
-                         * will probably be identical to NAME_MAX. For
803fb7
-                         * now we use that, but this should be updated
803fb7
-                         * one day when the final limit is known. */
803fb7
-                        uint8_t buf[CMSG_SPACE(sizeof(struct ucred)) +
803fb7
-                                    CMSG_SPACE(sizeof(struct timeval)) +
803fb7
-                                    CMSG_SPACE(sizeof(int)) + /* fd */
803fb7
-                                    CMSG_SPACE(NAME_MAX)]; /* selinux label */
803fb7
-                } control = {};
803fb7
-                union sockaddr_union sa = {};
803fb7
-                struct msghdr msghdr = {
803fb7
-                        .msg_iov = &iovec,
803fb7
-                        .msg_iovlen = 1,
803fb7
-                        .msg_control = &control,
803fb7
-                        .msg_controllen = sizeof(control),
803fb7
-                        .msg_name = &sa,
803fb7
-                        .msg_namelen = sizeof(sa),
803fb7
-                };
803fb7
-
803fb7
-                ssize_t n;
803fb7
-                int *fds = NULL;
803fb7
-                unsigned n_fds = 0;
803fb7
-                int v = 0;
803fb7
-                size_t m;
803fb7
-
803fb7
-                /* Try to get the right size, if we can. (Not all
803fb7
-                 * sockets support SIOCINQ, hence we just try, but
803fb7
-                 * don't rely on it. */
803fb7
-                (void) ioctl(fd, SIOCINQ, &v);
803fb7
-
803fb7
-                /* Fix it up, if it is too small. We use the same fixed value as auditd here. Awful! */
803fb7
-                m = PAGE_ALIGN(MAX3((size_t) v + 1,
803fb7
-                                    (size_t) LINE_MAX,
803fb7
-                                    ALIGN(sizeof(struct nlmsghdr)) + ALIGN((size_t) MAX_AUDIT_MESSAGE_LENGTH)) + 1);
803fb7
-
803fb7
-                if (!GREEDY_REALLOC(s->buffer, s->buffer_size, m))
803fb7
-                        return log_oom();
803fb7
-
803fb7
-                iovec.iov_base = s->buffer;
803fb7
-                iovec.iov_len = s->buffer_size - 1; /* Leave room for trailing NUL we add later */
803fb7
-
803fb7
-                n = recvmsg(fd, &msghdr, MSG_DONTWAIT|MSG_CMSG_CLOEXEC);
803fb7
-                if (n < 0) {
803fb7
-                        if (errno == EINTR || errno == EAGAIN)
803fb7
-                                return 0;
803fb7
-
803fb7
-                        log_error_errno(errno, "recvmsg() failed: %m");
803fb7
-                        return -errno;
803fb7
-                }
803fb7
+        /* Try to get the right size, if we can. (Not all
803fb7
+         * sockets support SIOCINQ, hence we just try, but
803fb7
+         * don't rely on it. */
803fb7
+        (void) ioctl(fd, SIOCINQ, &v);
803fb7
 
803fb7
-                CMSG_FOREACH(cmsg, &msghdr) {
803fb7
-
803fb7
-                        if (cmsg->cmsg_level == SOL_SOCKET &&
803fb7
-                            cmsg->cmsg_type == SCM_CREDENTIALS &&
803fb7
-                            cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred)))
803fb7
-                                ucred = (struct ucred*) CMSG_DATA(cmsg);
803fb7
-                        else if (cmsg->cmsg_level == SOL_SOCKET &&
803fb7
-                                 cmsg->cmsg_type == SCM_SECURITY) {
803fb7
-                                label = (char*) CMSG_DATA(cmsg);
803fb7
-                                label_len = cmsg->cmsg_len - CMSG_LEN(0);
803fb7
-                        } else if (cmsg->cmsg_level == SOL_SOCKET &&
803fb7
-                                   cmsg->cmsg_type == SO_TIMESTAMP &&
803fb7
-                                   cmsg->cmsg_len == CMSG_LEN(sizeof(struct timeval)))
803fb7
-                                tv = (struct timeval*) CMSG_DATA(cmsg);
803fb7
-                        else if (cmsg->cmsg_level == SOL_SOCKET &&
803fb7
-                                 cmsg->cmsg_type == SCM_RIGHTS) {
803fb7
-                                fds = (int*) CMSG_DATA(cmsg);
803fb7
-                                n_fds = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int);
803fb7
-                        }
803fb7
-                }
803fb7
+        /* Fix it up, if it is too small. We use the same fixed value as auditd here. Awful! */
803fb7
+        m = PAGE_ALIGN(MAX3((size_t) v + 1,
803fb7
+                            (size_t) LINE_MAX,
803fb7
+                            ALIGN(sizeof(struct nlmsghdr)) + ALIGN((size_t) MAX_AUDIT_MESSAGE_LENGTH)) + 1);
803fb7
 
803fb7
-                /* And a trailing NUL, just in case */
803fb7
-                s->buffer[n] = 0;
803fb7
+        if (!GREEDY_REALLOC(s->buffer, s->buffer_size, m))
803fb7
+                return log_oom();
803fb7
 
803fb7
-                if (fd == s->syslog_fd) {
803fb7
-                        if (n > 0 && n_fds == 0)
803fb7
-                                server_process_syslog_message(s, strstrip(s->buffer), ucred, tv, label, label_len);
803fb7
-                        else if (n_fds > 0)
803fb7
-                                log_warning("Got file descriptors via syslog socket. Ignoring.");
803fb7
+        iovec.iov_base = s->buffer;
803fb7
+        iovec.iov_len = s->buffer_size - 1; /* Leave room for trailing NUL we add later */
803fb7
 
803fb7
-                } else if (fd == s->native_fd) {
803fb7
-                        if (n > 0 && n_fds == 0)
803fb7
-                                server_process_native_message(s, s->buffer, n, ucred, tv, label, label_len);
803fb7
-                        else if (n == 0 && n_fds == 1)
803fb7
-                                server_process_native_file(s, fds[0], ucred, tv, label, label_len);
803fb7
-                        else if (n_fds > 0)
803fb7
-                                log_warning("Got too many file descriptors via native socket. Ignoring.");
803fb7
+        n = recvmsg(fd, &msghdr, MSG_DONTWAIT|MSG_CMSG_CLOEXEC);
803fb7
+        if (n < 0) {
803fb7
+                if (errno == EINTR || errno == EAGAIN)
803fb7
+                        return 0;
803fb7
 
803fb7
-                } else {
803fb7
-                        assert(fd == s->audit_fd);
803fb7
+                return log_error_errno(errno, "recvmsg() failed: %m");
803fb7
+        }
803fb7
 
803fb7
-                        if (n > 0 && n_fds == 0)
803fb7
-                                server_process_audit_message(s, s->buffer, n, ucred, &sa, msghdr.msg_namelen);
803fb7
-                        else if (n_fds > 0)
803fb7
-                                log_warning("Got file descriptors via audit socket. Ignoring.");
803fb7
+        CMSG_FOREACH(cmsg, &msghdr) {
803fb7
+
803fb7
+                if (cmsg->cmsg_level == SOL_SOCKET &&
803fb7
+                    cmsg->cmsg_type == SCM_CREDENTIALS &&
803fb7
+                    cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred)))
803fb7
+                        ucred = (struct ucred*) CMSG_DATA(cmsg);
803fb7
+                else if (cmsg->cmsg_level == SOL_SOCKET &&
803fb7
+                         cmsg->cmsg_type == SCM_SECURITY) {
803fb7
+                        label = (char*) CMSG_DATA(cmsg);
803fb7
+                        label_len = cmsg->cmsg_len - CMSG_LEN(0);
803fb7
+                } else if (cmsg->cmsg_level == SOL_SOCKET &&
803fb7
+                           cmsg->cmsg_type == SO_TIMESTAMP &&
803fb7
+                           cmsg->cmsg_len == CMSG_LEN(sizeof(struct timeval)))
803fb7
+                        tv = (struct timeval*) CMSG_DATA(cmsg);
803fb7
+                else if (cmsg->cmsg_level == SOL_SOCKET &&
803fb7
+                         cmsg->cmsg_type == SCM_RIGHTS) {
803fb7
+                        fds = (int*) CMSG_DATA(cmsg);
803fb7
+                        n_fds = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int);
803fb7
                 }
803fb7
+        }
803fb7
+
803fb7
+        /* And a trailing NUL, just in case */
803fb7
+        s->buffer[n] = 0;
803fb7
+
803fb7
+        if (fd == s->syslog_fd) {
803fb7
+                if (n > 0 && n_fds == 0)
803fb7
+                        server_process_syslog_message(s, strstrip(s->buffer), ucred, tv, label, label_len);
803fb7
+                else if (n_fds > 0)
803fb7
+                        log_warning("Got file descriptors via syslog socket. Ignoring.");
803fb7
+
803fb7
+        } else if (fd == s->native_fd) {
803fb7
+                if (n > 0 && n_fds == 0)
803fb7
+                        server_process_native_message(s, s->buffer, n, ucred, tv, label, label_len);
803fb7
+                else if (n == 0 && n_fds == 1)
803fb7
+                        server_process_native_file(s, fds[0], ucred, tv, label, label_len);
803fb7
+                else if (n_fds > 0)
803fb7
+                        log_warning("Got too many file descriptors via native socket. Ignoring.");
803fb7
 
803fb7
-                close_many(fds, n_fds);
803fb7
+        } else {
803fb7
+                assert(fd == s->audit_fd);
803fb7
+
803fb7
+                if (n > 0 && n_fds == 0)
803fb7
+                        server_process_audit_message(s, s->buffer, n, ucred, &sa, msghdr.msg_namelen);
803fb7
+                else if (n_fds > 0)
803fb7
+                        log_warning("Got file descriptors via audit socket. Ignoring.");
803fb7
         }
803fb7
+
803fb7
+        close_many(fds, n_fds);
803fb7
+        return 0;
803fb7
 }
803fb7
 
803fb7
 static int dispatch_sigusr1(sd_event_source *es, const struct signalfd_siginfo *si, void *userdata) {