diff mbox series

[RFC,2/6] mptcp: allow partial cleaning of rtx head dfrag

Message ID 20191108220953.30904-3-fw@strlen.de
State Superseded, archived
Headers show
Series None | expand

Commit Message

Florian Westphal Nov. 8, 2019, 10:09 p.m. UTC
After adding wmem accouting for the mptcp socket we could get
into a situation where the mptcp socket can't transmit more data,
and mptcp_clean_una doesn't reduce wmem even if snd_una has advanced
because it currently will only remove entire dfrags.

Allow advancing the dfrag head sequence and reduce wmem,
even though this isn't correct (as we can't release the page).

Because we will soon block on mptcp sk in case wmem is too large,
call sk_stream_write_space() in case we reduced the backlog so
userspace task blocked in sendmsg or poll will be woken up.

Signed-off-by: Florian Westphal <fw@strlen.de>
---
 net/mptcp/protocol.c | 28 +++++++++++++++++++++++++---
 1 file changed, 25 insertions(+), 3 deletions(-)

Comments

Mat Martineau Nov. 12, 2019, 12:23 a.m. UTC | #1
On Fri, 8 Nov 2019, Florian Westphal wrote:

> After adding wmem accouting for the mptcp socket we could get
> into a situation where the mptcp socket can't transmit more data,
> and mptcp_clean_una doesn't reduce wmem even if snd_una has advanced
> because it currently will only remove entire dfrags.
>
> Allow advancing the dfrag head sequence and reduce wmem,
> even though this isn't correct (as we can't release the page).

The approach seems ok to me, since it only ever has excess bytes from one 
page per MPTCP socket.

No changes to suggest in the code either.

Mat


>
> Because we will soon block on mptcp sk in case wmem is too large,
> call sk_stream_write_space() in case we reduced the backlog so
> userspace task blocked in sendmsg or poll will be woken up.
>
> Signed-off-by: Florian Westphal <fw@strlen.de>
> ---
> net/mptcp/protocol.c | 28 +++++++++++++++++++++++++---
> 1 file changed, 25 insertions(+), 3 deletions(-)
>

--
Mat Martineau
Intel
diff mbox series

Patch

diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c
index 65f10bb372aa..b93050056195 100644
--- a/net/mptcp/protocol.c
+++ b/net/mptcp/protocol.c
@@ -137,13 +137,18 @@  static inline bool mptcp_frag_can_collapse_to(const struct mptcp_sock *msk,
 		df->data_seq + df->data_len == msk->write_seq;
 }
 
+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)
 {
 	int len = dfrag->data_len + dfrag->overhead;
 
 	list_del(&dfrag->list);
-	sk_mem_uncharge(sk, len);
-	sk_wmem_queued_add(sk, -len);
+	dfrag_uncharge(sk, len);
 	put_page(dfrag->page);
 }
 
@@ -152,14 +157,31 @@  static void mptcp_clean_una(struct sock *sk)
 	struct mptcp_sock *msk = mptcp_sk(sk);
 	struct mptcp_data_frag *dtmp, *dfrag;
 	u64 snd_una = atomic64_read(&msk->snd_una);
+	bool cleaned = false;
 
 	list_for_each_entry_safe(dfrag, dtmp, &msk->rtx_queue, list) {
 		if (after64(dfrag->data_seq + dfrag->data_len, snd_una))
 			break;
 
 		dfrag_clear(sk, dfrag);
+		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);
+		sk_stream_write_space(sk);
 	}
-	sk_mem_reclaim_partial(sk);
 }
 
 /* ensure we get enough memory for the frag hdr, beyond some minimal amount of