]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
BUG/MINOR: mux-pt: do not pretend there's more data after a read0
authorWilly Tarreau <w@1wt.eu>
Mon, 15 Jul 2019 04:47:54 +0000 (06:47 +0200)
committerWilly Tarreau <w@1wt.eu>
Mon, 15 Jul 2019 04:47:54 +0000 (06:47 +0200)
Commit 8706c8131 ("BUG/MEDIUM: mux_pt: Always set CS_FL_RCV_MORE.")
was a bit excessive in setting this flag, it refrained from removing
it after read0 unless it was on an empty call. The problem it causes
is that read0 is thus ignored on the first call :

  $ strace -tts200 -e trace=recvfrom,epoll_wait,sendto  ./haproxy -db -f tcp.cfg
  06:34:23.956897 recvfrom(9, "blah\n", 15360, 0, NULL, NULL) = 5
  06:34:23.956938 recvfrom(9, "", 15355, 0, NULL, NULL) = 0
  06:34:23.956958 recvfrom(9, "", 15355, 0, NULL, NULL) = 0
  06:34:23.957033 sendto(8, "blah\n", 5, MSG_DONTWAIT|MSG_NOSIGNAL, NULL, 0) = 5
  06:34:23.957229 epoll_wait(3, [{EPOLLIN|EPOLLHUP|EPOLLRDHUP, {u32=8, u64=8}}], 200, 0) = 1
  06:34:23.957297 recvfrom(8, "", 15360, 0, NULL, NULL) = 0

If CO_FL_SOCK_RD_SH is reported by the transport layer, it indicates the
read0 was already seen thus we must not try again and we must immedaitely
report it. The simple fix consists in removing the test on ret==0 :

  $ strace -tts200 -e trace=recvfrom,epoll_wait,sendto  ./haproxy -db -f tcp.cfg
  06:44:21.634835 recvfrom(9, "blah\n", 15360, 0, NULL, NULL) = 5
  06:44:21.635020 recvfrom(9, "", 15355, 0, NULL, NULL) = 0
  06:44:21.635056 sendto(8, "blah\n", 5, MSG_DONTWAIT|MSG_NOSIGNAL, NULL, 0) = 5
  06:44:21.635269 epoll_wait(3, [{EPOLLIN|EPOLLHUP|EPOLLRDHUP, {u32=8, u64=8}}], 200, 0) = 1
  06:44:21.635330 recvfrom(8, "", 15360, 0, NULL, NULL) = 0

The issue is minor, it only results in extra syscalls and CPU usage.
This fix should be backported to 2.0 and 1.9.

src/mux_pt.c

index 47d0634bd85b6df5f681e6569b6a6fa13bf78447..323594f32db24b19bbf9fd9a46ef5fe1d30fc259 100644 (file)
@@ -260,13 +260,11 @@ static size_t mux_pt_rcv_buf(struct conn_stream *cs, struct buffer *buf, size_t
        b_realign_if_empty(buf);
        ret = cs->conn->xprt->rcv_buf(cs->conn, cs->conn->xprt_ctx, buf, count, flags);
        if (conn_xprt_read0_pending(cs->conn)) {
-               if (ret == 0)
-                       cs->flags &= ~(CS_FL_RCV_MORE | CS_FL_WANT_ROOM);
+               cs->flags &= ~(CS_FL_RCV_MORE | CS_FL_WANT_ROOM);
                cs->flags |= CS_FL_EOS;
        }
        if (cs->conn->flags & CO_FL_ERROR) {
-               if (ret == 0)
-                       cs->flags &= ~(CS_FL_RCV_MORE | CS_FL_WANT_ROOM);
+               cs->flags &= ~(CS_FL_RCV_MORE | CS_FL_WANT_ROOM);
                cs->flags |= CS_FL_ERROR;
        }
        return ret;