diff --git a/config/spl-build.m4 b/config/spl-build.m4 index b25db38f3..75267bb83 100644 --- a/config/spl-build.m4 +++ b/config/spl-build.m4 @@ -81,6 +81,7 @@ AC_DEFUN([SPL_AC_CONFIG_KERNEL], [ SPL_AC_SHRINK_ICACHE_MEMORY SPL_AC_KERN_PATH_PARENT SPL_AC_2ARGS_ZLIB_DEFLATE_WORKSPACESIZE + SPL_AC_SHRINK_CONTROL_STRUCT ]) AC_DEFUN([SPL_AC_MODULE_SYMVERS], [ @@ -1810,3 +1811,25 @@ AC_DEFUN([SPL_AC_2ARGS_ZLIB_DEFLATE_WORKSPACESIZE], AC_MSG_RESULT(no) ]) ]) + +dnl # +dnl # 2.6.39 API change, +dnl # Shrinker adjust to use common shrink_control structure. +dnl # +AC_DEFUN([SPL_AC_SHRINK_CONTROL_STRUCT], [ + AC_MSG_CHECKING([whether struct shrink_control exists]) + SPL_LINUX_TRY_COMPILE([ + #include + ],[ + struct shrink_control sc __attribute__ ((unused)); + + sc.nr_to_scan = 0; + sc.gfp_mask = GFP_KERNEL; + ],[ + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_SHRINK_CONTROL_STRUCT, 1, + [struct shrink_control exists]) + ],[ + AC_MSG_RESULT(no) + ]) +]) diff --git a/configure b/configure index 1fb10af36..c537b9817 100755 --- a/configure +++ b/configure @@ -15712,6 +15712,74 @@ $as_echo "no" >&6; } +fi + + rm -Rf build + + + + + { $as_echo "$as_me:$LINENO: checking whether struct shrink_control exists" >&5 +$as_echo_n "checking whether struct shrink_control exists... " >&6; } + + +cat confdefs.h - <<_ACEOF >conftest.c +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + + + #include + +int +main (void) +{ + + struct shrink_control sc __attribute__ ((unused)); + + sc.nr_to_scan = 0; + sc.gfp_mask = GFP_KERNEL; + + ; + return 0; +} + +_ACEOF + + + rm -Rf build && mkdir -p build + echo "obj-m := conftest.o" >build/Makefile + if { ac_try='cp conftest.c build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror-implicit-function-declaration $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } >/dev/null && { ac_try='test -s build/conftest.o' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + + { $as_echo "$as_me:$LINENO: result: yes" >&5 +$as_echo "yes" >&6; } + +cat >>confdefs.h <<\_ACEOF +#define HAVE_SHRINK_CONTROL_STRUCT 1 +_ACEOF + + +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + { $as_echo "$as_me:$LINENO: result: no" >&5 +$as_echo "no" >&6; } + + + fi rm -Rf build @@ -19775,6 +19843,74 @@ $as_echo "no" >&6; } +fi + + rm -Rf build + + + + + { $as_echo "$as_me:$LINENO: checking whether struct shrink_control exists" >&5 +$as_echo_n "checking whether struct shrink_control exists... " >&6; } + + +cat confdefs.h - <<_ACEOF >conftest.c +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + + + #include + +int +main (void) +{ + + struct shrink_control sc __attribute__ ((unused)); + + sc.nr_to_scan = 0; + sc.gfp_mask = GFP_KERNEL; + + ; + return 0; +} + +_ACEOF + + + rm -Rf build && mkdir -p build + echo "obj-m := conftest.o" >build/Makefile + if { ac_try='cp conftest.c build && make modules -C $LINUX_OBJ EXTRA_CFLAGS="-Werror-implicit-function-declaration $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } >/dev/null && { ac_try='test -s build/conftest.o' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + + { $as_echo "$as_me:$LINENO: result: yes" >&5 +$as_echo "yes" >&6; } + +cat >>confdefs.h <<\_ACEOF +#define HAVE_SHRINK_CONTROL_STRUCT 1 +_ACEOF + + +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + { $as_echo "$as_me:$LINENO: result: no" >&5 +$as_echo "no" >&6; } + + + fi rm -Rf build diff --git a/include/linux/mm_compat.h b/include/linux/mm_compat.h index 07231c9a4..173acd434 100644 --- a/include/linux/mm_compat.h +++ b/include/linux/mm_compat.h @@ -72,6 +72,13 @@ extern invalidate_inodes_t invalidate_inodes_fn; # endif /* HAVE_2ARGS_INVALIDATE_INODES */ #endif /* HAVE_INVALIDATE_INODES */ +#if !defined(HAVE_SHRINK_CONTROL_STRUCT) +struct shrink_control { + gfp_t gfp_mask; + unsigned long nr_to_scan; +}; +#endif /* HAVE_SHRINK_CONTROL_STRUCT */ + /* * 2.6.xx API compat, * There currently exists no exposed API to partially shrink the dcache. @@ -79,7 +86,16 @@ extern invalidate_inodes_t invalidate_inodes_fn; * which is called during memory pressure. */ #ifndef HAVE_SHRINK_DCACHE_MEMORY -# ifdef HAVE_3ARGS_SHRINKER_CALLBACK +# if defined(HAVE_SHRINK_CONTROL_STRUCT) +typedef int (*shrink_dcache_memory_t)(struct shrinker *, + struct shrink_control *); +extern shrink_dcache_memory_t shrink_dcache_memory_fn; +# define shrink_dcache_memory(nr, gfp) \ +({ \ + struct shrink_control sc = { .nr_to_scan = nr, .gfp_mask = gfp }; \ + shrink_dcache_memory_fn(NULL, &sc); \ +}) +# elif defined(HAVE_3ARGS_SHRINKER_CALLBACK) typedef int (*shrink_dcache_memory_t)(struct shrinker *, int, gfp_t); extern shrink_dcache_memory_t shrink_dcache_memory_fn; # define shrink_dcache_memory(nr, gfp) shrink_dcache_memory_fn(NULL, nr, gfp) @@ -97,7 +113,16 @@ extern shrink_dcache_memory_t shrink_dcache_memory_fn; * which is called during memory pressure. */ #ifndef HAVE_SHRINK_ICACHE_MEMORY -# ifdef HAVE_3ARGS_SHRINKER_CALLBACK +# if defined(HAVE_SHRINK_CONTROL_STRUCT) +typedef int (*shrink_icache_memory_t)(struct shrinker *, + struct shrink_control *); +extern shrink_icache_memory_t shrink_icache_memory_fn; +# define shrink_icache_memory(nr, gfp) \ +({ \ + struct shrink_control sc = { .nr_to_scan = nr, .gfp_mask = gfp }; \ + shrink_icache_memory_fn(NULL, &sc); \ +}) +# elif defined(HAVE_3ARGS_SHRINKER_CALLBACK) typedef int (*shrink_icache_memory_t)(struct shrinker *, int, gfp_t); extern shrink_icache_memory_t shrink_icache_memory_fn; # define shrink_icache_memory(nr, gfp) shrink_icache_memory_fn(NULL, nr, gfp) @@ -108,6 +133,9 @@ extern shrink_icache_memory_t shrink_icache_memory_fn; # endif /* HAVE_3ARGS_SHRINKER_CALLBACK */ #endif /* HAVE_SHRINK_ICACHE_MEMORY */ +/* + * Linux 2.6. - 2.6. Shrinker API Compatibility. + */ #ifdef HAVE_SET_SHRINKER typedef struct spl_shrinker { struct shrinker *shrinker; @@ -127,31 +155,86 @@ spl_unregister_shrinker(spl_shrinker_t *ss) remove_shrinker(ss->shrinker); } -# define SPL_SHRINKER_DECLARE(s, x, y) \ - static spl_shrinker_t s = { .shrinker = NULL, .fn = x, .seeks = y } -# define SPL_SHRINKER_CALLBACK_PROTO(fn, x, y, z) \ - static int fn(int y, unsigned int z) -# define spl_exec_shrinker(ss, nr, gfp) \ - ((spl_shrinker_t *)ss)->fn(nr, gfp) +# define SPL_SHRINKER_DECLARE(s, x, y) \ + static spl_shrinker_t s = { \ + .shrinker = NULL, \ + .fn = x, \ + .seeks = y \ + } -#else /* HAVE_SET_SHRINKER */ +# define SPL_SHRINKER_CALLBACK_FWD_DECLARE(fn) \ + static int fn(int, unsigned int) +# define SPL_SHRINKER_CALLBACK_WRAPPER(fn) \ +static int \ +fn(int nr_to_scan, unsigned int gfp_mask) \ +{ \ + struct shrink_control sc; \ + \ + sc.nr_to_scan = nr_to_scan; \ + sc.gfp_mask = gfp_mask; \ + \ + return __ ## fn(NULL, &sc); \ +} + +#else # define spl_register_shrinker(x) register_shrinker(x) # define spl_unregister_shrinker(x) unregister_shrinker(x) -# define SPL_SHRINKER_DECLARE(s, x, y) \ - static struct shrinker s = { .shrink = x, .seeks = y } +# define SPL_SHRINKER_DECLARE(s, x, y) \ + static struct shrinker s = { \ + .shrink = x, \ + .seeks = y \ + } -# ifdef HAVE_3ARGS_SHRINKER_CALLBACK -# define SPL_SHRINKER_CALLBACK_PROTO(fn, x, y, z) \ - static int fn(struct shrinker *x, int y, unsigned int z) -# define spl_exec_shrinker(ss, nr, gfp) \ - ((struct shrinker *)ss)->shrink(NULL, nr, gfp) -# else /* HAVE_3ARGS_SHRINKER_CALLBACK */ -# define SPL_SHRINKER_CALLBACK_PROTO(fn, x, y, z) \ - static int fn(int y, unsigned int z) -# define spl_exec_shrinker(ss, nr, gfp) \ - ((struct shrinker *)ss)->shrink(nr, gfp) -# endif /* HAVE_3ARGS_SHRINKER_CALLBACK */ +/* + * Linux 2.6. - 2.6. Shrinker API Compatibility. + */ +# if defined(HAVE_SHRINK_CONTROL_STRUCT) +# define SPL_SHRINKER_CALLBACK_FWD_DECLARE(fn) \ + static int fn(struct shrinker *, struct shrink_control *) +# define SPL_SHRINKER_CALLBACK_WRAPPER(fn) \ +static int \ +fn(struct shrinker *shrink, struct shrink_control *sc) { \ + return __ ## fn(shrink, sc); \ +} + +/* + * Linux 2.6. - 2.6. Shrinker API Compatibility. + */ +# elif defined(HAVE_3ARGS_SHRINKER_CALLBACK) +# define SPL_SHRINKER_CALLBACK_FWD_DECLARE(fn) \ + static int fn(struct shrinker *, int, unsigned int) +# define SPL_SHRINKER_CALLBACK_WRAPPER(fn) \ +static int \ +fn(struct shrinker *shrink, int nr_to_scan, unsigned int gfp_mask) \ +{ \ + struct shrink_control sc; \ + \ + sc.nr_to_scan = nr_to_scan; \ + sc.gfp_mask = gfp_mask; \ + \ + return __ ## fn(shrink, &sc); \ +} + +/* + * Linux 2.6. - 2.6. Shrinker API Compatibility. + */ +# else +# define SPL_SHRINKER_CALLBACK_FWD_DECLARE(fn) \ + static int fn(int, unsigned int) +# define SPL_SHRINKER_CALLBACK_WRAPPER(fn) \ +static int \ +fn(int nr_to_scan, unsigned int gfp_mask) \ +{ \ + struct shrink_control sc; \ + \ + sc.nr_to_scan = nr_to_scan; \ + sc.gfp_mask = gfp_mask; \ + \ + return __ ## fn(NULL, &sc); \ +} + +# endif #endif /* HAVE_SET_SHRINKER */ #endif /* SPL_MM_COMPAT_H */ diff --git a/module/spl/spl-kmem.c b/module/spl/spl-kmem.c index e7fc5f2c9..d71ab11bb 100644 --- a/module/spl/spl-kmem.c +++ b/module/spl/spl-kmem.c @@ -829,8 +829,7 @@ struct rw_semaphore spl_kmem_cache_sem; /* Cache list lock */ static int spl_cache_flush(spl_kmem_cache_t *skc, spl_kmem_magazine_t *skm, int flush); -SPL_SHRINKER_CALLBACK_PROTO(spl_kmem_cache_generic_shrinker, - shrinker_cb, nr_to_scan, gfp_mask); +SPL_SHRINKER_CALLBACK_FWD_DECLARE(spl_kmem_cache_generic_shrinker); SPL_SHRINKER_DECLARE(spl_kmem_cache_shrinker, spl_kmem_cache_generic_shrinker, KMC_DEFAULT_SEEKS); @@ -1858,15 +1857,16 @@ EXPORT_SYMBOL(spl_kmem_cache_free); * objects should be freed, because Solaris semantics are to free * all available objects we may free more objects than requested. */ -SPL_SHRINKER_CALLBACK_PROTO(spl_kmem_cache_generic_shrinker, - shrinker_cb, nr_to_scan, gfp_mask) +static int +__spl_kmem_cache_generic_shrinker(struct shrinker *shrink, + struct shrink_control *sc) { spl_kmem_cache_t *skc; int unused = 0; down_read(&spl_kmem_cache_sem); list_for_each_entry(skc, &spl_kmem_cache_list, skc_list) { - if (nr_to_scan) + if (sc->nr_to_scan) spl_kmem_cache_reap_now(skc); /* @@ -1882,6 +1882,8 @@ SPL_SHRINKER_CALLBACK_PROTO(spl_kmem_cache_generic_shrinker, return (unused * sysctl_vfs_cache_pressure) / 100; } +SPL_SHRINKER_CALLBACK_WRAPPER(spl_kmem_cache_generic_shrinker); + /* * Call the registered reclaim function for a cache. Depending on how * many and which objects are released it may simply repopulate the @@ -1923,7 +1925,12 @@ EXPORT_SYMBOL(spl_kmem_cache_reap_now); void spl_kmem_reap(void) { - spl_exec_shrinker(&spl_kmem_cache_shrinker, KMC_REAP_CHUNK, GFP_KERNEL); + struct shrink_control sc; + + sc.nr_to_scan = KMC_REAP_CHUNK; + sc.gfp_mask = GFP_KERNEL; + + __spl_kmem_cache_generic_shrinker(NULL, &sc); } EXPORT_SYMBOL(spl_kmem_reap); diff --git a/spl_config.h.in b/spl_config.h.in index b2ba74b8c..95394e6e2 100644 --- a/spl_config.h.in +++ b/spl_config.h.in @@ -165,6 +165,9 @@ /* set_shrinker() available */ #undef HAVE_SET_SHRINKER +/* struct shrink_control exists */ +#undef HAVE_SHRINK_CONTROL_STRUCT + /* shrink_dcache_memory() is available */ #undef HAVE_SHRINK_DCACHE_MEMORY