In preparation for being able to do a nonblocking confirm attempt of a pipe buffer, plumb a parameter through the stack to indicate if this is a nonblocking attempt or not. Each caller is passing down 'false' right now, but the only confirm method in the tree, page_cache_pipe_buf_confirm(), is converted to do a trylock_page() if nonblock == true. Acked-by: Dave Chinner <dchinner@xxxxxxxxxx> Reviewed-by: Christian Brauner <brauner@xxxxxxxxxx> Signed-off-by: Jens Axboe <axboe@xxxxxxxxx> --- fs/fuse/dev.c | 4 ++-- fs/pipe.c | 4 ++-- fs/splice.c | 11 +++++++---- include/linux/pipe_fs_i.h | 7 ++++--- 4 files changed, 15 insertions(+), 11 deletions(-) diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index eb4f88e3dc97..0bd1b0870f2d 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c @@ -700,7 +700,7 @@ static int fuse_copy_fill(struct fuse_copy_state *cs) struct pipe_buffer *buf = cs->pipebufs; if (!cs->write) { - err = pipe_buf_confirm(cs->pipe, buf); + err = pipe_buf_confirm(cs->pipe, buf, false); if (err) return err; @@ -800,7 +800,7 @@ static int fuse_try_move_page(struct fuse_copy_state *cs, struct page **pagep) fuse_copy_finish(cs); - err = pipe_buf_confirm(cs->pipe, buf); + err = pipe_buf_confirm(cs->pipe, buf, false); if (err) goto out_put_old; diff --git a/fs/pipe.c b/fs/pipe.c index 42c7ff41c2db..340f253913a2 100644 --- a/fs/pipe.c +++ b/fs/pipe.c @@ -297,7 +297,7 @@ pipe_read(struct kiocb *iocb, struct iov_iter *to) chars = total_len; } - error = pipe_buf_confirm(pipe, buf); + error = pipe_buf_confirm(pipe, buf, false); if (error) { if (!ret) ret = error; @@ -461,7 +461,7 @@ pipe_write(struct kiocb *iocb, struct iov_iter *from) if ((buf->flags & PIPE_BUF_FLAG_CAN_MERGE) && offset + chars <= PAGE_SIZE) { - ret = pipe_buf_confirm(pipe, buf); + ret = pipe_buf_confirm(pipe, buf, false); if (ret) goto out; diff --git a/fs/splice.c b/fs/splice.c index 2c3dec2b6dfa..130ee1052588 100644 --- a/fs/splice.c +++ b/fs/splice.c @@ -100,13 +100,16 @@ static void page_cache_pipe_buf_release(struct pipe_inode_info *pipe, * is a page cache page, IO may be in flight. */ static int page_cache_pipe_buf_confirm(struct pipe_inode_info *pipe, - struct pipe_buffer *buf) + struct pipe_buffer *buf, bool nonblock) { struct page *page = buf->page; int err; if (!PageUptodate(page)) { - lock_page(page); + if (nonblock && !trylock_page(page)) + return -EAGAIN; + else + lock_page(page); /* * Page got truncated/unhashed. This will cause a 0-byte @@ -498,7 +501,7 @@ static int splice_from_pipe_feed(struct pipe_inode_info *pipe, struct splice_des if (sd->len > sd->total_len) sd->len = sd->total_len; - ret = pipe_buf_confirm(pipe, buf); + ret = pipe_buf_confirm(pipe, buf, false); if (unlikely(ret)) { if (ret == -ENODATA) ret = 0; @@ -761,7 +764,7 @@ iter_file_splice_write(struct pipe_inode_info *pipe, struct file *out, continue; this_len = min(this_len, left); - ret = pipe_buf_confirm(pipe, buf); + ret = pipe_buf_confirm(pipe, buf, false); if (unlikely(ret)) { if (ret == -ENODATA) ret = 0; diff --git a/include/linux/pipe_fs_i.h b/include/linux/pipe_fs_i.h index d2c3f16cf6b1..d63278bb0797 100644 --- a/include/linux/pipe_fs_i.h +++ b/include/linux/pipe_fs_i.h @@ -100,7 +100,8 @@ struct pipe_buf_operations { * hook. Returns 0 for good, or a negative error value in case of * error. If not present all pages are considered good. */ - int (*confirm)(struct pipe_inode_info *, struct pipe_buffer *); + int (*confirm)(struct pipe_inode_info *, struct pipe_buffer *, + bool nonblock); /* * When the contents of this pipe buffer has been completely @@ -209,11 +210,11 @@ static inline void pipe_buf_release(struct pipe_inode_info *pipe, * @buf: the buffer to confirm */ static inline int pipe_buf_confirm(struct pipe_inode_info *pipe, - struct pipe_buffer *buf) + struct pipe_buffer *buf, bool nonblock) { if (!buf->ops->confirm) return 0; - return buf->ops->confirm(pipe, buf); + return buf->ops->confirm(pipe, buf, nonblock); } /** -- 2.39.2