Skip to content

Commit 2bfc668

Browse files
dhowellskuba-moo
authored andcommitted
splice, net: Add a splice_eof op to file-ops and socket-ops
Add an optional method, ->splice_eof(), to allow splice to indicate the premature termination of a splice to struct file_operations and struct proto_ops. This is called if sendfile() or splice() encounters all of the following conditions inside splice_direct_to_actor(): (1) the user did not set SPLICE_F_MORE (splice only), and (2) an EOF condition occurred (->splice_read() returned 0), and (3) we haven't read enough to fulfill the request (ie. len > 0 still), and (4) we have already spliced at least one byte. A further patch will modify the behaviour of SPLICE_F_MORE to always be passed to the actor if either the user set it or we haven't yet read sufficient data to fulfill the request. Suggested-by: Linus Torvalds <[email protected]> Link: https://lore.kernel.org/r/CAHk-=wh=V579PDYvkpnTobCLGczbgxpMgGmmhqiTyE34Cpi5Gg@mail.gmail.com/ Signed-off-by: David Howells <[email protected]> Reviewed-by: Jakub Kicinski <[email protected]> cc: Jens Axboe <[email protected]> cc: Christoph Hellwig <[email protected]> cc: Al Viro <[email protected]> cc: Matthew Wilcox <[email protected]> cc: Jan Kara <[email protected]> cc: Jeff Layton <[email protected]> cc: David Hildenbrand <[email protected]> cc: Christian Brauner <[email protected]> cc: Chuck Lever <[email protected]> cc: Boris Pismenny <[email protected]> cc: John Fastabend <[email protected]> cc: [email protected] Signed-off-by: Jakub Kicinski <[email protected]>
1 parent 2dc334f commit 2bfc668

File tree

6 files changed

+44
-1
lines changed

6 files changed

+44
-1
lines changed

fs/splice.c

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -969,6 +969,17 @@ static long do_splice_from(struct pipe_inode_info *pipe, struct file *out,
969969
return out->f_op->splice_write(pipe, out, ppos, len, flags);
970970
}
971971

