Skip to content

Commit 2dc334f

Browse files
dhowellskuba-moo
authored andcommitted
splice, net: Use sendmsg(MSG_SPLICE_PAGES) rather than ->sendpage()
Replace generic_splice_sendpage() + splice_from_pipe + pipe_to_sendpage() with a net-specific handler, splice_to_socket(), that calls sendmsg() with MSG_SPLICE_PAGES set instead of calling ->sendpage(). MSG_MORE is used to indicate if the sendmsg() is expected to be followed with more data. This allows multiple pipe-buffer pages to be passed in a single call in a BVEC iterator, allowing the processing to be pushed down to a loop in the protocol driver. This helps pave the way for passing multipage folios down too. Protocols that haven't been converted to handle MSG_SPLICE_PAGES yet should just ignore it and do a normal sendmsg() for now - although that may be a bit slower as it may copy everything. Signed-off-by: David Howells <[email protected]> Reviewed-by: Jakub Kicinski <[email protected]> cc: Jens Axboe <[email protected]> cc: Matthew Wilcox <[email protected]> Signed-off-by: Jakub Kicinski <[email protected]>
1 parent 81840b3 commit 2dc334f

File tree

4 files changed

+131
-57
lines changed

4 files changed

+131
-57
lines changed

fs/splice.c

Lines changed: 127 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#include <linux/fsnotify.h>
3434
#include <linux/security.h>
3535
#include <linux/gfp.h>
36+
#include <linux/net.h>
3637
#include <linux/socket.h>
3738
#include <linux/sched/signal.h>
3839

@@ -448,30 +449,6 @@ const struct pipe_buf_operations nosteal_pipe_buf_ops = {
448449
};
449450
EXPORT_SYMBOL(nosteal_pipe_buf_ops);
450451

