Blame view

lib/test_vmalloc.c 10.9 KB
3f21a6b7e   Uladzislau Rezki (Sony)   vmalloc: add test...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
  // SPDX-License-Identifier: GPL-2.0
  
  /*
   * Test module for stress and analyze performance of vmalloc allocator.
   * (C) 2018 Uladzislau Rezki (Sony) <urezki@gmail.com>
   */
  #include <linux/init.h>
  #include <linux/kernel.h>
  #include <linux/module.h>
  #include <linux/vmalloc.h>
  #include <linux/random.h>
  #include <linux/kthread.h>
  #include <linux/moduleparam.h>
  #include <linux/completion.h>
  #include <linux/delay.h>
  #include <linux/rwsem.h>
  #include <linux/mm.h>
da4fc00ab   Uladzislau Rezki (Sony)   lib/test_vmalloc....
18
19
  #include <linux/rcupdate.h>
  #include <linux/slab.h>
3f21a6b7e   Uladzislau Rezki (Sony)   vmalloc: add test...
20
21
22
23
24
  
  #define __param(type, name, init, msg)		\
  	static type name = init;				\
  	module_param(name, type, 0444);			\
  	MODULE_PARM_DESC(name, msg)				\
80f475996   Uladzislau Rezki (Sony)   lib/test_vmalloc....
25
26
  __param(int, nr_threads, 0,
  	"Number of workers to perform tests(min: 1 max: USHRT_MAX)");
3f21a6b7e   Uladzislau Rezki (Sony)   vmalloc: add test...
27
28
29
30
31
32
33
34
35
  
  __param(bool, sequential_test_order, false,
  	"Use sequential stress tests order");
  
  __param(int, test_repeat_count, 1,
  	"Set test repeat counter");
  
  __param(int, test_loop_count, 1000000,
  	"Set test loop counter");
f8bcbecfb   Uladzislau Rezki (Sony)   lib/test_vmalloc....
36
37
  __param(int, nr_pages, 0,
  	"Set number of pages for fix_size_alloc_test(default: 1)");
