Remove some code that's no longer used as the ->confirm() op is no longer used and pages spliced in from the pagecache and process VM are now pre-stolen or copied. Signed-off-by: David Howells <dhowells@xxxxxxxxxx> cc: Matthew Wilcox <willy@xxxxxxxxxxxxx> cc: Dave Chinner <david@xxxxxxxxxxxxx> cc: Christoph Hellwig <hch@xxxxxx> cc: Jens Axboe <axboe@xxxxxxxxx> cc: linux-fsdevel@xxxxxxxxxxxxxxx --- fs/fuse/dev.c | 37 --------- fs/pipe.c | 12 --- fs/splice.c | 155 +------------------------------------- include/linux/pipe_fs_i.h | 14 ---- include/linux/splice.h | 1 - mm/filemap.c | 2 +- 6 files changed, 3 insertions(+), 218 deletions(-) diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index 1a8f82f478cb..9718dce0f0d9 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c @@ -700,10 +700,6 @@ 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); - if (err) - return err; - BUG_ON(!cs->nr_segs); cs->currbuf = buf; cs->pg = buf->page; @@ -766,26 +762,6 @@ static int fuse_copy_do(struct fuse_copy_state *cs, void **val, unsigned *size) return ncpy; } -static int fuse_check_folio(struct folio *folio) -{ - if (folio_mapped(folio) || - folio->mapping != NULL || - (folio->flags & PAGE_FLAGS_CHECK_AT_PREP & - ~(1 << PG_locked | - 1 << PG_referenced | - 1 << PG_uptodate | - 1 << PG_lru | - 1 << PG_active | - 1 << PG_workingset | - 1 << PG_reclaim | - 1 << PG_waiters | - LRU_GEN_MASK | LRU_REFS_MASK))) { - dump_page(&folio->page, "fuse: trying to steal weird page"); - return 1; - } - return 0; -} - static int fuse_try_move_page(struct fuse_copy_state *cs, struct page **pagep) { int err; @@ -800,10 +776,6 @@ 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); - if (err) - goto out_put_old; - BUG_ON(!cs->nr_segs); cs->currbuf = buf; cs->len = buf->len; @@ -818,14 +790,6 @@ static int fuse_try_move_page(struct fuse_copy_state *cs, struct page **pagep) newfolio = page_folio(buf->page); - if (!folio_test_uptodate(newfolio)) - folio_mark_uptodate(newfolio); - - folio_clear_mappedtodisk(newfolio); - - if (fuse_check_folio(newfolio) != 0) - goto out_fallback_unlock; - /* * This is a new and locked page, it shouldn't be mapped or * have any special flags on it @@ -2020,7 +1984,6 @@ static ssize_t fuse_dev_splice_write(struct pipe_inode_info *pipe, goto out_free; *obuf = *ibuf; - obuf->flags &= ~PIPE_BUF_FLAG_GIFT; obuf->len = rem; ibuf->offset += obuf->len; ibuf->len -= obuf->len; diff --git a/fs/pipe.c b/fs/pipe.c index 2d88f73f585a..d5c86eb20f29 100644 --- a/fs/pipe.c +++ b/fs/pipe.c @@ -286,7 +286,6 @@ pipe_read(struct kiocb *iocb, struct iov_iter *to) struct pipe_buffer *buf = &pipe->bufs[tail & mask]; size_t chars = buf->len; size_t written; - int error; if (chars > total_len) { if (buf->flags & PIPE_BUF_FLAG_WHOLE) { @@ -297,13 +296,6 @@ pipe_read(struct kiocb *iocb, struct iov_iter *to) chars = total_len; } - error = pipe_buf_confirm(pipe, buf); - if (error) { - if (!ret) - ret = error; - break; - } - written = copy_page_to_iter(buf->page, buf->offset, chars, to); if (unlikely(written < chars)) { if (!ret) @@ -462,10 +454,6 @@ 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); - if (ret) - goto out; - ret = copy_page_from_iter(buf->page, offset, chars, from); if (unlikely(ret < chars)) { ret = -EFAULT; diff --git a/fs/splice.c b/fs/splice.c index 42af642c0ff8..2b1f109a7d4f 100644 --- a/fs/splice.c +++ b/fs/splice.c @@ -56,129 +56,6 @@ static noinline void noinline pipe_clear_nowait(struct file *file) } while (!try_cmpxchg(&file->f_mode, &fmode, fmode & ~FMODE_NOWAIT)); } -/* - * Attempt to steal a page from a pipe buffer. This should perhaps go into - * a vm helper function, it's already simplified quite a bit by the - * addition of remove_mapping(). If success is returned, the caller may - * attempt to reuse this page for another destination. - */ -static bool page_cache_pipe_buf_try_steal(struct pipe_inode_info *pipe, - struct pipe_buffer *buf) -{ - struct folio *folio = page_folio(buf->page); - struct address_space *mapping; - - folio_lock(folio); - - mapping = folio_mapping(folio); - if (mapping) { - WARN_ON(!folio_test_uptodate(folio)); - - /* - * At least for ext2 with nobh option, we need to wait on - * writeback completing on this folio, since we'll remove it - * from the pagecache. Otherwise truncate wont wait on the - * folio, allowing the disk blocks to be reused by someone else - * before we actually wrote our data to them. fs corruption - * ensues. - */ - folio_wait_writeback(folio); - - if (folio_has_private(folio) && - !filemap_release_folio(folio, GFP_KERNEL)) - goto out_unlock; - - /* - * If we succeeded in removing the mapping, set LRU flag - * and return good. - */ - if (remove_mapping(mapping, folio)) { - buf->flags |= PIPE_BUF_FLAG_LRU; - return true; - } - } - - /* - * Raced with truncate or failed to remove folio from current - * address space, unlock and return failure. - */ -out_unlock: - folio_unlock(folio); - return false; -} - -static void page_cache_pipe_buf_release(struct pipe_inode_info *pipe, - struct pipe_buffer *buf) -{ - put_page(buf->page); - buf->flags &= ~PIPE_BUF_FLAG_LRU; -} - -/* - * Check whether the contents of buf is OK to access. Since the content - * 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 page *page = buf->page; - int err; - - if (!PageUptodate(page)) { - lock_page(page); - - /* - * Page got truncated/unhashed. This will cause a 0-byte - * splice, if this is the first page. - */ - if (!page->mapping) { - err = -ENODATA; - goto error; - } - - /* - * Uh oh, read-error from disk. - */ - if (!PageUptodate(page)) { - err = -EIO; - goto error; - } - - /* - * Page is ok afterall, we are done. - */ - unlock_page(page); - } - - return 0; -error: - unlock_page(page); - return err; -} - -const struct pipe_buf_operations page_cache_pipe_buf_ops = { - .confirm = page_cache_pipe_buf_confirm, - .release = page_cache_pipe_buf_release, - .try_steal = page_cache_pipe_buf_try_steal, - .get = generic_pipe_buf_get, -}; - -static bool user_page_pipe_buf_try_steal(struct pipe_inode_info *pipe, - struct pipe_buffer *buf) -{ - if (!(buf->flags & PIPE_BUF_FLAG_GIFT)) - return false; - - buf->flags |= PIPE_BUF_FLAG_LRU; - return generic_pipe_buf_try_steal(pipe, buf); -} - -static const struct pipe_buf_operations user_page_pipe_buf_ops = { - .release = page_cache_pipe_buf_release, - .try_steal = user_page_pipe_buf_try_steal, - .get = generic_pipe_buf_get, -}; - static void wakeup_pipe_readers(struct pipe_inode_info *pipe) { smp_mb(); @@ -460,13 +337,6 @@ 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); - if (unlikely(ret)) { - if (ret == -ENODATA) - ret = 0; - return ret; - } - ret = actor(pipe, buf, sd); if (ret <= 0) return ret; @@ -723,13 +593,6 @@ 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); - if (unlikely(ret)) { - if (ret == -ENODATA) - ret = 0; - goto done; - } - bvec_set_page(&array[n], buf->page, this_len, buf->offset); left -= this_len; @@ -764,7 +627,7 @@ iter_file_splice_write(struct pipe_inode_info *pipe, struct file *out, } } } -done: + kfree(array); splice_from_pipe_end(pipe, &sd); @@ -855,13 +718,6 @@ ssize_t splice_to_socket(struct pipe_inode_info *pipe, struct file *out, 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)) @@ -1450,7 +1306,6 @@ static int splice_try_to_steal_page(struct pipe_inode_info *pipe, need_copy_unlock: folio_unlock(folio); need_copy: - copy = folio_alloc(GFP_KERNEL, 0); if (!copy) return -ENOMEM; @@ -1578,10 +1433,6 @@ static long vmsplice_to_pipe(struct file *file, struct iov_iter *iter, { struct pipe_inode_info *pipe; long ret = 0; - unsigned buf_flag = 0; - - if (flags & SPLICE_F_GIFT) - buf_flag = PIPE_BUF_FLAG_GIFT; pipe = get_pipe_info(file, true); if (!pipe) @@ -1592,7 +1443,7 @@ static long vmsplice_to_pipe(struct file *file, struct iov_iter *iter, pipe_lock(pipe); ret = wait_for_space(pipe, flags); if (!ret) - ret = iter_to_pipe(iter, pipe, buf_flag); + ret = iter_to_pipe(iter, pipe, flags); pipe_unlock(pipe); if (ret > 0) wakeup_pipe_readers(pipe); @@ -1876,7 +1727,6 @@ static int splice_pipe_to_pipe(struct pipe_inode_info *ipipe, * Don't inherit the gift and merge flags, we need to * prevent multiple steals of this page. */ - obuf->flags &= ~PIPE_BUF_FLAG_GIFT; obuf->flags &= ~PIPE_BUF_FLAG_CAN_MERGE; obuf->len = len; @@ -1968,7 +1818,6 @@ static int link_pipe(struct pipe_inode_info *ipipe, * Don't inherit the gift and merge flag, we need to prevent * multiple steals of this page. */ - obuf->flags &= ~PIPE_BUF_FLAG_GIFT; obuf->flags &= ~PIPE_BUF_FLAG_CAN_MERGE; if (obuf->len > len) diff --git a/include/linux/pipe_fs_i.h b/include/linux/pipe_fs_i.h index 02e0086b10f6..9cfbefd7ba31 100644 --- a/include/linux/pipe_fs_i.h +++ b/include/linux/pipe_fs_i.h @@ -6,7 +6,6 @@ #define PIPE_BUF_FLAG_LRU 0x01 /* page is on the LRU */ #define PIPE_BUF_FLAG_ATOMIC 0x02 /* was atomically mapped */ -#define PIPE_BUF_FLAG_GIFT 0x04 /* page is a gift */ #define PIPE_BUF_FLAG_PACKET 0x08 /* read() as a packet */ #define PIPE_BUF_FLAG_CAN_MERGE 0x10 /* can merge buffers */ #define PIPE_BUF_FLAG_WHOLE 0x20 /* read() must return entire buffer or error */ @@ -203,19 +202,6 @@ static inline void pipe_buf_release(struct pipe_inode_info *pipe, ops->release(pipe, buf); } -/** - * pipe_buf_confirm - verify contents of the pipe buffer - * @pipe: the pipe that the buffer belongs to - * @buf: the buffer to confirm - */ -static inline int pipe_buf_confirm(struct pipe_inode_info *pipe, - struct pipe_buffer *buf) -{ - if (!buf->ops->confirm) - return 0; - return buf->ops->confirm(pipe, buf); -} - /** * pipe_buf_try_steal - attempt to take ownership of a pipe_buffer * @pipe: the pipe that the buffer belongs to diff --git a/include/linux/splice.h b/include/linux/splice.h index 6c461573434d..3c5abbd49ff2 100644 --- a/include/linux/splice.h +++ b/include/linux/splice.h @@ -97,6 +97,5 @@ extern ssize_t splice_to_socket(struct pipe_inode_info *pipe, struct file *out, extern int splice_grow_spd(const struct pipe_inode_info *, struct splice_pipe_desc *); extern void splice_shrink_spd(struct splice_pipe_desc *); -extern const struct pipe_buf_operations page_cache_pipe_buf_ops; extern const struct pipe_buf_operations default_pipe_buf_ops; #endif diff --git a/mm/filemap.c b/mm/filemap.c index a002df515966..dd144b0dab69 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -2929,7 +2929,7 @@ ssize_t splice_folio_into_pipe(struct pipe_inode_info *pipe, size_t part = min_t(size_t, PAGE_SIZE - offset, size - spliced); *buf = (struct pipe_buffer) { - .ops = &page_cache_pipe_buf_ops, + .ops = &default_pipe_buf_ops, .page = page, .offset = offset, .len = part,