451-
/*
452-
* Send 'sd->len' bytes to socket from 'sd->file' at position 'sd->pos'
453-
* using sendpage(). Return the number of bytes sent.
454-
*/
455-
static int pipe_to_sendpage(struct pipe_inode_info *pipe,
456-
struct pipe_buffer *buf, struct splice_desc *sd)
457-
{
458-
struct file *file = sd->u.file;
459-
loff_t pos = sd->pos;
460-
int more;
461-
462-
if (!likely(file->f_op->sendpage))
463-
return -EINVAL;
464-
465-
more = (sd->flags & SPLICE_F_MORE) ? MSG_MORE : 0;
466-
467-
if (sd->len < sd->total_len &&
468-
pipe_occupancy(pipe->head, pipe->tail) > 1)
469-
more |= MSG_SENDPAGE_NOTLAST;
470-
471-
return file->f_op->sendpage(file, buf->page, buf->offset,
472-
sd->len, &pos, more);
473-
}
474-
475452
static void wakeup_pipe_writers(struct pipe_inode_info *pipe)
476453
{
477454
smp_mb();
@@ -652,7 +629,7 @@ static void splice_from_pipe_end(struct pipe_inode_info *pipe, struct splice_des
652629
* Description:
653630
* This function does little more than loop over the pipe and call
654631
* @actor to do the actual moving of a single struct pipe_buffer to
655-
* the desired destination. See pipe_to_file, pipe_to_sendpage, or
632+
* the desired destination. See pipe_to_file, pipe_to_sendmsg, or
656633
* pipe_to_user.
657634
*
658635
*/
@@ -833,8 +810,9 @@ iter_file_splice_write(struct pipe_inode_info *pipe, struct file *out,
833810

834811
EXPORT_SYMBOL(iter_file_splice_write);
835812

813+
#ifdef CONFIG_NET
836814
/**
837-
* generic_splice_sendpage - splice data from a pipe to a socket
815+
* splice_to_socket - splice data from a pipe to a socket
838816
* @pipe: pipe to splice from
839817
* @out: socket to write to
840818
* @ppos: position in @out
@@ -846,13 +824,131 @@ EXPORT_SYMBOL(iter_file_splice_write);
846824
* is involved.
847825
*
848826
*/
849-
ssize_t generic_splice_sendpage(struct pipe_inode_info *pipe, struct file *out,
850-
loff_t *ppos, size_t len, unsigned int flags)
827+
ssize_t splice_to_socket(struct pipe_inode_info *pipe, struct file *out,
828+
loff_t *ppos, size_t len, unsigned int flags)
851829
{
852-
return splice_from_pipe(pipe, out, ppos, len, flags, pipe_to_sendpage);
853-
}
830+
struct socket *sock = sock_from_file(out);
831+
struct bio_vec bvec[16];
832+
struct msghdr msg = {};
833+
ssize_t ret = 0;
834+
size_t spliced = 0;
835+
bool need_wakeup = false;
836+
837+
pipe_lock(pipe);
838+
839+
while (len > 0) {
840+
unsigned int head, tail, mask, bc = 0;
841+
size_t remain = len;
842+
843+
/*
844+
* Check for signal early to make process killable when there
845+
* are always buffers available
846+
*/
847+
ret = -ERESTARTSYS;
848+
if (signal_pending(current))
849+
break;
854850

855-
EXPORT_SYMBOL(generic_splice_sendpage);
851+
while (pipe_empty(pipe->head, pipe->tail)) {
852+
ret = 0;
853+
if (!pipe->writers)
854+
goto out;
855+
856+
if (spliced)
857+
goto out;
858+
859+
ret = -EAGAIN;
860+
if (flags & SPLICE_F_NONBLOCK)
861+
goto out;
862+
863+
ret = -ERESTARTSYS;
864+
if (signal_pending(current))
865+
goto out;
866+
867+
if (need_wakeup) {
868+
wakeup_pipe_writers(pipe);
869+
need_wakeup = false;
870+
}
871+
872+
pipe_wait_readable(pipe);
873+
}
874+
875+
head = pipe->head;
876+
tail = pipe->tail;
877+
mask = pipe->ring_size - 1;
878+
879+
while (!pipe_empty(head, tail)) {
880+
struct pipe_buffer *buf = &pipe->bufs[tail & mask];
881+
size_t seg;
882+
883+
if (!buf->len) {
884+
tail++;
885+
continue;
886+
}
887+
888+
seg = min_t(size_t, remain, buf->len);
889+
seg = min_t(size_t, seg, PAGE_SIZE);
890+
891+
ret = pipe_buf_confirm(pipe, buf);
892+
if (unlikely(ret)) {
893+
if (ret == -ENODATA)
894+
ret = 0;
895+
break;
896+
}
897+
898+
bvec_set_page(&bvec[bc++], buf->page, seg, buf->offset);
899+
remain -= seg;
900+
if (seg >= buf->len)
901+
tail++;
902+
if (bc >= ARRAY_SIZE(bvec))
903+
break;
904+
}
905+
906+
if (!bc)
907+
break;
908+
909+
msg.msg_flags = MSG_SPLICE_PAGES;
910+
if (flags & SPLICE_F_MORE)
911+
msg.msg_flags |= MSG_MORE;
912+
if (remain && pipe_occupancy(pipe->head, tail) > 0)
913+
msg.msg_flags |= MSG_MORE;
914+
915+
iov_iter_bvec(&msg.msg_iter, ITER_SOURCE, bvec, bc,
916+
len - remain);
917+
ret = sock_sendmsg(sock, &msg);
918+
if (ret <= 0)
919+
break;
920+
921+
spliced += ret;
922+
len -= ret;
923+
tail = pipe->tail;
924+
while (ret > 0) {
925+
struct pipe_buffer *buf = &pipe->bufs[tail & mask];
926+
size_t seg = min_t(size_t, ret, buf->len);
927+
928+
buf->offset += seg;
929+
buf->len -= seg;
930+
ret -= seg;
931+
932+
if (!buf->len) {
933+
pipe_buf_release(pipe, buf);
934+
tail++;
935+
}
936+
}
937+
938+
if (tail != pipe->tail) {
939+
pipe->tail = tail;
940+
if (pipe->files)
941+
need_wakeup = true;
942+
}
943+
}
944+
945+
out:
946+
pipe_unlock(pipe);
947+
if (need_wakeup)
948+
wakeup_pipe_writers(pipe);
949+
return spliced ?: ret;
950+
}
951+
#endif
856952

857953
static int warn_unsupported(struct file *file, const char *op)
858954
{

include/linux/fs.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2759,8 +2759,6 @@ extern ssize_t generic_file_splice_read(struct file *, loff_t *,
27592759
struct pipe_inode_info *, size_t, unsigned int);
27602760
extern ssize_t iter_file_splice_write(struct pipe_inode_info *,
27612761
struct file *, loff_t *, size_t, unsigned int);
2762-
extern ssize_t generic_splice_sendpage(struct pipe_inode_info *pipe,
2763-
struct file *out, loff_t *, size_t len, unsigned int flags);
27642762
extern long do_splice_direct(struct file *in, loff_t *ppos, struct file *out,
27652763
loff_t *opos, size_t len, unsigned int flags);
27662764

include/linux/splice.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,8 @@ extern long do_splice(struct file *in, loff_t *off_in,
8484

8585
extern long do_tee(struct file *in, struct file *out, size_t len,
8686
unsigned int flags);
87+
extern ssize_t splice_to_socket(struct pipe_inode_info *pipe, struct file *out,
88+
loff_t *ppos, size_t len, unsigned int flags);
8789

8890
/*
8991
* for dynamic pipe sizing

net/socket.c

Lines changed: 2 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
#include <linux/mm.h>
5858
#include <linux/socket.h>
5959
#include <linux/file.h>
60+
#include <linux/splice.h>
6061
#include <linux/net.h>
6162
#include <linux/interrupt.h>
6263
#include <linux/thread_info.h>
@@ -126,8 +127,6 @@ static long compat_sock_ioctl(struct file *file,
126127
unsigned int cmd, unsigned long arg);
127128
#endif
128129
static int sock_fasync(int fd, struct file *filp, int on);
129-
static ssize_t sock_sendpage(struct file *file, struct page *page,
130-
int offset, size_t size, loff_t *ppos, int more);
131130
static ssize_t sock_splice_read(struct file *file, loff_t *ppos,
132131
struct pipe_inode_info *pipe, size_t len,
133132
unsigned int flags);
@@ -162,8 +161,7 @@ static const struct file_operations socket_file_ops = {
162161
.mmap = sock_mmap,
163162
.release = sock_close,
164163
.fasync = sock_fasync,
165-
.sendpage = sock_sendpage,
166-
.splice_write = generic_splice_sendpage,
164+
.splice_write = splice_to_socket,
167165
.splice_read = sock_splice_read,
168166
.show_fdinfo = sock_show_fdinfo,
169167
};
@@ -1066,26 +1064,6 @@ int kernel_recvmsg(struct socket *sock, struct msghdr *msg,
10661064
}
10671065
EXPORT_SYMBOL(kernel_recvmsg);
10681066

1069-
static ssize_t sock_sendpage(struct file *file, struct page *page,
1070-
int offset, size_t size, loff_t *ppos, int more)
1071-
{
1072-
struct socket *sock;
1073-
int flags;
1074-
int ret;
1075-
1076-
sock = file->private_data;
1077-
1078-
flags = (file->f_flags & O_NONBLOCK) ? MSG_DONTWAIT : 0;
1079-
/* more is a combination of MSG_MORE and MSG_SENDPAGE_NOTLAST */
1080-
flags |= more;
1081-
1082-
ret = kernel_sendpage(sock, page, offset, size, flags);
1083-
1084-
if (trace_sock_send_length_enabled())
1085-
call_trace_sock_send_length(sock->sk, ret, 0);
1086-
return ret;
1087-
}
1088-
10891067
static ssize_t sock_splice_read(struct file *file, loff_t *ppos,
10901068
struct pipe_inode_info *pipe, size_t len,
10911069
unsigned int flags)

0 commit comments

Comments
 (0)