3f21a6b7e   Uladzislau Rezki (Sony)   vmalloc: add test...
38
39
40
41
  __param(int, run_test_mask, INT_MAX,
  	"Set tests specified in the mask.
  
  "
da4fc00ab   Uladzislau Rezki (Sony)   lib/test_vmalloc....
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
  		"\t\tid: 1,    name: fix_size_alloc_test
  "
  		"\t\tid: 2,    name: full_fit_alloc_test
  "
  		"\t\tid: 4,    name: long_busy_list_alloc_test
  "
  		"\t\tid: 8,    name: random_size_alloc_test
  "
  		"\t\tid: 16,   name: fix_align_alloc_test
  "
  		"\t\tid: 32,   name: random_size_align_alloc_test
  "
  		"\t\tid: 64,   name: align_shift_alloc_test
  "
  		"\t\tid: 128,  name: pcpu_alloc_test
  "
  		"\t\tid: 256,  name: kvfree_rcu_1_arg_vmalloc_test
  "
  		"\t\tid: 512,  name: kvfree_rcu_2_arg_vmalloc_test
  "
3f21a6b7e   Uladzislau Rezki (Sony)   vmalloc: add test...
62
63
64
65
  		/* Add a new test case description here. */
  );
  
  /*
3f21a6b7e   Uladzislau Rezki (Sony)   vmalloc: add test...
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
   * Read write semaphore for synchronization of setup
   * phase that is done in main thread and workers.
   */
  static DECLARE_RWSEM(prepare_for_test_rwsem);
  
  /*
   * Completion tracking for worker threads.
   */
  static DECLARE_COMPLETION(test_all_done_comp);
  static atomic_t test_n_undone = ATOMIC_INIT(0);
  
  static inline void
  test_report_one_done(void)
  {
  	if (atomic_dec_and_test(&test_n_undone))
  		complete(&test_all_done_comp);
  }
  
  static int random_size_align_alloc_test(void)
  {
  	unsigned long size, align, rnd;
  	void *ptr;
  	int i;
  
  	for (i = 0; i < test_loop_count; i++) {
  		get_random_bytes(&rnd, sizeof(rnd));
  
  		/*
  		 * Maximum 1024 pages, if PAGE_SIZE is 4096.
  		 */
  		align = 1 << (rnd % 23);
  
  		/*
  		 * Maximum 10 pages.
  		 */
  		size = ((rnd % 10) + 1) * PAGE_SIZE;
c3f896dcf   Christoph Hellwig   mm: switch the te...
102
103
  		ptr = __vmalloc_node(size, align, GFP_KERNEL | __GFP_ZERO, 0,
  				__builtin_return_address(0));
3f21a6b7e   Uladzislau Rezki (Sony)   vmalloc: add test...
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
  		if (!ptr)
  			return -1;
  
  		vfree(ptr);
  	}
  
  	return 0;
  }
  
  /*
   * This test case is supposed to be failed.
   */
  static int align_shift_alloc_test(void)
  {
  	unsigned long align;
  	void *ptr;
  	int i;
  
  	for (i = 0; i < BITS_PER_LONG; i++) {
  		align = ((unsigned long) 1) << i;
c3f896dcf   Christoph Hellwig   mm: switch the te...
124
125
  		ptr = __vmalloc_node(PAGE_SIZE, align, GFP_KERNEL|__GFP_ZERO, 0,
  				__builtin_return_address(0));
3f21a6b7e   Uladzislau Rezki (Sony)   vmalloc: add test...
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
  		if (!ptr)
  			return -1;
  
  		vfree(ptr);
  	}
  
  	return 0;
  }
  
  static int fix_align_alloc_test(void)
  {
  	void *ptr;
  	int i;
  
  	for (i = 0; i < test_loop_count; i++) {
c3f896dcf   Christoph Hellwig   mm: switch the te...
141
142
143
  		ptr = __vmalloc_node(5 * PAGE_SIZE, THREAD_ALIGN << 1,
  				GFP_KERNEL | __GFP_ZERO, 0,
  				__builtin_return_address(0));
3f21a6b7e   Uladzislau Rezki (Sony)   vmalloc: add test...
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
  		if (!ptr)
  			return -1;
  
  		vfree(ptr);
  	}
  
  	return 0;
  }
  
  static int random_size_alloc_test(void)
  {
  	unsigned int n;
  	void *p;
  	int i;
  
  	for (i = 0; i < test_loop_count; i++) {
  		get_random_bytes(&n, sizeof(i));
  		n = (n % 100) + 1;
  
  		p = vmalloc(n * PAGE_SIZE);
  
  		if (!p)
  			return -1;
  
  		*((__u8 *)p) = 1;
  		vfree(p);
  	}
  
  	return 0;
  }
  
  static int long_busy_list_alloc_test(void)
  {
  	void *ptr_1, *ptr_2;
  	void **ptr;
  	int rv = -1;
  	int i;
  
  	ptr = vmalloc(sizeof(void *) * 15000);
  	if (!ptr)
  		return rv;
  
  	for (i = 0; i < 15000; i++)
  		ptr[i] = vmalloc(1 * PAGE_SIZE);
  
  	for (i = 0; i < test_loop_count; i++) {
  		ptr_1 = vmalloc(100 * PAGE_SIZE);
  		if (!ptr_1)
  			goto leave;
  
  		ptr_2 = vmalloc(1 * PAGE_SIZE);
  		if (!ptr_2) {
  			vfree(ptr_1);
  			goto leave;
  		}
  
  		*((__u8 *)ptr_1) = 0;
  		*((__u8 *)ptr_2) = 1;
  
  		vfree(ptr_1);
  		vfree(ptr_2);
  	}
  
  	/*  Success */
  	rv = 0;
  
  leave:
  	for (i = 0; i < 15000; i++)
  		vfree(ptr[i]);
  
  	vfree(ptr);
  	return rv;
  }
  
  static int full_fit_alloc_test(void)
  {
  	void **ptr, **junk_ptr, *tmp;
  	int junk_length;
  	int rv = -1;
  	int i;
  
  	junk_length = fls(num_online_cpus());
  	junk_length *= (32 * 1024 * 1024 / PAGE_SIZE);
  
  	ptr = vmalloc(sizeof(void *) * junk_length);
  	if (!ptr)
  		return rv;
  
  	junk_ptr = vmalloc(sizeof(void *) * junk_length);
  	if (!junk_ptr) {
  		vfree(ptr);
  		return rv;
  	}
  
  	for (i = 0; i < junk_length; i++) {
  		ptr[i] = vmalloc(1 * PAGE_SIZE);
  		junk_ptr[i] = vmalloc(1 * PAGE_SIZE);
  	}
  
  	for (i = 0; i < junk_length; i++)
  		vfree(junk_ptr[i]);
  
  	for (i = 0; i < test_loop_count; i++) {
  		tmp = vmalloc(1 * PAGE_SIZE);
  
  		if (!tmp)
  			goto error;
  
  		*((__u8 *)tmp) = 1;
  		vfree(tmp);
  	}
  
  	/* Success */
  	rv = 0;
  
  error:
  	for (i = 0; i < junk_length; i++)
  		vfree(ptr[i]);
  
  	vfree(ptr);
  	vfree(junk_ptr);
  
  	return rv;
  }
  
  static int fix_size_alloc_test(void)
  {
  	void *ptr;
  	int i;
  
  	for (i = 0; i < test_loop_count; i++) {
f8bcbecfb   Uladzislau Rezki (Sony)   lib/test_vmalloc....
275
  		ptr = vmalloc((nr_pages > 0 ? nr_pages:1) * PAGE_SIZE);
3f21a6b7e   Uladzislau Rezki (Sony)   vmalloc: add test...
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
  
  		if (!ptr)
  			return -1;
  
  		*((__u8 *)ptr) = 0;
  
  		vfree(ptr);
  	}
  
  	return 0;
  }
  
  static int
  pcpu_alloc_test(void)
  {
  	int rv = 0;
  #ifndef CONFIG_NEED_PER_CPU_KM
  	void __percpu **pcpu;
  	size_t size, align;
  	int i;
  
  	pcpu = vmalloc(sizeof(void __percpu *) * 35000);
  	if (!pcpu)
  		return -1;
  
  	for (i = 0; i < 35000; i++) {
  		unsigned int r;
  
  		get_random_bytes(&r, sizeof(i));
  		size = (r % (PAGE_SIZE / 4)) + 1;
  
  		/*
  		 * Maximum PAGE_SIZE
  		 */
  		get_random_bytes(&r, sizeof(i));
  		align = 1 << ((i % 11) + 1);
  
  		pcpu[i] = __alloc_percpu(size, align);
  		if (!pcpu[i])
  			rv = -1;
  	}
  
  	for (i = 0; i < 35000; i++)
  		free_percpu(pcpu[i]);
  
  	vfree(pcpu);
  #endif
  	return rv;
  }
