summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorColeman Kane <ckane@colemankane.org>2021-07-26 13:55:55 -0400
committerTony Hutter <hutter2@llnl.gov>2021-09-22 15:19:08 -0700
commit6b9d0eda7573b68e0a6e0e1e972fb3b6e2c00804 (patch)
tree93cc2f5c9271b286c978ed2496418f764003af1a
parent744cdfd93b9e4d4e8ccc445cdc7371164b1a3bed (diff)
Linux 5.14 compat: explicity assign set_page_dirty
Kernel 5.14 introduced a change where set_page_dirty of struct address_space_operations is no longer implicitly set to __set_page_dirty_buffers(), which ended up resulting in a NULL pointer deref in the kernel when it is attempted to be called. This change sets .set_page_dirty in the structure to __set_page_dirty_nobuffers(), which was introduced with the related patch set. The breaking change was introduce in commit 0af573780b0b13fceb7fabd49dc1b073cee9a507 to torvalds/linux.git. Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov> Signed-off-by: Coleman Kane <ckane@colemankane.org> Closes #12427
-rw-r--r--config/kernel-vfs-set_page_dirty.m434
-rw-r--r--config/kernel.m42
-rw-r--r--module/os/linux/zfs/zpl_file.c6
3 files changed, 42 insertions, 0 deletions
diff --git a/config/kernel-vfs-set_page_dirty.m4 b/config/kernel-vfs-set_page_dirty.m4
new file mode 100644
index 000000000..a9d252e4e
--- /dev/null
+++ b/config/kernel-vfs-set_page_dirty.m4
@@ -0,0 +1,34 @@
+dnl #
+dnl # Linux 5.14 adds a change to require set_page_dirty to be manually
+dnl # wired up in struct address_space_operations. Determine if this needs
+dnl # to be done. This patch set also introduced __set_page_dirty_nobuffers
+dnl # declaration in linux/pagemap.h, so these tests look for the presence
+dnl # of that function to tell the compiler to assign set_page_dirty in
+dnl # module/os/linux/zfs/zpl_file.c
+dnl #
+AC_DEFUN([ZFS_AC_KERNEL_SRC_VFS_SET_PAGE_DIRTY_NOBUFFERS], [
+ ZFS_LINUX_TEST_SRC([vfs_has_set_page_dirty_nobuffers], [
+ #include <linux/pagemap.h>
+ #include <linux/fs.h>
+
+ static const struct address_space_operations
+ aops __attribute__ ((unused)) = {
+ .set_page_dirty = __set_page_dirty_nobuffers,
+ };
+ ],[])
+])
+
+AC_DEFUN([ZFS_AC_KERNEL_VFS_SET_PAGE_DIRTY_NOBUFFERS], [
+ dnl #
+ dnl # Linux 5.14 change requires set_page_dirty() to be assigned
+ dnl # in address_space_operations()
+ dnl #
+ AC_MSG_CHECKING([__set_page_dirty_nobuffers exists])
+ ZFS_LINUX_TEST_RESULT([vfs_has_set_page_dirty_nobuffers], [
+ AC_MSG_RESULT([yes])
+ AC_DEFINE(HAVE_VFS_SET_PAGE_DIRTY_NOBUFFERS, 1,
+ [__set_page_dirty_nobuffers exists])
+ ],[
+ AC_MSG_RESULT([no])
+ ])
+])
diff --git a/config/kernel.m4 b/config/kernel.m4
index c66c3a405..3433a300a 100644
--- a/config/kernel.m4
+++ b/config/kernel.m4
@@ -131,6 +131,7 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_SRC], [
ZFS_AC_KERNEL_SRC_SIGNAL_STOP
ZFS_AC_KERNEL_SRC_SIGINFO
ZFS_AC_KERNEL_SRC_SET_SPECIAL_STATE
+ ZFS_AC_KERNEL_SRC_VFS_SET_PAGE_DIRTY_NOBUFFERS
AC_MSG_CHECKING([for available kernel interfaces])
ZFS_LINUX_TEST_COMPILE_ALL([kabi])
@@ -235,6 +236,7 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_RESULT], [
ZFS_AC_KERNEL_SIGNAL_STOP
ZFS_AC_KERNEL_SIGINFO
ZFS_AC_KERNEL_SET_SPECIAL_STATE
+ ZFS_AC_KERNEL_VFS_SET_PAGE_DIRTY_NOBUFFERS
])
dnl #
diff --git a/module/os/linux/zfs/zpl_file.c b/module/os/linux/zfs/zpl_file.c
index 10a07f327..cd54c40ac 100644
--- a/module/os/linux/zfs/zpl_file.c
+++ b/module/os/linux/zfs/zpl_file.c
@@ -33,6 +33,9 @@
#include <sys/zfs_vfsops.h>
#include <sys/zfs_vnops.h>
#include <sys/zfs_project.h>
+#ifdef HAVE_VFS_SET_PAGE_DIRTY_NOBUFFERS
+#include <linux/pagemap.h>
+#endif
/*
* When using fallocate(2) to preallocate space, inflate the requested
@@ -1007,6 +1010,9 @@ const struct address_space_operations zpl_address_space_operations = {
.writepage = zpl_writepage,
.writepages = zpl_writepages,
.direct_IO = zpl_direct_IO,
+#ifdef HAVE_VFS_SET_PAGE_DIRTY_NOBUFFERS
+ .set_page_dirty = __set_page_dirty_nobuffers,
+#endif
};
const struct file_operations zpl_file_operations = {