Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

selftests: add new kallsyms selftests

We lack find_symbol() selftests, so add one. This let's us stress test
improvements easily on find_symbol() or optimizations. It also inherently
allows us to test the limits of kallsyms on Linux today.

We test a pathalogical use case for kallsyms by introducing modules
which are automatically written for us with a larger number of symbols.
We have 4 kallsyms test modules:

A: has KALLSYSMS_NUMSYMS exported symbols
B: uses one of A's symbols
C: adds KALLSYMS_SCALE_FACTOR * KALLSYSMS_NUMSYMS exported
D: adds 2 * the symbols than C

By using anything much larger than KALLSYSMS_NUMSYMS as 10,000 and
KALLSYMS_SCALE_FACTOR of 8 we segfault today. So we're capped at
around 160000 symbols somehow today. We can inpsect that issue at
our leasure later, but for now the real value to this test is that
this will easily allow us to test improvements on find_symbol().

We want to enable this test on allyesmodconfig builds so we can't
use this combination, so instead just use a safe value for now and
be informative on the Kconfig symbol documentation about where our
thresholds are for testers. We default then to KALLSYSMS_NUMSYMS of
just 100 and KALLSYMS_SCALE_FACTOR of 8.

On x86_64 we can use perf, for other architectures we just use 'time'
and allow for customizations. For example a future enhancements could
be done for parisc to check for unaligned accesses which triggers a
special special exception handler assembler code inside the kernel.
The negative impact on performance is so large on parisc that it
keeps track of its accesses on /proc/cpuinfo as UAH:

IRQ: CPU0 CPU1
3: 1332 0 SuperIO ttyS0
7: 1270013 0 SuperIO pata_ns87415
64: 320023012 320021431 CPU timer
65: 17080507 20624423 CPU IPI
UAH: 10948640 58104 Unaligned access handler traps

While at it, this tidies up lib/ test modules to allow us to have
a new directory for them. The amount of test modules under lib/
is insane.

This should also hopefully showcase how to start doing basic
self module writing code, which may be more useful for more complex
cases later in the future.

Signed-off-by: Luis Chamberlain <mcgrof@kernel.org>

