[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20250322203558.206411-3-jdamato@fastly.com>
Date: Sat, 22 Mar 2025 20:35:45 +0000
From: Joe Damato <jdamato@...tly.com>
To: linux-fsdevel@...r.kernel.org
Cc: netdev@...r.kernel.org,
brauner@...nel.org,
asml.silence@...il.com,
hch@...radead.org,
axboe@...nel.dk,
edumazet@...gle.com,
kuba@...nel.org,
pabeni@...hat.com,
horms@...nel.org,
Joe Damato <jdamato@...tly.com>,
Alexander Viro <viro@...iv.linux.org.uk>,
Jan Kara <jack@...e.cz>,
"David S. Miller" <davem@...emloft.net>,
linux-kernel@...r.kernel.org (open list)
Subject: [PATCH vfs/for-next 2/3] splice: Move splice_to_socket to net/socket.c
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@...tly.com>
---
fs/splice.c | 140 -----------------------------------------
include/linux/splice.h | 3 -
net/socket.c | 140 +++++++++++++++++++++++++++++++++++++++++
3 files changed, 140 insertions(+), 143 deletions(-)
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;
+}
--
2.43.0
Powered by blists - more mailing lists