]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
journald: don't employ inner loop for reading from incoming sockets 150/head
authorLennart Poettering <lennart@poettering.net>
Wed, 10 Jun 2015 17:24:58 +0000 (19:24 +0200)
committerLennart Poettering <lennart@poettering.net>
Wed, 10 Jun 2015 18:09:10 +0000 (20:09 +0200)
Otherwise, if the socket is constantly busy we will never return to the
event loop, but we really need to to dispatch other (possibly more
high-priority) events too. Hence, return after dispatching one message
to the event handler, and rely on the event loop calling us back
right-away.

Fixes #125

src/journal/journald-server.c

index 32da8d61fcbe71529d4ddd2e639d5ca7799bbb0b..d0d670f36e85910267280a3e3164bb8040b9378b 100644 (file)
@@ -1104,6 +1104,42 @@ finish:
 
 int server_process_datagram(sd_event_source *es, int fd, uint32_t revents, void *userdata) {
         Server *s = userdata;
+        struct ucred *ucred = NULL;
+        struct timeval *tv = NULL;
+        struct cmsghdr *cmsg;
+        char *label = NULL;
+        size_t label_len = 0, m;
+        struct iovec iovec;
+        ssize_t n;
+        int *fds = NULL, v = 0;
+        unsigned n_fds = 0;
+
+        union {
+                struct cmsghdr cmsghdr;
+
+                /* We use NAME_MAX space for the SELinux label
+                 * here. The kernel currently enforces no
+                 * limit, but according to suggestions from
+                 * the SELinux people this will change and it
+                 * will probably be identical to NAME_MAX. For
+                 * now we use that, but this should be updated
+                 * one day when the final limit is known. */
+                uint8_t buf[CMSG_SPACE(sizeof(struct ucred)) +
+                            CMSG_SPACE(sizeof(struct timeval)) +
+                            CMSG_SPACE(sizeof(int)) + /* fd */
+                            CMSG_SPACE(NAME_MAX)]; /* selinux label */
+        } control = {};
+
+        union sockaddr_union sa = {};
+
+        struct msghdr msghdr = {
+                .msg_iov = &iovec,
+                .msg_iovlen = 1,
+                .msg_control = &control,
+                .msg_controllen = sizeof(control),
+                .msg_name = &sa,
+                .msg_namelen = sizeof(sa),
+        };
 
         assert(s);
         assert(fd == s->native_fd || fd == s->syslog_fd || fd == s->audit_fd);
@@ -1113,119 +1149,79 @@ int server_process_datagram(sd_event_source *es, int fd, uint32_t revents, void
                 return -EIO;
         }
 
-        for (;;) {
-                struct ucred *ucred = NULL;
-                struct timeval *tv = NULL;
-                struct cmsghdr *cmsg;
-                char *label = NULL;
-                size_t label_len = 0;
-                struct iovec iovec;
-
-                union {
-                        struct cmsghdr cmsghdr;
-
-                        /* We use NAME_MAX space for the SELinux label
-                         * here. The kernel currently enforces no
-                         * limit, but according to suggestions from
-                         * the SELinux people this will change and it
-                         * will probably be identical to NAME_MAX. For
-                         * now we use that, but this should be updated
-                         * one day when the final limit is known. */
-                        uint8_t buf[CMSG_SPACE(sizeof(struct ucred)) +
-                                    CMSG_SPACE(sizeof(struct timeval)) +
-                                    CMSG_SPACE(sizeof(int)) + /* fd */
-                                    CMSG_SPACE(NAME_MAX)]; /* selinux label */
-                } control = {};
-                union sockaddr_union sa = {};
-                struct msghdr msghdr = {
-                        .msg_iov = &iovec,
-                        .msg_iovlen = 1,
-                        .msg_control = &control,
-                        .msg_controllen = sizeof(control),
-                        .msg_name = &sa,
-                        .msg_namelen = sizeof(sa),
-                };
-
-                ssize_t n;
-                int *fds = NULL;
-                unsigned n_fds = 0;
-                int v = 0;
-                size_t m;
-
-                /* Try to get the right size, if we can. (Not all
-                 * sockets support SIOCINQ, hence we just try, but
-                 * don't rely on it. */
-                (void) ioctl(fd, SIOCINQ, &v);
-
-                /* Fix it up, if it is too small. We use the same fixed value as auditd here. Awful! */
-                m = PAGE_ALIGN(MAX3((size_t) v + 1,
-                                    (size_t) LINE_MAX,
-                                    ALIGN(sizeof(struct nlmsghdr)) + ALIGN((size_t) MAX_AUDIT_MESSAGE_LENGTH)) + 1);
-
-                if (!GREEDY_REALLOC(s->buffer, s->buffer_size, m))
-                        return log_oom();
-
-                iovec.iov_base = s->buffer;
-                iovec.iov_len = s->buffer_size - 1; /* Leave room for trailing NUL we add later */
-
-                n = recvmsg(fd, &msghdr, MSG_DONTWAIT|MSG_CMSG_CLOEXEC);
-                if (n < 0) {
-                        if (errno == EINTR || errno == EAGAIN)
-                                return 0;
-
-                        log_error_errno(errno, "recvmsg() failed: %m");
-                        return -errno;
-                }
+        /* Try to get the right size, if we can. (Not all
+         * sockets support SIOCINQ, hence we just try, but
+         * don't rely on it. */
+        (void) ioctl(fd, SIOCINQ, &v);
 
-                CMSG_FOREACH(cmsg, &msghdr) {
-
-                        if (cmsg->cmsg_level == SOL_SOCKET &&
-                            cmsg->cmsg_type == SCM_CREDENTIALS &&
-                            cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred)))
-                                ucred = (struct ucred*) CMSG_DATA(cmsg);
-                        else if (cmsg->cmsg_level == SOL_SOCKET &&
-                                 cmsg->cmsg_type == SCM_SECURITY) {
-                                label = (char*) CMSG_DATA(cmsg);
-                                label_len = cmsg->cmsg_len - CMSG_LEN(0);
-                        } else if (cmsg->cmsg_level == SOL_SOCKET &&
-                                   cmsg->cmsg_type == SO_TIMESTAMP &&
-                                   cmsg->cmsg_len == CMSG_LEN(sizeof(struct timeval)))
-                                tv = (struct timeval*) CMSG_DATA(cmsg);
-                        else if (cmsg->cmsg_level == SOL_SOCKET &&
-                                 cmsg->cmsg_type == SCM_RIGHTS) {
-                                fds = (int*) CMSG_DATA(cmsg);
-                                n_fds = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int);
-                        }
-                }
+        /* Fix it up, if it is too small. We use the same fixed value as auditd here. Awful! */
+        m = PAGE_ALIGN(MAX3((size_t) v + 1,
+                            (size_t) LINE_MAX,
+                            ALIGN(sizeof(struct nlmsghdr)) + ALIGN((size_t) MAX_AUDIT_MESSAGE_LENGTH)) + 1);
 
