diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c index 19038c260f1f1c6df85829dea24e7c3913bff47d..1c93e76f0a594db3e6b14e48ac6fdec29d8e34a9 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -338,6 +338,7 @@ static bool mptcp_frag_can_collapse_to(const struct mptcp_sock *msk, static void dfrag_uncharge(struct sock *sk, int len) { sk_mem_uncharge(sk, len); + sk_wmem_queued_add(sk, -len); } static void dfrag_clear(struct sock *sk, struct mptcp_data_frag *dfrag) @@ -364,8 +365,23 @@ static void mptcp_clean_una(struct sock *sk) cleaned = true; } + dfrag = mptcp_rtx_head(sk); + if (dfrag && after64(snd_una, dfrag->data_seq)) { + u64 delta = dfrag->data_seq + dfrag->data_len - snd_una; + + dfrag->data_seq += delta; + dfrag->data_len -= delta; + + dfrag_uncharge(sk, delta); + cleaned = true; + } + if (cleaned) { sk_mem_reclaim_partial(sk); + + /* Only wake up writers if a subflow is ready */ + if (test_bit(MPTCP_SEND_SPACE, &msk->flags)) + sk_stream_write_space(sk); } } diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h index d222eea119222fcc6079e2619acf2a9b7049e45f..f855c954a8ff94e01671a37c8d24a09ff6e75509 100644 --- a/net/mptcp/protocol.h +++ b/net/mptcp/protocol.h @@ -190,6 +190,16 @@ static inline struct mptcp_data_frag *mptcp_rtx_tail(const struct sock *sk) return list_last_entry(&msk->rtx_queue, struct mptcp_data_frag, list); } +static inline struct mptcp_data_frag *mptcp_rtx_head(const struct sock *sk) +{ + struct mptcp_sock *msk = mptcp_sk(sk); + + if (list_empty(&msk->rtx_queue)) + return NULL; + + return list_first_entry(&msk->rtx_queue, struct mptcp_data_frag, list); +} + struct mptcp_subflow_request_sock { struct tcp_request_sock sk; u16 mp_capable : 1,