]> git.proxmox.com Git - mirror_zfs.git/blob - module/splat/splat-linux.c
Remove shrink_{i,d}node_cache() wrappers
[mirror_zfs.git] / module / splat / splat-linux.c
1 /*****************************************************************************\
2 * Copyright (C) 2011 Lawrence Livermore National Security, LLC.
3 * Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
4 * Written by Brian Behlendorf <behlendorf1@llnl.gov>.
5 * UCRL-CODE-235197
6 *
7 * This file is part of the SPL, Solaris Porting Layer.
8 * For details, see <http://zfsonlinux.org/>.
9 *
10 * The SPL is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by the
12 * Free Software Foundation; either version 2 of the License, or (at your
13 * option) any later version.
14 *
15 * The SPL is distributed in the hope that it will be useful, but WITHOUT
16 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
17 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
18 * for more details.
19 *
20 * You should have received a copy of the GNU General Public License along
21 * with the SPL. If not, see <http://www.gnu.org/licenses/>.
22 *****************************************************************************
23 * Solaris Porting LAyer Tests (SPLAT) Kernel Compatibility Tests.
24 \*****************************************************************************/
25
26 #include <sys/kmem.h>
27 #include "splat-internal.h"
28
29 #define SPLAT_LINUX_NAME "linux"
30 #define SPLAT_LINUX_DESC "Kernel Compatibility Tests"
31
32 #define SPLAT_LINUX_TEST1_ID 0x1001
33 #define SPLAT_LINUX_TEST1_NAME "shrinker"
34 #define SPLAT_LINUX_TEST1_DESC "Shrinker test"
35
36 /*
37 * Wait queue used to eliminate race between dropping of slab
38 * and execution of the shrinker callback
39 */
40 DECLARE_WAIT_QUEUE_HEAD(shrinker_wait);
41
42 SPL_SHRINKER_CALLBACK_FWD_DECLARE(splat_linux_shrinker_fn);
43 SPL_SHRINKER_DECLARE(splat_linux_shrinker, splat_linux_shrinker_fn, 1);
44 static unsigned long splat_linux_shrinker_size = 0;
45 static struct file *splat_linux_shrinker_file = NULL;
46
47 static int
48 __splat_linux_shrinker_fn(struct shrinker *shrink, struct shrink_control *sc)
49 {
50 static int failsafe = 0;
51 static unsigned long last_splat_linux_shrinker_size = 0;
52
53 /*
54 * shrinker_size can only decrease or stay the same between callbacks
55 * in the same run, so Reset failsafe whenever shrinker increases
56 * as this indicates a new run.
57 */
58 if (last_splat_linux_shrinker_size < splat_linux_shrinker_size)
59 failsafe = 0;
60
61 last_splat_linux_shrinker_size = splat_linux_shrinker_size;
62
63 if (sc->nr_to_scan) {
64 splat_linux_shrinker_size = splat_linux_shrinker_size -
65 MIN(sc->nr_to_scan, splat_linux_shrinker_size);
66
67 splat_vprint(splat_linux_shrinker_file, SPLAT_LINUX_TEST1_NAME,
68 "Reclaimed %lu objects, size now %lu\n",
69 sc->nr_to_scan, splat_linux_shrinker_size);
70 } else {
71 splat_vprint(splat_linux_shrinker_file, SPLAT_LINUX_TEST1_NAME,
72 "Cache size is %lu\n", splat_linux_shrinker_size);
73 }
74
75 /* Far more calls than expected abort drop_slab as a failsafe */
76 if (failsafe > 100) {
77 splat_vprint(splat_linux_shrinker_file, SPLAT_LINUX_TEST1_NAME,
78 "Far more calls than expected (%d), size now %lu\n",
79 failsafe, splat_linux_shrinker_size);
80 return -1;
81 } else {
82 /*
83 * We only increment failsafe if it doesn't trigger. This
84 * makes any failsafe failure persistent until the next test.
85 */
86 failsafe++;
87 }
88
89 /* Shrinker has run, so signal back to test. */
90 wake_up(&shrinker_wait);
91
92 return (int)splat_linux_shrinker_size;
93 }
94
95 SPL_SHRINKER_CALLBACK_WRAPPER(splat_linux_shrinker_fn);
96
97 #define DROP_SLAB_CMD \
98 "exec 0</dev/null " \
99 " 1>/proc/sys/vm/drop_caches " \
100 " 2>/dev/null; " \
101 "echo 2"
102
103 static int
104 splat_linux_drop_slab(struct file *file)
105 {
106 char *argv[] = { "/bin/sh",
107 "-c",
108 DROP_SLAB_CMD,
109 NULL };
110 char *envp[] = { "HOME=/",
111 "TERM=linux",
112 "PATH=/sbin:/usr/sbin:/bin:/usr/bin",
113 NULL };
114 int rc;
115
116 rc = call_usermodehelper(argv[0], argv, envp, UMH_WAIT_PROC);
117 if (rc)
118 splat_vprint(file, SPLAT_LINUX_TEST1_NAME,
119 "Failed user helper '%s %s %s', rc = %d\n",
120 argv[0], argv[1], argv[2], rc);
121
122 return rc;
123 }
124
125 /*
126 * Verify correct shrinker functionality by registering a shrinker
127 * with the required compatibility macros. We then use a simulated
128 * cache and force the systems caches to be dropped. The shrinker
129 * should be repeatedly called until it reports that the cache is
130 * empty. It is then cleanly unregistered and correct behavior is
131 * verified. There are now four slightly different supported shrinker
132 * API and this test ensures the compatibility code is correct.
133 */
134 static int
135 splat_linux_test1(struct file *file, void *arg)
136 {
137 int rc = -EINVAL;
138
139 /*
140 * Globals used by the shrinker, it is not safe to run this
141 * test concurrently this is a safe assumption for SPLAT tests.
142 * Regardless we do some minimal checking a bail if concurrent
143 * use is detected.
144 */
145 if (splat_linux_shrinker_size || splat_linux_shrinker_file) {
146 splat_vprint(file, SPLAT_LINUX_TEST1_NAME,
147 "Failed due to concurrent shrinker test, rc = %d\n", rc);
148 return (rc);
149 }
150
151 splat_linux_shrinker_size = 1024;
152 splat_linux_shrinker_file = file;
153
154 spl_register_shrinker(&splat_linux_shrinker);
155 rc = splat_linux_drop_slab(file);
156 if (rc)
157 goto out;
158
159 /*
160 * By the time we get here, it is possible that the shrinker has not
161 * yet run. splat_linux_drop_slab sends a signal for it to run, but
162 * there is no guarantee of when it will actually run. We wait for it
163 * to run here, terminating when either the shrinker size is now 0 or
164 * we timeout after 1 second, which should be an eternity (error).
165 */
166 rc = wait_event_timeout(shrinker_wait, !splat_linux_shrinker_size, HZ);
167 if (!rc) {
168 splat_vprint(file, SPLAT_LINUX_TEST1_NAME,
169 "Failed cache shrinking timed out, size now %lu",
170 splat_linux_shrinker_size);
171 rc = -ETIMEDOUT;
172 } else {
173 rc = 0;
174 }
175
176 if (!rc && splat_linux_shrinker_size != 0) {
177 splat_vprint(file, SPLAT_LINUX_TEST1_NAME,
178 "Failed cache was not shrunk to 0, size now %lu",
179 splat_linux_shrinker_size);
180 rc = -EDOM;
181 }
182 out:
183 spl_unregister_shrinker(&splat_linux_shrinker);
184
185 splat_linux_shrinker_size = 0;
186 splat_linux_shrinker_file = NULL;
187
188 return rc;
189 }
190
191 splat_subsystem_t *
192 splat_linux_init(void)
193 {
194 splat_subsystem_t *sub;
195
196 sub = kmalloc(sizeof(*sub), GFP_KERNEL);
197 if (sub == NULL)
198 return NULL;
199
200 memset(sub, 0, sizeof(*sub));
201 strncpy(sub->desc.name, SPLAT_LINUX_NAME, SPLAT_NAME_SIZE);
202 strncpy(sub->desc.desc, SPLAT_LINUX_DESC, SPLAT_DESC_SIZE);
203 INIT_LIST_HEAD(&sub->subsystem_list);
204 INIT_LIST_HEAD(&sub->test_list);
205 spin_lock_init(&sub->test_lock);
206 sub->desc.id = SPLAT_SUBSYSTEM_LINUX;
207
208 SPLAT_TEST_INIT(sub, SPLAT_LINUX_TEST1_NAME, SPLAT_LINUX_TEST1_DESC,
209 SPLAT_LINUX_TEST1_ID, splat_linux_test1);
210
211 return sub;
212 }
213
214 void
215 splat_linux_fini(splat_subsystem_t *sub)
216 {
217 ASSERT(sub);
218 SPLAT_TEST_FINI(sub, SPLAT_LINUX_TEST1_ID);
219
220 kfree(sub);
221 }
222
223 int
224 splat_linux_id(void) {
225 return SPLAT_SUBSYSTEM_LINUX;
226 }