[RFC PATCH] splice: Convert longs and some ints into ssize_t

From: David Howells
Date: Wed Mar 15 2023 - 12:36:03 EST


Christoph Hellwig <hch@xxxxxxxxxxxxx> wrote:

> The (pre-existing) long here is odd given that ->splice_read
> returns a ssize_t. This might be a good time to fix that up.

Here's a patch to do that. I'm not sure yet that I've got all the places that
need changing as there are a couple of function pointer-taking functions where
the pointed-to function return value should be changed.

There are a couple of potential bugs fixed here too, where something takes a
size_t length, but counts the data spliced in an int. iter_to_pipe() for
example.

David
---
splice: Convert longs and some ints into ssize_t

Convert 'long' and some 'int' into ssize_t in the code involved in splice.

Suggested-by: Christoph Hellwig <hch@xxxxxx>
Signed-off-by: David Howells <dhowells@xxxxxxxxxx>
cc: Christoph Hellwig <hch@xxxxxx>
cc: Jens Axboe <axboe@xxxxxxxxx>
cc: Al Viro <viro@xxxxxxxxxxxxxxxxxx>
cc: John Hubbard <jhubbard@xxxxxxxxxx>
cc: David Hildenbrand <david@xxxxxxxxxx>
cc: Matthew Wilcox <willy@xxxxxxxxxxxxx>
cc: linux-block@xxxxxxxxxxxxxxx
cc: linux-fsdevel@xxxxxxxxxxxxxxx
cc: linux-mm@xxxxxxxxx
Link: https://lore.kernel.org/r/ZBCvdKQskS46qyV3@xxxxxxxxxxxxx/
---
drivers/char/mem.c | 4 -
drivers/char/virtio_console.c | 7 +-
fs/splice.c | 119 +++++++++++++++++++++---------------------
include/linux/splice.h | 24 ++++----
4 files changed, 78 insertions(+), 76 deletions(-)

diff --git a/drivers/char/mem.c b/drivers/char/mem.c
index ffb101d349f0..230b72e12c54 100644
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -468,8 +468,8 @@ static ssize_t write_iter_null(struct kiocb *iocb, struct iov_iter *from)
return count;
}

-static int pipe_to_null(struct pipe_inode_info *info, struct pipe_buffer *buf,
- struct splice_desc *sd)
+static ssize_t pipe_to_null(struct pipe_inode_info *info, struct pipe_buffer *buf,
+ struct splice_desc *sd)
{
return sd->len;
}
diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
index d5ac4d955bc8..d38bee859d5c 100644
--- a/drivers/char/virtio_console.c
+++ b/drivers/char/virtio_console.c
@@ -854,11 +854,12 @@ struct sg_list {
struct scatterlist *sg;
};