972+
/*
973+
* Indicate to the caller that there was a premature EOF when reading from the
974+
* source and the caller didn't indicate they would be sending more data after
975+
* this.
976+
*/
977+
static void do_splice_eof(struct splice_desc *sd)
978+
{
979+
if (sd->splice_eof)
980+
sd->splice_eof(sd);
981+
}
982+
972983
/*
973984
* Attempt to initiate a splice from a file to a pipe.
974985
*/
@@ -1068,7 +1079,7 @@ ssize_t splice_direct_to_actor(struct file *in, struct splice_desc *sd,
10681079

10691080
ret = do_splice_to(in, &pos, pipe, len, flags);
10701081
if (unlikely(ret <= 0))
1071-
goto out_release;
1082+
goto read_failure;
10721083

10731084
read_len = ret;
10741085
sd->total_len = read_len;
@@ -1108,6 +1119,15 @@ ssize_t splice_direct_to_actor(struct file *in, struct splice_desc *sd,
11081119
file_accessed(in);
11091120
return bytes;
11101121

1122+
read_failure:
1123+
/*
1124+
* If the user did *not* set SPLICE_F_MORE *and* we didn't hit that
1125+
* "use all of len" case that cleared SPLICE_F_MORE, *and* we did a
1126+
* "->splice_in()" that returned EOF (ie zero) *and* we have sent at
1127+
* least 1 byte *then* we will also do the ->splice_eof() call.
1128+
*/
1129+
if (ret == 0 && !more && len > 0 && bytes)
1130+
do_splice_eof(sd);
11111131
out_release:
11121132
/*
11131133
* If we did an incomplete transfer we must release
@@ -1136,6 +1156,14 @@ static int direct_splice_actor(struct pipe_inode_info *pipe,
11361156
sd->flags);
11371157
}
11381158

1159+
static void direct_file_splice_eof(struct splice_desc *sd)
1160+
{
1161+
struct file *file = sd->u.file;
1162+
1163+
if (file->f_op->splice_eof)
1164+
file->f_op->splice_eof(file);
1165+
}
1166+
11391167
/**
11401168
* do_splice_direct - splices data directly between two files
11411169
* @in: file to splice from
@@ -1161,6 +1189,7 @@ long do_splice_direct(struct file *in, loff_t *ppos, struct file *out,
11611189
.flags = flags,
11621190
.pos = *ppos,
11631191
.u.file = out,
1192+
.splice_eof = direct_file_splice_eof,
11641193
.opos = opos,
11651194
};
11661195
long ret;

include/linux/fs.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1796,6 +1796,7 @@ struct file_operations {
17961796
int (*flock) (struct file *, int, struct file_lock *);
17971797
ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);
17981798
ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);
1799+
void (*splice_eof)(struct file *file);
17991800
int (*setlease)(struct file *, long, struct file_lock **, void **);
18001801
long (*fallocate)(struct file *file, int mode, loff_t offset,
18011802
loff_t len);

include/linux/net.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,7 @@ struct proto_ops {
210210
int offset, size_t size, int flags);
211211
ssize_t (*splice_read)(struct socket *sock, loff_t *ppos,
212212
struct pipe_inode_info *pipe, size_t len, unsigned int flags);
213+
void (*splice_eof)(struct socket *sock);
213214
int (*set_peek_off)(struct sock *sk, int val);
214215
int (*peek_len)(struct socket *sock);
215216

include/linux/splice.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ struct splice_desc {
3838
struct file *file; /* file to read/write */
3939
void *data; /* cookie */
4040
} u;
41+
void (*splice_eof)(struct splice_desc *sd); /* Unexpected EOF handler */
4142
loff_t pos; /* file position */
4243
loff_t *opos; /* sendfile: output position */
4344
size_t num_spliced; /* number of bytes already spliced */

include/net/sock.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1279,6 +1279,7 @@ struct proto {
12791279
size_t len, int flags, int *addr_len);
12801280
int (*sendpage)(struct sock *sk, struct page *page,
12811281
int offset, size_t size, int flags);
1282+
void (*splice_eof)(struct socket *sock);
12821283
int (*bind)(struct sock *sk,
12831284
struct sockaddr *addr, int addr_len);
12841285
int (*bind_add)(struct sock *sk,

net/socket.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ static int sock_fasync(int fd, struct file *filp, int on);
130130
static ssize_t sock_splice_read(struct file *file, loff_t *ppos,
131131
struct pipe_inode_info *pipe, size_t len,
132132
unsigned int flags);
133+
static void sock_splice_eof(struct file *file);
133134

134135
#ifdef CONFIG_PROC_FS
135136
static void sock_show_fdinfo(struct seq_file *m, struct file *f)
@@ -163,6 +164,7 @@ static const struct file_operations socket_file_ops = {
163164
.fasync = sock_fasync,
164165
.splice_write = splice_to_socket,
165166
.splice_read = sock_splice_read,
167+
.splice_eof = sock_splice_eof,
166168
.show_fdinfo = sock_show_fdinfo,
167169
};
168170

@@ -1076,6 +1078,14 @@ static ssize_t sock_splice_read(struct file *file, loff_t *ppos,
10761078
return sock->ops->splice_read(sock, ppos, pipe, len, flags);
10771079
}
10781080

1081+
static void sock_splice_eof(struct file *file)
1082+
{
1083+
struct socket *sock = file->private_data;
1084+
1085+
if (sock->ops->splice_eof)
1086+
sock->ops->splice_eof(sock);
1087+
}
1088+
10791089
static ssize_t sock_read_iter(struct kiocb *iocb, struct iov_iter *to)
10801090
{
10811091
struct file *file = iocb->ki_filp;

0 commit comments

Comments
 (0)