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://zfsonlinux.org/>.
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 \*****************************************************************************/
27 #include <linux/mm_compat.h>
28 #include "splat-internal.h"
30 #define SPLAT_LINUX_NAME "linux"
31 #define SPLAT_LINUX_DESC "Kernel Compatibility Tests"
33 #define SPLAT_LINUX_TEST1_ID 0x1001
34 #define SPLAT_LINUX_TEST1_NAME "shrinker"
35 #define SPLAT_LINUX_TEST1_DESC "Shrinker test"
38 * Wait queue used to eliminate race between dropping of slab
39 * and execution of the shrinker callback
41 DECLARE_WAIT_QUEUE_HEAD(shrinker_wait
);
43 SPL_SHRINKER_CALLBACK_FWD_DECLARE(splat_linux_shrinker_fn
);
44 SPL_SHRINKER_DECLARE(splat_linux_shrinker
, splat_linux_shrinker_fn
, 1);
45 static unsigned long splat_linux_shrinker_size
= 0;
46 static struct file
*splat_linux_shrinker_file
= NULL
;
49 __splat_linux_shrinker_fn(struct shrinker
*shrink
, struct shrink_control
*sc
)
51 static int failsafe
= 0;
52 static unsigned long last_splat_linux_shrinker_size
= 0;
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.
61 if (last_splat_linux_shrinker_size
< splat_linux_shrinker_size
)
64 last_splat_linux_shrinker_size
= splat_linux_shrinker_size
;
67 size
= MIN(sc
->nr_to_scan
, splat_linux_shrinker_size
);
68 splat_linux_shrinker_size
-= size
;
70 splat_vprint(splat_linux_shrinker_file
, SPLAT_LINUX_TEST1_NAME
,
71 "Reclaimed %lu objects, size now %lu\n",
72 size
, splat_linux_shrinker_size
);
74 #ifdef HAVE_SPLIT_SHRINKER_CALLBACK
77 count
= splat_linux_shrinker_size
;
78 #endif /* HAVE_SPLIT_SHRINKER_CALLBACK */
81 count
= splat_linux_shrinker_size
;
82 splat_vprint(splat_linux_shrinker_file
, SPLAT_LINUX_TEST1_NAME
,
83 "Cache size is %lu\n", splat_linux_shrinker_size
);
86 /* Far more calls than expected abort drop_slab as a failsafe */
88 splat_vprint(splat_linux_shrinker_file
, SPLAT_LINUX_TEST1_NAME
,
89 "Far more calls than expected (%d), size now %lu\n",
90 failsafe
, splat_linux_shrinker_size
);
94 * We only increment failsafe if it doesn't trigger. This
95 * makes any failsafe failure persistent until the next test.
100 /* Shrinker has run, so signal back to test. */
101 wake_up(&shrinker_wait
);
106 SPL_SHRINKER_CALLBACK_WRAPPER(splat_linux_shrinker_fn
);
108 #define DROP_SLAB_CMD \
109 "exec 0</dev/null " \
110 " 1>/proc/sys/vm/drop_caches " \
115 splat_linux_drop_slab(struct file
*file
)
117 char *argv
[] = { "/bin/sh",
121 char *envp
[] = { "HOME=/",
123 "PATH=/sbin:/usr/sbin:/bin:/usr/bin",
127 rc
= call_usermodehelper(argv
[0], argv
, envp
, UMH_WAIT_PROC
);
129 splat_vprint(file
, SPLAT_LINUX_TEST1_NAME
,
130 "Failed user helper '%s %s %s', rc = %d\n",
131 argv
[0], argv
[1], argv
[2], rc
);
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.
146 splat_linux_test1(struct file
*file
, void *arg
)
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
156 if (splat_linux_shrinker_size
|| splat_linux_shrinker_file
) {
157 splat_vprint(file
, SPLAT_LINUX_TEST1_NAME
,
158 "Failed due to concurrent shrinker test, rc = %d\n", rc
);
162 splat_linux_shrinker_size
= 1024;
163 splat_linux_shrinker_file
= file
;
165 spl_register_shrinker(&splat_linux_shrinker
);
166 rc
= splat_linux_drop_slab(file
);
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).
177 rc
= wait_event_timeout(shrinker_wait
, !splat_linux_shrinker_size
, HZ
);
179 splat_vprint(file
, SPLAT_LINUX_TEST1_NAME
,
180 "Failed cache shrinking timed out, size now %lu",
181 splat_linux_shrinker_size
);
187 if (!rc
&& splat_linux_shrinker_size
!= 0) {
188 splat_vprint(file
, SPLAT_LINUX_TEST1_NAME
,
189 "Failed cache was not shrunk to 0, size now %lu",
190 splat_linux_shrinker_size
);
194 spl_unregister_shrinker(&splat_linux_shrinker
);
196 splat_linux_shrinker_size
= 0;
197 splat_linux_shrinker_file
= NULL
;
203 splat_linux_init(void)
205 splat_subsystem_t
*sub
;
207 sub
= kmalloc(sizeof(*sub
), GFP_KERNEL
);
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
;
219 splat_test_init(sub
, SPLAT_LINUX_TEST1_NAME
, SPLAT_LINUX_TEST1_DESC
,
220 SPLAT_LINUX_TEST1_ID
, splat_linux_test1
);
226 splat_linux_fini(splat_subsystem_t
*sub
)
229 splat_test_fini(sub
, SPLAT_LINUX_TEST1_ID
);
235 splat_linux_id(void) {
236 return SPLAT_SUBSYSTEM_LINUX
;