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