803fb7
From 64e21697bdefe0a37edc8557fd110daea2667771 Mon Sep 17 00:00:00 2001
803fb7
From: David Herrmann <dh.herrmann@gmail.com>
803fb7
Date: Wed, 28 Oct 2015 19:11:36 +0100
803fb7
Subject: [PATCH] core: fix priority ordering in notify-handling
803fb7
803fb7
Currently, we dispatch NOTIFY messages in a tight loop. Regardless how
803fb7
much data is incoming, we always dispatch everything that is queued.
803fb7
This, however, completely breaks priority event-handling of sd-event.
803fb7
When dispatching one NOTIFY event, another completely different event
803fb7
might fire, or might be queued by the NOTIFY handling. However, this
803fb7
event will not get dispatched until all other further NOTIFY messages are
803fb7
handled. Those might even arrive _after_ the other event fired, and as
803fb7
such completely break priority ordering of sd-event (which several code
803fb7
paths rely on).
803fb7
803fb7
Break this by never dispatching multiple messages. Just return after each
803fb7
message that was read and let sd-event handle everything else.
803fb7
803fb7
(The patch looks scarier that it is. It basically just drops the for(;;)
803fb7
 loop and re-indents the loop-content.)
803fb7
803fb7
(cherry picked from commit b215b0ede11c0dda90009c8412609d2416150075)
803fb7
Related: #1267707
803fb7
---
803fb7
 src/core/manager.c | 158 ++++++++++++++++++++++++++---------------------------
803fb7
 1 file changed, 78 insertions(+), 80 deletions(-)
803fb7
803fb7
diff --git a/src/core/manager.c b/src/core/manager.c
803fb7
index 5da836593..c5021993e 100644
803fb7
--- a/src/core/manager.c
803fb7
+++ b/src/core/manager.c
803fb7
@@ -1635,9 +1635,33 @@ static void manager_invoke_notify_message(Manager *m, Unit *u, pid_t pid, char *
803fb7
 }
803fb7
 
803fb7
 static int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
803fb7
+        _cleanup_fdset_free_ FDSet *fds = NULL;
803fb7
         Manager *m = userdata;
803fb7
+
803fb7
+        char buf[NOTIFY_BUFFER_MAX+1];
803fb7
+        struct iovec iovec = {
803fb7
+                .iov_base = buf,
803fb7
+                .iov_len = sizeof(buf)-1,
803fb7
+        };
803fb7
+        union {
803fb7
+                struct cmsghdr cmsghdr;
803fb7
+                uint8_t buf[CMSG_SPACE(sizeof(struct ucred)) +
803fb7
+                            CMSG_SPACE(sizeof(int) * NOTIFY_FD_MAX)];
803fb7
+        } control = {};
803fb7
+        struct msghdr msghdr = {
803fb7
+                .msg_iov = &iovec,
803fb7
+                .msg_iovlen = 1,
803fb7
+                .msg_control = &control,
803fb7
+                .msg_controllen = sizeof(control),
803fb7
+        };
803fb7
+
803fb7
+        struct cmsghdr *cmsg;
803fb7
+        struct ucred *ucred = NULL;
803fb7
+        bool found = false;
803fb7
+        Unit *u1, *u2, *u3;
803fb7
+        int r, *fd_array = NULL;
803fb7
+        unsigned n_fds = 0;
803fb7
         ssize_t n;
803fb7
-        int r;
803fb7
 
803fb7
         assert(m);
803fb7
         assert(m->notify_fd == fd);
803fb7
@@ -1647,108 +1671,82 @@ static int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t
803fb7
                 return 0;
803fb7
         }
803fb7
 
