This isn't going to apply to your tree; it will apply to today's -next though. Happy to take this on top of my current pagecache patch set with appropriate acks. Maybe it's the wrong fix; I haven't spent very long trying to understand what all the parts of mp mean ... maybe it should only override the META_Dirty check and it needs to do something else for the other two checks? --- 8< --- For ->release_folio(), we can fail to release the metapage if, for example, it's dirty. For ->invalidate_folio(), we must release the metapage as the page is being removed and will be freed. Failing to release the metapage results in xfstests generic/537 hitting BUG reports like this: BUG: Bad page state in process umount pfn:12b03a page:000000000c3e2db5 refcount:0 mapcount:0 mapping:0000000000000000 index:0x10 pfn:0x12b03a flags: 0x8000000000002004(uptodate|private|zone=2) raw: 8000000000002004 ffffea000417a5c8 ffff88810a41bbe0 0000000000000000 raw: 0000000000000010 ffff888124e12680 00000000ffffffff 0000000000000000 page dumped because: PAGE_FLAGS_CHECK_AT_FREE flag(s) set as the page allocator checks that the page no longer has private data. Add a bool argument to inform the release routine whether to override the checks and release the metapage anyway. Signed-off-by: Matthew Wilcox (Oracle) <willy@xxxxxxxxxxxxx> --- fs/jfs/jfs_metapage.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/fs/jfs/jfs_metapage.c b/fs/jfs/jfs_metapage.c index 2e8461ce74de..5b4f0cd8d276 100644 --- a/fs/jfs/jfs_metapage.c +++ b/fs/jfs/jfs_metapage.c @@ -524,7 +524,8 @@ static int metapage_read_folio(struct file *fp, struct folio *folio) return -EIO; } -static bool metapage_release_folio(struct folio *folio, gfp_t gfp_mask) +static bool __metapage_release_folio(struct folio *folio, gfp_t gfp_mask, + bool force) { struct metapage *mp; bool ret = true; @@ -537,8 +538,9 @@ static bool metapage_release_folio(struct folio *folio, gfp_t gfp_mask) continue; jfs_info("metapage_release_folio: mp = 0x%p", mp); - if (mp->count || mp->nohomeok || - test_bit(META_dirty, &mp->flag)) { + if (!force && + (mp->count || mp->nohomeok || + test_bit(META_dirty, &mp->flag))) { jfs_info("count = %ld, nohomeok = %d", mp->count, mp->nohomeok); ret = false; @@ -553,6 +555,11 @@ static bool metapage_release_folio(struct folio *folio, gfp_t gfp_mask) return ret; } +static bool metapage_release_folio(struct folio *folio, gfp_t gfp) +{ + return __metapage_release_folio(folio, gfp, false); +} + static void metapage_invalidate_folio(struct folio *folio, size_t offset, size_t length) { @@ -560,7 +567,7 @@ static void metapage_invalidate_folio(struct folio *folio, size_t offset, BUG_ON(folio_test_writeback(folio)); - metapage_release_folio(folio, 0); + __metapage_release_folio(folio, 0, true); } const struct address_space_operations jfs_metapage_aops = { -- 2.34.1