aboutsummaryrefslogtreecommitdiffstats
path: root/module/os
diff options
context:
space:
mode:
authortstabrawa <[email protected]>2024-09-26 10:57:09 -0500
committerGitHub <[email protected]>2024-09-26 08:57:09 -0700
commitb052035990594408899fa32fd4ad6603b75b6c6d (patch)
treed0547a4d1a94e0f56cbe249ba27fce708207ab47 /module/os
parentb2ca5105b721d572ceefdaf57d3ed498f7ea5553 (diff)
Avoid BUG in migrate_folio_extra
Linux page migration code won't wait for writeback to complete unless it needs to call release_folio. Call SetPagePrivate wherever PageUptodate is set and define .release_folio, to cause fallback_migrate_folio to wait for us. Reviewed-by: Brian Behlendorf <[email protected]> Signed-off-by: tstabrawa <[email protected]> Closes #15140 Closes #16568
Diffstat (limited to 'module/os')
-rw-r--r--module/os/linux/zfs/zfs_vnops_os.c17
-rw-r--r--module/os/linux/zfs/zfs_znode_os.c8
-rw-r--r--module/os/linux/zfs/zpl_file.c46
3 files changed, 71 insertions, 0 deletions
diff --git a/module/os/linux/zfs/zfs_vnops_os.c b/module/os/linux/zfs/zfs_vnops_os.c
index 7d3a7b8d9..3dce3660c 100644
--- a/module/os/linux/zfs/zfs_vnops_os.c
+++ b/module/os/linux/zfs/zfs_vnops_os.c
@@ -260,6 +260,15 @@ update_pages(znode_t *zp, int64_t start, int len, objset_t *os)
} else {
ClearPageError(pp);
SetPageUptodate(pp);
+ if (!PagePrivate(pp)) {
+ /*
+ * Set private bit so page migration
+ * will wait for us to finish writeback
+ * before calling migrate_folio().
+ */
+ SetPagePrivate(pp);
+ get_page(pp);
+ }
if (mapping_writably_mapped(mp))
flush_dcache_page(pp);
@@ -4037,6 +4046,14 @@ zfs_fillpage(struct inode *ip, struct page *pp)
} else {
ClearPageError(pp);
SetPageUptodate(pp);
+ if (!PagePrivate(pp)) {
+ /*
+ * Set private bit so page migration will wait for us to
+ * finish writeback before calling migrate_folio().
+ */
+ SetPagePrivate(pp);
+ get_page(pp);
+ }
}
return (error);
diff --git a/module/os/linux/zfs/zfs_znode_os.c b/module/os/linux/zfs/zfs_znode_os.c
index e135f9044..cea15ad4b 100644
--- a/module/os/linux/zfs/zfs_znode_os.c
+++ b/module/os/linux/zfs/zfs_znode_os.c
@@ -1576,6 +1576,14 @@ zfs_zero_partial_page(znode_t *zp, uint64_t start, uint64_t len)
mark_page_accessed(pp);
SetPageUptodate(pp);
ClearPageError(pp);
+ if (!PagePrivate(pp)) {
+ /*
+ * Set private bit so page migration will wait for us to
+ * finish writeback before calling migrate_folio().
+ */
+ SetPagePrivate(pp);
+ get_page(pp);
+ }
unlock_page(pp);
put_page(pp);
}
diff --git a/module/os/linux/zfs/zpl_file.c b/module/os/linux/zfs/zpl_file.c
index 4d1bf1d54..50c63695d 100644
--- a/module/os/linux/zfs/zpl_file.c
+++ b/module/os/linux/zfs/zpl_file.c
@@ -607,6 +607,42 @@ zpl_writepage(struct page *pp, struct writeback_control *wbc)
return (zpl_putpage(pp, wbc, &for_sync));
}
+static int
+zpl_releasepage(struct page *pp, gfp_t gfp)
+{
+ if (PagePrivate(pp)) {
+ ClearPagePrivate(pp);
+ put_page(pp);
+ }
+ return (1);
+}
+
+#ifdef HAVE_VFS_RELEASE_FOLIO
+static bool
+zpl_release_folio(struct folio *folio, gfp_t gfp)
+{
+ return (zpl_releasepage(&folio->page, gfp));
+}
+#endif
+
+#ifdef HAVE_VFS_INVALIDATE_FOLIO
+static void
+zpl_invalidate_folio(struct folio *folio, size_t offset, size_t len)
+{
+ if ((offset == 0) && (len == PAGE_SIZE)) {
+ zpl_releasepage(&folio->page, 0);
+ }
+}
+#else
+static void
+zpl_invalidatepage(struct page *pp, unsigned int offset, unsigned int len)
+{
+ if ((offset == 0) && (len == PAGE_SIZE)) {
+ zpl_releasepage(pp, 0);
+ }
+}
+#endif
+
/*
* The flag combination which matches the behavior of zfs_space() is
* FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE. The FALLOC_FL_PUNCH_HOLE
@@ -1090,6 +1126,16 @@ const struct address_space_operations zpl_address_space_operations = {
#ifdef HAVE_VFS_FILEMAP_DIRTY_FOLIO
.dirty_folio = filemap_dirty_folio,
#endif
+#ifdef HAVE_VFS_RELEASE_FOLIO
+ .release_folio = zpl_release_folio,
+#else
+ .releasepage = zpl_releasepage,
+#endif
+#ifdef HAVE_VFS_INVALIDATE_FOLIO
+ .invalidate_folio = zpl_invalidate_folio,
+#else
+ .invalidatepage = zpl_invalidatepage,
+#endif
};
const struct file_operations zpl_file_operations = {