Skip to content

Commit

Permalink
mptcp: fix race in release_cb
Browse files Browse the repository at this point in the history
[ Upstream commit c2e6048 ]

If we receive a MPTCP_PUSH_PENDING even from a subflow when
mptcp_release_cb() is serving the previous one, the latter
will be delayed up to the next release_sock(msk).

Address the issue implementing a test/serve loop for such
event.

Additionally rename the push helper to __mptcp_push_pending()
to be more consistent with the existing code.

Fixes: 6e628cd ("mptcp: use mptcp release_cb for delayed tasks")
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Signed-off-by: Mat Martineau <mathew.j.martineau@linux.intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Sasha Levin <sashal@kernel.org>
  • Loading branch information
Paolo Abeni authored and gregkh committed Apr 7, 2021
1 parent 9634007 commit 9a958f6
Showing 1 changed file with 21 additions and 12 deletions.
33 changes: 21 additions & 12 deletions net/mptcp/protocol.c
Expand Up @@ -1442,7 +1442,7 @@ static void mptcp_push_release(struct sock *sk, struct sock *ssk,
release_sock(ssk);
}

static void mptcp_push_pending(struct sock *sk, unsigned int flags)
static void __mptcp_push_pending(struct sock *sk, unsigned int flags)
{
struct sock *prev_ssk = NULL, *ssk = NULL;
struct mptcp_sock *msk = mptcp_sk(sk);
Expand Down Expand Up @@ -1681,14 +1681,14 @@ static int mptcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)

wait_for_memory:
set_bit(MPTCP_NOSPACE, &msk->flags);
mptcp_push_pending(sk, msg->msg_flags);
__mptcp_push_pending(sk, msg->msg_flags);
ret = sk_stream_wait_memory(sk, &timeo);
if (ret)
goto out;
}

if (copied)
mptcp_push_pending(sk, msg->msg_flags);
__mptcp_push_pending(sk, msg->msg_flags);

out:
release_sock(sk);
Expand Down Expand Up @@ -2944,13 +2944,14 @@ static void mptcp_release_cb(struct sock *sk)
{
unsigned long flags, nflags;

/* push_pending may touch wmem_reserved, do it before the later
* cleanup
*/
if (test_and_clear_bit(MPTCP_CLEAN_UNA, &mptcp_sk(sk)->flags))
__mptcp_clean_una(sk);
if (test_and_clear_bit(MPTCP_PUSH_PENDING, &mptcp_sk(sk)->flags)) {
/* mptcp_push_pending() acquires the subflow socket lock
for (;;) {
flags = 0;
if (test_and_clear_bit(MPTCP_PUSH_PENDING, &mptcp_sk(sk)->flags))
flags |= MPTCP_PUSH_PENDING;
if (!flags)
break;

/* the following actions acquire the subflow socket lock
*
* 1) can't be invoked in atomic scope
* 2) must avoid ABBA deadlock with msk socket spinlock: the RX
Expand All @@ -2959,13 +2960,21 @@ static void mptcp_release_cb(struct sock *sk)
*/

spin_unlock_bh(&sk->sk_lock.slock);
mptcp_push_pending(sk, 0);
if (flags & MPTCP_PUSH_PENDING)
__mptcp_push_pending(sk, 0);

cond_resched();
spin_lock_bh(&sk->sk_lock.slock);
}

if (test_and_clear_bit(MPTCP_CLEAN_UNA, &mptcp_sk(sk)->flags))
__mptcp_clean_una(sk);
if (test_and_clear_bit(MPTCP_ERROR_REPORT, &mptcp_sk(sk)->flags))
__mptcp_error_report(sk);

/* clear any wmem reservation and errors */
/* push_pending may touch wmem_reserved, ensure we do the cleanup
* later
*/
__mptcp_update_wmem(sk);
__mptcp_update_rmem(sk);

Expand Down

0 comments on commit 9a958f6

Please sign in to comment.