diff mbox series

[vfs/for-next,2/3] splice: Move splice_to_socket to net/socket.c

Message ID 20250322203558.206411-3-jdamato@fastly.com (mailing list archive)
State Not Applicable
Delegated to: Netdev Maintainers
Headers show
Series Move splice_to_socket to net/socket.c | expand

Checks

Context Check Description
netdev/tree_selection success Guessing tree name failed - patch did not apply

Commit Message

Joe Damato March 22, 2025, 8:35 p.m. UTC
Eliminate the #ifdef CONFIG_NET from fs/splice.c and move the
splice_to_socket helper to net/socket.c, where the other splice socket
helpers live (like sock_splice_read and sock_splice_eof).

Signed-off-by: Joe Damato <jdamato@fastly.com>
---
 fs/splice.c            | 140 -----------------------------------------
 include/linux/splice.h |   3 -
 net/socket.c           | 140 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 140 insertions(+), 143 deletions(-)

Comments

Jakub Kicinski March 24, 2025, 9:15 p.m. UTC | #1
On Sat, 22 Mar 2025 20:35:45 +0000 Joe Damato wrote:
> Eliminate the #ifdef CONFIG_NET from fs/splice.c and move the
> splice_to_socket helper to net/socket.c, where the other splice socket
> helpers live (like sock_splice_read and sock_splice_eof).
> 
> Signed-off-by: Joe Damato <jdamato@fastly.com>

Matter of preference, to some extent, but FWIW:

Acked-by: Jakub Kicinski <kuba@kernel.org>
Joe Damato March 24, 2025, 10:53 p.m. UTC | #2
On Mon, Mar 24, 2025 at 02:15:26PM -0700, Jakub Kicinski wrote:
> On Sat, 22 Mar 2025 20:35:45 +0000 Joe Damato wrote:
> > Eliminate the #ifdef CONFIG_NET from fs/splice.c and move the
> > splice_to_socket helper to net/socket.c, where the other splice socket
> > helpers live (like sock_splice_read and sock_splice_eof).
> > 
> > Signed-off-by: Joe Damato <jdamato@fastly.com>
> 
> Matter of preference, to some extent, but FWIW:
> 
> Acked-by: Jakub Kicinski <kuba@kernel.org>

Thanks for the ACK.

It looks like Jens thinks maybe the code should stay where it is and
given that it might be more "splice related" than networking, it may
be better after all to leave it where it is.

In which case, my apologies for the noise.
Christian Brauner March 25, 2025, 2:40 p.m. UTC | #3
On Mon, Mar 24, 2025 at 03:53:23PM -0700, Joe Damato wrote:
> On Mon, Mar 24, 2025 at 02:15:26PM -0700, Jakub Kicinski wrote:
> > On Sat, 22 Mar 2025 20:35:45 +0000 Joe Damato wrote:
> > > Eliminate the #ifdef CONFIG_NET from fs/splice.c and move the
> > > splice_to_socket helper to net/socket.c, where the other splice socket
> > > helpers live (like sock_splice_read and sock_splice_eof).
> > > 
> > > Signed-off-by: Joe Damato <jdamato@fastly.com>
> > 
> > Matter of preference, to some extent, but FWIW:
> > 
> > Acked-by: Jakub Kicinski <kuba@kernel.org>
> 
> Thanks for the ACK.
> 
> It looks like Jens thinks maybe the code should stay where it is and
> given that it might be more "splice related" than networking, it may

Uhm, it should stay in fs/ especially since it's closely tied to
pipe_lock().
diff mbox series

Patch

