e08d45359bb03" // SPDX-License-Identifier: GPL-2.0 /* * Test cases for SL[AOU]B/page initialization at alloc/free time. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include #include #include #include #include #include #include #define GARBAGE_INT (0x09A7BA9E) #define GARBAGE_BYTE (0x9E) #define REPORT_FAILURES_IN_FN() \ do { \ if (failures) \ pr_info("%s failed %d out of %d times\n", \ __func__, failures, num_tests); \ else \ pr_info("all %d tests in %s passed\n", \ num_tests, __func__); \ } while (0) /* Calculate the number of uninitialized bytes in the buffer. */ static int __init count_nonzero_bytes(void *ptr, size_t size) { int i, ret = 0; unsigned char *p = (unsigned char *)ptr; for (i = 0; i < size; i++) if (p[i]) ret++; return ret; } /* Fill a buffer with garbage, skipping |skip| first bytes. */ static void __init fill_with_garbage_skip(void *ptr, int size, size_t skip) { unsigned int *p = (unsigned int *)((char *)ptr + skip); int i = 0; WARN_ON(skip > size); size -= skip; while (size >= sizeof(*p)) { p[i] = GARBAGE_INT; i++; size -= sizeof(*p); } if (size) memset(&p[i], GARBAGE_BYTE, size); } static void __init fill_with_garbage(void *ptr, size_t size) { fill_with_garbage_skip(ptr, size, 0); } static int __init do_alloc_pages_order(int order, int *total_failures) { struct page *page; void *buf; size_t size = PAGE_SIZE << order; page = alloc_pages(GFP_KERNEL, order); if (!page) goto err; buf = page_address(page); fill_with_garbage(buf, size); __free_pages(page, order); page = alloc_pages(GFP_KERNEL, order); if (!page) goto err; buf = page_address(page); if (count_nonzero_bytes(buf, size)) (*total_failures)++; fill_with_garbage(buf, size); __free_pages(page, order); return 1; err: (*total_failures)++; return 1; } /* Test the page allocator by calling alloc_pages with different orders. */ static int __init test_pages(int *total_failures) { int failures = 0, num_tests = 0; int i; for (i = 0; i <= MAX_ORDER; i++) num_tests += do_alloc_pages_order(i, &failures); REPORT_FAILURES_IN_FN(); *total_failures += failures; return num_tests; } /* Test kmalloc() with given parameters. */ static int __init do_kmalloc_size(size_t size, int *total_failures) { void *buf; buf = kmalloc(size, GFP_KERNEL); if (!buf) goto err; fill_with_garbage(buf, size); kfree(buf); buf = kmalloc(size, GFP_KERNEL); if (!buf) goto err; if (count_nonzero_bytes(buf, size)) (*total_failures)++; fill_with_garbage(buf, size); kfree(buf); return 1; err: (*total_failures)++; return 1; } /* Test vmalloc() with given parameters. */ static int __init do_vmalloc_size(size_t size, int *total_failures) { void *buf; buf = vmalloc(size); if (!buf) goto err; fill_with_garbage(buf, size); vfree(buf); buf = vmalloc(size); if (!buf) goto err; if (count_nonzero_bytes(buf, size)) (*total_failures)++; fill_with_garbage(buf, size); vfree(buf); return 1; err: (*total_failures)++; return 1; } /* Test kmalloc()/vmalloc() by allocating objects of different sizes. */ static int __init test_kvmalloc(int *total_failures) { int failures = 0, num_tests = 0; int i, size; for (i = 0; i < 20; i++) { size = 1 << i; num_tests += do_kmalloc_size(size, &failures); num_tests += do_vmalloc_size(size, &failures); } REPORT_FAILURES_IN_FN(); *total_failures += failures; return num_tests; } #define CTOR_BYTES (sizeof(unsigned int)) #define CTOR_PATTERN (0x41414141) /* Initialize the first 4 bytes of the object. */ static void test_ctor(void *obj) { *(unsigned int *)obj = CTOR