]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
jfs: implement migrate_folio for jfs_metapage_aops
authorShivank Garg <shivankg@amd.com>
Wed, 30 Apr 2025 10:01:52 +0000 (10:01 +0000)
committerAndrew Morton <akpm@linux-foundation.org>
Tue, 13 May 2025 06:50:47 +0000 (23:50 -0700)
Add the missing migrate_folio operation to jfs_metapage_aops to fix
warnings during memory compaction.  These warnings were introduced by
commit 7ee3647243e5 ("migrate: Remove call to ->writepage") which added
explicit warnings when filesystems don't implement migrate_folio.

System reports following warnings:
  jfs_metapage_aops does not implement migrate_folio
  WARNING: CPU: 0 PID: 6870 at mm/migrate.c:955 fallback_migrate_folio mm/migrate.c:953 [inline]
  WARNING: CPU: 0 PID: 6870 at mm/migrate.c:955 move_to_new_folio+0x70e/0x840 mm/migrate.c:1007

Implement metapage_migrate_folio() which handles both single and multiple
metapages per page configurations.

[shivankg@amd.com: change comment style]
Link: https://lkml.kernel.org/r/1967593d-8084-4a4a-b384-35d5adc54eb4@amd.com
[akpm@linux-foundation.org: fix build]
[shivankg@amd.com: remove redundant NULL check in __metapage_migrate_folio()]
Link: https://lkml.kernel.org/r/a67db238-0ca6-4725-abb2-dc092de87e1b@amd.com
Link: https://lkml.kernel.org/r/20250430100150.279751-3-shivankg@amd.com
Fixes: 35474d52c605 ("jfs: Convert metapage_writepage to metapage_write_folio")
Signed-off-by: Shivank Garg <shivankg@amd.com>
Reported-by: syzbot+8bb6fd945af4e0ad9299@syzkaller.appspotmail.com
Closes: https://lore.kernel.org/all/67faff52.050a0220.379d84.001b.GAE@google.com
Tested-by: syzbot+8bb6fd945af4e0ad9299@syzkaller.appspotmail.com
Cc: Alistair Popple <apopple@nvidia.com>
Cc: Dave Kleikamp <shaggy@kernel.org>
Cc: David Hildenbrand <david@redhat.com>
Cc: Donet Tom <donettom@linux.ibm.com>
Cc: Jane Chu <jane.chu@oracle.com>
Cc: Kefeng Wang <wangkefeng.wang@huawei.com>
Cc: Matthew Wilcox <willy@infradead.org>
Cc: Zi Yan <ziy@nvidia.com>
Cc: Dan Carpenter <dan.carpenter@linaro.org>
Cc: kernel test robot <lkp@intel.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
fs/jfs/jfs_metapage.c

index df575a873ec6d4af27c4c2c1dfd380b233f3d590..9029cd2169121326cb6f9ede0f4f757a7c9a56a0 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/mempool.h>
 #include <linux/seq_file.h>
 #include <linux/writeback.h>
+#include <linux/migrate.h>
 #include "jfs_incore.h"
 #include "jfs_superblock.h"
 #include "jfs_filsys.h"
@@ -151,7 +152,59 @@ static inline void dec_io(struct folio *folio, blk_status_t status,
                handler(folio, anchor->status);
 }
 
