summaryrefslogtreecommitdiff
path: root/lib/test_vmalloc.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/test_vmalloc.c')
-rw-r--r--lib/test_vmalloc.c146
1 files changed, 109 insertions, 37 deletions
diff --git a/lib/test_vmalloc.c b/lib/test_vmalloc.c
index f90d2c27675b..6521c05c7816 100644
--- a/lib/test_vmalloc.c
+++ b/lib/test_vmalloc.c
@@ -13,9 +13,9 @@
#include <linux/moduleparam.h>
#include <linux/completion.h>
#include <linux/delay.h>
-#include <linux/rwsem.h>
#include <linux/mm.h>
#include <linux/rcupdate.h>
+#include <linux/srcu.h>
#include <linux/slab.h>
#define __param(type, name, init, msg) \
@@ -38,7 +38,10 @@ __param(int, test_loop_count, 1000000,
__param(int, nr_pages, 0,
"Set number of pages for fix_size_alloc_test(default: 1)");
-__param(int, run_test_mask, INT_MAX,
+__param(bool, use_huge, false,
+ "Use vmalloc_huge in fix_size_alloc_test");
+
+__param(int, run_test_mask, 7,
"Set tests specified in the mask.\n\n"
"\t\tid: 1, name: fix_size_alloc_test\n"
"\t\tid: 2, name: full_fit_alloc_test\n"
@@ -50,14 +53,15 @@ __param(int, run_test_mask, INT_MAX,
"\t\tid: 128, name: pcpu_alloc_test\n"
"\t\tid: 256, name: kvfree_rcu_1_arg_vmalloc_test\n"
"\t\tid: 512, name: kvfree_rcu_2_arg_vmalloc_test\n"
+ "\t\tid: 1024, name: vm_map_ram_test\n"
+ "\t\tid: 2048, name: no_block_alloc_test\n"
/* Add a new test case description here. */
);
/*
- * Read write semaphore for synchronization of setup
- * phase that is done in main thread and workers.
+ * This is for synchronization of setup phase.
*/
-static DECLARE_RWSEM(prepare_for_test_rwsem);
+DEFINE_STATIC_SRCU(prepare_for_test_srcu);
/*
* Completion tracking for worker threads.
@@ -113,7 +117,7 @@ static int align_shift_alloc_test(void)
int i;
for (i = 0; i < BITS_PER_LONG; i++) {
- align = ((unsigned long) 1) << i;
+ align = 1UL << i;
ptr = __vmalloc_node(PAGE_SIZE, align, GFP_KERNEL|__GFP_ZERO, 0,
__builtin_return_address(0));
@@ -264,7 +268,10 @@ static int fix_size_alloc_test(void)
int i;
for (i = 0; i < test_loop_count; i++) {
- ptr = vmalloc((nr_pages > 0 ? nr_pages:1) * PAGE_SIZE);
+ if (use_huge)
+ ptr = vmalloc_huge((nr_pages > 0 ? nr_pages:1) * PAGE_SIZE, GFP_KERNEL);
+ else
+ ptr = vmalloc((nr_pages > 0 ? nr_pages:1) * PAGE_SIZE);
if (!ptr)
return -1;
@@ -277,6 +284,30 @@ static int fix_size_alloc_test(void)
return 0;
}
+static int no_block_alloc_test(void)
+{
+ void *ptr;
+ int i;
+
+ for (i = 0; i < test_loop_count; i++) {
+ bool use_atomic = !!(get_random_u8() % 2);
+ gfp_t gfp = use_atomic ? GFP_ATOMIC : GFP_NOWAIT;
+ unsigned long size = (nr_pages > 0 ? nr_pages : 1) * PAGE_SIZE;
+
+ preempt_disable();
+ ptr = __vmalloc(size, gfp);
+ preempt_enable();
+
+ if (!ptr)
+ return -1;
+
+ *((__u8 *)ptr) = 0;
+ vfree(ptr);
+ }
+
+ return 0;
+}
+
static int
pcpu_alloc_test(void)
{
@@ -328,7 +359,7 @@ kvfree_rcu_1_arg_vmalloc_test(void)
return -1;
p->array[0] = 'a';
- kvfree_rcu(p);
+ kvfree_rcu_mightsleep(p);
}
return 0;
@@ -352,27 +383,66 @@ kvfree_rcu_2_arg_vmalloc_test(void)
return 0;
}
+static int
+vm_map_ram_test(void)
+{
+ unsigned long nr_allocated;
+ unsigned int map_nr_pages;
+ unsigned char *v_ptr;
+ struct page **pages;
+ int i;
+
+ map_nr_pages = nr_pages > 0 ? nr_pages:1;
+ pages = kcalloc(map_nr_pages, sizeof(struct page *), GFP_KERNEL);
+ if (!pages)
+ return -1;
+
+ nr_allocated = alloc_pages_bulk(GFP_KERNEL, map_nr_pages, pages);
+ if (nr_allocated != map_nr_pages)
+ goto cleanup;
+
+ /* Run the test loop. */
+ for (i = 0; i < test_loop_count; i++) {
+ v_ptr = vm_map_ram(pages, map_nr_pages, NUMA_NO_NODE);
+ *v_ptr = 'a';
+ vm_unmap_ram(v_ptr, map_nr_pages);
+ }
+
+cleanup:
+ for (i = 0; i < nr_allocated; i++)
+ __free_page(pages[i]);
+
+ kfree(pages);
+
+ /* 0 indicates success. */
+ return nr_allocated != map_nr_pages;
+}
+
struct test_case_desc {
const char *test_name;
int (*test_func)(void);
+ bool xfail;
};
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 },
- { "kvfree_rcu_1_arg_vmalloc_test", kvfree_rcu_1_arg_vmalloc_test },
- { "kvfree_rcu_2_arg_vmalloc_test", kvfree_rcu_2_arg_vmalloc_test },
+ { "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, true },
+ { "pcpu_alloc_test", pcpu_alloc_test, },
+ { "kvfree_rcu_1_arg_vmalloc_test", kvfree_rcu_1_arg_vmalloc_test, },
+ { "kvfree_rcu_2_arg_vmalloc_test", kvfree_rcu_2_arg_vmalloc_test, },
+ { "vm_map_ram_test", vm_map_ram_test, },
+ { "no_block_alloc_test", no_block_alloc_test, true },
/* Add a new test case here. */
};
struct test_case_data {
int test_failed;
+ int test_xfailed;
int test_passed;
u64 time;
};
@@ -402,7 +472,7 @@ static int test_func(void *private)
{
struct test_driver *t = private;
int random_array[ARRAY_SIZE(test_case_array)];
- int index, i, j;
+ int index, i, j, ret;
ktime_t kt;
u64 delta;
@@ -415,7 +485,7 @@ static int test_func(void *private)
/*
* Block until initialization is done.
*/
- down_read(&prepare_for_test_rwsem);
+ synchronize_srcu(&prepare_for_test_srcu);
t->start = get_cycles();
for (i = 0; i < ARRAY_SIZE(test_case_array); i++) {
@@ -426,11 +496,14 @@ static int test_func(void *private)
*/
if (!((run_test_mask & (1 << index)) >> index))
continue;
-
kt = ktime_get();
for (j = 0; j < test_repeat_count; j++) {
- if (!test_case_array[index].test_func())
+ ret = test_case_array[index].test_func();
+
+ if (!ret)
t->data[index].test_passed++;
+ else if (ret && test_case_array[index].xfail)
+ t->data[index].test_xfailed++;
else
t->data[index].test_failed++;
}
@@ -444,8 +517,6 @@ static int test_func(void *private)
t->data[index].time = delta;
}
t->stop = get_cycles();
-
- up_read(&prepare_for_test_rwsem);
test_report_one_done();
/*
@@ -458,7 +529,7 @@ static int test_func(void *private)
}
static int
-init_test_configurtion(void)
+init_test_configuration(void)
{
/*
* A maximum number of workers is defined as hard-coded
@@ -483,19 +554,19 @@ init_test_configurtion(void)
static void do_concurrent_test(void)
{
- int i, ret;
+ int i, ret, idx;
/*
* Set some basic configurations plus sanity check.
*/
- ret = init_test_configurtion();
+ ret = init_test_configuration();
if (ret < 0)
return;
/*
* Put on hold all workers.
*/
- down_write(&prepare_for_test_rwsem);
+ idx = srcu_read_lock(&prepare_for_test_srcu);
for (i = 0; i < nr_threads; i++) {
struct test_driver *t = &tdriver[i];
@@ -512,7 +583,7 @@ static void do_concurrent_test(void)
/*
* Now let the workers do their job.
*/
- up_write(&prepare_for_test_rwsem);
+ srcu_read_unlock(&prepare_for_test_srcu, idx);
/*
* Sleep quiet until all workers are done with 1 second
@@ -536,10 +607,11 @@ static void do_concurrent_test(void)
continue;
pr_info(
- "Summary: %s passed: %d failed: %d repeat: %d loops: %d avg: %llu usec\n",
+ "Summary: %s passed: %d failed: %d xfailed: %d repeat: %d loops: %d avg: %llu usec\n",
test_case_array[j].test_name,
t->data[j].test_passed,
t->data[j].test_failed,
+ t->data[j].test_xfailed,
test_repeat_count, test_loop_count,
t->data[j].time);
}
@@ -551,18 +623,18 @@ static void do_concurrent_test(void)
kvfree(tdriver);
}
-static int vmalloc_test_init(void)
+static int __init vmalloc_test_init(void)
{
do_concurrent_test();
- return -EAGAIN; /* Fail will directly unload the module */
-}
-
-static void vmalloc_test_exit(void)
-{
+ /* Fail will directly unload the module */
+ return IS_BUILTIN(CONFIG_TEST_VMALLOC) ? 0:-EAGAIN;
}
+#ifdef MODULE
module_init(vmalloc_test_init)
-module_exit(vmalloc_test_exit)
+#else
+late_initcall(vmalloc_test_init);
+#endif
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Uladzislau Rezki");