-                /* And a trailing NUL, just in case */
-                s->buffer[n] = 0;
+        if (!GREEDY_REALLOC(s->buffer, s->buffer_size, m))
+                return log_oom();
 
-                if (fd == s->syslog_fd) {
-                        if (n > 0 && n_fds == 0)
-                                server_process_syslog_message(s, strstrip(s->buffer), ucred, tv, label, label_len);
-                        else if (n_fds > 0)
-                                log_warning("Got file descriptors via syslog socket. Ignoring.");
+        iovec.iov_base = s->buffer;
+        iovec.iov_len = s->buffer_size - 1; /* Leave room for trailing NUL we add later */
 
-                } else if (fd == s->native_fd) {
-                        if (n > 0 && n_fds == 0)
-                                server_process_native_message(s, s->buffer, n, ucred, tv, label, label_len);
-                        else if (n == 0 && n_fds == 1)
-                                server_process_native_file(s, fds[0], ucred, tv, label, label_len);
-                        else if (n_fds > 0)
-                                log_warning("Got too many file descriptors via native socket. Ignoring.");
+        n = recvmsg(fd, &msghdr, MSG_DONTWAIT|MSG_CMSG_CLOEXEC);
+        if (n < 0) {
+                if (errno == EINTR || errno == EAGAIN)
+                        return 0;
 
-                } else {
-                        assert(fd == s->audit_fd);
+                return log_error_errno(errno, "recvmsg() failed: %m");
+        }
 
-                        if (n > 0 && n_fds == 0)
-                                server_process_audit_message(s, s->buffer, n, ucred, &sa, msghdr.msg_namelen);
-                        else if (n_fds > 0)
-                                log_warning("Got file descriptors via audit socket. Ignoring.");
+        CMSG_FOREACH(cmsg, &msghdr) {
+
+                if (cmsg->cmsg_level == SOL_SOCKET &&
+                    cmsg->cmsg_type == SCM_CREDENTIALS &&
+                    cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred)))
+                        ucred = (struct ucred*) CMSG_DATA(cmsg);
+                else if (cmsg->cmsg_level == SOL_SOCKET &&
+                         cmsg->cmsg_type == SCM_SECURITY) {
+                        label = (char*) CMSG_DATA(cmsg);
+                        label_len = cmsg->cmsg_len - CMSG_LEN(0);
+                } else if (cmsg->cmsg_level == SOL_SOCKET &&
+                           cmsg->cmsg_type == SO_TIMESTAMP &&
+                           cmsg->cmsg_len == CMSG_LEN(sizeof(struct timeval)))
+                        tv = (struct timeval*) CMSG_DATA(cmsg);
+                else if (cmsg->cmsg_level == SOL_SOCKET &&
+                         cmsg->cmsg_type == SCM_RIGHTS) {
+                        fds = (int*) CMSG_DATA(cmsg);
+                        n_fds = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int);
                 }
+        }
+
+        /* And a trailing NUL, just in case */
+        s->buffer[n] = 0;
+
+        if (fd == s->syslog_fd) {
+                if (n > 0 && n_fds == 0)
+                        server_process_syslog_message(s, strstrip(s->buffer), ucred, tv, label, label_len);
+                else if (n_fds > 0)
+                        log_warning("Got file descriptors via syslog socket. Ignoring.");
+
+        } else if (fd == s->native_fd) {
+                if (n > 0 && n_fds == 0)
+                        server_process_native_message(s, s->buffer, n, ucred, tv, label, label_len);
+                else if (n == 0 && n_fds == 1)
+                        server_process_native_file(s, fds[0], ucred, tv, label, label_len);
+                else if (n_fds > 0)
+                        log_warning("Got too many file descriptors via native socket. Ignoring.");
 
-                close_many(fds, n_fds);
+        } else {
+                assert(fd == s->audit_fd);
+
+                if (n > 0 && n_fds == 0)
+                        server_process_audit_message(s, s->buffer, n, ucred, &sa, msghdr.msg_namelen);
+                else if (n_fds > 0)
+                        log_warning("Got file descriptors via audit socket. Ignoring.");
         }
+
+        close_many(fds, n_fds);
+        return 0;
 }
 
 static int dispatch_sigusr1(sd_event_source *es, const struct signalfd_siginfo *si, void *userdata) {