803fb7
-        for (;;) {
803fb7
-                _cleanup_fdset_free_ FDSet *fds = NULL;
803fb7
-                char buf[NOTIFY_BUFFER_MAX+1];
803fb7
-                struct iovec iovec = {
803fb7
-                        .iov_base = buf,
803fb7
-                        .iov_len = sizeof(buf)-1,
803fb7
-                };
803fb7
-                union {
803fb7
-                        struct cmsghdr cmsghdr;
803fb7
-                        uint8_t buf[CMSG_SPACE(sizeof(struct ucred)) +
803fb7
-                                    CMSG_SPACE(sizeof(int) * NOTIFY_FD_MAX)];
803fb7
-                } control = {};
803fb7
-                struct msghdr msghdr = {
803fb7
-                        .msg_iov = &iovec,
803fb7
-                        .msg_iovlen = 1,
803fb7
-                        .msg_control = &control,
803fb7
-                        .msg_controllen = sizeof(control),
803fb7
-                };
803fb7
-                struct cmsghdr *cmsg;
803fb7
-                struct ucred *ucred = NULL;
803fb7
-                bool found = false;
803fb7
-                Unit *u1, *u2, *u3;
803fb7
-                int *fd_array = NULL;
803fb7
-                unsigned n_fds = 0;
803fb7
-
803fb7
-                n = recvmsg(m->notify_fd, &msghdr, MSG_DONTWAIT|MSG_CMSG_CLOEXEC);
803fb7
-                if (n < 0) {
803fb7
-                        if (errno == EAGAIN || errno == EINTR)
803fb7
-                                break;
803fb7
+        n = recvmsg(m->notify_fd, &msghdr, MSG_DONTWAIT|MSG_CMSG_CLOEXEC);
803fb7
+        if (n < 0) {
803fb7
+                if (errno == EAGAIN || errno == EINTR)
803fb7
+                        return 0;
803fb7
 
803fb7
-                        return -errno;
803fb7
-                }
803fb7
+                return -errno;
803fb7
+        }
803fb7
 
803fb7
-                for (cmsg = CMSG_FIRSTHDR(&msghdr); cmsg; cmsg = CMSG_NXTHDR(&msghdr, cmsg)) {
803fb7
-                        if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
803fb7
+        for (cmsg = CMSG_FIRSTHDR(&msghdr); cmsg; cmsg = CMSG_NXTHDR(&msghdr, cmsg)) {
803fb7
+                if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
803fb7
 
803fb7
-                                fd_array = (int*) CMSG_DATA(cmsg);
803fb7
-                                n_fds = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int);
803fb7
+                        fd_array = (int*) CMSG_DATA(cmsg);
803fb7
+                        n_fds = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int);
803fb7
 
803fb7
-                        } else if (cmsg->cmsg_level == SOL_SOCKET &&
803fb7
-                                   cmsg->cmsg_type == SCM_CREDENTIALS &&
803fb7
-                                   cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred))) {
803fb7
+                } else if (cmsg->cmsg_level == SOL_SOCKET &&
803fb7
+                           cmsg->cmsg_type == SCM_CREDENTIALS &&
803fb7
+                           cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred))) {
803fb7
 
803fb7
-                                ucred = (struct ucred*) CMSG_DATA(cmsg);
803fb7
-                        }
803fb7
+                        ucred = (struct ucred*) CMSG_DATA(cmsg);
803fb7
                 }
803fb7
+        }
803fb7
 
