]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
BUG/MAJOR: stconn: Disable zero-copy forwarding if consumer is shut or in error
authorChristopher Faulet <cfaulet@haproxy.com>
Thu, 21 Dec 2023 09:27:53 +0000 (10:27 +0100)
committerChristopher Faulet <cfaulet@haproxy.com>
Thu, 21 Dec 2023 10:00:57 +0000 (11:00 +0100)
A regression was introduced by commit 2421c6fa7d ("BUG/MEDIUM: stconn: Block
zero-copy forwarding if EOS/ERROR on consumer side"). When zero-copy
forwarding is inuse and the consumer side is shut or in error, we declare it
as blocked and it is woken up. The idea is to handle this state at the
stream-connector level. However this definitly blocks receives on the
producer side. So if the mux is unable to close by itself, but instead wait
the peer to shut, this can lead to a wake up loop. And indeed, with the
passthrough multiplexer this may happen.

To fix the issue and prevent any loop, instead of blocking the zero-copy
forwarding, we now disable it. This way, the stream-connector on producer
side will fallback on classical receives and will be able to handle peer
shutdown properly. In addition, the wakeup of the consumer side was
removed. This will be handled, if necessary, by sc_notify().

This patch should fix the issue #2395. It must be backported to 2.9.

include/haproxy/stconn.h

index 9b5502a7df880bd0cca77b6195c11874122cf49c..afab784cae0dddbfd223b87d1f4f80056032a54b 100644 (file)
@@ -511,13 +511,9 @@ static inline size_t se_nego_ff(struct sedesc *se, struct buffer *input, size_t
 
                se->iobuf.flags &= ~IOBUF_FL_FF_BLOCKED;
                if (mux->nego_fastfwd && mux->done_fastfwd) {
-                       /* Declare SE as blocked if EOS or an error was reported.
-                        * This may happen if fast-forward was scheduled before the I/O processing on <SC>.
-                        * Wake <SC> up in this case.
-                        */
+                       /* Disable zero-copy forwarding if EOS or an error was reported. */
                        if (se_fl_test(se, SE_FL_EOS|SE_FL_ERROR|SE_FL_ERR_PENDING)) {
-                               se->iobuf.flags |= IOBUF_FL_FF_BLOCKED;
-                               tasklet_wakeup(se->sc->wait_event.tasklet);
+                               se->iobuf.flags |= IOBUF_FL_NO_FF;
                                goto end;
                        }