mptcp: implement .read_sock

Current in-kernel TCP sockets -- i.e. from nvme_tcp_try_recv() -- need
to call .read_sock interface of struct proto_ops, but it's not
implemented in MPTCP.

This patch implements it with reference to __tcp_read_sock() and
__mptcp_recvmsg_mskq().

Corresponding to tcp_recv_skb(), a new helper for MPTCP named
mptcp_recv_skb() is added to peek a skb from sk->sk_receive_queue.

Compared with __mptcp_recvmsg_mskq(), mptcp_read_sock() uses
sk->sk_rcvbuf as the max read length. The LISTEN status is checked
before the while loop, and mptcp_recv_skb() and mptcp_cleanup_rbuf()
are invoked after the loop. In the loop, all flags checks for
__mptcp_recvmsg_mskq() are removed.

Reviewed-by: Hannes Reinecke <hare@kernel.org>
Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn>
Reviewed-by: Mat Martineau <martineau@kernel.org>
Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org>
Link: https://patch.msgid.link/20260130-net-next-mptcp-splice-v2-2-31332ba70d7f@kernel.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Geliang Tang 2026-01-30 20:24:25 +01:00 committed by Jakub Kicinski
parent 436510df0c
commit 250d9766a9

View File

@ -4317,6 +4317,86 @@ static __poll_t mptcp_poll(struct file *file, struct socket *sock,
return mask;
}
static struct sk_buff *mptcp_recv_skb(struct sock *sk, u32 *off)
{
struct mptcp_sock *msk = mptcp_sk(sk);
struct sk_buff *skb;
u32 offset;
if (!list_empty(&msk->backlog_list))
mptcp_move_skbs(sk);
while ((skb = skb_peek(&sk->sk_receive_queue)) != NULL) {
offset = MPTCP_SKB_CB(skb)->offset;
if (offset < skb->len) {
*off = offset;
return skb;
}
mptcp_eat_recv_skb(sk, skb);
}
return NULL;
}
/*
* Note:
* - It is assumed that the socket was locked by the caller.
*/
static int __mptcp_read_sock(struct sock *sk, read_descriptor_t *desc,
sk_read_actor_t recv_actor, bool noack)
{
struct mptcp_sock *msk = mptcp_sk(sk);
struct sk_buff *skb;
int copied = 0;
u32 offset;
msk_owned_by_me(msk);
if (sk->sk_state == TCP_LISTEN)
return -ENOTCONN;
while ((skb = mptcp_recv_skb(sk, &offset)) != NULL) {
u32 data_len = skb->len - offset;
int count;
u32 size;
size = min_t(size_t, data_len, INT_MAX);
count = recv_actor(desc, skb, offset, size);
if (count <= 0) {
if (!copied)
copied = count;
break;
}
copied += count;
msk->bytes_consumed += count;
if (count < data_len) {
MPTCP_SKB_CB(skb)->offset += count;
MPTCP_SKB_CB(skb)->map_seq += count;
break;
}
mptcp_eat_recv_skb(sk, skb);
}
if (noack)
goto out;
mptcp_rcv_space_adjust(msk, copied);
if (copied > 0) {
mptcp_recv_skb(sk, &offset);
mptcp_cleanup_rbuf(msk, copied);
}
out:
return copied;
}
static int mptcp_read_sock(struct sock *sk, read_descriptor_t *desc,
sk_read_actor_t recv_actor)
{
return __mptcp_read_sock(sk, desc, recv_actor, false);
}
static const struct proto_ops mptcp_stream_ops = {
.family = PF_INET,
.owner = THIS_MODULE,
@ -4337,6 +4417,7 @@ static const struct proto_ops mptcp_stream_ops = {
.recvmsg = inet_recvmsg,
.mmap = sock_no_mmap,
.set_rcvlowat = mptcp_set_rcvlowat,
.read_sock = mptcp_read_sock,
};
static struct inet_protosw mptcp_protosw = {
@ -4441,6 +4522,7 @@ static const struct proto_ops mptcp_v6_stream_ops = {
.compat_ioctl = inet6_compat_ioctl,
#endif
.set_rcvlowat = mptcp_set_rcvlowat,
.read_sock = mptcp_read_sock,
};
static struct proto mptcp_v6_prot;