+#ifdef CONFIG_MIGRATION
+static int __metapage_migrate_folio(struct address_space *mapping,
+                                   struct folio *dst, struct folio *src,
+                                   enum migrate_mode mode)
+{
+       struct meta_anchor *src_anchor = src->private;
+       struct metapage *mps[MPS_PER_PAGE] = {0};
+       struct metapage *mp;
+       int i, rc;
+
+       for (i = 0; i < MPS_PER_PAGE; i++) {
+               mp = src_anchor->mp[i];
+               if (mp && metapage_locked(mp))
+                       return -EAGAIN;
+       }
+
+       rc = filemap_migrate_folio(mapping, dst, src, mode);
+       if (rc != MIGRATEPAGE_SUCCESS)
+               return rc;
+
+       for (i = 0; i < MPS_PER_PAGE; i++) {
+               mp = src_anchor->mp[i];
+               if (!mp)
+                       continue;
+               if (unlikely(insert_metapage(dst, mp))) {
+                       /* If error, roll-back previosly inserted pages */
+                       for (int j = 0 ; j < i; j++) {
+                               if (mps[j])
+                                       remove_metapage(dst, mps[j]);
+                       }
+                       return -EAGAIN;
+               }
+               mps[i] = mp;
+       }
+
+       /* Update the metapage and remove it from src */
+       for (i = 0; i < MPS_PER_PAGE; i++) {
+               mp = mps[i];
+               if (mp) {
+                       int page_offset = mp->data - folio_address(src);
+
+                       mp->data = folio_address(dst) + page_offset;
+                       mp->folio = dst;
+                       remove_metapage(src, mp);
+               }
+       }
+
+       return MIGRATEPAGE_SUCCESS;
+}
+#endif /* CONFIG_MIGRATION */
+
 #else
+
 static inline struct metapage *folio_to_mp(struct folio *folio, int offset)
 {
        return folio->private;
@@ -175,6 +228,35 @@ static inline void remove_metapage(struct folio *folio, struct metapage *mp)
 #define inc_io(folio) do {} while(0)
 #define dec_io(folio, status, handler) handler(folio, status)
 
+#ifdef CONFIG_MIGRATION
+static int __metapage_migrate_folio(struct address_space *mapping,
+                                   struct folio *dst, struct folio *src,
+                                   enum migrate_mode mode)
+{
+       struct metapage *mp;
+       int page_offset;
+       int rc;
+
+       mp = folio_to_mp(src, 0);
+       if (metapage_locked(mp))
+               return -EAGAIN;
+
+       rc = filemap_migrate_folio(mapping, dst, src, mode);
+       if (rc != MIGRATEPAGE_SUCCESS)
+               return rc;
+
+       if (unlikely(insert_metapage(dst, mp)))
+               return -EAGAIN;
+
+       page_offset = mp->data - folio_address(src);
+       mp->data = folio_address(dst) + page_offset;
+       mp->folio = dst;
+       remove_metapage(src, mp);
+
+       return MIGRATEPAGE_SUCCESS;
+}
+#endif /* CONFIG_MIGRATION */
+
 #endif
 
 static inline struct metapage *alloc_metapage(gfp_t gfp_mask)
@@ -554,6 +636,29 @@ static bool metapage_release_folio(struct folio *folio, gfp_t gfp_mask)
        return ret;
 }
 
+#ifdef CONFIG_MIGRATION
+/*
+ * metapage_migrate_folio - Migration function for JFS metapages
+ */
+static int metapage_migrate_folio(struct address_space *mapping,
+                                 struct folio *dst, struct folio *src,
+                                 enum migrate_mode mode)
+{
+       int expected_count;
+
+       if (!src->private)
+               return filemap_migrate_folio(mapping, dst, src, mode);
+
+       /* Check whether page does not have extra refs before we do more work */
+       expected_count = folio_expected_ref_count(src) + 1;
+       if (folio_ref_count(src) != expected_count)
+               return -EAGAIN;
+       return __metapage_migrate_folio(mapping, dst, src, mode);
+}
+#else
+#define metapage_migrate_folio NULL
+#endif /* CONFIG_MIGRATION */
+
 static void metapage_invalidate_folio(struct folio *folio, size_t offset,
                                    size_t length)
 {
@@ -570,6 +675,7 @@ const struct address_space_operations jfs_metapage_aops = {
        .release_folio  = metapage_release_folio,
        .invalidate_folio = metapage_invalidate_folio,
        .dirty_folio    = filemap_dirty_folio,
+       .migrate_folio  = metapage_migrate_folio,
 };
 
 struct metapage *__get_metapage(struct inode *inode, unsigned long lblock,