da4fc00ab   Uladzislau Rezki (Sony)   lib/test_vmalloc....
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
  struct test_kvfree_rcu {
  	struct rcu_head rcu;
  	unsigned char array[20];
  };
  
  static int
  kvfree_rcu_1_arg_vmalloc_test(void)
  {
  	struct test_kvfree_rcu *p;
  	int i;
  
  	for (i = 0; i < test_loop_count; i++) {
  		p = vmalloc(1 * PAGE_SIZE);
  		if (!p)
  			return -1;
  
  		p->array[0] = 'a';
  		kvfree_rcu(p);
  	}
  
  	return 0;
  }
  
  static int
  kvfree_rcu_2_arg_vmalloc_test(void)
  {
  	struct test_kvfree_rcu *p;
  	int i;
  
  	for (i = 0; i < test_loop_count; i++) {
  		p = vmalloc(1 * PAGE_SIZE);
  		if (!p)
  			return -1;
  
  		p->array[0] = 'a';
  		kvfree_rcu(p, rcu);
  	}
  
  	return 0;
  }
3f21a6b7e   Uladzislau Rezki (Sony)   vmalloc: add test...
365
366
367
368
369
370
371
372
373
374
375
376
377
378
  struct test_case_desc {
  	const char *test_name;
  	int (*test_func)(void);
  };
  
  static struct test_case_desc test_case_array[] = {
  	{ "fix_size_alloc_test", fix_size_alloc_test },
  	{ "full_fit_alloc_test", full_fit_alloc_test },
  	{ "long_busy_list_alloc_test", long_busy_list_alloc_test },
  	{ "random_size_alloc_test", random_size_alloc_test },
  	{ "fix_align_alloc_test", fix_align_alloc_test },
  	{ "random_size_align_alloc_test", random_size_align_alloc_test },
  	{ "align_shift_alloc_test", align_shift_alloc_test },
  	{ "pcpu_alloc_test", pcpu_alloc_test },
da4fc00ab   Uladzislau Rezki (Sony)   lib/test_vmalloc....
379
380
  	{ "kvfree_rcu_1_arg_vmalloc_test", kvfree_rcu_1_arg_vmalloc_test },
  	{ "kvfree_rcu_2_arg_vmalloc_test", kvfree_rcu_2_arg_vmalloc_test },
3f21a6b7e   Uladzislau Rezki (Sony)   vmalloc: add test...
381
382
383
384
385
386
387
388
  	/* Add a new test case here. */
  };
  
  struct test_case_data {
  	int test_failed;
  	int test_passed;
  	u64 time;
  };
