Skip to content

Commit 0201ebf

Browse files
dhowellsakpm00
authored andcommitted
mm: merge folio_has_private()/filemap_release_folio() call pairs
Patch series "mm, netfs, fscache: Stop read optimisation when folio removed from pagecache", v7. This fixes an optimisation in fscache whereby we don't read from the cache for a particular file until we know that there's data there that we don't have in the pagecache. The problem is that I'm no longer using PG_fscache (aka PG_private_2) to indicate that the page is cached and so I don't get a notification when a cached page is dropped from the pagecache. The first patch merges some folio_has_private() and filemap_release_folio() pairs and introduces a helper, folio_needs_release(), to indicate if a release is required. The second patch is the actual fix. Following Willy's suggestions[1], it adds an AS_RELEASE_ALWAYS flag to an address_space that will make filemap_release_folio() always call ->release_folio(), even if PG_private/PG_private_2 aren't set. folio_needs_release() is altered to add a check for this. This patch (of 2): Make filemap_release_folio() check folio_has_private(). Then, in most cases, where a call to folio_has_private() is immediately followed by a call to filemap_release_folio(), we can get rid of the test in the pair. There are a couple of sites in mm/vscan.c that this can't so easily be done. In shrink_folio_list(), there are actually three cases (something different is done for incompletely invalidated buffers), but filemap_release_folio() elides two of them. In shrink_active_list(), we don't have have the folio lock yet, so the check allows us to avoid locking the page unnecessarily. A wrapper function to check if a folio needs release is provided for those places that still need to do it in the mm/ directory. This will acquire additional parts to the condition in a future patch. After this, the only remaining caller of folio_has_private() outside of mm/ is a check in fuse. Link: https://lkml.kernel.org/r/[email protected] Link: https://lkml.kernel.org/r/[email protected] Reported-by: Rohith Surabattula <[email protected]> Suggested-by: Matthew Wilcox <[email protected]> Signed-off-by: David Howells <[email protected]> Cc: Matthew Wilcox <[email protected]> Cc: Linus Torvalds <[email protected]> Cc: Steve French <[email protected]> Cc: Shyam Prasad N <[email protected]> Cc: Rohith Surabattula <[email protected]> Cc: Dave Wysochanski <[email protected]> Cc: Dominique Martinet <[email protected]> Cc: Ilya Dryomov <[email protected]> Cc: "Theodore Ts'o" <[email protected]> Cc: Andreas Dilger <[email protected]> Cc: Xiubo Li <[email protected]> Cc: Jingbo Xu <[email protected]> Signed-off-by: Andrew Morton <[email protected]>
1 parent dba438b commit 0201ebf

File tree

10 files changed

+27
-29
lines changed

10 files changed

+27
-29
lines changed

