]> git.kaiwu.me - haproxy.git/commitdiff
BUG/MEDIUM: bwlim: never burst more than the pending data in input
authorChristopher Faulet <cfaulet@haproxy.com>
Mon, 19 Oct 2026 12:15:15 +0000 (14:15 +0200)
committerChristopher Faulet <cfaulet@haproxy.com>
Mon, 19 Oct 2026 19:54:04 +0000 (21:54 +0200)
When the bandwidth limitation filter applies a limitation on a channel, it
returns the amount of data the stream is authorized to forward to the data
filtering layer.
This amount could be larger than the amount of pending data in the channel
input when the min-size burst was used: with a shared limitation, the stream
quota was shared between all users and the burst was not clamped to the
pending input data when the producer of the channel was still open. When
this happened, more output data than available were removed from the
channel. The channel was then corrupted and the stream spinned at 100% CPU
with its tasklet woken up in a loop while the response buffer shown a
negative input count.

The fix clamps the burst to the pending input data, as already done when the
producer closed its endpoint. This way the filter never reports more data
than the channel really holds.

This patch should fix the issue #3541. It must be backported as far as 2.6.

src/flt_bwlim.c

index d163fcb2d56dbec42e1f4a0d22eacb1ee118e1ff..6a2710007d83fb3b5235194fdec6a881f7dcb22f 100644 (file)
@@ -160,9 +160,8 @@ static int bwlim_apply_limit(struct filter *filter, struct channel *chn, unsigne
                 */
                ret = tokens;
                if (tokens < conf->min_size) {
-                       ret = (chn_prod(chn)->flags & (SC_FL_EOI|SC_FL_EOS|SC_FL_ABRT_DONE))
-                               ? MIN(len, conf->min_size)
-                               : conf->min_size;
+                       /* The burst must never exceed the amount of pending data (<len>) */
+                       ret = MIN(len, conf->min_size);
 
                        if (ret <= remain)
                                wait = div64_32((uint64_t)(ret - tokens) * period * users + limit * factor - 1, limit * factor);