Nothing calls pipe_buf_try_steal() any more.  Remove ->try_steal() from
struct pipe_buf_operations, its implementations and the exported
generic_pipe_buf_try_steal().

PIPE_BUF_FLAG_LRU and PIPE_BUF_FLAG_GIFT were set only for stealing, and
go too.  page_cache_pipe_buf_release() did nothing but drop the page and
the LRU flag, so page cache and user page buffers use
generic_pipe_buf_release().

vmsplice() still accepts SPLICE_F_GIFT, and splice() SPLICE_F_MOVE.
Both were hints, and nothing acts on them now.

Suggested-by: Linus Torvalds <[email protected]>
Signed-off-by: Kiryl Shutsemau (Meta) <[email protected]>
---
 fs/pipe.c                 | 43 ------------------
 fs/splice.c               | 96 +++------------------------------------
 include/linux/pipe_fs_i.h | 36 ---------------
 kernel/watch_queue.c      |  4 --
 mm/shmem.c                |  7 ---
 5 files changed, 6 insertions(+), 180 deletions(-)

diff --git a/fs/pipe.c b/fs/pipe.c
index 4fa69192e6fb..4c1122597a3c 100644
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -222,48 +222,6 @@ static void anon_pipe_buf_release(struct pipe_inode_info 
*pipe,
        anon_pipe_put_page(pipe, page);
 }
 
-static bool anon_pipe_buf_try_steal(struct pipe_inode_info *pipe,
-               struct pipe_buffer *buf)
-{
-       struct page *page = buf->page;
-
-       if (page_count(page) != 1)
-               return false;
-       memcg_kmem_uncharge_page(page, 0);
-       __SetPageLocked(page);
-       return true;
-}
-
-/**
- * generic_pipe_buf_try_steal - attempt to take ownership of a &pipe_buffer
- * @pipe:      the pipe that the buffer belongs to
- * @buf:       the buffer to attempt to steal
- *
- * Description:
- *     This function attempts to steal the &struct page attached to
- *     @buf. If successful, this function returns 0 and returns with
- *     the page locked. The caller may then reuse the page for whatever
- *     he wishes; the typical use is insertion into a different file
- *     page cache.
- */
-bool generic_pipe_buf_try_steal(struct pipe_inode_info *pipe,
-               struct pipe_buffer *buf)
-{
-       struct page *page = buf->page;
-
-       /*
-        * A reference of one is golden, that means that the owner of this
-        * page is the only one holding a reference to it. lock the page
-        * and return OK.
-        */
-       if (page_count(page) == 1) {
-               lock_page(page);
-               return true;
-       }
-       return false;
-}
-EXPORT_SYMBOL(generic_pipe_buf_try_steal);
-
 /**
  * generic_pipe_buf_get - get a reference to a &struct pipe_buffer
  * @pipe:      the pipe that the buffer belongs to
@@ -297,7 +255,6 @@ EXPORT_SYMBOL(generic_pipe_buf_release);
 
 static const struct pipe_buf_operations anon_pipe_buf_ops = {
        .release        = anon_pipe_buf_release,
-       .try_steal      = anon_pipe_buf_try_steal,
        .get            = generic_pipe_buf_get,
 };
 
diff --git a/fs/splice.c b/fs/splice.c
index e6d43329ed3f..ba8f6f9aa3f0 100644
--- a/fs/splice.c
+++ b/fs/splice.c
@@ -55,63 +55,6 @@ static noinline void 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 (!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.
@@ -154,24 +97,12 @@ static int page_cache_pipe_buf_confirm(struct 
pipe_inode_info *pipe,
 
 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,
+       .release        = generic_pipe_buf_release,
        .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,
+       .release        = generic_pipe_buf_release,
        .get            = generic_pipe_buf_get,
 };
 
@@ -400,7 +331,6 @@ EXPORT_SYMBOL(copy_splice_read);
 
 const struct pipe_buf_operations default_pipe_buf_ops = {
        .release        = generic_pipe_buf_release,
-       .try_steal      = generic_pipe_buf_try_steal,
        .get            = generic_pipe_buf_get,
 };
 
@@ -1469,12 +1399,10 @@ static ssize_t __do_splice(struct file *in, loff_t 
__user *off_in,
 }
 
 static ssize_t iter_to_pipe(struct iov_iter *from,
-                           struct pipe_inode_info *pipe,
-                           unsigned int flags)
+                           struct pipe_inode_info *pipe)
 {
        struct pipe_buffer buf = {
                .ops = &user_page_pipe_buf_ops,
-               .flags = flags
        };
        size_t total = 0;
        ssize_t ret = 0;
@@ -1564,10 +1492,6 @@ static ssize_t vmsplice_to_pipe(struct file *file, 
struct iov_iter *iter,
 {
        struct pipe_inode_info *pipe;
        ssize_t 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)
@@ -1578,7 +1502,7 @@ static ssize_t 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);
        pipe_unlock(pipe);
        if (ret > 0) {
                wakeup_pipe_readers(pipe);
@@ -1839,11 +1763,7 @@ static int splice_pipe_to_pipe(struct pipe_inode_info 
*ipipe,
                        }
                        *obuf = *ibuf;
 
-                       /*
-                        * Don't inherit the gift and merge flags, we need to
-                        * prevent multiple steals of this page.
-                        */
-                       obuf->flags &= ~PIPE_BUF_FLAG_GIFT;
+                       /* The page is shared with ipipe: don't append to it */
                        obuf->flags &= ~PIPE_BUF_FLAG_CAN_MERGE;
 
                        obuf->len = len;