803fb7
-                if (n_fds > 0) {
803fb7
-                        assert(fd_array);
803fb7
+        if (n_fds > 0) {
803fb7
+                assert(fd_array);
803fb7
 
803fb7
-                        r = fdset_new_array(&fds, fd_array, n_fds);
803fb7
-                        if (r < 0) {
803fb7
-                                close_many(fd_array, n_fds);
803fb7
-                                return log_oom();
803fb7
-                        }
803fb7
+                r = fdset_new_array(&fds, fd_array, n_fds);
803fb7
+                if (r < 0) {
803fb7
+                        close_many(fd_array, n_fds);
803fb7
+                        return log_oom();
803fb7
                 }
803fb7
+        }
803fb7
 
803fb7
-                if (!ucred || ucred->pid <= 0) {
803fb7
-                        log_warning("Received notify message without valid credentials. Ignoring.");
803fb7
-                        continue;
803fb7
-                }
803fb7
+        if (!ucred || ucred->pid <= 0) {
803fb7
+                log_warning("Received notify message without valid credentials. Ignoring.");
803fb7
+                return 0;
803fb7
+        }
803fb7
 
803fb7
-                if ((size_t) n >= sizeof(buf)) {
803fb7
-                        log_warning("Received notify message exceeded maximum size. Ignoring.");
803fb7
-                        continue;
803fb7
-                }
803fb7
+        if ((size_t) n >= sizeof(buf)) {
803fb7
+                log_warning("Received notify message exceeded maximum size. Ignoring.");
803fb7
+                return 0;
803fb7
+        }
803fb7
 
803fb7
-                buf[n] = 0;
803fb7
+        buf[n] = 0;
803fb7
 
803fb7
-                /* Notify every unit that might be interested, but try
803fb7
-                 * to avoid notifying the same one multiple times. */
803fb7
-                u1 = manager_get_unit_by_pid(m, ucred->pid);
803fb7
-                if (u1) {
803fb7
-                        manager_invoke_notify_message(m, u1, ucred->pid, buf, n, fds);
803fb7
-                        found = true;
803fb7
-                }
803fb7
+        /* Notify every unit that might be interested, but try
803fb7
+         * to avoid notifying the same one multiple times. */
803fb7
+        u1 = manager_get_unit_by_pid(m, ucred->pid);
803fb7
+        if (u1) {
803fb7
+                manager_invoke_notify_message(m, u1, ucred->pid, buf, n, fds);
803fb7
+                found = true;
803fb7
+        }
803fb7
 
803fb7
-                u2 = hashmap_get(m->watch_pids1, LONG_TO_PTR(ucred->pid));
803fb7
-                if (u2 && u2 != u1) {
803fb7
-                        manager_invoke_notify_message(m, u2, ucred->pid, buf, n, fds);
803fb7
-                        found = true;
803fb7
-                }
803fb7
+        u2 = hashmap_get(m->watch_pids1, LONG_TO_PTR(ucred->pid));
803fb7
+        if (u2 && u2 != u1) {
803fb7
+                manager_invoke_notify_message(m, u2, ucred->pid, buf, n, fds);
803fb7
+                found = true;
803fb7
+        }
803fb7
 
803fb7
-                u3 = hashmap_get(m->watch_pids2, LONG_TO_PTR(ucred->pid));
803fb7
-                if (u3 && u3 != u2 && u3 != u1) {
803fb7
-                        manager_invoke_notify_message(m, u3, ucred->pid, buf, n, fds);
803fb7
-                        found = true;
803fb7
-                }
803fb7
+        u3 = hashmap_get(m->watch_pids2, LONG_TO_PTR(ucred->pid));
803fb7
+        if (u3 && u3 != u2 && u3 != u1) {
803fb7
+                manager_invoke_notify_message(m, u3, ucred->pid, buf, n, fds);
803fb7
+                found = true;
803fb7
+        }
803fb7
 
803fb7
-                if (!found)
803fb7
-                        log_warning("Cannot find unit for notify message of PID "PID_FMT".", ucred->pid);
803fb7
+        if (!found)
803fb7
+                log_warning("Cannot find unit for notify message of PID "PID_FMT".", ucred->pid);
803fb7
 
803fb7
-                if (fdset_size(fds) > 0)
803fb7
-                        log_warning("Got auxiliary fds with notification message, closing all.");
803fb7
-        }
803fb7
+        if (fdset_size(fds) > 0)
803fb7
+                log_warning("Got auxiliary fds with notification message, closing all.");
803fb7
 
803fb7
         return 0;
803fb7
 }
803fb7
 
803fb7
 static void invoke_sigchld_event(Manager *m, Unit *u, siginfo_t *si) {
803fb7
         uint64_t iteration;
803fb7
-        
803fb7
+
803fb7
         assert(m);
803fb7
         assert(u);
803fb7
         assert(si);