linux 6.7 compat: handle superblock shrinker member change

In 6.7 the superblock shrinker member s_shrink has changed from being an
embedded struct to a pointer. Detect this, and don't take a reference if
it already is one.

Signed-off-by: Rob Norris <robn@despairlabs.com>
Sponsored-by: https://github.com/sponsors/robn
This commit is contained in:
Rob Norris 2023-12-16 17:39:07 +11:00 committed by Brian Behlendorf
parent 3c13601a12
commit 18a9185165
2 changed files with 42 additions and 3 deletions

View File

@ -19,13 +19,45 @@ AC_DEFUN([ZFS_AC_KERNEL_SRC_SUPER_BLOCK_S_SHRINK], [
],[]) ],[])
]) ])
dnl #
dnl # 6.7 API change
dnl # s_shrink is now a pointer.
dnl #
AC_DEFUN([ZFS_AC_KERNEL_SRC_SUPER_BLOCK_S_SHRINK_PTR], [
ZFS_LINUX_TEST_SRC([super_block_s_shrink_ptr], [
#include <linux/fs.h>
unsigned long shrinker_cb(struct shrinker *shrink,
struct shrink_control *sc) { return 0; }
static struct shrinker shrinker = {
.count_objects = shrinker_cb,
.scan_objects = shrinker_cb,
.seeks = DEFAULT_SEEKS,
};
static const struct super_block
sb __attribute__ ((unused)) = {
.s_shrink = &shrinker,
};
],[])
])
AC_DEFUN([ZFS_AC_KERNEL_SUPER_BLOCK_S_SHRINK], [ AC_DEFUN([ZFS_AC_KERNEL_SUPER_BLOCK_S_SHRINK], [
AC_MSG_CHECKING([whether super_block has s_shrink]) AC_MSG_CHECKING([whether super_block has s_shrink])
ZFS_LINUX_TEST_RESULT([super_block_s_shrink], [ ZFS_LINUX_TEST_RESULT([super_block_s_shrink], [
AC_MSG_RESULT(yes) AC_MSG_RESULT(yes)
AC_DEFINE(HAVE_SUPER_BLOCK_S_SHRINK, 1,
[have super_block s_shrink])
],[ ],[
AC_MSG_RESULT(no)
AC_MSG_CHECKING([whether super_block has s_shrink pointer])
ZFS_LINUX_TEST_RESULT([super_block_s_shrink_ptr], [
AC_MSG_RESULT(yes)
AC_DEFINE(HAVE_SUPER_BLOCK_S_SHRINK_PTR, 1,
[have super_block s_shrink pointer])
],[
AC_MSG_RESULT(no)
ZFS_LINUX_TEST_ERROR([sb->s_shrink()]) ZFS_LINUX_TEST_ERROR([sb->s_shrink()])
]) ])
])
]) ])
dnl # dnl #
@ -174,6 +206,7 @@ AC_DEFUN([ZFS_AC_KERNEL_SHRINK_CONTROL_STRUCT], [
AC_DEFUN([ZFS_AC_KERNEL_SRC_SHRINKER], [ AC_DEFUN([ZFS_AC_KERNEL_SRC_SHRINKER], [
ZFS_AC_KERNEL_SRC_SUPER_BLOCK_S_SHRINK ZFS_AC_KERNEL_SRC_SUPER_BLOCK_S_SHRINK
ZFS_AC_KERNEL_SRC_SUPER_BLOCK_S_SHRINK_PTR
ZFS_AC_KERNEL_SRC_SHRINK_CONTROL_HAS_NID ZFS_AC_KERNEL_SRC_SHRINK_CONTROL_HAS_NID
ZFS_AC_KERNEL_SRC_SHRINKER_CALLBACK ZFS_AC_KERNEL_SRC_SHRINKER_CALLBACK
ZFS_AC_KERNEL_SRC_SHRINK_CONTROL_STRUCT ZFS_AC_KERNEL_SRC_SHRINK_CONTROL_STRUCT

View File

@ -1240,12 +1240,18 @@ zfs_prune_aliases(zfsvfs_t *zfsvfs, unsigned long nr_to_scan)
* and inode caches. This can occur when the ARC needs to free meta data * and inode caches. This can occur when the ARC needs to free meta data
* blocks but can't because they are all pinned by entries in these caches. * blocks but can't because they are all pinned by entries in these caches.
*/ */
#if defined(HAVE_SUPER_BLOCK_S_SHRINK)
#define S_SHRINK(sb) (&(sb)->s_shrink)
#elif defined(HAVE_SUPER_BLOCK_S_SHRINK_PTR)
#define S_SHRINK(sb) ((sb)->s_shrink)
#endif
int int
zfs_prune(struct super_block *sb, unsigned long nr_to_scan, int *objects) zfs_prune(struct super_block *sb, unsigned long nr_to_scan, int *objects)
{ {
zfsvfs_t *zfsvfs = sb->s_fs_info; zfsvfs_t *zfsvfs = sb->s_fs_info;
int error = 0; int error = 0;
struct shrinker *shrinker = &sb->s_shrink; struct shrinker *shrinker = S_SHRINK(sb);
struct shrink_control sc = { struct shrink_control sc = {
.nr_to_scan = nr_to_scan, .nr_to_scan = nr_to_scan,
.gfp_mask = GFP_KERNEL, .gfp_mask = GFP_KERNEL,
@ -1257,7 +1263,7 @@ zfs_prune(struct super_block *sb, unsigned long nr_to_scan, int *objects)
#if defined(HAVE_SPLIT_SHRINKER_CALLBACK) && \ #if defined(HAVE_SPLIT_SHRINKER_CALLBACK) && \
defined(SHRINK_CONTROL_HAS_NID) && \ defined(SHRINK_CONTROL_HAS_NID) && \
defined(SHRINKER_NUMA_AWARE) defined(SHRINKER_NUMA_AWARE)
if (sb->s_shrink.flags & SHRINKER_NUMA_AWARE) { if (shrinker->flags & SHRINKER_NUMA_AWARE) {
*objects = 0; *objects = 0;
for_each_online_node(sc.nid) { for_each_online_node(sc.nid) {
*objects += (*shrinker->scan_objects)(shrinker, &sc); *objects += (*shrinker->scan_objects)(shrinker, &sc);