mirror of
https://git.proxmox.com/git/mirror_zfs.git
synced 2025-04-06 17:49:11 +03:00
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 <behlendorf1@llnl.gov> Signed-off-by: tstabrawa <59430211+tstabrawa@users.noreply.github.com> Closes #15140 Closes #16568
This commit is contained in:
parent
b2ca5105b7
commit
b052035990
33
config/kernel-vfs-invalidate_folio.m4
Normal file
33
config/kernel-vfs-invalidate_folio.m4
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
dnl #
|
||||||
|
dnl # Linux 5.18 uses invalidate_folio in lieu of invalidate_page
|
||||||
|
dnl #
|
||||||
|
AC_DEFUN([ZFS_AC_KERNEL_SRC_VFS_INVALIDATE_FOLIO], [
|
||||||
|
ZFS_LINUX_TEST_SRC([vfs_has_invalidate_folio], [
|
||||||
|
#include <linux/fs.h>
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_invalidate_folio(struct folio *folio, size_t offset,
|
||||||
|
size_t len) {
|
||||||
|
(void) folio; (void) offset; (void) len;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct address_space_operations
|
||||||
|
aops __attribute__ ((unused)) = {
|
||||||
|
.invalidate_folio = test_invalidate_folio,
|
||||||
|
};
|
||||||
|
],[])
|
||||||
|
])
|
||||||
|
|
||||||
|
AC_DEFUN([ZFS_AC_KERNEL_VFS_INVALIDATE_FOLIO], [
|
||||||
|
dnl #
|
||||||
|
dnl # Linux 5.18 uses invalidate_folio in lieu of invalidate_page
|
||||||
|
dnl #
|
||||||
|
AC_MSG_CHECKING([whether invalidate_folio exists])
|
||||||
|
ZFS_LINUX_TEST_RESULT([vfs_has_invalidate_folio], [
|
||||||
|
AC_MSG_RESULT([yes])
|
||||||
|
AC_DEFINE(HAVE_VFS_INVALIDATE_FOLIO, 1, [invalidate_folio exists])
|
||||||
|
],[
|
||||||
|
AC_MSG_RESULT([no])
|
||||||
|
])
|
||||||
|
])
|
32
config/kernel-vfs-release_folio.m4
Normal file
32
config/kernel-vfs-release_folio.m4
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
dnl #
|
||||||
|
dnl # Linux 5.19 uses release_folio in lieu of releasepage
|
||||||
|
dnl #
|
||||||
|
AC_DEFUN([ZFS_AC_KERNEL_SRC_VFS_RELEASE_FOLIO], [
|
||||||
|
ZFS_LINUX_TEST_SRC([vfs_has_release_folio], [
|
||||||
|
#include <linux/fs.h>
|
||||||
|
|
||||||
|
static bool
|
||||||
|
test_release_folio(struct folio *folio, gfp_t gfp) {
|
||||||
|
(void) folio; (void) gfp;
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct address_space_operations
|
||||||
|
aops __attribute__ ((unused)) = {
|
||||||
|
.release_folio = test_release_folio,
|
||||||
|
};
|
||||||
|
],[])
|
||||||
|
])
|
||||||
|
|
||||||
|
AC_DEFUN([ZFS_AC_KERNEL_VFS_RELEASE_FOLIO], [
|
||||||
|
dnl #
|
||||||
|
dnl # Linux 5.19 uses release_folio in lieu of releasepage
|
||||||
|
dnl #
|
||||||
|
AC_MSG_CHECKING([whether release_folio exists])
|
||||||
|
ZFS_LINUX_TEST_RESULT([vfs_has_release_folio], [
|
||||||
|
AC_MSG_RESULT([yes])
|
||||||
|
AC_DEFINE(HAVE_VFS_RELEASE_FOLIO, 1, [release_folio exists])
|
||||||
|
],[
|
||||||
|
AC_MSG_RESULT([no])
|
||||||
|
])
|
||||||
|
])
|
@ -77,6 +77,8 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_SRC], [
|
|||||||
ZFS_AC_KERNEL_SRC_SGET
|
ZFS_AC_KERNEL_SRC_SGET
|
||||||
ZFS_AC_KERNEL_SRC_VFS_FILEMAP_DIRTY_FOLIO
|
ZFS_AC_KERNEL_SRC_VFS_FILEMAP_DIRTY_FOLIO
|
||||||
ZFS_AC_KERNEL_SRC_VFS_READ_FOLIO
|
ZFS_AC_KERNEL_SRC_VFS_READ_FOLIO
|
||||||
|
ZFS_AC_KERNEL_SRC_VFS_RELEASE_FOLIO
|
||||||
|
ZFS_AC_KERNEL_SRC_VFS_INVALIDATE_FOLIO
|
||||||
ZFS_AC_KERNEL_SRC_VFS_FSYNC_2ARGS
|
ZFS_AC_KERNEL_SRC_VFS_FSYNC_2ARGS
|
||||||
ZFS_AC_KERNEL_SRC_VFS_DIRECT_IO
|
ZFS_AC_KERNEL_SRC_VFS_DIRECT_IO
|
||||||
ZFS_AC_KERNEL_SRC_VFS_READPAGES
|
ZFS_AC_KERNEL_SRC_VFS_READPAGES
|
||||||
@ -185,6 +187,8 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_RESULT], [
|
|||||||
ZFS_AC_KERNEL_SGET
|
ZFS_AC_KERNEL_SGET
|
||||||
ZFS_AC_KERNEL_VFS_FILEMAP_DIRTY_FOLIO
|
ZFS_AC_KERNEL_VFS_FILEMAP_DIRTY_FOLIO
|
||||||
ZFS_AC_KERNEL_VFS_READ_FOLIO
|
ZFS_AC_KERNEL_VFS_READ_FOLIO
|
||||||
|
ZFS_AC_KERNEL_VFS_RELEASE_FOLIO
|
||||||
|
ZFS_AC_KERNEL_VFS_INVALIDATE_FOLIO
|
||||||
ZFS_AC_KERNEL_VFS_FSYNC_2ARGS
|
ZFS_AC_KERNEL_VFS_FSYNC_2ARGS
|
||||||
ZFS_AC_KERNEL_VFS_DIRECT_IO
|
ZFS_AC_KERNEL_VFS_DIRECT_IO
|
||||||
ZFS_AC_KERNEL_VFS_READPAGES
|
ZFS_AC_KERNEL_VFS_READPAGES
|
||||||
|
@ -260,6 +260,15 @@ update_pages(znode_t *zp, int64_t start, int len, objset_t *os)
|
|||||||
} else {
|
} else {
|
||||||
ClearPageError(pp);
|
ClearPageError(pp);
|
||||||
SetPageUptodate(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))
|
if (mapping_writably_mapped(mp))
|
||||||
flush_dcache_page(pp);
|
flush_dcache_page(pp);
|
||||||
@ -4037,6 +4046,14 @@ zfs_fillpage(struct inode *ip, struct page *pp)
|
|||||||
} else {
|
} else {
|
||||||
ClearPageError(pp);
|
ClearPageError(pp);
|
||||||
SetPageUptodate(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);
|
return (error);
|
||||||
|
@ -1576,6 +1576,14 @@ zfs_zero_partial_page(znode_t *zp, uint64_t start, uint64_t len)
|
|||||||
mark_page_accessed(pp);
|
mark_page_accessed(pp);
|
||||||
SetPageUptodate(pp);
|
SetPageUptodate(pp);
|
||||||
ClearPageError(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);
|
unlock_page(pp);
|
||||||
put_page(pp);
|
put_page(pp);
|
||||||
}
|
}
|
||||||
|
@ -607,6 +607,42 @@ zpl_writepage(struct page *pp, struct writeback_control *wbc)
|
|||||||
return (zpl_putpage(pp, wbc, &for_sync));
|
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
|
* The flag combination which matches the behavior of zfs_space() is
|
||||||
* FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE. The FALLOC_FL_PUNCH_HOLE
|
* 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
|
#ifdef HAVE_VFS_FILEMAP_DIRTY_FOLIO
|
||||||
.dirty_folio = filemap_dirty_folio,
|
.dirty_folio = filemap_dirty_folio,
|
||||||
#endif
|
#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 = {
|
const struct file_operations zpl_file_operations = {
|
||||||
|
Loading…
Reference in New Issue
Block a user