Merge tag 'v5.11' into next
[linux-2.6-microblaze.git] / tools / testing / selftests / kmod / kmod.sh
1 #!/bin/bash
2 #
3 # Copyright (C) 2017 Luis R. Rodriguez <mcgrof@kernel.org>
4 #
5 # This program is free software; you can redistribute it and/or modify it
6 # under the terms of the GNU General Public License as published by the Free
7 # Software Foundation; either version 2 of the License, or at your option any
8 # later version; or, when distributed separately from the Linux kernel or
9 # when incorporated into other software packages, subject to the following
10 # license:
11 #
12 # This program is free software; you can redistribute it and/or modify it
13 # under the terms of copyleft-next (version 0.3.1 or later) as published
14 # at http://copyleft-next.org/.
15
16 # This is a stress test script for kmod, the kernel module loader. It uses
17 # test_kmod which exposes a series of knobs for the API for us so we can
18 # tweak each test in userspace rather than in kernelspace.
19 #
20 # The way kmod works is it uses the kernel's usermode helper API to eventually
21 # call /sbin/modprobe. It has a limit of the number of concurrent calls
22 # possible. The kernel interface to load modules is request_module(), however
23 # mount uses get_fs_type(). Both behave slightly differently, but the
24 # differences are important enough to test each call separately. For this
25 # reason test_kmod starts by providing tests for both calls.
26 #
27 # The test driver test_kmod assumes a series of defaults which you can
28 # override by exporting to your environment prior running this script.
29 # For instance this script assumes you do not have xfs loaded upon boot.
30 # If this is false, export DEFAULT_KMOD_FS="ext4" prior to running this
31 # script if the filesystem module you don't have loaded upon bootup
32 # is ext4 instead. Refer to allow_user_defaults() for a list of user
33 # override variables possible.
34 #
35 # You'll want at least 4 GiB of RAM to expect to run these tests
36 # without running out of memory on them. For other requirements refer
37 # to test_reqs()
38
39 set -e
40
41 TEST_NAME="kmod"
42 TEST_DRIVER="test_${TEST_NAME}"
43 TEST_DIR=$(dirname $0)
44
45 # This represents
46 #
47 # TEST_ID:TEST_COUNT:ENABLED
48 #
49 # TEST_ID: is the test id number
50 # TEST_COUNT: number of times we should run the test
51 # ENABLED: 1 if enabled, 0 otherwise
52 #
53 # Once these are enabled please leave them as-is. Write your own test,
54 # we have tons of space.
55 ALL_TESTS="0001:3:1"
56 ALL_TESTS="$ALL_TESTS 0002:3:1"
57 ALL_TESTS="$ALL_TESTS 0003:1:1"
58 ALL_TESTS="$ALL_TESTS 0004:1:1"
59 ALL_TESTS="$ALL_TESTS 0005:10:1"
60 ALL_TESTS="$ALL_TESTS 0006:10:1"
61 ALL_TESTS="$ALL_TESTS 0007:5:1"
62 ALL_TESTS="$ALL_TESTS 0008:150:1"
63 ALL_TESTS="$ALL_TESTS 0009:150:1"
64 ALL_TESTS="$ALL_TESTS 0010:1:1"
65 ALL_TESTS="$ALL_TESTS 0011:1:1"
66 ALL_TESTS="$ALL_TESTS 0012:1:1"
67 ALL_TESTS="$ALL_TESTS 0013:1:1"
68
69 # Kselftest framework requirement - SKIP code is 4.
70 ksft_skip=4
71
72 test_modprobe()
73 {
74        if [ ! -d $DIR ]; then
75                echo "$0: $DIR not present" >&2
76                echo "You must have the following enabled in your kernel:" >&2
77                cat $TEST_DIR/config >&2
78                exit $ksft_skip
79        fi
80 }
81
82 function allow_user_defaults()
83 {
84         if [ -z $DEFAULT_KMOD_DRIVER ]; then
85                 DEFAULT_KMOD_DRIVER="test_module"
86         fi
87
88         if [ -z $DEFAULT_KMOD_FS ]; then
89                 DEFAULT_KMOD_FS="xfs"
90         fi
91
92         if [ -z $PROC_DIR ]; then
93                 PROC_DIR="/proc/sys/kernel/"
94         fi
95
96         if [ -z $MODPROBE_LIMIT ]; then
97                 MODPROBE_LIMIT=50
98         fi
99
100         if [ -z $DIR ]; then
101                 DIR="/sys/devices/virtual/misc/${TEST_DRIVER}0/"
102         fi
103
104         if [ -z $DEFAULT_NUM_TESTS ]; then
105                 DEFAULT_NUM_TESTS=150
106         fi
107
108         MODPROBE_LIMIT_FILE="${PROC_DIR}/kmod-limit"
109 }
110
111 test_reqs()
112 {
113         if ! which modprobe 2> /dev/null > /dev/null; then
114                 echo "$0: You need modprobe installed" >&2
115                 exit $ksft_skip
116         fi
117
118         if ! which kmod 2> /dev/null > /dev/null; then
119                 echo "$0: You need kmod installed" >&2
120                 exit $ksft_skip
121         fi
122
123         # kmod 19 has a bad bug where it returns 0 when modprobe
124         # gets called *even* if the module was not loaded due to
125         # some bad heuristics. For details see:
126         #
127         # A work around is possible in-kernel but its rather
128         # complex.
129         KMOD_VERSION=$(kmod --version | awk '{print $3}')
130         if [[ $KMOD_VERSION  -le 19 ]]; then
131                 echo "$0: You need at least kmod 20" >&2
132                 echo "kmod <= 19 is buggy, for details see:" >&2
133                 echo "https://git.kernel.org/cgit/utils/kernel/kmod/kmod.git/commit/libkmod/libkmod-module.c?id=fd44a98ae2eb5eb32161088954ab21e58e19dfc4" >&2
134                 exit $ksft_skip
135         fi
136
137         uid=$(id -u)
138         if [ $uid -ne 0 ]; then
139                 echo $msg must be run as root >&2
140                 exit $ksft_skip
141         fi
142 }
143
144 function load_req_mod()
145 {
146         trap "test_modprobe" EXIT
147
148         if [ ! -d $DIR ]; then
149                 # Alanis: "Oh isn't it ironic?"
150                 modprobe $TEST_DRIVER
151         fi
152 }
153
154 test_finish()
155 {
156         echo "$MODPROBE" > /proc/sys/kernel/modprobe
157         echo "Test completed"
158 }
159
160 errno_name_to_val()
161 {
162         case "$1" in
163         # kmod calls modprobe and upon of a module not found
164         # modprobe returns just 1... However in the kernel we
165         # *sometimes* see 256...
166         MODULE_NOT_FOUND)
167                 echo 256;;
168         SUCCESS)
169                 echo 0;;
170         -EPERM)
171                 echo -1;;
172         -ENOENT)
173                 echo -2;;
174         -EINVAL)
175                 echo -22;;
176         -ERR_ANY)
177                 echo -123456;;
178         *)
179                 echo invalid;;
180         esac
181 }
182
183 errno_val_to_name()
184         case "$1" in
185         256)
186                 echo MODULE_NOT_FOUND;;
187         0)
188                 echo SUCCESS;;
189         -1)
190                 echo -EPERM;;
191         -2)
192                 echo -ENOENT;;
193         -22)
194                 echo -EINVAL;;
195         -123456)
196                 echo -ERR_ANY;;
197         *)
198                 echo invalid;;
199         esac
200
201 config_set_test_case_driver()
202 {
203         if ! echo -n 1 >$DIR/config_test_case; then
204                 echo "$0: Unable to set to test case to driver" >&2
205                 exit 1
206         fi
207 }
208
209 config_set_test_case_fs()
210 {
211         if ! echo -n 2 >$DIR/config_test_case; then
212                 echo "$0: Unable to set to test case to fs" >&2
213                 exit 1
214         fi
215 }
216
217 config_num_threads()
218 {
219         if ! echo -n $1 >$DIR/config_num_threads; then
220                 echo "$0: Unable to set to number of threads" >&2
221                 exit 1
222         fi
223 }
224
225 config_get_modprobe_limit()
226 {
227         if [[ -f ${MODPROBE_LIMIT_FILE} ]] ; then
228                 MODPROBE_LIMIT=$(cat $MODPROBE_LIMIT_FILE)
229         fi
230         echo $MODPROBE_LIMIT
231 }
232
233 config_num_thread_limit_extra()
234 {
235         MODPROBE_LIMIT=$(config_get_modprobe_limit)
236         let EXTRA_LIMIT=$MODPROBE_LIMIT+$1
237         config_num_threads $EXTRA_LIMIT
238 }
239
240 # For special characters use printf directly,
241 # refer to kmod_test_0001
242 config_set_driver()
243 {
244         if ! echo -n $1 >$DIR/config_test_driver; then
245                 echo "$0: Unable to set driver" >&2
246                 exit 1
247         fi
248 }
249
250 config_set_fs()
251 {
252         if ! echo -n $1 >$DIR/config_test_fs; then
253                 echo "$0: Unable to set driver" >&2
254                 exit 1
255         fi
256 }
257
258 config_get_driver()
259 {
260         cat $DIR/config_test_driver
261 }
262
263 config_get_test_result()
264 {
265         cat $DIR/test_result
266 }
267
268 config_reset()
269 {
270         if ! echo -n "1" >"$DIR"/reset; then
271                 echo "$0: reset should have worked" >&2
272                 exit 1
273         fi
274 }
275
276 config_show_config()
277 {
278         echo "----------------------------------------------------"
279         cat "$DIR"/config
280         echo "----------------------------------------------------"
281 }
282
283 config_trigger()
284 {
285         if ! echo -n "1" >"$DIR"/trigger_config 2>/dev/null; then
286                 echo "$1: FAIL - loading should have worked"
287                 config_show_config
288                 exit 1
289         fi
290         echo "$1: OK! - loading kmod test"
291 }
292
293 config_trigger_want_fail()
294 {
295         if echo "1" > $DIR/trigger_config 2>/dev/null; then
296                 echo "$1: FAIL - test case was expected to fail"
297                 config_show_config
298                 exit 1
299         fi
300         echo "$1: OK! - kmod test case failed as expected"
301 }
302
303 config_expect_result()
304 {
305         RC=$(config_get_test_result)
306         RC_NAME=$(errno_val_to_name $RC)
307
308         ERRNO_NAME=$2
309         ERRNO=$(errno_name_to_val $ERRNO_NAME)
310
311         if [[ $ERRNO_NAME = "-ERR_ANY" ]]; then
312                 if [[ $RC -ge 0 ]]; then
313                         echo "$1: FAIL, test expects $ERRNO_NAME - got $RC_NAME ($RC)" >&2
314                         config_show_config
315                         exit 1
316                 fi
317         elif [[ $RC != $ERRNO ]]; then
318                 echo "$1: FAIL, test expects $ERRNO_NAME ($ERRNO) - got $RC_NAME ($RC)" >&2
319                 config_show_config
320                 exit 1
321         fi
322         echo "$1: OK! - Return value: $RC ($RC_NAME), expected $ERRNO_NAME"
323 }
324
325 kmod_defaults_driver()
326 {
327         config_reset
328         modprobe -r $DEFAULT_KMOD_DRIVER
329         config_set_driver $DEFAULT_KMOD_DRIVER
330 }
331
332 kmod_defaults_fs()
333 {
334         config_reset
335         modprobe -r $DEFAULT_KMOD_FS
336         config_set_fs $DEFAULT_KMOD_FS
337         config_set_test_case_fs
338 }
339
340 kmod_test_0001_driver()
341 {
342         NAME='\000'
343
344         kmod_defaults_driver
345         config_num_threads 1
346         printf $NAME >"$DIR"/config_test_driver
347         config_trigger ${FUNCNAME[0]}
348         config_expect_result ${FUNCNAME[0]} MODULE_NOT_FOUND
349 }
350
351 kmod_test_0001_fs()
352 {
353         NAME='\000'
354
355         kmod_defaults_fs
356         config_num_threads 1
357         printf $NAME >"$DIR"/config_test_fs
358         config_trigger ${FUNCNAME[0]}
359         config_expect_result ${FUNCNAME[0]} -EINVAL
360 }
361
362 kmod_test_0001()
363 {
364         kmod_test_0001_driver
365         kmod_test_0001_fs
366 }
367
368 kmod_test_0002_driver()
369 {
370         NAME="nope-$DEFAULT_KMOD_DRIVER"
371
372         kmod_defaults_driver
373         config_set_driver $NAME
374         config_num_threads 1
375         config_trigger ${FUNCNAME[0]}
376         config_expect_result ${FUNCNAME[0]} MODULE_NOT_FOUND
377 }
378
379 kmod_test_0002_fs()
380 {
381         NAME="nope-$DEFAULT_KMOD_FS"
382
383         kmod_defaults_fs
384         config_set_fs $NAME
385         config_trigger ${FUNCNAME[0]}
386         config_expect_result ${FUNCNAME[0]} -EINVAL
387 }
388
389 kmod_test_0002()
390 {
391         kmod_test_0002_driver
392         kmod_test_0002_fs
393 }
394
395 kmod_test_0003()
396 {
397         kmod_defaults_fs
398         config_num_threads 1
399         config_trigger ${FUNCNAME[0]}
400         config_expect_result ${FUNCNAME[0]} SUCCESS
401 }
402
403 kmod_test_0004()
404 {
405         kmod_defaults_fs
406         config_num_threads 2
407         config_trigger ${FUNCNAME[0]}
408         config_expect_result ${FUNCNAME[0]} SUCCESS
409 }
410
411 kmod_test_0005()
412 {
413         kmod_defaults_driver
414         config_trigger ${FUNCNAME[0]}
415         config_expect_result ${FUNCNAME[0]} SUCCESS
416 }
417
418 kmod_test_0006()
419 {
420         kmod_defaults_fs
421         config_trigger ${FUNCNAME[0]}
422         config_expect_result ${FUNCNAME[0]} SUCCESS
423 }
424
425 kmod_test_0007()
426 {
427         kmod_test_0005
428         kmod_test_0006
429 }
430
431 kmod_test_0008()
432 {
433         kmod_defaults_driver
434         MODPROBE_LIMIT=$(config_get_modprobe_limit)
435         let EXTRA=$MODPROBE_LIMIT/6
436         config_num_thread_limit_extra $EXTRA
437         config_trigger ${FUNCNAME[0]}
438         config_expect_result ${FUNCNAME[0]} SUCCESS
439 }
440
441 kmod_test_0009()
442 {
443         kmod_defaults_fs
444         MODPROBE_LIMIT=$(config_get_modprobe_limit)
445         let EXTRA=$MODPROBE_LIMIT/4
446         config_num_thread_limit_extra $EXTRA
447         config_trigger ${FUNCNAME[0]}
448         config_expect_result ${FUNCNAME[0]} SUCCESS
449 }
450
451 kmod_test_0010()
452 {
453         kmod_defaults_driver
454         config_num_threads 1
455         echo "/KMOD_TEST_NONEXISTENT" > /proc/sys/kernel/modprobe
456         config_trigger ${FUNCNAME[0]}
457         config_expect_result ${FUNCNAME[0]} -ENOENT
458         echo "$MODPROBE" > /proc/sys/kernel/modprobe
459 }
460
461 kmod_test_0011()
462 {
463         kmod_defaults_driver
464         config_num_threads 1
465         # This causes the kernel to not even try executing modprobe.  The error
466         # code is still -ENOENT like when modprobe doesn't exist, so we can't
467         # easily test for the exact difference.  But this still is a useful test
468         # since there was a bug where request_module() returned 0 in this case.
469         echo > /proc/sys/kernel/modprobe
470         config_trigger ${FUNCNAME[0]}
471         config_expect_result ${FUNCNAME[0]} -ENOENT
472         echo "$MODPROBE" > /proc/sys/kernel/modprobe
473 }
474
475 kmod_check_visibility()
476 {
477         local name="$1"
478         local cmd="$2"
479
480         modprobe $DEFAULT_KMOD_DRIVER
481
482         local priv=$(eval $cmd)
483         local unpriv=$(capsh --drop=CAP_SYSLOG -- -c "$cmd")
484
485         if [ "$priv" = "$unpriv" ] || \
486            [ "${priv:0:3}" = "0x0" ] || \
487            [ "${unpriv:0:3}" != "0x0" ] ; then
488                 echo "${FUNCNAME[0]}: FAIL, $name visible to unpriv: '$priv' vs '$unpriv'" >&2
489                 exit 1
490         else
491                 echo "${FUNCNAME[0]}: OK!"
492         fi
493 }
494
495 kmod_test_0012()
496 {
497         kmod_check_visibility /proc/modules \
498                 "grep '^${DEFAULT_KMOD_DRIVER}\b' /proc/modules | awk '{print \$NF}'"
499 }
500
501 kmod_test_0013()
502 {
503         kmod_check_visibility '/sys/module/*/sections/*' \
504                 "cat /sys/module/${DEFAULT_KMOD_DRIVER}/sections/.*text | head -n1"
505 }
506
507 list_tests()
508 {
509         echo "Test ID list:"
510         echo
511         echo "TEST_ID x NUM_TEST"
512         echo "TEST_ID:   Test ID"
513         echo "NUM_TESTS: Number of recommended times to run the test"
514         echo
515         echo "0001 x $(get_test_count 0001) - Simple test - 1 thread  for empty string"
516         echo "0002 x $(get_test_count 0002) - Simple test - 1 thread  for modules/filesystems that do not exist"
517         echo "0003 x $(get_test_count 0003) - Simple test - 1 thread  for get_fs_type() only"
518         echo "0004 x $(get_test_count 0004) - Simple test - 2 threads for get_fs_type() only"
519         echo "0005 x $(get_test_count 0005) - multithreaded tests with default setup - request_module() only"
520         echo "0006 x $(get_test_count 0006) - multithreaded tests with default setup - get_fs_type() only"
521         echo "0007 x $(get_test_count 0007) - multithreaded tests with default setup test request_module() and get_fs_type()"
522         echo "0008 x $(get_test_count 0008) - multithreaded - push kmod_concurrent over max_modprobes for request_module()"
523         echo "0009 x $(get_test_count 0009) - multithreaded - push kmod_concurrent over max_modprobes for get_fs_type()"
524         echo "0010 x $(get_test_count 0010) - test nonexistent modprobe path"
525         echo "0011 x $(get_test_count 0011) - test completely disabling module autoloading"
526         echo "0012 x $(get_test_count 0012) - test /proc/modules address visibility under CAP_SYSLOG"
527         echo "0013 x $(get_test_count 0013) - test /sys/module/*/sections/* visibility under CAP_SYSLOG"
528 }
529
530 usage()
531 {
532         NUM_TESTS=$(grep -o ' ' <<<"$ALL_TESTS" | grep -c .)
533         let NUM_TESTS=$NUM_TESTS+1
534         MAX_TEST=$(printf "%04d\n" $NUM_TESTS)
535         echo "Usage: $0 [ -t <4-number-digit> ] | [ -w <4-number-digit> ] |"
536         echo "           [ -s <4-number-digit> ] | [ -c <4-number-digit> <test- count>"
537         echo "           [ all ] [ -h | --help ] [ -l ]"
538         echo ""
539         echo "Valid tests: 0001-$MAX_TEST"
540         echo ""
541         echo "    all     Runs all tests (default)"
542         echo "    -t      Run test ID the number amount of times is recommended"
543         echo "    -w      Watch test ID run until it runs into an error"
544         echo "    -s      Run test ID once"
545         echo "    -c      Run test ID x test-count number of times"
546         echo "    -l      List all test ID list"
547         echo " -h|--help  Help"
548         echo
549         echo "If an error every occurs execution will immediately terminate."
550         echo "If you are adding a new test try using -w <test-ID> first to"
551         echo "make sure the test passes a series of tests."
552         echo
553         echo Example uses:
554         echo
555         echo "${TEST_NAME}.sh           -- executes all tests"
556         echo "${TEST_NAME}.sh -t 0008   -- Executes test ID 0008 number of times is recommended"
557         echo "${TEST_NAME}.sh -w 0008   -- Watch test ID 0008 run until an error occurs"
558         echo "${TEST_NAME}.sh -s 0008   -- Run test ID 0008 once"
559         echo "${TEST_NAME}.sh -c 0008 3 -- Run test ID 0008 three times"
560         echo
561         list_tests
562         exit 1
563 }
564
565 function test_num()
566 {
567         re='^[0-9]+$'
568         if ! [[ $1 =~ $re ]]; then
569                 usage
570         fi
571 }
572
573 function get_test_data()
574 {
575         test_num $1
576         local field_num=$(echo $1 | sed 's/^0*//')
577         echo $ALL_TESTS | awk '{print $'$field_num'}'
578 }
579
580 function get_test_count()
581 {
582         TEST_DATA=$(get_test_data $1)
583         LAST_TWO=${TEST_DATA#*:*}
584         echo ${LAST_TWO%:*}
585 }
586
587 function get_test_enabled()
588 {
589         TEST_DATA=$(get_test_data $1)
590         echo ${TEST_DATA#*:*:}
591 }
592
593 function run_all_tests()
594 {
595         for i in $ALL_TESTS ; do
596                 TEST_ID=${i%:*:*}
597                 ENABLED=$(get_test_enabled $TEST_ID)
598                 TEST_COUNT=$(get_test_count $TEST_ID)
599                 if [[ $ENABLED -eq "1" ]]; then
600                         test_case $TEST_ID $TEST_COUNT
601                 fi
602         done
603 }
604
605 function watch_log()
606 {
607         if [ $# -ne 3 ]; then
608                 clear
609         fi
610         date
611         echo "Running test: $2 - run #$1"
612 }
613
614 function watch_case()
615 {
616         i=0
617         while [ 1 ]; do
618
619                 if [ $# -eq 1 ]; then
620                         test_num $1
621                         watch_log $i ${TEST_NAME}_test_$1
622                         ${TEST_NAME}_test_$1
623                 else
624                         watch_log $i all
625                         run_all_tests
626                 fi
627                 let i=$i+1
628         done
629 }
630
631 function test_case()
632 {
633         NUM_TESTS=$DEFAULT_NUM_TESTS
634         if [ $# -eq 2 ]; then
635                 NUM_TESTS=$2
636         fi
637
638         i=0
639         while [ $i -lt $NUM_TESTS ]; do
640                 test_num $1
641                 watch_log $i ${TEST_NAME}_test_$1 noclear
642                 RUN_TEST=${TEST_NAME}_test_$1
643                 $RUN_TEST
644                 let i=$i+1
645         done
646 }
647
648 function parse_args()
649 {
650         if [ $# -eq 0 ]; then
651                 run_all_tests
652         else
653                 if [[ "$1" = "all" ]]; then
654                         run_all_tests
655                 elif [[ "$1" = "-w" ]]; then
656                         shift
657                         watch_case $@
658                 elif [[ "$1" = "-t" ]]; then
659                         shift
660                         test_num $1
661                         test_case $1 $(get_test_count $1)
662                 elif [[ "$1" = "-c" ]]; then
663                         shift
664                         test_num $1
665                         test_num $2
666                         test_case $1 $2
667                 elif [[ "$1" = "-s" ]]; then
668                         shift
669                         test_case $1 1
670                 elif [[ "$1" = "-l" ]]; then
671                         list_tests
672                 elif [[ "$1" = "-h" || "$1" = "--help" ]]; then
673                         usage
674                 else
675                         usage
676                 fi
677         fi
678 }
679
680 test_reqs
681 allow_user_defaults
682 load_req_mod
683
684 MODPROBE=$(</proc/sys/kernel/modprobe)
685 trap "test_finish" EXIT
686
687 parse_args $@
688
689 exit 0