diff --git a/include/haproxy/mux_quic.h b/include/haproxy/mux_quic.h index a9e571bf0..83f54f507 100644 --- a/include/haproxy/mux_quic.h +++ b/include/haproxy/mux_quic.h @@ -26,7 +26,7 @@ void qcs_notify_send(struct qcs *qcs); void qcc_notify_buf(struct qcc *qcc, uint64_t free_size); struct buffer *qcc_get_stream_rxbuf(struct qcs *qcs); -struct buffer *qcc_get_stream_txbuf(struct qcs *qcs, int *err); +struct buffer *qcc_get_stream_txbuf(struct qcs *qcs, int *err, int small); int qcc_realign_stream_txbuf(const struct qcs *qcs, struct buffer *out); int qcc_release_stream_txbuf(struct qcs *qcs); int qcc_stream_can_send(const struct qcs *qcs); diff --git a/include/haproxy/quic_stream-t.h b/include/haproxy/quic_stream-t.h index 649316e34..1a5cf47df 100644 --- a/include/haproxy/quic_stream-t.h +++ b/include/haproxy/quic_stream-t.h @@ -17,6 +17,7 @@ struct qc_stream_buf { struct buffer buf; /* STREAM payload */ struct list list; /* element for qc_stream_desc list */ + int sbuf; }; #define QC_SD_FL_RELEASE 0x00000001 /* set when MUX has finished to use this stream */ diff --git a/include/haproxy/quic_stream.h b/include/haproxy/quic_stream.h index c7a237969..4417ee2c9 100644 --- a/include/haproxy/quic_stream.h +++ b/include/haproxy/quic_stream.h @@ -16,7 +16,7 @@ void qc_stream_desc_free(struct qc_stream_desc *stream, int closing); struct buffer *qc_stream_buf_get(struct qc_stream_desc *stream); struct buffer *qc_stream_buf_alloc(struct qc_stream_desc *stream, - uint64_t offset); + uint64_t offset, int small); void qc_stream_buf_release(struct qc_stream_desc *stream); #endif /* USE_QUIC */ diff --git a/src/h3.c b/src/h3.c index f19b99ba3..794c30ff8 100644 --- a/src/h3.c +++ b/src/h3.c @@ -1524,7 +1524,7 @@ static int h3_control_send(struct qcs *qcs, void *ctx) goto err; } - if (!(res = qcc_get_stream_txbuf(qcs, &err))) { + if (!(res = qcc_get_stream_txbuf(qcs, &err, 0))) { /* Only memory failure can cause buf alloc error for control stream due to qcs_send_metadata() usage. */ TRACE_ERROR("cannot allocate Tx buffer", H3_EV_TX_FRAME|H3_EV_TX_SETTINGS, qcs->qcc->conn, qcs); goto err; @@ -1606,7 +1606,7 @@ static int h3_resp_headers_send(struct qcs *qcs, struct htx *htx) list[hdr].n = ist(""); - if (!(res = qcc_get_stream_txbuf(qcs, &err))) { + if (!(res = qcc_get_stream_txbuf(qcs, &err, 0))) { if (err) { TRACE_ERROR("cannot allocate Tx buffer", H3_EV_TX_FRAME|H3_EV_TX_HDR, qcs->qcc->conn, qcs); goto err; @@ -1764,7 +1764,7 @@ static int h3_resp_trailers_send(struct qcs *qcs, struct htx *htx) list[hdr].n = ist(""); start: - if (!(res = qcc_get_stream_txbuf(qcs, &err))) { + if (!(res = qcc_get_stream_txbuf(qcs, &err, 0))) { if (err) { TRACE_ERROR("cannot allocate Tx buffer", H3_EV_TX_FRAME|H3_EV_TX_HDR, qcs->qcc->conn, qcs); goto err; @@ -1898,7 +1898,7 @@ static int h3_resp_data_send(struct qcs *qcs, struct htx *htx, if (type != HTX_BLK_DATA) goto end; - if (!(res = qcc_get_stream_txbuf(qcs, &err))) { + if (!(res = qcc_get_stream_txbuf(qcs, &err, 0))) { if (err) { TRACE_ERROR("cannot allocate Tx buffer", H3_EV_TX_FRAME|H3_EV_TX_DATA, qcs->qcc->conn, qcs); goto err; @@ -2109,7 +2109,7 @@ static size_t h3_nego_ff(struct qcs *qcs, size_t count) TRACE_ENTER(H3_EV_STRM_SEND, qcs->qcc->conn, qcs); start: - if (!(res = qcc_get_stream_txbuf(qcs, &err))) { + if (!(res = qcc_get_stream_txbuf(qcs, &err, 0))) { if (err) { qcs->sd->iobuf.flags |= IOBUF_FL_NO_FF; goto end; @@ -2319,7 +2319,7 @@ static int h3_send_goaway(struct h3c *h3c) b_quic_enc_int(&pos, frm_len, 0); b_quic_enc_int(&pos, h3c->id_goaway, 0); - res = qcc_get_stream_txbuf(qcs, &err); + res = qcc_get_stream_txbuf(qcs, &err, 0); if (!res || b_room(res) < b_data(&pos) || qfctl_sblocked(&qcs->tx.fc) || qfctl_sblocked(&h3c->qcc->tx.fc)) { /* Do not try forcefully to emit GOAWAY if no buffer available or not enough space left. */ diff --git a/src/hq_interop.c b/src/hq_interop.c index c88f888be..d0c6b43c2 100644 --- a/src/hq_interop.c +++ b/src/hq_interop.c @@ -110,7 +110,7 @@ static size_t hq_interop_snd_buf(struct qcs *qcs, struct buffer *buf, switch (btype) { case HTX_BLK_DATA: - res = qcc_get_stream_txbuf(qcs, &err); + res = qcc_get_stream_txbuf(qcs, &err, 0); if (!res) { if (err) ABORT_NOW(); @@ -185,7 +185,7 @@ static size_t hq_interop_nego_ff(struct qcs *qcs, size_t count) struct buffer *res; start: - res = qcc_get_stream_txbuf(qcs, &err); + res = qcc_get_stream_txbuf(qcs, &err, 0); if (!res) { if (err) ABORT_NOW(); diff --git a/src/mux_quic.c b/src/mux_quic.c index 66d2b59d8..7b25bba6c 100644 --- a/src/mux_quic.c +++ b/src/mux_quic.c @@ -1037,7 +1037,7 @@ struct buffer *qcc_get_stream_rxbuf(struct qcs *qcs) * Returns buffer pointer. May be NULL on allocation failure, in which case * will refer to the cause. */ -struct buffer *qcc_get_stream_txbuf(struct qcs *qcs, int *err) +struct buffer *qcc_get_stream_txbuf(struct qcs *qcs, int *err, int small) { struct qcc *qcc = qcs->qcc; struct buffer *out = qc_stream_buf_get(qcs->stream); @@ -1065,7 +1065,7 @@ struct buffer *qcc_get_stream_txbuf(struct qcs *qcs, int *err) } } - out = qc_stream_buf_alloc(qcs->stream, qcs->tx.fc.off_real); + out = qc_stream_buf_alloc(qcs->stream, qcs->tx.fc.off_real, small); if (!out) { TRACE_ERROR("stream desc alloc failure", QMUX_EV_QCS_SEND, qcc->conn, qcs); *err = 1; @@ -1073,7 +1073,7 @@ struct buffer *qcc_get_stream_txbuf(struct qcs *qcs, int *err) } if (likely(!unlimited)) - qcc->tx.buf_in_flight += global.tune.bufsize; + qcc->tx.buf_in_flight += b_size(out); } out: diff --git a/src/quic_stream.c b/src/quic_stream.c index b0ad776ff..5f1f1f4c5 100644 --- a/src/quic_stream.c +++ b/src/quic_stream.c @@ -39,8 +39,13 @@ static void qc_stream_buf_free(struct qc_stream_desc *stream, stream->buf = NULL; free_size = b_size(buf); - b_free(buf); - offer_buffers(NULL, 1); + if ((*stream_buf)->sbuf) { + pool_free(pool_head_sbuf, buf->area); + } + else { + b_free(buf); + offer_buffers(NULL, 1); + } pool_free(pool_head_quic_stream_buf, *stream_buf); *stream_buf = NULL; @@ -213,7 +218,10 @@ void qc_stream_desc_free(struct qc_stream_desc *stream, int closing) list_for_each_entry_safe(buf, buf_back, &stream->buf_list, list) { if (!(b_data(&buf->buf)) || closing) { free_size += b_size(&buf->buf); - b_free(&buf->buf); + if (buf->sbuf) + pool_free(pool_head_sbuf, buf->buf.area); + else + b_free(&buf->buf); LIST_DELETE(&buf->list); pool_free(pool_head_quic_stream_buf, buf); ++free_count; @@ -269,7 +277,7 @@ struct buffer *qc_stream_buf_get(struct qc_stream_desc *stream) * Returns the buffer or NULL on error. */ struct buffer *qc_stream_buf_alloc(struct qc_stream_desc *stream, - uint64_t offset) + uint64_t offset, int small) { /* current buffer must be released first before allocate a new one. */ BUG_ON(stream->buf); @@ -280,10 +288,26 @@ struct buffer *qc_stream_buf_alloc(struct qc_stream_desc *stream, return NULL; stream->buf->buf = BUF_NULL; - if (!b_alloc(&stream->buf->buf, DB_MUX_TX)) { - pool_free(pool_head_quic_stream_buf, stream->buf); - stream->buf = NULL; - return NULL; + + if (!small) { + stream->buf->sbuf = 0; + if (!b_alloc(&stream->buf->buf, DB_MUX_TX)) { + pool_free(pool_head_quic_stream_buf, stream->buf); + stream->buf = NULL; + return NULL; + } + } + else { + char *area; + + if (!(area = pool_alloc(pool_head_sbuf))) { + pool_free(pool_head_quic_stream_buf, stream->buf); + stream->buf = NULL; + return NULL; + } + + stream->buf->sbuf = 1; + stream->buf->buf = b_make(area, global.tune.bufsize_small, 0, 0); } LIST_APPEND(&stream->buf_list, &stream->buf->list);