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.
This commit is contained in:
Willy Tarreau 2017-09-05 15:32:56 +02:00
parent 52a91d3d48
commit 9fab7bedfb
1 changed files with 2 additions and 2 deletions

View File

@ -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 */