[PATCH mptcp-next v15 4/6] mptcp: implement .splice_read

Geliang Tang posted 6 patches 2 months ago
[PATCH mptcp-next v15 4/6] mptcp: implement .splice_read
Posted by Geliang Tang 2 months ago
From: Geliang Tang <tanggeliang@kylinos.cn>

This patch implements .splice_read interface of mptcp struct proto_ops
as mptcp_splice_read() with reference to tcp_splice_read().

Corresponding to __tcp_splice_read(), __mptcp_splice_read() is defined,
invoking mptcp_read_sock() instead of tcp_read_sock().

mptcp_splice_read() is almost the same as tcp_splice_read(), except for
sock_rps_record_flow().

Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn>
---
 net/mptcp/protocol.c | 114 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 114 insertions(+)

diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c
index 01d602f0d556..334fdb10fdf3 100644
--- a/net/mptcp/protocol.c
+++ b/net/mptcp/protocol.c
@@ -4402,6 +4402,118 @@ static int mptcp_read_sock(struct sock *sk, read_descriptor_t *desc,
 	return __mptcp_read_sock(sk, desc, recv_actor, false);
 }
 
+static int __mptcp_splice_read(struct sock *sk, struct tcp_splice_state *tss)
+{
+	/* Store TCP splice context information in read_descriptor_t. */
+	read_descriptor_t rd_desc = {
+		.arg.data = tss,
+		.count	  = tss->len,
+	};
+
+	return mptcp_read_sock(sk, &rd_desc, tcp_splice_data_recv);
+}
+
+/**
+ *  mptcp_splice_read - splice data from MPTCP socket to a pipe
+ * @sock:	socket to splice from
+ * @ppos:	position (not valid)
+ * @pipe:	pipe to splice to
+ * @len:	number of bytes to splice
+ * @flags:	splice modifier flags
+ *
+ * Description:
+ *    Will read pages from given socket and fill them into a pipe.
+ *
+ **/
+static ssize_t mptcp_splice_read(struct socket *sock, loff_t *ppos,
+				 struct pipe_inode_info *pipe, size_t len,
+				 unsigned int flags)
+{
+	struct tcp_splice_state tss = {
+		.pipe	= pipe,
+		.len	= len,
+		.flags	= flags,
+	};
+	struct sock *sk = sock->sk;
+	ssize_t spliced = 0;
+	int ret = 0;
+	long timeo;
+
+	/*
+	 * We can't seek on a socket input
+	 */
+	if (unlikely(*ppos))
+		return -ESPIPE;
+
+	lock_sock(sk);
+
+	mptcp_rps_record_subflows(mptcp_sk(sk));
+
+	timeo = sock_rcvtimeo(sk, sock->file->f_flags & O_NONBLOCK);
+	while (tss.len) {
+		ret = __mptcp_splice_read(sk, &tss);
+		if (ret < 0) {
+			break;
+		} else if (!ret) {
+			if (spliced)
+				break;
+			if (sock_flag(sk, SOCK_DONE))
+				break;
+			if (sk->sk_err) {
+				ret = sock_error(sk);
+				break;
+			}
+			if (sk->sk_shutdown & RCV_SHUTDOWN)
+				break;
+			if (sk->sk_state == TCP_CLOSE) {
+				/*
+				 * This occurs when user tries to read
+				 * from never connected socket.
+				 */
+				ret = -ENOTCONN;
+				break;
+			}
+			if (!timeo) {
+				ret = -EAGAIN;
+				break;
+			}
+			/* if __mptcp_splice_read() got nothing while we have
+			 * an skb in receive queue, we do not want to loop.
+			 * This might happen with URG data.
+			 */
+			if (!skb_queue_empty(&sk->sk_receive_queue))
+				break;
+			ret = sk_wait_data(sk, &timeo, NULL);
+			if (ret < 0)
+				break;
+			if (signal_pending(current)) {
+				ret = sock_intr_errno(timeo);
+				break;
+			}
+			continue;
+		}
+		tss.len -= ret;
+		spliced += ret;
+
+		if (!tss.len || !timeo)
+			break;
+		release_sock(sk);
+		lock_sock(sk);
+
+		if (sk->sk_err || sk->sk_state == TCP_CLOSE ||
+		    (sk->sk_shutdown & RCV_SHUTDOWN) ||
+		    signal_pending(current))
+			break;
+	}
+
+	release_sock(sk);
+
+	if (spliced)
+		return spliced;
+
+	return ret;
+}
+
 static const struct proto_ops mptcp_stream_ops = {
 	.family		   = PF_INET,
 	.owner		   = THIS_MODULE,
@@ -4423,6 +4535,7 @@ static const struct proto_ops mptcp_stream_ops = {
 	.mmap		   = sock_no_mmap,
 	.set_rcvlowat	   = mptcp_set_rcvlowat,
 	.read_sock	   = mptcp_read_sock,
+	.splice_read	   = mptcp_splice_read,
 };
 
 static struct inet_protosw mptcp_protosw = {
@@ -4528,6 +4641,7 @@ static const struct proto_ops mptcp_v6_stream_ops = {
 #endif
 	.set_rcvlowat	   = mptcp_set_rcvlowat,
 	.read_sock	   = mptcp_read_sock,
+	.splice_read	   = mptcp_splice_read,
 };
 
 static struct proto mptcp_v6_prot;
-- 
2.51.0
Re: [PATCH mptcp-next v15 4/6] mptcp: implement .splice_read
Posted by Matthieu Baerts 1 week, 3 days ago
Hi Geliang,

On 06/12/2025 13:33, Geliang Tang wrote:
> From: Geliang Tang <tanggeliang@kylinos.cn>
> 
> This patch implements .splice_read interface of mptcp struct proto_ops
> as mptcp_splice_read() with reference to tcp_splice_read().
> 
> Corresponding to __tcp_splice_read(), __mptcp_splice_read() is defined,
> invoking mptcp_read_sock() instead of tcp_read_sock().
> 
> mptcp_splice_read() is almost the same as tcp_splice_read(), except for
> sock_rps_record_flow().

(...)

> diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c
> index 01d602f0d556..334fdb10fdf3 100644
> --- a/net/mptcp/protocol.c
> +++ b/net/mptcp/protocol.c

(...)

> @@ -4423,6 +4535,7 @@ static const struct proto_ops mptcp_stream_ops = {
>  	.mmap		   = sock_no_mmap,
>  	.set_rcvlowat	   = mptcp_set_rcvlowat,
>  	.read_sock	   = mptcp_read_sock,
> +	.splice_read	   = mptcp_splice_read,

When looking at this patch in more details (after the issue with kdoc),
I was wondering: is it not needed to also implement .splice_eof, similar
to tcp_splice_eof()?

Cheers,
Matt
-- 
Sponsored by the NGI0 Core fund.
Re: [PATCH mptcp-next v15 4/6] mptcp: implement .splice_read
Posted by Geliang Tang 1 week, 2 days ago
Hi Matt,

On Fri, 2026-01-30 at 08:19 +0100, Matthieu Baerts wrote:
> Hi Geliang,
> 
> On 06/12/2025 13:33, Geliang Tang wrote:
> > From: Geliang Tang <tanggeliang@kylinos.cn>
> > 
> > This patch implements .splice_read interface of mptcp struct
> > proto_ops
> > as mptcp_splice_read() with reference to tcp_splice_read().
> > 
> > Corresponding to __tcp_splice_read(), __mptcp_splice_read() is
> > defined,
> > invoking mptcp_read_sock() instead of tcp_read_sock().
> > 
> > mptcp_splice_read() is almost the same as tcp_splice_read(), except
> > for
> > sock_rps_record_flow().
> 
> (...)
> 
> > diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c
> > index 01d602f0d556..334fdb10fdf3 100644
> > --- a/net/mptcp/protocol.c
> > +++ b/net/mptcp/protocol.c
> 
> (...)
> 
> > @@ -4423,6 +4535,7 @@ static const struct proto_ops
> > mptcp_stream_ops = {
> >  	.mmap		   = sock_no_mmap,
> >  	.set_rcvlowat	   = mptcp_set_rcvlowat,
> >  	.read_sock	   = mptcp_read_sock,
> > +	.splice_read	   = mptcp_splice_read,
> 
> When looking at this patch in more details (after the issue with
> kdoc),
> I was wondering: is it not needed to also implement .splice_eof,
> similar
> to tcp_splice_eof()?

Thanks for the reminder, I'll try to implement mptcp_splice_eof later.

-Geliang

> 
> Cheers,
> Matt
Re: [PATCH mptcp-next v15 4/6] mptcp: implement .splice_read
Posted by Matthieu Baerts 1 week, 2 days ago
Hi Matt,

On 30/01/2026 14:54, Geliang Tang wrote:
> Hi Matt,
> 
> On Fri, 2026-01-30 at 08:19 +0100, Matthieu Baerts wrote:
>> Hi Geliang,
>>
>> On 06/12/2025 13:33, Geliang Tang wrote:
>>> From: Geliang Tang <tanggeliang@kylinos.cn>
>>>
>>> This patch implements .splice_read interface of mptcp struct
>>> proto_ops
>>> as mptcp_splice_read() with reference to tcp_splice_read().
>>>
>>> Corresponding to __tcp_splice_read(), __mptcp_splice_read() is
>>> defined,
>>> invoking mptcp_read_sock() instead of tcp_read_sock().
>>>
>>> mptcp_splice_read() is almost the same as tcp_splice_read(), except
>>> for
>>> sock_rps_record_flow().
>>
>> (...)
>>
>>> diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c
>>> index 01d602f0d556..334fdb10fdf3 100644
>>> --- a/net/mptcp/protocol.c
>>> +++ b/net/mptcp/protocol.c
>>
>> (...)
>>
>>> @@ -4423,6 +4535,7 @@ static const struct proto_ops
>>> mptcp_stream_ops = {
>>>  	.mmap		   = sock_no_mmap,
>>>  	.set_rcvlowat	   = mptcp_set_rcvlowat,
>>>  	.read_sock	   = mptcp_read_sock,
>>> +	.splice_read	   = mptcp_splice_read,
>>
>> When looking at this patch in more details (after the issue with
>> kdoc),
>> I was wondering: is it not needed to also implement .splice_eof,
>> similar
>> to tcp_splice_eof()?
> 
> Thanks for the reminder, I'll try to implement mptcp_splice_eof later.

Thank you!

I didn't check (yet), but do you know when it is used and what happens
if splice is used, but this interface is not implemented on MPTCP side?
Are there issues with the current implementation?

Cheers,
Matt
-- 
Sponsored by the NGI0 Core fund.