+350
+105
lib/Kconfig.debug
··· 2903 2903 2904 2904 If unsure, say N. 2905 2905 2906 + config TEST_RUNTIME 2907 + bool 2908 + 2909 + config TEST_RUNTIME_MODULE 2910 + bool 2911 + 2912 + config TEST_KALLSYMS 2913 + tristate "module kallsyms find_symbol() test" 2914 + depends on m 2915 + select TEST_RUNTIME 2916 + select TEST_RUNTIME_MODULE 2917 + select TEST_KALLSYMS_A 2918 + select TEST_KALLSYMS_B 2919 + select TEST_KALLSYMS_C 2920 + select TEST_KALLSYMS_D 2921 + help 2922 + This allows us to stress test find_symbol() through the kallsyms 2923 + used to place symbols on the kernel ELF kallsyms and modules kallsyms 2924 + where we place kernel symbols such as exported symbols. 2925 + 2926 + We have four test modules: 2927 + 2928 + A: has KALLSYSMS_NUMSYMS exported symbols 2929 + B: uses one of A's symbols 2930 + C: adds KALLSYMS_SCALE_FACTOR * KALLSYSMS_NUMSYMS exported 2931 + D: adds 2 * the symbols than C 2932 + 2933 + We stress test find_symbol() through two means: 2934 + 2935 + 1) Upon load of B it will trigger simplify_symbols() to look for the 2936 + one symbol it uses from the module A with tons of symbols. This is an 2937 + indirect way for us to have B call resolve_symbol_wait() upon module 2938 + load. This will eventually call find_symbol() which will eventually 2939 + try to find the symbols used with find_exported_symbol_in_section(). 2940 + find_exported_symbol_in_section() uses bsearch() so a binary search 2941 + for each symbol. Binary search will at worst be O(log(n)) so the 2942 + larger TEST_MODULE_KALLSYSMS the worse the search. 2943 + 2944 + 2) The selftests should load C first, before B. Upon B's load towards 2945 + the end right before we call module B's init routine we get 2946 + complete_formation() called on the module. That will first check 2947 + for duplicate symbols with the call to verify_exported_symbols(). 2948 + That is when we'll force iteration on module C's insane symbol list. 2949 + Since it has 10 * KALLSYMS_NUMSYMS it means we can first test 2950 + just loading B without C. The amount of time it takes to load C Vs 2951 + B can give us an idea of the impact growth of the symbol space and 2952 + give us projection. Module A only uses one symbol from B so to allow 2953 + this scaling in module C to be proportional, if it used more symbols 2954 + then the first test would be doing more and increasing just the 2955 + search space would be slightly different. The last module, module D 2956 + will just increase the search space by twice the number of symbols in 2957 + C so to allow for full projects. 2958 + 2959 + tools/testing/selftests/module/find_symbol.sh 2960 + 2961 + The current defaults will incur a build delay of about 7 minutes 2962 + on an x86_64 with only 8 cores. Enable this only if you want to 2963 + stress test find_symbol() with thousands of symbols. At the same 2964 + time this is also useful to test building modules with thousands of 2965 + symbols, and if BTF is enabled this also stress tests adding BTF 2966 + information for each module. Currently enabling many more symbols 2967 + will segfault the build system. 2968 + 2969 + If unsure, say N. 2970 + 2971 + if TEST_KALLSYMS 2972 + 2973 + config TEST_KALLSYMS_A 2974 + tristate 2975 + depends on m 2976 + 2977 + config TEST_KALLSYMS_B 2978 + tristate 2979 + depends on m 2980 + 2981 + config TEST_KALLSYMS_C 2982 + tristate 2983 + depends on m 2984 + 2985 + config TEST_KALLSYMS_D 2986 + tristate 2987 + depends on m 2988 + 2989 + config TEST_KALLSYMS_NUMSYMS 2990 + int "test kallsyms number of symbols" 2991 + default 100 2992 + help 2993 + The number of symbols to create on TEST_KALLSYMS_A, only one of which 2994 + module TEST_KALLSYMS_B will use. This also will be used 2995 + for how many symbols TEST_KALLSYMS_C will have, scaled up by 2996 + TEST_KALLSYMS_SCALE_FACTOR. Note that setting this to 10,000 will 2997 + trigger a segfault today, don't use anything close to it unless 2998 + you are aware that this should not be used for automated build tests. 2999 + 3000 + config TEST_KALLSYMS_SCALE_FACTOR 3001 + int "test kallsyms scale factor" 3002 + default 8 3003 + help 3004 + How many more unusued symbols will TEST_KALLSYSMS_C have than 3005 + TEST_KALLSYMS_A. If 8, then module C will have 8 * syms 3006 + than module A. Then TEST_KALLSYMS_D will have double the amount 3007 + of symbols than C so to allow projections. 3008 + 3009 + endif # TEST_KALLSYMS 3010 + 2906 3011 config TEST_DEBUG_VIRTUAL 2907 3012 tristate "Test CONFIG_DEBUG_VIRTUAL feature" 2908 3013 depends on DEBUG_VIRTUAL
+1
lib/Makefile
··· 96 96 obj-$(CONFIG_TEST_MAPLE_TREE) += test_maple_tree.o 97 97 obj-$(CONFIG_TEST_PARMAN) += test_parman.o 98 98 obj-$(CONFIG_TEST_KMOD) += test_kmod.o 99 + obj-$(CONFIG_TEST_RUNTIME) += tests/ 99 100 obj-$(CONFIG_TEST_DEBUG_VIRTUAL) += test_debug_virtual.o 100 101 obj-$(CONFIG_TEST_MEMCAT_P) += test_memcat_p.o 101 102 obj-$(CONFIG_TEST_OBJAGG) += test_objagg.o
+1
lib/tests/Makefile
··· 1 + obj-$(CONFIG_TEST_RUNTIME_MODULE) += module/
+4
lib/tests/module/.gitignore
··· 1 + test_kallsyms_a.c 2 + test_kallsyms_b.c 3 + test_kallsyms_c.c 4 + test_kallsyms_d.c
+15
lib/tests/module/Makefile
··· 1 + obj-$(CONFIG_TEST_KALLSYMS_A) += test_kallsyms_a.o 2 + obj-$(CONFIG_TEST_KALLSYMS_B) += test_kallsyms_b.o 3 + obj-$(CONFIG_TEST_KALLSYMS_C) += test_kallsyms_c.o 4 + obj-$(CONFIG_TEST_KALLSYMS_D) += test_kallsyms_d.o 5 + 6 + $(obj)/%.c: FORCE 7 + @$(kecho) " GEN $@" 8 + $(Q)$(srctree)/lib/tests/module/gen_test_kallsyms.sh $@\ 9 + $(CONFIG_TEST_KALLSYMS_NUMSYMS) \ 10 + $(CONFIG_TEST_KALLSYMS_SCALE_FACTOR) 11 + 12 + clean-files += test_kallsyms_a.c 13 + clean-files += test_kallsyms_b.c 14 + clean-files += test_kallsyms_c.c 15 + clean-files += test_kallsyms_d.c
+128
lib/tests/module/gen_test_kallsyms.sh
··· 1 + #!/bin/bash 2 + 3 + TARGET=$(basename $1) 4 + DIR=lib/tests/module 5 + TARGET="$DIR/$TARGET" 6 + NUM_SYMS=$2 7 + SCALE_FACTOR=$3 8 + TEST_TYPE=$(echo $TARGET | sed -e 's|lib/tests/module/test_kallsyms_||g') 9 + TEST_TYPE=$(echo $TEST_TYPE | sed -e 's|.c||g') 10 + 11 + gen_template_module_header() 12 + { 13 + cat <<____END_MODULE 14 + // SPDX-License-Identifier: GPL-2.0-or-later OR copyleft-next-0.3.1 15 + /* 16 + * Copyright (C) 2023 Luis Chamberlain <mcgrof@kernel.org> 17 + * 18 + * Automatically generated code for testing, do not edit manually. 19 + */ 20 + 21 + #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 22 + 23 + #include <linux/init.h> 24 + #include <linux/module.h> 25 + #include <linux/printk.h> 26 + 27 + ____END_MODULE 28 + } 29 + 30 + gen_num_syms() 31 + { 32 + PREFIX=$1 33 + NUM=$2 34 + for i in $(seq 1 $NUM); do 35 + printf "int auto_test_%s_%010d = 0xff;\n" $PREFIX $i 36 + printf "EXPORT_SYMBOL_GPL(auto_test_%s_%010d);\n" $PREFIX $i 37 + done 38 + echo 39 + } 40 + 41 + gen_template_module_data_a() 42 + { 43 + gen_num_syms a $1 44 + cat <<____END_MODULE 45 + static int auto_runtime_test(void) 46 + { 47 + return 0; 48 + } 49 + 50 + ____END_MODULE 51 + } 52 + 53 + gen_template_module_data_b() 54 + { 55 + printf "\nextern int auto_test_a_%010d;\n\n" 28 56 + echo "static int auto_runtime_test(void)" 57 + echo "{" 58 + printf "\nreturn auto_test_a_%010d;\n" 28 59 + echo "}" 60 + } 61 + 62 + gen_template_module_data_c() 63 + { 64 + gen_num_syms c $1 65 + cat <<____END_MODULE 66 + static int auto_runtime_test(void) 67 + { 68 + return 0; 69 + } 70 + 71 + ____END_MODULE 72 + } 73 + 74 + gen_template_module_data_d() 75 + { 76 + gen_num_syms d $1 77 + cat <<____END_MODULE 78 + static int auto_runtime_test(void) 79 + { 80 + return 0; 81 + } 82 + 83 + ____END_MODULE 84 + } 85 + 86 + gen_template_module_exit() 87 + { 88 + cat <<____END_MODULE 89 + static int __init auto_test_module_init(void) 90 + { 91 + return auto_runtime_test(); 92 + } 93 + module_init(auto_test_module_init); 94 + 95 + static void __exit auto_test_module_exit(void) 96 + { 97 + } 98 + module_exit(auto_test_module_exit); 99 + 100 + MODULE_AUTHOR("Luis Chamberlain <mcgrof@kernel.org>"); 101 + MODULE_LICENSE("GPL"); 102 + ____END_MODULE 103 + } 104 + 105 + case $TEST_TYPE in 106 + a) 107 + gen_template_module_header > $TARGET 108 + gen_template_module_data_a $NUM_SYMS >> $TARGET 109 + gen_template_module_exit >> $TARGET 110 + ;; 111 + b) 112 + gen_template_module_header > $TARGET 113 + gen_template_module_data_b >> $TARGET 114 + gen_template_module_exit >> $TARGET 115 + ;; 116 + c) 117 + gen_template_module_header > $TARGET 118 + gen_template_module_data_c $((NUM_SYMS * SCALE_FACTOR)) >> $TARGET 119 + gen_template_module_exit >> $TARGET 120 + ;; 121 + d) 122 + gen_template_module_header > $TARGET 123 + gen_template_module_data_d $((NUM_SYMS * SCALE_FACTOR * 2)) >> $TARGET 124 + gen_template_module_exit >> $TARGET 125 + ;; 126 + *) 127 + ;; 128 + esac
+12
tools/testing/selftests/module/Makefile
··· 1 + # SPDX-License-Identifier: GPL-2.0-only 2 + # Makefile for module loading selftests 3 + 4 + # No binaries, but make sure arg-less "make" doesn't trigger "run_tests" 5 + all: 6 + 7 + TEST_PROGS := find_symbol.sh 8 + 9 + include ../lib.mk 10 + 11 + # Nothing to clean up. 12 + clean:
+3
tools/testing/selftests/module/config
··· 1 + CONFIG_TEST_RUNTIME=y 2 + CONFIG_TEST_RUNTIME_MODULE=y 3 + CONFIG_TEST_KALLSYMS=m
+81
tools/testing/selftests/module/find_symbol.sh
··· 1 + #!/bin/bash 2 + # SPDX-License-Identifier: GPL-2.0-or-later OR copyleft-next-0.3.1 3 + # Copyright (C) 2023 Luis Chamberlain <mcgrof@kernel.org> 4 + # 5 + # This is a stress test script for kallsyms through find_symbol() 6 + 7 + set -e 8 + 9 + # Kselftest framework requirement - SKIP code is 4. 10 + ksft_skip=4 11 + 12 + test_reqs() 13 + { 14 + if ! which modprobe 2> /dev/null > /dev/null; then 15 + echo "$0: You need modprobe installed" >&2 16 + exit $ksft_skip 17 + fi 18 + 19 + if ! which kmod 2> /dev/null > /dev/null; then 20 + echo "$0: You need kmod installed" >&2 21 + exit $ksft_skip 22 + fi 23 + 24 + if ! which perf 2> /dev/null > /dev/null; then 25 + echo "$0: You need perf installed" >&2 26 + exit $ksft_skip 27 + fi 28 + 29 + uid=$(id -u) 30 + if [ $uid -ne 0 ]; then 31 + echo $msg must be run as root >&2 32 + exit $ksft_skip 33 + fi 34 + } 35 + 36 + load_mod() 37 + { 38 + local STATS="-e duration_time" 39 + STATS="$STATS -e user_time" 40 + STATS="$STATS -e system_time" 41 + STATS="$STATS -e page-faults" 42 + local MOD=$1 43 + 44 + local ARCH="$(uname -m)" 45 + case "${ARCH}" in 46 + x86_64) 47 + perf stat $STATS $MODPROBE test_kallsyms_b 48 + ;; 49 + *) 50 + time $MODPROBE test_kallsyms_b 51 + exit 1 52 + ;; 53 + esac 54 + } 55 + 56 + remove_all() 57 + { 58 + $MODPROBE -r test_kallsyms_b 59 + for i in a b c d; do 60 + $MODPROBE -r test_kallsyms_$i 61 + done 62 + } 63 + test_reqs 64 + 65 + MODPROBE=$(</proc/sys/kernel/modprobe) 66 + 67 + remove_all 68 + load_mod test_kallsyms_b 69 + remove_all 70 + 71 + # Now pollute the namespace 72 + $MODPROBE test_kallsyms_c 73 + load_mod test_kallsyms_b 74 + 75 + # Now pollute the namespace with twice the number of symbols than the last time 76 + remove_all 77 + $MODPROBE test_kallsyms_c 78 + $MODPROBE test_kallsyms_d 79 + load_mod test_kallsyms_b 80 + 81 + exit 0