From 9fab7bedfb1cdbd9bf390bdcc0a1d043c0bcc0b0 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Tue, 5 Sep 2017 15:32:56 +0200 Subject: [PATCH] BUG/MEDIUM: epoll: ensure we always consider HUP and ERR Since commit 5be2f35 ("MAJOR: polling: centralize calls to I/O callbacks") that came into 1.6-dev1, each poller deals with its own events and decides to signal ability to receive or send on a file descriptor based on the active events on the file descriptor. The commit above was incorrectly done for the epoll code. Instead of checking the active events on the fd, it checks for the new events. In general these ones are the same for POLL_IN and POLL_OUT since they are always cleared prior to being computed, but it is possible that POLL_HUP and POLL_ERR were initially reported and are not reported again (especially for HUP). This could happen for example if POLL_HUP and POLL_IN were received together, the pending data exactly correspond to a full buffer which is read at once, preventing the POLL_HUP from being dealt with in the same call, and on the next call only POLL_OUT is reported (eg: to emit some response or peers protocol ACKs). In this case fd_may_recv() will not be enabled anymore and the close event will be missed. It seems quite hard to trigger this case, though it might explain some of the rare missed close events that were detected in the past on the peers. This fix needs to be backported to 1.6 and 1.7. --- src/ev_epoll.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ev_epoll.c b/src/ev_epoll.c index eb2bceb03..a2e5e0a60 100644 --- a/src/ev_epoll.c +++ b/src/ev_epoll.c @@ -160,10 +160,10 @@ REGPRM2 static void _do_poll(struct poller *p, int exp) } fdtab[fd].ev |= n; - if (n & (FD_POLL_IN | FD_POLL_HUP | FD_POLL_ERR)) + if (fdtab[fd].ev & (FD_POLL_IN | FD_POLL_HUP | FD_POLL_ERR)) fd_may_recv(fd); - if (n & (FD_POLL_OUT | FD_POLL_ERR)) + if (fdtab[fd].ev & (FD_POLL_OUT | FD_POLL_ERR)) fd_may_send(fd); } /* the caller will take care of cached events */