Re: [PATCH mptcp-next 6/6] mptcp: defer sk_data_ready to the worker

Paolo Abeni <[email protected]> Thu, 30 Jul 2026 17:18:39 +0200
Newsgroups dev.linux.lists.mptcp
Message-ID <[email protected]>
On 7/30/26 2:57 AM, Geliang Tang wrote:
> On Wed, 2026-07-29 at 10:55 +0200, Paolo Abeni wrote:
>> On 7/27/26 1:29 PM, Geliang Tang wrote:
>>> From: Geliang Tang <[email protected]>
>>>
>>> When MPTCP carries TLS, the data path runs under mptcp_data_lock().
>>> Reaching sk->sk_data_ready(sk) synchronously ends up at
>>> tls_strp_check_rcv() -> mptcp_recv_skb() -> mptcp_move_skbs(),
>>> which
>>> calls mptcp_data_lock() on the same sk and recurses on
>>> sk_lock.slock.
>>
>> Is mptcp_move_skbs() really needed in mptcp_recv_skb()? Anyway it
>> looks 
>> like that is not the only constraint: AFAICS, before the
>> mptcp_recv_skb() 
>> calls, the TLS code would call __mptcp_read_sock() which in turns
>> callsĀ  
>> mptcp_rcv_space_adjust() and mptcp_cleanup_rbuf() that requires
>> holding 
>> the msk socket lock in process context, while the mptcp/TLS caller is
>> in 
>> BH scope.
>>
>>> Fix this by deferring sk->sk_data_ready(sk) to mptcp_worker() via a
>>> new MPTCP_WORK_DATA_READY bit, re-using the existing
>>> mptcp_schedule_work()/mptcp_cancel_work() infrastructure. The
>>> wakeup
>>> bit is consumed after the SOCK_DEAD && TCP_CLOSE destroy branch, so
>>> a
>>> socket that reaches the destroy path drops the pending wakeup
>>> rather
>>> than running it post-free.
>>
>> I think that unconditionally adding the work latency for non-TLS
>> application 
>> is a no-go.
>>
>> Instead I *think* that the constraints in __mptcp_read_sock() could
>> be relaxed
>> with something alike the following (completely untested):
> 
> Thank you for your patch. It is very useful, but when running TLS
> tests, it deadlocks with the mptcp_data_lock in mptcp_inq_hint(). 

This looks like an unrelated problem.

AFAICS tls calls tcp_in() under the sk socket lock, and the helper is
implemented accordingly (in fact is separated from tcp_inq_hint()). Even
the mptcp helper must use the same assumption. No need to call
additional locking, nor (AFAICS) ONCE annoation, as `ack_seq` and
`copied_seq` should be modified only under the msk socket lock.

> Currently, the implementation of mptcp_read_done() is as follows:
> 
> static void mptcp_read_done(struct sock *sk, size_t len)
> {
>         struct mptcp_sock *msk = mptcp_sk(sk);
>         struct sk_buff *skb;
>         size_t left;
>         u32 offset;
> 
>         msk_owned_by_me(msk);
> 
>         if (sk->sk_state == TCP_LISTEN)
>                 return;
> 
>         left = len;
>         while (left && (skb = mptcp_recv_skb(sk, &offset)) != NULL) {
>                 int used;
>                 
>                 used = min_t(size_t, skb->len - offset, left);
>                 msk->bytes_consumed += used;
>                 msk->copied_seq += used;
>                 left -= used;
>            
>                 if (skb->len > offset + used)
>                         break;
> 
>                 mptcp_eat_recv_skb(sk, skb);
>         }
>         
>         /* Clean up data we have read: This will do ACK frames. */
>         if (left != len) {
>                 msk->read_copied = len - left;

Possibly both here and in __mptcp_read_sock() should be:

		msk->read_copied += len - left

(note the '+=' operator instead of '=')

/P