fs/ext4/move_extent.c

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -340,10 +340,8 @@ move_extent_per_page(struct file *o_filp, struct inode *donor_inode,
340340
ext4_double_up_write_data_sem(orig_inode, donor_inode);
341341
goto data_copy;
342342
}
343-
if ((folio_has_private(folio[0]) &&
344-
!filemap_release_folio(folio[0], 0)) ||
345-
(folio_has_private(folio[1]) &&
346-
!filemap_release_folio(folio[1], 0))) {
343+
if (!filemap_release_folio(folio[0], 0) ||
344+
!filemap_release_folio(folio[1], 0)) {
347345
*err = -EBUSY;
348346
goto drop_data_sem;
349347
}
@@ -362,10 +360,8 @@ move_extent_per_page(struct file *o_filp, struct inode *donor_inode,
362360

363361
/* At this point all buffers in range are uptodate, old mapping layout
364362
* is no longer required, try to drop it now. */
365-
if ((folio_has_private(folio[0]) &&
366-
!filemap_release_folio(folio[0], 0)) ||
367-
(folio_has_private(folio[1]) &&
368-
!filemap_release_folio(folio[1], 0))) {
363+
if (!filemap_release_folio(folio[0], 0) ||
364+
!filemap_release_folio(folio[1], 0)) {
369365
*err = -EBUSY;
370366
goto unlock_folios;
371367
}

fs/splice.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,8 +83,7 @@ static bool page_cache_pipe_buf_try_steal(struct pipe_inode_info *pipe,
8383
*/
8484
folio_wait_writeback(folio);
8585

86-
if (folio_has_private(folio) &&
87-
!filemap_release_folio(folio, GFP_KERNEL))
86+
if (!filemap_release_folio(folio, GFP_KERNEL))
8887
goto out_unlock;
8988

9089
/*

mm/filemap.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4073,6 +4073,8 @@ bool filemap_release_folio(struct folio *folio, gfp_t gfp)
40734073
struct address_space * const mapping = folio->mapping;
40744074

40754075
BUG_ON(!folio_test_locked(folio));
4076+
if (!folio_needs_release(folio))
4077+
return true;
40764078
if (folio_test_writeback(folio))
40774079
return false;
40784080

mm/huge_memory.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2697,8 +2697,7 @@ int split_huge_page_to_list(struct page *page, struct list_head *list)
26972697
gfp = current_gfp_context(mapping_gfp_mask(mapping) &
26982698
GFP_RECLAIM_MASK);
26992699

2700-
if (folio_test_private(folio) &&
2701-
!filemap_release_folio(folio, gfp)) {
2700+
if (!filemap_release_folio(folio, gfp)) {
27022701
ret = -EBUSY;
27032702
goto out;
27042703
}

mm/internal.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,14 @@ static inline void set_page_refcounted(struct page *page)
176176
set_page_count(page, 1);
177177
}
178178

179+
/*
180+
* Return true if a folio needs ->release_folio() calling upon it.
181+
*/
182+
static inline bool folio_needs_release(struct folio *folio)
183+
{
184+
return folio_has_private(folio);
185+
}
186+
179187
extern unsigned long highest_memmap_pfn;
180188

181189
/*

mm/khugepaged.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2078,8 +2078,7 @@ static int collapse_file(struct mm_struct *mm, unsigned long addr,
20782078
goto out_unlock;
20792079
}
20802080

2081-
if (folio_has_private(folio) &&
2082-
!filemap_release_folio(folio, GFP_KERNEL)) {
2081+
if (!filemap_release_folio(folio, GFP_KERNEL)) {
20832082
result = SCAN_PAGE_HAS_PRIVATE;
20842083
folio_putback_lru(folio);
20852084
goto out_unlock;

mm/memory-failure.c

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -936,14 +936,12 @@ static int truncate_error_page(struct page *p, unsigned long pfn,
936936
struct folio *folio = page_folio(p);
937937
int err = mapping->a_ops->error_remove_page(mapping, p);
938938

939-
if (err != 0) {
939+
if (err != 0)
940940
pr_info("%#lx: Failed to punch page: %d\n", pfn, err);
941-
} else if (folio_has_private(folio) &&
942-
!filemap_release_folio(folio, GFP_NOIO)) {
941+
else if (!filemap_release_folio(folio, GFP_NOIO))
943942
pr_info("%#lx: failed to release buffers\n", pfn);
944-
} else {
943+
else
945944
ret = MF_RECOVERED;
946-
}
947945
} else {
948946
/*
949947
* If the file system doesn't support it just invalidate

mm/migrate.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -922,8 +922,7 @@ static int fallback_migrate_folio(struct address_space *mapping,
922922
* Buffers may be managed in a filesystem specific way.
923923
* We must have no buffers or drop them.
924924
*/
925-
if (folio_test_private(src) &&
926-
!filemap_release_folio(src, GFP_KERNEL))
925+
if (!filemap_release_folio(src, GFP_KERNEL))
927926
return mode == MIGRATE_SYNC ? -EAGAIN : -EBUSY;
928927

929928
return migrate_folio(mapping, dst, src, mode);

mm/truncate.c

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
#include <linux/highmem.h>
2020
#include <linux/pagevec.h>
2121
#include <linux/task_io_accounting_ops.h>
22-
#include <linux/buffer_head.h> /* grr. try_to_release_page */
2322
#include <linux/shmem_fs.h>
2423
#include <linux/rmap.h>
2524
#include "internal.h"
@@ -276,7 +275,7 @@ static long mapping_evict_folio(struct address_space *mapping,
276275
if (folio_ref_count(folio) >
277276
folio_nr_pages(folio) + folio_has_private(folio) + 1)
278277
return 0;
279-
if (folio_has_private(folio) && !filemap_release_folio(folio, 0))
278+
if (!filemap_release_folio(folio, 0))
280279
return 0;
281280

282281
return remove_mapping(mapping, folio);
@@ -573,8 +572,7 @@ static int invalidate_complete_folio2(struct address_space *mapping,
573572
if (folio->mapping != mapping)
574573
return 0;
575574

576-
if (folio_has_private(folio) &&
577-
!filemap_release_folio(folio, GFP_KERNEL))
575+
if (!filemap_release_folio(folio, GFP_KERNEL))
578576
return 0;
579577

580578
spin_lock(&mapping->host->i_lock);

mm/vmscan.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2064,7 +2064,7 @@ static unsigned int shrink_folio_list(struct list_head *folio_list,
20642064
* (refcount == 1) it can be freed. Otherwise, leave
20652065
* the folio on the LRU so it is swappable.
20662066
*/
2067-
if (folio_has_private(folio)) {
2067+
if (folio_needs_release(folio)) {
20682068
if (!filemap_release_folio(folio, sc->gfp_mask))
20692069
goto activate_locked;
20702070
if (!mapping && folio_ref_count(folio) == 1) {
@@ -2729,9 +2729,9 @@ static void shrink_active_list(unsigned long nr_to_scan,
27292729
}
27302730

27312731
if (unlikely(buffer_heads_over_limit)) {
2732-
if (folio_test_private(folio) && folio_trylock(folio)) {
2733-
if (folio_test_private(folio))
2734-
filemap_release_folio(folio, 0);
2732+
if (folio_needs_release(folio) &&
2733+
folio_trylock(folio)) {
2734+
filemap_release_folio(folio, 0);
27352735
folio_unlock(folio);
27362736
}
27372737
}

0 commit comments

Comments
 (0)