Make filemap_release_folio() return one of three values:

 (0) FILEMAP_CANT_RELEASE_FOLIO

     Couldn't release the folio's private data, so the folio can't itself
     be released.

 (1) FILEMAP_RELEASED_FOLIO

     The private data on the folio was released and the folio can be
     released.

 (2) FILEMAP_FOLIO_HAD_NO_PRIVATE

     There was no private data on the folio and the folio can be released.

The first must be zero so that existing tests of !filemap_release_folio()
continue to work as expected; similarly the other two must both be non-zero
so that existing tests of filemap_release_folio() continue to work as
expected.

Using this, make shrink_folio_list() choose which of three cases to follow
based on the return from filemap_release_folio() rather than testing the
folio's private bit itself.

Signed-off-by: David Howells <dhowe...@redhat.com>
cc: Matthew Wilcox <wi...@infradead.org>
cc: Linus Torvalds <torva...@linux-foundation.org>
cc: Steve French <sfre...@samba.org>
cc: Shyam Prasad N <nspmangal...@gmail.com>
cc: Rohith Surabattula <rohiths.m...@gmail.com>
cc: Dave Wysochanski <dwyso...@redhat.com>
cc: Dominique Martinet <asmad...@codewreck.org>
cc: Ilya Dryomov <idryo...@gmail.com>
cc: linux-cachefs@redhat.com
cc: linux-c...@vger.kernel.org
cc: linux-...@lists.infradead.org
cc: v9fs-develo...@lists.sourceforge.net
cc: ceph-de...@vger.kernel.org
cc: linux-...@vger.kernel.org
cc: linux-fsde...@vger.kernel.org
cc: linux...@kvack.org
Link: https://lore.kernel.org/r/1459152.1669208...@warthog.procyon.org.uk/ # v3
---

 include/linux/pagemap.h |    7 ++++++-
 mm/filemap.c            |   20 ++++++++++++++------
 mm/vmscan.c             |   29 +++++++++++++++--------------
 3 files changed, 35 insertions(+), 21 deletions(-)

diff --git a/include/linux/pagemap.h b/include/linux/pagemap.h
index 9a824b43c6af..b763182b6d3f 100644
--- a/include/linux/pagemap.h
+++ b/include/linux/pagemap.h
@@ -1124,7 +1124,12 @@ void replace_page_cache_page(struct page *old, struct 
page *new);
 void delete_from_page_cache_batch(struct address_space *mapping,
                                  struct folio_batch *fbatch);
 int try_to_release_page(struct page *page, gfp_t gfp);
-bool filemap_release_folio(struct folio *folio, gfp_t gfp);
+enum filemap_released_folio {
+       FILEMAP_CANT_RELEASE_FOLIO      = 0, /* (This must be 0) Release failed 
*/
+       FILEMAP_RELEASED_FOLIO          = 1, /* Folio's private data released */
+       FILEMAP_FOLIO_HAD_NO_PRIVATE    = 2, /* Folio had no private data */
+};
+enum filemap_released_folio filemap_release_folio(struct folio *folio, gfp_t 
gfp);
 loff_t mapping_seek_hole_data(struct address_space *, loff_t start, loff_t end,
                int whence);
 
diff --git a/mm/filemap.c b/mm/filemap.c
index 93757247cd11..859831c70439 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -3934,20 +3934,28 @@ EXPORT_SYMBOL(generic_file_write_iter);
  * this page (__GFP_IO), and whether the call may block
  * (__GFP_RECLAIM & __GFP_FS).
  *
- * Return: %true if the release was successful, otherwise %false.
+ * Return: %FILEMAP_RELEASED_FOLIO if the release was successful,
+ * %FILEMAP_CANT_RELEASE_FOLIO if the private data couldn't be released and
+ * %FILEMAP_FOLIO_HAD_NO_PRIVATE if there was no private data.
  */
-bool filemap_release_folio(struct folio *folio, gfp_t gfp)
+enum filemap_released_folio filemap_release_folio(struct folio *folio,
+                                                 gfp_t gfp)
 {
        struct address_space * const mapping = folio->mapping;
+       bool released;
 
        BUG_ON(!folio_test_locked(folio));
        if (!folio_needs_release(folio))
-               return true;
+               return FILEMAP_FOLIO_HAD_NO_PRIVATE;
        if (folio_test_writeback(folio))
-               return false;
+               return FILEMAP_CANT_RELEASE_FOLIO;
 
        if (mapping && mapping->a_ops->release_folio)
-               return mapping->a_ops->release_folio(folio, gfp);
-       return try_to_free_buffers(folio);
+               released = mapping->a_ops->release_folio(folio, gfp);
+       else
+               released = try_to_free_buffers(folio);
+
+       return released ?
+               FILEMAP_RELEASED_FOLIO : FILEMAP_CANT_RELEASE_FOLIO;
 }
 EXPORT_SYMBOL(filemap_release_folio);
diff --git a/mm/vmscan.c b/mm/vmscan.c
index b9316f447238..d5c7b3be9947 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -1978,25 +1978,26 @@ static unsigned int shrink_folio_list(struct list_head 
*folio_list,
                 * (refcount == 1) it can be freed.  Otherwise, leave
                 * the folio on the LRU so it is swappable.
                 */
-               if (folio_needs_release(folio)) {
-                       if (!filemap_release_folio(folio, sc->gfp_mask))
-                               goto activate_locked;
+               switch (filemap_release_folio(folio, sc->gfp_mask)) {
+               case FILEMAP_CANT_RELEASE_FOLIO:
+                       goto activate_locked;
+               case FILEMAP_RELEASED_FOLIO:
                        if (!mapping && folio_ref_count(folio) == 1) {
                                folio_unlock(folio);
                                if (folio_put_testzero(folio))
                                        goto free_it;
-                               else {
-                                       /*
-                                        * rare race with speculative reference.
-                                        * the speculative reference will free
-                                        * this folio shortly, so we may
-                                        * increment nr_reclaimed here (and
-                                        * leave it off the LRU).
-                                        */
-                                       nr_reclaimed += nr_pages;
-                                       continue;
-                               }
+                               /*
+                                * rare race with speculative reference.  the
+                                * speculative reference will free this folio
+                                * shortly, so we may increment nr_reclaimed
+                                * here (and leave it off the LRU).
+                                */
+                               nr_reclaimed += nr_pages;
+                               continue;
                        }
+                       break;
+               case FILEMAP_FOLIO_HAD_NO_PRIVATE:
+                       break;
                }
 
                if (folio_test_anon(folio) && !folio_test_swapbacked(folio)) {


--
Linux-cachefs mailing list
Linux-cachefs@redhat.com
https://listman.redhat.com/mailman/listinfo/linux-cachefs

Reply via email to