]>
Commit | Line | Data |
---|---|---|
2b5e1b7b JR |
1 | From c3d9c0df3ee8d43db22815ebbfbe8b803fa46e46 Mon Sep 17 00:00:00 2001 |
2 | From: Richard Yao <ryao@gentoo.org> | |
3 | Date: Tue, 5 Nov 2013 11:35:54 -0500 | |
4 | Subject: [PATCH] Linux 3.12 compat: New shrinker API | |
5 | ||
6 | torvalds/linux@24f7c6 introduced a new shrinker API while | |
7 | torvalds/linux@a0b021 dropped support for the old shrinker API. | |
8 | This patch adds support for the new shrinker API by wrapping | |
9 | the old one with the new one. | |
10 | ||
11 | This change also reorganizes the autotools checks on the shrinker | |
12 | API such that the configure script will fail early if an unknown | |
13 | API is encountered in the future. | |
14 | ||
15 | Support for the set_shrinker() API which was used by Linux 2.6.22 | |
16 | and older has been dropped. As a general rule compatibility is | |
17 | only maintained back to Linux 2.6.26. | |
18 | ||
19 | Signed-off-by: Richard Yao <ryao@gentoo.org> | |
20 | Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov> | |
21 | Closes zfsonlinux/zfs#1732 | |
22 | Closes zfsonlinux/zfs#1822 | |
23 | Closes #293 | |
24 | Closes #307 | |
25 | --- | |
26 | config/spl-build.m4 | 116 ++++++++++++++++++------ | |
27 | include/linux/mm_compat.h | 226 +++++++++++++++++++++++++++++----------------- | |
28 | 2 files changed, 229 insertions(+), 113 deletions(-) | |
29 | ||
30 | diff --git a/config/spl-build.m4 b/config/spl-build.m4 | |
31 | index b0e3348..7d744db 100644 | |
32 | --- a/config/spl-build.m4 | |
33 | +++ b/config/spl-build.m4 | |
34 | @@ -27,8 +27,7 @@ AC_DEFUN([SPL_AC_CONFIG_KERNEL], [ | |
35 | SPL_AC_TYPE_ATOMIC64_XCHG | |
36 | SPL_AC_TYPE_UINTPTR_T | |
37 | SPL_AC_2ARGS_REGISTER_SYSCTL | |
38 | - SPL_AC_SET_SHRINKER | |
39 | - SPL_AC_3ARGS_SHRINKER_CALLBACK | |
40 | + SPL_AC_SHRINKER_CALLBACK | |
41 | SPL_AC_PATH_IN_NAMEIDATA | |
42 | SPL_AC_TASK_CURR | |
43 | SPL_AC_CTL_UNNUMBERED | |
44 | @@ -885,37 +884,18 @@ AC_DEFUN([SPL_AC_2ARGS_REGISTER_SYSCTL], | |
45 | ]) | |
46 | ]) | |
47 | ||
48 | -dnl # | |
49 | -dnl # 2.6.23 API change | |
50 | -dnl # Old set_shrinker API replaced with register_shrinker | |
51 | -dnl # | |
52 | -AC_DEFUN([SPL_AC_SET_SHRINKER], [ | |
53 | - AC_MSG_CHECKING([whether set_shrinker() available]) | |
54 | - SPL_LINUX_TRY_COMPILE([ | |
55 | - #include <linux/mm.h> | |
56 | - ],[ | |
57 | - return set_shrinker(DEFAULT_SEEKS, NULL); | |
58 | - ],[ | |
59 | - AC_MSG_RESULT([yes]) | |
60 | - AC_DEFINE(HAVE_SET_SHRINKER, 1, | |
61 | - [set_shrinker() available]) | |
62 | - ],[ | |
63 | - AC_MSG_RESULT([no]) | |
64 | - ]) | |
65 | -]) | |
66 | - | |
67 | -dnl # | |
68 | -dnl # 2.6.35 API change, | |
69 | -dnl # Add context to shrinker callback | |
70 | -dnl # | |
71 | -AC_DEFUN([SPL_AC_3ARGS_SHRINKER_CALLBACK], | |
72 | - [AC_MSG_CHECKING([whether shrinker callback wants 3 args]) | |
73 | +AC_DEFUN([SPL_AC_SHRINKER_CALLBACK],[ | |
74 | tmp_flags="$EXTRA_KCFLAGS" | |
75 | EXTRA_KCFLAGS="-Werror" | |
76 | + dnl # | |
77 | + dnl # 2.6.23 to 2.6.34 API change | |
78 | + dnl # ->shrink(int nr_to_scan, gfp_t gfp_mask) | |
79 | + dnl # | |
80 | + AC_MSG_CHECKING([whether old 2-argument shrinker exists]) | |
81 | SPL_LINUX_TRY_COMPILE([ | |
82 | #include <linux/mm.h> | |
83 | ||
84 | - int shrinker_cb(struct shrinker *, int, unsigned int); | |
85 | + int shrinker_cb(int nr_to_scan, gfp_t gfp_mask); | |
86 | ],[ | |
87 | struct shrinker cache_shrinker = { | |
88 | .shrink = shrinker_cb, | |
89 | @@ -924,10 +904,86 @@ AC_DEFUN([SPL_AC_3ARGS_SHRINKER_CALLBACK], | |
90 | register_shrinker(&cache_shrinker); | |
91 | ],[ | |
92 | AC_MSG_RESULT(yes) | |
93 | - AC_DEFINE(HAVE_3ARGS_SHRINKER_CALLBACK, 1, | |
94 | - [shrinker callback wants 3 args]) | |
95 | + AC_DEFINE(HAVE_2ARGS_OLD_SHRINKER_CALLBACK, 1, | |
96 | + [old shrinker callback wants 2 args]) | |
97 | ],[ | |
98 | AC_MSG_RESULT(no) | |
99 | + dnl # | |
100 | + dnl # 2.6.35 - 2.6.39 API change | |
101 | + dnl # ->shrink(struct shrinker *, | |
102 | + dnl # int nr_to_scan, gfp_t gfp_mask) | |
103 | + dnl # | |
104 | + AC_MSG_CHECKING([whether old 3-argument shrinker exists]) | |
105 | + SPL_LINUX_TRY_COMPILE([ | |
106 | + #include <linux/mm.h> | |
107 | + | |
108 | + int shrinker_cb(struct shrinker *, int nr_to_scan, | |
109 | + gfp_t gfp_mask); | |
110 | + ],[ | |
111 | + struct shrinker cache_shrinker = { | |
112 | + .shrink = shrinker_cb, | |
113 | + .seeks = DEFAULT_SEEKS, | |
114 | + }; | |
115 | + register_shrinker(&cache_shrinker); | |
116 | + ],[ | |
117 | + AC_MSG_RESULT(yes) | |
118 | + AC_DEFINE(HAVE_3ARGS_SHRINKER_CALLBACK, 1, | |
119 | + [old shrinker callback wants 3 args]) | |
120 | + ],[ | |
121 | + AC_MSG_RESULT(no) | |
122 | + dnl # | |
123 | + dnl # 3.0 - 3.11 API change | |
124 | + dnl # ->shrink(struct shrinker *, | |
125 | + dnl # struct shrink_control *sc) | |
126 | + dnl # | |
127 | + AC_MSG_CHECKING( | |
128 | + [whether new 2-argument shrinker exists]) | |
129 | + SPL_LINUX_TRY_COMPILE([ | |
130 | + #include <linux/mm.h> | |
131 | + | |
132 | + int shrinker_cb(struct shrinker *, | |
133 | + struct shrink_control *sc); | |
134 | + ],[ | |
135 | + struct shrinker cache_shrinker = { | |
136 | + .shrink = shrinker_cb, | |
137 | + .seeks = DEFAULT_SEEKS, | |
138 | + }; | |
139 | + register_shrinker(&cache_shrinker); | |
140 | + ],[ | |
141 | + AC_MSG_RESULT(yes) | |
142 | + AC_DEFINE(HAVE_2ARGS_NEW_SHRINKER_CALLBACK, 1, | |
143 | + [new shrinker callback wants 2 args]) | |
144 | + ],[ | |
145 | + AC_MSG_RESULT(no) | |
146 | + dnl # | |
147 | + dnl # 3.12 API change, | |
148 | + dnl # ->shrink() is logically split in to | |
149 | + dnl # ->count_objects() and ->scan_objects() | |
150 | + dnl # | |
151 | + AC_MSG_CHECKING( | |
152 | + [whether ->count_objects callback exists]) | |
153 | + SPL_LINUX_TRY_COMPILE([ | |
154 | + #include <linux/mm.h> | |
155 | + | |
156 | + unsigned long shrinker_cb( | |
157 | + struct shrinker *, | |
158 | + struct shrink_control *sc); | |
159 | + ],[ | |
160 | + struct shrinker cache_shrinker = { | |
161 | + .count_objects = shrinker_cb, | |
162 | + .scan_objects = shrinker_cb, | |
163 | + .seeks = DEFAULT_SEEKS, | |
164 | + }; | |
165 | + register_shrinker(&cache_shrinker); | |
166 | + ],[ | |
167 | + AC_MSG_RESULT(yes) | |
168 | + AC_DEFINE(HAVE_SPLIT_SHRINKER_CALLBACK, | |
169 | + 1, [->count_objects exists]) | |
170 | + ],[ | |
171 | + AC_MSG_ERROR(error) | |
172 | + ]) | |
173 | + ]) | |
174 | + ]) | |
175 | ]) | |
176 | EXTRA_KCFLAGS="$tmp_flags" | |
177 | ]) | |
178 | diff --git a/include/linux/mm_compat.h b/include/linux/mm_compat.h | |
179 | index cb1bef9..37c9b08 100644 | |
180 | --- a/include/linux/mm_compat.h | |
181 | +++ b/include/linux/mm_compat.h | |
182 | @@ -148,107 +148,167 @@ typedef int (*shrink_icache_memory_t)(struct shrinker *, | |
183 | #endif /* HAVE_SHRINK_ICACHE_MEMORY */ | |
184 | ||
185 | /* | |
186 | - * Linux 2.6. - 2.6. Shrinker API Compatibility. | |
187 | + * Due to frequent changes in the shrinker API the following | |
188 | + * compatibility wrappers should be used. They are as follows: | |
189 | + * | |
190 | + * SPL_SHRINKER_DECLARE is used to declare the shrinker which is | |
191 | + * passed to spl_register_shrinker()/spl_unregister_shrinker(). Use | |
192 | + * shrinker_name to set the shrinker variable name, shrinker_callback | |
193 | + * to set the callback function, and seek_cost to define the cost of | |
194 | + * reclaiming an object. | |
195 | + * | |
196 | + * SPL_SHRINKER_DECLARE(shrinker_name, shrinker_callback, seek_cost); | |
197 | + * | |
198 | + * SPL_SHRINKER_CALLBACK_FWD_DECLARE is used when a forward declaration | |
199 | + * of the shrinker callback function is required. Only the callback | |
200 | + * function needs to be passed. | |
201 | + * | |
202 | + * SPL_SHRINKER_CALLBACK_FWD_DECLARE(shrinker_callback); | |
203 | + * | |
204 | + * SPL_SHRINKER_CALLBACK_WRAPPER is used to declare the callback function | |
205 | + * which is registered with the shrinker. This function will call your | |
206 | + * custom shrinker which must use the following prototype. Notice the | |
207 | + * leading __'s, these must be appended to the callback_function name. | |
208 | + * | |
209 | + * int __shrinker_callback(struct shrinker *, struct shrink_control *) | |
210 | + * SPL_SHRINKER_CALLBACK_WRAPPER(shrinker_callback);a | |
211 | + * | |
212 | + * | |
213 | + * Example: | |
214 | + * | |
215 | + * SPL_SHRINKER_CALLBACK_FWD_DECLARE(my_shrinker_fn); | |
216 | + * SPL_SHRINKER_DECLARE(my_shrinker, my_shrinker_fn, 1); | |
217 | + * | |
218 | + * static int | |
219 | + * __my_shrinker_fn(struct shrinker *shrink, struct shrink_control *sc) | |
220 | + * { | |
221 | + * if (sc->nr_to_scan) { | |
222 | + * ...scan objects in the cache and reclaim them... | |
223 | + * } | |
224 | + * | |
225 | + * ...calculate number of objects in the cache... | |
226 | + * | |
227 | + * return (number of objects in the cache); | |
228 | + * } | |
229 | + * SPL_SHRINKER_CALLBACK_WRAPPER(my_shrinker_fn); | |
230 | */ | |
231 | -#ifdef HAVE_SET_SHRINKER | |
232 | -typedef struct spl_shrinker { | |
233 | - struct shrinker *shrinker; | |
234 | - shrinker_t fn; | |
235 | - int seeks; | |
236 | -} spl_shrinker_t; | |
237 | - | |
238 | -static inline void | |
239 | -spl_register_shrinker(spl_shrinker_t *ss) | |
240 | -{ | |
241 | - ss->shrinker = set_shrinker(ss->seeks, ss->fn); | |
242 | -} | |
243 | ||
244 | -static inline void | |
245 | -spl_unregister_shrinker(spl_shrinker_t *ss) | |
246 | -{ | |
247 | - remove_shrinker(ss->shrinker); | |
248 | -} | |
249 | +#define spl_register_shrinker(x) register_shrinker(x) | |
250 | +#define spl_unregister_shrinker(x) unregister_shrinker(x) | |
251 | ||
252 | -# define SPL_SHRINKER_DECLARE(s, x, y) \ | |
253 | - static spl_shrinker_t s = { \ | |
254 | - .shrinker = NULL, \ | |
255 | - .fn = x, \ | |
256 | - .seeks = y \ | |
257 | - } | |
258 | - | |
259 | -# define SPL_SHRINKER_CALLBACK_FWD_DECLARE(fn) \ | |
260 | - static int fn(int, unsigned int) | |
261 | -# define SPL_SHRINKER_CALLBACK_WRAPPER(fn) \ | |
262 | -static int \ | |
263 | -fn(int nr_to_scan, unsigned int gfp_mask) \ | |
264 | -{ \ | |
265 | - struct shrink_control sc; \ | |
266 | - \ | |
267 | - sc.nr_to_scan = nr_to_scan; \ | |
268 | - sc.gfp_mask = gfp_mask; \ | |
269 | - \ | |
270 | - return __ ## fn(NULL, &sc); \ | |
271 | +/* | |
272 | + * Linux 2.6.23 - 2.6.34 Shrinker API Compatibility. | |
273 | + */ | |
274 | +#if defined(HAVE_2ARGS_OLD_SHRINKER_CALLBACK) | |
275 | +#define SPL_SHRINKER_DECLARE(s, x, y) \ | |
276 | +static struct shrinker s = { \ | |
277 | + .shrink = x, \ | |
278 | + .seeks = y \ | |
279 | } | |
280 | ||
281 | -#else | |
282 | +#define SPL_SHRINKER_CALLBACK_FWD_DECLARE(fn) \ | |
283 | +static int fn(int nr_to_scan, unsigned int gfp_mask) | |
284 | ||
285 | -# define spl_register_shrinker(x) register_shrinker(x) | |
286 | -# define spl_unregister_shrinker(x) unregister_shrinker(x) | |
287 | -# define SPL_SHRINKER_DECLARE(s, x, y) \ | |
288 | - static struct shrinker s = { \ | |
289 | - .shrink = x, \ | |
290 | - .seeks = y \ | |
291 | - } | |
292 | +#define SPL_SHRINKER_CALLBACK_WRAPPER(fn) \ | |
293 | +static int \ | |
294 | +fn(int nr_to_scan, unsigned int gfp_mask) \ | |
295 | +{ \ | |
296 | + struct shrink_control sc; \ | |
297 | + \ | |
298 | + sc.nr_to_scan = nr_to_scan; \ | |
299 | + sc.gfp_mask = gfp_mask; \ | |
300 | + \ | |
301 | + return (__ ## fn(NULL, &sc)); \ | |
302 | +} | |
303 | ||
304 | /* | |
305 | - * Linux 2.6. - 2.6. Shrinker API Compatibility. | |
306 | + * Linux 2.6.35 to 2.6.39 Shrinker API Compatibility. | |
307 | */ | |
308 | -# if defined(HAVE_SHRINK_CONTROL_STRUCT) | |
309 | -# define SPL_SHRINKER_CALLBACK_FWD_DECLARE(fn) \ | |
310 | - static int fn(struct shrinker *, struct shrink_control *) | |
311 | -# define SPL_SHRINKER_CALLBACK_WRAPPER(fn) \ | |
312 | -static int \ | |
313 | -fn(struct shrinker *shrink, struct shrink_control *sc) { \ | |
314 | - return __ ## fn(shrink, sc); \ | |
315 | +#elif defined(HAVE_3ARGS_SHRINKER_CALLBACK) | |
316 | +#define SPL_SHRINKER_DECLARE(s, x, y) \ | |
317 | +static struct shrinker s = { \ | |
318 | + .shrink = x, \ | |
319 | + .seeks = y \ | |
320 | +} | |
321 | + | |
322 | +#define SPL_SHRINKER_CALLBACK_FWD_DECLARE(fn) \ | |
323 | +static int fn(struct shrinker *, int, unsigned int) | |
324 | + | |
325 | +#define SPL_SHRINKER_CALLBACK_WRAPPER(fn) \ | |
326 | +static int \ | |
327 | +fn(struct shrinker *shrink, int nr_to_scan, unsigned int gfp_mask) \ | |
328 | +{ \ | |
329 | + struct shrink_control sc; \ | |
330 | + \ | |
331 | + sc.nr_to_scan = nr_to_scan; \ | |
332 | + sc.gfp_mask = gfp_mask; \ | |
333 | + \ | |
334 | + return (__ ## fn(shrink, &sc)); \ | |
335 | } | |
336 | ||
337 | /* | |
338 | - * Linux 2.6. - 2.6. Shrinker API Compatibility. | |
339 | + * Linux 3.0 to 3.11 Shrinker API Compatibility. | |
340 | */ | |
341 | -# elif defined(HAVE_3ARGS_SHRINKER_CALLBACK) | |
342 | -# define SPL_SHRINKER_CALLBACK_FWD_DECLARE(fn) \ | |
343 | - static int fn(struct shrinker *, int, unsigned int) | |
344 | -# define SPL_SHRINKER_CALLBACK_WRAPPER(fn) \ | |
345 | -static int \ | |
346 | -fn(struct shrinker *shrink, int nr_to_scan, unsigned int gfp_mask) \ | |
347 | -{ \ | |
348 | - struct shrink_control sc; \ | |
349 | - \ | |
350 | - sc.nr_to_scan = nr_to_scan; \ | |
351 | - sc.gfp_mask = gfp_mask; \ | |
352 | - \ | |
353 | - return __ ## fn(shrink, &sc); \ | |
354 | +#elif defined(HAVE_2ARGS_NEW_SHRINKER_CALLBACK) | |
355 | +#define SPL_SHRINKER_DECLARE(s, x, y) \ | |
356 | +static struct shrinker s = { \ | |
357 | + .shrink = x, \ | |
358 | + .seeks = y \ | |
359 | +} | |
360 | + | |
361 | +#define SPL_SHRINKER_CALLBACK_FWD_DECLARE(fn) \ | |
362 | +static int fn(struct shrinker *, struct shrink_control *) | |
363 | + | |
364 | +#define SPL_SHRINKER_CALLBACK_WRAPPER(fn) \ | |
365 | +static int \ | |
366 | +fn(struct shrinker *shrink, struct shrink_control *sc) \ | |
367 | +{ \ | |
368 | + return (__ ## fn(shrink, sc)); \ | |
369 | } | |
370 | ||
371 | /* | |
372 | - * Linux 2.6. - 2.6. Shrinker API Compatibility. | |
373 | + * Linux 3.12 and later Shrinker API Compatibility. | |
374 | */ | |
375 | -# else | |
376 | -# define SPL_SHRINKER_CALLBACK_FWD_DECLARE(fn) \ | |
377 | - static int fn(int, unsigned int) | |
378 | -# define SPL_SHRINKER_CALLBACK_WRAPPER(fn) \ | |
379 | -static int \ | |
380 | -fn(int nr_to_scan, unsigned int gfp_mask) \ | |
381 | -{ \ | |
382 | - struct shrink_control sc; \ | |
383 | - \ | |
384 | - sc.nr_to_scan = nr_to_scan; \ | |
385 | - sc.gfp_mask = gfp_mask; \ | |
386 | - \ | |
387 | - return __ ## fn(NULL, &sc); \ | |
388 | +#elif defined(HAVE_SPLIT_SHRINKER_CALLBACK) | |
389 | +#define SPL_SHRINKER_DECLARE(s, x, y) \ | |
390 | +static struct shrinker s = { \ | |
391 | + .count_objects = x ## _count_objects, \ | |
392 | + .scan_objects = x ## _scan_objects, \ | |
393 | + .seeks = y \ | |
394 | } | |
395 | ||
396 | -# endif | |
397 | -#endif /* HAVE_SET_SHRINKER */ | |
398 | +#define SPL_SHRINKER_CALLBACK_FWD_DECLARE(fn) \ | |
399 | +static unsigned long fn ## _count_objects(struct shrinker *, \ | |
400 | + struct shrink_control *); \ | |
401 | +static unsigned long fn ## _scan_objects(struct shrinker *, \ | |
402 | + struct shrink_control *) | |
403 | + | |
404 | +#define SPL_SHRINKER_CALLBACK_WRAPPER(fn) \ | |
405 | +static unsigned long \ | |
406 | +fn ## _count_objects(struct shrinker *shrink, struct shrink_control *sc)\ | |
407 | +{ \ | |
408 | + int __ret__; \ | |
409 | + \ | |
410 | + sc->nr_to_scan = 0; \ | |
411 | + __ret__ = __ ## fn(NULL, sc); \ | |
412 | + \ | |
413 | + /* Errors may not be returned and must be converted to zeros */ \ | |
414 | + return ((__ret__ < 0) ? 0 : __ret__); \ | |
415 | +} \ | |
416 | + \ | |
417 | +static unsigned long \ | |
418 | +fn ## _scan_objects(struct shrinker *shrink, struct shrink_control *sc) \ | |
419 | +{ \ | |
420 | + int __ret__; \ | |
421 | + \ | |
422 | + __ret__ = __ ## fn(NULL, sc); \ | |
423 | + return ((__ret__ < 0) ? SHRINK_STOP : __ret__); \ | |
424 | +} | |
425 | +#else | |
426 | +/* | |
427 | + * Linux 2.x to 2.6.22, or a newer shrinker API has been introduced. | |
428 | + */ | |
429 | +#error "Unknown shrinker callback" | |
430 | +#endif | |
431 | ||
432 | #endif /* SPL_MM_COMPAT_H */ | |
433 | -- | |
434 | 1.8.5.1 | |
435 |