]> git.proxmox.com Git - mirror_spl-debian.git/blame - modules/splat/splat-kmem.c
Go through and add a header with the proper UCRL number.
[mirror_spl-debian.git] / modules / splat / splat-kmem.c
CommitLineData
715f6251 1/*
2 * This file is part of the SPL: Solaris Porting Layer.
3 *
4 * Copyright (c) 2008 Lawrence Livermore National Security, LLC.
5 * Produced at Lawrence Livermore National Laboratory
6 * Written by:
7 * Brian Behlendorf <behlendorf1@llnl.gov>,
8 * Herb Wartens <wartens2@llnl.gov>,
9 * Jim Garlick <garlick@llnl.gov>
10 * UCRL-CODE-235197
11 *
12 * This is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This is distributed in the hope that it will be useful, but WITHOUT
18 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
20 * for more details.
21 *
22 * You should have received a copy of the GNU General Public License along
23 * with this program; if not, write to the Free Software Foundation, Inc.,
24 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25 */
26
7c50328b 27#include "splat-internal.h"
f1ca4da6 28
7c50328b 29#define SPLAT_SUBSYSTEM_KMEM 0x0100
30#define SPLAT_KMEM_NAME "kmem"
31#define SPLAT_KMEM_DESC "Kernel Malloc/Slab Tests"
f1ca4da6 32
7c50328b 33#define SPLAT_KMEM_TEST1_ID 0x0101
34#define SPLAT_KMEM_TEST1_NAME "kmem_alloc"
35#define SPLAT_KMEM_TEST1_DESC "Memory allocation test (kmem_alloc)"
f1ca4da6 36
7c50328b 37#define SPLAT_KMEM_TEST2_ID 0x0102
38#define SPLAT_KMEM_TEST2_NAME "kmem_zalloc"
39#define SPLAT_KMEM_TEST2_DESC "Memory allocation test (kmem_zalloc)"
f1ca4da6 40
7c50328b 41#define SPLAT_KMEM_TEST3_ID 0x0103
42#define SPLAT_KMEM_TEST3_NAME "slab_alloc"
43#define SPLAT_KMEM_TEST3_DESC "Slab constructor/destructor test"
f1ca4da6 44
7c50328b 45#define SPLAT_KMEM_TEST4_ID 0x0104
46#define SPLAT_KMEM_TEST4_NAME "slab_reap"
47#define SPLAT_KMEM_TEST4_DESC "Slab reaping test"
f1ca4da6 48
79b31f36 49#define SPLAT_KMEM_TEST5_ID 0x0105
50#define SPLAT_KMEM_TEST5_NAME "vmem_alloc"
51#define SPLAT_KMEM_TEST5_DESC "Memory allocation test (vmem_alloc)"
52
7c50328b 53#define SPLAT_KMEM_ALLOC_COUNT 10
79b31f36 54#define SPLAT_VMEM_ALLOC_COUNT 10
55
f1ca4da6 56/* XXX - This test may fail under tight memory conditions */
57static int
7c50328b 58splat_kmem_test1(struct file *file, void *arg)
f1ca4da6 59{
7c50328b 60 void *ptr[SPLAT_KMEM_ALLOC_COUNT];
f1ca4da6 61 int size = PAGE_SIZE;
62 int i, count, rc = 0;
63
c19c06f3 64 /* We are intentionally going to push kmem_alloc to its max
65 * allocation size, so suppress the console warnings for now */
66 kmem_set_warning(0);
67
79b31f36 68 while ((!rc) && (size <= (PAGE_SIZE * 32))) {
f1ca4da6 69 count = 0;
70
7c50328b 71 for (i = 0; i < SPLAT_KMEM_ALLOC_COUNT; i++) {
f1ca4da6 72 ptr[i] = kmem_alloc(size, KM_SLEEP);
73 if (ptr[i])
74 count++;
75 }
76
7c50328b 77 for (i = 0; i < SPLAT_KMEM_ALLOC_COUNT; i++)
f1ca4da6 78 if (ptr[i])
79 kmem_free(ptr[i], size);
80
7c50328b 81 splat_vprint(file, SPLAT_KMEM_TEST1_NAME,
f1ca4da6 82 "%d byte allocations, %d/%d successful\n",
7c50328b 83 size, count, SPLAT_KMEM_ALLOC_COUNT);
84 if (count != SPLAT_KMEM_ALLOC_COUNT)
f1ca4da6 85 rc = -ENOMEM;
86
87 size *= 2;
88 }
89
c19c06f3 90 kmem_set_warning(1);
91
f1ca4da6 92 return rc;
93}
94
95static int
7c50328b 96splat_kmem_test2(struct file *file, void *arg)
f1ca4da6 97{
7c50328b 98 void *ptr[SPLAT_KMEM_ALLOC_COUNT];
f1ca4da6 99 int size = PAGE_SIZE;
100 int i, j, count, rc = 0;
101
c19c06f3 102 /* We are intentionally going to push kmem_alloc to its max
103 * allocation size, so suppress the console warnings for now */
104 kmem_set_warning(0);
105
79b31f36 106 while ((!rc) && (size <= (PAGE_SIZE * 32))) {
f1ca4da6 107 count = 0;
108
7c50328b 109 for (i = 0; i < SPLAT_KMEM_ALLOC_COUNT; i++) {
f1ca4da6 110 ptr[i] = kmem_zalloc(size, KM_SLEEP);
111 if (ptr[i])
112 count++;
113 }
114
115 /* Ensure buffer has been zero filled */
7c50328b 116 for (i = 0; i < SPLAT_KMEM_ALLOC_COUNT; i++) {
f1ca4da6 117 for (j = 0; j < size; j++) {
118 if (((char *)ptr[i])[j] != '\0') {
7c50328b 119 splat_vprint(file, SPLAT_KMEM_TEST2_NAME,
f1ca4da6 120 "%d-byte allocation was "
121 "not zeroed\n", size);
122 rc = -EFAULT;
123 }
124 }
125 }
126
7c50328b 127 for (i = 0; i < SPLAT_KMEM_ALLOC_COUNT; i++)
f1ca4da6 128 if (ptr[i])
129 kmem_free(ptr[i], size);
130
7c50328b 131 splat_vprint(file, SPLAT_KMEM_TEST2_NAME,
f1ca4da6 132 "%d byte allocations, %d/%d successful\n",
7c50328b 133 size, count, SPLAT_KMEM_ALLOC_COUNT);
134 if (count != SPLAT_KMEM_ALLOC_COUNT)
f1ca4da6 135 rc = -ENOMEM;
136
137 size *= 2;
138 }
139
c19c06f3 140 kmem_set_warning(1);
141
f1ca4da6 142 return rc;
143}
144
7c50328b 145#define SPLAT_KMEM_TEST_MAGIC 0x004488CCUL
146#define SPLAT_KMEM_CACHE_NAME "kmem_test"
147#define SPLAT_KMEM_CACHE_SIZE 256
148#define SPLAT_KMEM_OBJ_COUNT 128
149#define SPLAT_KMEM_OBJ_RECLAIM 64
f1ca4da6 150
151typedef struct kmem_cache_data {
7c50328b 152 char kcd_buf[SPLAT_KMEM_CACHE_SIZE];
f1ca4da6 153 unsigned long kcd_magic;
154 int kcd_flag;
155} kmem_cache_data_t;
156
157typedef struct kmem_cache_priv {
158 unsigned long kcp_magic;
159 struct file *kcp_file;
160 kmem_cache_t *kcp_cache;
7c50328b 161 kmem_cache_data_t *kcp_kcd[SPLAT_KMEM_OBJ_COUNT];
f1ca4da6 162 int kcp_count;
163 int kcp_rc;
164} kmem_cache_priv_t;
165
166static int
7c50328b 167splat_kmem_test34_constructor(void *ptr, void *priv, int flags)
f1ca4da6 168{
169 kmem_cache_data_t *kcd = (kmem_cache_data_t *)ptr;
170 kmem_cache_priv_t *kcp = (kmem_cache_priv_t *)priv;
171
172 if (kcd) {
7c50328b 173 memset(kcd->kcd_buf, 0xaa, SPLAT_KMEM_CACHE_SIZE);
f1ca4da6 174 kcd->kcd_flag = 1;
175
176 if (kcp) {
d6a26c6a 177 kcd->kcd_magic = kcp->kcp_magic;
f1ca4da6 178 kcp->kcp_count++;
179 }
180 }
181
182 return 0;
183}
184
185static void
7c50328b 186splat_kmem_test34_destructor(void *ptr, void *priv)
f1ca4da6 187{
188 kmem_cache_data_t *kcd = (kmem_cache_data_t *)ptr;
189 kmem_cache_priv_t *kcp = (kmem_cache_priv_t *)priv;
190
191 if (kcd) {
7c50328b 192 memset(kcd->kcd_buf, 0xbb, SPLAT_KMEM_CACHE_SIZE);
f1ca4da6 193 kcd->kcd_flag = 0;
194
195 if (kcp)
196 kcp->kcp_count--;
197 }
198
199 return;
200}
201
202static int
7c50328b 203splat_kmem_test3(struct file *file, void *arg)
f1ca4da6 204{
205 kmem_cache_t *cache = NULL;
206 kmem_cache_data_t *kcd = NULL;
207 kmem_cache_priv_t kcp;
208 int rc = 0, max;
209
7c50328b 210 kcp.kcp_magic = SPLAT_KMEM_TEST_MAGIC;
f1ca4da6 211 kcp.kcp_file = file;
212 kcp.kcp_count = 0;
213 kcp.kcp_rc = 0;
214
7c50328b 215 cache = kmem_cache_create(SPLAT_KMEM_CACHE_NAME, sizeof(*kcd), 0,
216 splat_kmem_test34_constructor,
217 splat_kmem_test34_destructor,
f1ca4da6 218 NULL, &kcp, NULL, 0);
219 if (!cache) {
7c50328b 220 splat_vprint(file, SPLAT_KMEM_TEST3_NAME,
221 "Unable to create '%s'\n", SPLAT_KMEM_CACHE_NAME);
f1ca4da6 222 return -ENOMEM;
223 }
224
225 kcd = kmem_cache_alloc(cache, 0);
226 if (!kcd) {
7c50328b 227 splat_vprint(file, SPLAT_KMEM_TEST3_NAME,
f1ca4da6 228 "Unable to allocate from '%s'\n",
7c50328b 229 SPLAT_KMEM_CACHE_NAME);
f1ca4da6 230 rc = -EINVAL;
231 goto out_free;
232 }
233
234 if (!kcd->kcd_flag) {
7c50328b 235 splat_vprint(file, SPLAT_KMEM_TEST3_NAME,
f1ca4da6 236 "Failed to run contructor for '%s'\n",
7c50328b 237 SPLAT_KMEM_CACHE_NAME);
f1ca4da6 238 rc = -EINVAL;
239 goto out_free;
240 }
241
242 if (kcd->kcd_magic != kcp.kcp_magic) {
7c50328b 243 splat_vprint(file, SPLAT_KMEM_TEST3_NAME,
f1ca4da6 244 "Failed to pass private data to constructor "
7c50328b 245 "for '%s'\n", SPLAT_KMEM_CACHE_NAME);
f1ca4da6 246 rc = -EINVAL;
247 goto out_free;
248 }
249
250 max = kcp.kcp_count;
251
252 /* Destructor's run lazily so it hard to check correctness here.
253 * We assume if it doesn't crash the free worked properly */
254 kmem_cache_free(cache, kcd);
255
256 /* Destroy the entire cache which will force destructors to
257 * run and we can verify one was called for every object */
258 kmem_cache_destroy(cache);
259 if (kcp.kcp_count) {
7c50328b 260 splat_vprint(file, SPLAT_KMEM_TEST3_NAME,
f1ca4da6 261 "Failed to run destructor on all slab objects "
7c50328b 262 "for '%s'\n", SPLAT_KMEM_CACHE_NAME);
f1ca4da6 263 rc = -EINVAL;
264 }
265
7c50328b 266 splat_vprint(file, SPLAT_KMEM_TEST3_NAME,
f1ca4da6 267 "%d allocated/destroyed objects for '%s'\n",
7c50328b 268 max, SPLAT_KMEM_CACHE_NAME);
f1ca4da6 269
270 return rc;
271
272out_free:
273 if (kcd)
274 kmem_cache_free(cache, kcd);
f1b59d26 275
f1ca4da6 276 kmem_cache_destroy(cache);
277 return rc;
278}
279
280static void
7c50328b 281splat_kmem_test4_reclaim(void *priv)
f1ca4da6 282{
283 kmem_cache_priv_t *kcp = (kmem_cache_priv_t *)priv;
284 int i;
285
7c50328b 286 splat_vprint(kcp->kcp_file, SPLAT_KMEM_TEST4_NAME,
d6a26c6a 287 "Reaping %d objects from '%s'\n",
288 SPLAT_KMEM_OBJ_RECLAIM, SPLAT_KMEM_CACHE_NAME);
7c50328b 289 for (i = 0; i < SPLAT_KMEM_OBJ_RECLAIM; i++) {
f1ca4da6 290 if (kcp->kcp_kcd[i]) {
291 kmem_cache_free(kcp->kcp_cache, kcp->kcp_kcd[i]);
292 kcp->kcp_kcd[i] = NULL;
293 }
294 }
295
296 return;
297}
298
299static int
7c50328b 300splat_kmem_test4(struct file *file, void *arg)
f1ca4da6 301{
302 kmem_cache_t *cache;
303 kmem_cache_priv_t kcp;
304 int i, rc = 0, max, reclaim_percent, target_percent;
305
7c50328b 306 kcp.kcp_magic = SPLAT_KMEM_TEST_MAGIC;
f1ca4da6 307 kcp.kcp_file = file;
308 kcp.kcp_count = 0;
309 kcp.kcp_rc = 0;
310
7c50328b 311 cache = kmem_cache_create(SPLAT_KMEM_CACHE_NAME,
f1ca4da6 312 sizeof(kmem_cache_data_t), 0,
7c50328b 313 splat_kmem_test34_constructor,
314 splat_kmem_test34_destructor,
315 splat_kmem_test4_reclaim, &kcp, NULL, 0);
f1ca4da6 316 if (!cache) {
7c50328b 317 splat_vprint(file, SPLAT_KMEM_TEST4_NAME,
318 "Unable to create '%s'\n", SPLAT_KMEM_CACHE_NAME);
f1ca4da6 319 return -ENOMEM;
320 }
321
322 kcp.kcp_cache = cache;
323
7c50328b 324 for (i = 0; i < SPLAT_KMEM_OBJ_COUNT; i++) {
f1b59d26 325 /* All allocations need not succeed */
f1ca4da6 326 kcp.kcp_kcd[i] = kmem_cache_alloc(cache, 0);
327 if (!kcp.kcp_kcd[i]) {
7c50328b 328 splat_vprint(file, SPLAT_KMEM_TEST4_NAME,
f1ca4da6 329 "Unable to allocate from '%s'\n",
7c50328b 330 SPLAT_KMEM_CACHE_NAME);
f1ca4da6 331 }
332 }
333
334 max = kcp.kcp_count;
d6a26c6a 335 ASSERT(max > 0);
f1ca4da6 336
337 /* Force shrinker to run */
338 kmem_reap();
339
340 /* Reclaim reclaimed objects, this ensure the destructors are run */
341 kmem_cache_reap_now(cache);
342
343 reclaim_percent = ((kcp.kcp_count * 100) / max);
7c50328b 344 target_percent = (((SPLAT_KMEM_OBJ_COUNT - SPLAT_KMEM_OBJ_RECLAIM) * 100) /
345 SPLAT_KMEM_OBJ_COUNT);
346 splat_vprint(file, SPLAT_KMEM_TEST4_NAME,
f1ca4da6 347 "%d%% (%d/%d) of previous size, target of "
348 "%d%%-%d%% for '%s'\n", reclaim_percent, kcp.kcp_count,
349 max, target_percent - 10, target_percent + 10,
7c50328b 350 SPLAT_KMEM_CACHE_NAME);
f1ca4da6 351 if ((reclaim_percent < target_percent - 10) ||
352 (reclaim_percent > target_percent + 10))
353 rc = -EINVAL;
354
355 /* Cleanup our mess */
7c50328b 356 for (i = 0; i < SPLAT_KMEM_OBJ_COUNT; i++)
f1ca4da6 357 if (kcp.kcp_kcd[i])
358 kmem_cache_free(cache, kcp.kcp_kcd[i]);
359
360 kmem_cache_destroy(cache);
361
362 return rc;
363}
364
79b31f36 365static int
366splat_kmem_test5(struct file *file, void *arg)
367{
368 void *ptr[SPLAT_VMEM_ALLOC_COUNT];
369 int size = PAGE_SIZE;
370 int i, count, rc = 0;
371
372 while ((!rc) && (size <= (PAGE_SIZE * 1024))) {
373 count = 0;
374
375 for (i = 0; i < SPLAT_VMEM_ALLOC_COUNT; i++) {
376 ptr[i] = vmem_alloc(size, KM_SLEEP);
377 if (ptr[i])
378 count++;
379 }
380
381 for (i = 0; i < SPLAT_VMEM_ALLOC_COUNT; i++)
382 if (ptr[i])
383 vmem_free(ptr[i], size);
384
385 splat_vprint(file, SPLAT_KMEM_TEST5_NAME,
386 "%d byte allocations, %d/%d successful\n",
387 size, count, SPLAT_VMEM_ALLOC_COUNT);
388 if (count != SPLAT_VMEM_ALLOC_COUNT)
389 rc = -ENOMEM;
390
391 size *= 2;
392 }
393
394 return rc;
395}
396
7c50328b 397splat_subsystem_t *
398splat_kmem_init(void)
f1ca4da6 399{
7c50328b 400 splat_subsystem_t *sub;
f1ca4da6 401
402 sub = kmalloc(sizeof(*sub), GFP_KERNEL);
403 if (sub == NULL)
404 return NULL;
405
406 memset(sub, 0, sizeof(*sub));
7c50328b 407 strncpy(sub->desc.name, SPLAT_KMEM_NAME, SPLAT_NAME_SIZE);
408 strncpy(sub->desc.desc, SPLAT_KMEM_DESC, SPLAT_DESC_SIZE);
f1ca4da6 409 INIT_LIST_HEAD(&sub->subsystem_list);
410 INIT_LIST_HEAD(&sub->test_list);
411 spin_lock_init(&sub->test_lock);
7c50328b 412 sub->desc.id = SPLAT_SUBSYSTEM_KMEM;
f1ca4da6 413
7c50328b 414 SPLAT_TEST_INIT(sub, SPLAT_KMEM_TEST1_NAME, SPLAT_KMEM_TEST1_DESC,
415 SPLAT_KMEM_TEST1_ID, splat_kmem_test1);
416 SPLAT_TEST_INIT(sub, SPLAT_KMEM_TEST2_NAME, SPLAT_KMEM_TEST2_DESC,
417 SPLAT_KMEM_TEST2_ID, splat_kmem_test2);
418 SPLAT_TEST_INIT(sub, SPLAT_KMEM_TEST3_NAME, SPLAT_KMEM_TEST3_DESC,
419 SPLAT_KMEM_TEST3_ID, splat_kmem_test3);
420 SPLAT_TEST_INIT(sub, SPLAT_KMEM_TEST4_NAME, SPLAT_KMEM_TEST4_DESC,
421 SPLAT_KMEM_TEST4_ID, splat_kmem_test4);
79b31f36 422 SPLAT_TEST_INIT(sub, SPLAT_KMEM_TEST5_NAME, SPLAT_KMEM_TEST5_DESC,
423 SPLAT_KMEM_TEST5_ID, splat_kmem_test5);
f1ca4da6 424
425 return sub;
426}
427
428void
7c50328b 429splat_kmem_fini(splat_subsystem_t *sub)
f1ca4da6 430{
431 ASSERT(sub);
79b31f36 432 SPLAT_TEST_FINI(sub, SPLAT_KMEM_TEST5_ID);
7c50328b 433 SPLAT_TEST_FINI(sub, SPLAT_KMEM_TEST4_ID);
434 SPLAT_TEST_FINI(sub, SPLAT_KMEM_TEST3_ID);
435 SPLAT_TEST_FINI(sub, SPLAT_KMEM_TEST2_ID);
436 SPLAT_TEST_FINI(sub, SPLAT_KMEM_TEST1_ID);
f1ca4da6 437
438 kfree(sub);
439}
440
441int
7c50328b 442splat_kmem_id(void) {
443 return SPLAT_SUBSYSTEM_KMEM;
f1ca4da6 444}