Currently the enforcement of the rcvbuf constraint is implemented
when moving the skbs into the msk receive or OoO queue.
Under significant memory pressure the above can cause permanent data
transfer stalls. Move the checks early on, before landing even in
the subflow queues.
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
---
Note that:
- this needs the follow-up patches to really fix the stall
- the memory comparison is intentionally very rough, as
the msk socket lock is not currently held where the condition is
now enforced. This should require some refinement, shared as-is
to avoid more latency on my side
---
net/mptcp/options.c | 21 +++++++++++++++++++--
net/mptcp/protocol.c | 9 ++-------
2 files changed, 21 insertions(+), 9 deletions(-)
diff --git a/net/mptcp/options.c b/net/mptcp/options.c
index 4cc583fdc7a9..a6d290427611 100644
--- a/net/mptcp/options.c
+++ b/net/mptcp/options.c
@@ -1158,8 +1158,19 @@ static bool add_addr_hmac_valid(struct mptcp_sock *msk,
return hmac == mp_opt->ahmac;
}
-/* Return false in case of error (or subflow has been reset),
- * else return true.
+static bool mptcp_over_limit(const struct sock *sk, struct sk_buff *skb)
+{
+ int limit;
+
+ if (!skb->len)
+ return false;
+
+ limit = READ_ONCE(sk->sk_rcvbuf) << 1;
+ return sk_rmem_alloc_get(sk) > limit;
+}
+
+/* Return false when the caller must to drop the packet, i.e. in case of error,
+ * subflow has been reset, or over memory limits.
*/
bool mptcp_incoming_options(struct sock *sk, struct sk_buff *skb)
{
@@ -1185,6 +1196,9 @@ bool mptcp_incoming_options(struct sock *sk, struct sk_buff *skb)
__mptcp_data_acked(subflow->conn);
mptcp_data_unlock(subflow->conn);
+
+ if (mptcp_over_limit(subflow->conn, skb))
+ return false;
return true;
}
@@ -1263,6 +1277,9 @@ bool mptcp_incoming_options(struct sock *sk, struct sk_buff *skb)
return true;
}
+ if (mptcp_over_limit(subflow->conn, skb))
+ return false;
+
mpext = skb_ext_add(skb, SKB_EXT_MPTCP);
if (!mpext)
return false;
diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c
index 17b9a8c13ebf..2d143b929bbf 100644
--- a/net/mptcp/protocol.c
+++ b/net/mptcp/protocol.c
@@ -739,7 +739,7 @@ static bool __mptcp_move_skbs_from_subflow(struct mptcp_sock *msk,
mptcp_init_skb(ssk, skb, offset, len);
- if (own_msk && sk_rmem_alloc_get(sk) < sk->sk_rcvbuf) {
+ if (own_msk) {
mptcp_subflow_lend_fwdmem(subflow, skb);
ret |= __mptcp_move_skb(sk, skb);
} else {
@@ -2197,10 +2197,6 @@ static bool __mptcp_move_skbs(struct sock *sk, struct list_head *skbs, u32 *delt
*delta = 0;
while (1) {
- /* If the msk recvbuf is full stop, don't drop */
- if (sk_rmem_alloc_get(sk) > sk->sk_rcvbuf)
- break;
-
prefetch(skb->next);
list_del(&skb->list);
*delta += skb->truesize;
@@ -2229,8 +2225,7 @@ static bool mptcp_can_spool_backlog(struct sock *sk, struct list_head *skbs)
mem_cgroup_from_sk(sk));
/* Don't spool the backlog if the rcvbuf is full. */
- if (list_empty(&msk->backlog_list) ||
- sk_rmem_alloc_get(sk) > sk->sk_rcvbuf)
+ if (list_empty(&msk->backlog_list))
return false;
INIT_LIST_HEAD(skbs);
--
2.53.0