From 9cca8dfc0b96a2cbe35e789e2ff0b65aec78dbe6 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Mon, 15 Jul 2019 06:47:54 +0200 Subject: BUG/MINOR: mux-pt: do not pretend there's more data after a read0 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 | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/mux_pt.c b/src/mux_pt.c index 47d0634bd..323594f32 100644 --- a/src/mux_pt.c +++ b/src/mux_pt.c @@ -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; -- cgit v1.2.1