mirror of
https://git.proxmox.com/git/mirror_zfs
synced 2025-04-28 06:00:44 +00:00
Linux: Fix zfs_prune panics v2 (#17121)
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 <snajpa@snajpa.net> Reviewed-by: Tony Hutter <hutter2@llnl.gov> Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
This commit is contained in:
parent
9611dfdc70
commit
a0e62718cf
19
config/kernel-sb-dying.m4
Normal file
19
config/kernel-sb-dying.m4
Normal file
@ -0,0 +1,19 @@
|
||||
dnl #
|
||||
dnl # SB_DYING exists since Linux 6.6
|
||||
dnl #
|
||||
AC_DEFUN([ZFS_AC_KERNEL_SRC_SB_DYING], [
|
||||
ZFS_LINUX_TEST_SRC([sb_dying], [
|
||||
#include <linux/fs.h>
|
||||
],[
|
||||
(void) SB_DYING;
|
||||
])
|
||||
])
|
||||
|
||||
AC_DEFUN([ZFS_AC_KERNEL_SB_DYING], [
|
||||
AC_MSG_CHECKING([whether SB_DYING is defined])
|
||||
ZFS_LINUX_TEST_RESULT([sb_dying], [
|
||||
AC_MSG_RESULT(yes)
|
||||
],[
|
||||
AC_MSG_RESULT(no)
|
||||
])
|
||||
])
|
@ -73,6 +73,7 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_SRC], [
|
||||
ZFS_AC_KERNEL_SRC_TRUNCATE_SETSIZE
|
||||
ZFS_AC_KERNEL_SRC_SECURITY_INODE
|
||||
ZFS_AC_KERNEL_SRC_FST_MOUNT
|
||||
ZFS_AC_KERNEL_SRC_SB_DYING
|
||||
ZFS_AC_KERNEL_SRC_SET_NLINK
|
||||
ZFS_AC_KERNEL_SRC_SGET
|
||||
ZFS_AC_KERNEL_SRC_VFS_FILEMAP_DIRTY_FOLIO
|
||||
@ -184,6 +185,7 @@ AC_DEFUN([ZFS_AC_KERNEL_TEST_RESULT], [
|
||||
ZFS_AC_KERNEL_TRUNCATE_SETSIZE
|
||||
ZFS_AC_KERNEL_SECURITY_INODE
|
||||
ZFS_AC_KERNEL_FST_MOUNT
|
||||
ZFS_AC_KERNEL_SB_DYING
|
||||
ZFS_AC_KERNEL_SET_NLINK
|
||||
ZFS_AC_KERNEL_SGET
|
||||
ZFS_AC_KERNEL_VFS_FILEMAP_DIRTY_FOLIO
|
||||
|
@ -377,17 +377,25 @@ zpl_prune_sb(uint64_t nr_to_scan, void *arg)
|
||||
int objects = 0;
|
||||
|
||||
/*
|
||||
* deactivate_locked_super calls shrinker_free and only then
|
||||
* sops->kill_sb cb, resulting in UAF on umount when trying to reach
|
||||
* for the shrinker functions in zpl_prune_sb of in-umount dataset.
|
||||
* Increment if s_active is not zero, but don't prune if it is -
|
||||
* umount could be underway.
|
||||
* Ensure the superblock is not in the process of being torn down.
|
||||
*/
|
||||
if (atomic_inc_not_zero(&sb->s_active)) {
|
||||
(void) -zfs_prune(sb, nr_to_scan, &objects);
|
||||
atomic_dec(&sb->s_active);
|
||||
#ifdef HAVE_SB_DYING
|
||||
if (down_read_trylock(&sb->s_umount)) {
|
||||
if (!(sb->s_flags & SB_DYING) && sb->s_root &&
|
||||
(sb->s_flags & SB_BORN)) {
|
||||
(void) zfs_prune(sb, nr_to_scan, &objects);
|
||||
}
|
||||
up_read(&sb->s_umount);
|
||||
}
|
||||
|
||||
#else
|
||||
if (down_read_trylock(&sb->s_umount)) {
|
||||
if (!hlist_unhashed(&sb->s_instances) &&
|
||||
sb->s_root && (sb->s_flags & SB_BORN)) {
|
||||
(void) zfs_prune(sb, nr_to_scan, &objects);
|
||||
}
|
||||
up_read(&sb->s_umount);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
const struct super_operations zpl_super_operations = {
|
||||
|
Loading…
Reference in New Issue
Block a user