summaryrefslogtreecommitdiffstats
path: root/config/kernel-shrink.m4
blob: 37da0ec721aa6a06221dfa787302af12003150ec (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
dnl #
dnl # 3.1 API change
dnl # The super_block structure now stores a per-filesystem shrinker.
dnl # This interface is preferable because it can be used to specifically
dnl # target only the zfs filesystem for pruning.
dnl #
AC_DEFUN([ZFS_AC_KERNEL_SHRINK], [
	AC_MSG_CHECKING([whether super_block has s_shrink])
	ZFS_LINUX_TRY_COMPILE([
		#include <linux/fs.h>

		int shrink(struct shrinker *s, struct shrink_control *sc)
		    { return 0; }

		static const struct super_block
		    sb __attribute__ ((unused)) = {
			.s_shrink.shrink = shrink,
			.s_shrink.seeks = DEFAULT_SEEKS,
			.s_shrink.batch = 0,
		};
	],[
	],[
		AC_MSG_RESULT(yes)
		AC_DEFINE(HAVE_SHRINK, 1, [struct super_block has s_shrink])

	],[
		AC_MSG_RESULT(no)
	])
])

dnl #
dnl # 3.3 API change
dnl # The super_block structure was changed to use an hlist_node instead
dnl # of a list_head for the .s_instance linkage.
dnl #
dnl # This was done in part to resolve a race in the iterate_supers_type()
dnl # function which was introduced in Linux 3.0 kernel.  The iterator
dnl # was supposed to provide a safe way to call an arbitrary function on
dnl # all super blocks of a specific type.  Unfortunately, because a
dnl # list_head was used it was possible for iterate_supers_type() to
dnl # get stuck spinning a super block which was just deactivated.
dnl #
dnl # This can occur because when the list head is removed from the
dnl # fs_supers list it is reinitialized to point to itself.  If the
dnl # iterate_supers_type() function happened to be processing the
dnl # removed list_head it will get stuck spinning on that list_head.
dnl #
dnl # To resolve the issue for existing 3.0 - 3.2 kernels we detect when
dnl # a list_head is used.  Then to prevent the spinning from occurring
dnl # the .next pointer is set to the fs_supers list_head which ensures
dnl # the iterate_supers_type() function will always terminate.
dnl #
AC_DEFUN([ZFS_AC_KERNEL_S_INSTANCES_LIST_HEAD], [
	AC_MSG_CHECKING([whether super_block has s_instances list_head])
	ZFS_LINUX_TRY_COMPILE([
		#include <linux/fs.h>
	],[
		struct super_block sb __attribute__ ((unused));

		INIT_LIST_HEAD(&sb.s_instances);
	],[
		AC_MSG_RESULT(yes)
		AC_DEFINE(HAVE_S_INSTANCES_LIST_HEAD, 1,
		    [struct super_block has s_instances list_head])
	],[
		AC_MSG_RESULT(no)
	])
])

AC_DEFUN([ZFS_AC_KERNEL_NR_CACHED_OBJECTS], [
	AC_MSG_CHECKING([whether sops->nr_cached_objects() exists])
	ZFS_LINUX_TRY_COMPILE([
		#include <linux/fs.h>

		int nr_cached_objects(struct super_block *sb) { return 0; }

		static const struct super_operations
		    sops __attribute__ ((unused)) = {
			.nr_cached_objects = nr_cached_objects,
		};
	],[
	],[
		AC_MSG_RESULT(yes)
		AC_DEFINE(HAVE_NR_CACHED_OBJECTS, 1,
			[sops->nr_cached_objects() exists])
	],[
		AC_MSG_RESULT(no)
	])
])

AC_DEFUN([ZFS_AC_KERNEL_FREE_CACHED_OBJECTS], [
	AC_MSG_CHECKING([whether sops->free_cached_objects() exists])
	ZFS_LINUX_TRY_COMPILE([
		#include <linux/fs.h>

		void free_cached_objects(struct super_block *sb, int x)
		    { return; }

		static const struct super_operations
		    sops __attribute__ ((unused)) = {
			.free_cached_objects = free_cached_objects,
		};
	],[
	],[
		AC_MSG_RESULT(yes)
		AC_DEFINE(HAVE_FREE_CACHED_OBJECTS, 1,
			[sops->free_cached_objects() exists])
	],[
		AC_MSG_RESULT(no)
	])
])

dnl #
dnl # 3.12 API change
dnl # The nid member was added to struct shrink_control to support
dnl # NUMA-aware shrinkers.
dnl #
AC_DEFUN([ZFS_AC_KERNEL_SHRINK_CONTROL_HAS_NID], [
	AC_MSG_CHECKING([whether shrink_control has nid])
	ZFS_LINUX_TRY_COMPILE([
		#include <linux/fs.h>
	],[
		struct shrink_control sc __attribute__ ((unused));
		unsigned long scnidsize __attribute__ ((unused)) =
		    sizeof(sc.nid);
	],[
		AC_MSG_RESULT(yes)
		AC_DEFINE(SHRINK_CONTROL_HAS_NID, 1,
		    [struct shrink_control has nid])
	],[
		AC_MSG_RESULT(no)
	])
])


AC_DEFUN([ZFS_AC_KERNEL_SHRINKER_CALLBACK],[
	tmp_flags="$EXTRA_KCFLAGS"
	EXTRA_KCFLAGS="-Werror"
	dnl #
	dnl # 2.6.23 to 2.6.34 API change
	dnl # ->shrink(int nr_to_scan, gfp_t gfp_mask)
	dnl #
	AC_MSG_CHECKING([whether old 2-argument shrinker exists])
	ZFS_LINUX_TRY_COMPILE([
		#include <linux/mm.h>

		int shrinker_cb(int nr_to_scan, gfp_t gfp_mask);
	],[
		struct shrinker cache_shrinker = {
			.shrink = shrinker_cb,
			.seeks = DEFAULT_SEEKS,
		};
		register_shrinker(&cache_shrinker);
	],[
		AC_MSG_RESULT(yes)
		AC_DEFINE(HAVE_2ARGS_OLD_SHRINKER_CALLBACK, 1,
			[old shrinker callback wants 2 args])
	],[
		AC_MSG_RESULT(no)
		dnl #
		dnl # 2.6.35 - 2.6.39 API change
		dnl # ->shrink(struct shrinker *,
		dnl #          int nr_to_scan, gfp_t gfp_mask)
		dnl #
		AC_MSG_CHECKING([whether old 3-argument shrinker exists])
		ZFS_LINUX_TRY_COMPILE([
			#include <linux/mm.h>

			int shrinker_cb(struct shrinker *, int nr_to_scan,
					gfp_t gfp_mask);
		],[
			struct shrinker cache_shrinker = {
				.shrink = shrinker_cb,
				.seeks = DEFAULT_SEEKS,
			};
			register_shrinker(&cache_shrinker);
		],[
			AC_MSG_RESULT(yes)
			AC_DEFINE(HAVE_3ARGS_SHRINKER_CALLBACK, 1,
				[old shrinker callback wants 3 args])
		],[
			AC_MSG_RESULT(no)
			dnl #
			dnl # 3.0 - 3.11 API change
			dnl # ->shrink(struct shrinker *,
			dnl #          struct shrink_control *sc)
			dnl #
			AC_MSG_CHECKING(
				[whether new 2-argument shrinker exists])
			ZFS_LINUX_TRY_COMPILE([
				#include <linux/mm.h>

				int shrinker_cb(struct shrinker *,
						struct shrink_control *sc);
			],[
				struct shrinker cache_shrinker = {
					.shrink = shrinker_cb,
					.seeks = DEFAULT_SEEKS,
				};
				register_shrinker(&cache_shrinker);
			],[
				AC_MSG_RESULT(yes)
				AC_DEFINE(HAVE_2ARGS_NEW_SHRINKER_CALLBACK, 1,
					[new shrinker callback wants 2 args])
			],[
				AC_MSG_RESULT(no)
				dnl #
				dnl # 3.12 API change,
				dnl # ->shrink() is logically split in to
				dnl # ->count_objects() and ->scan_objects()
				dnl #
				AC_MSG_CHECKING(
				    [whether ->count_objects callback exists])
				ZFS_LINUX_TRY_COMPILE([
					#include <linux/mm.h>

					unsigned long shrinker_cb(
						struct shrinker *,
						struct shrink_control *sc);
				],[
					struct shrinker cache_shrinker = {
						.count_objects = shrinker_cb,
						.scan_objects = shrinker_cb,
						.seeks = DEFAULT_SEEKS,
					};
					register_shrinker(&cache_shrinker);
				],[
					AC_MSG_RESULT(yes)
					AC_DEFINE(HAVE_SPLIT_SHRINKER_CALLBACK,
						1, [->count_objects exists])
				],[
					AC_MSG_ERROR(error)
				])
			])
		])
	])
	EXTRA_KCFLAGS="$tmp_flags"
])

dnl #
dnl # 2.6.39 API change,
dnl # Shrinker adjust to use common shrink_control structure.
dnl #
AC_DEFUN([ZFS_AC_KERNEL_SHRINK_CONTROL_STRUCT], [
	AC_MSG_CHECKING([whether struct shrink_control exists])
	ZFS_LINUX_TRY_COMPILE([
		#include <linux/mm.h>
	],[
		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)
	])
])