diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/Kconfig | 45 | ||||
-rw-r--r-- | lib/Kconfig.debug | 108 | ||||
-rw-r--r-- | lib/Kconfig.ubsan | 25 | ||||
-rw-r--r-- | lib/Makefile | 47 | ||||
-rw-r--r-- | lib/atomic64_test.c | 2 | ||||
-rw-r--r-- | lib/cpumask.c | 37 | ||||
-rw-r--r-- | lib/crc32.c | 21 | ||||
-rw-r--r-- | lib/crc64-rocksoft.c | 126 | ||||
-rw-r--r-- | lib/crc64.c | 49 | ||||
-rw-r--r-- | lib/crc7.c | 6 | ||||
-rw-r--r-- | lib/dump_stack.c | 4 | ||||
-rw-r--r-- | lib/gen_crc64table.c | 10 | ||||
-rw-r--r-- | lib/math/Makefile | 5 | ||||
-rw-r--r-- | lib/math/prime_numbers.c | 91 | ||||
-rw-r--r-- | lib/math/prime_numbers_private.h | 16 | ||||
-rw-r--r-- | lib/math/tests/Makefile | 8 | ||||
-rw-r--r-- | lib/math/tests/gcd_kunit.c | 56 | ||||
-rw-r--r-- | lib/math/tests/int_log_kunit.c | 74 | ||||
-rw-r--r-- | lib/math/tests/prime_numbers_kunit.c | 59 | ||||
-rw-r--r-- | lib/math/tests/rational_kunit.c (renamed from lib/math/rational-test.c) | 0 | ||||
-rw-r--r-- | lib/test_bitmap.c | 28 | ||||
-rw-r--r-- | lib/test_objpool.c | 3 | ||||
-rw-r--r-- | lib/test_ubsan.c | 18 | ||||
-rw-r--r-- | lib/tests/Makefile | 43 | ||||
-rw-r--r-- | lib/tests/bitfield_kunit.c (renamed from lib/bitfield_kunit.c) | 0 | ||||
-rw-r--r-- | lib/tests/checksum_kunit.c (renamed from lib/checksum_kunit.c) | 0 | ||||
-rw-r--r-- | lib/tests/cmdline_kunit.c (renamed from lib/cmdline_kunit.c) | 0 | ||||
-rw-r--r-- | lib/tests/cpumask_kunit.c (renamed from lib/cpumask_kunit.c) | 0 | ||||
-rw-r--r-- | lib/tests/crc_kunit.c (renamed from lib/crc_kunit.c) | 68 | ||||
-rw-r--r-- | lib/tests/fortify_kunit.c (renamed from lib/fortify_kunit.c) | 156 | ||||
-rw-r--r-- | lib/tests/hashtable_test.c (renamed from lib/hashtable_test.c) | 0 | ||||
-rw-r--r-- | lib/tests/is_signed_type_kunit.c (renamed from lib/is_signed_type_kunit.c) | 0 | ||||
-rw-r--r-- | lib/tests/kfifo_kunit.c | 224 | ||||
-rw-r--r-- | lib/tests/kunit_iov_iter.c (renamed from lib/kunit_iov_iter.c) | 0 | ||||
-rw-r--r-- | lib/tests/list-test.c (renamed from lib/list-test.c) | 0 | ||||
-rw-r--r-- | lib/tests/memcpy_kunit.c (renamed from lib/memcpy_kunit.c) | 0 | ||||
-rw-r--r-- | lib/tests/overflow_kunit.c (renamed from lib/overflow_kunit.c) | 38 | ||||
-rw-r--r-- | lib/tests/printf_kunit.c (renamed from lib/test_printf.c) | 442 | ||||
-rw-r--r-- | lib/tests/scanf_kunit.c (renamed from lib/test_scanf.c) | 295 | ||||
-rw-r--r-- | lib/tests/siphash_kunit.c (renamed from lib/siphash_kunit.c) | 0 | ||||
-rw-r--r-- | lib/tests/slub_kunit.c (renamed from lib/slub_kunit.c) | 59 | ||||
-rw-r--r-- | lib/tests/stackinit_kunit.c (renamed from lib/stackinit_kunit.c) | 30 | ||||
-rw-r--r-- | lib/tests/string_helpers_kunit.c (renamed from lib/string_helpers_kunit.c) | 0 | ||||
-rw-r--r-- | lib/tests/string_kunit.c (renamed from lib/string_kunit.c) | 4 | ||||
-rw-r--r-- | lib/tests/test_bits.c (renamed from lib/test_bits.c) | 0 | ||||
-rw-r--r-- | lib/tests/test_fprobe.c (renamed from lib/test_fprobe.c) | 0 | ||||
-rw-r--r-- | lib/tests/test_hash.c (renamed from lib/test_hash.c) | 0 | ||||
-rw-r--r-- | lib/tests/test_kprobes.c (renamed from lib/test_kprobes.c) | 0 | ||||
-rw-r--r-- | lib/tests/test_linear_ranges.c (renamed from lib/test_linear_ranges.c) | 0 | ||||
-rw-r--r-- | lib/tests/test_list_sort.c (renamed from lib/test_list_sort.c) | 0 | ||||
-rw-r--r-- | lib/tests/test_sort.c (renamed from lib/test_sort.c) | 0 | ||||
-rw-r--r-- | lib/tests/usercopy_kunit.c (renamed from lib/usercopy_kunit.c) | 0 | ||||
-rw-r--r-- | lib/tests/util_macros_kunit.c (renamed from lib/util_macros_kunit.c) | 0 | ||||
-rw-r--r-- | lib/ubsan.c | 28 | ||||
-rw-r--r-- | lib/ubsan.h | 8 | ||||
-rw-r--r-- | lib/vdso/Kconfig | 5 | ||||
-rw-r--r-- | lib/vdso/Makefile | 19 | ||||
-rw-r--r-- | lib/vdso/Makefile.include | 18 | ||||
-rw-r--r-- | lib/vdso/datastore.c | 129 | ||||
-rw-r--r-- | lib/vdso/getrandom.c | 8 | ||||
-rw-r--r-- | lib/vdso/gettimeofday.c | 196 | ||||
-rw-r--r-- | lib/vsprintf.c | 7 | ||||
-rw-r--r-- | lib/zstd/common/portability_macros.h | 2 |
63 files changed, 1589 insertions, 1028 deletions
diff --git a/lib/Kconfig b/lib/Kconfig index dccb61b7d698..61cce0686b53 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -168,15 +168,6 @@ config CRC_T10DIF_ARCH tristate default CRC_T10DIF if ARCH_HAS_CRC_T10DIF && CRC_OPTIMIZATIONS -config CRC64_ROCKSOFT - tristate "CRC calculation for the Rocksoft model CRC64" - select CRC64 - select CRYPTO - select CRYPTO_CRC64_ROCKSOFT - help - This option provides a CRC64 API to a registered crypto driver. - This is used with the block layer's data integrity subsystem. - config CRC_ITU_T tristate "CRC ITU-T V.41 functions" help @@ -203,42 +194,30 @@ config CRC32_ARCH default CRC32 if ARCH_HAS_CRC32 && CRC_OPTIMIZATIONS config CRC64 - tristate "CRC64 functions" - help - This option is provided for the case where no in-kernel-tree - modules require CRC64 functions, but a module built outside - the kernel tree does. Such modules that use library CRC64 - functions require M here. + tristate + +config ARCH_HAS_CRC64 + bool + +config CRC64_ARCH + tristate + default CRC64 if ARCH_HAS_CRC64 && CRC_OPTIMIZATIONS config CRC4 - tristate "CRC4 functions" - help - This option is provided for the case where no in-kernel-tree - modules require CRC4 functions, but a module built outside - the kernel tree does. Such modules that use library CRC4 - functions require M here. + tristate config CRC7 - tristate "CRC7 functions" - help - This option is provided for the case where no in-kernel-tree - modules require CRC7 functions, but a module built outside - the kernel tree does. Such modules that use library CRC7 - functions require M here. + tristate config LIBCRC32C - tristate "CRC32c (Castagnoli, et al) Cyclic Redundancy-Check" + tristate select CRC32 help This option just selects CRC32 and is provided for compatibility purposes until the users are updated to select CRC32 directly. config CRC8 - tristate "CRC8 function" - help - This option provides CRC8 function. Drivers may select this - when they need to do cyclic redundancy check according CRC8 - algorithm. Module will be called crc8. + tristate config CRC_OPTIMIZATIONS bool "Enable optimized CRC implementations" if EXPERT diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 35796c290ca3..c7086ed09cde 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -545,6 +545,17 @@ config FRAME_POINTER config OBJTOOL bool +config OBJTOOL_WERROR + bool "Upgrade objtool warnings to errors" + depends on OBJTOOL && !COMPILE_TEST + help + Fail the build on objtool warnings. + + Objtool warnings can indicate kernel instability, including boot + failures. This option is highly recommended. + + If unsure, say Y. + config STACK_VALIDATION bool "Compile-time stack metadata validation" depends on HAVE_STACK_VALIDATION && UNWINDER_FRAME_POINTER @@ -808,6 +819,15 @@ config ARCH_HAS_DEBUG_VM_PGTABLE An architecture should select this when it can successfully build and run DEBUG_VM_PGTABLE. +config DEBUG_VFS + bool "Debug VFS" + depends on DEBUG_KERNEL + help + Enable this to turn on extended checks in the VFS layer that may impact + performance. + + If unsure, say N. + config DEBUG_VM_IRQSOFF def_bool DEBUG_VM && !PREEMPT_RT @@ -1301,15 +1321,6 @@ endmenu # "Debug lockups and hangs" menu "Scheduler Debugging" -config SCHED_DEBUG - bool "Collect scheduler debugging info" - depends on DEBUG_KERNEL && DEBUG_FS - default y - help - If you say Y here, the /sys/kernel/debug/sched file will be provided - that can help debug the scheduler. The runtime overhead of this - option is minimal. - config SCHED_INFO bool default n @@ -2427,6 +2438,24 @@ config ASYNC_RAID6_TEST config TEST_HEXDUMP tristate "Test functions located in the hexdump module at runtime" +config PRINTF_KUNIT_TEST + tristate "KUnit test printf() family of functions at runtime" if !KUNIT_ALL_TESTS + depends on KUNIT + default KUNIT_ALL_TESTS + help + Enable this option to test the printf functions at runtime. + + If unsure, say N. + +config SCANF_KUNIT_TEST + tristate "KUnit test scanf() family of functions at runtime" if !KUNIT_ALL_TESTS + depends on KUNIT + default KUNIT_ALL_TESTS + help + Enable this option to test the scanf functions at runtime. + + If unsure, say N. + config STRING_KUNIT_TEST tristate "KUnit test string functions at runtime" if !KUNIT_ALL_TESTS depends on KUNIT @@ -2440,12 +2469,6 @@ config STRING_HELPERS_KUNIT_TEST config TEST_KSTRTOX tristate "Test kstrto*() family of functions at runtime" -config TEST_PRINTF - tristate "Test printf() family of functions at runtime" - -config TEST_SCANF - tristate "Test scanf() family of functions at runtime" - config TEST_BITMAP tristate "Test bitmap_*() family of functions at runtime" help @@ -2691,6 +2714,20 @@ config SYSCTL_KUNIT_TEST If unsure, say N. +config KFIFO_KUNIT_TEST + tristate "KUnit Test for the generic kernel FIFO implementation" if !KUNIT_ALL_TESTS + depends on KUNIT + default KUNIT_ALL_TESTS + help + This builds the generic FIFO implementation KUnit test suite. + It tests that the API and basic functionality of the kfifo type + and associated macros. + + For more information on KUnit and unit tests in general please refer + to the KUnit documentation in Documentation/dev-tools/kunit/. + + If unsure, say N. + config LIST_KUNIT_TEST tristate "KUnit Test for Kernel Linked-list structures" if !KUNIT_ALL_TESTS depends on KUNIT @@ -2852,6 +2889,7 @@ config CRC_KUNIT_TEST tristate "KUnit tests for CRC functions" if !KUNIT_ALL_TESTS depends on KUNIT default KUNIT_ALL_TESTS + select CRC7 select CRC16 select CRC_T10DIF select CRC32 @@ -3166,7 +3204,7 @@ config TEST_OBJPOOL If unsure, say N. -config INT_POW_TEST +config INT_POW_KUNIT_TEST tristate "Integer exponentiation (int_pow) test" if !KUNIT_ALL_TESTS depends on KUNIT default KUNIT_ALL_TESTS @@ -3197,6 +3235,44 @@ config INT_SQRT_KUNIT_TEST If unsure, say N +config INT_LOG_KUNIT_TEST + tristate "Integer log (int_log) test" if !KUNIT_ALL_TESTS + depends on KUNIT + default KUNIT_ALL_TESTS + help + This option enables the KUnit test suite for the int_log library, which + provides two functions to compute the integer logarithm in base 2 and + base 10, called respectively as intlog2 and intlog10. + + If unsure, say N + +config GCD_KUNIT_TEST + tristate "Greatest common divisor test" if !KUNIT_ALL_TESTS + depends on KUNIT + default KUNIT_ALL_TESTS + help + This option enables the KUnit test suite for the gcd() function, + which computes the greatest common divisor of two numbers. + + This test suite verifies the correctness of gcd() across various + scenarios, including edge cases. + + If unsure, say N + +config PRIME_NUMBERS_KUNIT_TEST + tristate "Prime number generator test" if !KUNIT_ALL_TESTS + depends on KUNIT + select PRIME_NUMBERS + default KUNIT_ALL_TESTS + help + This option enables the KUnit test suite for the {is,next}_prime_number + functions. + + Enabling this option will include tests that compare the prime number + generator functions against a brute force implementation. + + If unsure, say N + endif # RUNTIME_TESTING_MENU config ARCH_USE_MEMTEST diff --git a/lib/Kconfig.ubsan b/lib/Kconfig.ubsan index 1d4aa7a83b3a..4216b3a4ff21 100644 --- a/lib/Kconfig.ubsan +++ b/lib/Kconfig.ubsan @@ -116,21 +116,22 @@ config UBSAN_UNREACHABLE This option enables -fsanitize=unreachable which checks for control flow reaching an expected-to-be-unreachable position. -config UBSAN_SIGNED_WRAP - bool "Perform checking for signed arithmetic wrap-around" +config UBSAN_INTEGER_WRAP + bool "Perform checking for integer arithmetic wrap-around" default UBSAN depends on !COMPILE_TEST - # The no_sanitize attribute was introduced in GCC with version 8. - depends on !CC_IS_GCC || GCC_VERSION >= 80000 + depends on $(cc-option,-fsanitize-undefined-ignore-overflow-pattern=all) depends on $(cc-option,-fsanitize=signed-integer-overflow) - help - This option enables -fsanitize=signed-integer-overflow which checks - for wrap-around of any arithmetic operations with signed integers. - This currently performs nearly no instrumentation due to the - kernel's use of -fno-strict-overflow which converts all would-be - arithmetic undefined behavior into wrap-around arithmetic. Future - sanitizer versions will allow for wrap-around checking (rather than - exclusively undefined behavior). + depends on $(cc-option,-fsanitize=unsigned-integer-overflow) + depends on $(cc-option,-fsanitize=implicit-signed-integer-truncation) + depends on $(cc-option,-fsanitize=implicit-unsigned-integer-truncation) + depends on $(cc-option,-fsanitize-ignorelist=/dev/null) + help + This option enables all of the sanitizers involved in integer overflow + (wrap-around) mitigation: signed-integer-overflow, unsigned-integer-overflow, + implicit-signed-integer-truncation, and implicit-unsigned-integer-truncation. + This is currently limited only to the size_t type while testing and + compiler development continues. config UBSAN_BOOL bool "Perform checking for non-boolean values used as boolean" diff --git a/lib/Makefile b/lib/Makefile index d5cfc7afbbb8..0fdcd6d635ad 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -5,6 +5,11 @@ ccflags-remove-$(CONFIG_FUNCTION_TRACER) += $(CC_FLAGS_FTRACE) +# Branch profiling isn't noinstr-safe +ifdef CONFIG_TRACE_BRANCH_PROFILING +CFLAGS_smp_processor_id.o += -DDISABLE_BRANCH_PROFILING +endif + # These files are disabled because they produce lots of non-interesting and/or # flaky coverage that is not a function of syscall inputs. For example, # rbtree can be global and individual rotations don't correlate with inputs. @@ -52,9 +57,7 @@ obj-y += bcd.o sort.o parser.o debug_locks.o random32.o \ percpu-refcount.o rhashtable.o base64.o \ once.o refcount.o rcuref.o usercopy.o errseq.o bucket_locks.o \ generic-radix-tree.o bitmap-str.o -obj-$(CONFIG_STRING_KUNIT_TEST) += string_kunit.o obj-y += string_helpers.o -obj-$(CONFIG_STRING_HELPERS_KUNIT_TEST) += string_helpers_kunit.o obj-y += hexdump.o obj-$(CONFIG_TEST_HEXDUMP) += test_hexdump.o obj-y += kstrtox.o @@ -65,27 +68,20 @@ obj-$(CONFIG_TEST_DHRY) += test_dhry.o obj-$(CONFIG_TEST_FIRMWARE) += test_firmware.o obj-$(CONFIG_TEST_BITOPS) += test_bitops.o CFLAGS_test_bitops.o += -Werror -obj-$(CONFIG_CPUMASK_KUNIT_TEST) += cpumask_kunit.o obj-$(CONFIG_TEST_SYSCTL) += test_sysctl.o -obj-$(CONFIG_TEST_IOV_ITER) += kunit_iov_iter.o -obj-$(CONFIG_HASH_KUNIT_TEST) += test_hash.o obj-$(CONFIG_TEST_IDA) += test_ida.o obj-$(CONFIG_TEST_UBSAN) += test_ubsan.o CFLAGS_test_ubsan.o += $(call cc-disable-warning, vla) CFLAGS_test_ubsan.o += $(call cc-disable-warning, unused-but-set-variable) UBSAN_SANITIZE_test_ubsan.o := y obj-$(CONFIG_TEST_KSTRTOX) += test-kstrtox.o -obj-$(CONFIG_TEST_LIST_SORT) += test_list_sort.o obj-$(CONFIG_TEST_MIN_HEAP) += test_min_heap.o obj-$(CONFIG_TEST_LKM) += test_module.o obj-$(CONFIG_TEST_VMALLOC) += test_vmalloc.o obj-$(CONFIG_TEST_RHASHTABLE) += test_rhashtable.o -obj-$(CONFIG_TEST_SORT) += test_sort.o obj-$(CONFIG_TEST_STATIC_KEYS) += test_static_keys.o obj-$(CONFIG_TEST_STATIC_KEYS) += test_static_key_base.o obj-$(CONFIG_TEST_DYNAMIC_DEBUG) += test_dynamic_debug.o -obj-$(CONFIG_TEST_PRINTF) += test_printf.o -obj-$(CONFIG_TEST_SCANF) += test_scanf.o obj-$(CONFIG_TEST_BITMAP) += test_bitmap.o ifeq ($(CONFIG_CC_IS_CLANG)$(CONFIG_KASAN),yy) @@ -98,7 +94,6 @@ obj-$(CONFIG_TEST_XARRAY) += test_xarray.o obj-$(CONFIG_TEST_MAPLE_TREE) += test_maple_tree.o obj-$(CONFIG_TEST_PARMAN) += test_parman.o obj-$(CONFIG_TEST_KMOD) += test_kmod.o -obj-$(CONFIG_TEST_RUNTIME) += tests/ obj-$(CONFIG_TEST_DEBUG_VIRTUAL) += test_debug_virtual.o obj-$(CONFIG_TEST_MEMCAT_P) += test_memcat_p.o obj-$(CONFIG_TEST_OBJAGG) += test_objagg.o @@ -107,10 +102,7 @@ obj-$(CONFIG_TEST_MEMINIT) += test_meminit.o obj-$(CONFIG_TEST_LOCKUP) += test_lockup.o obj-$(CONFIG_TEST_HMM) += test_hmm.o obj-$(CONFIG_TEST_FREE_PAGES) += test_free_pages.o -obj-$(CONFIG_KPROBES_SANITY_TEST) += test_kprobes.o obj-$(CONFIG_TEST_REF_TRACKER) += test_ref_tracker.o -CFLAGS_test_fprobe.o += $(CC_FLAGS_FTRACE) -obj-$(CONFIG_FPROBE_SANITY_TEST) += test_fprobe.o obj-$(CONFIG_TEST_OBJPOOL) += test_objpool.o obj-$(CONFIG_TEST_FPU) += test_fpu.o @@ -132,7 +124,7 @@ endif obj-$(CONFIG_DEBUG_INFO_REDUCED) += debug_info.o CFLAGS_debug_info.o += $(call cc-option, -femit-struct-debug-detailed=any) -obj-y += math/ crypto/ +obj-y += math/ crypto/ tests/ vdso/ obj-$(CONFIG_GENERIC_IOMAP) += iomap.o obj-$(CONFIG_HAS_IOMEM) += iomap_copy.o devres.o @@ -167,7 +159,6 @@ obj-$(CONFIG_CRC64) += crc64.o obj-$(CONFIG_CRC4) += crc4.o obj-$(CONFIG_CRC7) += crc7.o obj-$(CONFIG_CRC8) += crc8.o -obj-$(CONFIG_CRC64_ROCKSOFT) += crc64-rocksoft.o obj-$(CONFIG_XXHASH) += xxhash.o obj-$(CONFIG_GENERIC_ALLOCATOR) += genalloc.o @@ -368,32 +359,6 @@ obj-$(CONFIG_OBJAGG) += objagg.o # pldmfw library obj-$(CONFIG_PLDMFW) += pldmfw/ -# KUnit tests -CFLAGS_bitfield_kunit.o := $(DISABLE_STRUCTLEAK_PLUGIN) -obj-$(CONFIG_BITFIELD_KUNIT) += bitfield_kunit.o -obj-$(CONFIG_CHECKSUM_KUNIT) += checksum_kunit.o -obj-$(CONFIG_UTIL_MACROS_KUNIT) += util_macros_kunit.o -obj-$(CONFIG_LIST_KUNIT_TEST) += list-test.o -obj-$(CONFIG_HASHTABLE_KUNIT_TEST) += hashtable_test.o -obj-$(CONFIG_LINEAR_RANGES_TEST) += test_linear_ranges.o -obj-$(CONFIG_BITS_TEST) += test_bits.o -obj-$(CONFIG_CMDLINE_KUNIT_TEST) += cmdline_kunit.o -obj-$(CONFIG_SLUB_KUNIT_TEST) += slub_kunit.o -obj-$(CONFIG_MEMCPY_KUNIT_TEST) += memcpy_kunit.o -obj-$(CONFIG_IS_SIGNED_TYPE_KUNIT_TEST) += is_signed_type_kunit.o -CFLAGS_overflow_kunit.o = $(call cc-disable-warning, tautological-constant-out-of-range-compare) -obj-$(CONFIG_OVERFLOW_KUNIT_TEST) += overflow_kunit.o -CFLAGS_stackinit_kunit.o += $(call cc-disable-warning, switch-unreachable) -obj-$(CONFIG_STACKINIT_KUNIT_TEST) += stackinit_kunit.o -CFLAGS_fortify_kunit.o += $(call cc-disable-warning, unsequenced) -CFLAGS_fortify_kunit.o += $(call cc-disable-warning, stringop-overread) -CFLAGS_fortify_kunit.o += $(call cc-disable-warning, stringop-truncation) -CFLAGS_fortify_kunit.o += $(DISABLE_STRUCTLEAK_PLUGIN) -obj-$(CONFIG_FORTIFY_KUNIT_TEST) += fortify_kunit.o -obj-$(CONFIG_CRC_KUNIT_TEST) += crc_kunit.o -obj-$(CONFIG_SIPHASH_KUNIT_TEST) += siphash_kunit.o -obj-$(CONFIG_USERCOPY_KUNIT_TEST) += usercopy_kunit.o - obj-$(CONFIG_GENERIC_LIB_DEVMEM_IS_ALLOWED) += devmem_is_allowed.o obj-$(CONFIG_FIRMWARE_TABLE) += fw_table.o diff --git a/lib/atomic64_test.c b/lib/atomic64_test.c index 759ea1783cc5..d726068358c7 100644 --- a/lib/atomic64_test.c +++ b/lib/atomic64_test.c @@ -254,7 +254,7 @@ static __init int test_atomics_init(void) pr_info("passed for %s platform %s CX8 and %s SSE\n", #ifdef CONFIG_X86_64 "x86-64", -#elif defined(CONFIG_X86_CMPXCHG64) +#elif defined(CONFIG_X86_CX8) "i586+", #else "i386+", diff --git a/lib/cpumask.c b/lib/cpumask.c index 57274ba8b6d9..5adb9874fbd0 100644 --- a/lib/cpumask.c +++ b/lib/cpumask.c @@ -7,38 +7,6 @@ #include <linux/memblock.h> #include <linux/numa.h> -/** - * cpumask_next_wrap - helper to implement for_each_cpu_wrap - * @n: the cpu prior to the place to search - * @mask: the cpumask pointer - * @start: the start point of the iteration - * @wrap: assume @n crossing @start terminates the iteration - * - * Return: >= nr_cpu_ids on completion - * - * Note: the @wrap argument is required for the start condition when - * we cannot assume @start is set in @mask. - */ -unsigned int cpumask_next_wrap(int n, const struct cpumask *mask, int start, bool wrap) -{ - unsigned int next; - -again: - next = cpumask_next(n, mask); - - if (wrap && n < start && next >= start) { - return nr_cpumask_bits; - - } else if (next >= nr_cpumask_bits) { - wrap = true; - n = -1; - goto again; - } - - return next; -} -EXPORT_SYMBOL(cpumask_next_wrap); - /* These are not inline because of header tangles. */ #ifdef CONFIG_CPUMASK_OFFSTACK /** @@ -171,8 +139,7 @@ unsigned int cpumask_any_and_distribute(const struct cpumask *src1p, /* NOTE: our first selection will skip 0. */ prev = __this_cpu_read(distribute_cpu_mask_prev); - next = find_next_and_bit_wrap(cpumask_bits(src1p), cpumask_bits(src2p), - nr_cpumask_bits, prev + 1); + next = cpumask_next_and_wrap(prev, src1p, src2p); if (next < nr_cpu_ids) __this_cpu_write(distribute_cpu_mask_prev, next); @@ -192,7 +159,7 @@ unsigned int cpumask_any_distribute(const struct cpumask *srcp) /* NOTE: our first selection will skip 0. */ prev = __this_cpu_read(distribute_cpu_mask_prev); - next = find_next_bit_wrap(cpumask_bits(srcp), nr_cpumask_bits, prev + 1); + next = cpumask_next_wrap(prev, srcp); if (next < nr_cpu_ids) __this_cpu_write(distribute_cpu_mask_prev, next); diff --git a/lib/crc32.c b/lib/crc32.c index ede6131f66fc..fddd424ff224 100644 --- a/lib/crc32.c +++ b/lib/crc32.c @@ -37,7 +37,7 @@ MODULE_AUTHOR("Matt Domsch <Matt_Domsch@dell.com>"); MODULE_DESCRIPTION("Various CRC32 calculations"); MODULE_LICENSE("GPL"); -u32 __pure crc32_le_base(u32 crc, const u8 *p, size_t len) +u32 crc32_le_base(u32 crc, const u8 *p, size_t len) { while (len--) crc = (crc >> 8) ^ crc32table_le[(crc & 255) ^ *p++]; @@ -45,20 +45,20 @@ u32 __pure crc32_le_base(u32 crc, const u8 *p, size_t len) } EXPORT_SYMBOL(crc32_le_base); -u32 __pure crc32c_le_base(u32 crc, const u8 *p, size_t len) +u32 crc32c_base(u32 crc, const u8 *p, size_t len) { while (len--) crc = (crc >> 8) ^ crc32ctable_le[(crc & 255) ^ *p++]; return crc; } -EXPORT_SYMBOL(crc32c_le_base); +EXPORT_SYMBOL(crc32c_base); /* * This multiplies the polynomials x and y modulo the given modulus. * This follows the "little-endian" CRC convention that the lsbit * represents the highest power of x, and the msbit represents x^0. */ -static u32 __attribute_const__ gf2_multiply(u32 x, u32 y, u32 modulus) +static u32 gf2_multiply(u32 x, u32 y, u32 modulus) { u32 product = x & 1 ? y : 0; int i; @@ -84,8 +84,7 @@ static u32 __attribute_const__ gf2_multiply(u32 x, u32 y, u32 modulus) * as appending len bytes of zero to the data), in time proportional * to log(len). */ -static u32 __attribute_const__ crc32_generic_shift(u32 crc, size_t len, - u32 polynomial) +static u32 crc32_generic_shift(u32 crc, size_t len, u32 polynomial) { u32 power = polynomial; /* CRC of x^32 */ int i; @@ -114,19 +113,19 @@ static u32 __attribute_const__ crc32_generic_shift(u32 crc, size_t len, return crc; } -u32 __attribute_const__ crc32_le_shift(u32 crc, size_t len) +u32 crc32_le_shift(u32 crc, size_t len) { return crc32_generic_shift(crc, len, CRC32_POLY_LE); } +EXPORT_SYMBOL(crc32_le_shift); -u32 __attribute_const__ __crc32c_le_shift(u32 crc, size_t len) +u32 crc32c_shift(u32 crc, size_t len) { return crc32_generic_shift(crc, len, CRC32C_POLY_LE); } -EXPORT_SYMBOL(crc32_le_shift); -EXPORT_SYMBOL(__crc32c_le_shift); +EXPORT_SYMBOL(crc32c_shift); -u32 __pure crc32_be_base(u32 crc, const u8 *p, size_t len) +u32 crc32_be_base(u32 crc, const u8 *p, size_t len) { while (len--) crc = (crc << 8) ^ crc32table_be[(crc >> 24) ^ *p++]; diff --git a/lib/crc64-rocksoft.c b/lib/crc64-rocksoft.c deleted file mode 100644 index fc9ae0da5df7..000000000000 --- a/lib/crc64-rocksoft.c +++ /dev/null @@ -1,126 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only - -#include <linux/types.h> -#include <linux/module.h> -#include <linux/crc64.h> -#include <linux/err.h> -#include <linux/init.h> -#include <crypto/hash.h> -#include <crypto/algapi.h> -#include <linux/static_key.h> -#include <linux/notifier.h> - -static struct crypto_shash __rcu *crc64_rocksoft_tfm; -static DEFINE_STATIC_KEY_TRUE(crc64_rocksoft_fallback); -static DEFINE_MUTEX(crc64_rocksoft_mutex); -static struct work_struct crc64_rocksoft_rehash_work; - -static int crc64_rocksoft_notify(struct notifier_block *self, unsigned long val, void *data) -{ - struct crypto_alg *alg = data; - - if (val != CRYPTO_MSG_ALG_LOADED || - strcmp(alg->cra_name, CRC64_ROCKSOFT_STRING)) - return NOTIFY_DONE; - - schedule_work(&crc64_rocksoft_rehash_work); - return NOTIFY_OK; -} - -static void crc64_rocksoft_rehash(struct work_struct *work) -{ - struct crypto_shash *new, *old; - - mutex_lock(&crc64_rocksoft_mutex); - old = rcu_dereference_protected(crc64_rocksoft_tfm, - lockdep_is_held(&crc64_rocksoft_mutex)); - new = crypto_alloc_shash(CRC64_ROCKSOFT_STRING, 0, 0); - if (IS_ERR(new)) { - mutex_unlock(&crc64_rocksoft_mutex); - return; - } - rcu_assign_pointer(crc64_rocksoft_tfm, new); - mutex_unlock(&crc64_rocksoft_mutex); - - if (old) { - synchronize_rcu(); - crypto_free_shash(old); - } else { - static_branch_disable(&crc64_rocksoft_fallback); - } -} - -static struct notifier_block crc64_rocksoft_nb = { - .notifier_call = crc64_rocksoft_notify, -}; - -u64 crc64_rocksoft_update(u64 crc, const unsigned char *buffer, size_t len) -{ - struct { - struct shash_desc shash; - u64 crc; - } desc; - int err; - - if (static_branch_unlikely(&crc64_rocksoft_fallback)) - return crc64_rocksoft_generic(crc, buffer, len); - - rcu_read_lock(); - desc.shash.tfm = rcu_dereference(crc64_rocksoft_tfm); - desc.crc = crc; - err = crypto_shash_update(&desc.shash, buffer, len); - rcu_read_unlock(); - - BUG_ON(err); - - return desc.crc; -} -EXPORT_SYMBOL_GPL(crc64_rocksoft_update); - -u64 crc64_rocksoft(const unsigned char *buffer, size_t len) -{ - return crc64_rocksoft_update(0, buffer, len); -} -EXPORT_SYMBOL_GPL(crc64_rocksoft); - -static int __init crc64_rocksoft_mod_init(void) -{ - INIT_WORK(&crc64_rocksoft_rehash_work, crc64_rocksoft_rehash); - crypto_register_notifier(&crc64_rocksoft_nb); - crc64_rocksoft_rehash(&crc64_rocksoft_rehash_work); - return 0; -} - -static void __exit crc64_rocksoft_mod_fini(void) -{ - crypto_unregister_notifier(&crc64_rocksoft_nb); - cancel_work_sync(&crc64_rocksoft_rehash_work); - crypto_free_shash(rcu_dereference_protected(crc64_rocksoft_tfm, 1)); -} - -module_init(crc64_rocksoft_mod_init); -module_exit(crc64_rocksoft_mod_fini); - -static int crc64_rocksoft_transform_show(char *buffer, const struct kernel_param *kp) -{ - struct crypto_shash *tfm; - int len; - - if (static_branch_unlikely(&crc64_rocksoft_fallback)) - return sprintf(buffer, "fallback\n"); - - rcu_read_lock(); - tfm = rcu_dereference(crc64_rocksoft_tfm); - len = snprintf(buffer, PAGE_SIZE, "%s\n", - crypto_shash_driver_name(tfm)); - rcu_read_unlock(); - - return len; -} - -module_param_call(transform, NULL, crc64_rocksoft_transform_show, NULL, 0444); - -MODULE_AUTHOR("Keith Busch <kbusch@kernel.org>"); -MODULE_DESCRIPTION("Rocksoft model CRC64 calculation (library API)"); -MODULE_LICENSE("GPL"); -MODULE_SOFTDEP("pre: crc64"); diff --git a/lib/crc64.c b/lib/crc64.c index 61ae8dfb6a1c..5b1b17057f0a 100644 --- a/lib/crc64.c +++ b/lib/crc64.c @@ -22,8 +22,8 @@ * x^24 + x^23 + x^22 + x^21 + x^19 + x^17 + x^13 + x^12 + x^10 + x^9 + * x^7 + x^4 + x + 1 * - * crc64rocksoft[256] table is from the Rocksoft specification polynomial - * defined as, + * crc64nvmetable[256] uses the CRC64 polynomial from the NVME NVM Command Set + * Specification and uses least-significant-bit first bit order: * * x^64 + x^63 + x^61 + x^59 + x^58 + x^56 + x^55 + x^52 + x^49 + x^48 + x^47 + * x^46 + x^44 + x^41 + x^37 + x^36 + x^34 + x^32 + x^31 + x^28 + x^26 + x^23 + @@ -41,45 +41,18 @@ MODULE_DESCRIPTION("CRC64 calculations"); MODULE_LICENSE("GPL v2"); -/** - * crc64_be - Calculate bitwise big-endian ECMA-182 CRC64 - * @crc: seed value for computation. 0 or (u64)~0 for a new CRC calculation, - * or the previous crc64 value if computing incrementally. - * @p: pointer to buffer over which CRC64 is run - * @len: length of buffer @p - */ -u64 __pure crc64_be(u64 crc, const void *p, size_t len) +u64 crc64_be_generic(u64 crc, const u8 *p, size_t len) { - size_t i, t; - - const unsigned char *_p = p; - - for (i = 0; i < len; i++) { - t = ((crc >> 56) ^ (*_p++)) & 0xFF; - crc = crc64table[t] ^ (crc << 8); - } - + while (len--) + crc = (crc << 8) ^ crc64table[(crc >> 56) ^ *p++]; return crc; } -EXPORT_SYMBOL_GPL(crc64_be); +EXPORT_SYMBOL_GPL(crc64_be_generic); -/** - * crc64_rocksoft_generic - Calculate bitwise Rocksoft CRC64 - * @crc: seed value for computation. 0 for a new CRC calculation, or the - * previous crc64 value if computing incrementally. - * @p: pointer to buffer over which CRC64 is run - * @len: length of buffer @p - */ -u64 __pure crc64_rocksoft_generic(u64 crc, const void *p, size_t len) +u64 crc64_nvme_generic(u64 crc, const u8 *p, size_t len) { - const unsigned char *_p = p; - size_t i; - - crc = ~crc; - - for (i = 0; i < len; i++) - crc = (crc >> 8) ^ crc64rocksofttable[(crc & 0xff) ^ *_p++]; - - return ~crc; + while (len--) + crc = (crc >> 8) ^ crc64nvmetable[(crc & 0xff) ^ *p++]; + return crc; } -EXPORT_SYMBOL_GPL(crc64_rocksoft_generic); +EXPORT_SYMBOL_GPL(crc64_nvme_generic); diff --git a/lib/crc7.c b/lib/crc7.c index 3848e313b722..8dd991cc6114 100644 --- a/lib/crc7.c +++ b/lib/crc7.c @@ -7,14 +7,13 @@ #include <linux/module.h> #include <linux/crc7.h> - /* * Table for CRC-7 (polynomial x^7 + x^3 + 1). * This is a big-endian CRC (msbit is highest power of x), * aligned so the msbit of the byte is the x^6 coefficient * and the lsbit is not used. */ -const u8 crc7_be_syndrome_table[256] = { +static const u8 crc7_be_syndrome_table[256] = { 0x00, 0x12, 0x24, 0x36, 0x48, 0x5a, 0x6c, 0x7e, 0x90, 0x82, 0xb4, 0xa6, 0xd8, 0xca, 0xfc, 0xee, 0x32, 0x20, 0x16, 0x04, 0x7a, 0x68, 0x5e, 0x4c, @@ -48,7 +47,6 @@ const u8 crc7_be_syndrome_table[256] = { 0x1c, 0x0e, 0x38, 0x2a, 0x54, 0x46, 0x70, 0x62, 0x8c, 0x9e, 0xa8, 0xba, 0xc4, 0xd6, 0xe0, 0xf2 }; -EXPORT_SYMBOL(crc7_be_syndrome_table); /** * crc7_be - update the CRC7 for the data buffer @@ -65,7 +63,7 @@ EXPORT_SYMBOL(crc7_be_syndrome_table); u8 crc7_be(u8 crc, const u8 *buffer, size_t len) { while (len--) - crc = crc7_be_byte(crc, *buffer++); + crc = crc7_be_syndrome_table[crc ^ *buffer++]; return crc; } EXPORT_SYMBOL(crc7_be); diff --git a/lib/dump_stack.c b/lib/dump_stack.c index 388da1aea14a..b3a85fe8b673 100644 --- a/lib/dump_stack.c +++ b/lib/dump_stack.c @@ -54,7 +54,7 @@ void __init dump_stack_set_arch_desc(const char *fmt, ...) */ void dump_stack_print_info(const char *log_lvl) { - printk("%sCPU: %d UID: %u PID: %d Comm: %.20s %s%s %s %.*s" BUILD_ID_FMT "\n", + printk("%sCPU: %d UID: %u PID: %d Comm: %.20s %s%s %s %.*s %s " BUILD_ID_FMT "\n", log_lvl, raw_smp_processor_id(), __kuid_val(current_real_cred()->euid), current->pid, current->comm, @@ -62,7 +62,7 @@ void dump_stack_print_info(const char *log_lvl) print_tainted(), init_utsname()->release, (int)strcspn(init_utsname()->version, " "), - init_utsname()->version, BUILD_ID_VAL); + init_utsname()->version, preempt_model_str(), BUILD_ID_VAL); if (get_taint()) printk("%s%s\n", log_lvl, print_tainted_verbose()); diff --git a/lib/gen_crc64table.c b/lib/gen_crc64table.c index 55e222acd0b8..e05a4230a0a0 100644 --- a/lib/gen_crc64table.c +++ b/lib/gen_crc64table.c @@ -17,10 +17,10 @@ #include <stdio.h> #define CRC64_ECMA182_POLY 0x42F0E1EBA9EA3693ULL -#define CRC64_ROCKSOFT_POLY 0x9A6C9329AC4BC9B5ULL +#define CRC64_NVME_POLY 0x9A6C9329AC4BC9B5ULL static uint64_t crc64_table[256] = {0}; -static uint64_t crc64_rocksoft_table[256] = {0}; +static uint64_t crc64_nvme_table[256] = {0}; static void generate_reflected_crc64_table(uint64_t table[256], uint64_t poly) { @@ -82,14 +82,14 @@ static void print_crc64_tables(void) printf("static const u64 ____cacheline_aligned crc64table[256] = {\n"); output_table(crc64_table); - printf("\nstatic const u64 ____cacheline_aligned crc64rocksofttable[256] = {\n"); - output_table(crc64_rocksoft_table); + printf("\nstatic const u64 ____cacheline_aligned crc64nvmetable[256] = {\n"); + output_table(crc64_nvme_table); } int main(int argc, char *argv[]) { generate_crc64_table(crc64_table, CRC64_ECMA182_POLY); - generate_reflected_crc64_table(crc64_rocksoft_table, CRC64_ROCKSOFT_POLY); + generate_reflected_crc64_table(crc64_nvme_table, CRC64_NVME_POLY); print_crc64_tables(); return 0; } diff --git a/lib/math/Makefile b/lib/math/Makefile index 853f023ae537..d1caba23baa0 100644 --- a/lib/math/Makefile +++ b/lib/math/Makefile @@ -5,8 +5,7 @@ obj-$(CONFIG_CORDIC) += cordic.o obj-$(CONFIG_PRIME_NUMBERS) += prime_numbers.o obj-$(CONFIG_RATIONAL) += rational.o -obj-$(CONFIG_INT_POW_TEST) += tests/int_pow_kunit.o obj-$(CONFIG_TEST_DIV64) += test_div64.o obj-$(CONFIG_TEST_MULDIV64) += test_mul_u64_u64_div_u64.o -obj-$(CONFIG_RATIONAL_KUNIT_TEST) += rational-test.o -obj-$(CONFIG_INT_SQRT_KUNIT_TEST) += tests/int_sqrt_kunit.o
\ No newline at end of file + +obj-y += tests/ diff --git a/lib/math/prime_numbers.c b/lib/math/prime_numbers.c index 9a17ee9af93a..95a6f7960db9 100644 --- a/lib/math/prime_numbers.c +++ b/lib/math/prime_numbers.c @@ -1,16 +1,11 @@ // SPDX-License-Identifier: GPL-2.0-only -#define pr_fmt(fmt) "prime numbers: " fmt #include <linux/module.h> #include <linux/mutex.h> #include <linux/prime_numbers.h> #include <linux/slab.h> -struct primes { - struct rcu_head rcu; - unsigned long last, sz; - unsigned long primes[]; -}; +#include "prime_numbers_private.h" #if BITS_PER_LONG == 64 static const struct primes small_primes = { @@ -62,9 +57,25 @@ static const struct primes small_primes = { static DEFINE_MUTEX(lock); static const struct primes __rcu *primes = RCU_INITIALIZER(&small_primes); -static unsigned long selftest_max; +#if IS_ENABLED(CONFIG_PRIME_NUMBERS_KUNIT_TEST) +/* + * Calls the callback under RCU lock. The callback must not retain + * the primes pointer. + */ +void with_primes(void *ctx, primes_fn fn) +{ + rcu_read_lock(); + fn(ctx, rcu_dereference(primes)); + rcu_read_unlock(); +} +EXPORT_SYMBOL(with_primes); + +EXPORT_SYMBOL(slow_is_prime_number); -static bool slow_is_prime_number(unsigned long x) +#else +static +#endif +bool slow_is_prime_number(unsigned long x) { unsigned long y = int_sqrt(x); @@ -239,77 +250,13 @@ bool is_prime_number(unsigned long x) } EXPORT_SYMBOL(is_prime_number); -static void dump_primes(void) -{ - const struct primes *p; - char *buf; - - buf = kmalloc(PAGE_SIZE, GFP_KERNEL); - - rcu_read_lock(); - p = rcu_dereference(primes); - - if (buf) - bitmap_print_to_pagebuf(true, buf, p->primes, p->sz); - pr_info("primes.{last=%lu, .sz=%lu, .primes[]=...x%lx} = %s\n", - p->last, p->sz, p->primes[BITS_TO_LONGS(p->sz) - 1], buf); - - rcu_read_unlock(); - - kfree(buf); -} - -static int selftest(unsigned long max) -{ - unsigned long x, last; - - if (!max) - return 0; - - for (last = 0, x = 2; x < max; x++) { - bool slow = slow_is_prime_number(x); - bool fast = is_prime_number(x); - - if (slow != fast) { - pr_err("inconsistent result for is-prime(%lu): slow=%s, fast=%s!\n", - x, slow ? "yes" : "no", fast ? "yes" : "no"); - goto err; - } - - if (!slow) - continue; - - if (next_prime_number(last) != x) { - pr_err("incorrect result for next-prime(%lu): expected %lu, got %lu\n", - last, x, next_prime_number(last)); - goto err; - } - last = x; - } - - pr_info("%s(%lu) passed, last prime was %lu\n", __func__, x, last); - return 0; - -err: - dump_primes(); - return -EINVAL; -} - -static int __init primes_init(void) -{ - return selftest(selftest_max); -} - static void __exit primes_exit(void) { free_primes(); } -module_init(primes_init); module_exit(primes_exit); -module_param_named(selftest, selftest_max, ulong, 0400); - MODULE_AUTHOR("Intel Corporation"); MODULE_DESCRIPTION("Prime number library"); MODULE_LICENSE("GPL"); diff --git a/lib/math/prime_numbers_private.h b/lib/math/prime_numbers_private.h new file mode 100644 index 000000000000..f3ebf5386e6b --- /dev/null +++ b/lib/math/prime_numbers_private.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#include <linux/types.h> + +struct primes { + struct rcu_head rcu; + unsigned long last, sz; + unsigned long primes[]; +}; + +#if IS_ENABLED(CONFIG_PRIME_NUMBERS_KUNIT_TEST) +typedef void (*primes_fn)(void *, const struct primes *); + +void with_primes(void *ctx, primes_fn fn); +bool slow_is_prime_number(unsigned long x); +#endif diff --git a/lib/math/tests/Makefile b/lib/math/tests/Makefile index e1a79f093b2d..13dc96e48408 100644 --- a/lib/math/tests/Makefile +++ b/lib/math/tests/Makefile @@ -1,4 +1,8 @@ # SPDX-License-Identifier: GPL-2.0-only -obj-$(CONFIG_INT_POW_TEST) += int_pow_kunit.o -obj-$(CONFIG_INT_SQRT_KUNIT_TEST) += int_sqrt_kunit.o +obj-$(CONFIG_GCD_KUNIT_TEST) += gcd_kunit.o +obj-$(CONFIG_INT_LOG_KUNIT_TEST) += int_log_kunit.o +obj-$(CONFIG_INT_POW_KUNIT_TEST) += int_pow_kunit.o +obj-$(CONFIG_INT_SQRT_KUNIT_TEST) += int_sqrt_kunit.o +obj-$(CONFIG_PRIME_NUMBERS_KUNIT_TEST) += prime_numbers_kunit.o +obj-$(CONFIG_RATIONAL_KUNIT_TEST) += rational_kunit.o diff --git a/lib/math/tests/gcd_kunit.c b/lib/math/tests/gcd_kunit.c new file mode 100644 index 000000000000..ede1883583b1 --- /dev/null +++ b/lib/math/tests/gcd_kunit.c @@ -0,0 +1,56 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include <kunit/test.h> +#include <linux/gcd.h> +#include <linux/limits.h> + +struct test_case_params { + unsigned long val1; + unsigned long val2; + unsigned long expected_result; + const char *name; +}; + +static const struct test_case_params params[] = { + { 48, 18, 6, "GCD of 48 and 18" }, + { 18, 48, 6, "GCD of 18 and 48" }, + { 56, 98, 14, "GCD of 56 and 98" }, + { 17, 13, 1, "Coprime numbers" }, + { 101, 103, 1, "Coprime numbers" }, + { 270, 192, 6, "GCD of 270 and 192" }, + { 0, 5, 5, "GCD with zero" }, + { 7, 0, 7, "GCD with zero reversed" }, + { 36, 36, 36, "GCD of identical numbers" }, + { ULONG_MAX, 1, 1, "GCD of max ulong and 1" }, + { ULONG_MAX, ULONG_MAX, ULONG_MAX, "GCD of max ulong values" }, +}; + +static void get_desc(const struct test_case_params *tc, char *desc) +{ + strscpy(desc, tc->name, KUNIT_PARAM_DESC_SIZE); +} + +KUNIT_ARRAY_PARAM(gcd, params, get_desc); + +static void gcd_test(struct kunit *test) +{ + const struct test_case_params *tc = (const struct test_case_params *)test->param_value; + + KUNIT_EXPECT_EQ(test, tc->expected_result, gcd(tc->val1, tc->val2)); +} + +static struct kunit_case math_gcd_test_cases[] = { + KUNIT_CASE_PARAM(gcd_test, gcd_gen_params), + {} +}; + +static struct kunit_suite gcd_test_suite = { + .name = "math-gcd", + .test_cases = math_gcd_test_cases, +}; + +kunit_test_suite(gcd_test_suite); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("math.gcd KUnit test suite"); +MODULE_AUTHOR("Yu-Chun Lin <eleanor15x@gmail.com>"); diff --git a/lib/math/tests/int_log_kunit.c b/lib/math/tests/int_log_kunit.c new file mode 100644 index 000000000000..14e854146cb4 --- /dev/null +++ b/lib/math/tests/int_log_kunit.c @@ -0,0 +1,74 @@ +// SPDX-License-Identifier: GPL-2.0-only +#include <kunit/test.h> +#include <linux/int_log.h> + +struct test_case_params { + u32 value; + unsigned int expected_result; + const char *name; +}; + + +/* The expected result takes into account the log error */ +static const struct test_case_params intlog2_params[] = { + {0, 0, "Log base 2 of 0"}, + {1, 0, "Log base 2 of 1"}, + {2, 16777216, "Log base 2 of 2"}, + {3, 26591232, "Log base 2 of 3"}, + {4, 33554432, "Log base 2 of 4"}, + {8, 50331648, "Log base 2 of 8"}, + {16, 67108864, "Log base 2 of 16"}, + {32, 83886080, "Log base 2 of 32"}, + {U32_MAX, 536870911, "Log base 2 of MAX"}, +}; + +static const struct test_case_params intlog10_params[] = { + {0, 0, "Log base 10 of 0"}, + {1, 0, "Log base 10 of 1"}, + {6, 13055203, "Log base 10 of 6"}, + {10, 16777225, "Log base 10 of 10"}, + {100, 33554450, "Log base 10 of 100"}, + {1000, 50331675, "Log base 10 of 1000"}, + {10000, 67108862, "Log base 10 of 10000"}, + {U32_MAX, 161614247, "Log base 10 of MAX"} +}; + +static void get_desc(const struct test_case_params *tc, char *desc) +{ + strscpy(desc, tc->name, KUNIT_PARAM_DESC_SIZE); +} + + +KUNIT_ARRAY_PARAM(intlog2, intlog2_params, get_desc); + +static void intlog2_test(struct kunit *test) +{ + const struct test_case_params *tc = (const struct test_case_params *)test->param_value; + + KUNIT_EXPECT_EQ(test, tc->expected_result, intlog2(tc->value)); +} + +KUNIT_ARRAY_PARAM(intlog10, intlog10_params, get_desc); + +static void intlog10_test(struct kunit *test) +{ + const struct test_case_params *tc = (const struct test_case_params *)test->param_value; + + KUNIT_EXPECT_EQ(test, tc->expected_result, intlog10(tc->value)); +} + +static struct kunit_case math_int_log_test_cases[] = { + KUNIT_CASE_PARAM(intlog2_test, intlog2_gen_params), + KUNIT_CASE_PARAM(intlog10_test, intlog10_gen_params), + {} +}; + +static struct kunit_suite int_log_test_suite = { + .name = "math-int_log", + .test_cases = math_int_log_test_cases, +}; + +kunit_test_suites(&int_log_test_suite); + +MODULE_DESCRIPTION("math.int_log KUnit test suite"); +MODULE_LICENSE("GPL"); diff --git a/lib/math/tests/prime_numbers_kunit.c b/lib/math/tests/prime_numbers_kunit.c new file mode 100644 index 000000000000..2f1643208c66 --- /dev/null +++ b/lib/math/tests/prime_numbers_kunit.c @@ -0,0 +1,59 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include <kunit/test.h> +#include <linux/module.h> +#include <linux/prime_numbers.h> + +#include "../prime_numbers_private.h" + +static void dump_primes(void *ctx, const struct primes *p) +{ + static char buf[PAGE_SIZE]; + struct kunit_suite *suite = ctx; + + bitmap_print_to_pagebuf(true, buf, p->primes, p->sz); + kunit_info(suite, "primes.{last=%lu, .sz=%lu, .primes[]=...x%lx} = %s", + p->last, p->sz, p->primes[BITS_TO_LONGS(p->sz) - 1], buf); +} + +static void prime_numbers_test(struct kunit *test) +{ + const unsigned long max = 65536; + unsigned long x, last, next; + + for (last = 0, x = 2; x < max; x++) { + const bool slow = slow_is_prime_number(x); + const bool fast = is_prime_number(x); + + KUNIT_ASSERT_EQ_MSG(test, slow, fast, "is-prime(%lu)", x); + + if (!slow) + continue; + + next = next_prime_number(last); + KUNIT_ASSERT_EQ_MSG(test, next, x, "next-prime(%lu)", last); + last = next; + } +} + +static void kunit_suite_exit(struct kunit_suite *suite) +{ + with_primes(suite, dump_primes); +} + +static struct kunit_case prime_numbers_cases[] = { + KUNIT_CASE(prime_numbers_test), + {}, +}; + +static struct kunit_suite prime_numbers_suite = { + .name = "math-prime_numbers", + .suite_exit = kunit_suite_exit, + .test_cases = prime_numbers_cases, +}; + +kunit_test_suite(prime_numbers_suite); + +MODULE_AUTHOR("Intel Corporation"); +MODULE_DESCRIPTION("Prime number library"); +MODULE_LICENSE("GPL"); diff --git a/lib/math/rational-test.c b/lib/math/tests/rational_kunit.c index 47486a95f088..47486a95f088 100644 --- a/lib/math/rational-test.c +++ b/lib/math/tests/rational_kunit.c diff --git a/lib/test_bitmap.c b/lib/test_bitmap.c index 65a75d58ed9e..c83829ef557f 100644 --- a/lib/test_bitmap.c +++ b/lib/test_bitmap.c @@ -100,34 +100,6 @@ __check_eq_pbl(const char *srcfile, unsigned int line, return true; } -static bool __init -__check_eq_u32_array(const char *srcfile, unsigned int line, - const u32 *exp_arr, unsigned int exp_len, - const u32 *arr, unsigned int len) __used; -static bool __init -__check_eq_u32_array(const char *srcfile, unsigned int line, - const u32 *exp_arr, unsigned int exp_len, - const u32 *arr, unsigned int len) -{ - if (exp_len != len) { - pr_warn("[%s:%u] array length differ: expected %u, got %u\n", - srcfile, line, - exp_len, len); - return false; - } - - if (memcmp(exp_arr, arr, len*sizeof(*arr))) { - pr_warn("[%s:%u] array contents differ\n", srcfile, line); - print_hex_dump(KERN_WARNING, " exp: ", DUMP_PREFIX_OFFSET, - 32, 4, exp_arr, exp_len*sizeof(*exp_arr), false); - print_hex_dump(KERN_WARNING, " got: ", DUMP_PREFIX_OFFSET, - 32, 4, arr, len*sizeof(*arr), false); - return false; - } - - return true; -} - static bool __init __check_eq_clump8(const char *srcfile, unsigned int line, const unsigned int offset, const unsigned int size, diff --git a/lib/test_objpool.c b/lib/test_objpool.c index 896c0131c9a8..8f688187fa87 100644 --- a/lib/test_objpool.c +++ b/lib/test_objpool.c @@ -190,8 +190,7 @@ static int ot_init_hrtimer(struct ot_item *item, unsigned long hrtimer) return -ENOENT; item->hrtcycle = ktime_set(0, hrtimer * 1000000UL); - hrtimer_init(hrt, CLOCK_MONOTONIC, HRTIMER_MODE_REL); - hrt->function = ot_hrtimer_handler; + hrtimer_setup(hrt, ot_hrtimer_handler, CLOCK_MONOTONIC, HRTIMER_MODE_REL); return 0; } diff --git a/lib/test_ubsan.c b/lib/test_ubsan.c index 5d7b10e98610..8772e5edaa4f 100644 --- a/lib/test_ubsan.c +++ b/lib/test_ubsan.c @@ -15,7 +15,7 @@ static void test_ubsan_add_overflow(void) { volatile int val = INT_MAX; - UBSAN_TEST(CONFIG_UBSAN_SIGNED_WRAP); + UBSAN_TEST(CONFIG_UBSAN_INTEGER_WRAP); val += 2; } @@ -24,7 +24,7 @@ static void test_ubsan_sub_overflow(void) volatile int val = INT_MIN; volatile int val2 = 2; - UBSAN_TEST(CONFIG_UBSAN_SIGNED_WRAP); + UBSAN_TEST(CONFIG_UBSAN_INTEGER_WRAP); val -= val2; } @@ -32,7 +32,7 @@ static void test_ubsan_mul_overflow(void) { volatile int val = INT_MAX / 2; - UBSAN_TEST(CONFIG_UBSAN_SIGNED_WRAP); + UBSAN_TEST(CONFIG_UBSAN_INTEGER_WRAP); val *= 3; } @@ -40,7 +40,7 @@ static void test_ubsan_negate_overflow(void) { volatile int val = INT_MIN; - UBSAN_TEST(CONFIG_UBSAN_SIGNED_WRAP); + UBSAN_TEST(CONFIG_UBSAN_INTEGER_WRAP); val = -val; } @@ -53,6 +53,15 @@ static void test_ubsan_divrem_overflow(void) val /= val2; } +static void test_ubsan_truncate_signed(void) +{ + volatile long val = LONG_MAX; + volatile int val2 = 0; + + UBSAN_TEST(CONFIG_UBSAN_INTEGER_WRAP); + val2 = val; +} + static void test_ubsan_shift_out_of_bounds(void) { volatile int neg = -1, wrap = 4; @@ -127,6 +136,7 @@ static const test_ubsan_fp test_ubsan_array[] = { test_ubsan_sub_overflow, test_ubsan_mul_overflow, test_ubsan_negate_overflow, + test_ubsan_truncate_signed, test_ubsan_shift_out_of_bounds, test_ubsan_out_of_bounds, test_ubsan_load_invalid_value, diff --git a/lib/tests/Makefile b/lib/tests/Makefile index 8e4f42cb9c54..498915255860 100644 --- a/lib/tests/Makefile +++ b/lib/tests/Makefile @@ -1 +1,44 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Makefile for tests of kernel library functions. + +# KUnit tests +CFLAGS_bitfield_kunit.o := $(DISABLE_STRUCTLEAK_PLUGIN) +obj-$(CONFIG_BITFIELD_KUNIT) += bitfield_kunit.o +obj-$(CONFIG_BITS_TEST) += test_bits.o +obj-$(CONFIG_CHECKSUM_KUNIT) += checksum_kunit.o +obj-$(CONFIG_CMDLINE_KUNIT_TEST) += cmdline_kunit.o +obj-$(CONFIG_CPUMASK_KUNIT_TEST) += cpumask_kunit.o +obj-$(CONFIG_CRC_KUNIT_TEST) += crc_kunit.o +CFLAGS_fortify_kunit.o += $(call cc-disable-warning, unsequenced) +CFLAGS_fortify_kunit.o += $(call cc-disable-warning, stringop-overread) +CFLAGS_fortify_kunit.o += $(call cc-disable-warning, stringop-truncation) +CFLAGS_fortify_kunit.o += $(DISABLE_STRUCTLEAK_PLUGIN) +obj-$(CONFIG_FORTIFY_KUNIT_TEST) += fortify_kunit.o +CFLAGS_test_fprobe.o += $(CC_FLAGS_FTRACE) +obj-$(CONFIG_FPROBE_SANITY_TEST) += test_fprobe.o +obj-$(CONFIG_HASHTABLE_KUNIT_TEST) += hashtable_test.o +obj-$(CONFIG_HASH_KUNIT_TEST) += test_hash.o +obj-$(CONFIG_TEST_IOV_ITER) += kunit_iov_iter.o +obj-$(CONFIG_IS_SIGNED_TYPE_KUNIT_TEST) += is_signed_type_kunit.o +obj-$(CONFIG_KPROBES_SANITY_TEST) += test_kprobes.o +obj-$(CONFIG_LIST_KUNIT_TEST) += list-test.o +obj-$(CONFIG_KFIFO_KUNIT_TEST) += kfifo_kunit.o +obj-$(CONFIG_TEST_LIST_SORT) += test_list_sort.o +obj-$(CONFIG_LINEAR_RANGES_TEST) += test_linear_ranges.o +obj-$(CONFIG_MEMCPY_KUNIT_TEST) += memcpy_kunit.o +CFLAGS_overflow_kunit.o = $(call cc-disable-warning, tautological-constant-out-of-range-compare) +obj-$(CONFIG_OVERFLOW_KUNIT_TEST) += overflow_kunit.o +obj-$(CONFIG_PRINTF_KUNIT_TEST) += printf_kunit.o +obj-$(CONFIG_SCANF_KUNIT_TEST) += scanf_kunit.o +obj-$(CONFIG_SIPHASH_KUNIT_TEST) += siphash_kunit.o +obj-$(CONFIG_SLUB_KUNIT_TEST) += slub_kunit.o +obj-$(CONFIG_TEST_SORT) += test_sort.o +CFLAGS_stackinit_kunit.o += $(call cc-disable-warning, switch-unreachable) +obj-$(CONFIG_STACKINIT_KUNIT_TEST) += stackinit_kunit.o +obj-$(CONFIG_STRING_KUNIT_TEST) += string_kunit.o +obj-$(CONFIG_STRING_HELPERS_KUNIT_TEST) += string_helpers_kunit.o +obj-$(CONFIG_USERCOPY_KUNIT_TEST) += usercopy_kunit.o +obj-$(CONFIG_UTIL_MACROS_KUNIT) += util_macros_kunit.o + obj-$(CONFIG_TEST_RUNTIME_MODULE) += module/ diff --git a/lib/bitfield_kunit.c b/lib/tests/bitfield_kunit.c index 5ccd86f61896..5ccd86f61896 100644 --- a/lib/bitfield_kunit.c +++ b/lib/tests/bitfield_kunit.c diff --git a/lib/checksum_kunit.c b/lib/tests/checksum_kunit.c index be04aa42125c..be04aa42125c 100644 --- a/lib/checksum_kunit.c +++ b/lib/tests/checksum_kunit.c diff --git a/lib/cmdline_kunit.c b/lib/tests/cmdline_kunit.c index c1602f797637..c1602f797637 100644 --- a/lib/cmdline_kunit.c +++ b/lib/tests/cmdline_kunit.c diff --git a/lib/cpumask_kunit.c b/lib/tests/cpumask_kunit.c index 6b62a6bdd50e..6b62a6bdd50e 100644 --- a/lib/cpumask_kunit.c +++ b/lib/tests/cpumask_kunit.c diff --git a/lib/crc_kunit.c b/lib/tests/crc_kunit.c index 6a61d4b5fd45..585c48b65cef 100644 --- a/lib/crc_kunit.c +++ b/lib/tests/crc_kunit.c @@ -7,6 +7,7 @@ * Author: Eric Biggers <ebiggers@google.com> */ #include <kunit/test.h> +#include <linux/crc7.h> #include <linux/crc16.h> #include <linux/crc-t10dif.h> #include <linux/crc32.h> @@ -32,7 +33,9 @@ static size_t test_buflen; * @poly: The generator polynomial with the highest-order term omitted. * Bit-reversed if @le is true. * @func: The function to compute a CRC. The type signature uses u64 so that it - * can fit any CRC up to CRC-64. + * can fit any CRC up to CRC-64. The CRC is passed in, and is expected + * to be returned in, the least significant bits of the u64. The + * function is expected to *not* invert the CRC at the beginning and end. * @combine_func: Optional function to combine two CRCs. */ struct crc_variant { @@ -223,8 +226,9 @@ crc_benchmark(struct kunit *test, }; size_t len, i, j, num_iters; /* - * Some of the CRC library functions are marked as __pure, so use - * volatile to ensure that all calls are really made as intended. + * The CRC value that this function computes in a series of calls to + * crc_func is never actually used, so use volatile to ensure that the + * computations are done as intended and don't all get optimized out. */ volatile u64 crc = 0; u64 t; @@ -251,6 +255,33 @@ crc_benchmark(struct kunit *test, } } +/* crc7_be */ + +static u64 crc7_be_wrapper(u64 crc, const u8 *p, size_t len) +{ + /* + * crc7_be() left-aligns the 7-bit CRC in a u8, whereas the test wants a + * right-aligned CRC (in a u64). Convert between the conventions. + */ + return crc7_be(crc << 1, p, len) >> 1; +} + +static const struct crc_variant crc_variant_crc7_be = { + .bits = 7, + .poly = 0x9, + .func = crc7_be_wrapper, +}; + +static void crc7_be_test(struct kunit *test) +{ + crc_test(test, &crc_variant_crc7_be); +} + +static void crc7_be_benchmark(struct kunit *test) +{ + crc_benchmark(test, crc7_be_wrapper); +} + /* crc16 */ static u64 crc16_wrapper(u64 crc, const u8 *p, size_t len) @@ -362,7 +393,7 @@ static u64 crc32c_wrapper(u64 crc, const u8 *p, size_t len) static u64 crc32c_combine_wrapper(u64 crc1, u64 crc2, size_t len2) { - return __crc32c_le_combine(crc1, crc2, len2); + return crc32c_combine(crc1, crc2, len2); } static const struct crc_variant crc_variant_crc32c = { @@ -407,7 +438,34 @@ static void crc64_be_benchmark(struct kunit *test) crc_benchmark(test, crc64_be_wrapper); } +/* crc64_nvme */ + +static u64 crc64_nvme_wrapper(u64 crc, const u8 *p, size_t len) +{ + /* The inversions that crc64_nvme() does have to be undone here. */ + return ~crc64_nvme(~crc, p, len); +} + +static const struct crc_variant crc_variant_crc64_nvme = { + .bits = 64, + .le = true, + .poly = 0x9a6c9329ac4bc9b5, + .func = crc64_nvme_wrapper, +}; + +static void crc64_nvme_test(struct kunit *test) +{ + crc_test(test, &crc_variant_crc64_nvme); +} + +static void crc64_nvme_benchmark(struct kunit *test) +{ + crc_benchmark(test, crc64_nvme_wrapper); +} + static struct kunit_case crc_test_cases[] = { + KUNIT_CASE(crc7_be_test), + KUNIT_CASE(crc7_be_benchmark), KUNIT_CASE(crc16_test), KUNIT_CASE(crc16_benchmark), KUNIT_CASE(crc_t10dif_test), @@ -420,6 +478,8 @@ static struct kunit_case crc_test_cases[] = { KUNIT_CASE(crc32c_benchmark), KUNIT_CASE(crc64_be_test), KUNIT_CASE(crc64_be_benchmark), + KUNIT_CASE(crc64_nvme_test), + KUNIT_CASE(crc64_nvme_benchmark), {}, }; diff --git a/lib/fortify_kunit.c b/lib/tests/fortify_kunit.c index ecb638d4cde1..29ffc62a71e3 100644 --- a/lib/fortify_kunit.c +++ b/lib/tests/fortify_kunit.c @@ -60,6 +60,7 @@ static int fortify_write_overflows; static const char array_of_10[] = "this is 10"; static const char *ptr_of_11 = "this is 11!"; +static const char * const unchanging_12 = "this is 12!!"; static char array_unknown[] = "compiler thinks I might change"; void fortify_add_kunit_error(int write) @@ -83,12 +84,28 @@ void fortify_add_kunit_error(int write) static void fortify_test_known_sizes(struct kunit *test) { + char stack[80] = "Test!"; + + KUNIT_EXPECT_FALSE(test, __is_constexpr(__builtin_strlen(stack))); + KUNIT_EXPECT_EQ(test, __compiletime_strlen(stack), 5); + + KUNIT_EXPECT_TRUE(test, __is_constexpr(__builtin_strlen("88888888"))); KUNIT_EXPECT_EQ(test, __compiletime_strlen("88888888"), 8); + + KUNIT_EXPECT_TRUE(test, __is_constexpr(__builtin_strlen(array_of_10))); KUNIT_EXPECT_EQ(test, __compiletime_strlen(array_of_10), 10); + + KUNIT_EXPECT_FALSE(test, __is_constexpr(__builtin_strlen(ptr_of_11))); KUNIT_EXPECT_EQ(test, __compiletime_strlen(ptr_of_11), 11); + KUNIT_EXPECT_TRUE(test, __is_constexpr(__builtin_strlen(unchanging_12))); + KUNIT_EXPECT_EQ(test, __compiletime_strlen(unchanging_12), 12); + + KUNIT_EXPECT_FALSE(test, __is_constexpr(__builtin_strlen(array_unknown))); KUNIT_EXPECT_EQ(test, __compiletime_strlen(array_unknown), SIZE_MAX); + /* Externally defined and dynamically sized string pointer: */ + KUNIT_EXPECT_FALSE(test, __is_constexpr(__builtin_strlen(test->name))); KUNIT_EXPECT_EQ(test, __compiletime_strlen(test->name), SIZE_MAX); } @@ -394,8 +411,6 @@ struct fortify_padding { char buf[32]; unsigned long bytes_after; }; -/* Force compiler into not being able to resolve size at compile-time. */ -static volatile int unconst; static void fortify_test_strlen(struct kunit *test) { @@ -520,57 +535,56 @@ static void fortify_test_strncpy(struct kunit *test) { struct fortify_padding pad = { }; char src[] = "Copy me fully into a small buffer and I will overflow!"; + size_t sizeof_buf = sizeof(pad.buf); + + OPTIMIZER_HIDE_VAR(sizeof_buf); /* Destination is %NUL-filled to start with. */ KUNIT_EXPECT_EQ(test, pad.bytes_before, 0); - KUNIT_EXPECT_EQ(test, pad.buf[sizeof(pad.buf) - 1], '\0'); - KUNIT_EXPECT_EQ(test, pad.buf[sizeof(pad.buf) - 2], '\0'); - KUNIT_EXPECT_EQ(test, pad.buf[sizeof(pad.buf) - 3], '\0'); + KUNIT_EXPECT_EQ(test, pad.buf[sizeof_buf - 1], '\0'); + KUNIT_EXPECT_EQ(test, pad.buf[sizeof_buf - 2], '\0'); + KUNIT_EXPECT_EQ(test, pad.buf[sizeof_buf - 3], '\0'); KUNIT_EXPECT_EQ(test, pad.bytes_after, 0); /* Legitimate strncpy() 1 less than of max size. */ - KUNIT_ASSERT_TRUE(test, strncpy(pad.buf, src, - sizeof(pad.buf) + unconst - 1) + KUNIT_ASSERT_TRUE(test, strncpy(pad.buf, src, sizeof_buf - 1) == pad.buf); KUNIT_EXPECT_EQ(test, fortify_write_overflows, 0); /* Only last byte should be %NUL */ - KUNIT_EXPECT_EQ(test, pad.buf[sizeof(pad.buf) - 1], '\0'); - KUNIT_EXPECT_NE(test, pad.buf[sizeof(pad.buf) - 2], '\0'); - KUNIT_EXPECT_NE(test, pad.buf[sizeof(pad.buf) - 3], '\0'); + KUNIT_EXPECT_EQ(test, pad.buf[sizeof_buf - 1], '\0'); + KUNIT_EXPECT_NE(test, pad.buf[sizeof_buf - 2], '\0'); + KUNIT_EXPECT_NE(test, pad.buf[sizeof_buf - 3], '\0'); /* Legitimate (though unterminated) max-size strncpy. */ - KUNIT_ASSERT_TRUE(test, strncpy(pad.buf, src, - sizeof(pad.buf) + unconst) + KUNIT_ASSERT_TRUE(test, strncpy(pad.buf, src, sizeof_buf) == pad.buf); KUNIT_EXPECT_EQ(test, fortify_write_overflows, 0); /* No trailing %NUL -- thanks strncpy API. */ - KUNIT_EXPECT_NE(test, pad.buf[sizeof(pad.buf) - 1], '\0'); - KUNIT_EXPECT_NE(test, pad.buf[sizeof(pad.buf) - 2], '\0'); - KUNIT_EXPECT_NE(test, pad.buf[sizeof(pad.buf) - 2], '\0'); + KUNIT_EXPECT_NE(test, pad.buf[sizeof_buf - 1], '\0'); + KUNIT_EXPECT_NE(test, pad.buf[sizeof_buf - 2], '\0'); + KUNIT_EXPECT_NE(test, pad.buf[sizeof_buf - 2], '\0'); /* But we will not have gone beyond. */ KUNIT_EXPECT_EQ(test, pad.bytes_after, 0); /* Now verify that FORTIFY is working... */ - KUNIT_ASSERT_TRUE(test, strncpy(pad.buf, src, - sizeof(pad.buf) + unconst + 1) + KUNIT_ASSERT_TRUE(test, strncpy(pad.buf, src, sizeof_buf + 1) == pad.buf); /* Should catch the overflow. */ KUNIT_EXPECT_EQ(test, fortify_write_overflows, 1); - KUNIT_EXPECT_NE(test, pad.buf[sizeof(pad.buf) - 1], '\0'); - KUNIT_EXPECT_NE(test, pad.buf[sizeof(pad.buf) - 2], '\0'); - KUNIT_EXPECT_NE(test, pad.buf[sizeof(pad.buf) - 2], '\0'); + KUNIT_EXPECT_NE(test, pad.buf[sizeof_buf - 1], '\0'); + KUNIT_EXPECT_NE(test, pad.buf[sizeof_buf - 2], '\0'); + KUNIT_EXPECT_NE(test, pad.buf[sizeof_buf - 2], '\0'); /* And we will not have gone beyond. */ KUNIT_EXPECT_EQ(test, pad.bytes_after, 0); /* And further... */ - KUNIT_ASSERT_TRUE(test, strncpy(pad.buf, src, - sizeof(pad.buf) + unconst + 2) + KUNIT_ASSERT_TRUE(test, strncpy(pad.buf, src, sizeof_buf + 2) == pad.buf); /* Should catch the overflow. */ KUNIT_EXPECT_EQ(test, fortify_write_overflows, 2); - KUNIT_EXPECT_NE(test, pad.buf[sizeof(pad.buf) - 1], '\0'); - KUNIT_EXPECT_NE(test, pad.buf[sizeof(pad.buf) - 2], '\0'); - KUNIT_EXPECT_NE(test, pad.buf[sizeof(pad.buf) - 2], '\0'); + KUNIT_EXPECT_NE(test, pad.buf[sizeof_buf - 1], '\0'); + KUNIT_EXPECT_NE(test, pad.buf[sizeof_buf - 2], '\0'); + KUNIT_EXPECT_NE(test, pad.buf[sizeof_buf - 2], '\0'); /* And we will not have gone beyond. */ KUNIT_EXPECT_EQ(test, pad.bytes_after, 0); } @@ -579,55 +593,56 @@ static void fortify_test_strscpy(struct kunit *test) { struct fortify_padding pad = { }; char src[] = "Copy me fully into a small buffer and I will overflow!"; + size_t sizeof_buf = sizeof(pad.buf); + size_t sizeof_src = sizeof(src); + + OPTIMIZER_HIDE_VAR(sizeof_buf); + OPTIMIZER_HIDE_VAR(sizeof_src); /* Destination is %NUL-filled to start with. */ KUNIT_EXPECT_EQ(test, pad.bytes_before, 0); - KUNIT_EXPECT_EQ(test, pad.buf[sizeof(pad.buf) - 1], '\0'); - KUNIT_EXPECT_EQ(test, pad.buf[sizeof(pad.buf) - 2], '\0'); - KUNIT_EXPECT_EQ(test, pad.buf[sizeof(pad.buf) - 3], '\0'); + KUNIT_EXPECT_EQ(test, pad.buf[sizeof_buf - 1], '\0'); + KUNIT_EXPECT_EQ(test, pad.buf[sizeof_buf - 2], '\0'); + KUNIT_EXPECT_EQ(test, pad.buf[sizeof_buf - 3], '\0'); KUNIT_EXPECT_EQ(test, pad.bytes_after, 0); /* Legitimate strscpy() 1 less than of max size. */ - KUNIT_ASSERT_EQ(test, strscpy(pad.buf, src, - sizeof(pad.buf) + unconst - 1), + KUNIT_ASSERT_EQ(test, strscpy(pad.buf, src, sizeof_buf - 1), -E2BIG); KUNIT_EXPECT_EQ(test, fortify_write_overflows, 0); /* Keeping space for %NUL, last two bytes should be %NUL */ - KUNIT_EXPECT_EQ(test, pad.buf[sizeof(pad.buf) - 1], '\0'); - KUNIT_EXPECT_EQ(test, pad.buf[sizeof(pad.buf) - 2], '\0'); - KUNIT_EXPECT_NE(test, pad.buf[sizeof(pad.buf) - 3], '\0'); + KUNIT_EXPECT_EQ(test, pad.buf[sizeof_buf - 1], '\0'); + KUNIT_EXPECT_EQ(test, pad.buf[sizeof_buf - 2], '\0'); + KUNIT_EXPECT_NE(test, pad.buf[sizeof_buf - 3], '\0'); /* Legitimate max-size strscpy. */ - KUNIT_ASSERT_EQ(test, strscpy(pad.buf, src, - sizeof(pad.buf) + unconst), + KUNIT_ASSERT_EQ(test, strscpy(pad.buf, src, sizeof_buf), -E2BIG); KUNIT_EXPECT_EQ(test, fortify_write_overflows, 0); /* A trailing %NUL will exist. */ - KUNIT_EXPECT_EQ(test, pad.buf[sizeof(pad.buf) - 1], '\0'); - KUNIT_EXPECT_NE(test, pad.buf[sizeof(pad.buf) - 2], '\0'); - KUNIT_EXPECT_NE(test, pad.buf[sizeof(pad.buf) - 2], '\0'); + KUNIT_EXPECT_EQ(test, pad.buf[sizeof_buf - 1], '\0'); + KUNIT_EXPECT_NE(test, pad.buf[sizeof_buf - 2], '\0'); + KUNIT_EXPECT_NE(test, pad.buf[sizeof_buf - 2], '\0'); /* Now verify that FORTIFY is working... */ - KUNIT_ASSERT_EQ(test, strscpy(pad.buf, src, - sizeof(pad.buf) + unconst + 1), + KUNIT_ASSERT_EQ(test, strscpy(pad.buf, src, sizeof_buf + 1), -E2BIG); /* Should catch the overflow. */ KUNIT_EXPECT_EQ(test, fortify_write_overflows, 1); - KUNIT_EXPECT_EQ(test, pad.buf[sizeof(pad.buf) - 1], '\0'); - KUNIT_EXPECT_NE(test, pad.buf[sizeof(pad.buf) - 2], '\0'); - KUNIT_EXPECT_NE(test, pad.buf[sizeof(pad.buf) - 2], '\0'); + KUNIT_EXPECT_EQ(test, pad.buf[sizeof_buf - 1], '\0'); + KUNIT_EXPECT_NE(test, pad.buf[sizeof_buf - 2], '\0'); + KUNIT_EXPECT_NE(test, pad.buf[sizeof_buf - 2], '\0'); /* And we will not have gone beyond. */ KUNIT_EXPECT_EQ(test, pad.bytes_after, 0); /* And much further... */ - KUNIT_ASSERT_EQ(test, strscpy(pad.buf, src, - sizeof(src) * 2 + unconst), + KUNIT_ASSERT_EQ(test, strscpy(pad.buf, src, sizeof_src * 2), -E2BIG); /* Should catch the overflow. */ KUNIT_EXPECT_EQ(test, fortify_write_overflows, 2); - KUNIT_EXPECT_EQ(test, pad.buf[sizeof(pad.buf) - 1], '\0'); - KUNIT_EXPECT_NE(test, pad.buf[sizeof(pad.buf) - 2], '\0'); - KUNIT_EXPECT_NE(test, pad.buf[sizeof(pad.buf) - 2], '\0'); + KUNIT_EXPECT_EQ(test, pad.buf[sizeof_buf - 1], '\0'); + KUNIT_EXPECT_NE(test, pad.buf[sizeof_buf - 2], '\0'); + KUNIT_EXPECT_NE(test, pad.buf[sizeof_buf - 2], '\0'); /* And we will not have gone beyond. */ KUNIT_EXPECT_EQ(test, pad.bytes_after, 0); } @@ -767,7 +782,9 @@ static void fortify_test_strlcat(struct kunit *test) struct fortify_padding pad = { }; char src[sizeof(pad.buf)] = { }; int i, partial; - int len = sizeof(pad.buf) + unconst; + int len = sizeof(pad.buf); + + OPTIMIZER_HIDE_VAR(len); /* Fill 15 bytes with valid characters. */ partial = sizeof(src) / 2 - 1; @@ -857,28 +874,32 @@ struct fortify_zero_sized { #define __fortify_test(memfunc) \ static void fortify_test_##memfunc(struct kunit *test) \ { \ - struct fortify_zero_sized zero = { }; \ + struct fortify_zero_sized empty = { }; \ struct fortify_padding pad = { }; \ char srcA[sizeof(pad.buf) + 2]; \ char srcB[sizeof(pad.buf) + 2]; \ - size_t len = sizeof(pad.buf) + unconst; \ + size_t len = sizeof(pad.buf); \ + size_t zero = 0; \ + \ + OPTIMIZER_HIDE_VAR(len); \ + OPTIMIZER_HIDE_VAR(zero); \ \ memset(srcA, 'A', sizeof(srcA)); \ KUNIT_ASSERT_EQ(test, srcA[0], 'A'); \ memset(srcB, 'B', sizeof(srcB)); \ KUNIT_ASSERT_EQ(test, srcB[0], 'B'); \ \ - memfunc(pad.buf, srcA, 0 + unconst); \ + memfunc(pad.buf, srcA, zero); \ KUNIT_EXPECT_EQ(test, pad.buf[0], '\0'); \ KUNIT_EXPECT_EQ(test, fortify_read_overflows, 0); \ KUNIT_EXPECT_EQ(test, fortify_write_overflows, 0); \ - memfunc(pad.buf + 1, srcB, 1 + unconst); \ + memfunc(pad.buf + 1, srcB, zero + 1); \ KUNIT_EXPECT_EQ(test, pad.buf[0], '\0'); \ KUNIT_EXPECT_EQ(test, pad.buf[1], 'B'); \ KUNIT_EXPECT_EQ(test, pad.buf[2], '\0'); \ KUNIT_EXPECT_EQ(test, fortify_read_overflows, 0); \ KUNIT_EXPECT_EQ(test, fortify_write_overflows, 0); \ - memfunc(pad.buf, srcA, 1 + unconst); \ + memfunc(pad.buf, srcA, zero + 1); \ KUNIT_EXPECT_EQ(test, pad.buf[0], 'A'); \ KUNIT_EXPECT_EQ(test, pad.buf[1], 'B'); \ KUNIT_EXPECT_EQ(test, fortify_read_overflows, 0); \ @@ -904,10 +925,10 @@ static void fortify_test_##memfunc(struct kunit *test) \ /* Reset error counter. */ \ fortify_write_overflows = 0; \ /* Copy nothing into nothing: no errors. */ \ - memfunc(zero.buf, srcB, 0 + unconst); \ + memfunc(empty.buf, srcB, zero); \ KUNIT_EXPECT_EQ(test, fortify_read_overflows, 0); \ KUNIT_EXPECT_EQ(test, fortify_write_overflows, 0); \ - memfunc(zero.buf, srcB, 1 + unconst); \ + memfunc(empty.buf, srcB, zero + 1); \ KUNIT_EXPECT_EQ(test, fortify_read_overflows, 0); \ KUNIT_EXPECT_EQ(test, fortify_write_overflows, 1); \ } @@ -919,7 +940,9 @@ static void fortify_test_memscan(struct kunit *test) char haystack[] = "Where oh where is my memory range?"; char *mem = haystack + strlen("Where oh where is "); char needle = 'm'; - size_t len = sizeof(haystack) + unconst; + size_t len = sizeof(haystack); + + OPTIMIZER_HIDE_VAR(len); KUNIT_ASSERT_PTR_EQ(test, memscan(haystack, needle, len), mem); @@ -938,7 +961,9 @@ static void fortify_test_memchr(struct kunit *test) char haystack[] = "Where oh where is my memory range?"; char *mem = haystack + strlen("Where oh where is "); char needle = 'm'; - size_t len = sizeof(haystack) + unconst; + size_t len = sizeof(haystack); + + OPTIMIZER_HIDE_VAR(len); KUNIT_ASSERT_PTR_EQ(test, memchr(haystack, needle, len), mem); @@ -957,7 +982,9 @@ static void fortify_test_memchr_inv(struct kunit *test) char haystack[] = "Where oh where is my memory range?"; char *mem = haystack + 1; char needle = 'W'; - size_t len = sizeof(haystack) + unconst; + size_t len = sizeof(haystack); + + OPTIMIZER_HIDE_VAR(len); /* Normal search is okay. */ KUNIT_ASSERT_PTR_EQ(test, memchr_inv(haystack, needle, len), @@ -976,8 +1003,11 @@ static void fortify_test_memcmp(struct kunit *test) { char one[] = "My mind is going ..."; char two[] = "My mind is going ... I can feel it."; - size_t one_len = sizeof(one) + unconst - 1; - size_t two_len = sizeof(two) + unconst - 1; + size_t one_len = sizeof(one) - 1; + size_t two_len = sizeof(two) - 1; + + OPTIMIZER_HIDE_VAR(one_len); + OPTIMIZER_HIDE_VAR(two_len); /* We match the first string (ignoring the %NUL). */ KUNIT_ASSERT_EQ(test, memcmp(one, two, one_len), 0); @@ -998,7 +1028,9 @@ static void fortify_test_kmemdup(struct kunit *test) { char src[] = "I got Doom running on it!"; char *copy; - size_t len = sizeof(src) + unconst; + size_t len = sizeof(src); + + OPTIMIZER_HIDE_VAR(len); /* Copy is within bounds. */ copy = kmemdup(src, len, GFP_KERNEL); diff --git a/lib/hashtable_test.c b/lib/tests/hashtable_test.c index 3521de6bad15..3521de6bad15 100644 --- a/lib/hashtable_test.c +++ b/lib/tests/hashtable_test.c diff --git a/lib/is_signed_type_kunit.c b/lib/tests/is_signed_type_kunit.c index 88adbe813f3a..88adbe813f3a 100644 --- a/lib/is_signed_type_kunit.c +++ b/lib/tests/is_signed_type_kunit.c diff --git a/lib/tests/kfifo_kunit.c b/lib/tests/kfifo_kunit.c new file mode 100644 index 000000000000..a85eedc3195a --- /dev/null +++ b/lib/tests/kfifo_kunit.c @@ -0,0 +1,224 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * KUnit test for the generic kernel FIFO implementation. + * + * Copyright (C) 2024 Diego Vieira <diego.daniel.professional@gmail.com> + */ +#include <kunit/test.h> + +#include <linux/kfifo.h> + +#define KFIFO_SIZE 32 +#define N_ELEMENTS 5 + +static void kfifo_test_reset_should_clear_the_fifo(struct kunit *test) +{ + DEFINE_KFIFO(my_fifo, u8, KFIFO_SIZE); + + kfifo_put(&my_fifo, 1); + kfifo_put(&my_fifo, 2); + kfifo_put(&my_fifo, 3); + KUNIT_EXPECT_EQ(test, kfifo_len(&my_fifo), 3); + + kfifo_reset(&my_fifo); + + KUNIT_EXPECT_EQ(test, kfifo_len(&my_fifo), 0); + KUNIT_EXPECT_TRUE(test, kfifo_is_empty(&my_fifo)); +} + +static void kfifo_test_define_should_define_an_empty_fifo(struct kunit *test) +{ + DEFINE_KFIFO(my_fifo, u8, KFIFO_SIZE); + + KUNIT_EXPECT_TRUE(test, kfifo_initialized(&my_fifo)); + KUNIT_EXPECT_TRUE(test, kfifo_is_empty(&my_fifo)); + KUNIT_EXPECT_EQ(test, kfifo_len(&my_fifo), 0); +} + +static void kfifo_test_len_should_ret_n_of_stored_elements(struct kunit *test) +{ + u8 buffer1[N_ELEMENTS]; + + for (int i = 0; i < N_ELEMENTS; i++) + buffer1[i] = i + 1; + + DEFINE_KFIFO(my_fifo, u8, KFIFO_SIZE); + + KUNIT_EXPECT_EQ(test, kfifo_len(&my_fifo), 0); + + kfifo_in(&my_fifo, buffer1, N_ELEMENTS); + KUNIT_EXPECT_EQ(test, kfifo_len(&my_fifo), N_ELEMENTS); + + kfifo_in(&my_fifo, buffer1, N_ELEMENTS); + KUNIT_EXPECT_EQ(test, kfifo_len(&my_fifo), N_ELEMENTS * 2); + + kfifo_reset(&my_fifo); + KUNIT_EXPECT_EQ(test, kfifo_len(&my_fifo), 0); +} + +static void kfifo_test_put_should_insert_and_get_should_pop(struct kunit *test) +{ + u8 out_data = 0; + int processed_elements; + u8 elements[] = { 3, 5, 11 }; + + DEFINE_KFIFO(my_fifo, u8, KFIFO_SIZE); + + // If the fifo is empty, get returns 0 + processed_elements = kfifo_get(&my_fifo, &out_data); + KUNIT_EXPECT_EQ(test, processed_elements, 0); + KUNIT_EXPECT_EQ(test, out_data, 0); + + for (int i = 0; i < 3; i++) + kfifo_put(&my_fifo, elements[i]); + + for (int i = 0; i < 3; i++) { + processed_elements = kfifo_get(&my_fifo, &out_data); + KUNIT_EXPECT_EQ(test, processed_elements, 1); + KUNIT_EXPECT_EQ(test, out_data, elements[i]); + } +} + +static void kfifo_test_in_should_insert_multiple_elements(struct kunit *test) +{ + u8 in_buffer[] = { 11, 25, 65 }; + u8 out_data; + int processed_elements; + + DEFINE_KFIFO(my_fifo, u8, KFIFO_SIZE); + + kfifo_in(&my_fifo, in_buffer, 3); + + for (int i = 0; i < 3; i++) { + processed_elements = kfifo_get(&my_fifo, &out_data); + KUNIT_EXPECT_EQ(test, processed_elements, 1); + KUNIT_EXPECT_EQ(test, out_data, in_buffer[i]); + } +} + +static void kfifo_test_out_should_pop_multiple_elements(struct kunit *test) +{ + u8 in_buffer[] = { 11, 25, 65 }; + u8 out_buffer[3]; + int copied_elements; + + DEFINE_KFIFO(my_fifo, u8, KFIFO_SIZE); + + for (int i = 0; i < 3; i++) + kfifo_put(&my_fifo, in_buffer[i]); + + copied_elements = kfifo_out(&my_fifo, out_buffer, 3); + KUNIT_EXPECT_EQ(test, copied_elements, 3); + + for (int i = 0; i < 3; i++) + KUNIT_EXPECT_EQ(test, out_buffer[i], in_buffer[i]); + KUNIT_EXPECT_TRUE(test, kfifo_is_empty(&my_fifo)); +} + +static void kfifo_test_dec_init_should_define_an_empty_fifo(struct kunit *test) +{ + DECLARE_KFIFO(my_fifo, u8, KFIFO_SIZE); + + INIT_KFIFO(my_fifo); + + // my_fifo is a struct with an inplace buffer + KUNIT_EXPECT_FALSE(test, __is_kfifo_ptr(&my_fifo)); + + KUNIT_EXPECT_TRUE(test, kfifo_initialized(&my_fifo)); +} + +static void kfifo_test_define_should_equal_declare_init(struct kunit *test) +{ + // declare a variable my_fifo of type struct kfifo of u8 + DECLARE_KFIFO(my_fifo1, u8, KFIFO_SIZE); + // initialize the my_fifo variable + INIT_KFIFO(my_fifo1); + + // DEFINE_KFIFO declares the variable with the initial value + // essentially the same as calling DECLARE_KFIFO and INIT_KFIFO + DEFINE_KFIFO(my_fifo2, u8, KFIFO_SIZE); + + // my_fifo1 and my_fifo2 have the same size + KUNIT_EXPECT_EQ(test, sizeof(my_fifo1), sizeof(my_fifo2)); + KUNIT_EXPECT_EQ(test, kfifo_initialized(&my_fifo1), + kfifo_initialized(&my_fifo2)); + KUNIT_EXPECT_EQ(test, kfifo_is_empty(&my_fifo1), + kfifo_is_empty(&my_fifo2)); +} + +static void kfifo_test_alloc_should_initiliaze_a_ptr_fifo(struct kunit *test) +{ + int ret; + DECLARE_KFIFO_PTR(my_fifo, u8); + + INIT_KFIFO(my_fifo); + + // kfifo_initialized returns false signaling the buffer pointer is NULL + KUNIT_EXPECT_FALSE(test, kfifo_initialized(&my_fifo)); + + // kfifo_alloc allocates the buffer + ret = kfifo_alloc(&my_fifo, KFIFO_SIZE, GFP_KERNEL); + KUNIT_EXPECT_EQ_MSG(test, ret, 0, "Memory allocation should succeed"); + KUNIT_EXPECT_TRUE(test, kfifo_initialized(&my_fifo)); + + // kfifo_free frees the buffer + kfifo_free(&my_fifo); +} + +static void kfifo_test_peek_should_not_remove_elements(struct kunit *test) +{ + u8 out_data; + int processed_elements; + + DEFINE_KFIFO(my_fifo, u8, KFIFO_SIZE); + + // If the fifo is empty, peek returns 0 + processed_elements = kfifo_peek(&my_fifo, &out_data); + KUNIT_EXPECT_EQ(test, processed_elements, 0); + + kfifo_put(&my_fifo, 3); + kfifo_put(&my_fifo, 5); + kfifo_put(&my_fifo, 11); + + KUNIT_EXPECT_EQ(test, kfifo_len(&my_fifo), 3); + + processed_elements = kfifo_peek(&my_fifo, &out_data); + KUNIT_EXPECT_EQ(test, processed_elements, 1); + KUNIT_EXPECT_EQ(test, out_data, 3); + + KUNIT_EXPECT_EQ(test, kfifo_len(&my_fifo), 3); + + // Using peek doesn't remove the element + // so the read element and the fifo length + // remains the same + processed_elements = kfifo_peek(&my_fifo, &out_data); + KUNIT_EXPECT_EQ(test, processed_elements, 1); + KUNIT_EXPECT_EQ(test, out_data, 3); + + KUNIT_EXPECT_EQ(test, kfifo_len(&my_fifo), 3); +} + +static struct kunit_case kfifo_test_cases[] = { + KUNIT_CASE(kfifo_test_reset_should_clear_the_fifo), + KUNIT_CASE(kfifo_test_define_should_define_an_empty_fifo), + KUNIT_CASE(kfifo_test_len_should_ret_n_of_stored_elements), + KUNIT_CASE(kfifo_test_put_should_insert_and_get_should_pop), + KUNIT_CASE(kfifo_test_in_should_insert_multiple_elements), + KUNIT_CASE(kfifo_test_out_should_pop_multiple_elements), + KUNIT_CASE(kfifo_test_dec_init_should_define_an_empty_fifo), + KUNIT_CASE(kfifo_test_define_should_equal_declare_init), + KUNIT_CASE(kfifo_test_alloc_should_initiliaze_a_ptr_fifo), + KUNIT_CASE(kfifo_test_peek_should_not_remove_elements), + {}, +}; + +static struct kunit_suite kfifo_test_module = { + .name = "kfifo", + .test_cases = kfifo_test_cases, +}; + +kunit_test_suites(&kfifo_test_module); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Diego Vieira <diego.daniel.professional@gmail.com>"); +MODULE_DESCRIPTION("KUnit test for the kernel FIFO"); diff --git a/lib/kunit_iov_iter.c b/lib/tests/kunit_iov_iter.c index 48342736d016..48342736d016 100644 --- a/lib/kunit_iov_iter.c +++ b/lib/tests/kunit_iov_iter.c diff --git a/lib/list-test.c b/lib/tests/list-test.c index 9135cdc1bb39..9135cdc1bb39 100644 --- a/lib/list-test.c +++ b/lib/tests/list-test.c diff --git a/lib/memcpy_kunit.c b/lib/tests/memcpy_kunit.c index d36933554e46..d36933554e46 100644 --- a/lib/memcpy_kunit.c +++ b/lib/tests/memcpy_kunit.c diff --git a/lib/overflow_kunit.c b/lib/tests/overflow_kunit.c index 5222c6393f11..894691b4411a 100644 --- a/lib/overflow_kunit.c +++ b/lib/tests/overflow_kunit.c @@ -1185,22 +1185,40 @@ struct bar { static void DEFINE_FLEX_test(struct kunit *test) { - /* Using _RAW_ on a __counted_by struct will initialize "counter" to zero */ - DEFINE_RAW_FLEX(struct foo, two_but_zero, array, 2); -#ifdef CONFIG_CC_HAS_COUNTED_BY - int expected_raw_size = sizeof(struct foo); -#else - int expected_raw_size = sizeof(struct foo) + 2 * sizeof(s16); -#endif - /* Without annotation, it will always be on-stack size. */ DEFINE_RAW_FLEX(struct bar, two, array, 2); DEFINE_FLEX(struct foo, eight, array, counter, 8); DEFINE_FLEX(struct foo, empty, array, counter, 0); + /* Using _RAW_ on a __counted_by struct will initialize "counter" to zero */ + DEFINE_RAW_FLEX(struct foo, two_but_zero, array, 2); + int array_size_override = 0; - KUNIT_EXPECT_EQ(test, __struct_size(two_but_zero), expected_raw_size); + KUNIT_EXPECT_EQ(test, sizeof(*two), sizeof(struct bar)); KUNIT_EXPECT_EQ(test, __struct_size(two), sizeof(struct bar) + 2 * sizeof(s16)); - KUNIT_EXPECT_EQ(test, __struct_size(eight), 24); + KUNIT_EXPECT_EQ(test, __member_size(two), sizeof(struct bar) + 2 * sizeof(s16)); + KUNIT_EXPECT_EQ(test, __struct_size(two->array), 2 * sizeof(s16)); + KUNIT_EXPECT_EQ(test, __member_size(two->array), 2 * sizeof(s16)); + + KUNIT_EXPECT_EQ(test, sizeof(*eight), sizeof(struct foo)); + KUNIT_EXPECT_EQ(test, __struct_size(eight), sizeof(struct foo) + 8 * sizeof(s16)); + KUNIT_EXPECT_EQ(test, __member_size(eight), sizeof(struct foo) + 8 * sizeof(s16)); + KUNIT_EXPECT_EQ(test, __struct_size(eight->array), 8 * sizeof(s16)); + KUNIT_EXPECT_EQ(test, __member_size(eight->array), 8 * sizeof(s16)); + + KUNIT_EXPECT_EQ(test, sizeof(*empty), sizeof(struct foo)); KUNIT_EXPECT_EQ(test, __struct_size(empty), sizeof(struct foo)); + KUNIT_EXPECT_EQ(test, __member_size(empty), sizeof(struct foo)); + KUNIT_EXPECT_EQ(test, __struct_size(empty->array), 0); + KUNIT_EXPECT_EQ(test, __member_size(empty->array), 0); + + /* If __counted_by is not being used, array size will have the on-stack size. */ + if (!IS_ENABLED(CONFIG_CC_HAS_COUNTED_BY)) + array_size_override = 2 * sizeof(s16); + + KUNIT_EXPECT_EQ(test, sizeof(*two_but_zero), sizeof(struct foo)); + KUNIT_EXPECT_EQ(test, __struct_size(two_but_zero), sizeof(struct foo) + 2 * sizeof(s16)); + KUNIT_EXPECT_EQ(test, __member_size(two_but_zero), sizeof(struct foo) + 2 * sizeof(s16)); + KUNIT_EXPECT_EQ(test, __struct_size(two_but_zero->array), array_size_override); + KUNIT_EXPECT_EQ(test, __member_size(two_but_zero->array), array_size_override); } static struct kunit_case overflow_test_cases[] = { diff --git a/lib/test_printf.c b/lib/tests/printf_kunit.c index 59dbe4f9a4cb..2c9f6170bacd 100644 --- a/lib/test_printf.c +++ b/lib/tests/printf_kunit.c @@ -3,9 +3,7 @@ * Test cases for printf facility. */ -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include <linux/init.h> +#include <kunit/test.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/printk.h> @@ -25,8 +23,6 @@ #include <linux/property.h> -#include "../tools/testing/selftests/kselftest_module.h" - #define BUF_SIZE 256 #define PAD_SIZE 16 #define FILL_CHAR '$' @@ -37,14 +33,14 @@ block \ __diag_pop(); -KSTM_MODULE_GLOBALS(); +static unsigned int total_tests; -static char *test_buffer __initdata; -static char *alloced_buffer __initdata; +static char *test_buffer; +static char *alloced_buffer; -static int __printf(4, 0) __init -do_test(int bufsize, const char *expect, int elen, - const char *fmt, va_list ap) +static void __printf(7, 0) +do_test(struct kunit *kunittest, const char *file, const int line, int bufsize, const char *expect, + int elen, const char *fmt, va_list ap) { va_list aq; int ret, written; @@ -57,62 +53,70 @@ do_test(int bufsize, const char *expect, int elen, va_end(aq); if (ret != elen) { - pr_warn("vsnprintf(buf, %d, \"%s\", ...) returned %d, expected %d\n", - bufsize, fmt, ret, elen); - return 1; + KUNIT_FAIL(kunittest, + "%s:%d: vsnprintf(buf, %d, \"%s\", ...) returned %d, expected %d\n", + file, line, bufsize, fmt, ret, elen); + return; } if (memchr_inv(alloced_buffer, FILL_CHAR, PAD_SIZE)) { - pr_warn("vsnprintf(buf, %d, \"%s\", ...) wrote before buffer\n", bufsize, fmt); - return 1; + KUNIT_FAIL(kunittest, + "%s:%d: vsnprintf(buf, %d, \"%s\", ...) wrote before buffer\n", + file, line, bufsize, fmt); + return; } if (!bufsize) { if (memchr_inv(test_buffer, FILL_CHAR, BUF_SIZE + PAD_SIZE)) { - pr_warn("vsnprintf(buf, 0, \"%s\", ...) wrote to buffer\n", - fmt); - return 1; + KUNIT_FAIL(kunittest, + "%s:%d: vsnprintf(buf, 0, \"%s\", ...) wrote to buffer\n", + file, line, fmt); } - return 0; + return; } written = min(bufsize-1, elen); if (test_buffer[written]) { - pr_warn("vsnprintf(buf, %d, \"%s\", ...) did not nul-terminate buffer\n", - bufsize, fmt); - return 1; + KUNIT_FAIL(kunittest, + "%s:%d: vsnprintf(buf, %d, \"%s\", ...) did not nul-terminate buffer\n", + file, line, bufsize, fmt); + return; } if (memchr_inv(test_buffer + written + 1, FILL_CHAR, bufsize - (written + 1))) { - pr_warn("vsnprintf(buf, %d, \"%s\", ...) wrote beyond the nul-terminator\n", - bufsize, fmt); - return 1; + KUNIT_FAIL(kunittest, + "%s:%d: vsnprintf(buf, %d, \"%s\", ...) wrote beyond the nul-terminator\n", + file, line, bufsize, fmt); + return; } if (memchr_inv(test_buffer + bufsize, FILL_CHAR, BUF_SIZE + PAD_SIZE - bufsize)) { - pr_warn("vsnprintf(buf, %d, \"%s\", ...) wrote beyond buffer\n", bufsize, fmt); - return 1; + KUNIT_FAIL(kunittest, + "%s:%d: vsnprintf(buf, %d, \"%s\", ...) wrote beyond buffer\n", + file, line, bufsize, fmt); + return; } if (memcmp(test_buffer, expect, written)) { - pr_warn("vsnprintf(buf, %d, \"%s\", ...) wrote '%s', expected '%.*s'\n", - bufsize, fmt, test_buffer, written, expect); - return 1; + KUNIT_FAIL(kunittest, + "%s:%d: vsnprintf(buf, %d, \"%s\", ...) wrote '%s', expected '%.*s'\n", + file, line, bufsize, fmt, test_buffer, written, expect); + return; } - return 0; } -static void __printf(3, 4) __init -__test(const char *expect, int elen, const char *fmt, ...) +static void __printf(6, 7) +__test(struct kunit *kunittest, const char *file, const int line, const char *expect, int elen, + const char *fmt, ...) { va_list ap; int rand; char *p; if (elen >= BUF_SIZE) { - pr_err("error in test suite: expected output length %d too long. Format was '%s'.\n", - elen, fmt); - failed_tests++; + KUNIT_FAIL(kunittest, + "%s:%d: error in test suite: expected length (%d) >= BUF_SIZE (%d). fmt=\"%s\"\n", + file, line, elen, BUF_SIZE, fmt); return; } @@ -124,19 +128,19 @@ __test(const char *expect, int elen, const char *fmt, ...) * enough and 0), and then we also test that kvasprintf would * be able to print it as expected. */ - failed_tests += do_test(BUF_SIZE, expect, elen, fmt, ap); + do_test(kunittest, file, line, BUF_SIZE, expect, elen, fmt, ap); rand = get_random_u32_inclusive(1, elen + 1); /* Since elen < BUF_SIZE, we have 1 <= rand <= BUF_SIZE. */ - failed_tests += do_test(rand, expect, elen, fmt, ap); - failed_tests += do_test(0, expect, elen, fmt, ap); + do_test(kunittest, file, line, rand, expect, elen, fmt, ap); + do_test(kunittest, file, line, 0, expect, elen, fmt, ap); p = kvasprintf(GFP_KERNEL, fmt, ap); if (p) { total_tests++; if (memcmp(p, expect, elen+1)) { - pr_warn("kvasprintf(..., \"%s\", ...) returned '%s', expected '%s'\n", - fmt, p, expect); - failed_tests++; + KUNIT_FAIL(kunittest, + "%s:%d: kvasprintf(..., \"%s\", ...) returned '%s', expected '%s'\n", + file, line, fmt, p, expect); } kfree(p); } @@ -144,10 +148,10 @@ __test(const char *expect, int elen, const char *fmt, ...) } #define test(expect, fmt, ...) \ - __test(expect, strlen(expect), fmt, ##__VA_ARGS__) + __test(kunittest, __FILE__, __LINE__, expect, strlen(expect), fmt, ##__VA_ARGS__) -static void __init -test_basic(void) +static void +test_basic(struct kunit *kunittest) { /* Work around annoying "warning: zero-length gnu_printf format string". */ char nul = '\0'; @@ -155,11 +159,11 @@ test_basic(void) test("", &nul); test("100%", "100%%"); test("xxx%yyy", "xxx%cyyy", '%'); - __test("xxx\0yyy", 7, "xxx%cyyy", '\0'); + __test(kunittest, __FILE__, __LINE__, "xxx\0yyy", 7, "xxx%cyyy", '\0'); } -static void __init -test_number(void) +static void +test_number(struct kunit *kunittest) { test("0x1234abcd ", "%#-12x", 0x1234abcd); test(" 0x1234abcd", "%#12x", 0x1234abcd); @@ -180,8 +184,8 @@ test_number(void) test("00|0|0|0|0", "%.2d|%.1d|%.0d|%.*d|%1.0d", 0, 0, 0, 0, 0, 0); } -static void __init -test_string(void) +static void +test_string(struct kunit *kunittest) { test("", "%s%.0s", "", "123"); test("ABCD|abc|123", "%s|%.3s|%.*s", "ABCD", "abcdef", 3, "123456"); @@ -218,29 +222,6 @@ test_string(void) #define ZEROS "00000000" /* hex 32 zero bits */ #define ONES "ffffffff" /* hex 32 one bits */ -static int __init -plain_format(void) -{ - char buf[PLAIN_BUF_SIZE]; - int nchars; - - nchars = snprintf(buf, PLAIN_BUF_SIZE, "%p", PTR); - - if (nchars != PTR_WIDTH) - return -1; - - if (strncmp(buf, PTR_VAL_NO_CRNG, PTR_WIDTH) == 0) { - pr_warn("crng possibly not yet initialized. plain 'p' buffer contains \"%s\"", - PTR_VAL_NO_CRNG); - return 0; - } - - if (strncmp(buf, ZEROS, strlen(ZEROS)) != 0) - return -1; - - return 0; -} - #else #define PTR_WIDTH 8 @@ -250,92 +231,47 @@ plain_format(void) #define ZEROS "" #define ONES "" -static int __init -plain_format(void) -{ - /* Format is implicitly tested for 32 bit machines by plain_hash() */ - return 0; -} - #endif /* BITS_PER_LONG == 64 */ -static int __init -plain_hash_to_buffer(const void *p, char *buf, size_t len) +static void +plain_hash_to_buffer(struct kunit *kunittest, const void *p, char *buf, size_t len) { - int nchars; - - nchars = snprintf(buf, len, "%p", p); - - if (nchars != PTR_WIDTH) - return -1; + KUNIT_ASSERT_EQ(kunittest, snprintf(buf, len, "%p", p), PTR_WIDTH); if (strncmp(buf, PTR_VAL_NO_CRNG, PTR_WIDTH) == 0) { - pr_warn("crng possibly not yet initialized. plain 'p' buffer contains \"%s\"", - PTR_VAL_NO_CRNG); - return 0; + kunit_skip(kunittest, + "crng possibly not yet initialized. plain 'p' buffer contains \"%s\"\n", + PTR_VAL_NO_CRNG); } - - return 0; } -static int __init -plain_hash(void) +static void +hash_pointer(struct kunit *kunittest) { - char buf[PLAIN_BUF_SIZE]; - int ret; - - ret = plain_hash_to_buffer(PTR, buf, PLAIN_BUF_SIZE); - if (ret) - return ret; - - if (strncmp(buf, PTR_STR, PTR_WIDTH) == 0) - return -1; - - return 0; -} + if (no_hash_pointers) + kunit_skip(kunittest, "hash pointers disabled"); -/* - * We can't use test() to test %p because we don't know what output to expect - * after an address is hashed. - */ -static void __init -plain(void) -{ - int err; + char buf[PLAIN_BUF_SIZE]; - if (no_hash_pointers) { - pr_warn("skipping plain 'p' tests"); - skipped_tests += 2; - return; - } + plain_hash_to_buffer(kunittest, PTR, buf, PLAIN_BUF_SIZE); - err = plain_hash(); - if (err) { - pr_warn("plain 'p' does not appear to be hashed\n"); - failed_tests++; - return; - } + /* + * The hash of %p is unpredictable, therefore test() cannot be used. + * + * Instead verify that the first 32 bits are zeros on a 64-bit system + * and that the non-hashed value is not printed. + */ - err = plain_format(); - if (err) { - pr_warn("hashing plain 'p' has unexpected format\n"); - failed_tests++; - } + KUNIT_EXPECT_MEMEQ(kunittest, buf, ZEROS, strlen(ZEROS)); + KUNIT_EXPECT_MEMNEQ(kunittest, buf, PTR_STR, PTR_WIDTH); } -static void __init -test_hashed(const char *fmt, const void *p) +static void +test_hashed(struct kunit *kunittest, const char *fmt, const void *p) { char buf[PLAIN_BUF_SIZE]; - int ret; - /* - * No need to increase failed test counter since this is assumed - * to be called after plain(). - */ - ret = plain_hash_to_buffer(p, buf, PLAIN_BUF_SIZE); - if (ret) - return; + plain_hash_to_buffer(kunittest, p, buf, PLAIN_BUF_SIZE); test(buf, fmt, p); } @@ -343,8 +279,8 @@ test_hashed(const char *fmt, const void *p) /* * NULL pointers aren't hashed. */ -static void __init -null_pointer(void) +static void +null_pointer(struct kunit *kunittest) { test(ZEROS "00000000", "%p", NULL); test(ZEROS "00000000", "%px", NULL); @@ -354,8 +290,8 @@ null_pointer(void) /* * Error pointers aren't hashed. */ -static void __init -error_pointer(void) +static void +error_pointer(struct kunit *kunittest) { test(ONES "fffffff5", "%p", ERR_PTR(-11)); test(ONES "fffffff5", "%px", ERR_PTR(-11)); @@ -364,27 +300,27 @@ error_pointer(void) #define PTR_INVALID ((void *)0x000000ab) -static void __init -invalid_pointer(void) +static void +invalid_pointer(struct kunit *kunittest) { - test_hashed("%p", PTR_INVALID); + test_hashed(kunittest, "%p", PTR_INVALID); test(ZEROS "000000ab", "%px", PTR_INVALID); test("(efault)", "%pE", PTR_INVALID); } -static void __init -symbol_ptr(void) +static void +symbol_ptr(struct kunit *kunittest) { } -static void __init -kernel_ptr(void) +static void +kernel_ptr(struct kunit *kunittest) { /* We can't test this without access to kptr_restrict. */ } -static void __init -struct_resource(void) +static void +struct_resource(struct kunit *kunittest) { struct resource test_resource = { .start = 0xc0ffee00, @@ -432,8 +368,8 @@ struct_resource(void) "%pR", &test_resource); } -static void __init -struct_range(void) +static void +struct_range(struct kunit *kunittest) { struct range test_range = DEFINE_RANGE(0xc0ffee00ba5eba11, 0xc0ffee00ba5eba11); @@ -448,18 +384,18 @@ struct_range(void) "%pra", &test_range); } -static void __init -addr(void) +static void +addr(struct kunit *kunittest) { } -static void __init -escaped_str(void) +static void +escaped_str(struct kunit *kunittest) { } -static void __init -hex_string(void) +static void +hex_string(struct kunit *kunittest) { const char buf[3] = {0xc0, 0xff, 0xee}; @@ -469,8 +405,8 @@ hex_string(void) "%*ph|%*phC|%*phD|%*phN", 3, buf, 3, buf, 3, buf, 3, buf); } -static void __init -mac(void) +static void +mac(struct kunit *kunittest) { const u8 addr[6] = {0x2d, 0x48, 0xd6, 0xfc, 0x7a, 0x05}; @@ -481,8 +417,8 @@ mac(void) test("057afcd6482d", "%pmR", addr); } -static void __init -ip4(void) +static void +ip4(struct kunit *kunittest) { struct sockaddr_in sa; @@ -496,20 +432,13 @@ ip4(void) test("001.002.003.004:12345|1.2.3.4:12345", "%piSp|%pISp", &sa, &sa); } -static void __init -ip6(void) +static void +ip6(struct kunit *kunittest) { } -static void __init -ip(void) -{ - ip4(); - ip6(); -} - -static void __init -uuid(void) +static void +uuid(struct kunit *kunittest) { const char uuid[16] = {0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf}; @@ -520,7 +449,7 @@ uuid(void) test("03020100-0504-0706-0809-0A0B0C0D0E0F", "%pUL", uuid); } -static struct dentry test_dentry[4] __initdata = { +static struct dentry test_dentry[4] = { { .d_parent = &test_dentry[0], .d_name = QSTR_INIT(test_dentry[0].d_iname, 3), .d_iname = "foo" }, @@ -535,8 +464,8 @@ static struct dentry test_dentry[4] __initdata = { .d_iname = "romeo" }, }; -static void __init -dentry(void) +static void +dentry(struct kunit *kunittest) { test("foo", "%pd", &test_dentry[0]); test("foo", "%pd2", &test_dentry[0]); @@ -556,13 +485,13 @@ dentry(void) test(" bravo/alfa| bravo/alfa", "%12pd2|%*pd2", &test_dentry[2], 12, &test_dentry[2]); } -static void __init -struct_va_format(void) +static void +struct_va_format(struct kunit *kunittest) { } -static void __init -time_and_date(void) +static void +time_and_date(struct kunit *kunittest) { /* 1543210543 */ const struct rtc_time tm = { @@ -595,13 +524,13 @@ time_and_date(void) test("15:32:23|0119-00-04", "%ptTtrs|%ptTdrs", &t, &t); } -static void __init -struct_clk(void) +static void +struct_clk(struct kunit *kunittest) { } -static void __init -large_bitmap(void) +static void +large_bitmap(struct kunit *kunittest) { const int nbits = 1 << 16; unsigned long *bits = bitmap_zalloc(nbits, GFP_KERNEL); @@ -614,8 +543,8 @@ large_bitmap(void) bitmap_free(bits); } -static void __init -bitmap(void) +static void +bitmap(struct kunit *kunittest) { DECLARE_BITMAP(bits, 20); const int primes[] = {2,3,5,7,11,13,17,19}; @@ -634,11 +563,11 @@ bitmap(void) test("fffff|fffff", "%20pb|%*pb", bits, 20, bits); test("0-19|0-19", "%20pbl|%*pbl", bits, 20, bits); - large_bitmap(); + large_bitmap(kunittest); } -static void __init -netdev_features(void) +static void +netdev_features(struct kunit *kunittest) { } @@ -663,9 +592,9 @@ static const struct page_flags_test pft[] = { "%#x", "kasantag"}, }; -static void __init -page_flags_test(int section, int node, int zone, int last_cpupid, - int kasan_tag, unsigned long flags, const char *name, +static void +page_flags_test(struct kunit *kunittest, int section, int node, int zone, + int last_cpupid, int kasan_tag, unsigned long flags, const char *name, char *cmp_buf) { unsigned long values[] = {section, node, zone, last_cpupid, kasan_tag}; @@ -701,26 +630,25 @@ page_flags_test(int section, int node, int zone, int last_cpupid, test(cmp_buf, "%pGp", &flags); } -static void __init -flags(void) +static void +flags(struct kunit *kunittest) { unsigned long flags; char *cmp_buffer; gfp_t gfp; - cmp_buffer = kmalloc(BUF_SIZE, GFP_KERNEL); - if (!cmp_buffer) - return; + cmp_buffer = kunit_kmalloc(kunittest, BUF_SIZE, GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(kunittest, cmp_buffer); flags = 0; - page_flags_test(0, 0, 0, 0, 0, flags, "", cmp_buffer); + page_flags_test(kunittest, 0, 0, 0, 0, 0, flags, "", cmp_buffer); flags = 1UL << NR_PAGEFLAGS; - page_flags_test(0, 0, 0, 0, 0, flags, "", cmp_buffer); + page_flags_test(kunittest, 0, 0, 0, 0, 0, flags, "", cmp_buffer); flags |= 1UL << PG_uptodate | 1UL << PG_dirty | 1UL << PG_lru | 1UL << PG_active | 1UL << PG_swapbacked; - page_flags_test(1, 1, 1, 0x1fffff, 1, flags, + page_flags_test(kunittest, 1, 1, 1, 0x1fffff, 1, flags, "uptodate|dirty|lru|active|swapbacked", cmp_buffer); @@ -745,11 +673,9 @@ flags(void) (unsigned long) gfp); gfp |= __GFP_HIGH; test(cmp_buffer, "%pGg", &gfp); - - kfree(cmp_buffer); } -static void __init fwnode_pointer(void) +static void fwnode_pointer(struct kunit *kunittest) { const struct software_node first = { .name = "first" }; const struct software_node second = { .name = "second", .parent = &first }; @@ -763,8 +689,7 @@ static void __init fwnode_pointer(void) rval = software_node_register_node_group(group); if (rval) { - pr_warn("cannot register softnodes; rval %d\n", rval); - return; + kunit_skip(kunittest, "cannot register softnodes; rval %d\n", rval); } test(full_name_second, "%pfw", software_node_fwnode(&second)); @@ -776,7 +701,7 @@ static void __init fwnode_pointer(void) software_node_unregister_node_group(group); } -static void __init fourcc_pointer(void) +static void fourcc_pointer(struct kunit *kunittest) { struct { u32 code; @@ -793,14 +718,14 @@ static void __init fourcc_pointer(void) test(try[i].str, "%p4cc", &try[i].code); } -static void __init -errptr(void) +static void +errptr(struct kunit *kunittest) { test("-1234", "%pe", ERR_PTR(-1234)); /* Check that %pe with a non-ERR_PTR gets treated as ordinary %p. */ BUILD_BUG_ON(IS_ERR(PTR)); - test_hashed("%pe", PTR); + test_hashed(kunittest, "%pe", PTR); #ifdef CONFIG_SYMBOLIC_ERRNAME test("(-ENOTSOCK)", "(%pe)", ERR_PTR(-ENOTSOCK)); @@ -813,51 +738,66 @@ errptr(void) #endif } -static void __init -test_pointer(void) -{ - plain(); - null_pointer(); - error_pointer(); - invalid_pointer(); - symbol_ptr(); - kernel_ptr(); - struct_resource(); - struct_range(); - addr(); - escaped_str(); - hex_string(); - mac(); - ip(); - uuid(); - dentry(); - struct_va_format(); - time_and_date(); - struct_clk(); - bitmap(); - netdev_features(); - flags(); - errptr(); - fwnode_pointer(); - fourcc_pointer(); -} - -static void __init selftest(void) +static int printf_suite_init(struct kunit_suite *suite) { + total_tests = 0; + alloced_buffer = kmalloc(BUF_SIZE + 2*PAD_SIZE, GFP_KERNEL); if (!alloced_buffer) - return; + return -ENOMEM; test_buffer = alloced_buffer + PAD_SIZE; - test_basic(); - test_number(); - test_string(); - test_pointer(); + return 0; +} +static void printf_suite_exit(struct kunit_suite *suite) +{ kfree(alloced_buffer); -} -KSTM_MODULE_LOADERS(test_printf); + kunit_info(suite, "ran %u tests\n", total_tests); +} + +static struct kunit_case printf_test_cases[] = { + KUNIT_CASE(test_basic), + KUNIT_CASE(test_number), + KUNIT_CASE(test_string), + KUNIT_CASE(hash_pointer), + KUNIT_CASE(null_pointer), + KUNIT_CASE(error_pointer), + KUNIT_CASE(invalid_pointer), + KUNIT_CASE(symbol_ptr), + KUNIT_CASE(kernel_ptr), + KUNIT_CASE(struct_resource), + KUNIT_CASE(struct_range), + KUNIT_CASE(addr), + KUNIT_CASE(escaped_str), + KUNIT_CASE(hex_string), + KUNIT_CASE(mac), + KUNIT_CASE(ip4), + KUNIT_CASE(ip6), + KUNIT_CASE(uuid), + KUNIT_CASE(dentry), + KUNIT_CASE(struct_va_format), + KUNIT_CASE(time_and_date), + KUNIT_CASE(struct_clk), + KUNIT_CASE(bitmap), + KUNIT_CASE(netdev_features), + KUNIT_CASE(flags), + KUNIT_CASE(errptr), + KUNIT_CASE(fwnode_pointer), + KUNIT_CASE(fourcc_pointer), + {} +}; + +static struct kunit_suite printf_test_suite = { + .name = "printf", + .suite_init = printf_suite_init, + .suite_exit = printf_suite_exit, + .test_cases = printf_test_cases, +}; + +kunit_test_suite(printf_test_suite); + MODULE_AUTHOR("Rasmus Villemoes <linux@rasmusvillemoes.dk>"); MODULE_DESCRIPTION("Test cases for printf facility"); MODULE_LICENSE("GPL"); diff --git a/lib/test_scanf.c b/lib/tests/scanf_kunit.c index 44f8508c9d88..e9a36ed80575 100644 --- a/lib/test_scanf.c +++ b/lib/tests/scanf_kunit.c @@ -3,152 +3,138 @@ * Test cases for sscanf facility. */ -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - +#include <kunit/test.h> #include <linux/bitops.h> -#include <linux/init.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/overflow.h> -#include <linux/printk.h> #include <linux/prandom.h> #include <linux/slab.h> #include <linux/string.h> -#include "../tools/testing/selftests/kselftest_module.h" - #define BUF_SIZE 1024 -KSTM_MODULE_GLOBALS(); -static char *test_buffer __initdata; -static char *fmt_buffer __initdata; -static struct rnd_state rnd_state __initdata; +static char *test_buffer; +static char *fmt_buffer; +static struct rnd_state rnd_state; -typedef int (*check_fn)(const void *check_data, const char *string, - const char *fmt, int n_args, va_list ap); +typedef void (*check_fn)(struct kunit *test, const char *file, const int line, + const void *check_data, const char *string, const char *fmt, int n_args, + va_list ap); -static void __scanf(4, 6) __init -_test(check_fn fn, const void *check_data, const char *string, const char *fmt, - int n_args, ...) +static void __scanf(7, 9) +_test(struct kunit *test, const char *file, const int line, check_fn fn, const void *check_data, + const char *string, const char *fmt, int n_args, ...) { va_list ap, ap_copy; int ret; - total_tests++; - va_start(ap, n_args); va_copy(ap_copy, ap); ret = vsscanf(string, fmt, ap_copy); va_end(ap_copy); if (ret != n_args) { - pr_warn("vsscanf(\"%s\", \"%s\", ...) returned %d expected %d\n", - string, fmt, ret, n_args); - goto fail; + KUNIT_FAIL(test, "%s:%d: vsscanf(\"%s\", \"%s\", ...) returned %d expected %d", + file, line, string, fmt, ret, n_args); + } else { + (*fn)(test, file, line, check_data, string, fmt, n_args, ap); } - ret = (*fn)(check_data, string, fmt, n_args, ap); - if (ret) - goto fail; - - va_end(ap); - - return; - -fail: - failed_tests++; va_end(ap); } #define _check_numbers_template(arg_fmt, expect, str, fmt, n_args, ap) \ do { \ - pr_debug("\"%s\", \"%s\" ->\n", str, fmt); \ for (; n_args > 0; n_args--, expect++) { \ typeof(*expect) got = *va_arg(ap, typeof(expect)); \ - pr_debug("\t" arg_fmt "\n", got); \ if (got != *expect) { \ - pr_warn("vsscanf(\"%s\", \"%s\", ...) expected " arg_fmt " got " arg_fmt "\n", \ - str, fmt, *expect, got); \ - return 1; \ + KUNIT_FAIL(test, \ + "%s:%d: vsscanf(\"%s\", \"%s\", ...) expected " arg_fmt " got " arg_fmt, \ + file, line, str, fmt, *expect, got); \ + return; \ } \ } \ - return 0; \ } while (0) -static int __init check_ull(const void *check_data, const char *string, - const char *fmt, int n_args, va_list ap) +static void check_ull(struct kunit *test, const char *file, const int line, const void *check_data, + const char *string, const char *fmt, int n_args, va_list ap) { const unsigned long long *pval = check_data; _check_numbers_template("%llu", pval, string, fmt, n_args, ap); } -static int __init check_ll(const void *check_data, const char *string, - const char *fmt, int n_args, va_list ap) +static void check_ll(struct kunit *test, const char *file, const int line, const void *check_data, + const char *string, const char *fmt, int n_args, va_list ap) { const long long *pval = check_data; _check_numbers_template("%lld", pval, string, fmt, n_args, ap); } -static int __init check_ulong(const void *check_data, const char *string, - const char *fmt, int n_args, va_list ap) +static void check_ulong(struct kunit *test, const char *file, const int line, + const void *check_data, const char *string, const char *fmt, int n_args, + va_list ap) { const unsigned long *pval = check_data; _check_numbers_template("%lu", pval, string, fmt, n_args, ap); } -static int __init check_long(const void *check_data, const char *string, - const char *fmt, int n_args, va_list ap) +static void check_long(struct kunit *test, const char *file, const int line, const void *check_data, + const char *string, const char *fmt, int n_args, va_list ap) { const long *pval = check_data; _check_numbers_template("%ld", pval, string, fmt, n_args, ap); } -static int __init check_uint(const void *check_data, const char *string, - const char *fmt, int n_args, va_list ap) +static void check_uint(struct kunit *test, const char *file, const int line, const void *check_data, + const char *string, const char *fmt, int n_args, va_list ap) { const unsigned int *pval = check_data; _check_numbers_template("%u", pval, string, fmt, n_args, ap); } -static int __init check_int(const void *check_data, const char *string, - const char *fmt, int n_args, va_list ap) +static void check_int(struct kunit *test, const char *file, const int line, const void *check_data, + const char *string, const char *fmt, int n_args, va_list ap) { const int *pval = check_data; _check_numbers_template("%d", pval, string, fmt, n_args, ap); } -static int __init check_ushort(const void *check_data, const char *string, - const char *fmt, int n_args, va_list ap) +static void check_ushort(struct kunit *test, const char *file, const int line, + const void *check_data, const char *string, const char *fmt, int n_args, + va_list ap) { const unsigned short *pval = check_data; _check_numbers_template("%hu", pval, string, fmt, n_args, ap); } -static int __init check_short(const void *check_data, const char *string, - const char *fmt, int n_args, va_list ap) +static void check_short(struct kunit *test, const char *file, const int line, + const void *check_data, const char *string, const char *fmt, int n_args, + va_list ap) { const short *pval = check_data; _check_numbers_template("%hd", pval, string, fmt, n_args, ap); } -static int __init check_uchar(const void *check_data, const char *string, - const char *fmt, int n_args, va_list ap) +static void check_uchar(struct kunit *test, const char *file, const int line, + const void *check_data, const char *string, const char *fmt, int n_args, + va_list ap) { const unsigned char *pval = check_data; _check_numbers_template("%hhu", pval, string, fmt, n_args, ap); } -static int __init check_char(const void *check_data, const char *string, - const char *fmt, int n_args, va_list ap) +static void check_char(struct kunit *test, const char *file, const int line, const void *check_data, + const char *string, const char *fmt, int n_args, va_list ap) { const signed char *pval = check_data; @@ -156,7 +142,7 @@ static int __init check_char(const void *check_data, const char *string, } /* Selection of interesting numbers to test, copied from test-kstrtox.c */ -static const unsigned long long numbers[] __initconst = { +static const unsigned long long numbers[] = { 0x0ULL, 0x1ULL, 0x7fULL, @@ -196,7 +182,7 @@ do { \ T result = ~expect_val; /* should be overwritten */ \ \ snprintf(test_buffer, BUF_SIZE, gen_fmt, expect_val); \ - _test(fn, &expect_val, test_buffer, "%" scan_fmt, 1, &result); \ + _test(test, __FILE__, __LINE__, fn, &expect_val, test_buffer, "%" scan_fmt, 1, &result);\ } while (0) #define simple_numbers_loop(T, gen_fmt, scan_fmt, fn) \ @@ -214,7 +200,7 @@ do { \ } \ } while (0) -static void __init numbers_simple(void) +static void numbers_simple(struct kunit *test) { simple_numbers_loop(unsigned long long, "%llu", "llu", check_ull); simple_numbers_loop(long long, "%lld", "lld", check_ll); @@ -267,14 +253,14 @@ static void __init numbers_simple(void) * the raw prandom*() functions (Not mathematically rigorous!!). * Variabilty of length and value is more important than perfect randomness. */ -static u32 __init next_test_random(u32 max_bits) +static u32 next_test_random(u32 max_bits) { u32 n_bits = hweight32(prandom_u32_state(&rnd_state)) % (max_bits + 1); return prandom_u32_state(&rnd_state) & GENMASK(n_bits, 0); } -static unsigned long long __init next_test_random_ull(void) +static unsigned long long next_test_random_ull(void) { u32 rand1 = prandom_u32_state(&rnd_state); u32 n_bits = (hweight32(rand1) * 3) % 64; @@ -311,7 +297,7 @@ do { \ * updating buf_pos and returning the number of characters appended. * On error buf_pos is not changed and return value is 0. */ -static int __init __printf(4, 5) +static int __printf(4, 5) append_fmt(char *buf, int *buf_pos, int buf_len, const char *val_fmt, ...) { va_list ap; @@ -333,7 +319,7 @@ append_fmt(char *buf, int *buf_pos, int buf_len, const char *val_fmt, ...) * Convenience function to append the field delimiter string * to both the value string and format string buffers. */ -static void __init append_delim(char *str_buf, int *str_buf_pos, int str_buf_len, +static void append_delim(char *str_buf, int *str_buf_pos, int str_buf_len, char *fmt_buf, int *fmt_buf_pos, int fmt_buf_len, const char *delim_str) { @@ -344,7 +330,7 @@ static void __init append_delim(char *str_buf, int *str_buf_pos, int str_buf_len #define test_array_8(fn, check_data, string, fmt, arr) \ do { \ BUILD_BUG_ON(ARRAY_SIZE(arr) != 8); \ - _test(fn, check_data, string, fmt, 8, \ + _test(test, __FILE__, __LINE__, fn, check_data, string, fmt, 8, \ &(arr)[0], &(arr)[1], &(arr)[2], &(arr)[3], \ &(arr)[4], &(arr)[5], &(arr)[6], &(arr)[7]); \ } while (0) @@ -398,7 +384,7 @@ do { \ test_array_8(fn, expect, test_buffer, fmt_buffer, result); \ } while (0) -static void __init numbers_list_ll(const char *delim) +static void numbers_list_ll(struct kunit *test, const char *delim) { numbers_list_8(unsigned long long, "%llu", delim, "llu", check_ull); numbers_list_8(long long, "%lld", delim, "lld", check_ll); @@ -408,7 +394,7 @@ static void __init numbers_list_ll(const char *delim) numbers_list_8(long long, "0x%llx", delim, "lli", check_ll); } -static void __init numbers_list_l(const char *delim) +static void numbers_list_l(struct kunit *test, const char *delim) { numbers_list_8(unsigned long, "%lu", delim, "lu", check_ulong); numbers_list_8(long, "%ld", delim, "ld", check_long); @@ -418,7 +404,7 @@ static void __init numbers_list_l(const char *delim) numbers_list_8(long, "0x%lx", delim, "li", check_long); } -static void __init numbers_list_d(const char *delim) +static void numbers_list_d(struct kunit *test, const char *delim) { numbers_list_8(unsigned int, "%u", delim, "u", check_uint); numbers_list_8(int, "%d", delim, "d", check_int); @@ -428,7 +414,7 @@ static void __init numbers_list_d(const char *delim) numbers_list_8(int, "0x%x", delim, "i", check_int); } -static void __init numbers_list_h(const char *delim) +static void numbers_list_h(struct kunit *test, const char *delim) { numbers_list_8(unsigned short, "%hu", delim, "hu", check_ushort); numbers_list_8(short, "%hd", delim, "hd", check_short); @@ -438,7 +424,7 @@ static void __init numbers_list_h(const char *delim) numbers_list_8(short, "0x%hx", delim, "hi", check_short); } -static void __init numbers_list_hh(const char *delim) +static void numbers_list_hh(struct kunit *test, const char *delim) { numbers_list_8(unsigned char, "%hhu", delim, "hhu", check_uchar); numbers_list_8(signed char, "%hhd", delim, "hhd", check_char); @@ -448,16 +434,19 @@ static void __init numbers_list_hh(const char *delim) numbers_list_8(signed char, "0x%hhx", delim, "hhi", check_char); } -static void __init numbers_list(const char *delim) +static void numbers_list(struct kunit *test) { - numbers_list_ll(delim); - numbers_list_l(delim); - numbers_list_d(delim); - numbers_list_h(delim); - numbers_list_hh(delim); + const char * const *param = test->param_value; + const char *delim = *param; + + numbers_list_ll(test, delim); + numbers_list_l(test, delim); + numbers_list_d(test, delim); + numbers_list_h(test, delim); + numbers_list_hh(test, delim); } -static void __init numbers_list_field_width_ll(const char *delim) +static void numbers_list_field_width_ll(struct kunit *test, const char *delim) { numbers_list_fix_width(unsigned long long, "%llu", delim, 20, "llu", check_ull); numbers_list_fix_width(long long, "%lld", delim, 20, "lld", check_ll); @@ -467,7 +456,7 @@ static void __init numbers_list_field_width_ll(const char *delim) numbers_list_fix_width(long long, "0x%llx", delim, 18, "lli", check_ll); } -static void __init numbers_list_field_width_l(const char *delim) +static void numbers_list_field_width_l(struct kunit *test, const char *delim) { #if BITS_PER_LONG == 64 numbers_list_fix_width(unsigned long, "%lu", delim, 20, "lu", check_ulong); @@ -486,7 +475,7 @@ static void __init numbers_list_field_width_l(const char *delim) #endif } -static void __init numbers_list_field_width_d(const char *delim) +static void numbers_list_field_width_d(struct kunit *test, const char *delim) { numbers_list_fix_width(unsigned int, "%u", delim, 10, "u", check_uint); numbers_list_fix_width(int, "%d", delim, 11, "d", check_int); @@ -496,7 +485,7 @@ static void __init numbers_list_field_width_d(const char *delim) numbers_list_fix_width(int, "0x%x", delim, 10, "i", check_int); } -static void __init numbers_list_field_width_h(const char *delim) +static void numbers_list_field_width_h(struct kunit *test, const char *delim) { numbers_list_fix_width(unsigned short, "%hu", delim, 5, "hu", check_ushort); numbers_list_fix_width(short, "%hd", delim, 6, "hd", check_short); @@ -506,7 +495,7 @@ static void __init numbers_list_field_width_h(const char *delim) numbers_list_fix_width(short, "0x%hx", delim, 6, "hi", check_short); } -static void __init numbers_list_field_width_hh(const char *delim) +static void numbers_list_field_width_hh(struct kunit *test, const char *delim) { numbers_list_fix_width(unsigned char, "%hhu", delim, 3, "hhu", check_uchar); numbers_list_fix_width(signed char, "%hhd", delim, 4, "hhd", check_char); @@ -520,16 +509,19 @@ static void __init numbers_list_field_width_hh(const char *delim) * List of numbers separated by delim. Each field width specifier is the * maximum possible digits for the given type and base. */ -static void __init numbers_list_field_width_typemax(const char *delim) +static void numbers_list_field_width_typemax(struct kunit *test) { - numbers_list_field_width_ll(delim); - numbers_list_field_width_l(delim); - numbers_list_field_width_d(delim); - numbers_list_field_width_h(delim); - numbers_list_field_width_hh(delim); + const char * const *param = test->param_value; + const char *delim = *param; + + numbers_list_field_width_ll(test, delim); + numbers_list_field_width_l(test, delim); + numbers_list_field_width_d(test, delim); + numbers_list_field_width_h(test, delim); + numbers_list_field_width_hh(test, delim); } -static void __init numbers_list_field_width_val_ll(const char *delim) +static void numbers_list_field_width_val_ll(struct kunit *test, const char *delim) { numbers_list_val_width(unsigned long long, "%llu", delim, "llu", check_ull); numbers_list_val_width(long long, "%lld", delim, "lld", check_ll); @@ -539,7 +531,7 @@ static void __init numbers_list_field_width_val_ll(const char *delim) numbers_list_val_width(long long, "0x%llx", delim, "lli", check_ll); } -static void __init numbers_list_field_width_val_l(const char *delim) +static void numbers_list_field_width_val_l(struct kunit *test, const char *delim) { numbers_list_val_width(unsigned long, "%lu", delim, "lu", check_ulong); numbers_list_val_width(long, "%ld", delim, "ld", check_long); @@ -549,7 +541,7 @@ static void __init numbers_list_field_width_val_l(const char *delim) numbers_list_val_width(long, "0x%lx", delim, "li", check_long); } -static void __init numbers_list_field_width_val_d(const char *delim) +static void numbers_list_field_width_val_d(struct kunit *test, const char *delim) { numbers_list_val_width(unsigned int, "%u", delim, "u", check_uint); numbers_list_val_width(int, "%d", delim, "d", check_int); @@ -559,7 +551,7 @@ static void __init numbers_list_field_width_val_d(const char *delim) numbers_list_val_width(int, "0x%x", delim, "i", check_int); } -static void __init numbers_list_field_width_val_h(const char *delim) +static void numbers_list_field_width_val_h(struct kunit *test, const char *delim) { numbers_list_val_width(unsigned short, "%hu", delim, "hu", check_ushort); numbers_list_val_width(short, "%hd", delim, "hd", check_short); @@ -569,7 +561,7 @@ static void __init numbers_list_field_width_val_h(const char *delim) numbers_list_val_width(short, "0x%hx", delim, "hi", check_short); } -static void __init numbers_list_field_width_val_hh(const char *delim) +static void numbers_list_field_width_val_hh(struct kunit *test, const char *delim) { numbers_list_val_width(unsigned char, "%hhu", delim, "hhu", check_uchar); numbers_list_val_width(signed char, "%hhd", delim, "hhd", check_char); @@ -583,13 +575,16 @@ static void __init numbers_list_field_width_val_hh(const char *delim) * List of numbers separated by delim. Each field width specifier is the * exact length of the corresponding value digits in the string being scanned. */ -static void __init numbers_list_field_width_val_width(const char *delim) +static void numbers_list_field_width_val_width(struct kunit *test) { - numbers_list_field_width_val_ll(delim); - numbers_list_field_width_val_l(delim); - numbers_list_field_width_val_d(delim); - numbers_list_field_width_val_h(delim); - numbers_list_field_width_val_hh(delim); + const char * const *param = test->param_value; + const char *delim = *param; + + numbers_list_field_width_val_ll(test, delim); + numbers_list_field_width_val_l(test, delim); + numbers_list_field_width_val_d(test, delim); + numbers_list_field_width_val_h(test, delim); + numbers_list_field_width_val_hh(test, delim); } /* @@ -598,9 +593,14 @@ static void __init numbers_list_field_width_val_width(const char *delim) * of digits. For example the hex values c0,3,bf01,303 would have a * string representation of "c03bf01303" and extracted with "%2x%1x%4x%3x". */ -static void __init numbers_slice(void) +static void numbers_slice(struct kunit *test) { - numbers_list_field_width_val_width(""); + const char *delim = ""; + + KUNIT_ASSERT_PTR_EQ(test, test->param_value, NULL); + test->param_value = &delim; + + numbers_list_field_width_val_width(test); } #define test_number_prefix(T, str, scan_fmt, expect0, expect1, n_args, fn) \ @@ -608,14 +608,14 @@ do { \ const T expect[2] = { expect0, expect1 }; \ T result[2] = { (T)~expect[0], (T)~expect[1] }; \ \ - _test(fn, &expect, str, scan_fmt, n_args, &result[0], &result[1]); \ + _test(test, __FILE__, __LINE__, fn, &expect, str, scan_fmt, n_args, &result[0], &result[1]);\ } while (0) /* * Number prefix is >= field width. * Expected behaviour is derived from testing userland sscanf. */ -static void __init numbers_prefix_overflow(void) +static void numbers_prefix_overflow(struct kunit *test) { /* * Negative decimal with a field of width 1, should quit scanning @@ -684,25 +684,17 @@ do { \ T got; \ char *endp; \ int len; \ - bool fail = false; \ \ - total_tests++; \ len = snprintf(test_buffer, BUF_SIZE, gen_fmt, expect); \ got = (fn)(test_buffer, &endp, base); \ - pr_debug(#fn "(\"%s\", %d) -> " gen_fmt "\n", test_buffer, base, got); \ if (got != (expect)) { \ - fail = true; \ - pr_warn(#fn "(\"%s\", %d): got " gen_fmt " expected " gen_fmt "\n", \ - test_buffer, base, got, expect); \ + KUNIT_FAIL(test, #fn "(\"%s\", %d): got " gen_fmt " expected " gen_fmt, \ + test_buffer, base, got, expect); \ } else if (endp != test_buffer + len) { \ - fail = true; \ - pr_warn(#fn "(\"%s\", %d) startp=0x%px got endp=0x%px expected 0x%px\n", \ - test_buffer, base, test_buffer, \ - test_buffer + len, endp); \ + KUNIT_FAIL(test, #fn "(\"%s\", %d) startp=0x%px got endp=0x%px expected 0x%px", \ + test_buffer, base, test_buffer, \ + test_buffer + len, endp); \ } \ - \ - if (fail) \ - failed_tests++; \ } while (0) #define test_simple_strtoxx(T, fn, gen_fmt, base) \ @@ -718,7 +710,7 @@ do { \ } \ } while (0) -static void __init test_simple_strtoull(void) +static void test_simple_strtoull(struct kunit *test) { test_simple_strtoxx(unsigned long long, simple_strtoull, "%llu", 10); test_simple_strtoxx(unsigned long long, simple_strtoull, "%llu", 0); @@ -727,7 +719,7 @@ static void __init test_simple_strtoull(void) test_simple_strtoxx(unsigned long long, simple_strtoull, "0x%llx", 0); } -static void __init test_simple_strtoll(void) +static void test_simple_strtoll(struct kunit *test) { test_simple_strtoxx(long long, simple_strtoll, "%lld", 10); test_simple_strtoxx(long long, simple_strtoll, "%lld", 0); @@ -736,7 +728,7 @@ static void __init test_simple_strtoll(void) test_simple_strtoxx(long long, simple_strtoll, "0x%llx", 0); } -static void __init test_simple_strtoul(void) +static void test_simple_strtoul(struct kunit *test) { test_simple_strtoxx(unsigned long, simple_strtoul, "%lu", 10); test_simple_strtoxx(unsigned long, simple_strtoul, "%lu", 0); @@ -745,7 +737,7 @@ static void __init test_simple_strtoul(void) test_simple_strtoxx(unsigned long, simple_strtoul, "0x%lx", 0); } -static void __init test_simple_strtol(void) +static void test_simple_strtol(struct kunit *test) { test_simple_strtoxx(long, simple_strtol, "%ld", 10); test_simple_strtoxx(long, simple_strtol, "%ld", 0); @@ -755,60 +747,69 @@ static void __init test_simple_strtol(void) } /* Selection of common delimiters/separators between numbers in a string. */ -static const char * const number_delimiters[] __initconst = { +static const char * const number_delimiters[] = { " ", ":", ",", "-", "/", }; -static void __init test_numbers(void) +static void number_delimiter_param_desc(const char * const *param, + char *desc) { - int i; + snprintf(desc, KUNIT_PARAM_DESC_SIZE, "\"%s\"", *param); +} - /* String containing only one number. */ - numbers_simple(); +KUNIT_ARRAY_PARAM(number_delimiters, number_delimiters, number_delimiter_param_desc); +static struct kunit_case scanf_test_cases[] = { + KUNIT_CASE(numbers_simple), /* String with multiple numbers separated by delimiter. */ - for (i = 0; i < ARRAY_SIZE(number_delimiters); i++) { - numbers_list(number_delimiters[i]); - - /* Field width may be longer than actual field digits. */ - numbers_list_field_width_typemax(number_delimiters[i]); - - /* Each field width exactly length of actual field digits. */ - numbers_list_field_width_val_width(number_delimiters[i]); - } - + KUNIT_CASE_PARAM(numbers_list, number_delimiters_gen_params), + /* Field width may be longer than actual field digits. */ + KUNIT_CASE_PARAM(numbers_list_field_width_typemax, number_delimiters_gen_params), + /* Each field width exactly length of actual field digits. */ + KUNIT_CASE_PARAM(numbers_list_field_width_val_width, number_delimiters_gen_params), /* Slice continuous sequence of digits using field widths. */ - numbers_slice(); - - numbers_prefix_overflow(); -} + KUNIT_CASE(numbers_slice), + KUNIT_CASE(numbers_prefix_overflow), + + KUNIT_CASE(test_simple_strtoull), + KUNIT_CASE(test_simple_strtoll), + KUNIT_CASE(test_simple_strtoul), + KUNIT_CASE(test_simple_strtol), + {} +}; -static void __init selftest(void) +static int scanf_suite_init(struct kunit_suite *suite) { test_buffer = kmalloc(BUF_SIZE, GFP_KERNEL); if (!test_buffer) - return; + return -ENOMEM; fmt_buffer = kmalloc(BUF_SIZE, GFP_KERNEL); if (!fmt_buffer) { kfree(test_buffer); - return; + return -ENOMEM; } prandom_seed_state(&rnd_state, 3141592653589793238ULL); - test_numbers(); - - test_simple_strtoull(); - test_simple_strtoll(); - test_simple_strtoul(); - test_simple_strtol(); + return 0; +} +static void scanf_suite_exit(struct kunit_suite *suite) +{ kfree(fmt_buffer); kfree(test_buffer); } -KSTM_MODULE_LOADERS(test_scanf); +static struct kunit_suite scanf_test_suite = { + .name = "scanf", + .suite_init = scanf_suite_init, + .suite_exit = scanf_suite_exit, + .test_cases = scanf_test_cases, +}; + +kunit_test_suite(scanf_test_suite); + MODULE_AUTHOR("Richard Fitzgerald <rf@opensource.cirrus.com>"); MODULE_DESCRIPTION("Test cases for sscanf facility"); MODULE_LICENSE("GPL v2"); diff --git a/lib/siphash_kunit.c b/lib/tests/siphash_kunit.c index 26bd4e8dc03e..26bd4e8dc03e 100644 --- a/lib/siphash_kunit.c +++ b/lib/tests/siphash_kunit.c diff --git a/lib/slub_kunit.c b/lib/tests/slub_kunit.c index f11691315c2f..d47c472b0520 100644 --- a/lib/slub_kunit.c +++ b/lib/tests/slub_kunit.c @@ -6,6 +6,7 @@ #include <linux/module.h> #include <linux/kernel.h> #include <linux/rcupdate.h> +#include <linux/delay.h> #include "../mm/slab.h" static struct kunit_resource resource; @@ -181,6 +182,63 @@ static void test_kfree_rcu(struct kunit *test) KUNIT_EXPECT_EQ(test, 0, slab_errors); } +struct cache_destroy_work { + struct work_struct work; + struct kmem_cache *s; +}; + +static void cache_destroy_workfn(struct work_struct *w) +{ + struct cache_destroy_work *cdw; + + cdw = container_of(w, struct cache_destroy_work, work); + kmem_cache_destroy(cdw->s); +} + +#define KMEM_CACHE_DESTROY_NR 10 + +static void test_kfree_rcu_wq_destroy(struct kunit *test) +{ + struct test_kfree_rcu_struct *p; + struct cache_destroy_work cdw; + struct workqueue_struct *wq; + struct kmem_cache *s; + unsigned int delay; + int i; + + if (IS_BUILTIN(CONFIG_SLUB_KUNIT_TEST)) + kunit_skip(test, "can't do kfree_rcu() when test is built-in"); + + INIT_WORK_ONSTACK(&cdw.work, cache_destroy_workfn); + wq = alloc_workqueue("test_kfree_rcu_destroy_wq", + WQ_HIGHPRI | WQ_UNBOUND | WQ_MEM_RECLAIM, 0); + + if (!wq) + kunit_skip(test, "failed to alloc wq"); + + for (i = 0; i < KMEM_CACHE_DESTROY_NR; i++) { + s = test_kmem_cache_create("TestSlub_kfree_rcu_wq_destroy", + sizeof(struct test_kfree_rcu_struct), + SLAB_NO_MERGE); + + if (!s) + kunit_skip(test, "failed to create cache"); + + delay = get_random_u8(); + p = kmem_cache_alloc(s, GFP_KERNEL); + kfree_rcu(p, rcu); + + cdw.s = s; + + msleep(delay); + queue_work(wq, &cdw.work); + flush_work(&cdw.work); + } + + destroy_workqueue(wq); + KUNIT_EXPECT_EQ(test, 0, slab_errors); +} + static void test_leak_destroy(struct kunit *test) { struct kmem_cache *s = test_kmem_cache_create("TestSlub_leak_destroy", @@ -254,6 +312,7 @@ static struct kunit_case test_cases[] = { KUNIT_CASE(test_clobber_redzone_free), KUNIT_CASE(test_kmalloc_redzone_access), KUNIT_CASE(test_kfree_rcu), + KUNIT_CASE(test_kfree_rcu_wq_destroy), KUNIT_CASE(test_leak_destroy), KUNIT_CASE(test_krealloc_redzone_zeroing), {} diff --git a/lib/stackinit_kunit.c b/lib/tests/stackinit_kunit.c index 135322592faf..63aa78e6f5c1 100644 --- a/lib/stackinit_kunit.c +++ b/lib/tests/stackinit_kunit.c @@ -185,6 +185,15 @@ static bool stackinit_range_contains(char *haystack_start, size_t haystack_size, INIT_STRUCT_assigned_copy(var_type) /* + * The "did we actually fill the stack?" check value needs + * to be neither 0 nor any of the "pattern" bytes. The + * pattern bytes are compiler, architecture, and type based, + * so we have to pick a value that never appears for those + * combinations. Use 0x99 which is not 0xFF, 0xFE, nor 0xAA. + */ +#define FILL_BYTE 0x99 + +/* * @name: unique string name for the test * @var_type: type to be tested for zeroing initialization * @which: is this a SCALAR, STRING, or STRUCT type? @@ -206,12 +215,12 @@ static noinline void test_ ## name (struct kunit *test) \ ZERO_CLONE_ ## which(zero); \ /* Clear entire check buffer for 0xFF overlap test. */ \ memset(check_buf, 0x00, sizeof(check_buf)); \ - /* Fill stack with 0xFF. */ \ + /* Fill stack with FILL_BYTE. */ \ ignored = leaf_ ##name((unsigned long)&ignored, 1, \ FETCH_ARG_ ## which(zero)); \ - /* Verify all bytes overwritten with 0xFF. */ \ + /* Verify all bytes overwritten with FILL_BYTE. */ \ for (sum = 0, i = 0; i < target_size; i++) \ - sum += (check_buf[i] != 0xFF); \ + sum += (check_buf[i] != FILL_BYTE); \ /* Clear entire check buffer for later bit tests. */ \ memset(check_buf, 0x00, sizeof(check_buf)); \ /* Extract stack-defined variable contents. */ \ @@ -222,7 +231,8 @@ static noinline void test_ ## name (struct kunit *test) \ * possible between the two leaf function calls. \ */ \ KUNIT_ASSERT_EQ_MSG(test, sum, 0, \ - "leaf fill was not 0xFF!?\n"); \ + "leaf fill was not 0x%02X!?\n", \ + FILL_BYTE); \ \ /* Validate that compiler lined up fill and target. */ \ KUNIT_ASSERT_TRUE_MSG(test, \ @@ -234,9 +244,9 @@ static noinline void test_ ## name (struct kunit *test) \ (int)((ssize_t)(uintptr_t)fill_start - \ (ssize_t)(uintptr_t)target_start)); \ \ - /* Look for any bytes still 0xFF in check region. */ \ + /* Validate check region has no FILL_BYTE bytes. */ \ for (sum = 0, i = 0; i < target_size; i++) \ - sum += (check_buf[i] == 0xFF); \ + sum += (check_buf[i] == FILL_BYTE); \ \ if (sum != 0 && xfail) \ kunit_skip(test, \ @@ -271,12 +281,12 @@ static noinline int leaf_ ## name(unsigned long sp, bool fill, \ * stack frame of SOME kind... \ */ \ memset(buf, (char)(sp & 0xff), sizeof(buf)); \ - /* Fill variable with 0xFF. */ \ + /* Fill variable with FILL_BYTE. */ \ if (fill) { \ fill_start = &var; \ fill_size = sizeof(var); \ memset(fill_start, \ - (char)((sp & 0xff) | forced_mask), \ + FILL_BYTE & forced_mask, \ fill_size); \ } \ \ @@ -469,7 +479,7 @@ static int noinline __leaf_switch_none(int path, bool fill) fill_start = &var; fill_size = sizeof(var); - memset(fill_start, forced_mask | 0x55, fill_size); + memset(fill_start, (forced_mask | 0x55) & FILL_BYTE, fill_size); } memcpy(check_buf, target_start, target_size); break; @@ -480,7 +490,7 @@ static int noinline __leaf_switch_none(int path, bool fill) fill_start = &var; fill_size = sizeof(var); - memset(fill_start, forced_mask | 0xaa, fill_size); + memset(fill_start, (forced_mask | 0xaa) & FILL_BYTE, fill_size); } memcpy(check_buf, target_start, target_size); break; diff --git a/lib/string_helpers_kunit.c b/lib/tests/string_helpers_kunit.c index c853046183d2..c853046183d2 100644 --- a/lib/string_helpers_kunit.c +++ b/lib/tests/string_helpers_kunit.c diff --git a/lib/string_kunit.c b/lib/tests/string_kunit.c index c919e3293da6..0ed7448a26d3 100644 --- a/lib/string_kunit.c +++ b/lib/tests/string_kunit.c @@ -579,8 +579,8 @@ static void string_test_strtomem(struct kunit *test) static void string_test_memtostr(struct kunit *test) { - char nonstring[7] = { 'a', 'b', 'c', 'd', 'e', 'f', 'g' }; - char nonstring_small[3] = { 'a', 'b', 'c' }; + char nonstring[7] __nonstring = { 'a', 'b', 'c', 'd', 'e', 'f', 'g' }; + char nonstring_small[3] __nonstring = { 'a', 'b', 'c' }; char dest[sizeof(nonstring) + 1]; /* Copy in a non-NUL-terminated string into exactly right-sized dest. */ diff --git a/lib/test_bits.c b/lib/tests/test_bits.c index c7b38d91e1f1..c7b38d91e1f1 100644 --- a/lib/test_bits.c +++ b/lib/tests/test_bits.c diff --git a/lib/test_fprobe.c b/lib/tests/test_fprobe.c index cf92111b5c79..cf92111b5c79 100644 --- a/lib/test_fprobe.c +++ b/lib/tests/test_fprobe.c diff --git a/lib/test_hash.c b/lib/tests/test_hash.c index a7af39662a0a..a7af39662a0a 100644 --- a/lib/test_hash.c +++ b/lib/tests/test_hash.c diff --git a/lib/test_kprobes.c b/lib/tests/test_kprobes.c index b7582010125c..b7582010125c 100644 --- a/lib/test_kprobes.c +++ b/lib/tests/test_kprobes.c diff --git a/lib/test_linear_ranges.c b/lib/tests/test_linear_ranges.c index f482be00f1bc..f482be00f1bc 100644 --- a/lib/test_linear_ranges.c +++ b/lib/tests/test_linear_ranges.c diff --git a/lib/test_list_sort.c b/lib/tests/test_list_sort.c index 30879abc8a42..30879abc8a42 100644 --- a/lib/test_list_sort.c +++ b/lib/tests/test_list_sort.c diff --git a/lib/test_sort.c b/lib/tests/test_sort.c index cd4a338d1153..cd4a338d1153 100644 --- a/lib/test_sort.c +++ b/lib/tests/test_sort.c diff --git a/lib/usercopy_kunit.c b/lib/tests/usercopy_kunit.c index 77fa00a13df7..77fa00a13df7 100644 --- a/lib/usercopy_kunit.c +++ b/lib/tests/usercopy_kunit.c diff --git a/lib/util_macros_kunit.c b/lib/tests/util_macros_kunit.c index 94cc9f0de50a..94cc9f0de50a 100644 --- a/lib/util_macros_kunit.c +++ b/lib/tests/util_macros_kunit.c diff --git a/lib/ubsan.c b/lib/ubsan.c index a1c983d148f1..cdc1d31c3821 100644 --- a/lib/ubsan.c +++ b/lib/ubsan.c @@ -44,7 +44,7 @@ const char *report_ubsan_failure(struct pt_regs *regs, u32 check_type) case ubsan_shift_out_of_bounds: return "UBSAN: shift out of bounds"; #endif -#if defined(CONFIG_UBSAN_DIV_ZERO) || defined(CONFIG_UBSAN_SIGNED_WRAP) +#if defined(CONFIG_UBSAN_DIV_ZERO) || defined(CONFIG_UBSAN_INTEGER_WRAP) /* * SanitizerKind::IntegerDivideByZero and * SanitizerKind::SignedIntegerOverflow emit @@ -79,7 +79,7 @@ const char *report_ubsan_failure(struct pt_regs *regs, u32 check_type) case ubsan_type_mismatch: return "UBSAN: type mismatch"; #endif -#ifdef CONFIG_UBSAN_SIGNED_WRAP +#ifdef CONFIG_UBSAN_INTEGER_WRAP /* * SanitizerKind::SignedIntegerOverflow emits * SanitizerHandler::AddOverflow, SanitizerHandler::SubOverflow, @@ -303,6 +303,30 @@ void __ubsan_handle_negate_overflow(void *_data, void *old_val) } EXPORT_SYMBOL(__ubsan_handle_negate_overflow); +void __ubsan_handle_implicit_conversion(void *_data, void *from_val, void *to_val) +{ + struct implicit_conversion_data *data = _data; + char from_val_str[VALUE_LENGTH]; + char to_val_str[VALUE_LENGTH]; + + if (suppress_report(&data->location)) + return; + + val_to_string(from_val_str, sizeof(from_val_str), data->from_type, from_val); + val_to_string(to_val_str, sizeof(to_val_str), data->to_type, to_val); + + ubsan_prologue(&data->location, "implicit-conversion"); + + pr_err("cannot represent %s value %s during %s %s, truncated to %s\n", + data->from_type->type_name, + from_val_str, + type_check_kinds[data->type_check_kind], + data->to_type->type_name, + to_val_str); + + ubsan_epilogue(); +} +EXPORT_SYMBOL(__ubsan_handle_implicit_conversion); void __ubsan_handle_divrem_overflow(void *_data, void *lhs, void *rhs) { diff --git a/lib/ubsan.h b/lib/ubsan.h index 07e37d4429b4..b37e22374e77 100644 --- a/lib/ubsan.h +++ b/lib/ubsan.h @@ -62,6 +62,13 @@ struct overflow_data { struct type_descriptor *type; }; +struct implicit_conversion_data { + struct source_location location; + struct type_descriptor *from_type; + struct type_descriptor *to_type; + unsigned char type_check_kind; +}; + struct type_mismatch_data { struct source_location location; struct type_descriptor *type; @@ -142,6 +149,7 @@ void ubsan_linkage __ubsan_handle_sub_overflow(void *data, void *lhs, void *rhs) void ubsan_linkage __ubsan_handle_mul_overflow(void *data, void *lhs, void *rhs); void ubsan_linkage __ubsan_handle_negate_overflow(void *_data, void *old_val); void ubsan_linkage __ubsan_handle_divrem_overflow(void *_data, void *lhs, void *rhs); +void ubsan_linkage __ubsan_handle_implicit_conversion(void *_data, void *lhs, void *rhs); void ubsan_linkage __ubsan_handle_type_mismatch(struct type_mismatch_data *data, void *ptr); void ubsan_linkage __ubsan_handle_type_mismatch_v1(void *_data, void *ptr); void ubsan_linkage __ubsan_handle_out_of_bounds(void *_data, void *index); diff --git a/lib/vdso/Kconfig b/lib/vdso/Kconfig index 82fe827af542..45df764b49ad 100644 --- a/lib/vdso/Kconfig +++ b/lib/vdso/Kconfig @@ -43,3 +43,8 @@ config VDSO_GETRANDOM bool help Selected by architectures that support vDSO getrandom(). + +config GENERIC_VDSO_DATA_STORE + bool + help + Selected by architectures that use the generic vDSO data store. diff --git a/lib/vdso/Makefile b/lib/vdso/Makefile index cedbf15f8087..aedd40aaa950 100644 --- a/lib/vdso/Makefile +++ b/lib/vdso/Makefile @@ -1,18 +1,3 @@ -# SPDX-License-Identifier: GPL-2.0 +# SPDX-License-Identifier: GPL-2.0-only -GENERIC_VDSO_MK_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) -GENERIC_VDSO_DIR := $(dir $(GENERIC_VDSO_MK_PATH)) - -c-gettimeofday-$(CONFIG_GENERIC_GETTIMEOFDAY) := $(addprefix $(GENERIC_VDSO_DIR), gettimeofday.c) -c-getrandom-$(CONFIG_VDSO_GETRANDOM) := $(addprefix $(GENERIC_VDSO_DIR), getrandom.c) - -# This cmd checks that the vdso library does not contain dynamic relocations. -# It has to be called after the linking of the vdso library and requires it -# as a parameter. -# -# As a workaround for some GNU ld ports which produce unneeded R_*_NONE -# dynamic relocations, ignore R_*_NONE. -quiet_cmd_vdso_check = VDSOCHK $@ - cmd_vdso_check = if $(READELF) -rW $@ | grep -v _NONE | grep -q " R_\w*_"; \ - then (echo >&2 "$@: dynamic relocations are not supported"; \ - rm -f $@; /bin/false); fi +obj-$(CONFIG_GENERIC_VDSO_DATA_STORE) += datastore.o diff --git a/lib/vdso/Makefile.include b/lib/vdso/Makefile.include new file mode 100644 index 000000000000..cedbf15f8087 --- /dev/null +++ b/lib/vdso/Makefile.include @@ -0,0 +1,18 @@ +# SPDX-License-Identifier: GPL-2.0 + +GENERIC_VDSO_MK_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) +GENERIC_VDSO_DIR := $(dir $(GENERIC_VDSO_MK_PATH)) + +c-gettimeofday-$(CONFIG_GENERIC_GETTIMEOFDAY) := $(addprefix $(GENERIC_VDSO_DIR), gettimeofday.c) +c-getrandom-$(CONFIG_VDSO_GETRANDOM) := $(addprefix $(GENERIC_VDSO_DIR), getrandom.c) + +# This cmd checks that the vdso library does not contain dynamic relocations. +# It has to be called after the linking of the vdso library and requires it +# as a parameter. +# +# As a workaround for some GNU ld ports which produce unneeded R_*_NONE +# dynamic relocations, ignore R_*_NONE. +quiet_cmd_vdso_check = VDSOCHK $@ + cmd_vdso_check = if $(READELF) -rW $@ | grep -v _NONE | grep -q " R_\w*_"; \ + then (echo >&2 "$@: dynamic relocations are not supported"; \ + rm -f $@; /bin/false); fi diff --git a/lib/vdso/datastore.c b/lib/vdso/datastore.c new file mode 100644 index 000000000000..c715e217ec65 --- /dev/null +++ b/lib/vdso/datastore.c @@ -0,0 +1,129 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include <linux/linkage.h> +#include <linux/mmap_lock.h> +#include <linux/mm.h> +#include <linux/time_namespace.h> +#include <linux/types.h> +#include <linux/vdso_datastore.h> +#include <vdso/datapage.h> + +/* + * The vDSO data page. + */ +#ifdef CONFIG_HAVE_GENERIC_VDSO +static union { + struct vdso_time_data data; + u8 page[PAGE_SIZE]; +} vdso_time_data_store __page_aligned_data; +struct vdso_time_data *vdso_k_time_data = &vdso_time_data_store.data; +static_assert(sizeof(vdso_time_data_store) == PAGE_SIZE); +#endif /* CONFIG_HAVE_GENERIC_VDSO */ + +#ifdef CONFIG_VDSO_GETRANDOM +static union { + struct vdso_rng_data data; + u8 page[PAGE_SIZE]; +} vdso_rng_data_store __page_aligned_data; +struct vdso_rng_data *vdso_k_rng_data = &vdso_rng_data_store.data; +static_assert(sizeof(vdso_rng_data_store) == PAGE_SIZE); +#endif /* CONFIG_VDSO_GETRANDOM */ + +#ifdef CONFIG_ARCH_HAS_VDSO_ARCH_DATA +static union { + struct vdso_arch_data data; + u8 page[VDSO_ARCH_DATA_SIZE]; +} vdso_arch_data_store __page_aligned_data; +struct vdso_arch_data *vdso_k_arch_data = &vdso_arch_data_store.data; +#endif /* CONFIG_ARCH_HAS_VDSO_ARCH_DATA */ + +static vm_fault_t vvar_fault(const struct vm_special_mapping *sm, + struct vm_area_struct *vma, struct vm_fault *vmf) +{ + struct page *timens_page = find_timens_vvar_page(vma); + unsigned long addr, pfn; + vm_fault_t err; + + switch (vmf->pgoff) { + case VDSO_TIME_PAGE_OFFSET: + if (!IS_ENABLED(CONFIG_HAVE_GENERIC_VDSO)) + return VM_FAULT_SIGBUS; + pfn = __phys_to_pfn(__pa_symbol(vdso_k_time_data)); + if (timens_page) { + /* + * Fault in VVAR page too, since it will be accessed + * to get clock data anyway. + */ + addr = vmf->address + VDSO_TIMENS_PAGE_OFFSET * PAGE_SIZE; + err = vmf_insert_pfn(vma, addr, pfn); + if (unlikely(err & VM_FAULT_ERROR)) + return err; + pfn = page_to_pfn(timens_page); + } + break; + case VDSO_TIMENS_PAGE_OFFSET: + /* + * If a task belongs to a time namespace then a namespace + * specific VVAR is mapped with the VVAR_DATA_PAGE_OFFSET and + * the real VVAR page is mapped with the VVAR_TIMENS_PAGE_OFFSET + * offset. + * See also the comment near timens_setup_vdso_data(). + */ + if (!IS_ENABLED(CONFIG_TIME_NS) || !timens_page) + return VM_FAULT_SIGBUS; + pfn = __phys_to_pfn(__pa_symbol(vdso_k_time_data)); + break; + case VDSO_RNG_PAGE_OFFSET: + if (!IS_ENABLED(CONFIG_VDSO_GETRANDOM)) + return VM_FAULT_SIGBUS; + pfn = __phys_to_pfn(__pa_symbol(vdso_k_rng_data)); + break; + case VDSO_ARCH_PAGES_START ... VDSO_ARCH_PAGES_END: + if (!IS_ENABLED(CONFIG_ARCH_HAS_VDSO_ARCH_DATA)) + return VM_FAULT_SIGBUS; + pfn = __phys_to_pfn(__pa_symbol(vdso_k_arch_data)) + + vmf->pgoff - VDSO_ARCH_PAGES_START; + break; + default: + return VM_FAULT_SIGBUS; + } + + return vmf_insert_pfn(vma, vmf->address, pfn); +} + +const struct vm_special_mapping vdso_vvar_mapping = { + .name = "[vvar]", + .fault = vvar_fault, +}; + +struct vm_area_struct *vdso_install_vvar_mapping(struct mm_struct *mm, unsigned long addr) +{ + return _install_special_mapping(mm, addr, VDSO_NR_PAGES * PAGE_SIZE, + VM_READ | VM_MAYREAD | VM_IO | VM_DONTDUMP | VM_PFNMAP, + &vdso_vvar_mapping); +} + +#ifdef CONFIG_TIME_NS +/* + * The vvar page layout depends on whether a task belongs to the root or + * non-root time namespace. Whenever a task changes its namespace, the VVAR + * page tables are cleared and then they will be re-faulted with a + * corresponding layout. + * See also the comment near timens_setup_vdso_clock_data() for details. + */ +int vdso_join_timens(struct task_struct *task, struct time_namespace *ns) +{ + struct mm_struct *mm = task->mm; + struct vm_area_struct *vma; + VMA_ITERATOR(vmi, mm, 0); + + mmap_read_lock(mm); + for_each_vma(vmi, vma) { + if (vma_is_special_mapping(vma, &vdso_vvar_mapping)) + zap_vma_pages(vma); + } + mmap_read_unlock(mm); + + return 0; +} +#endif diff --git a/lib/vdso/getrandom.c b/lib/vdso/getrandom.c index 938ca539aaa6..440f8a6203a6 100644 --- a/lib/vdso/getrandom.c +++ b/lib/vdso/getrandom.c @@ -12,6 +12,9 @@ #include <uapi/linux/mman.h> #include <uapi/linux/random.h> +/* Bring in default accessors */ +#include <vdso/vsyscall.h> + #undef PAGE_SIZE #undef PAGE_MASK #define PAGE_SIZE (1UL << CONFIG_PAGE_SHIFT) @@ -152,7 +155,7 @@ retry_generation: /* * Prevent the syscall from being reordered wrt current_generation. Pairs with the - * smp_store_release(&_vdso_rng_data.generation) in random.c. + * smp_store_release(&vdso_k_rng_data->generation) in random.c. */ smp_rmb(); @@ -256,5 +259,6 @@ fallback_syscall: static __always_inline ssize_t __cvdso_getrandom(void *buffer, size_t len, unsigned int flags, void *opaque_state, size_t opaque_len) { - return __cvdso_getrandom_data(__arch_get_vdso_rng_data(), buffer, len, flags, opaque_state, opaque_len); + return __cvdso_getrandom_data(__arch_get_vdso_u_rng_data(), buffer, len, flags, + opaque_state, opaque_len); } diff --git a/lib/vdso/gettimeofday.c b/lib/vdso/gettimeofday.c index c01eaafd8041..93ef801a97ef 100644 --- a/lib/vdso/gettimeofday.c +++ b/lib/vdso/gettimeofday.c @@ -5,6 +5,9 @@ #include <vdso/datapage.h> #include <vdso/helpers.h> +/* Bring in default accessors */ +#include <vdso/vsyscall.h> + #ifndef vdso_calc_ns #ifdef VDSO_DELTA_NOMASK @@ -14,12 +17,12 @@ #endif #ifdef CONFIG_GENERIC_VDSO_OVERFLOW_PROTECT -static __always_inline bool vdso_delta_ok(const struct vdso_data *vd, u64 delta) +static __always_inline bool vdso_delta_ok(const struct vdso_clock *vc, u64 delta) { - return delta < vd->max_cycles; + return delta < vc->max_cycles; } #else -static __always_inline bool vdso_delta_ok(const struct vdso_data *vd, u64 delta) +static __always_inline bool vdso_delta_ok(const struct vdso_clock *vc, u64 delta) { return true; } @@ -36,14 +39,14 @@ static __always_inline u64 vdso_shift_ns(u64 ns, u32 shift) * Default implementation which works for all sane clocksources. That * obviously excludes x86/TSC. */ -static __always_inline u64 vdso_calc_ns(const struct vdso_data *vd, u64 cycles, u64 base) +static __always_inline u64 vdso_calc_ns(const struct vdso_clock *vc, u64 cycles, u64 base) { - u64 delta = (cycles - vd->cycle_last) & VDSO_DELTA_MASK(vd); + u64 delta = (cycles - vc->cycle_last) & VDSO_DELTA_MASK(vc); - if (likely(vdso_delta_ok(vd, delta))) - return vdso_shift_ns((delta * vd->mult) + base, vd->shift); + if (likely(vdso_delta_ok(vc, delta))) + return vdso_shift_ns((delta * vc->mult) + base, vc->shift); - return mul_u64_u32_add_u64_shr(delta, vd->mult, base, vd->shift); + return mul_u64_u32_add_u64_shr(delta, vc->mult, base, vc->shift); } #endif /* vdso_calc_ns */ @@ -55,9 +58,9 @@ static inline bool __arch_vdso_hres_capable(void) #endif #ifndef vdso_clocksource_ok -static inline bool vdso_clocksource_ok(const struct vdso_data *vd) +static inline bool vdso_clocksource_ok(const struct vdso_clock *vc) { - return vd->clock_mode != VDSO_CLOCKMODE_NONE; + return vc->clock_mode != VDSO_CLOCKMODE_NONE; } #endif @@ -69,36 +72,45 @@ static inline bool vdso_cycles_ok(u64 cycles) #endif #ifdef CONFIG_TIME_NS -static __always_inline int do_hres_timens(const struct vdso_data *vdns, clockid_t clk, - struct __kernel_timespec *ts) + +#ifdef CONFIG_GENERIC_VDSO_DATA_STORE +static __always_inline +const struct vdso_time_data *__arch_get_vdso_u_timens_data(const struct vdso_time_data *vd) +{ + return (void *)vd + PAGE_SIZE; +} +#endif /* CONFIG_GENERIC_VDSO_DATA_STORE */ + +static __always_inline +int do_hres_timens(const struct vdso_time_data *vdns, const struct vdso_clock *vcns, + clockid_t clk, struct __kernel_timespec *ts) { - const struct timens_offset *offs = &vdns->offset[clk]; + const struct vdso_time_data *vd = __arch_get_vdso_u_timens_data(vdns); + const struct timens_offset *offs = &vcns->offset[clk]; + const struct vdso_clock *vc = vd->clock_data; const struct vdso_timestamp *vdso_ts; - const struct vdso_data *vd; u64 cycles, ns; u32 seq; s64 sec; - vd = vdns - (clk == CLOCK_MONOTONIC_RAW ? CS_RAW : CS_HRES_COARSE); - vd = __arch_get_timens_vdso_data(vd); if (clk != CLOCK_MONOTONIC_RAW) - vd = &vd[CS_HRES_COARSE]; + vc = &vc[CS_HRES_COARSE]; else - vd = &vd[CS_RAW]; - vdso_ts = &vd->basetime[clk]; + vc = &vc[CS_RAW]; + vdso_ts = &vc->basetime[clk]; do { - seq = vdso_read_begin(vd); + seq = vdso_read_begin(vc); - if (unlikely(!vdso_clocksource_ok(vd))) + if (unlikely(!vdso_clocksource_ok(vc))) return -1; - cycles = __arch_get_hw_counter(vd->clock_mode, vd); + cycles = __arch_get_hw_counter(vc->clock_mode, vd); if (unlikely(!vdso_cycles_ok(cycles))) return -1; - ns = vdso_calc_ns(vd, cycles, vdso_ts->nsec); + ns = vdso_calc_ns(vc, cycles, vdso_ts->nsec); sec = vdso_ts->sec; - } while (unlikely(vdso_read_retry(vd, seq))); + } while (unlikely(vdso_read_retry(vc, seq))); /* Add the namespace offset */ sec += offs->sec; @@ -115,22 +127,24 @@ static __always_inline int do_hres_timens(const struct vdso_data *vdns, clockid_ } #else static __always_inline -const struct vdso_data *__arch_get_timens_vdso_data(const struct vdso_data *vd) +const struct vdso_time_data *__arch_get_vdso_u_timens_data(const struct vdso_time_data *vd) { return NULL; } -static __always_inline int do_hres_timens(const struct vdso_data *vdns, clockid_t clk, - struct __kernel_timespec *ts) +static __always_inline +int do_hres_timens(const struct vdso_time_data *vdns, const struct vdso_clock *vcns, + clockid_t clk, struct __kernel_timespec *ts) { return -EINVAL; } #endif -static __always_inline int do_hres(const struct vdso_data *vd, clockid_t clk, - struct __kernel_timespec *ts) +static __always_inline +int do_hres(const struct vdso_time_data *vd, const struct vdso_clock *vc, + clockid_t clk, struct __kernel_timespec *ts) { - const struct vdso_timestamp *vdso_ts = &vd->basetime[clk]; + const struct vdso_timestamp *vdso_ts = &vc->basetime[clk]; u64 cycles, sec, ns; u32 seq; @@ -142,31 +156,31 @@ static __always_inline int do_hres(const struct vdso_data *vd, clockid_t clk, /* * Open coded function vdso_read_begin() to handle * VDSO_CLOCKMODE_TIMENS. Time namespace enabled tasks have a - * special VVAR page installed which has vd->seq set to 1 and - * vd->clock_mode set to VDSO_CLOCKMODE_TIMENS. For non time + * special VVAR page installed which has vc->seq set to 1 and + * vc->clock_mode set to VDSO_CLOCKMODE_TIMENS. For non time * namespace affected tasks this does not affect performance - * because if vd->seq is odd, i.e. a concurrent update is in - * progress the extra check for vd->clock_mode is just a few - * extra instructions while spin waiting for vd->seq to become + * because if vc->seq is odd, i.e. a concurrent update is in + * progress the extra check for vc->clock_mode is just a few + * extra instructions while spin waiting for vc->seq to become * even again. */ - while (unlikely((seq = READ_ONCE(vd->seq)) & 1)) { + while (unlikely((seq = READ_ONCE(vc->seq)) & 1)) { if (IS_ENABLED(CONFIG_TIME_NS) && - vd->clock_mode == VDSO_CLOCKMODE_TIMENS) - return do_hres_timens(vd, clk, ts); + vc->clock_mode == VDSO_CLOCKMODE_TIMENS) + return do_hres_timens(vd, vc, clk, ts); cpu_relax(); } smp_rmb(); - if (unlikely(!vdso_clocksource_ok(vd))) + if (unlikely(!vdso_clocksource_ok(vc))) return -1; - cycles = __arch_get_hw_counter(vd->clock_mode, vd); + cycles = __arch_get_hw_counter(vc->clock_mode, vd); if (unlikely(!vdso_cycles_ok(cycles))) return -1; - ns = vdso_calc_ns(vd, cycles, vdso_ts->nsec); + ns = vdso_calc_ns(vc, cycles, vdso_ts->nsec); sec = vdso_ts->sec; - } while (unlikely(vdso_read_retry(vd, seq))); + } while (unlikely(vdso_read_retry(vc, seq))); /* * Do this outside the loop: a race inside the loop could result @@ -179,21 +193,25 @@ static __always_inline int do_hres(const struct vdso_data *vd, clockid_t clk, } #ifdef CONFIG_TIME_NS -static __always_inline int do_coarse_timens(const struct vdso_data *vdns, clockid_t clk, - struct __kernel_timespec *ts) +static __always_inline +int do_coarse_timens(const struct vdso_time_data *vdns, const struct vdso_clock *vcns, + clockid_t clk, struct __kernel_timespec *ts) { - const struct vdso_data *vd = __arch_get_timens_vdso_data(vdns); - const struct vdso_timestamp *vdso_ts = &vd->basetime[clk]; - const struct timens_offset *offs = &vdns->offset[clk]; + const struct vdso_time_data *vd = __arch_get_vdso_u_timens_data(vdns); + const struct timens_offset *offs = &vcns->offset[clk]; + const struct vdso_clock *vc = vd->clock_data; + const struct vdso_timestamp *vdso_ts; u64 nsec; s64 sec; s32 seq; + vdso_ts = &vc->basetime[clk]; + do { - seq = vdso_read_begin(vd); + seq = vdso_read_begin(vc); sec = vdso_ts->sec; nsec = vdso_ts->nsec; - } while (unlikely(vdso_read_retry(vd, seq))); + } while (unlikely(vdso_read_retry(vc, seq))); /* Add the namespace offset */ sec += offs->sec; @@ -208,17 +226,19 @@ static __always_inline int do_coarse_timens(const struct vdso_data *vdns, clocki return 0; } #else -static __always_inline int do_coarse_timens(const struct vdso_data *vdns, clockid_t clk, - struct __kernel_timespec *ts) +static __always_inline +int do_coarse_timens(const struct vdso_time_data *vdns, const struct vdso_clock *vcns, + clockid_t clk, struct __kernel_timespec *ts) { return -1; } #endif -static __always_inline int do_coarse(const struct vdso_data *vd, clockid_t clk, - struct __kernel_timespec *ts) +static __always_inline +int do_coarse(const struct vdso_time_data *vd, const struct vdso_clock *vc, + clockid_t clk, struct __kernel_timespec *ts) { - const struct vdso_timestamp *vdso_ts = &vd->basetime[clk]; + const struct vdso_timestamp *vdso_ts = &vc->basetime[clk]; u32 seq; do { @@ -226,25 +246,26 @@ static __always_inline int do_coarse(const struct vdso_data *vd, clockid_t clk, * Open coded function vdso_read_begin() to handle * VDSO_CLOCK_TIMENS. See comment in do_hres(). */ - while ((seq = READ_ONCE(vd->seq)) & 1) { + while ((seq = READ_ONCE(vc->seq)) & 1) { if (IS_ENABLED(CONFIG_TIME_NS) && - vd->clock_mode == VDSO_CLOCKMODE_TIMENS) - return do_coarse_timens(vd, clk, ts); + vc->clock_mode == VDSO_CLOCKMODE_TIMENS) + return do_coarse_timens(vd, vc, clk, ts); cpu_relax(); } smp_rmb(); ts->tv_sec = vdso_ts->sec; ts->tv_nsec = vdso_ts->nsec; - } while (unlikely(vdso_read_retry(vd, seq))); + } while (unlikely(vdso_read_retry(vc, seq))); return 0; } static __always_inline int -__cvdso_clock_gettime_common(const struct vdso_data *vd, clockid_t clock, +__cvdso_clock_gettime_common(const struct vdso_time_data *vd, clockid_t clock, struct __kernel_timespec *ts) { + const struct vdso_clock *vc = vd->clock_data; u32 msk; /* Check for negative values or invalid clocks */ @@ -257,19 +278,19 @@ __cvdso_clock_gettime_common(const struct vdso_data *vd, clockid_t clock, */ msk = 1U << clock; if (likely(msk & VDSO_HRES)) - vd = &vd[CS_HRES_COARSE]; + vc = &vc[CS_HRES_COARSE]; else if (msk & VDSO_COARSE) - return do_coarse(&vd[CS_HRES_COARSE], clock, ts); + return do_coarse(vd, &vc[CS_HRES_COARSE], clock, ts); else if (msk & VDSO_RAW) - vd = &vd[CS_RAW]; + vc = &vc[CS_RAW]; else return -1; - return do_hres(vd, clock, ts); + return do_hres(vd, vc, clock, ts); } static __maybe_unused int -__cvdso_clock_gettime_data(const struct vdso_data *vd, clockid_t clock, +__cvdso_clock_gettime_data(const struct vdso_time_data *vd, clockid_t clock, struct __kernel_timespec *ts) { int ret = __cvdso_clock_gettime_common(vd, clock, ts); @@ -282,12 +303,12 @@ __cvdso_clock_gettime_data(const struct vdso_data *vd, clockid_t clock, static __maybe_unused int __cvdso_clock_gettime(clockid_t clock, struct __kernel_timespec *ts) { - return __cvdso_clock_gettime_data(__arch_get_vdso_data(), clock, ts); + return __cvdso_clock_gettime_data(__arch_get_vdso_u_time_data(), clock, ts); } #ifdef BUILD_VDSO32 static __maybe_unused int -__cvdso_clock_gettime32_data(const struct vdso_data *vd, clockid_t clock, +__cvdso_clock_gettime32_data(const struct vdso_time_data *vd, clockid_t clock, struct old_timespec32 *res) { struct __kernel_timespec ts; @@ -308,19 +329,20 @@ __cvdso_clock_gettime32_data(const struct vdso_data *vd, clockid_t clock, static __maybe_unused int __cvdso_clock_gettime32(clockid_t clock, struct old_timespec32 *res) { - return __cvdso_clock_gettime32_data(__arch_get_vdso_data(), clock, res); + return __cvdso_clock_gettime32_data(__arch_get_vdso_u_time_data(), clock, res); } #endif /* BUILD_VDSO32 */ static __maybe_unused int -__cvdso_gettimeofday_data(const struct vdso_data *vd, +__cvdso_gettimeofday_data(const struct vdso_time_data *vd, struct __kernel_old_timeval *tv, struct timezone *tz) { + const struct vdso_clock *vc = vd->clock_data; if (likely(tv != NULL)) { struct __kernel_timespec ts; - if (do_hres(&vd[CS_HRES_COARSE], CLOCK_REALTIME, &ts)) + if (do_hres(vd, &vc[CS_HRES_COARSE], CLOCK_REALTIME, &ts)) return gettimeofday_fallback(tv, tz); tv->tv_sec = ts.tv_sec; @@ -329,8 +351,8 @@ __cvdso_gettimeofday_data(const struct vdso_data *vd, if (unlikely(tz != NULL)) { if (IS_ENABLED(CONFIG_TIME_NS) && - vd->clock_mode == VDSO_CLOCKMODE_TIMENS) - vd = __arch_get_timens_vdso_data(vd); + vc->clock_mode == VDSO_CLOCKMODE_TIMENS) + vd = __arch_get_vdso_u_timens_data(vd); tz->tz_minuteswest = vd[CS_HRES_COARSE].tz_minuteswest; tz->tz_dsttime = vd[CS_HRES_COARSE].tz_dsttime; @@ -342,20 +364,23 @@ __cvdso_gettimeofday_data(const struct vdso_data *vd, static __maybe_unused int __cvdso_gettimeofday(struct __kernel_old_timeval *tv, struct timezone *tz) { - return __cvdso_gettimeofday_data(__arch_get_vdso_data(), tv, tz); + return __cvdso_gettimeofday_data(__arch_get_vdso_u_time_data(), tv, tz); } #ifdef VDSO_HAS_TIME static __maybe_unused __kernel_old_time_t -__cvdso_time_data(const struct vdso_data *vd, __kernel_old_time_t *time) +__cvdso_time_data(const struct vdso_time_data *vd, __kernel_old_time_t *time) { + const struct vdso_clock *vc = vd->clock_data; __kernel_old_time_t t; if (IS_ENABLED(CONFIG_TIME_NS) && - vd->clock_mode == VDSO_CLOCKMODE_TIMENS) - vd = __arch_get_timens_vdso_data(vd); + vc->clock_mode == VDSO_CLOCKMODE_TIMENS) { + vd = __arch_get_vdso_u_timens_data(vd); + vc = vd->clock_data; + } - t = READ_ONCE(vd[CS_HRES_COARSE].basetime[CLOCK_REALTIME].sec); + t = READ_ONCE(vc[CS_HRES_COARSE].basetime[CLOCK_REALTIME].sec); if (time) *time = t; @@ -365,15 +390,16 @@ __cvdso_time_data(const struct vdso_data *vd, __kernel_old_time_t *time) static __maybe_unused __kernel_old_time_t __cvdso_time(__kernel_old_time_t *time) { - return __cvdso_time_data(__arch_get_vdso_data(), time); + return __cvdso_time_data(__arch_get_vdso_u_time_data(), time); } #endif /* VDSO_HAS_TIME */ #ifdef VDSO_HAS_CLOCK_GETRES static __maybe_unused -int __cvdso_clock_getres_common(const struct vdso_data *vd, clockid_t clock, +int __cvdso_clock_getres_common(const struct vdso_time_data *vd, clockid_t clock, struct __kernel_timespec *res) { + const struct vdso_clock *vc = vd->clock_data; u32 msk; u64 ns; @@ -382,8 +408,8 @@ int __cvdso_clock_getres_common(const struct vdso_data *vd, clockid_t clock, return -1; if (IS_ENABLED(CONFIG_TIME_NS) && - vd->clock_mode == VDSO_CLOCKMODE_TIMENS) - vd = __arch_get_timens_vdso_data(vd); + vc->clock_mode == VDSO_CLOCKMODE_TIMENS) + vd = __arch_get_vdso_u_timens_data(vd); /* * Convert the clockid to a bitmask and use it to check which @@ -394,7 +420,7 @@ int __cvdso_clock_getres_common(const struct vdso_data *vd, clockid_t clock, /* * Preserves the behaviour of posix_get_hrtimer_res(). */ - ns = READ_ONCE(vd[CS_HRES_COARSE].hrtimer_res); + ns = READ_ONCE(vd->hrtimer_res); } else if (msk & VDSO_COARSE) { /* * Preserves the behaviour of posix_get_coarse_res(). @@ -412,7 +438,7 @@ int __cvdso_clock_getres_common(const struct vdso_data *vd, clockid_t clock, } static __maybe_unused -int __cvdso_clock_getres_data(const struct vdso_data *vd, clockid_t clock, +int __cvdso_clock_getres_data(const struct vdso_time_data *vd, clockid_t clock, struct __kernel_timespec *res) { int ret = __cvdso_clock_getres_common(vd, clock, res); @@ -425,12 +451,12 @@ int __cvdso_clock_getres_data(const struct vdso_data *vd, clockid_t clock, static __maybe_unused int __cvdso_clock_getres(clockid_t clock, struct __kernel_timespec *res) { - return __cvdso_clock_getres_data(__arch_get_vdso_data(), clock, res); + return __cvdso_clock_getres_data(__arch_get_vdso_u_time_data(), clock, res); } #ifdef BUILD_VDSO32 static __maybe_unused int -__cvdso_clock_getres_time32_data(const struct vdso_data *vd, clockid_t clock, +__cvdso_clock_getres_time32_data(const struct vdso_time_data *vd, clockid_t clock, struct old_timespec32 *res) { struct __kernel_timespec ts; @@ -451,7 +477,7 @@ __cvdso_clock_getres_time32_data(const struct vdso_data *vd, clockid_t clock, static __maybe_unused int __cvdso_clock_getres_time32(clockid_t clock, struct old_timespec32 *res) { - return __cvdso_clock_getres_time32_data(__arch_get_vdso_data(), + return __cvdso_clock_getres_time32_data(__arch_get_vdso_u_time_data(), clock, res); } #endif /* BUILD_VDSO32 */ diff --git a/lib/vsprintf.c b/lib/vsprintf.c index 56fe96319292..734bd70c8b9b 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c @@ -114,6 +114,13 @@ unsigned long simple_strtoul(const char *cp, char **endp, unsigned int base) } EXPORT_SYMBOL(simple_strtoul); +unsigned long simple_strntoul(const char *cp, char **endp, unsigned int base, + size_t max_chars) +{ + return simple_strntoull(cp, endp, base, max_chars); +} +EXPORT_SYMBOL(simple_strntoul); + /** * simple_strtol - convert a string to a signed long * @cp: The start of the string diff --git a/lib/zstd/common/portability_macros.h b/lib/zstd/common/portability_macros.h index 0e3b2c0a527d..0dde8bf56595 100644 --- a/lib/zstd/common/portability_macros.h +++ b/lib/zstd/common/portability_macros.h @@ -55,7 +55,7 @@ #ifndef DYNAMIC_BMI2 #if ((defined(__clang__) && __has_attribute(__target__)) \ || (defined(__GNUC__) \ - && (__GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)))) \ + && (__GNUC__ >= 11))) \ && (defined(__x86_64__) || defined(_M_X64)) \ && !defined(__BMI2__) # define DYNAMIC_BMI2 1 |