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>.
7 * This file is part of the SPL, Solaris Porting Layer.
8 * For details, see <http://github.com/behlendorf/spl/>.
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.
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
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 \*****************************************************************************/
26 #include "splat-internal.h"
28 #define SPLAT_LINUX_NAME "linux"
29 #define SPLAT_LINUX_DESC "Kernel Compatibility Tests"
31 #define SPLAT_LINUX_TEST1_ID 0x1001
32 #define SPLAT_LINUX_TEST1_NAME "shrink_dcache"
33 #define SPLAT_LINUX_TEST1_DESC "Shrink dcache test"
35 #define SPLAT_LINUX_TEST2_ID 0x1002
36 #define SPLAT_LINUX_TEST2_NAME "shrink_icache"
37 #define SPLAT_LINUX_TEST2_DESC "Shrink icache test"
39 #define SPLAT_LINUX_TEST3_ID 0x1003
40 #define SPLAT_LINUX_TEST3_NAME "shrinker"
41 #define SPLAT_LINUX_TEST3_DESC "Shrinker test"
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.
51 splat_linux_test1(struct file
*file
, void *arg
)
56 remain_before
= shrink_dcache_memory(0, GFP_KERNEL
);
57 remain_after
= shrink_dcache_memory(KMC_REAP_CHUNK
, GFP_KERNEL
);
59 splat_vprint(file
, SPLAT_LINUX_TEST1_NAME
,
60 "Shrink dcache memory, remain %d -> %d\n",
61 remain_before
, remain_after
);
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.
73 splat_linux_test2(struct file
*file
, void *arg
)
78 remain_before
= shrink_icache_memory(0, GFP_KERNEL
);
79 remain_after
= shrink_icache_memory(KMC_REAP_CHUNK
, GFP_KERNEL
);
81 splat_vprint(file
, SPLAT_LINUX_TEST2_NAME
,
82 "Shrink icache memory, remain %d -> %d\n",
83 remain_before
, remain_after
);
88 SPL_SHRINKER_CALLBACK_FWD_DECLARE(splat_linux_shrinker_fn
);
89 SPL_SHRINKER_DECLARE(splat_linux_shrinker
, splat_linux_shrinker_fn
, 1);
90 static unsigned long splat_linux_shrinker_size
= 0;
91 static struct file
*splat_linux_shrinker_file
= NULL
;
94 __splat_linux_shrinker_fn(struct shrinker
*shrink
, struct shrink_control
*sc
)
96 static int failsafe
= 0;
99 splat_linux_shrinker_size
= splat_linux_shrinker_size
-
100 MIN(sc
->nr_to_scan
, splat_linux_shrinker_size
);
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
);
106 splat_vprint(splat_linux_shrinker_file
, SPLAT_LINUX_TEST3_NAME
,
107 "Cache size is %lu\n", splat_linux_shrinker_size
);
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
);
118 return (int)splat_linux_shrinker_size
;
121 SPL_SHRINKER_CALLBACK_WRAPPER(splat_linux_shrinker_fn
);
123 #define DROP_SLAB_CMD \
124 "exec 0</dev/null " \
125 " 1>/proc/sys/vm/drop_caches " \
130 splat_linux_drop_slab(struct file
*file
)
132 char *argv
[] = { "/bin/sh",
136 char *envp
[] = { "HOME=/",
138 "PATH=/sbin:/usr/sbin:/bin:/usr/bin",
142 rc
= call_usermodehelper(argv
[0], argv
, envp
, 1);
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
);
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.
161 splat_linux_test3(struct file
*file
, void *arg
)
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
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
);
177 splat_linux_shrinker_size
= 1024;
178 splat_linux_shrinker_file
= file
;
180 spl_register_shrinker(&splat_linux_shrinker
);
181 rc
= splat_linux_drop_slab(file
);
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
);
192 spl_unregister_shrinker(&splat_linux_shrinker
);
194 splat_linux_shrinker_size
= 0;
195 splat_linux_shrinker_file
= NULL
;
201 splat_linux_init(void)
203 splat_subsystem_t
*sub
;
205 sub
= kmalloc(sizeof(*sub
), GFP_KERNEL
);
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
;
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
);
228 splat_linux_fini(splat_subsystem_t
*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
);
239 splat_linux_id(void) {
240 return SPLAT_SUBSYSTEM_LINUX
;