mirror of
http://git.haproxy.org/git/haproxy.git/
synced 2025-02-06 13:33:02 +00:00
BUG/MAJOR: stconn: Check support for zero-copy forwarding on both sides
There is a nego stage when a producer is ready to forward data to the other side. At this stage, the zero-copy forwarding may be disabled if the consumer does not support it. However, there is a flaw with this way to proceed. If the channel buffer is not empty, we delay the zero-copy forwarding to flush all data from the channel first. During this delay, receives on the endpoint (at connection level for muxes), are blocked to be sure to have the opportunity to switch on zero-copy forwarding. It is a problem if the consumer cannot flush data from the channel's buffer, waiting for more data for instance. It is especially annoying with the CLI applet, because this scenario can happen if a command is partially received. For instance without the LF at the end. In this case, the CLI applet is blocked because it waits more data. The frontend connexion is also blocked because channel's data must be flushed before trying to receive more data. Worst, this happen at where no timeout is armed. Thus the session is stuck infinitly, client aborts cannot be detected because receives are blocked, and the applet cannot abort on its side because there are pending outgoing data. It is clearly a situation where it is easy to consume all CLI slots. To fix the issue, thanks to previous commits, we now check zero-copy forwarding support on both sides before proceeding. This patch relies on the following commits: * MINOR: muxes: Announce support for zero-copy forwarding on consumer side * MINOR: stconn: Add SE flag to announce zero-copy forwarding on consumer side * MINOR: stconn: Rename SE_FL_MAY_FASTFWD and reorder bitfield * CLEANUP: stconn: Move SE flags set by app layer at the end of the bitfield All the series must be backported to 2.9.
This commit is contained in:
parent
e2921ffad1
commit
ddf6b7539c
14
src/stconn.c
14
src/stconn.c
@ -544,6 +544,14 @@ static inline int sc_cond_forward_shut(struct stconn *sc)
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static inline int sc_is_fastfwd_supported(struct stconn *sc)
|
||||
{
|
||||
return (!(global.tune.no_zero_copy_fwd & NO_ZERO_COPY_FWD) &&
|
||||
sc_ep_test(sc, SE_FL_MAY_FASTFWD_PROD) &&
|
||||
sc_ep_test(sc_opposite(sc), SE_FL_MAY_FASTFWD_CONS) &&
|
||||
sc_ic(sc)->to_forward);
|
||||
}
|
||||
/*
|
||||
* This function performs a shutdown-read on a detached stream connector in a
|
||||
* connected or init state (it does nothing for other states). It either shuts
|
||||
@ -1267,8 +1275,7 @@ int sc_conn_recv(struct stconn *sc)
|
||||
/* First, let's see if we may fast-forward data from a side to the other
|
||||
* one without using the channel buffer.
|
||||
*/
|
||||
if (!(global.tune.no_zero_copy_fwd & NO_ZERO_COPY_FWD) &&
|
||||
sc_ep_test(sc, SE_FL_MAY_FASTFWD_PROD) && ic->to_forward) {
|
||||
if (sc_is_fastfwd_supported(sc)) {
|
||||
if (channel_data(ic)) {
|
||||
/* We're embarrassed, there are already data pending in
|
||||
* the buffer and we don't want to have them at two
|
||||
@ -1907,8 +1914,7 @@ int sc_applet_recv(struct stconn *sc)
|
||||
/* First, let's see if we may fast-forward data from a side to the other
|
||||
* one without using the channel buffer.
|
||||
*/
|
||||
if (!(global.tune.no_zero_copy_fwd & NO_ZERO_COPY_FWD) &&
|
||||
sc_ep_test(sc, SE_FL_MAY_FASTFWD_PROD) && ic->to_forward) {
|
||||
if (sc_is_fastfwd_supported(sc)) {
|
||||
if (channel_data(ic)) {
|
||||
/* We're embarrassed, there are already data pending in
|
||||
* the buffer and we don't want to have them at two
|
||||
|
Loading…
Reference in New Issue
Block a user