3f21a6b7e   Uladzislau Rezki (Sony)   vmalloc: add test...
389
390
  static struct test_driver {
  	struct task_struct *task;
80f475996   Uladzislau Rezki (Sony)   lib/test_vmalloc....
391
  	struct test_case_data data[ARRAY_SIZE(test_case_array)];
3f21a6b7e   Uladzislau Rezki (Sony)   vmalloc: add test...
392
393
  	unsigned long start;
  	unsigned long stop;
80f475996   Uladzislau Rezki (Sony)   lib/test_vmalloc....
394
  } *tdriver;
3f21a6b7e   Uladzislau Rezki (Sony)   vmalloc: add test...
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
  
  static void shuffle_array(int *arr, int n)
  {
  	unsigned int rnd;
  	int i, j, x;
  
  	for (i = n - 1; i > 0; i--)  {
  		get_random_bytes(&rnd, sizeof(rnd));
  
  		/* Cut the range. */
  		j = rnd % i;
  
  		/* Swap indexes. */
  		x = arr[i];
  		arr[i] = arr[j];
  		arr[j] = x;
  	}
  }
  
  static int test_func(void *private)
  {
  	struct test_driver *t = private;
3f21a6b7e   Uladzislau Rezki (Sony)   vmalloc: add test...
417
  	int random_array[ARRAY_SIZE(test_case_array)];
7507c4025   Andrew Morton   lib/test_vmalloc....
418
  	int index, i, j;
3f21a6b7e   Uladzislau Rezki (Sony)   vmalloc: add test...
419
420
  	ktime_t kt;
  	u64 delta;
3f21a6b7e   Uladzislau Rezki (Sony)   vmalloc: add test...
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
  	for (i = 0; i < ARRAY_SIZE(test_case_array); i++)
  		random_array[i] = i;
  
  	if (!sequential_test_order)
  		shuffle_array(random_array, ARRAY_SIZE(test_case_array));
  
  	/*
  	 * Block until initialization is done.
  	 */
  	down_read(&prepare_for_test_rwsem);
  
  	t->start = get_cycles();
  	for (i = 0; i < ARRAY_SIZE(test_case_array); i++) {
  		index = random_array[i];
  
  		/*
  		 * Skip tests if run_test_mask has been specified.
  		 */
  		if (!((run_test_mask & (1 << index)) >> index))
  			continue;
  
  		kt = ktime_get();
  		for (j = 0; j < test_repeat_count; j++) {
7507c4025   Andrew Morton   lib/test_vmalloc....
444
  			if (!test_case_array[index].test_func())
80f475996   Uladzislau Rezki (Sony)   lib/test_vmalloc....
445
  				t->data[index].test_passed++;
3f21a6b7e   Uladzislau Rezki (Sony)   vmalloc: add test...
446
  			else
80f475996   Uladzislau Rezki (Sony)   lib/test_vmalloc....
447
  				t->data[index].test_failed++;
3f21a6b7e   Uladzislau Rezki (Sony)   vmalloc: add test...
448
449
450
451
452
453
454
  		}
  
  		/*
  		 * Take an average time that test took.
  		 */
  		delta = (u64) ktime_us_delta(ktime_get(), kt);
  		do_div(delta, (u32) test_repeat_count);
80f475996   Uladzislau Rezki (Sony)   lib/test_vmalloc....
455
  		t->data[index].time = delta;
3f21a6b7e   Uladzislau Rezki (Sony)   vmalloc: add test...
456
457
458
459
460
461
462
463
464
465
466
467
468
469
  	}
  	t->stop = get_cycles();
  
  	up_read(&prepare_for_test_rwsem);
  	test_report_one_done();
  
  	/*
  	 * Wait for the kthread_stop() call.
  	 */
  	while (!kthread_should_stop())
  		msleep(10);
  
  	return 0;
  }