-static int pipe_to_sg(struct pipe_inode_info *pipe, struct pipe_buffer *buf,
- struct splice_desc *sd)
+static ssize_t pipe_to_sg(struct pipe_inode_info *pipe, struct pipe_buffer *buf,
+ struct splice_desc *sd)
{
struct sg_list *sgl = sd->u.data;
- unsigned int offset, len;
+ ssize_t len;
+ size_t offset;

if (sgl->n == sgl->size)
return 0;
diff --git a/fs/splice.c b/fs/splice.c
index f46dd1fb367b..2bfa94d21346 100644
--- a/fs/splice.c
+++ b/fs/splice.c
@@ -186,7 +186,8 @@ ssize_t splice_to_pipe(struct pipe_inode_info *pipe,
unsigned int tail = pipe->tail;
unsigned int head = pipe->head;
unsigned int mask = pipe->ring_size - 1;
- int ret = 0, page_nr = 0;
+ ssize_t ret = 0;
+ int page_nr = 0;

if (!spd_pages)
return 0;
@@ -232,7 +233,7 @@ ssize_t add_to_pipe(struct pipe_inode_info *pipe, struct pipe_buffer *buf)
unsigned int head = pipe->head;
unsigned int tail = pipe->tail;
unsigned int mask = pipe->ring_size - 1;
- int ret;
+ ssize_t ret;

if (unlikely(!pipe->readers)) {
send_sig(SIGPIPE, current, 0);
@@ -414,8 +415,8 @@ EXPORT_SYMBOL(nosteal_pipe_buf_ops);
* Send 'sd->len' bytes to socket from 'sd->file' at position 'sd->pos'
* using sendpage(). Return the number of bytes sent.
*/
-static int pipe_to_sendpage(struct pipe_inode_info *pipe,
- struct pipe_buffer *buf, struct splice_desc *sd)
+static ssize_t pipe_to_sendpage(struct pipe_inode_info *pipe,
+ struct pipe_buffer *buf, struct splice_desc *sd)
{
struct file *file = sd->u.file;
loff_t pos = sd->pos;
@@ -468,7 +469,7 @@ static int splice_from_pipe_feed(struct pipe_inode_info *pipe, struct splice_des
unsigned int head = pipe->head;
unsigned int tail = pipe->tail;
unsigned int mask = pipe->ring_size - 1;
- int ret;
+ ssize_t ret;

while (!pipe_empty(head, tail)) {
struct pipe_buffer *buf = &pipe->bufs[tail & mask];
@@ -621,7 +622,7 @@ static void splice_from_pipe_end(struct pipe_inode_info *pipe, struct splice_des
ssize_t __splice_from_pipe(struct pipe_inode_info *pipe, struct splice_desc *sd,
splice_actor *actor)
{
- int ret;
+ ssize_t ret;

splice_from_pipe_begin(sd);
do {
@@ -827,8 +828,8 @@ static int warn_unsupported(struct file *file, const char *op)
/*
* Attempt to initiate a splice from pipe to file.
*/
-static long do_splice_from(struct pipe_inode_info *pipe, struct file *out,
- loff_t *ppos, size_t len, unsigned int flags)
+static ssize_t do_splice_from(struct pipe_inode_info *pipe, struct file *out,
+ loff_t *ppos, size_t len, unsigned int flags)
{
if (unlikely(!out->f_op->splice_write))
return warn_unsupported(out, "write");
@@ -850,12 +851,12 @@ static long do_splice_from(struct pipe_inode_info *pipe, struct file *out,
* If successful, it returns the amount of data spliced, 0 if it hit the EOF or
* a hole and a negative error code otherwise.
*/
-long vfs_splice_read(struct file *in, loff_t *ppos,
- struct pipe_inode_info *pipe, size_t len,
- unsigned int flags)
+ssize_t vfs_splice_read(struct file *in, loff_t *ppos,
+ struct pipe_inode_info *pipe, size_t len,
+ unsigned int flags)
{
unsigned int p_space;
- int ret;
+ ssize_t ret;

if (unlikely(!(in->f_mode & FMODE_READ)))
return -EBADF;
@@ -894,7 +895,7 @@ ssize_t splice_direct_to_actor(struct file *in, struct splice_desc *sd,
splice_direct_actor *actor)
{
struct pipe_inode_info *pipe;
- long ret, bytes;
+ ssize_t ret, bytes;
size_t len;
int i, flags, more;

@@ -1007,7 +1008,7 @@ ssize_t splice_direct_to_actor(struct file *in, struct splice_desc *sd,
}
EXPORT_SYMBOL(splice_direct_to_actor);

-static int direct_splice_actor(struct pipe_inode_info *pipe,
+static ssize_t direct_splice_actor(struct pipe_inode_info *pipe,
struct splice_desc *sd)
{
struct file *file = sd->u.file;
@@ -1032,8 +1033,8 @@ static int direct_splice_actor(struct pipe_inode_info *pipe,
* can splice directly through a process-private pipe.
*
*/
-long do_splice_direct(struct file *in, loff_t *ppos, struct file *out,
- loff_t *opos, size_t len, unsigned int flags)
+ssize_t do_splice_direct(struct file *in, loff_t *ppos, struct file *out,
+ loff_t *opos, size_t len, unsigned int flags)
{
struct splice_desc sd = {
.len = len,
@@ -1043,7 +1044,7 @@ long do_splice_direct(struct file *in, loff_t *ppos, struct file *out,
.u.file = out,
.opos = opos,
};
- long ret;
+ ssize_t ret;

if (unlikely(!(out->f_mode & FMODE_WRITE)))
return -EBADF;
@@ -1080,16 +1081,16 @@ static int wait_for_space(struct pipe_inode_info *pipe, unsigned flags)
}
}

-static int splice_pipe_to_pipe(struct pipe_inode_info *ipipe,
- struct pipe_inode_info *opipe,
- size_t len, unsigned int flags);
+static ssize_t splice_pipe_to_pipe(struct pipe_inode_info *ipipe,
+ struct pipe_inode_info *opipe,
+ size_t len, unsigned int flags);

-long splice_file_to_pipe(struct file *in,
- struct pipe_inode_info *opipe,
- loff_t *offset,
- size_t len, unsigned int flags)
+ssize_t splice_file_to_pipe(struct file *in,
+ struct pipe_inode_info *opipe,
+ loff_t *offset,
+ size_t len, unsigned int flags)
{
- long ret;
+ ssize_t ret;

pipe_lock(opipe);
ret = wait_for_space(opipe, flags);
@@ -1104,13 +1105,13 @@ long splice_file_to_pipe(struct file *in,
/*
* Determine where to splice to/from.
*/
-long do_splice(struct file *in, loff_t *off_in, struct file *out,
- loff_t *off_out, size_t len, unsigned int flags)
+ssize_t do_splice(struct file *in, loff_t *off_in, struct file *out,
+ loff_t *off_out, size_t len, unsigned int flags)
{
struct pipe_inode_info *ipipe;
struct pipe_inode_info *opipe;
loff_t offset;
- long ret;
+ ssize_t ret;

if (unlikely(!(in->f_mode & FMODE_READ) ||
!(out->f_mode & FMODE_WRITE)))
@@ -1192,14 +1193,14 @@ long do_splice(struct file *in, loff_t *off_in, struct file *out,
return -EINVAL;
}

-static long __do_splice(struct file *in, loff_t __user *off_in,
- struct file *out, loff_t __user *off_out,
- size_t len, unsigned int flags)
+static ssize_t __do_splice(struct file *in, loff_t __user *off_in,
+ struct file *out, loff_t __user *off_out,
+ size_t len, unsigned int flags)
{
struct pipe_inode_info *ipipe;
struct pipe_inode_info *opipe;
loff_t offset, *__off_in = NULL, *__off_out = NULL;
- long ret;
+ ssize_t ret;

ipipe = get_pipe_info(in, true);
opipe = get_pipe_info(out, true);
@@ -1232,16 +1233,16 @@ static long __do_splice(struct file *in, loff_t __user *off_in,
return ret;
}

-static int iter_to_pipe(struct iov_iter *from,
- struct pipe_inode_info *pipe,
- unsigned flags)
+static ssize_t iter_to_pipe(struct iov_iter *from,
+ struct pipe_inode_info *pipe,
+ unsigned flags)
{
struct pipe_buffer buf = {
.ops = &user_page_pipe_buf_ops,
.flags = flags
};
size_t total = 0;
- int ret = 0;
+ ssize_t ret = 0;

while (iov_iter_count(from)) {
struct page *pages[16];
@@ -1257,7 +1258,7 @@ static int iter_to_pipe(struct iov_iter *from,

n = DIV_ROUND_UP(left + start, PAGE_SIZE);
for (i = 0; i < n; i++) {
- int size = min_t(int, left, PAGE_SIZE - start);
+ size_t size = min_t(int, left, PAGE_SIZE - start);

buf.page = pages[i];
buf.offset = start;
@@ -1279,10 +1280,10 @@ static int iter_to_pipe(struct iov_iter *from,
return total ? total : ret;
}

-static int pipe_to_user(struct pipe_inode_info *pipe, struct pipe_buffer *buf,
- struct splice_desc *sd)
+static ssize_t pipe_to_user(struct pipe_inode_info *pipe, struct pipe_buffer *buf,
+ struct splice_desc *sd)
{
- int n = copy_page_to_iter(buf->page, buf->offset, sd->len, sd->u.data);
+ size_t n = copy_page_to_iter(buf->page, buf->offset, sd->len, sd->u.data);
return n == sd->len ? n : -EFAULT;
}

@@ -1290,8 +1291,8 @@ static int pipe_to_user(struct pipe_inode_info *pipe, struct pipe_buffer *buf,
* For lack of a better implementation, implement vmsplice() to userspace
* as a simple copy of the pipes pages to the user iov.
*/
-static long vmsplice_to_user(struct file *file, struct iov_iter *iter,
- unsigned int flags)
+static ssize_t vmsplice_to_user(struct file *file, struct iov_iter *iter,
+ unsigned int flags)
{
struct pipe_inode_info *pipe = get_pipe_info(file, true);
struct splice_desc sd = {
@@ -1299,7 +1300,7 @@ static long vmsplice_to_user(struct file *file, struct iov_iter *iter,
.flags = flags,
.u.data = iter
};
- long ret = 0;
+ ssize_t ret = 0;

if (!pipe)
return -EBADF;
@@ -1318,12 +1319,12 @@ static long vmsplice_to_user(struct file *file, struct iov_iter *iter,
* as splice-from-memory, where the regular splice is splice-from-file (or
* to file). In both cases the output is a pipe, naturally.
*/
-static long vmsplice_to_pipe(struct file *file, struct iov_iter *iter,
- unsigned int flags)
+static ssize_t vmsplice_to_pipe(struct file *file, struct iov_iter *iter,
+ unsigned int flags)
{
struct pipe_inode_info *pipe;
- long ret = 0;
- unsigned buf_flag = 0;
+ ssize_t ret = 0;
+ unsigned int buf_flag = 0;

if (flags & SPLICE_F_GIFT)
buf_flag = PIPE_BUF_FLAG_GIFT;
@@ -1414,7 +1415,7 @@ SYSCALL_DEFINE6(splice, int, fd_in, loff_t __user *, off_in,
size_t, len, unsigned int, flags)
{
struct fd in, out;
- long error;
+ ssize_t error;

if (unlikely(!len))
return 0;
@@ -1514,15 +1515,15 @@ static int opipe_prep(struct pipe_inode_info *pipe, unsigned int flags)
/*
* Splice contents of ipipe to opipe.
*/
-static int splice_pipe_to_pipe(struct pipe_inode_info *ipipe,
- struct pipe_inode_info *opipe,
- size_t len, unsigned int flags)
+static ssize_t splice_pipe_to_pipe(struct pipe_inode_info *ipipe,
+ struct pipe_inode_info *opipe,
+ size_t len, unsigned int flags)
{
struct pipe_buffer *ibuf, *obuf;
unsigned int i_head, o_head;
unsigned int i_tail, o_tail;
unsigned int i_mask, o_mask;
- int ret = 0;
+ ssize_t ret = 0;
bool input_wakeup = false;


@@ -1651,15 +1652,15 @@ static int splice_pipe_to_pipe(struct pipe_inode_info *ipipe,
/*
* Link contents of ipipe to opipe.
*/
-static int link_pipe(struct pipe_inode_info *ipipe,
- struct pipe_inode_info *opipe,
- size_t len, unsigned int flags)
+static ssize_t link_pipe(struct pipe_inode_info *ipipe,
+ struct pipe_inode_info *opipe,
+ size_t len, unsigned int flags)
{
struct pipe_buffer *ibuf, *obuf;
unsigned int i_head, o_head;
unsigned int i_tail, o_tail;
unsigned int i_mask, o_mask;
- int ret = 0;
+ ssize_t ret = 0;

/*
* Potential ABBA deadlock, work around it by ordering lock
@@ -1742,11 +1743,11 @@ static int link_pipe(struct pipe_inode_info *ipipe,
* The 'flags' used are the SPLICE_F_* variants, currently the only
* applicable one is SPLICE_F_NONBLOCK.
*/
-long do_tee(struct file *in, struct file *out, size_t len, unsigned int flags)
+ssize_t do_tee(struct file *in, struct file *out, size_t len, unsigned int flags)
{
struct pipe_inode_info *ipipe = get_pipe_info(in, true);
struct pipe_inode_info *opipe = get_pipe_info(out, true);
- int ret = -EINVAL;
+ ssize_t ret = -EINVAL;

if (unlikely(!(in->f_mode & FMODE_READ) ||
!(out->f_mode & FMODE_WRITE)))
@@ -1778,7 +1779,7 @@ long do_tee(struct file *in, struct file *out, size_t len, unsigned int flags)
SYSCALL_DEFINE4(tee, int, fdin, int, fdout, size_t, len, unsigned int, flags)
{
struct fd in, out;
- int error;
+ ssize_t error;

if (unlikely(flags & ~SPLICE_F_ALL))
return -EINVAL;
diff --git a/include/linux/splice.h b/include/linux/splice.h
index 8f052c3dae95..6af5e197ccd0 100644
--- a/include/linux/splice.h
+++ b/include/linux/splice.h
@@ -62,10 +62,10 @@ struct splice_pipe_desc {
void (*spd_release)(struct splice_pipe_desc *, unsigned int);
};

-typedef int (splice_actor)(struct pipe_inode_info *, struct pipe_buffer *,
- struct splice_desc *);
-typedef int (splice_direct_actor)(struct pipe_inode_info *,
- struct splice_desc *);
+typedef ssize_t (splice_actor)(struct pipe_inode_info *, struct pipe_buffer *,
+ struct splice_desc *);
+typedef ssize_t (splice_direct_actor)(struct pipe_inode_info *,
+ struct splice_desc *);

extern ssize_t splice_from_pipe(struct pipe_inode_info *, struct file *,
loff_t *, size_t, unsigned int,
@@ -76,17 +76,17 @@ extern ssize_t splice_to_pipe(struct pipe_inode_info *,
struct splice_pipe_desc *);
extern ssize_t add_to_pipe(struct pipe_inode_info *,
struct pipe_buffer *);
-long vfs_splice_read(struct file *in, loff_t *ppos,
- struct pipe_inode_info *pipe, size_t len,
- unsigned int flags);
+ssize_t vfs_splice_read(struct file *in, loff_t *ppos,
+ struct pipe_inode_info *pipe, size_t len,
+ unsigned int flags);
extern ssize_t splice_direct_to_actor(struct file *, struct splice_desc *,
splice_direct_actor *);
-extern long do_splice(struct file *in, loff_t *off_in,
- struct file *out, loff_t *off_out,
- size_t len, unsigned int flags);
+extern ssize_t do_splice(struct file *in, loff_t *off_in,
+ struct file *out, loff_t *off_out,
+ size_t len, unsigned int flags);

-extern long do_tee(struct file *in, struct file *out, size_t len,
- unsigned int flags);
+extern ssize_t do_tee(struct file *in, struct file *out, size_t len,
+ unsigned int flags);

/*
* for dynamic pipe sizing