diff --git a/include/haproxy/connection-t.h b/include/haproxy/connection-t.h index 35b7eaf34..ab0231642 100644 --- a/include/haproxy/connection-t.h +++ b/include/haproxy/connection-t.h @@ -144,8 +144,7 @@ enum { */ CO_FL_WAIT_ROOM = 0x00000800, /* data sink is full */ - /* These flags are used to report whether the from/to addresses are set or not */ - /* unused: 0x00001000 */ + CO_FL_WANT_SPLICING = 0x00001000, /* we wish to use splicing on the connection when possible */ /* unused: 0x00002000 */ CO_FL_EARLY_SSL_HS = 0x00004000, /* We have early data pending, don't start SSL handshake yet */ diff --git a/src/mux_h1.c b/src/mux_h1.c index 204964613..a8a6efa93 100644 --- a/src/mux_h1.c +++ b/src/mux_h1.c @@ -4856,16 +4856,35 @@ static size_t h1_nego_ff(struct stconn *sc, struct buffer *input, size_t count, * supported to mix data. */ if (!b_data(input) && !b_data(&h1c->obuf) && (flags & NEGO_FF_FL_MAY_SPLICE)) { + int can_splice = XPRT_CONN_CAN_NOT_SPLICE; #if defined(USE_LINUX_SPLICE) - if (h1c->conn->xprt->snd_pipe && (h1s->sd->iobuf.pipe || (pipes_used < global.maxpipes && (h1s->sd->iobuf.pipe = get_pipe())))) { + + if (h1c->conn->xprt->snd_pipe && + h1c->conn->xprt->get_capability && + h1c->conn->xprt->get_capability(h1c->conn, h1c->conn->xprt_ctx, XPRT_CAN_SPLICE, &can_splice) == 0 && + can_splice == XPRT_CONN_CAN_SPLICE && + (h1s->sd->iobuf.pipe || (pipes_used < global.maxpipes && (h1s->sd->iobuf.pipe = get_pipe())))) { h1s->sd->iobuf.offset = 0; h1s->sd->iobuf.data = 0; ret = count; goto out; } #endif - h1s->sd->iobuf.flags |= IOBUF_FL_NO_SPLICING; - TRACE_DEVEL("Unable to allocate pipe for splicing, fallback to buffer", H1_EV_STRM_SEND, h1c->conn, h1s); + /* + * If can_splice is XPRT_CONN_COULD_SPLICE, it means + * that it can not splice right now, but it may at a later + * time, so don't disable it completely, just do not attempt + * to splice right now. If we got that, then no pipe has + * been allowed, so we should not try to splice. + * Set CO_FL_WANT_SPLICING to let the upper layers know that + * we would love to be able to use splicing if possible. + */ + if (can_splice == XPRT_CONN_COULD_SPLICE) { + h1c->conn->flags |= CO_FL_WANT_SPLICING; + } else { + h1s->sd->iobuf.flags |= IOBUF_FL_NO_SPLICING; + TRACE_DEVEL("Unable to allocate pipe for splicing, fallback to buffer", H1_EV_STRM_SEND, h1c->conn, h1s); + } } no_splicing: @@ -5048,8 +5067,16 @@ static int h1_fastfwd(struct stconn *sc, unsigned int count, unsigned int flags) count = h1m->curr_len; } - if (h1c->conn->xprt->rcv_pipe && !!(flags & CO_RFL_MAY_SPLICE) && !(sdo->iobuf.flags & IOBUF_FL_NO_SPLICING)) - nego_flags |= NEGO_FF_FL_MAY_SPLICE; + if (h1c->conn->xprt->rcv_pipe && !!(flags & CO_RFL_MAY_SPLICE) && !(sdo->iobuf.flags & IOBUF_FL_NO_SPLICING)) { + int can_splice = XPRT_CONN_CAN_NOT_SPLICE; + + if (h1c->conn->xprt->get_capability && + h1c->conn->xprt->get_capability(h1c->conn, h1c->conn->xprt_ctx, XPRT_CAN_SPLICE, &can_splice) == 0 && + can_splice == XPRT_CONN_CAN_SPLICE) + nego_flags |= NEGO_FF_FL_MAY_SPLICE; + else if (can_splice == XPRT_CONN_COULD_SPLICE) + h1c->conn->flags |= CO_FL_WANT_SPLICING; + } try = se_nego_ff(sdo, &h1c->ibuf, count, nego_flags); if (b_room(&h1c->ibuf) && (h1c->flags & H1C_F_IN_FULL)) { diff --git a/src/mux_pt.c b/src/mux_pt.c index 5a26a153e..0b4c9ce78 100644 --- a/src/mux_pt.c +++ b/src/mux_pt.c @@ -592,16 +592,33 @@ static size_t mux_pt_nego_ff(struct stconn *sc, struct buffer *input, size_t cou * supported to mix data. */ if (!b_data(input) && (flags & NEGO_FF_FL_MAY_SPLICE)) { - if (conn->xprt->snd_pipe && (ctx->sd->iobuf.pipe || (pipes_used < global.maxpipes && (ctx->sd->iobuf.pipe = get_pipe())))) { + int can_splice = XPRT_CONN_CAN_NOT_SPLICE; + + if (conn->xprt->snd_pipe && conn->xprt->get_capability && + conn->xprt->get_capability(conn, conn->xprt_ctx, XPRT_CAN_SPLICE, &can_splice) == 0 && + can_splice == XPRT_CONN_CAN_SPLICE && + (ctx->sd->iobuf.pipe || (pipes_used < global.maxpipes && (ctx->sd->iobuf.pipe = get_pipe())))) { ctx->sd->iobuf.offset = 0; ctx->sd->iobuf.data = 0; ret = count; goto out; } - ctx->sd->iobuf.flags |= IOBUF_FL_NO_SPLICING; - TRACE_DEVEL("Unable to allocate pipe for splicing, fallback to buffer", PT_EV_TX_DATA, conn, sc); + /* + * If can_splice is XPRT_CONN_COULD, it means + * that it can not splice right now, but it may at a later + * time, so don't disable it completely, just do not attempt + * to splice right now. If we got that, then no pipe has + * been allowed, so we should not try to splice. + * Set CO_FL_WANT_SPLICING to let the upper layers know that + * we would love to be able to use splicing if possible. + */ + if (can_splice == XPRT_CONN_COULD_SPLICE) { + conn->flags |= CO_FL_WANT_SPLICING; + } else { + ctx->sd->iobuf.flags |= IOBUF_FL_NO_SPLICING; + TRACE_DEVEL("Unable to allocate pipe for splicing, fallback to buffer", PT_EV_TX_DATA, conn, sc); + } } - /* No buffer case */ out: @@ -664,8 +681,17 @@ static int mux_pt_fastfwd(struct stconn *sc, unsigned int count, unsigned int fl goto out; } - if (conn->xprt->rcv_pipe && !!(flags & CO_RFL_MAY_SPLICE) && !(sdo->iobuf.flags & IOBUF_FL_NO_SPLICING)) - nego_flags |= NEGO_FF_FL_MAY_SPLICE; + if (conn->xprt->rcv_pipe && !!(flags & CO_RFL_MAY_SPLICE) && !(sdo->iobuf.flags & IOBUF_FL_NO_SPLICING)) { + int can_splice = XPRT_CONN_CAN_NOT_SPLICE; + + if (conn->xprt->get_capability && + conn->xprt->get_capability(conn, conn->xprt_ctx, XPRT_CAN_SPLICE, &can_splice) == 0 && + can_splice == XPRT_CONN_CAN_SPLICE) + nego_flags |= NEGO_FF_FL_MAY_SPLICE; + else if (can_splice == XPRT_CONN_COULD_SPLICE) + conn->flags |= CO_FL_WANT_SPLICING; + } + try = se_nego_ff(sdo, &BUF_NULL, count, nego_flags); if (sdo->iobuf.flags & IOBUF_FL_NO_FF) {