MINOR: quic: support sbuf allocation in quic_stream

This patch extends qc_stream_desc API to be able to allocate small
buffers. QUIC MUX API is similarly updated as ultimatly each application
protocol is responsible to choose between a default or a smaller buffer.

Internally, the type of allocated buffer is remembered via qc_stream_buf
instance. This is mandatory to ensure that the buffer is released in the
correct pool, in particular as small and standard buffers can be
configured with the same size.

This commit is purely an API change. For the moment, small buffers are
not used. This will changed in a dedicated patch.
This commit is contained in:
Amaury Denoyelle 2024-06-13 15:26:51 +02:00
parent d0d8e57d47
commit 885e4c5cf8
7 changed files with 46 additions and 21 deletions

View File

@ -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);

View File

@ -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 */

View File

@ -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 */

View File

@ -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. */

View File

@ -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();

View File

@ -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
* <err> 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:

View File

@ -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);