Skip to content

Commit 1c24bf9

Browse files
authored
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 <[email protected]> Signed-off-by: Coleman Kane <[email protected]> Closes #12427
1 parent f1ca799 commit 1c24bf9

File tree

3 files changed

+42
-0
lines changed

3 files changed

+42
-0
lines changed

config/kernel-vfs-set_page_dirty.m4

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
dnl #
2+
dnl # Linux 5.14 adds a change to require set_page_dirty to be manually
3+
dnl # wired up in struct address_space_operations. Determine if this needs
4+
dnl # to be done. This patch set also introduced __set_page_dirty_nobuffers
5+
dnl # declaration in linux/pagemap.h, so these tests look for the presence
6+
dnl # of that function to tell the compiler to assign set_page_dirty in
7+
dnl # module/os/linux/zfs/zpl_file.c
8+
dnl #
9+
AC_DEFUN([ZFS_AC_KERNEL_SRC_VFS_SET_PAGE_DIRTY_NOBUFFERS], [
10+
ZFS_LINUX_TEST_SRC([vfs_has_set_page_dirty_nobuffers], [
11+
#include <linux/pagemap.h>
12+
#include <linux/fs.h>
13+
14+
static const struct address_space_operations
15+
aops __attribute__ ((unused)) = {
16+
.set_page_dirty = __set_page_dirty_nobuffers,
17+
};
18+
],[])
19+
])
20+
21+
AC_DEFUN([ZFS_AC_KERNEL_VFS_SET_PAGE_DIRTY_NOBUFFERS], [
22+
dnl #
23+
dnl # Linux 5.14 change requires set_page_dirty() to be assigned
24+
dnl # in address_space_operations()
25+
dnl #
26+
AC_MSG_CHECKING([__set_page_dirty_nobuffers exists])
27+
ZFS_LINUX_TEST_RESULT([vfs_has_set_page_dirty_nobuffers], [
28+
AC_MSG_RESULT([yes])
29+
AC_DEFINE(HAVE_VFS_SET_PAGE_DIRTY_NOBUFFERS, 1,
30+
[__set_page_dirty_nobuffers exists])
31+
],[
32+
AC_MSG_RESULT([no])
33+
])
34+
])

config/kernel.m4

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,7 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_SRC], [
132132
ZFS_AC_KERNEL_SRC_SIGNAL_STOP
133133
ZFS_AC_KERNEL_SRC_SIGINFO
134134
ZFS_AC_KERNEL_SRC_SET_SPECIAL_STATE
135+
ZFS_AC_KERNEL_SRC_VFS_SET_PAGE_DIRTY_NOBUFFERS
135136
136137
AC_MSG_CHECKING([for available kernel interfaces])
137138
ZFS_LINUX_TEST_COMPILE_ALL([kabi])
@@ -237,6 +238,7 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_RESULT], [
237238
ZFS_AC_KERNEL_SIGNAL_STOP
238239
ZFS_AC_KERNEL_SIGINFO
239240
ZFS_AC_KERNEL_SET_SPECIAL_STATE
241+
ZFS_AC_KERNEL_VFS_SET_PAGE_DIRTY_NOBUFFERS
240242
])
241243

242244
dnl #

module/os/linux/zfs/zpl_file.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@
3333
#include <sys/zfs_vfsops.h>
3434
#include <sys/zfs_vnops.h>
3535
#include <sys/zfs_project.h>
36+
#ifdef HAVE_VFS_SET_PAGE_DIRTY_NOBUFFERS
37+
#include <linux/pagemap.h>
38+
#endif
3639

3740
/*
3841
* When using fallocate(2) to preallocate space, inflate the requested
@@ -1018,6 +1021,9 @@ const struct address_space_operations zpl_address_space_operations = {
10181021
.writepage = zpl_writepage,
10191022
.writepages = zpl_writepages,
10201023
.direct_IO = zpl_direct_IO,
1024+
#ifdef HAVE_VFS_SET_PAGE_DIRTY_NOBUFFERS
1025+
.set_page_dirty = __set_page_dirty_nobuffers,
1026+
#endif
10211027
};
10221028

10231029
const struct file_operations zpl_file_operations = {

0 commit comments

Comments
 (0)