diff options
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/Kconfig.debug | 107 | ||||
| -rw-r--r-- | lib/Kconfig.ubsan | 25 | ||||
| -rw-r--r-- | lib/Makefile | 46 | ||||
| -rw-r--r-- | lib/atomic64_test.c | 2 | ||||
| -rw-r--r-- | lib/cpumask.c | 37 | ||||
| -rw-r--r-- | lib/dump_stack.c | 4 | ||||
| -rw-r--r-- | lib/iov_iter.c | 8 | ||||
| -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) | 0 | ||||
| -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 | 
58 files changed, 1490 insertions, 808 deletions
| diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 35796c290ca3..b1b92a9a8f24 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 @@ -3166,7 +3203,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 +3234,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..b752fcbc83d2 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 @@ -368,32 +360,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/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/iov_iter.c b/lib/iov_iter.c index 65f550cb5081..8c7fdb7d8c8f 100644 --- a/lib/iov_iter.c +++ b/lib/iov_iter.c @@ -1190,8 +1190,12 @@ static ssize_t __iov_iter_get_pages_alloc(struct iov_iter *i,  		if (!n)  			return -ENOMEM;  		p = *pages; -		for (int k = 0; k < n; k++) -			get_page(p[k] = page + k); +		for (int k = 0; k < n; k++) { +			struct folio *folio = page_folio(page); +			p[k] = page + k; +			if (!folio_test_slab(folio)) +				folio_get(folio); +		}  		maxsize = min_t(size_t, maxsize, n * PAGE_SIZE - *start);  		i->count -= maxsize;  		i->iov_offset += maxsize; 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..6a61d4b5fd45 100644 --- a/lib/crc_kunit.c +++ b/lib/tests/crc_kunit.c 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 | 