80f475996   Uladzislau Rezki (Sony)   lib/test_vmalloc....
470
  static int
3f21a6b7e   Uladzislau Rezki (Sony)   vmalloc: add test...
471
472
473
  init_test_configurtion(void)
  {
  	/*
80f475996   Uladzislau Rezki (Sony)   lib/test_vmalloc....
474
475
476
  	 * A maximum number of workers is defined as hard-coded
  	 * value and set to USHRT_MAX. We add such gap just in
  	 * case and for potential heavy stressing.
3f21a6b7e   Uladzislau Rezki (Sony)   vmalloc: add test...
477
  	 */
80f475996   Uladzislau Rezki (Sony)   lib/test_vmalloc....
478
  	nr_threads = clamp(nr_threads, 1, (int) USHRT_MAX);
3f21a6b7e   Uladzislau Rezki (Sony)   vmalloc: add test...
479

80f475996   Uladzislau Rezki (Sony)   lib/test_vmalloc....
480
481
482
483
  	/* Allocate the space for test instances. */
  	tdriver = kvcalloc(nr_threads, sizeof(*tdriver), GFP_KERNEL);
  	if (tdriver == NULL)
  		return -1;
3f21a6b7e   Uladzislau Rezki (Sony)   vmalloc: add test...
484
485
486
487
488
489
  
  	if (test_repeat_count <= 0)
  		test_repeat_count = 1;
  
  	if (test_loop_count <= 0)
  		test_loop_count = 1;
80f475996   Uladzislau Rezki (Sony)   lib/test_vmalloc....
490
491
  
  	return 0;
3f21a6b7e   Uladzislau Rezki (Sony)   vmalloc: add test...
492
493
494
495
  }
  
  static void do_concurrent_test(void)
  {
80f475996   Uladzislau Rezki (Sony)   lib/test_vmalloc....
496
  	int i, ret;
3f21a6b7e   Uladzislau Rezki (Sony)   vmalloc: add test...
497
498
499
500
  
  	/*
  	 * Set some basic configurations plus sanity check.
  	 */
80f475996   Uladzislau Rezki (Sony)   lib/test_vmalloc....
501
502
503
  	ret = init_test_configurtion();
  	if (ret < 0)
  		return;
3f21a6b7e   Uladzislau Rezki (Sony)   vmalloc: add test...
504
505
506
507
508
  
  	/*
  	 * Put on hold all workers.
  	 */
  	down_write(&prepare_for_test_rwsem);
80f475996   Uladzislau Rezki (Sony)   lib/test_vmalloc....
509
510
  	for (i = 0; i < nr_threads; i++) {
  		struct test_driver *t = &tdriver[i];
3f21a6b7e   Uladzislau Rezki (Sony)   vmalloc: add test...
511

80f475996   Uladzislau Rezki (Sony)   lib/test_vmalloc....
512
  		t->task = kthread_run(test_func, t, "vmalloc_test/%d", i);
3f21a6b7e   Uladzislau Rezki (Sony)   vmalloc: add test...
513
514
515
516
517
  
  		if (!IS_ERR(t->task))
  			/* Success. */
  			atomic_inc(&test_n_undone);
  		else
80f475996   Uladzislau Rezki (Sony)   lib/test_vmalloc....
518
519
  			pr_err("Failed to start %d kthread
  ", i);
3f21a6b7e   Uladzislau Rezki (Sony)   vmalloc: add test...
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
  	}
  
  	/*
  	 * Now let the workers do their job.
  	 */
  	up_write(&prepare_for_test_rwsem);
  
  	/*
  	 * Sleep quiet until all workers are done with 1 second
  	 * interval. Since the test can take a lot of time we
  	 * can run into a stack trace of the hung task. That is
  	 * why we go with completion_timeout and HZ value.
  	 */
  	do {
  		ret = wait_for_completion_timeout(&test_all_done_comp, HZ);
  	} while (!ret);
80f475996   Uladzislau Rezki (Sony)   lib/test_vmalloc....
536
537
538
  	for (i = 0; i < nr_threads; i++) {
  		struct test_driver *t = &tdriver[i];
  		int j;
3f21a6b7e   Uladzislau Rezki (Sony)   vmalloc: add test...
539
540
541
  
  		if (!IS_ERR(t->task))
  			kthread_stop(t->task);
80f475996   Uladzislau Rezki (Sony)   lib/test_vmalloc....
542
543
  		for (j = 0; j < ARRAY_SIZE(test_case_array); j++) {
  			if (!((run_test_mask & (1 << j)) >> j))
3f21a6b7e   Uladzislau Rezki (Sony)   vmalloc: add test...
544
545
546
547
548
  				continue;
  
  			pr_info(
  				"Summary: %s passed: %d failed: %d repeat: %d loops: %d avg: %llu usec
  ",
80f475996   Uladzislau Rezki (Sony)   lib/test_vmalloc....
549
550
551
  				test_case_array[j].test_name,
  				t->data[j].test_passed,
  				t->data[j].test_failed,
3f21a6b7e   Uladzislau Rezki (Sony)   vmalloc: add test...
552
  				test_repeat_count, test_loop_count,
80f475996   Uladzislau Rezki (Sony)   lib/test_vmalloc....
553
  				t->data[j].time);
3f21a6b7e   Uladzislau Rezki (Sony)   vmalloc: add test...
554
  		}
80f475996   Uladzislau Rezki (Sony)   lib/test_vmalloc....
555
556
557
  		pr_info("All test took worker%d=%lu cycles
  ",
  			i, t->stop - t->start);
3f21a6b7e   Uladzislau Rezki (Sony)   vmalloc: add test...
558
  	}
80f475996   Uladzislau Rezki (Sony)   lib/test_vmalloc....
559
560
  
  	kvfree(tdriver);
3f21a6b7e   Uladzislau Rezki (Sony)   vmalloc: add test...
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
  }
  
  static int vmalloc_test_init(void)
  {
  	do_concurrent_test();
  	return -EAGAIN; /* Fail will directly unload the module */
  }
  
  static void vmalloc_test_exit(void)
  {
  }
  
  module_init(vmalloc_test_init)
  module_exit(vmalloc_test_exit)
  
  MODULE_LICENSE("GPL");
  MODULE_AUTHOR("Uladzislau Rezki");
  MODULE_DESCRIPTION("vmalloc test module");