[RFC mptcp-next v9 05/10] mptcp: avoid deadlocks in read_sock path

Geliang Tang posted 10 patches 1 week, 2 days ago
There is a newer version of this series
[RFC mptcp-next v9 05/10] mptcp: avoid deadlocks in read_sock path
Posted by Geliang Tang 1 week, 2 days ago
From: Geliang Tang <tanggeliang@kylinos.cn>

When invoking mptcp_read_sock() from a softirq context (e.g., through
the TLS read_sock interface), calling lock_sock_fast() in
mptcp_rcv_space_adjust() or mptcp_cleanup_rbuf() can lead to deadlocks,
since the socket lock may already be held.

Replace lock_sock_fast() with spin_trylock_bh() in these functions to
make the locking attempt non-blocking. If the lock cannot be acquired,
skip the operation to avoid deadlock.

Also introduce mptcp_data_trylock() and use it in mptcp_move_skbs() to
make the data locking non-blocking in the read_sock path.

Co-developed-by: Gang Yan <yangang@kylinos.cn>
Signed-off-by: Gang Yan <yangang@kylinos.cn>
Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn>
---
 net/mptcp/protocol.c | 16 ++++++++--------
 net/mptcp/protocol.h |  1 +
 2 files changed, 9 insertions(+), 8 deletions(-)

diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c
index c0109338648a..fdfe6145f6da 100644
--- a/net/mptcp/protocol.c
+++ b/net/mptcp/protocol.c
@@ -557,12 +557,11 @@ static void mptcp_send_ack(struct mptcp_sock *msk)
 
 static void mptcp_subflow_cleanup_rbuf(struct sock *ssk, int copied)
 {
-	bool slow;
-
-	slow = lock_sock_fast(ssk);
+	if (!spin_trylock_bh(&ssk->sk_lock.slock))
+		return;
 	if (tcp_can_send_ack(ssk))
 		tcp_cleanup_rbuf(ssk, copied);
-	unlock_sock_fast(ssk, slow);
+	spin_unlock_bh(&ssk->sk_lock.slock);
 }
 
 static bool mptcp_subflow_could_cleanup(const struct sock *ssk, bool rx_empty)
@@ -2152,14 +2151,14 @@ static void mptcp_rcv_space_adjust(struct mptcp_sock *msk, int copied)
 		 */
 		mptcp_for_each_subflow(msk, subflow) {
 			struct sock *ssk;
-			bool slow;
 
 			ssk = mptcp_subflow_tcp_sock(subflow);
-			slow = lock_sock_fast(ssk);
+			if (!spin_trylock_bh(&ssk->sk_lock.slock))
+				continue;
 			/* subflows can be added before tcp_init_transfer() */
 			if (tcp_sk(ssk)->rcvq_space.space)
 				tcp_rcvbuf_grow(ssk, copied);
-			unlock_sock_fast(ssk, slow);
+			spin_unlock_bh(&ssk->sk_lock.slock);
 		}
 	}
 
@@ -2232,7 +2231,8 @@ static bool mptcp_move_skbs(struct sock *sk)
 	bool enqueued = false;
 	u32 moved;
 
-	mptcp_data_lock(sk);
+	if (!mptcp_data_trylock(sk))
+		return false;
 	while (mptcp_can_spool_backlog(sk, &skbs)) {
 		mptcp_data_unlock(sk);
 		enqueued |= __mptcp_move_skbs(sk, &skbs, &moved);
diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h
index f5d4d7d030f2..3146e26687b4 100644
--- a/net/mptcp/protocol.h
+++ b/net/mptcp/protocol.h
@@ -378,6 +378,7 @@ struct mptcp_sock {
 };
 
 #define mptcp_data_lock(sk) spin_lock_bh(&(sk)->sk_lock.slock)
+#define mptcp_data_trylock(sk) spin_trylock_bh(&(sk)->sk_lock.slock)
 #define mptcp_data_unlock(sk) spin_unlock_bh(&(sk)->sk_lock.slock)
 
 #define mptcp_for_each_subflow(__msk, __subflow)			\
-- 
2.53.0