-/*****************************************************************************\
+/*
* Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
* Copyright (C) 2007 The Regents of the University of California.
* Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
* UCRL-CODE-235197
*
* This file is part of the SPL, Solaris Porting Layer.
- * For details, see <http://github.com/behlendorf/spl/>.
+ * For details, see <http://zfsonlinux.org/>.
*
* The SPL is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
*
* You should have received a copy of the GNU General Public License along
* with the SPL. If not, see <http://www.gnu.org/licenses/>.
-\*****************************************************************************/
+ */
#ifndef _SPL_MM_COMPAT_H
-#define _SPL_MM_COMPAT_H
+#define _SPL_MM_COMPAT_H
#include <linux/mm.h>
#include <linux/fs.h>
-/*
- * Linux 2.6.31 API Change.
- * Individual pages_{min,low,high} moved in to watermark array.
- */
-#ifndef min_wmark_pages
-#define min_wmark_pages(z) (z->pages_min)
-#endif
-
-#ifndef low_wmark_pages
-#define low_wmark_pages(z) (z->pages_low)
-#endif
-
-#ifndef high_wmark_pages
-#define high_wmark_pages(z) (z->pages_high)
-#endif
-
-/*
- * 2.6.37 API compat,
- * The function invalidate_inodes() is no longer exported by the kernel.
- * The prototype however is still available which means it is safe
- * to acquire the symbol's address using spl_kallsyms_lookup_name().
- *
- * 2.6.39 API compat,
- * As for 2.6.39 invalidate_inodes() was updated to take a second
- * argument which controls how dirty inodes should be handled.
- */
-#ifdef HAVE_INVALIDATE_INODES
-# ifdef HAVE_2ARGS_INVALIDATE_INODES
-# define spl_invalidate_inodes(sb, kd) invalidate_inodes(sb, kd)
-# else
-# define spl_invalidate_inodes(sb, kd) invalidate_inodes(sb)
-# endif /* HAVE_2ARGS_INVALIDATE_INODES */
-#else
-# ifdef HAVE_2ARGS_INVALIDATE_INODES
-typedef int (*invalidate_inodes_t)(struct super_block *sb, bool kd);
-extern invalidate_inodes_t invalidate_inodes_fn;
-# define spl_invalidate_inodes(sb, kd) invalidate_inodes_fn(sb, kd)
-# else
-typedef int (*invalidate_inodes_t)(struct super_block *sb);
-extern invalidate_inodes_t invalidate_inodes_fn;
-# define spl_invalidate_inodes(sb, kd) invalidate_inodes_fn(sb)
-# endif /* HAVE_2ARGS_INVALIDATE_INODES */
-#endif /* HAVE_INVALIDATE_INODES */
-
#if !defined(HAVE_SHRINK_CONTROL_STRUCT)
struct shrink_control {
gfp_t gfp_mask;
#endif /* HAVE_SHRINK_CONTROL_STRUCT */
/*
- * 2.6.xx API compat,
- * There currently exists no exposed API to partially shrink the dcache.
- * The expected mechanism to shrink the cache is a registered shrinker
- * which is called during memory pressure.
+ * Due to frequent changes in the shrinker API the following
+ * compatibility wrappers should be used. They are as follows:
+ *
+ * SPL_SHRINKER_DECLARE is used to declare the shrinker which is
+ * passed to spl_register_shrinker()/spl_unregister_shrinker(). Use
+ * shrinker_name to set the shrinker variable name, shrinker_callback
+ * to set the callback function, and seek_cost to define the cost of
+ * reclaiming an object.
+ *
+ * SPL_SHRINKER_DECLARE(shrinker_name, shrinker_callback, seek_cost);
+ *
+ * SPL_SHRINKER_CALLBACK_FWD_DECLARE is used when a forward declaration
+ * of the shrinker callback function is required. Only the callback
+ * function needs to be passed.
+ *
+ * SPL_SHRINKER_CALLBACK_FWD_DECLARE(shrinker_callback);
+ *
+ * SPL_SHRINKER_CALLBACK_WRAPPER is used to declare the callback function
+ * which is registered with the shrinker. This function will call your
+ * custom shrinker which must use the following prototype. Notice the
+ * leading __'s, these must be appended to the callback_function name.
+ *
+ * int __shrinker_callback(struct shrinker *, struct shrink_control *)
+ * SPL_SHRINKER_CALLBACK_WRAPPER(shrinker_callback);a
+ *
+ *
+ * Example:
+ *
+ * SPL_SHRINKER_CALLBACK_FWD_DECLARE(my_shrinker_fn);
+ * SPL_SHRINKER_DECLARE(my_shrinker, my_shrinker_fn, 1);
+ *
+ * static int
+ * __my_shrinker_fn(struct shrinker *shrink, struct shrink_control *sc)
+ * {
+ * if (sc->nr_to_scan) {
+ * ...scan objects in the cache and reclaim them...
+ * }
+ *
+ * ...calculate number of objects in the cache...
+ *
+ * return (number of objects in the cache);
+ * }
+ * SPL_SHRINKER_CALLBACK_WRAPPER(my_shrinker_fn);
*/
-#ifndef HAVE_SHRINK_DCACHE_MEMORY
-# 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 }; \
- int __ret__ = 0; \
- \
- if (shrink_dcache_memory_fn) \
- __ret__ = shrink_dcache_memory_fn(NULL, &sc); \
- \
- __ret__; \
-})
-# 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) \
-({ \
- int __ret__ = 0; \
- \
- if (shrink_dcache_memory_fn) \
- __ret__ = shrink_dcache_memory_fn(NULL, nr, gfp); \
- \
- __ret__; \
-})
-# else
-typedef int (*shrink_dcache_memory_t)(int, gfp_t);
-extern shrink_dcache_memory_t shrink_dcache_memory_fn;
-# define shrink_dcache_memory(nr, gfp) \
-({ \
- int __ret__ = 0; \
- \
- if (shrink_dcache_memory_fn) \
- __ret__ = shrink_dcache_memory_fn(nr, gfp); \
- \
- __ret__; \
-})
-# endif /* HAVE_3ARGS_SHRINKER_CALLBACK */
-#endif /* HAVE_SHRINK_DCACHE_MEMORY */
-/*
- * 2.6.xx API compat,
- * There currently exists no exposed API to partially shrink the icache.
- * The expected mechanism to shrink the cache is a registered shrinker
- * which is called during memory pressure.
- */
-#ifndef HAVE_SHRINK_ICACHE_MEMORY
-# 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 }; \
- int __ret__ = 0; \
- \
- if (shrink_icache_memory_fn) \
- __ret__ = shrink_icache_memory_fn(NULL, &sc); \
- \
- __ret__; \
-})
-# 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) \
-({ \
- int __ret__ = 0; \
- \
- if (shrink_icache_memory_fn) \
- __ret__ = shrink_icache_memory_fn(NULL, nr, gfp); \
- \
- __ret__; \
-})
-# else
-typedef int (*shrink_icache_memory_t)(int, gfp_t);
-extern shrink_icache_memory_t shrink_icache_memory_fn;
-# define shrink_icache_memory(nr, gfp) \
-({ \
- int __ret__ = 0; \
- \
- if (shrink_icache_memory_fn) \
- __ret__ = shrink_icache_memory_fn(nr, gfp); \
- \
- __ret__; \
-})
-# endif /* HAVE_3ARGS_SHRINKER_CALLBACK */
-#endif /* HAVE_SHRINK_ICACHE_MEMORY */
+#define spl_register_shrinker(x) register_shrinker(x)
+#define spl_unregister_shrinker(x) unregister_shrinker(x)
/*
- * Linux 2.6. - 2.6. Shrinker API Compatibility.
+ * Linux 2.6.23 - 2.6.34 Shrinker API Compatibility.
*/
-#ifdef HAVE_SET_SHRINKER
-typedef struct spl_shrinker {
- struct shrinker *shrinker;
- shrinker_t fn;
- int seeks;
-} spl_shrinker_t;
-
-static inline void
-spl_register_shrinker(spl_shrinker_t *ss)
-{
- ss->shrinker = set_shrinker(ss->seeks, ss->fn);
+#if defined(HAVE_2ARGS_OLD_SHRINKER_CALLBACK)
+#define SPL_SHRINKER_DECLARE(s, x, y) \
+static struct shrinker s = { \
+ .shrink = x, \
+ .seeks = y \
}
-static inline void
-spl_unregister_shrinker(spl_shrinker_t *ss)
-{
- remove_shrinker(ss->shrinker);
+#define SPL_SHRINKER_CALLBACK_FWD_DECLARE(fn) \
+static int fn(int nr_to_scan, unsigned int gfp_mask)
+
+#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)); \
}
-# define SPL_SHRINKER_DECLARE(s, x, y) \
- static spl_shrinker_t s = { \
- .shrinker = NULL, \
- .fn = x, \
- .seeks = y \
- }
-
-# 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); \
+/*
+ * Linux 2.6.35 to 2.6.39 Shrinker API Compatibility.
+ */
+#elif defined(HAVE_3ARGS_SHRINKER_CALLBACK)
+#define SPL_SHRINKER_DECLARE(s, x, y) \
+static struct shrinker s = { \
+ .shrink = x, \
+ .seeks = y \
}
-#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_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.
+ * Linux 3.0 to 3.11 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); \
+#elif defined(HAVE_2ARGS_NEW_SHRINKER_CALLBACK)
+#define SPL_SHRINKER_DECLARE(s, x, y) \
+static struct shrinker s = { \
+ .shrink = x, \
+ .seeks = y \
+}
+
+#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.
+ * Linux 3.12 and later 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); \
+#elif defined(HAVE_SPLIT_SHRINKER_CALLBACK)
+#define SPL_SHRINKER_DECLARE(s, x, y) \
+static struct shrinker s = { \
+ .count_objects = x ## _count_objects, \
+ .scan_objects = x ## _scan_objects, \
+ .seeks = y \
}
+#define SPL_SHRINKER_CALLBACK_FWD_DECLARE(fn) \
+static unsigned long fn ## _count_objects(struct shrinker *, \
+ struct shrink_control *); \
+static unsigned long fn ## _scan_objects(struct shrinker *, \
+ struct shrink_control *)
+
+#define SPL_SHRINKER_CALLBACK_WRAPPER(fn) \
+static unsigned long \
+fn ## _count_objects(struct shrinker *shrink, struct shrink_control *sc)\
+{ \
+ int __ret__; \
+ \
+ sc->nr_to_scan = 0; \
+ __ret__ = __ ## fn(NULL, sc); \
+ \
+ /* Errors may not be returned and must be converted to zeros */ \
+ return ((__ret__ < 0) ? 0 : __ret__); \
+} \
+ \
+static unsigned long \
+fn ## _scan_objects(struct shrinker *shrink, struct shrink_control *sc) \
+{ \
+ int __ret__; \
+ \
+ __ret__ = __ ## fn(NULL, sc); \
+ return ((__ret__ < 0) ? SHRINK_STOP : __ret__); \
+}
+#else
/*
- * Linux 2.6. - 2.6. Shrinker API Compatibility.
+ * Linux 2.x to 2.6.22, or a newer shrinker API has been introduced.
*/
-# 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); \
-}
+#error "Unknown shrinker callback"
+#endif
-# endif
-#endif /* HAVE_SET_SHRINKER */
+#if defined(HAVE_SPLIT_SHRINKER_CALLBACK)
+typedef unsigned long spl_shrinker_t;
+#else
+typedef int spl_shrinker_t;
+#define SHRINK_STOP (-1)
+#endif
#endif /* SPL_MM_COMPAT_H */