@@ -1956,11 +1876,7 @@ static ssize_t link_pipe(struct pipe_inode_info *ipipe,
 
                *obuf = *ibuf;
 
-               /*
-                * Don't inherit the gift and merge flag, we need to prevent
-                * multiple steals of this page.
-                */
-               obuf->flags &= ~PIPE_BUF_FLAG_GIFT;
+               /* The page is shared with ipipe: don't append to it */
                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 6402930282e5..fb6570e80d01 100644
--- a/include/linux/pipe_fs_i.h
+++ b/include/linux/pipe_fs_i.h
@@ -4,9 +4,7 @@
 
 #define PIPE_DEF_BUFFERS       16
 
-#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 */
@@ -127,16 +125,6 @@ struct pipe_inode_info {
 #endif
 };
 
-/*
- * Note on the nesting of these functions:
- *
- * ->confirm()
- *     ->try_steal()
- *
- * That is, ->try_steal() must be called on a confirmed buffer.  See below for
- * the meaning of each operation.  Also see the kerneldoc in fs/pipe.c for the
- * pipe and generic variants of these hooks.
- */
 struct pipe_buf_operations {
        /*
         * ->confirm() verifies that the data in the pipe buffer is there
@@ -153,16 +141,6 @@ struct pipe_buf_operations {
         */
        void (*release)(struct pipe_inode_info *, struct pipe_buffer *);
 
-       /*
-        * Attempt to take ownership of the pipe buffer and its contents.
-        * ->try_steal() returns %true for success, in which case the contents
-        * of the pipe (the buf->page) is locked and now completely owned by the
-        * caller. The page may then be transferred to a different mapping, the
-        * most often used case is insertion into different file address space
-        * cache.
-        */
-       bool (*try_steal)(struct pipe_inode_info *, struct pipe_buffer *);
-
        /*
         * Get a reference to the pipe buffer.
         */
@@ -304,19 +282,6 @@ static inline int pipe_buf_confirm(struct pipe_inode_info 
*pipe,
        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
- * @buf:       the buffer to attempt to steal
- */
-static inline bool pipe_buf_try_steal(struct pipe_inode_info *pipe,
-               struct pipe_buffer *buf)
-{
-       if (!buf->ops->try_steal)
-               return false;
-       return buf->ops->try_steal(pipe, buf);
-}
-
 /* Differs from PIPE_BUF in that PIPE_SIZE is the length of the actual
    memory allocation, whereas PIPE_BUF makes atomicity guarantees.  */
 #define PIPE_SIZE              PAGE_SIZE
@@ -335,7 +300,6 @@ void free_pipe_info(struct pipe_inode_info *);
 
 /* Generic pipe buffer ops functions */
 bool generic_pipe_buf_get(struct pipe_inode_info *, struct pipe_buffer *);
-bool generic_pipe_buf_try_steal(struct pipe_inode_info *, struct pipe_buffer 
*);
 void generic_pipe_buf_release(struct pipe_inode_info *, struct pipe_buffer *);
 
 extern const struct pipe_buf_operations nosteal_pipe_buf_ops;
diff --git a/kernel/watch_queue.c b/kernel/watch_queue.c
index 453dcf613205..e2bdd5fb0db1 100644
--- a/kernel/watch_queue.c
+++ b/kernel/watch_queue.c
@@ -77,13 +77,9 @@ static void watch_queue_pipe_buf_release(struct 
pipe_inode_info *pipe,
        generic_pipe_buf_release(pipe, buf);
 }
 
-// No try_steal function => no stealing
-#define watch_queue_pipe_buf_try_steal NULL
-
 /* New data written to a pipe may be appended to a buffer with this type. */
 static const struct pipe_buf_operations watch_queue_pipe_buf_ops = {
        .release        = watch_queue_pipe_buf_release,
-       .try_steal      = watch_queue_pipe_buf_try_steal,
        .get            = generic_pipe_buf_get,
 };
 
diff --git a/mm/shmem.c b/mm/shmem.c
index af21a89abb0f..4a9440a1e1f8 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -3655,15 +3655,8 @@ static void zero_pipe_buf_release(struct pipe_inode_info 
*pipe,
 {
 }
 
-static bool zero_pipe_buf_try_steal(struct pipe_inode_info *pipe,
-                                   struct pipe_buffer *buf)
-{
-       return false;
-}
-
 static const struct pipe_buf_operations zero_pipe_buf_ops = {
        .release        = zero_pipe_buf_release,
-       .try_steal      = zero_pipe_buf_try_steal,
        .get            = zero_pipe_buf_get,
 };
 
-- 
2.54.0


Reply via email to