15015a300SAlexander Potapenko // SPDX-License-Identifier: GPL-2.0 25015a300SAlexander Potapenko /* 35015a300SAlexander Potapenko * Test cases for SL[AOU]B/page initialization at alloc/free time. 45015a300SAlexander Potapenko */ 55015a300SAlexander Potapenko #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 65015a300SAlexander Potapenko 75015a300SAlexander Potapenko #include <linux/init.h> 85015a300SAlexander Potapenko #include <linux/kernel.h> 95015a300SAlexander Potapenko #include <linux/mm.h> 105015a300SAlexander Potapenko #include <linux/module.h> 115015a300SAlexander Potapenko #include <linux/slab.h> 125015a300SAlexander Potapenko #include <linux/string.h> 135015a300SAlexander Potapenko #include <linux/vmalloc.h> 145015a300SAlexander Potapenko 155015a300SAlexander Potapenko #define GARBAGE_INT (0x09A7BA9E) 165015a300SAlexander Potapenko #define GARBAGE_BYTE (0x9E) 175015a300SAlexander Potapenko 185015a300SAlexander Potapenko #define REPORT_FAILURES_IN_FN() \ 195015a300SAlexander Potapenko do { \ 205015a300SAlexander Potapenko if (failures) \ 215015a300SAlexander Potapenko pr_info("%s failed %d out of %d times\n", \ 225015a300SAlexander Potapenko __func__, failures, num_tests); \ 235015a300SAlexander Potapenko else \ 245015a300SAlexander Potapenko pr_info("all %d tests in %s passed\n", \ 255015a300SAlexander Potapenko num_tests, __func__); \ 265015a300SAlexander Potapenko } while (0) 275015a300SAlexander Potapenko 285015a300SAlexander Potapenko /* Calculate the number of uninitialized bytes in the buffer. */ 295015a300SAlexander Potapenko static int __init count_nonzero_bytes(void *ptr, size_t size) 305015a300SAlexander Potapenko { 315015a300SAlexander Potapenko int i, ret = 0; 325015a300SAlexander Potapenko unsigned char *p = (unsigned char *)ptr; 335015a300SAlexander Potapenko 345015a300SAlexander Potapenko for (i = 0; i < size; i++) 355015a300SAlexander Potapenko if (p[i]) 365015a300SAlexander Potapenko ret++; 375015a300SAlexander Potapenko return ret; 385015a300SAlexander Potapenko } 395015a300SAlexander Potapenko 405015a300SAlexander Potapenko /* Fill a buffer with garbage, skipping |skip| first bytes. */ 414ab7ace4SAlexander Potapenko static void __init fill_with_garbage_skip(void *ptr, int size, size_t skip) 425015a300SAlexander Potapenko { 434ab7ace4SAlexander Potapenko unsigned int *p = (unsigned int *)((char *)ptr + skip); 445015a300SAlexander Potapenko int i = 0; 455015a300SAlexander Potapenko 465015a300SAlexander Potapenko WARN_ON(skip > size); 474ab7ace4SAlexander Potapenko size -= skip; 484ab7ace4SAlexander Potapenko 495015a300SAlexander Potapenko while (size >= sizeof(*p)) { 505015a300SAlexander Potapenko p[i] = GARBAGE_INT; 515015a300SAlexander Potapenko i++; 525015a300SAlexander Potapenko size -= sizeof(*p); 535015a300SAlexander Potapenko } 545015a300SAlexander Potapenko if (size) 555015a300SAlexander Potapenko memset(&p[i], GARBAGE_BYTE, size); 565015a300SAlexander Potapenko } 575015a300SAlexander Potapenko 585015a300SAlexander Potapenko static void __init fill_with_garbage(void *ptr, size_t size) 595015a300SAlexander Potapenko { 605015a300SAlexander Potapenko fill_with_garbage_skip(ptr, size, 0); 615015a300SAlexander Potapenko } 625015a300SAlexander Potapenko 635015a300SAlexander Potapenko static int __init do_alloc_pages_order(int order, int *total_failures) 645015a300SAlexander Potapenko { 655015a300SAlexander Potapenko struct page *page; 665015a300SAlexander Potapenko void *buf; 675015a300SAlexander Potapenko size_t size = PAGE_SIZE << order; 685015a300SAlexander Potapenko 695015a300SAlexander Potapenko page = alloc_pages(GFP_KERNEL, order); 705015a300SAlexander Potapenko buf = page_address(page); 715015a300SAlexander Potapenko fill_with_garbage(buf, size); 725015a300SAlexander Potapenko __free_pages(page, order); 735015a300SAlexander Potapenko 745015a300SAlexander Potapenko page = alloc_pages(GFP_KERNEL, order); 755015a300SAlexander Potapenko buf = page_address(page); 765015a300SAlexander Potapenko if (count_nonzero_bytes(buf, size)) 775015a300SAlexander Potapenko (*total_failures)++; 785015a300SAlexander Potapenko fill_with_garbage(buf, size); 795015a300SAlexander Potapenko __free_pages(page, order); 805015a300SAlexander Potapenko return 1; 815015a300SAlexander Potapenko } 825015a300SAlexander Potapenko 835015a300SAlexander Potapenko /* Test the page allocator by calling alloc_pages with different orders. */ 845015a300SAlexander Potapenko static int __init test_pages(int *total_failures) 855015a300SAlexander Potapenko { 865015a300SAlexander Potapenko int failures = 0, num_tests = 0; 875015a300SAlexander Potapenko int i; 885015a300SAlexander Potapenko 895015a300SAlexander Potapenko for (i = 0; i < 10; i++) 905015a300SAlexander Potapenko num_tests += do_alloc_pages_order(i, &failures); 915015a300SAlexander Potapenko 925015a300SAlexander Potapenko REPORT_FAILURES_IN_FN(); 935015a300SAlexander Potapenko *total_failures += failures; 945015a300SAlexander Potapenko return num_tests; 955015a300SAlexander Potapenko } 965015a300SAlexander Potapenko 975015a300SAlexander Potapenko /* Test kmalloc() with given parameters. */ 985015a300SAlexander Potapenko static int __init do_kmalloc_size(size_t size, int *total_failures) 995015a300SAlexander Potapenko { 1005015a300SAlexander Potapenko void *buf; 1015015a300SAlexander Potapenko 1025015a300SAlexander Potapenko buf = kmalloc(size, GFP_KERNEL); 1035015a300SAlexander Potapenko fill_with_garbage(buf, size); 1045015a300SAlexander Potapenko kfree(buf); 1055015a300SAlexander Potapenko 1065015a300SAlexander Potapenko buf = kmalloc(size, GFP_KERNEL); 1075015a300SAlexander Potapenko if (count_nonzero_bytes(buf, size)) 1085015a300SAlexander Potapenko (*total_failures)++; 1095015a300SAlexander Potapenko fill_with_garbage(buf, size); 1105015a300SAlexander Potapenko kfree(buf); 1115015a300SAlexander Potapenko return 1; 1125015a300SAlexander Potapenko } 1135015a300SAlexander Potapenko 1145015a300SAlexander Potapenko /* Test vmalloc() with given parameters. */ 1155015a300SAlexander Potapenko static int __init do_vmalloc_size(size_t size, int *total_failures) 1165015a300SAlexander Potapenko { 1175015a300SAlexander Potapenko void *buf; 1185015a300SAlexander Potapenko 1195015a300SAlexander Potapenko buf = vmalloc(size); 1205015a300SAlexander Potapenko fill_with_garbage(buf, size); 1215015a300SAlexander Potapenko vfree(buf); 1225015a300SAlexander Potapenko 1235015a300SAlexander Potapenko buf = vmalloc(size); 1245015a300SAlexander Potapenko if (count_nonzero_bytes(buf, size)) 1255015a300SAlexander Potapenko (*total_failures)++; 1265015a300SAlexander Potapenko fill_with_garbage(buf, size); 1275015a300SAlexander Potapenko vfree(buf); 1285015a300SAlexander Potapenko return 1; 1295015a300SAlexander Potapenko } 1305015a300SAlexander Potapenko 1315015a300SAlexander Potapenko /* Test kmalloc()/vmalloc() by allocating objects of different sizes. */ 1325015a300SAlexander Potapenko static int __init test_kvmalloc(int *total_failures) 1335015a300SAlexander Potapenko { 1345015a300SAlexander Potapenko int failures = 0, num_tests = 0; 1355015a300SAlexander Potapenko int i, size; 1365015a300SAlexander Potapenko 1375015a300SAlexander Potapenko for (i = 0; i < 20; i++) { 1385015a300SAlexander Potapenko size = 1 << i; 1395015a300SAlexander Potapenko num_tests += do_kmalloc_size(size, &failures); 1405015a300SAlexander Potapenko num_tests += do_vmalloc_size(size, &failures); 1415015a300SAlexander Potapenko } 1425015a300SAlexander Potapenko 1435015a300SAlexander Potapenko REPORT_FAILURES_IN_FN(); 1445015a300SAlexander Potapenko *total_failures += failures; 1455015a300SAlexander Potapenko return num_tests; 1465015a300SAlexander Potapenko } 1475015a300SAlexander Potapenko 1485015a300SAlexander Potapenko #define CTOR_BYTES (sizeof(unsigned int)) 1495015a300SAlexander Potapenko #define CTOR_PATTERN (0x41414141) 1505015a300SAlexander Potapenko /* Initialize the first 4 bytes of the object. */ 1515015a300SAlexander Potapenko static void test_ctor(void *obj) 1525015a300SAlexander Potapenko { 1535015a300SAlexander Potapenko *(unsigned int *)obj = CTOR_PATTERN; 1545015a300SAlexander Potapenko } 1555015a300SAlexander Potapenko 1565015a300SAlexander Potapenko /* 1575015a300SAlexander Potapenko * Check the invariants for the buffer allocated from a slab cache. 1585015a300SAlexander Potapenko * If the cache has a test constructor, the first 4 bytes of the object must 1595015a300SAlexander Potapenko * always remain equal to CTOR_PATTERN. 1605015a300SAlexander Potapenko * If the cache isn't an RCU-typesafe one, or if the allocation is done with 1615015a300SAlexander Potapenko * __GFP_ZERO, then the object contents must be zeroed after allocation. 1625015a300SAlexander Potapenko * If the cache is an RCU-typesafe one, the object contents must never be 1635015a300SAlexander Potapenko * zeroed after the first use. This is checked by memcmp() in 1645015a300SAlexander Potapenko * do_kmem_cache_size(). 1655015a300SAlexander Potapenko */ 1665015a300SAlexander Potapenko static bool __init check_buf(void *buf, int size, bool want_ctor, 1675015a300SAlexander Potapenko bool want_rcu, bool want_zero) 1685015a300SAlexander Potapenko { 1695015a300SAlexander Potapenko int bytes; 1705015a300SAlexander Potapenko bool fail = false; 1715015a300SAlexander Potapenko 1725015a300SAlexander Potapenko bytes = count_nonzero_bytes(buf, size); 1735015a300SAlexander Potapenko WARN_ON(want_ctor && want_zero); 1745015a300SAlexander Potapenko if (want_zero) 1755015a300SAlexander Potapenko return bytes; 1765015a300SAlexander Potapenko if (want_ctor) { 1775015a300SAlexander Potapenko if (*(unsigned int *)buf != CTOR_PATTERN) 1785015a300SAlexander Potapenko fail = 1; 1795015a300SAlexander Potapenko } else { 1805015a300SAlexander Potapenko if (bytes) 1815015a300SAlexander Potapenko fail = !want_rcu; 1825015a300SAlexander Potapenko } 1835015a300SAlexander Potapenko return fail; 1845015a300SAlexander Potapenko } 1855015a300SAlexander Potapenko 1865015a300SAlexander Potapenko /* 1875015a300SAlexander Potapenko * Test kmem_cache with given parameters: 1885015a300SAlexander Potapenko * want_ctor - use a constructor; 1895015a300SAlexander Potapenko * want_rcu - use SLAB_TYPESAFE_BY_RCU; 1905015a300SAlexander Potapenko * want_zero - use __GFP_ZERO. 1915015a300SAlexander Potapenko */ 1925015a300SAlexander Potapenko static int __init do_kmem_cache_size(size_t size, bool want_ctor, 1935015a300SAlexander Potapenko bool want_rcu, bool want_zero, 1945015a300SAlexander Potapenko int *total_failures) 1955015a300SAlexander Potapenko { 1965015a300SAlexander Potapenko struct kmem_cache *c; 1975015a300SAlexander Potapenko int iter; 1985015a300SAlexander Potapenko bool fail = false; 1995015a300SAlexander Potapenko gfp_t alloc_mask = GFP_KERNEL | (want_zero ? __GFP_ZERO : 0); 2005015a300SAlexander Potapenko void *buf, *buf_copy; 2015015a300SAlexander Potapenko 2025015a300SAlexander Potapenko c = kmem_cache_create("test_cache", size, 1, 2035015a300SAlexander Potapenko want_rcu ? SLAB_TYPESAFE_BY_RCU : 0, 2045015a300SAlexander Potapenko want_ctor ? test_ctor : NULL); 2055015a300SAlexander Potapenko for (iter = 0; iter < 10; iter++) { 2065015a300SAlexander Potapenko buf = kmem_cache_alloc(c, alloc_mask); 2075015a300SAlexander Potapenko /* Check that buf is zeroed, if it must be. */ 2085015a300SAlexander Potapenko fail = check_buf(buf, size, want_ctor, want_rcu, want_zero); 2095015a300SAlexander Potapenko fill_with_garbage_skip(buf, size, want_ctor ? CTOR_BYTES : 0); 210d3a81161SArnd Bergmann 211d3a81161SArnd Bergmann if (!want_rcu) { 212d3a81161SArnd Bergmann kmem_cache_free(c, buf); 213d3a81161SArnd Bergmann continue; 214d3a81161SArnd Bergmann } 215d3a81161SArnd Bergmann 2165015a300SAlexander Potapenko /* 2175015a300SAlexander Potapenko * If this is an RCU cache, use a critical section to ensure we 2185015a300SAlexander Potapenko * can touch objects after they're freed. 2195015a300SAlexander Potapenko */ 2205015a300SAlexander Potapenko rcu_read_lock(); 2215015a300SAlexander Potapenko /* 2225015a300SAlexander Potapenko * Copy the buffer to check that it's not wiped on 2235015a300SAlexander Potapenko * free(). 2245015a300SAlexander Potapenko */ 225733d1d1aSAlexander Potapenko buf_copy = kmalloc(size, GFP_ATOMIC); 2265015a300SAlexander Potapenko if (buf_copy) 2275015a300SAlexander Potapenko memcpy(buf_copy, buf, size); 228d3a81161SArnd Bergmann 2294ab7ace4SAlexander Potapenko kmem_cache_free(c, buf); 2305015a300SAlexander Potapenko /* 2315015a300SAlexander Potapenko * Check that |buf| is intact after kmem_cache_free(). 2325015a300SAlexander Potapenko * |want_zero| is false, because we wrote garbage to 2335015a300SAlexander Potapenko * the buffer already. 2345015a300SAlexander Potapenko */ 2355015a300SAlexander Potapenko fail |= check_buf(buf, size, want_ctor, want_rcu, 2365015a300SAlexander Potapenko false); 2375015a300SAlexander Potapenko if (buf_copy) { 2385015a300SAlexander Potapenko fail |= (bool)memcmp(buf, buf_copy, size); 2395015a300SAlexander Potapenko kfree(buf_copy); 2405015a300SAlexander Potapenko } 2415015a300SAlexander Potapenko rcu_read_unlock(); 2425015a300SAlexander Potapenko } 2435015a300SAlexander Potapenko kmem_cache_destroy(c); 2445015a300SAlexander Potapenko 2455015a300SAlexander Potapenko *total_failures += fail; 2465015a300SAlexander Potapenko return 1; 2475015a300SAlexander Potapenko } 2485015a300SAlexander Potapenko 2495015a300SAlexander Potapenko /* 2505015a300SAlexander Potapenko * Check that the data written to an RCU-allocated object survives 2515015a300SAlexander Potapenko * reallocation. 2525015a300SAlexander Potapenko */ 2535015a300SAlexander Potapenko static int __init do_kmem_cache_rcu_persistent(int size, int *total_failures) 2545015a300SAlexander Potapenko { 2555015a300SAlexander Potapenko struct kmem_cache *c; 2565015a300SAlexander Potapenko void *buf, *buf_contents, *saved_ptr; 2575015a300SAlexander Potapenko void **used_objects; 2585015a300SAlexander Potapenko int i, iter, maxiter = 1024; 2595015a300SAlexander Potapenko bool fail = false; 2605015a300SAlexander Potapenko 2615015a300SAlexander Potapenko c = kmem_cache_create("test_cache", size, size, SLAB_TYPESAFE_BY_RCU, 2625015a300SAlexander Potapenko NULL); 2635015a300SAlexander Potapenko buf = kmem_cache_alloc(c, GFP_KERNEL); 2645015a300SAlexander Potapenko saved_ptr = buf; 2655015a300SAlexander Potapenko fill_with_garbage(buf, size); 2665015a300SAlexander Potapenko buf_contents = kmalloc(size, GFP_KERNEL); 2675015a300SAlexander Potapenko if (!buf_contents) 2685015a300SAlexander Potapenko goto out; 2695015a300SAlexander Potapenko used_objects = kmalloc_array(maxiter, sizeof(void *), GFP_KERNEL); 2705015a300SAlexander Potapenko if (!used_objects) { 2715015a300SAlexander Potapenko kfree(buf_contents); 2725015a300SAlexander Potapenko goto out; 2735015a300SAlexander Potapenko } 2745015a300SAlexander Potapenko memcpy(buf_contents, buf, size); 2755015a300SAlexander Potapenko kmem_cache_free(c, buf); 2765015a300SAlexander Potapenko /* 2775015a300SAlexander Potapenko * Run for a fixed number of iterations. If we never hit saved_ptr, 2785015a300SAlexander Potapenko * assume the test passes. 2795015a300SAlexander Potapenko */ 2805015a300SAlexander Potapenko for (iter = 0; iter < maxiter; iter++) { 2815015a300SAlexander Potapenko buf = kmem_cache_alloc(c, GFP_KERNEL); 2825015a300SAlexander Potapenko used_objects[iter] = buf; 2835015a300SAlexander Potapenko if (buf == saved_ptr) { 2845015a300SAlexander Potapenko fail = memcmp(buf_contents, buf, size); 2855015a300SAlexander Potapenko for (i = 0; i <= iter; i++) 2865015a300SAlexander Potapenko kmem_cache_free(c, used_objects[i]); 2875015a300SAlexander Potapenko goto free_out; 2885015a300SAlexander Potapenko } 2895015a300SAlexander Potapenko } 2905015a300SAlexander Potapenko 2915015a300SAlexander Potapenko free_out: 2925015a300SAlexander Potapenko kmem_cache_destroy(c); 2935015a300SAlexander Potapenko kfree(buf_contents); 2945015a300SAlexander Potapenko kfree(used_objects); 2955015a300SAlexander Potapenko out: 2965015a300SAlexander Potapenko *total_failures += fail; 2975015a300SAlexander Potapenko return 1; 2985015a300SAlexander Potapenko } 2995015a300SAlexander Potapenko 300*03a9349aSAlexander Potapenko static int __init do_kmem_cache_size_bulk(int size, int *total_failures) 301*03a9349aSAlexander Potapenko { 302*03a9349aSAlexander Potapenko struct kmem_cache *c; 303*03a9349aSAlexander Potapenko int i, iter, maxiter = 1024; 304*03a9349aSAlexander Potapenko int num, bytes; 305*03a9349aSAlexander Potapenko bool fail = false; 306*03a9349aSAlexander Potapenko void *objects[10]; 307*03a9349aSAlexander Potapenko 308*03a9349aSAlexander Potapenko c = kmem_cache_create("test_cache", size, size, 0, NULL); 309*03a9349aSAlexander Potapenko for (iter = 0; (iter < maxiter) && !fail; iter++) { 310*03a9349aSAlexander Potapenko num = kmem_cache_alloc_bulk(c, GFP_KERNEL, ARRAY_SIZE(objects), 311*03a9349aSAlexander Potapenko objects); 312*03a9349aSAlexander Potapenko for (i = 0; i < num; i++) { 313*03a9349aSAlexander Potapenko bytes = count_nonzero_bytes(objects[i], size); 314*03a9349aSAlexander Potapenko if (bytes) 315*03a9349aSAlexander Potapenko fail = true; 316*03a9349aSAlexander Potapenko fill_with_garbage(objects[i], size); 317*03a9349aSAlexander Potapenko } 318*03a9349aSAlexander Potapenko 319*03a9349aSAlexander Potapenko if (num) 320*03a9349aSAlexander Potapenko kmem_cache_free_bulk(c, num, objects); 321*03a9349aSAlexander Potapenko } 322*03a9349aSAlexander Potapenko *total_failures += fail; 323*03a9349aSAlexander Potapenko return 1; 324*03a9349aSAlexander Potapenko } 325*03a9349aSAlexander Potapenko 3265015a300SAlexander Potapenko /* 3275015a300SAlexander Potapenko * Test kmem_cache allocation by creating caches of different sizes, with and 3285015a300SAlexander Potapenko * without constructors, with and without SLAB_TYPESAFE_BY_RCU. 3295015a300SAlexander Potapenko */ 3305015a300SAlexander Potapenko static int __init test_kmemcache(int *total_failures) 3315015a300SAlexander Potapenko { 3325015a300SAlexander Potapenko int failures = 0, num_tests = 0; 3335015a300SAlexander Potapenko int i, flags, size; 3345015a300SAlexander Potapenko bool ctor, rcu, zero; 3355015a300SAlexander Potapenko 3365015a300SAlexander Potapenko for (i = 0; i < 10; i++) { 3375015a300SAlexander Potapenko size = 8 << i; 3385015a300SAlexander Potapenko for (flags = 0; flags < 8; flags++) { 3395015a300SAlexander Potapenko ctor = flags & 1; 3405015a300SAlexander Potapenko rcu = flags & 2; 3415015a300SAlexander Potapenko zero = flags & 4; 3425015a300SAlexander Potapenko if (ctor & zero) 3435015a300SAlexander Potapenko continue; 3445015a300SAlexander Potapenko num_tests += do_kmem_cache_size(size, ctor, rcu, zero, 3455015a300SAlexander Potapenko &failures); 3465015a300SAlexander Potapenko } 347*03a9349aSAlexander Potapenko num_tests += do_kmem_cache_size_bulk(size, &failures); 3485015a300SAlexander Potapenko } 3495015a300SAlexander Potapenko REPORT_FAILURES_IN_FN(); 3505015a300SAlexander Potapenko *total_failures += failures; 3515015a300SAlexander Potapenko return num_tests; 3525015a300SAlexander Potapenko } 3535015a300SAlexander Potapenko 3545015a300SAlexander Potapenko /* Test the behavior of SLAB_TYPESAFE_BY_RCU caches of different sizes. */ 3555015a300SAlexander Potapenko static int __init test_rcu_persistent(int *total_failures) 3565015a300SAlexander Potapenko { 3575015a300SAlexander Potapenko int failures = 0, num_tests = 0; 3585015a300SAlexander Potapenko int i, size; 3595015a300SAlexander Potapenko 3605015a300SAlexander Potapenko for (i = 0; i < 10; i++) { 3615015a300SAlexander Potapenko size = 8 << i; 3625015a300SAlexander Potapenko num_tests += do_kmem_cache_rcu_persistent(size, &failures); 3635015a300SAlexander Potapenko } 3645015a300SAlexander Potapenko REPORT_FAILURES_IN_FN(); 3655015a300SAlexander Potapenko *total_failures += failures; 3665015a300SAlexander Potapenko return num_tests; 3675015a300SAlexander Potapenko } 3685015a300SAlexander Potapenko 3695015a300SAlexander Potapenko /* 3705015a300SAlexander Potapenko * Run the tests. Each test function returns the number of executed tests and 3715015a300SAlexander Potapenko * updates |failures| with the number of failed tests. 3725015a300SAlexander Potapenko */ 3735015a300SAlexander Potapenko static int __init test_meminit_init(void) 3745015a300SAlexander Potapenko { 3755015a300SAlexander Potapenko int failures = 0, num_tests = 0; 3765015a300SAlexander Potapenko 3775015a300SAlexander Potapenko num_tests += test_pages(&failures); 3785015a300SAlexander Potapenko num_tests += test_kvmalloc(&failures); 3795015a300SAlexander Potapenko num_tests += test_kmemcache(&failures); 3805015a300SAlexander Potapenko num_tests += test_rcu_persistent(&failures); 3815015a300SAlexander Potapenko 3825015a300SAlexander Potapenko if (failures == 0) 3835015a300SAlexander Potapenko pr_info("all %d tests passed!\n", num_tests); 3845015a300SAlexander Potapenko else 3855015a300SAlexander Potapenko pr_info("failures: %d out of %d\n", failures, num_tests); 3865015a300SAlexander Potapenko 3875015a300SAlexander Potapenko return failures ? -EINVAL : 0; 3885015a300SAlexander Potapenko } 3895015a300SAlexander Potapenko module_init(test_meminit_init); 3905015a300SAlexander Potapenko 3915015a300SAlexander Potapenko MODULE_LICENSE("GPL"); 392