diff --git a/fs/splice.c b/fs/splice.c
index dcd594a8fc06..40b96387a515 100644
--- a/fs/splice.c
+++ b/fs/splice.c
@@ -766,146 +766,6 @@  iter_file_splice_write(struct pipe_inode_info *pipe, struct file *out,
 
 EXPORT_SYMBOL(iter_file_splice_write);
 
-#ifdef CONFIG_NET
-/**
- * splice_to_socket - splice data from a pipe to a socket
- * @pipe:	pipe to splice from
- * @out:	socket to write to
- * @ppos:	position in @out
- * @len:	number of bytes to splice
- * @flags:	splice modifier flags
- *
- * Description:
- *    Will send @len bytes from the pipe to a network socket. No data copying
- *    is involved.
- *
- */
-ssize_t splice_to_socket(struct pipe_inode_info *pipe, struct file *out,
-			 loff_t *ppos, size_t len, unsigned int flags)
-{
-	struct socket *sock = sock_from_file(out);
-	struct bio_vec bvec[16];
-	struct msghdr msg = {};
-	ssize_t ret = 0;
-	size_t spliced = 0;
-	bool need_wakeup = false;
-
-	pipe_lock(pipe);
-
-	while (len > 0) {
-		unsigned int head, tail, mask, bc = 0;
-		size_t remain = len;
-
-		/*
-		 * Check for signal early to make process killable when there
-		 * are always buffers available
-		 */
-		ret = -ERESTARTSYS;
-		if (signal_pending(current))
-			break;
-
-		while (pipe_empty(pipe->head, pipe->tail)) {
-			ret = 0;
-			if (!pipe->writers)
-				goto out;
-
-			if (spliced)
-				goto out;
-
-			ret = -EAGAIN;
-			if (flags & SPLICE_F_NONBLOCK)
-				goto out;
-
-			ret = -ERESTARTSYS;
-			if (signal_pending(current))
-				goto out;
-
-			if (need_wakeup) {
-				pipe_wakeup_writers(pipe);
-				need_wakeup = false;
-			}
-
-			pipe_wait_readable(pipe);
-		}
-
-		head = pipe->head;
-		tail = pipe->tail;
-		mask = pipe->ring_size - 1;
-
-		while (!pipe_empty(head, tail)) {
-			struct pipe_buffer *buf = &pipe->bufs[tail & mask];
-			size_t seg;
-
-			if (!buf->len) {
-				tail++;
-				continue;
-			}
-
-			seg = min_t(size_t, remain, buf->len);
-
-			ret = pipe_buf_confirm(pipe, buf);
-			if (unlikely(ret)) {
-				if (ret == -ENODATA)
-					ret = 0;
-				break;
-			}
-
-			bvec_set_page(&bvec[bc++], buf->page, seg, buf->offset);
-			remain -= seg;
-			if (remain == 0 || bc >= ARRAY_SIZE(bvec))
-				break;
-			tail++;
-		}
-
-		if (!bc)
-			break;
-
-		msg.msg_flags = MSG_SPLICE_PAGES;
-		if (flags & SPLICE_F_MORE)
-			msg.msg_flags |= MSG_MORE;
-		if (remain && pipe_occupancy(pipe->head, tail) > 0)
-			msg.msg_flags |= MSG_MORE;
-		if (out->f_flags & O_NONBLOCK)
-			msg.msg_flags |= MSG_DONTWAIT;
-
-		iov_iter_bvec(&msg.msg_iter, ITER_SOURCE, bvec, bc,
-			      len - remain);
-		ret = sock_sendmsg(sock, &msg);
-		if (ret <= 0)
-			break;
-
-		spliced += ret;
-		len -= ret;
-		tail = pipe->tail;
-		while (ret > 0) {
-			struct pipe_buffer *buf = &pipe->bufs[tail & mask];
-			size_t seg = min_t(size_t, ret, buf->len);
-
-			buf->offset += seg;
-			buf->len -= seg;
-			ret -= seg;
-
-			if (!buf->len) {
-				pipe_buf_release(pipe, buf);
-				tail++;
-			}
-		}
-
-		if (tail != pipe->tail) {
-			pipe->tail = tail;
-			if (pipe->files)
-				need_wakeup = true;
-		}
-	}
-
-out:
-	pipe_unlock(pipe);
-	if (need_wakeup)
-		pipe_wakeup_writers(pipe);
-	return spliced ?: ret;
-}
-#endif
-
 static int warn_unsupported(struct file *file, const char *op)
 {
 	pr_debug_ratelimited(
diff --git a/include/linux/splice.h b/include/linux/splice.h
index 9dec4861d09f..54c47776469d 100644
--- a/include/linux/splice.h
+++ b/include/linux/splice.h
@@ -97,9 +97,6 @@  static inline long splice_copy_file_range(struct file *in, loff_t pos_in,
 
 ssize_t do_tee(struct file *in, struct file *out, size_t len,
 	       unsigned int flags);
-ssize_t splice_to_socket(struct pipe_inode_info *pipe, struct file *out,
-			 loff_t *ppos, size_t len, unsigned int flags);
-
 /*
  * for dynamic pipe sizing
  */
diff --git a/net/socket.c b/net/socket.c
index 9a117248f18f..2640b42cf320 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -132,6 +132,8 @@  static ssize_t sock_splice_read(struct file *file, loff_t *ppos,
 				struct pipe_inode_info *pipe, size_t len,
 				unsigned int flags);
 static void sock_splice_eof(struct file *file);
+static ssize_t splice_to_socket(struct pipe_inode_info *pipe, struct file *out,
+				loff_t *ppos, size_t len, unsigned int flags);
 
 #ifdef CONFIG_PROC_FS
 static void sock_show_fdinfo(struct seq_file *m, struct file *f)
@@ -3719,3 +3721,141 @@  u32 kernel_sock_ip_overhead(struct sock *sk)
 	}
 }
 EXPORT_SYMBOL(kernel_sock_ip_overhead);
+
+/**
+ * splice_to_socket - splice data from a pipe to a socket
+ * @pipe:	pipe to splice from
+ * @out:	socket to write to
+ * @ppos:	position in @out
+ * @len:	number of bytes to splice
+ * @flags:	splice modifier flags
+ *
+ * Description:
+ *    Will send @len bytes from the pipe to a network socket. No data copying
+ *    is involved.
+ *
+ */
+static ssize_t splice_to_socket(struct pipe_inode_info *pipe, struct file *out,
+				loff_t *ppos, size_t len, unsigned int flags)
+{
+	struct socket *sock = sock_from_file(out);
+	struct bio_vec bvec[16];
+	struct msghdr msg = {};
+	ssize_t ret = 0;
+	size_t spliced = 0;
+	bool need_wakeup = false;
+
+	pipe_lock(pipe);
+
+	while (len > 0) {
+		unsigned int head, tail, mask, bc = 0;
+		size_t remain = len;
+
+		/*
+		 * Check for signal early to make process killable when there
+		 * are always buffers available
+		 */
+		ret = -ERESTARTSYS;
+		if (signal_pending(current))
+			break;
+
+		while (pipe_empty(pipe->head, pipe->tail)) {
+			ret = 0;
+			if (!pipe->writers)
+				goto out;
+
+			if (spliced)
+				goto out;
+
+			ret = -EAGAIN;
+			if (flags & SPLICE_F_NONBLOCK)
+				goto out;
+
+			ret = -ERESTARTSYS;
+			if (signal_pending(current))
+				goto out;
+
+			if (need_wakeup) {
+				pipe_wakeup_writers(pipe);
+				need_wakeup = false;
+			}
+
+			pipe_wait_readable(pipe);
+		}
+
+		head = pipe->head;
+		tail = pipe->tail;
+		mask = pipe->ring_size - 1;
+
+		while (!pipe_empty(head, tail)) {
+			struct pipe_buffer *buf = &pipe->bufs[tail & mask];
+			size_t seg;
+
+			if (!buf->len) {
+				tail++;
+				continue;
+			}
+
+			seg = min_t(size_t, remain, buf->len);
+
+			ret = pipe_buf_confirm(pipe, buf);
+			if (unlikely(ret)) {
+				if (ret == -ENODATA)
+					ret = 0;
+				break;
+			}
+
+			bvec_set_page(&bvec[bc++], buf->page, seg, buf->offset);
+			remain -= seg;
+			if (remain == 0 || bc >= ARRAY_SIZE(bvec))
+				break;
+			tail++;
+		}
+
+		if (!bc)
+			break;
+
+		msg.msg_flags = MSG_SPLICE_PAGES;
+		if (flags & SPLICE_F_MORE)
+			msg.msg_flags |= MSG_MORE;
+		if (remain && pipe_occupancy(pipe->head, tail) > 0)
+			msg.msg_flags |= MSG_MORE;
+		if (out->f_flags & O_NONBLOCK)
+			msg.msg_flags |= MSG_DONTWAIT;
+
+		iov_iter_bvec(&msg.msg_iter, ITER_SOURCE, bvec, bc,
+			      len - remain);
+		ret = sock_sendmsg(sock, &msg);
+		if (ret <= 0)
+			break;
+
+		spliced += ret;
+		len -= ret;
+		tail = pipe->tail;
+		while (ret > 0) {
+			struct pipe_buffer *buf = &pipe->bufs[tail & mask];
+			size_t seg = min_t(size_t, ret, buf->len);
+
+			buf->offset += seg;
+			buf->len -= seg;
+			ret -= seg;
+
+			if (!buf->len) {
+				pipe_buf_release(pipe, buf);
+				tail++;
+			}
+		}
+
+		if (tail != pipe->tail) {
+			pipe->tail = tail;
+			if (pipe->files)
+				need_wakeup = true;
+		}
+	}
+
+out:
+	pipe_unlock(pipe);
+	if (need_wakeup)
+		pipe_wakeup_writers(pipe);
+	return spliced ?: ret;
+}