diff options
author | tstabrawa <[email protected]> | 2024-09-26 10:57:09 -0500 |
---|---|---|
committer | GitHub <[email protected]> | 2024-09-26 08:57:09 -0700 |
commit | b052035990594408899fa32fd4ad6603b75b6c6d (patch) | |
tree | d0547a4d1a94e0f56cbe249ba27fce708207ab47 /module/os | |
parent | b2ca5105b721d572ceefdaf57d3ed498f7ea5553 (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.c | 17 | ||||
-rw-r--r-- | module/os/linux/zfs/zfs_znode_os.c | 8 | ||||
-rw-r--r-- | module/os/linux/zfs/zpl_file.c | 46 |
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 = { |