]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
BUG/MAJOR: stream: Force channel analysis on successful synchronous send
authorChristopher Faulet <cfaulet@haproxy.com>
Thu, 11 Sep 2025 07:38:41 +0000 (09:38 +0200)
committerChristopher Faulet <cfaulet@haproxy.com>
Thu, 11 Sep 2025 07:47:47 +0000 (09:47 +0200)
This patchs reverts commit a498e527b ("BUG/MAJOR: stream: Remove READ/WRITE
events on channels after analysers eval") because of a regression. It was an
attempt to properly detect synchronous sends, even when the stream was woken
up on a write event. However, the fix was wrong because it could mask
shutdowns performed during process_stream() and block the stream.

Indeed, when a shutdown is performed, because an error occurred for
instance, a write event is reported. The commit above could mask this event
while the shutdown prevent any synchronous sends. In such case, the stream
could remain blocked infinitly because an I/O event was missed.

So to properly fix the original issue (#3070), the write event must not be
masked before a synchronous send. Instead, we now force the channel analysis
by setting explicitly CF_WAKE_ONCE flags on the corresponding channel if a
write event is reported after the synchronous send. CF_WRITE_EVENT flag is
remove explicitly just before, so it is quite easy to detect.

This patch must be backport to all stable version in same time of the commit
above.

src/stconn.c
src/stream.c

index 430f2d4e1e5f22cb35d3cc167724623554710926..f9eda533fc33730c2bee94148ceca1463040af98 100644 (file)
@@ -1806,6 +1806,8 @@ void sc_conn_sync_send(struct stconn *sc)
                return;
 
        sc_conn_send(sc);
+       if (oc->flags & CF_WRITE_EVENT)
+               oc->flags |= CF_WAKE_ONCE;
 }
 
 /* Called by I/O handlers after completion.. It propagates
@@ -2311,6 +2313,8 @@ void sc_applet_sync_send(struct stconn *sc)
                return;
 
        sc_applet_send(sc);
+       if (oc->flags & CF_WRITE_EVENT)
+               oc->flags |= CF_WAKE_ONCE;
 }
 
 /* Callback to be used by applet handlers upon completion. It updates the stream
index c6e2d33f11c3556bca9db86ad0112951d6d7eba3..f7784c53adc144bd3a1fbc3a379072f66bbb6954 100644 (file)
@@ -2067,7 +2067,7 @@ struct task *process_stream(struct task *t, void *context, unsigned int state)
 
                rq_prod_last = scf->state;
                rq_cons_last = scb->state;
-               req->flags &= ~(CF_WAKE_ONCE|CF_READ_EVENT|CF_WRITE_EVENT);
+               req->flags &= ~CF_WAKE_ONCE;
                rqf_last = req->flags;
                scf_flags = (scf_flags & ~(SC_FL_EOS|SC_FL_ABRT_DONE|SC_FL_ABRT_WANTED)) | (scf->flags & (SC_FL_EOS|SC_FL_ABRT_DONE|SC_FL_ABRT_WANTED));
                scb_flags = (scb_flags & ~(SC_FL_SHUT_DONE|SC_FL_SHUT_WANTED)) | (scb->flags & (SC_FL_SHUT_DONE|SC_FL_SHUT_WANTED));
@@ -2142,7 +2142,7 @@ struct task *process_stream(struct task *t, void *context, unsigned int state)
 
                rp_cons_last = scf->state;
                rp_prod_last = scb->state;
-               res->flags &= ~(CF_WAKE_ONCE|CF_READ_EVENT|CF_WRITE_EVENT);
+               res->flags &= ~CF_WAKE_ONCE;
                rpf_last = res->flags;
                scb_flags = (scb_flags & ~(SC_FL_EOS|SC_FL_ABRT_DONE|SC_FL_ABRT_WANTED)) | (scb->flags & (SC_FL_EOS|SC_FL_ABRT_DONE|SC_FL_ABRT_WANTED));
                scf_flags = (scf_flags & ~(SC_FL_SHUT_DONE|SC_FL_SHUT_WANTED)) | (scf->flags & (SC_FL_SHUT_DONE|SC_FL_SHUT_WANTED));