diff options
Diffstat (limited to 'net/mptcp/subflow.c')
| -rw-r--r-- | net/mptcp/subflow.c | 60 | 
1 files changed, 30 insertions, 30 deletions
diff --git a/net/mptcp/subflow.c b/net/mptcp/subflow.c index 9ee3b7abbaf6..9bf3c7bc1762 100644 --- a/net/mptcp/subflow.c +++ b/net/mptcp/subflow.c @@ -1359,7 +1359,7 @@ void mptcp_space(const struct sock *ssk, int *space, int *full_space)  	const struct sock *sk = subflow->conn;  	*space = __mptcp_space(sk); -	*full_space = tcp_full_space(sk); +	*full_space = mptcp_win_from_space(sk, READ_ONCE(sk->sk_rcvbuf));  }  void __mptcp_error_report(struct sock *sk) @@ -1793,16 +1793,31 @@ static void subflow_state_change(struct sock *sk)  void mptcp_subflow_queue_clean(struct sock *listener_sk, struct sock *listener_ssk)  {  	struct request_sock_queue *queue = &inet_csk(listener_ssk)->icsk_accept_queue; -	struct mptcp_sock *msk, *next, *head = NULL; -	struct request_sock *req; -	struct sock *sk; +	struct request_sock *req, *head, *tail; +	struct mptcp_subflow_context *subflow; +	struct sock *sk, *ssk; -	/* build a list of all unaccepted mptcp sockets */ +	/* Due to lock dependencies no relevant lock can be acquired under rskq_lock. +	 * Splice the req list, so that accept() can not reach the pending ssk after +	 * the listener socket is released below. +	 */  	spin_lock_bh(&queue->rskq_lock); -	for (req = queue->rskq_accept_head; req; req = req->dl_next) { -		struct mptcp_subflow_context *subflow; -		struct sock *ssk = req->sk; +	head = queue->rskq_accept_head; +	tail = queue->rskq_accept_tail; +	queue->rskq_accept_head = NULL; +	queue->rskq_accept_tail = NULL; +	spin_unlock_bh(&queue->rskq_lock); + +	if (!head) +		return; +	/* can't acquire the msk socket lock under the subflow one, +	 * or will cause ABBA deadlock +	 */ +	release_sock(listener_ssk); + +	for (req = head; req; req = req->dl_next) { +		ssk = req->sk;  		if (!sk_is_mptcp(ssk))  			continue; @@ -1810,32 +1825,10 @@ void mptcp_subflow_queue_clean(struct sock *listener_sk, struct sock *listener_s  		if (!subflow || !subflow->conn)  			continue; -		/* skip if already in list */  		sk = subflow->conn; -		msk = mptcp_sk(sk); -		if (msk->dl_next || msk == head) -			continue; -  		sock_hold(sk); -		msk->dl_next = head; -		head = msk; -	} -	spin_unlock_bh(&queue->rskq_lock); -	if (!head) -		return; - -	/* can't acquire the msk socket lock under the subflow one, -	 * or will cause ABBA deadlock -	 */ -	release_sock(listener_ssk); - -	for (msk = head; msk; msk = next) { -		sk = (struct sock *)msk;  		lock_sock_nested(sk, SINGLE_DEPTH_NESTING); -		next = msk->dl_next; -		msk->dl_next = NULL; -  		__mptcp_unaccepted_force_close(sk);  		release_sock(sk); @@ -1859,6 +1852,13 @@ void mptcp_subflow_queue_clean(struct sock *listener_sk, struct sock *listener_s  	/* we are still under the listener msk socket lock */  	lock_sock_nested(listener_ssk, SINGLE_DEPTH_NESTING); + +	/* restore the listener queue, to let the TCP code clean it up */ +	spin_lock_bh(&queue->rskq_lock); +	WARN_ON_ONCE(queue->rskq_accept_head); +	queue->rskq_accept_head = head; +	queue->rskq_accept_tail = tail; +	spin_unlock_bh(&queue->rskq_lock);  }  static int subflow_ulp_init(struct sock *sk)  | 
