struct {
struct quic_fctl fc; /* stream flow control applied on sending */
int avail_bufs; /* count of available buffers for this connection */
+ uint64_t buf_in_flight; /* sum of currently allocated Tx buffer sizes */
} tx;
uint64_t largest_bidi_r; /* largest remote bidi stream ID opened. */
int qcs_subscribe(struct qcs *qcs, int event_type, struct wait_event *es);
void qcs_notify_recv(struct qcs *qcs);
void qcs_notify_send(struct qcs *qcs);
-void qcc_notify_buf(struct qcc *qcc, int free_count);
+void qcc_notify_buf(struct qcc *qcc, int free_count, uint64_t free_size);
struct buffer *qcc_get_stream_rxbuf(struct qcs *qcs);
struct buffer *qcc_get_stream_txbuf(struct qcs *qcs, int *err);
}
}
-/* Report that <free_count> stream-desc buffer have been released for <qcc>
- * connection.
+/* Report that one or several stream-desc buffers have been released for <qcc>
+ * connection. <free_size> represent the sum of freed buffers sizes.
*/
-void qcc_notify_buf(struct qcc *qcc, int free_count)
+void qcc_notify_buf(struct qcc *qcc, int free_count, uint64_t free_size)
{
struct qcs *qcs;
BUG_ON(qcc->tx.avail_bufs + free_count > global.tune.quic_streams_buf);
qcc->tx.avail_bufs += free_count;
+ /* Cannot have a negative buf_in_flight counter */
+ BUG_ON(qcc->tx.buf_in_flight < free_size);
+ qcc->tx.buf_in_flight -= free_size;
+
if (qcc->flags & QC_CF_CONN_FULL) {
TRACE_STATE("new stream desc buffer available", QMUX_EV_QCC_WAKE, qcc->conn);
qcc->flags &= ~QC_CF_CONN_FULL;
goto out;
}
- if (likely(!unlimited))
+ if (likely(!unlimited)) {
--qcc->tx.avail_bufs;
+ qcc->tx.buf_in_flight += global.tune.bufsize;
+ }
}
out:
qcc->rfctl.msd_uni_l = rparams->initial_max_stream_data_uni;
qcc->tx.avail_bufs = global.tune.quic_streams_buf;
+ qcc->tx.buf_in_flight = 0;
if (conn_is_back(conn)) {
qcc->next_bidi_l = 0x00;
{
struct quic_conn *qc = stream->qc;
struct buffer *buf = &(*stream_buf)->buf;
+ uint64_t free_size;
LIST_DEL_INIT(&(*stream_buf)->list);
if (*stream_buf == stream->buf)
stream->buf = NULL;
+ free_size = b_size(buf);
b_free(buf);
offer_buffers(NULL, 1);
pool_free(pool_head_quic_stream_buf, *stream_buf);
if (qc->mux_state == QC_MUX_READY) {
if (!(stream->flags & QC_SD_FL_OOB_BUF)) {
/* notify MUX about available buffers. */
- qcc_notify_buf(qc->qcc, 1);
+ qcc_notify_buf(qc->qcc, 1, free_size);
}
}
}
struct quic_conn *qc = stream->qc;
struct eb64_node *frm_node;
unsigned int free_count = 0;
+ uint64_t free_size = 0;
/* This function only deals with released streams. */
BUG_ON(!(stream->flags & QC_SD_FL_RELEASE));
/* free remaining stream buffers */
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);
LIST_DELETE(&buf->list);
pool_free(pool_head_quic_stream_buf, buf);
if (qc->mux_state == QC_MUX_READY) {
if (!(stream->flags & QC_SD_FL_OOB_BUF)) {
/* notify MUX about available buffers. */
- qcc_notify_buf(qc->qcc, free_count);
+ qcc_notify_buf(qc->qcc, free_count, free_size);
}
}
}