]> git.proxmox.com Git - mirror_spl-debian.git/blame - module/splat/splat-linux.c
New upstream version 0.7.2
[mirror_spl-debian.git] / module / splat / splat-linux.c
CommitLineData
bf0c60c0
BB
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.
3d6af2dd 8 * For details, see <http://zfsonlinux.org/>.
bf0c60c0
BB
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
df870a69 26#include <sys/kmem.h>
10946b02 27#include <linux/mm_compat.h>
bf0c60c0
BB
28#include "splat-internal.h"
29
30#define SPLAT_LINUX_NAME "linux"
31#define SPLAT_LINUX_DESC "Kernel Compatibility Tests"
32
33#define SPLAT_LINUX_TEST1_ID 0x1001
10946b02
AX
34#define SPLAT_LINUX_TEST1_NAME "shrinker"
35#define SPLAT_LINUX_TEST1_DESC "Shrinker test"
bf0c60c0 36
ca072ee7
SJ
37/*
38 * Wait queue used to eliminate race between dropping of slab
39 * and execution of the shrinker callback
40 */
41DECLARE_WAIT_QUEUE_HEAD(shrinker_wait);
42
bf0c60c0
BB
43SPL_SHRINKER_CALLBACK_FWD_DECLARE(splat_linux_shrinker_fn);
44SPL_SHRINKER_DECLARE(splat_linux_shrinker, splat_linux_shrinker_fn, 1);
45static unsigned long splat_linux_shrinker_size = 0;
46static struct file *splat_linux_shrinker_file = NULL;
47
10946b02 48static spl_shrinker_t
bf0c60c0
BB
49__splat_linux_shrinker_fn(struct shrinker *shrink, struct shrink_control *sc)
50{
51 static int failsafe = 0;
794f145b 52 static unsigned long last_splat_linux_shrinker_size = 0;
10946b02
AX
53 unsigned long size;
54 spl_shrinker_t count;
794f145b
SJ
55
56 /*
57 * shrinker_size can only decrease or stay the same between callbacks
58 * in the same run, so Reset failsafe whenever shrinker increases
59 * as this indicates a new run.
60 */
61 if (last_splat_linux_shrinker_size < splat_linux_shrinker_size)
62 failsafe = 0;
63
64 last_splat_linux_shrinker_size = splat_linux_shrinker_size;
bf0c60c0
BB
65
66 if (sc->nr_to_scan) {
10946b02
AX
67 size = MIN(sc->nr_to_scan, splat_linux_shrinker_size);
68 splat_linux_shrinker_size -= size;
bf0c60c0 69
10946b02 70 splat_vprint(splat_linux_shrinker_file, SPLAT_LINUX_TEST1_NAME,
bf0c60c0 71 "Reclaimed %lu objects, size now %lu\n",
10946b02
AX
72 size, splat_linux_shrinker_size);
73
74#ifdef HAVE_SPLIT_SHRINKER_CALLBACK
75 count = size;
76#else
77 count = splat_linux_shrinker_size;
78#endif /* HAVE_SPLIT_SHRINKER_CALLBACK */
79
bf0c60c0 80 } else {
10946b02
AX
81 count = splat_linux_shrinker_size;
82 splat_vprint(splat_linux_shrinker_file, SPLAT_LINUX_TEST1_NAME,
bf0c60c0
BB
83 "Cache size is %lu\n", splat_linux_shrinker_size);
84 }
85
86 /* Far more calls than expected abort drop_slab as a failsafe */
794f145b 87 if (failsafe > 100) {
10946b02 88 splat_vprint(splat_linux_shrinker_file, SPLAT_LINUX_TEST1_NAME,
bf0c60c0
BB
89 "Far more calls than expected (%d), size now %lu\n",
90 failsafe, splat_linux_shrinker_size);
10946b02 91 return (SHRINK_STOP);
794f145b
SJ
92 } else {
93 /*
94 * We only increment failsafe if it doesn't trigger. This
95 * makes any failsafe failure persistent until the next test.
96 */
97 failsafe++;
bf0c60c0
BB
98 }
99
ca072ee7
SJ
100 /* Shrinker has run, so signal back to test. */
101 wake_up(&shrinker_wait);
102
10946b02 103 return (count);
bf0c60c0
BB
104}
105
106SPL_SHRINKER_CALLBACK_WRAPPER(splat_linux_shrinker_fn);
107
108#define DROP_SLAB_CMD \
109 "exec 0</dev/null " \
110 " 1>/proc/sys/vm/drop_caches " \
111 " 2>/dev/null; " \
112 "echo 2"
113
114static int
115splat_linux_drop_slab(struct file *file)
116{
117 char *argv[] = { "/bin/sh",
118 "-c",
119 DROP_SLAB_CMD,
120 NULL };
121 char *envp[] = { "HOME=/",
122 "TERM=linux",
123 "PATH=/sbin:/usr/sbin:/bin:/usr/bin",
124 NULL };
125 int rc;
126
8842263b 127 rc = call_usermodehelper(argv[0], argv, envp, UMH_WAIT_PROC);
bf0c60c0 128 if (rc)
10946b02 129 splat_vprint(file, SPLAT_LINUX_TEST1_NAME,
bf0c60c0
BB
130 "Failed user helper '%s %s %s', rc = %d\n",
131 argv[0], argv[1], argv[2], rc);
132
133 return rc;
134}
135
136/*
137 * Verify correct shrinker functionality by registering a shrinker
138 * with the required compatibility macros. We then use a simulated
139 * cache and force the systems caches to be dropped. The shrinker
140 * should be repeatedly called until it reports that the cache is
141 * empty. It is then cleanly unregistered and correct behavior is
142 * verified. There are now four slightly different supported shrinker
143 * API and this test ensures the compatibility code is correct.
144 */
145static int
10946b02 146splat_linux_test1(struct file *file, void *arg)
bf0c60c0
BB
147{
148 int rc = -EINVAL;
149
150 /*
151 * Globals used by the shrinker, it is not safe to run this
152 * test concurrently this is a safe assumption for SPLAT tests.
153 * Regardless we do some minimal checking a bail if concurrent
154 * use is detected.
155 */
156 if (splat_linux_shrinker_size || splat_linux_shrinker_file) {
10946b02 157 splat_vprint(file, SPLAT_LINUX_TEST1_NAME,
794f145b 158 "Failed due to concurrent shrinker test, rc = %d\n", rc);
bf0c60c0
BB
159 return (rc);
160 }
161
162 splat_linux_shrinker_size = 1024;
163 splat_linux_shrinker_file = file;
164
165 spl_register_shrinker(&splat_linux_shrinker);
166 rc = splat_linux_drop_slab(file);
167 if (rc)
168 goto out;
169
ca072ee7
SJ
170 /*
171 * By the time we get here, it is possible that the shrinker has not
172 * yet run. splat_linux_drop_slab sends a signal for it to run, but
173 * there is no guarantee of when it will actually run. We wait for it
174 * to run here, terminating when either the shrinker size is now 0 or
175 * we timeout after 1 second, which should be an eternity (error).
176 */
177 rc = wait_event_timeout(shrinker_wait, !splat_linux_shrinker_size, HZ);
178 if (!rc) {
10946b02 179 splat_vprint(file, SPLAT_LINUX_TEST1_NAME,
794f145b 180 "Failed cache shrinking timed out, size now %lu",
ca072ee7
SJ
181 splat_linux_shrinker_size);
182 rc = -ETIMEDOUT;
183 } else {
184 rc = 0;
185 }
186
187 if (!rc && splat_linux_shrinker_size != 0) {
10946b02 188 splat_vprint(file, SPLAT_LINUX_TEST1_NAME,
794f145b 189 "Failed cache was not shrunk to 0, size now %lu",
bf0c60c0
BB
190 splat_linux_shrinker_size);
191 rc = -EDOM;
192 }
193out:
194 spl_unregister_shrinker(&splat_linux_shrinker);
195
196 splat_linux_shrinker_size = 0;
197 splat_linux_shrinker_file = NULL;
198
199 return rc;
200}
201
202splat_subsystem_t *
203splat_linux_init(void)
204{
205 splat_subsystem_t *sub;
206
207 sub = kmalloc(sizeof(*sub), GFP_KERNEL);
208 if (sub == NULL)
209 return NULL;
210
211 memset(sub, 0, sizeof(*sub));
212 strncpy(sub->desc.name, SPLAT_LINUX_NAME, SPLAT_NAME_SIZE);
213 strncpy(sub->desc.desc, SPLAT_LINUX_DESC, SPLAT_DESC_SIZE);
214 INIT_LIST_HEAD(&sub->subsystem_list);
215 INIT_LIST_HEAD(&sub->test_list);
216 spin_lock_init(&sub->test_lock);
217 sub->desc.id = SPLAT_SUBSYSTEM_LINUX;
218
ec06701b 219 splat_test_init(sub, SPLAT_LINUX_TEST1_NAME, SPLAT_LINUX_TEST1_DESC,
bf0c60c0 220 SPLAT_LINUX_TEST1_ID, splat_linux_test1);
bf0c60c0
BB
221
222 return sub;
223}
224
225void
226splat_linux_fini(splat_subsystem_t *sub)
227{
228 ASSERT(sub);
ec06701b 229 splat_test_fini(sub, SPLAT_LINUX_TEST1_ID);
bf0c60c0
BB
230
231 kfree(sub);
232}
233
234int
235splat_linux_id(void) {
236 return SPLAT_SUBSYSTEM_LINUX;
237}