Skip to content

Commit 7948f6c

Browse files
Florian Westphaldavem330
authored andcommitted
mptcp: allow partial cleaning of rtx head dfrag
After adding wmem accounting 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. This isn't an issue if the send buffer is large, but it is when SO_SNDBUF is used to reduce it to a lower value. Note we can still get a deadlock for low SO_SNDBUF values in case both sides of the connection write to the socket: both could be blocked due to wmem being too small -- and current mptcp stack will only increment mptcp ack_seq on recv. This doesn't happen with the selftest as it uses poll() and will always call recv if there is data to read. Signed-off-by: Florian Westphal <[email protected]> Signed-off-by: Mat Martineau <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent d027236 commit 7948f6c

File tree

2 files changed

+26
-0
lines changed

2 files changed

+26
-0
lines changed

net/mptcp/protocol.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,7 @@ static bool mptcp_frag_can_collapse_to(const struct mptcp_sock *msk,
338338
static void dfrag_uncharge(struct sock *sk, int len)
339339
{
340340
sk_mem_uncharge(sk, len);
341+
sk_wmem_queued_add(sk, -len);
341342
}
342343

343344
static void dfrag_clear(struct sock *sk, struct mptcp_data_frag *dfrag)
@@ -364,8 +365,23 @@ static void mptcp_clean_una(struct sock *sk)
364365
cleaned = true;
365366
}
366367

368+
dfrag = mptcp_rtx_head(sk);
369+
if (dfrag && after64(snd_una, dfrag->data_seq)) {
370+
u64 delta = dfrag->data_seq + dfrag->data_len - snd_una;
371+
372+
dfrag->data_seq += delta;
373+
dfrag->data_len -= delta;
374+
375+
dfrag_uncharge(sk, delta);
376+
cleaned = true;
377+
}
378+
367379
if (cleaned) {
368380
sk_mem_reclaim_partial(sk);
381+
382+
/* Only wake up writers if a subflow is ready */
383+
if (test_bit(MPTCP_SEND_SPACE, &msk->flags))
384+
sk_stream_write_space(sk);
369385
}
370386
}
371387

net/mptcp/protocol.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,16 @@ static inline struct mptcp_data_frag *mptcp_rtx_tail(const struct sock *sk)
190190
return list_last_entry(&msk->rtx_queue, struct mptcp_data_frag, list);
191191
}
192192

193+
static inline struct mptcp_data_frag *mptcp_rtx_head(const struct sock *sk)
194+
{
195+
struct mptcp_sock *msk = mptcp_sk(sk);
196+
197+
if (list_empty(&msk->rtx_queue))
198+
return NULL;
199+
200+
return list_first_entry(&msk->rtx_queue, struct mptcp_data_frag, list);
201+
}
202+
193203
struct mptcp_subflow_request_sock {
194204
struct tcp_request_sock sk;
195205
u16 mp_capable : 1,

0 commit comments

Comments
 (0)