]> git.proxmox.com Git - mirror_spl-debian.git/blame - module/splat/splat-linux.c
Add linux compatibility tests
[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.
8 * For details, see <http://github.com/behlendorf/spl/>.
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 "splat-internal.h"
27
28#define SPLAT_LINUX_NAME "linux"
29#define SPLAT_LINUX_DESC "Kernel Compatibility Tests"
30
31#define SPLAT_LINUX_TEST1_ID 0x1001
32#define SPLAT_LINUX_TEST1_NAME "shrink_dcache"
33#define SPLAT_LINUX_TEST1_DESC "Shrink dcache test"
34
35#define SPLAT_LINUX_TEST2_ID 0x1002
36#define SPLAT_LINUX_TEST2_NAME "shrink_icache"
37#define SPLAT_LINUX_TEST2_DESC "Shrink icache test"
38
39#define SPLAT_LINUX_TEST3_ID 0x1003
40#define SPLAT_LINUX_TEST3_NAME "shrinker"
41#define SPLAT_LINUX_TEST3_DESC "Shrinker test"
42
43
44/*
45 * Attempt to shrink the dcache memory. This is simply a functional
46 * to ensure we can correctly call the shrinker. We don't check that
47 * the cache actually decreased because we have no control over what
48 * else may be running on the system. This avoid false positives.
49 */
50static int
51splat_linux_test1(struct file *file, void *arg)
52{
53 int remain_before;
54 int remain_after;
55
56 remain_before = shrink_dcache_memory(0, GFP_KERNEL);
57 remain_after = shrink_dcache_memory(KMC_REAP_CHUNK, GFP_KERNEL);
58
59 splat_vprint(file, SPLAT_LINUX_TEST1_NAME,
60 "Shrink dcache memory, remain %d -> %d\n",
61 remain_before, remain_after);
62
63 return 0;
64}
65
66/*
67 * Attempt to shrink the icache memory. This is simply a functional
68 * to ensure we can correctly call the shrinker. We don't check that
69 * the cache actually decreased because we have no control over what
70 * else may be running on the system. This avoid false positives.
71 */
72static int
73splat_linux_test2(struct file *file, void *arg)
74{
75 int remain_before;
76 int remain_after;
77
78 remain_before = shrink_icache_memory(0, GFP_KERNEL);
79 remain_after = shrink_icache_memory(KMC_REAP_CHUNK, GFP_KERNEL);
80
81 splat_vprint(file, SPLAT_LINUX_TEST2_NAME,
82 "Shrink icache memory, remain %d -> %d\n",
83 remain_before, remain_after);
84
85 return 0;
86}
87
88SPL_SHRINKER_CALLBACK_FWD_DECLARE(splat_linux_shrinker_fn);
89SPL_SHRINKER_DECLARE(splat_linux_shrinker, splat_linux_shrinker_fn, 1);
90static unsigned long splat_linux_shrinker_size = 0;
91static struct file *splat_linux_shrinker_file = NULL;
92
93static int
94__splat_linux_shrinker_fn(struct shrinker *shrink, struct shrink_control *sc)
95{
96 static int failsafe = 0;
97
98 if (sc->nr_to_scan) {
99 splat_linux_shrinker_size = splat_linux_shrinker_size -
100 MIN(sc->nr_to_scan, splat_linux_shrinker_size);
101
102 splat_vprint(splat_linux_shrinker_file, SPLAT_LINUX_TEST3_NAME,
103 "Reclaimed %lu objects, size now %lu\n",
104 sc->nr_to_scan, splat_linux_shrinker_size);
105 } else {
106 splat_vprint(splat_linux_shrinker_file, SPLAT_LINUX_TEST3_NAME,
107 "Cache size is %lu\n", splat_linux_shrinker_size);
108 }
109
110 /* Far more calls than expected abort drop_slab as a failsafe */
111 if ((++failsafe % 1000) == 0) {
112 splat_vprint(splat_linux_shrinker_file, SPLAT_LINUX_TEST3_NAME,
113 "Far more calls than expected (%d), size now %lu\n",
114 failsafe, splat_linux_shrinker_size);
115 return -1;
116 }
117
118 return (int)splat_linux_shrinker_size;
119}
120
121SPL_SHRINKER_CALLBACK_WRAPPER(splat_linux_shrinker_fn);
122
123#define DROP_SLAB_CMD \
124 "exec 0</dev/null " \
125 " 1>/proc/sys/vm/drop_caches " \
126 " 2>/dev/null; " \
127 "echo 2"
128
129static int
130splat_linux_drop_slab(struct file *file)
131{
132 char *argv[] = { "/bin/sh",
133 "-c",
134 DROP_SLAB_CMD,
135 NULL };
136 char *envp[] = { "HOME=/",
137 "TERM=linux",
138 "PATH=/sbin:/usr/sbin:/bin:/usr/bin",
139 NULL };
140 int rc;
141
142 rc = call_usermodehelper(argv[0], argv, envp, 1);
143 if (rc)
144 splat_vprint(file, SPLAT_LINUX_TEST3_NAME,
145 "Failed user helper '%s %s %s', rc = %d\n",
146 argv[0], argv[1], argv[2], rc);
147
148 return rc;
149}
150
151/*
152 * Verify correct shrinker functionality by registering a shrinker
153 * with the required compatibility macros. We then use a simulated
154 * cache and force the systems caches to be dropped. The shrinker
155 * should be repeatedly called until it reports that the cache is
156 * empty. It is then cleanly unregistered and correct behavior is
157 * verified. There are now four slightly different supported shrinker
158 * API and this test ensures the compatibility code is correct.
159 */
160static int
161splat_linux_test3(struct file *file, void *arg)
162{
163 int rc = -EINVAL;
164
165 /*
166 * Globals used by the shrinker, it is not safe to run this
167 * test concurrently this is a safe assumption for SPLAT tests.
168 * Regardless we do some minimal checking a bail if concurrent
169 * use is detected.
170 */
171 if (splat_linux_shrinker_size || splat_linux_shrinker_file) {
172 splat_vprint(file, SPLAT_LINUX_TEST3_NAME,
173 "Failed due to concurrent shrinker test, rc = %d\n", rc);
174 return (rc);
175 }
176
177 splat_linux_shrinker_size = 1024;
178 splat_linux_shrinker_file = file;
179
180 spl_register_shrinker(&splat_linux_shrinker);
181 rc = splat_linux_drop_slab(file);
182 if (rc)
183 goto out;
184
185 if (splat_linux_shrinker_size != 0) {
186 splat_vprint(file, SPLAT_LINUX_TEST3_NAME,
187 "Failed cache was not shrunk to 0, size now %lu",
188 splat_linux_shrinker_size);
189 rc = -EDOM;
190 }
191out:
192 spl_unregister_shrinker(&splat_linux_shrinker);
193
194 splat_linux_shrinker_size = 0;
195 splat_linux_shrinker_file = NULL;
196
197 return rc;
198}
199
200splat_subsystem_t *
201splat_linux_init(void)
202{
203 splat_subsystem_t *sub;
204
205 sub = kmalloc(sizeof(*sub), GFP_KERNEL);
206 if (sub == NULL)
207 return NULL;
208
209 memset(sub, 0, sizeof(*sub));
210 strncpy(sub->desc.name, SPLAT_LINUX_NAME, SPLAT_NAME_SIZE);
211 strncpy(sub->desc.desc, SPLAT_LINUX_DESC, SPLAT_DESC_SIZE);
212 INIT_LIST_HEAD(&sub->subsystem_list);
213 INIT_LIST_HEAD(&sub->test_list);
214 spin_lock_init(&sub->test_lock);
215 sub->desc.id = SPLAT_SUBSYSTEM_LINUX;
216
217 SPLAT_TEST_INIT(sub, SPLAT_LINUX_TEST1_NAME, SPLAT_LINUX_TEST1_DESC,
218 SPLAT_LINUX_TEST1_ID, splat_linux_test1);
219 SPLAT_TEST_INIT(sub, SPLAT_LINUX_TEST2_NAME, SPLAT_LINUX_TEST2_DESC,
220 SPLAT_LINUX_TEST2_ID, splat_linux_test2);
221 SPLAT_TEST_INIT(sub, SPLAT_LINUX_TEST3_NAME, SPLAT_LINUX_TEST3_DESC,
222 SPLAT_LINUX_TEST3_ID, splat_linux_test3);
223
224 return sub;
225}
226
227void
228splat_linux_fini(splat_subsystem_t *sub)
229{
230 ASSERT(sub);
231 SPLAT_TEST_FINI(sub, SPLAT_LINUX_TEST3_ID);
232 SPLAT_TEST_FINI(sub, SPLAT_LINUX_TEST2_ID);
233 SPLAT_TEST_FINI(sub, SPLAT_LINUX_TEST1_ID);
234
235 kfree(sub);
236}
237
238int
239splat_linux_id(void) {
240 return SPLAT_SUBSYSTEM_LINUX;
241}