Skip to content

Commit 9631ecf

Browse files
snajpatonyhutter
authored andcommitted
Linux: Fix zfs_prune panics v2
It turns out that approach taken in the original version of the patch was wrong. So now, we're taking approach in-line with how kernel actually does it - when sb is being torn down, access to it is serialized via sb->s_umount rwsem, only when that lock is taken is it okay to work with s_flags - and the other mistake I was doing was trying to make SB_ACTIVE work, but apparently the kernel checks the negative variant - not SB_DYING and not SB_BORN. Kernels pre-6.6 don't have SB_DYING, but check if sb is hashed instead. Signed-off-by: Pavel Snajdr <[email protected]> Reviewed-by: Tony Hutter <[email protected]> Reviewed-by: Brian Behlendorf <[email protected]> Closes: #17121 (cherry picked from commit a0e6271)
1 parent 8ff37c6 commit 9631ecf

File tree

3 files changed

+38
-9
lines changed

3 files changed

+38
-9
lines changed

config/kernel-sb-dying.m4

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
dnl #
2+
dnl # SB_DYING exists since Linux 6.6
3+
dnl #
4+
AC_DEFUN([ZFS_AC_KERNEL_SRC_SB_DYING], [
5+
ZFS_LINUX_TEST_SRC([sb_dying], [
6+
#include <linux/fs.h>
7+
],[
8+
(void) SB_DYING;
9+
])
10+
])
11+
12+
AC_DEFUN([ZFS_AC_KERNEL_SB_DYING], [
13+
AC_MSG_CHECKING([whether SB_DYING is defined])
14+
ZFS_LINUX_TEST_RESULT([sb_dying], [
15+
AC_MSG_RESULT(yes)
16+
],[
17+
AC_MSG_RESULT(no)
18+
])
19+
])

config/kernel.m4

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_SRC], [
7373
ZFS_AC_KERNEL_SRC_TRUNCATE_SETSIZE
7474
ZFS_AC_KERNEL_SRC_SECURITY_INODE
7575
ZFS_AC_KERNEL_SRC_FST_MOUNT
76+
ZFS_AC_KERNEL_SRC_SB_DYING
7677
ZFS_AC_KERNEL_SRC_SET_NLINK
7778
ZFS_AC_KERNEL_SRC_SGET
7879
ZFS_AC_KERNEL_SRC_VFS_FILEMAP_DIRTY_FOLIO
@@ -183,6 +184,7 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_RESULT], [
183184
ZFS_AC_KERNEL_TRUNCATE_SETSIZE
184185
ZFS_AC_KERNEL_SECURITY_INODE
185186
ZFS_AC_KERNEL_FST_MOUNT
187+
ZFS_AC_KERNEL_SB_DYING
186188
ZFS_AC_KERNEL_SET_NLINK
187189
ZFS_AC_KERNEL_SGET
188190
ZFS_AC_KERNEL_VFS_FILEMAP_DIRTY_FOLIO

module/os/linux/zfs/zpl_super.c

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -370,17 +370,25 @@ zpl_prune_sb(uint64_t nr_to_scan, void *arg)
370370
int objects = 0;
371371

372372
/*
373-
* deactivate_locked_super calls shrinker_free and only then
374-
* sops->kill_sb cb, resulting in UAF on umount when trying to reach
375-
* for the shrinker functions in zpl_prune_sb of in-umount dataset.
376-
* Increment if s_active is not zero, but don't prune if it is -
377-
* umount could be underway.
373+
* Ensure the superblock is not in the process of being torn down.
378374
*/
379-
if (atomic_inc_not_zero(&sb->s_active)) {
380-
(void) -zfs_prune(sb, nr_to_scan, &objects);
381-
atomic_dec(&sb->s_active);
375+
#ifdef HAVE_SB_DYING
376+
if (down_read_trylock(&sb->s_umount)) {
377+
if (!(sb->s_flags & SB_DYING) && sb->s_root &&
378+
(sb->s_flags & SB_BORN)) {
379+
(void) zfs_prune(sb, nr_to_scan, &objects);
380+
}
381+
up_read(&sb->s_umount);
382382
}
383-
383+
#else
384+
if (down_read_trylock(&sb->s_umount)) {
385+
if (!hlist_unhashed(&sb->s_instances) &&
386+
sb->s_root && (sb->s_flags & SB_BORN)) {
387+
(void) zfs_prune(sb, nr_to_scan, &objects);
388+
}
389+
up_read(&sb->s_umount);
390+
}
391+
#endif
384392
}
385393

386394
const struct super_operations zpl_super_operations = {

0 commit comments

Comments
 (0)