]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
BUG/MINOR: epoll: correctly disable FD polling in fd_rem()
authorWilly Tarreau <w@1wt.eu>
Thu, 4 Oct 2012 19:54:41 +0000 (21:54 +0200)
committerWilly Tarreau <w@1wt.eu>
Thu, 4 Oct 2012 20:26:09 +0000 (22:26 +0200)
When calling fd_rem(), the polling was not correctly disabled because the
->prev state was set to zero instead of the previous value. fd_rem() is
very rarely used, only just before closing a socket.

The effect is that upon an error reported at the connection level, if the
task assigned to the connection was too slow to be woken up because of too
many other tasks in the run queue, the FD was still not disabled and caused
the connection handler to be called again with the same event until the task
was finally executed to close the fd.

This issue only affects the epoll poller, not the sepoll variant nor any of
the other ones.

It was already present in 1.4 and even 1.3 with the same almost unnoticeable
effects. The bug can in fact only be discovered during development where it
emphasizes other bugs.

It should be backported anyway.

src/ev_epoll.c

index a566917bac8855b07f6773667e21285e6091a111..90769c1ca8610d4f635aca387b475109d3f17979 100644 (file)
@@ -182,11 +182,15 @@ REGPRM2 static void __fd_clr(const int fd, int dir)
 REGPRM1 static void __fd_rem(int fd)
 {
        uint32_t ofs = FD2OFS(fd);
+       uint32_t old_evt;
 
-       if (unlikely(!((fd_evts[ofs] >> FD2BIT(fd)) & 3)))
+       old_evt = fd_evts[ofs] >> FD2BIT(fd);
+       old_evt &= 3;
+
+       if (unlikely(!old_evt))
                return;
 
-       alloc_chg_list(fd, 0);
+       alloc_chg_list(fd, old_evt);
        fd_evts[ofs] &= ~FD2MSK(fd);
 }