diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-07-15 00:57:25 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-07-15 00:57:25 -0400 |
commit | 867eacd7fb975273703766f52f485f08471a1ae9 (patch) | |
tree | be3c024c940d34331d5329a61a8e2be64f21da17 | |
parent | 077d2ba519b2e8bf1abd80cbade699b1de42cafe (diff) | |
parent | 6d7964a722afc8e4f880b947f174009063028c99 (diff) |
Merge branch 'akpm' (patches from Andrew)
Merge even more updates from Andrew Morton:
- a few leftovers
- fault-injector rework
- add a module loader test driver
* emailed patches from Andrew Morton <akpm@linux-foundation.org>:
kmod: throttle kmod thread limit
kmod: add test driver to stress test the module loader
MAINTAINERS: give kmod some maintainer love
xtensa: use generic fb.h
fault-inject: add /proc/<pid>/fail-nth
fault-inject: simplify access check for fail-nth
fault-inject: make fail-nth read/write interface symmetric
fault-inject: parse as natural 1-based value for fail-nth write interface
fault-inject: automatically detect the number base for fail-nth write interface
kernel/watchdog.c: use better pr_fmt prefix
MAINTAINERS: move the befs tree to kernel.org
lib/atomic64_test.c: add a test that atomic64_inc_not_zero() returns an int
mm: fix overflow check in expand_upwards()
-rw-r--r-- | Documentation/fault-injection/fault-injection.txt | 21 | ||||
-rw-r--r-- | MAINTAINERS | 13 | ||||
-rw-r--r-- | arch/xtensa/include/asm/Kbuild | 1 | ||||
-rw-r--r-- | arch/xtensa/include/asm/fb.h | 12 | ||||
-rw-r--r-- | fs/proc/base.c | 41 | ||||
-rw-r--r-- | include/linux/sched.h | 2 | ||||
-rw-r--r-- | kernel/kmod.c | 16 | ||||
-rw-r--r-- | kernel/watchdog.c | 2 | ||||
-rw-r--r-- | lib/Kconfig.debug | 27 | ||||
-rw-r--r-- | lib/Makefile | 1 | ||||
-rw-r--r-- | lib/atomic64_test.c | 7 | ||||
-rw-r--r-- | lib/fault-inject.c | 7 | ||||
-rw-r--r-- | lib/test_kmod.c | 1246 | ||||
-rw-r--r-- | mm/mmap.c | 2 | ||||
-rw-r--r-- | tools/testing/selftests/kmod/Makefile | 11 | ||||
-rw-r--r-- | tools/testing/selftests/kmod/config | 7 | ||||
-rw-r--r-- | tools/testing/selftests/kmod/kmod.sh | 615 |
17 files changed, 1969 insertions, 62 deletions
diff --git a/Documentation/fault-injection/fault-injection.txt b/Documentation/fault-injection/fault-injection.txt index 192d8cbcc5f9..918972babcd8 100644 --- a/Documentation/fault-injection/fault-injection.txt +++ b/Documentation/fault-injection/fault-injection.txt | |||
@@ -136,12 +136,13 @@ use the boot option: | |||
136 | 136 | ||
137 | o proc entries | 137 | o proc entries |
138 | 138 | ||
139 | - /proc/self/task/<current-tid>/fail-nth: | 139 | - /proc/<pid>/fail-nth: |
140 | - /proc/self/task/<tid>/fail-nth: | ||
140 | 141 | ||
141 | Write to this file of integer N makes N-th call in the current task fail | 142 | Write to this file of integer N makes N-th call in the task fail. |
142 | (N is 0-based). Read from this file returns a single char 'Y' or 'N' | 143 | Read from this file returns a integer value. A value of '0' indicates |
143 | that says if the fault setup with a previous write to this file was | 144 | that the fault setup with a previous write to this file was injected. |
144 | injected or not, and disables the fault if it wasn't yet injected. | 145 | A positive integer N indicates that the fault wasn't yet injected. |
145 | Note that this file enables all types of faults (slab, futex, etc). | 146 | Note that this file enables all types of faults (slab, futex, etc). |
146 | This setting takes precedence over all other generic debugfs settings | 147 | This setting takes precedence over all other generic debugfs settings |
147 | like probability, interval, times, etc. But per-capability settings | 148 | like probability, interval, times, etc. But per-capability settings |
@@ -320,18 +321,19 @@ int main() | |||
320 | system("echo N > /sys/kernel/debug/failslab/ignore-gfp-wait"); | 321 | system("echo N > /sys/kernel/debug/failslab/ignore-gfp-wait"); |
321 | sprintf(buf, "/proc/self/task/%ld/fail-nth", syscall(SYS_gettid)); | 322 | sprintf(buf, "/proc/self/task/%ld/fail-nth", syscall(SYS_gettid)); |
322 | fail_nth = open(buf, O_RDWR); | 323 | fail_nth = open(buf, O_RDWR); |
323 | for (i = 0;; i++) { | 324 | for (i = 1;; i++) { |
324 | sprintf(buf, "%d", i); | 325 | sprintf(buf, "%d", i); |
325 | write(fail_nth, buf, strlen(buf)); | 326 | write(fail_nth, buf, strlen(buf)); |
326 | res = socketpair(AF_LOCAL, SOCK_STREAM, 0, fds); | 327 | res = socketpair(AF_LOCAL, SOCK_STREAM, 0, fds); |
327 | err = errno; | 328 | err = errno; |
328 | read(fail_nth, buf, 1); | 329 | pread(fail_nth, buf, sizeof(buf), 0); |
329 | if (res == 0) { | 330 | if (res == 0) { |
330 | close(fds[0]); | 331 | close(fds[0]); |
331 | close(fds[1]); | 332 | close(fds[1]); |
332 | } | 333 | } |
333 | printf("%d-th fault %c: res=%d/%d\n", i, buf[0], res, err); | 334 | printf("%d-th fault %c: res=%d/%d\n", i, atoi(buf) ? 'N' : 'Y', |
334 | if (buf[0] != 'Y') | 335 | res, err); |
336 | if (atoi(buf)) | ||
335 | break; | 337 | break; |
336 | } | 338 | } |
337 | return 0; | 339 | return 0; |
@@ -339,7 +341,6 @@ int main() | |||
339 | 341 | ||
340 | An example output: | 342 | An example output: |
341 | 343 | ||
342 | 0-th fault Y: res=-1/23 | ||
343 | 1-th fault Y: res=-1/23 | 344 | 1-th fault Y: res=-1/23 |
344 | 2-th fault Y: res=-1/23 | 345 | 2-th fault Y: res=-1/23 |
345 | 3-th fault Y: res=-1/12 | 346 | 3-th fault Y: res=-1/12 |
diff --git a/MAINTAINERS b/MAINTAINERS index 4bae99c37635..428e042dcd21 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
@@ -2516,10 +2516,10 @@ S: Supported | |||
2516 | F: drivers/media/platform/sti/delta | 2516 | F: drivers/media/platform/sti/delta |
2517 | 2517 | ||
2518 | BEFS FILE SYSTEM | 2518 | BEFS FILE SYSTEM |
2519 | M: Luis de Bethencourt <luisbg@osg.samsung.com> | 2519 | M: Luis de Bethencourt <luisbg@kernel.org> |
2520 | M: Salah Triki <salah.triki@gmail.com> | 2520 | M: Salah Triki <salah.triki@gmail.com> |
2521 | S: Maintained | 2521 | S: Maintained |
2522 | T: git git://github.com/luisbg/linux-befs.git | 2522 | T: git git://git.kernel.org/pub/scm/linux/kernel/git/luisbg/linux-befs.git |
2523 | F: Documentation/filesystems/befs.txt | 2523 | F: Documentation/filesystems/befs.txt |
2524 | F: fs/befs/ | 2524 | F: fs/befs/ |
2525 | 2525 | ||
@@ -7554,6 +7554,15 @@ F: include/linux/kmemleak.h | |||
7554 | F: mm/kmemleak.c | 7554 | F: mm/kmemleak.c |
7555 | F: mm/kmemleak-test.c | 7555 | F: mm/kmemleak-test.c |
7556 | 7556 | ||
7557 | KMOD MODULE USERMODE HELPER | ||
7558 | M: "Luis R. Rodriguez" <mcgrof@kernel.org> | ||
7559 | L: linux-kernel@vger.kernel.org | ||
7560 | S: Maintained | ||
7561 | F: kernel/kmod.c | ||
7562 | F: include/linux/kmod.h | ||
7563 | F: lib/test_kmod.c | ||
7564 | F: tools/testing/selftests/kmod/ | ||
7565 | |||
7557 | KPROBES | 7566 | KPROBES |
7558 | M: Ananth N Mavinakayanahalli <ananth@linux.vnet.ibm.com> | 7567 | M: Ananth N Mavinakayanahalli <ananth@linux.vnet.ibm.com> |
7559 | M: Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com> | 7568 | M: Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com> |
diff --git a/arch/xtensa/include/asm/Kbuild b/arch/xtensa/include/asm/Kbuild index c04efde775a5..2d716ebc5a5e 100644 --- a/arch/xtensa/include/asm/Kbuild +++ b/arch/xtensa/include/asm/Kbuild | |||
@@ -5,6 +5,7 @@ generic-y += dma-contiguous.h | |||
5 | generic-y += emergency-restart.h | 5 | generic-y += emergency-restart.h |
6 | generic-y += exec.h | 6 | generic-y += exec.h |
7 | generic-y += extable.h | 7 | generic-y += extable.h |
8 | generic-y += fb.h | ||
8 | generic-y += hardirq.h | 9 | generic-y += hardirq.h |
9 | generic-y += irq_regs.h | 10 | generic-y += irq_regs.h |
10 | generic-y += irq_work.h | 11 | generic-y += irq_work.h |
diff --git a/arch/xtensa/include/asm/fb.h b/arch/xtensa/include/asm/fb.h deleted file mode 100644 index c7df38030992..000000000000 --- a/arch/xtensa/include/asm/fb.h +++ /dev/null | |||
@@ -1,12 +0,0 @@ | |||
1 | #ifndef _ASM_FB_H_ | ||
2 | #define _ASM_FB_H_ | ||
3 | #include <linux/fb.h> | ||
4 | |||
5 | #define fb_pgprotect(...) do {} while (0) | ||
6 | |||
7 | static inline int fb_is_primary_device(struct fb_info *info) | ||
8 | { | ||
9 | return 0; | ||
10 | } | ||
11 | |||
12 | #endif /* _ASM_FB_H_ */ | ||
diff --git a/fs/proc/base.c b/fs/proc/base.c index 88b773f318cd..719c2e943ea1 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c | |||
@@ -1360,20 +1360,19 @@ static ssize_t proc_fail_nth_write(struct file *file, const char __user *buf, | |||
1360 | size_t count, loff_t *ppos) | 1360 | size_t count, loff_t *ppos) |
1361 | { | 1361 | { |
1362 | struct task_struct *task; | 1362 | struct task_struct *task; |
1363 | int err, n; | 1363 | int err; |
1364 | unsigned int n; | ||
1365 | |||
1366 | err = kstrtouint_from_user(buf, count, 0, &n); | ||
1367 | if (err) | ||
1368 | return err; | ||
1364 | 1369 | ||
1365 | task = get_proc_task(file_inode(file)); | 1370 | task = get_proc_task(file_inode(file)); |
1366 | if (!task) | 1371 | if (!task) |
1367 | return -ESRCH; | 1372 | return -ESRCH; |
1373 | WRITE_ONCE(task->fail_nth, n); | ||
1368 | put_task_struct(task); | 1374 | put_task_struct(task); |
1369 | if (task != current) | 1375 | |
1370 | return -EPERM; | ||
1371 | err = kstrtoint_from_user(buf, count, 10, &n); | ||
1372 | if (err) | ||
1373 | return err; | ||
1374 | if (n < 0 || n == INT_MAX) | ||
1375 | return -EINVAL; | ||
1376 | current->fail_nth = n + 1; | ||
1377 | return count; | 1376 | return count; |
1378 | } | 1377 | } |
1379 | 1378 | ||
@@ -1381,21 +1380,18 @@ static ssize_t proc_fail_nth_read(struct file *file, char __user *buf, | |||
1381 | size_t count, loff_t *ppos) | 1380 | size_t count, loff_t *ppos) |
1382 | { | 1381 | { |
1383 | struct task_struct *task; | 1382 | struct task_struct *task; |
1384 | int err; | 1383 | char numbuf[PROC_NUMBUF]; |
1384 | ssize_t len; | ||
1385 | 1385 | ||
1386 | task = get_proc_task(file_inode(file)); | 1386 | task = get_proc_task(file_inode(file)); |
1387 | if (!task) | 1387 | if (!task) |
1388 | return -ESRCH; | 1388 | return -ESRCH; |
1389 | len = snprintf(numbuf, sizeof(numbuf), "%u\n", | ||
1390 | READ_ONCE(task->fail_nth)); | ||
1391 | len = simple_read_from_buffer(buf, count, ppos, numbuf, len); | ||
1389 | put_task_struct(task); | 1392 | put_task_struct(task); |
1390 | if (task != current) | 1393 | |
1391 | return -EPERM; | 1394 | return len; |
1392 | if (count < 1) | ||
1393 | return -EINVAL; | ||
1394 | err = put_user((char)(current->fail_nth ? 'N' : 'Y'), buf); | ||
1395 | if (err) | ||
1396 | return err; | ||
1397 | current->fail_nth = 0; | ||
1398 | return 1; | ||
1399 | } | 1395 | } |
1400 | 1396 | ||
1401 | static const struct file_operations proc_fail_nth_operations = { | 1397 | static const struct file_operations proc_fail_nth_operations = { |
@@ -2966,6 +2962,7 @@ static const struct pid_entry tgid_base_stuff[] = { | |||
2966 | #endif | 2962 | #endif |
2967 | #ifdef CONFIG_FAULT_INJECTION | 2963 | #ifdef CONFIG_FAULT_INJECTION |
2968 | REG("make-it-fail", S_IRUGO|S_IWUSR, proc_fault_inject_operations), | 2964 | REG("make-it-fail", S_IRUGO|S_IWUSR, proc_fault_inject_operations), |
2965 | REG("fail-nth", 0644, proc_fail_nth_operations), | ||
2969 | #endif | 2966 | #endif |
2970 | #ifdef CONFIG_ELF_CORE | 2967 | #ifdef CONFIG_ELF_CORE |
2971 | REG("coredump_filter", S_IRUGO|S_IWUSR, proc_coredump_filter_operations), | 2968 | REG("coredump_filter", S_IRUGO|S_IWUSR, proc_coredump_filter_operations), |
@@ -3358,11 +3355,7 @@ static const struct pid_entry tid_base_stuff[] = { | |||
3358 | #endif | 3355 | #endif |
3359 | #ifdef CONFIG_FAULT_INJECTION | 3356 | #ifdef CONFIG_FAULT_INJECTION |
3360 | REG("make-it-fail", S_IRUGO|S_IWUSR, proc_fault_inject_operations), | 3357 | REG("make-it-fail", S_IRUGO|S_IWUSR, proc_fault_inject_operations), |
3361 | /* | 3358 | REG("fail-nth", 0644, proc_fail_nth_operations), |
3362 | * Operations on the file check that the task is current, | ||
3363 | * so we create it with 0666 to support testing under unprivileged user. | ||
3364 | */ | ||
3365 | REG("fail-nth", 0666, proc_fail_nth_operations), | ||
3366 | #endif | 3359 | #endif |
3367 | #ifdef CONFIG_TASK_IO_ACCOUNTING | 3360 | #ifdef CONFIG_TASK_IO_ACCOUNTING |
3368 | ONE("io", S_IRUSR, proc_tid_io_accounting), | 3361 | ONE("io", S_IRUSR, proc_tid_io_accounting), |
diff --git a/include/linux/sched.h b/include/linux/sched.h index 3822d749fc9e..2ba9ec93423f 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h | |||
@@ -974,7 +974,7 @@ struct task_struct { | |||
974 | 974 | ||
975 | #ifdef CONFIG_FAULT_INJECTION | 975 | #ifdef CONFIG_FAULT_INJECTION |
976 | int make_it_fail; | 976 | int make_it_fail; |
977 | int fail_nth; | 977 | unsigned int fail_nth; |
978 | #endif | 978 | #endif |
979 | /* | 979 | /* |
980 | * When (nr_dirtied >= nr_dirtied_pause), it's time to call | 980 | * When (nr_dirtied >= nr_dirtied_pause), it's time to call |
diff --git a/kernel/kmod.c b/kernel/kmod.c index ff68198fe83b..6d016c5d97c8 100644 --- a/kernel/kmod.c +++ b/kernel/kmod.c | |||
@@ -68,6 +68,7 @@ static DECLARE_RWSEM(umhelper_sem); | |||
68 | */ | 68 | */ |
69 | #define MAX_KMOD_CONCURRENT 50 | 69 | #define MAX_KMOD_CONCURRENT 50 |
70 | static atomic_t kmod_concurrent_max = ATOMIC_INIT(MAX_KMOD_CONCURRENT); | 70 | static atomic_t kmod_concurrent_max = ATOMIC_INIT(MAX_KMOD_CONCURRENT); |
71 | static DECLARE_WAIT_QUEUE_HEAD(kmod_wq); | ||
71 | 72 | ||
72 | /* | 73 | /* |
73 | modprobe_path is set via /proc/sys. | 74 | modprobe_path is set via /proc/sys. |
@@ -140,7 +141,6 @@ int __request_module(bool wait, const char *fmt, ...) | |||
140 | va_list args; | 141 | va_list args; |
141 | char module_name[MODULE_NAME_LEN]; | 142 | char module_name[MODULE_NAME_LEN]; |
142 | int ret; | 143 | int ret; |
143 | static int kmod_loop_msg; | ||
144 | 144 | ||
145 | /* | 145 | /* |
146 | * We don't allow synchronous module loading from async. Module | 146 | * We don't allow synchronous module loading from async. Module |
@@ -164,14 +164,11 @@ int __request_module(bool wait, const char *fmt, ...) | |||
164 | return ret; | 164 | return ret; |
165 | 165 | ||
166 | if (atomic_dec_if_positive(&kmod_concurrent_max) < 0) { | 166 | if (atomic_dec_if_positive(&kmod_concurrent_max) < 0) { |
167 | /* We may be blaming an innocent here, but unlikely */ | 167 | pr_warn_ratelimited("request_module: kmod_concurrent_max (%u) close to 0 (max_modprobes: %u), for module %s, throttling...", |
168 | if (kmod_loop_msg < 5) { | 168 | atomic_read(&kmod_concurrent_max), |
169 | printk(KERN_ERR | 169 | MAX_KMOD_CONCURRENT, module_name); |
170 | "request_module: runaway loop modprobe %s\n", | 170 | wait_event_interruptible(kmod_wq, |
171 | module_name); | 171 | atomic_dec_if_positive(&kmod_concurrent_max) >= 0); |
172 | kmod_loop_msg++; | ||
173 | } | ||
174 | return -ENOMEM; | ||
175 | } | 172 | } |
176 | 173 | ||
177 | trace_module_request(module_name, wait, _RET_IP_); | 174 | trace_module_request(module_name, wait, _RET_IP_); |
@@ -179,6 +176,7 @@ int __request_module(bool wait, const char *fmt, ...) | |||
179 | ret = call_modprobe(module_name, wait ? UMH_WAIT_PROC : UMH_WAIT_EXEC); | 176 | ret = call_modprobe(module_name, wait ? UMH_WAIT_PROC : UMH_WAIT_EXEC); |
180 | 177 | ||
181 | atomic_inc(&kmod_concurrent_max); | 178 | atomic_inc(&kmod_concurrent_max); |
179 | wake_up(&kmod_wq); | ||
182 | 180 | ||
183 | return ret; | 181 | return ret; |
184 | } | 182 | } |
diff --git a/kernel/watchdog.c b/kernel/watchdog.c index cabe3e9fb620..06d3389bca0d 100644 --- a/kernel/watchdog.c +++ b/kernel/watchdog.c | |||
@@ -9,7 +9,7 @@ | |||
9 | * to those contributors as well. | 9 | * to those contributors as well. |
10 | */ | 10 | */ |
11 | 11 | ||
12 | #define pr_fmt(fmt) "NMI watchdog: " fmt | 12 | #define pr_fmt(fmt) "watchdog: " fmt |
13 | 13 | ||
14 | #include <linux/mm.h> | 14 | #include <linux/mm.h> |
15 | #include <linux/cpu.h> | 15 | #include <linux/cpu.h> |
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index b0d01c6d4e03..789c6e9e5e01 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug | |||
@@ -1847,6 +1847,33 @@ config BUG_ON_DATA_CORRUPTION | |||
1847 | 1847 | ||
1848 | If unsure, say N. | 1848 | If unsure, say N. |
1849 | 1849 | ||
1850 | config TEST_KMOD | ||
1851 | tristate "kmod stress tester" | ||
1852 | default n | ||
1853 | depends on m | ||
1854 | depends on BLOCK && (64BIT || LBDAF) # for XFS, BTRFS | ||
1855 | depends on NETDEVICES && NET_CORE && INET # for TUN | ||
1856 | select TEST_LKM | ||
1857 | select XFS_FS | ||
1858 | select TUN | ||
1859 | select BTRFS_FS | ||
1860 | help | ||
1861 | Test the kernel's module loading mechanism: kmod. kmod implements | ||
1862 | support to load modules using the Linux kernel's usermode helper. | ||
1863 | This test provides a series of tests against kmod. | ||
1864 | |||
1865 | Although technically you can either build test_kmod as a module or | ||
1866 | into the kernel we disallow building it into the kernel since | ||
1867 | it stress tests request_module() and this will very likely cause | ||
1868 | some issues by taking over precious threads available from other | ||
1869 | module load requests, ultimately this could be fatal. | ||
1870 | |||
1871 | To run tests run: | ||
1872 | |||
1873 | tools/testing/selftests/kmod/kmod.sh --help | ||
1874 | |||
1875 | If unsure, say N. | ||
1876 | |||
1850 | source "samples/Kconfig" | 1877 | source "samples/Kconfig" |
1851 | 1878 | ||
1852 | source "lib/Kconfig.kgdb" | 1879 | source "lib/Kconfig.kgdb" |
diff --git a/lib/Makefile b/lib/Makefile index 85e91e51a9fe..40c18372b301 100644 --- a/lib/Makefile +++ b/lib/Makefile | |||
@@ -61,6 +61,7 @@ obj-$(CONFIG_TEST_PRINTF) += test_printf.o | |||
61 | obj-$(CONFIG_TEST_BITMAP) += test_bitmap.o | 61 | obj-$(CONFIG_TEST_BITMAP) += test_bitmap.o |
62 | obj-$(CONFIG_TEST_UUID) += test_uuid.o | 62 | obj-$(CONFIG_TEST_UUID) += test_uuid.o |
63 | obj-$(CONFIG_TEST_PARMAN) += test_parman.o | 63 | obj-$(CONFIG_TEST_PARMAN) += test_parman.o |
64 | obj-$(CONFIG_TEST_KMOD) += test_kmod.o | ||
64 | 65 | ||
65 | ifeq ($(CONFIG_DEBUG_KOBJECT),y) | 66 | ifeq ($(CONFIG_DEBUG_KOBJECT),y) |
66 | CFLAGS_kobject.o += -DDEBUG | 67 | CFLAGS_kobject.o += -DDEBUG |
diff --git a/lib/atomic64_test.c b/lib/atomic64_test.c index fd70c0e0e673..62ab629f51ca 100644 --- a/lib/atomic64_test.c +++ b/lib/atomic64_test.c | |||
@@ -153,8 +153,10 @@ static __init void test_atomic64(void) | |||
153 | long long v0 = 0xaaa31337c001d00dLL; | 153 | long long v0 = 0xaaa31337c001d00dLL; |
154 | long long v1 = 0xdeadbeefdeafcafeLL; | 154 | long long v1 = 0xdeadbeefdeafcafeLL; |
155 | long long v2 = 0xfaceabadf00df001LL; | 155 | long long v2 = 0xfaceabadf00df001LL; |
156 | long long v3 = 0x8000000000000000LL; | ||
156 | long long onestwos = 0x1111111122222222LL; | 157 | long long onestwos = 0x1111111122222222LL; |
157 | long long one = 1LL; | 158 | long long one = 1LL; |
159 | int r_int; | ||
158 | 160 | ||
159 | atomic64_t v = ATOMIC64_INIT(v0); | 161 | atomic64_t v = ATOMIC64_INIT(v0); |
160 | long long r = v0; | 162 | long long r = v0; |
@@ -240,6 +242,11 @@ static __init void test_atomic64(void) | |||
240 | BUG_ON(!atomic64_inc_not_zero(&v)); | 242 | BUG_ON(!atomic64_inc_not_zero(&v)); |
241 | r += one; | 243 | r += one; |
242 | BUG_ON(v.counter != r); | 244 | BUG_ON(v.counter != r); |
245 | |||
246 | /* Confirm the return value fits in an int, even if the value doesn't */ | ||
247 | INIT(v3); | ||
248 | r_int = atomic64_inc_not_zero(&v); | ||
249 | BUG_ON(!r_int); | ||
243 | } | 250 | } |
244 | 251 | ||
245 | static __init int test_atomics_init(void) | 252 | static __init int test_atomics_init(void) |
diff --git a/lib/fault-inject.c b/lib/fault-inject.c index 09ac73c177fd..7d315fdb9f13 100644 --- a/lib/fault-inject.c +++ b/lib/fault-inject.c | |||
@@ -107,9 +107,12 @@ static inline bool fail_stacktrace(struct fault_attr *attr) | |||
107 | 107 | ||
108 | bool should_fail(struct fault_attr *attr, ssize_t size) | 108 | bool should_fail(struct fault_attr *attr, ssize_t size) |
109 | { | 109 | { |
110 | if (in_task() && current->fail_nth) { | 110 | if (in_task()) { |
111 | if (--current->fail_nth == 0) | 111 | unsigned int fail_nth = READ_ONCE(current->fail_nth); |
112 | |||
113 | if (fail_nth && !WRITE_ONCE(current->fail_nth, fail_nth - 1)) | ||
112 | goto fail; | 114 | goto fail; |
115 | |||
113 | return false; | 116 | return false; |
114 | } | 117 | } |
115 | 118 | ||
diff --git a/lib/test_kmod.c b/lib/test_kmod.c new file mode 100644 index 000000000000..6c1d678bcf8b --- /dev/null +++ b/lib/test_kmod.c | |||
@@ -0,0 +1,1246 @@ | |||
1 | /* | ||
2 | * kmod stress test driver | ||
3 | * | ||
4 | * Copyright (C) 2017 Luis R. Rodriguez <mcgrof@kernel.org> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms of the GNU General Public License as published by the Free | ||
8 | * Software Foundation; either version 2 of the License, or at your option any | ||
9 | * later version; or, when distributed separately from the Linux kernel or | ||
10 | * when incorporated into other software packages, subject to the following | ||
11 | * license: | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or modify it | ||
14 | * under the terms of copyleft-next (version 0.3.1 or later) as published | ||
15 | * at http://copyleft-next.org/. | ||
16 | */ | ||
17 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
18 | |||
19 | /* | ||
20 | * This driver provides an interface to trigger and test the kernel's | ||
21 | * module loader through a series of configurations and a few triggers. | ||
22 | * To test this driver use the following script as root: | ||
23 | * | ||
24 | * tools/testing/selftests/kmod/kmod.sh --help | ||
25 | */ | ||
26 | |||
27 | #include <linux/kernel.h> | ||
28 | #include <linux/module.h> | ||
29 | #include <linux/kmod.h> | ||
30 | #include <linux/printk.h> | ||
31 | #include <linux/kthread.h> | ||
32 | #include <linux/sched.h> | ||
33 | #include <linux/fs.h> | ||
34 | #include <linux/miscdevice.h> | ||
35 | #include <linux/vmalloc.h> | ||
36 | #include <linux/slab.h> | ||
37 | #include <linux/device.h> | ||
38 | |||
39 | #define TEST_START_NUM_THREADS 50 | ||
40 | #define TEST_START_DRIVER "test_module" | ||
41 | #define TEST_START_TEST_FS "xfs" | ||
42 | #define TEST_START_TEST_CASE TEST_KMOD_DRIVER | ||
43 | |||
44 | |||
45 | static bool force_init_test = false; | ||
46 | module_param(force_init_test, bool_enable_only, 0644); | ||
47 | MODULE_PARM_DESC(force_init_test, | ||
48 | "Force kicking a test immediately after driver loads"); | ||
49 | |||
50 | /* | ||
51 | * For device allocation / registration | ||
52 | */ | ||
53 | static DEFINE_MUTEX(reg_dev_mutex); | ||
54 | static LIST_HEAD(reg_test_devs); | ||
55 | |||
56 | /* | ||
57 | * num_test_devs actually represents the *next* ID of the next | ||
58 | * device we will allow to create. | ||
59 | */ | ||
60 | static int num_test_devs; | ||
61 | |||
62 | /** | ||
63 | * enum kmod_test_case - linker table test case | ||
64 | * | ||
65 | * If you add a test case, please be sure to review if you need to se | ||
66 | * @need_mod_put for your tests case. | ||
67 | * | ||
68 | * @TEST_KMOD_DRIVER: stress tests request_module() | ||
69 | * @TEST_KMOD_FS_TYPE: stress tests get_fs_type() | ||
70 | */ | ||
71 | enum kmod_test_case { | ||
72 | __TEST_KMOD_INVALID = 0, | ||
73 | |||
74 | TEST_KMOD_DRIVER, | ||
75 | TEST_KMOD_FS_TYPE, | ||
76 | |||
77 | __TEST_KMOD_MAX, | ||
78 | }; | ||
79 | |||
80 | struct test_config { | ||
81 | char *test_driver; | ||
82 | char *test_fs; | ||
83 | unsigned int num_threads; | ||
84 | enum kmod_test_case test_case; | ||
85 | int test_result; | ||
86 | }; | ||
87 | |||
88 | struct kmod_test_device; | ||
89 | |||
90 | /** | ||
91 | * kmod_test_device_info - thread info | ||
92 | * | ||
93 | * @ret_sync: return value if request_module() is used, sync request for | ||
94 | * @TEST_KMOD_DRIVER | ||
95 | * @fs_sync: return value of get_fs_type() for @TEST_KMOD_FS_TYPE | ||
96 | * @thread_idx: thread ID | ||
97 | * @test_dev: test device test is being performed under | ||
98 | * @need_mod_put: Some tests (get_fs_type() is one) requires putting the module | ||
99 | * (module_put(fs_sync->owner)) when done, otherwise you will not be able | ||
100 | * to unload the respective modules and re-test. We use this to keep | ||
101 | * accounting of when we need this and to help out in case we need to | ||
102 | * error out and deal with module_put() on error. | ||
103 | */ | ||
104 | struct kmod_test_device_info { | ||
105 | int ret_sync; | ||
106 | struct file_system_type *fs_sync; | ||
107 | struct task_struct *task_sync; | ||
108 | unsigned int thread_idx; | ||
109 | struct kmod_test_device *test_dev; | ||
110 | bool need_mod_put; | ||
111 | }; | ||
112 | |||
113 | /** | ||
114 | * kmod_test_device - test device to help test kmod | ||
115 | * | ||
116 | * @dev_idx: unique ID for test device | ||
117 | * @config: configuration for the test | ||
118 | * @misc_dev: we use a misc device under the hood | ||
119 | * @dev: pointer to misc_dev's own struct device | ||
120 | * @config_mutex: protects configuration of test | ||
121 | * @trigger_mutex: the test trigger can only be fired once at a time | ||
122 | * @thread_lock: protects @done count, and the @info per each thread | ||
123 | * @done: number of threads which have completed or failed | ||
124 | * @test_is_oom: when we run out of memory, use this to halt moving forward | ||
125 | * @kthreads_done: completion used to signal when all work is done | ||
126 | * @list: needed to be part of the reg_test_devs | ||
127 | * @info: array of info for each thread | ||
128 | */ | ||
129 | struct kmod_test_device { | ||
130 | int dev_idx; | ||
131 | struct test_config config; | ||
132 | struct miscdevice misc_dev; | ||
133 | struct device *dev; | ||
134 | struct mutex config_mutex; | ||
135 | struct mutex trigger_mutex; | ||
136 | struct mutex thread_mutex; | ||
137 | |||
138 | unsigned int done; | ||
139 | |||
140 | bool test_is_oom; | ||
141 | struct completion kthreads_done; | ||
142 | struct list_head list; | ||
143 | |||
144 | struct kmod_test_device_info *info; | ||
145 | }; | ||
146 | |||
147 | static const char *test_case_str(enum kmod_test_case test_case) | ||
148 | { | ||
149 | switch (test_case) { | ||
150 | case TEST_KMOD_DRIVER: | ||
151 | return "TEST_KMOD_DRIVER"; | ||
152 | case TEST_KMOD_FS_TYPE: | ||
153 | return "TEST_KMOD_FS_TYPE"; | ||
154 | default: | ||
155 | return "invalid"; | ||
156 | } | ||
157 | } | ||
158 | |||
159 | static struct miscdevice *dev_to_misc_dev(struct device *dev) | ||
160 | { | ||
161 | return dev_get_drvdata(dev); | ||
162 | } | ||
163 | |||
164 | static struct kmod_test_device *misc_dev_to_test_dev(struct miscdevice *misc_dev) | ||
165 | { | ||
166 | return container_of(misc_dev, struct kmod_test_device, misc_dev); | ||
167 | } | ||
168 | |||
169 | static struct kmod_test_device *dev_to_test_dev(struct device *dev) | ||
170 | { | ||
171 | struct miscdevice *misc_dev; | ||
172 | |||
173 | misc_dev = dev_to_misc_dev(dev); | ||
174 | |||
175 | return misc_dev_to_test_dev(misc_dev); | ||
176 | } | ||
177 | |||
178 | /* Must run with thread_mutex held */ | ||
179 | static void kmod_test_done_check(struct kmod_test_device *test_dev, | ||
180 | unsigned int idx) | ||
181 | { | ||
182 | struct test_config *config = &test_dev->config; | ||
183 | |||
184 | test_dev->done++; | ||
185 | dev_dbg(test_dev->dev, "Done thread count: %u\n", test_dev->done); | ||
186 | |||
187 | if (test_dev->done == config->num_threads) { | ||
188 | dev_info(test_dev->dev, "Done: %u threads have all run now\n", | ||
189 | test_dev->done); | ||
190 | dev_info(test_dev->dev, "Last thread to run: %u\n", idx); | ||
191 | complete(&test_dev->kthreads_done); | ||
192 | } | ||
193 | } | ||
194 | |||
195 | static void test_kmod_put_module(struct kmod_test_device_info *info) | ||
196 | { | ||
197 | struct kmod_test_device *test_dev = info->test_dev; | ||
198 | struct test_config *config = &test_dev->config; | ||
199 | |||
200 | if (!info->need_mod_put) | ||
201 | return; | ||
202 | |||
203 | switch (config->test_case) { | ||
204 | case TEST_KMOD_DRIVER: | ||
205 | break; | ||
206 | case TEST_KMOD_FS_TYPE: | ||
207 | if (info && info->fs_sync && info->fs_sync->owner) | ||
208 | module_put(info->fs_sync->owner); | ||
209 | break; | ||
210 | default: | ||
211 | BUG(); | ||
212 | } | ||
213 | |||
214 | info->need_mod_put = true; | ||
215 | } | ||
216 | |||
217 | static int run_request(void *data) | ||
218 | { | ||
219 | struct kmod_test_device_info *info = data; | ||
220 | struct kmod_test_device *test_dev = info->test_dev; | ||
221 | struct test_config *config = &test_dev->config; | ||
222 | |||
223 | switch (config->test_case) { | ||
224 | case TEST_KMOD_DRIVER: | ||
225 | info->ret_sync = request_module("%s", config->test_driver); | ||
226 | break; | ||
227 | case TEST_KMOD_FS_TYPE: | ||
228 | info->fs_sync = get_fs_type(config->test_fs); | ||
229 | info->need_mod_put = true; | ||
230 | break; | ||
231 | default: | ||
232 | /* __trigger_config_run() already checked for test sanity */ | ||
233 | BUG(); | ||
234 | return -EINVAL; | ||
235 | } | ||
236 | |||
237 | dev_dbg(test_dev->dev, "Ran thread %u\n", info->thread_idx); | ||
238 | |||
239 | test_kmod_put_module(info); | ||
240 | |||
241 | mutex_lock(&test_dev->thread_mutex); | ||
242 | info->task_sync = NULL; | ||
243 | kmod_test_done_check(test_dev, info->thread_idx); | ||
244 | mutex_unlock(&test_dev->thread_mutex); | ||
245 | |||
246 | return 0; | ||
247 | } | ||
248 | |||
249 | static int tally_work_test(struct kmod_test_device_info *info) | ||
250 | { | ||
251 | struct kmod_test_device *test_dev = info->test_dev; | ||
252 | struct test_config *config = &test_dev->config; | ||
253 | int err_ret = 0; | ||
254 | |||
255 | switch (config->test_case) { | ||
256 | case TEST_KMOD_DRIVER: | ||
257 | /* | ||
258 | * Only capture errors, if one is found that's | ||
259 | * enough, for now. | ||
260 | */ | ||
261 | if (info->ret_sync != 0) | ||
262 | err_ret = info->ret_sync; | ||
263 | dev_info(test_dev->dev, | ||
264 | "Sync thread %d return status: %d\n", | ||
265 | info->thread_idx, info->ret_sync); | ||
266 | break; | ||
267 | case TEST_KMOD_FS_TYPE: | ||
268 | /* For now we make this simple */ | ||
269 | if (!info->fs_sync) | ||
270 | err_ret = -EINVAL; | ||
271 | dev_info(test_dev->dev, "Sync thread %u fs: %s\n", | ||
272 | info->thread_idx, info->fs_sync ? config->test_fs : | ||
273 | "NULL"); | ||
274 | break; | ||
275 | default: | ||
276 | BUG(); | ||
277 | } | ||
278 | |||
279 | return err_ret; | ||
280 | } | ||
281 | |||
282 | /* | ||
283 | * XXX: add result option to display if all errors did not match. | ||
284 | * For now we just keep any error code if one was found. | ||
285 | * | ||
286 | * If this ran it means *all* tasks were created fine and we | ||
287 | * are now just collecting results. | ||
288 | * | ||
289 | * Only propagate errors, do not override with a subsequent sucess case. | ||
290 | */ | ||
291 | static void tally_up_work(struct kmod_test_device *test_dev) | ||
292 | { | ||
293 | struct test_config *config = &test_dev->config; | ||
294 | struct kmod_test_device_info *info; | ||
295 | unsigned int idx; | ||
296 | int err_ret = 0; | ||
297 | int ret = 0; | ||
298 | |||
299 | mutex_lock(&test_dev->thread_mutex); | ||
300 | |||
301 | dev_info(test_dev->dev, "Results:\n"); | ||
302 | |||
303 | for (idx=0; idx < config->num_threads; idx++) { | ||
304 | info = &test_dev->info[idx]; | ||
305 | ret = tally_work_test(info); | ||
306 | if (ret) | ||
307 | err_ret = ret; | ||
308 | } | ||
309 | |||
310 | /* | ||
311 | * Note: request_module() returns 256 for a module not found even | ||
312 | * though modprobe itself returns 1. | ||
313 | */ | ||
314 | config->test_result = err_ret; | ||
315 | |||
316 | mutex_unlock(&test_dev->thread_mutex); | ||
317 | } | ||
318 | |||
319 | static int try_one_request(struct kmod_test_device *test_dev, unsigned int idx) | ||
320 | { | ||
321 | struct kmod_test_device_info *info = &test_dev->info[idx]; | ||
322 | int fail_ret = -ENOMEM; | ||
323 | |||
324 | mutex_lock(&test_dev->thread_mutex); | ||
325 | |||
326 | info->thread_idx = idx; | ||
327 | info->test_dev = test_dev; | ||
328 | info->task_sync = kthread_run(run_request, info, "%s-%u", | ||
329 | KBUILD_MODNAME, idx); | ||
330 | |||
331 | if (!info->task_sync || IS_ERR(info->task_sync)) { | ||
332 | test_dev->test_is_oom = true; | ||
333 | dev_err(test_dev->dev, "Setting up thread %u failed\n", idx); | ||
334 | info->task_sync = NULL; | ||
335 | goto err_out; | ||
336 | } else | ||
337 | dev_dbg(test_dev->dev, "Kicked off thread %u\n", idx); | ||
338 | |||
339 | mutex_unlock(&test_dev->thread_mutex); | ||
340 | |||
341 | return 0; | ||
342 | |||
343 | err_out: | ||
344 | info->ret_sync = fail_ret; | ||
345 | mutex_unlock(&test_dev->thread_mutex); | ||
346 | |||
347 | return fail_ret; | ||
348 | } | ||
349 | |||
350 | static void test_dev_kmod_stop_tests(struct kmod_test_device *test_dev) | ||
351 | { | ||
352 | struct test_config *config = &test_dev->config; | ||
353 | struct kmod_test_device_info *info; | ||
354 | unsigned int i; | ||
355 | |||
356 | dev_info(test_dev->dev, "Ending request_module() tests\n"); | ||
357 | |||
358 | mutex_lock(&test_dev->thread_mutex); | ||
359 | |||
360 | for (i=0; i < config->num_threads; i++) { | ||
361 | info = &test_dev->info[i]; | ||
362 | if (info->task_sync && !IS_ERR(info->task_sync)) { | ||
363 | dev_info(test_dev->dev, | ||
364 | "Stopping still-running thread %i\n", i); | ||
365 | kthread_stop(info->task_sync); | ||
366 | } | ||
367 | |||
368 | /* | ||
369 | * info->task_sync is well protected, it can only be | ||
370 | * NULL or a pointer to a struct. If its NULL we either | ||
371 | * never ran, or we did and we completed the work. Completed | ||
372 | * tasks *always* put the module for us. This is a sanity | ||
373 | * check -- just in case. | ||
374 | */ | ||
375 | if (info->task_sync && info->need_mod_put) | ||
376 | test_kmod_put_module(info); | ||
377 | } | ||
378 | |||
379 | mutex_unlock(&test_dev->thread_mutex); | ||
380 | } | ||
381 | |||
382 | /* | ||
383 | * Only wait *iff* we did not run into any errors during all of our thread | ||
384 | * set up. If run into any issues we stop threads and just bail out with | ||
385 | * an error to the trigger. This also means we don't need any tally work | ||
386 | * for any threads which fail. | ||
387 | */ | ||
388 | static int try_requests(struct kmod_test_device *test_dev) | ||
389 | { | ||
390 | struct test_config *config = &test_dev->config; | ||
391 | unsigned int idx; | ||
392 | int ret; | ||
393 | bool any_error = false; | ||
394 | |||
395 | for (idx=0; idx < config->num_threads; idx++) { | ||
396 | if (test_dev->test_is_oom) { | ||
397 | any_error = true; | ||
398 | break; | ||
399 | } | ||
400 | |||
401 | ret = try_one_request(test_dev, idx); | ||
402 | if (ret) { | ||
403 | any_error = true; | ||
404 | break; | ||
405 | } | ||
406 | } | ||
407 | |||
408 | if (!any_error) { | ||
409 | test_dev->test_is_oom = false; | ||
410 | dev_info(test_dev->dev, | ||
411 | "No errors were found while initializing threads\n"); | ||
412 | wait_for_completion(&test_dev->kthreads_done); | ||
413 | tally_up_work(test_dev); | ||
414 | } else { | ||
415 | test_dev->test_is_oom = true; | ||
416 | dev_info(test_dev->dev, | ||
417 | "At least one thread failed to start, stop all work\n"); | ||
418 | test_dev_kmod_stop_tests(test_dev); | ||
419 | return -ENOMEM; | ||
420 | } | ||
421 | |||
422 | return 0; | ||
423 | } | ||
424 | |||
425 | static int run_test_driver(struct kmod_test_device *test_dev) | ||
426 | { | ||
427 | struct test_config *config = &test_dev->config; | ||
428 | |||
429 | dev_info(test_dev->dev, "Test case: %s (%u)\n", | ||
430 | test_case_str(config->test_case), | ||
431 | config->test_case); | ||
432 | dev_info(test_dev->dev, "Test driver to load: %s\n", | ||
433 | config->test_driver); | ||
434 | dev_info(test_dev->dev, "Number of threads to run: %u\n", | ||
435 | config->num_threads); | ||
436 | dev_info(test_dev->dev, "Thread IDs will range from 0 - %u\n", | ||
437 | config->num_threads - 1); | ||
438 | |||
439 | return try_requests(test_dev); | ||
440 | } | ||
441 | |||
442 | static int run_test_fs_type(struct kmod_test_device *test_dev) | ||
443 | { | ||
444 | struct test_config *config = &test_dev->config; | ||
445 | |||
446 | dev_info(test_dev->dev, "Test case: %s (%u)\n", | ||
447 | test_case_str(config->test_case), | ||
448 | config->test_case); | ||
449 | dev_info(test_dev->dev, "Test filesystem to load: %s\n", | ||
450 | config->test_fs); | ||
451 | dev_info(test_dev->dev, "Number of threads to run: %u\n", | ||
452 | config->num_threads); | ||
453 | dev_info(test_dev->dev, "Thread IDs will range from 0 - %u\n", | ||
454 | config->num_threads - 1); | ||
455 | |||
456 | return try_requests(test_dev); | ||
457 | } | ||
458 | |||
459 | static ssize_t config_show(struct device *dev, | ||
460 | struct device_attribute *attr, | ||
461 | char *buf) | ||
462 | { | ||
463 | struct kmod_test_device *test_dev = dev_to_test_dev(dev); | ||
464 | struct test_config *config = &test_dev->config; | ||
465 | int len = 0; | ||
466 | |||
467 | mutex_lock(&test_dev->config_mutex); | ||
468 | |||
469 | len += snprintf(buf, PAGE_SIZE, | ||
470 | "Custom trigger configuration for: %s\n", | ||
471 | dev_name(dev)); | ||
472 | |||
473 | len += snprintf(buf+len, PAGE_SIZE - len, | ||
474 | "Number of threads:\t%u\n", | ||
475 | config->num_threads); | ||
476 | |||
477 | len += snprintf(buf+len, PAGE_SIZE - len, | ||
478 | "Test_case:\t%s (%u)\n", | ||
479 | test_case_str(config->test_case), | ||
480 | config->test_case); | ||
481 | |||
482 | if (config->test_driver) | ||
483 | len += snprintf(buf+len, PAGE_SIZE - len, | ||
484 | "driver:\t%s\n", | ||
485 | config->test_driver); | ||
486 | else | ||
487 | len += snprintf(buf+len, PAGE_SIZE - len, | ||
488 | "driver:\tEMTPY\n"); | ||
489 | |||
490 | if (config->test_fs) | ||
491 | len += snprintf(buf+len, PAGE_SIZE - len, | ||
492 | "fs:\t%s\n", | ||
493 | config->test_fs); | ||
494 | else | ||
495 | len += snprintf(buf+len, PAGE_SIZE - len, | ||
496 | "fs:\tEMTPY\n"); | ||
497 | |||
498 | mutex_unlock(&test_dev->config_mutex); | ||
499 | |||
500 | return len; | ||
501 | } | ||
502 | static DEVICE_ATTR_RO(config); | ||
503 | |||
504 | /* | ||
505 | * This ensures we don't allow kicking threads through if our configuration | ||
506 | * is faulty. | ||
507 | */ | ||
508 | static int __trigger_config_run(struct kmod_test_device *test_dev) | ||
509 | { | ||
510 | struct test_config *config = &test_dev->config; | ||
511 | |||
512 | test_dev->done = 0; | ||
513 | |||
514 | switch (config->test_case) { | ||
515 | case TEST_KMOD_DRIVER: | ||
516 | return run_test_driver(test_dev); | ||
517 | case TEST_KMOD_FS_TYPE: | ||
518 | return run_test_fs_type(test_dev); | ||
519 | default: | ||
520 | dev_warn(test_dev->dev, | ||
521 | "Invalid test case requested: %u\n", | ||
522 | config->test_case); | ||
523 | return -EINVAL; | ||
524 | } | ||
525 | } | ||
526 | |||
527 | static int trigger_config_run(struct kmod_test_device *test_dev) | ||
528 | { | ||
529 | struct test_config *config = &test_dev->config; | ||
530 | int ret; | ||
531 | |||
532 | mutex_lock(&test_dev->trigger_mutex); | ||
533 | mutex_lock(&test_dev->config_mutex); | ||
534 | |||
535 | ret = __trigger_config_run(test_dev); | ||
536 | if (ret < 0) | ||
537 | goto out; | ||
538 | dev_info(test_dev->dev, "General test result: %d\n", | ||
539 | config->test_result); | ||
540 | |||
541 | /* | ||
542 | * We must return 0 after a trigger even unless something went | ||
543 | * wrong with the setup of the test. If the test setup went fine | ||
544 | * then userspace must just check the result of config->test_result. | ||
545 | * One issue with relying on the return from a call in the kernel | ||
546 | * is if the kernel returns a possitive value using this trigger | ||
547 | * will not return the value to userspace, it would be lost. | ||
548 | * | ||
549 | * By not relying on capturing the return value of tests we are using | ||
550 | * through the trigger it also us to run tests with set -e and only | ||
551 | * fail when something went wrong with the driver upon trigger | ||
552 | * requests. | ||
553 | */ | ||
554 | ret = 0; | ||
555 | |||
556 | out: | ||
557 | mutex_unlock(&test_dev->config_mutex); | ||
558 | mutex_unlock(&test_dev->trigger_mutex); | ||
559 | |||
560 | return ret; | ||
561 | } | ||
562 | |||
563 | static ssize_t | ||
564 | trigger_config_store(struct device *dev, | ||
565 | struct device_attribute *attr, | ||
566 | const char *buf, size_t count) | ||
567 | { | ||
568 | struct kmod_test_device *test_dev = dev_to_test_dev(dev); | ||
569 | int ret; | ||
570 | |||
571 | if (test_dev->test_is_oom) | ||
572 | return -ENOMEM; | ||
573 | |||
574 | /* For all intents and purposes we don't care what userspace | ||
575 | * sent this trigger, we care only that we were triggered. | ||
576 | * We treat the return value only for caputuring issues with | ||
577 | * the test setup. At this point all the test variables should | ||
578 | * have been allocated so typically this should never fail. | ||
579 | */ | ||
580 | ret = trigger_config_run(test_dev); | ||
581 | if (unlikely(ret < 0)) | ||
582 | goto out; | ||
583 | |||
584 | /* | ||
585 | * Note: any return > 0 will be treated as success | ||
586 | * and the error value will not be available to userspace. | ||
587 | * Do not rely on trying to send to userspace a test value | ||
588 | * return value as possitive return errors will be lost. | ||
589 | */ | ||
590 | if (WARN_ON(ret > 0)) | ||
591 | return -EINVAL; | ||
592 | |||
593 | ret = count; | ||
594 | out: | ||
595 | return ret; | ||
596 | } | ||
597 | static DEVICE_ATTR_WO(trigger_config); | ||
598 | |||
599 | /* | ||
600 | * XXX: move to kstrncpy() once merged. | ||
601 | * | ||
602 | * Users should use kfree_const() when freeing these. | ||
603 | */ | ||
604 | static int __kstrncpy(char **dst, const char *name, size_t count, gfp_t gfp) | ||
605 | { | ||
606 | *dst = kstrndup(name, count, gfp); | ||
607 | if (!*dst) | ||
608 | return -ENOSPC; | ||
609 | return count; | ||
610 | } | ||
611 | |||
612 | static int config_copy_test_driver_name(struct test_config *config, | ||
613 | const char *name, | ||
614 | size_t count) | ||
615 | { | ||
616 | return __kstrncpy(&config->test_driver, name, count, GFP_KERNEL); | ||
617 | } | ||
618 | |||
619 | |||
620 | static int config_copy_test_fs(struct test_config *config, const char *name, | ||
621 | size_t count) | ||
622 | { | ||
623 | return __kstrncpy(&config->test_fs, name, count, GFP_KERNEL); | ||
624 | } | ||
625 | |||
626 | static void __kmod_config_free(struct test_config *config) | ||
627 | { | ||
628 | if (!config) | ||
629 | return; | ||
630 | |||
631 | kfree_const(config->test_driver); | ||
632 | config->test_driver = NULL; | ||
633 | |||
634 | kfree_const(config->test_fs); | ||
635 | config->test_driver = NULL; | ||
636 | } | ||
637 | |||
638 | static void kmod_config_free(struct kmod_test_device *test_dev) | ||
639 | { | ||
640 | struct test_config *config; | ||
641 | |||
642 | if (!test_dev) | ||
643 | return; | ||
644 | |||
645 | config = &test_dev->config; | ||
646 | |||
647 | mutex_lock(&test_dev->config_mutex); | ||
648 | __kmod_config_free(config); | ||
649 | mutex_unlock(&test_dev->config_mutex); | ||
650 | } | ||
651 | |||
652 | static ssize_t config_test_driver_store(struct device *dev, | ||
653 | struct device_attribute *attr, | ||
654 | const char *buf, size_t count) | ||
655 | { | ||
656 | struct kmod_test_device *test_dev = dev_to_test_dev(dev); | ||
657 | struct test_config *config = &test_dev->config; | ||
658 | int copied; | ||
659 | |||
660 | mutex_lock(&test_dev->config_mutex); | ||
661 | |||
662 | kfree_const(config->test_driver); | ||
663 | config->test_driver = NULL; | ||
664 | |||
665 | copied = config_copy_test_driver_name(config, buf, count); | ||
666 | mutex_unlock(&test_dev->config_mutex); | ||
667 | |||
668 | return copied; | ||
669 | } | ||
670 | |||
671 | /* | ||
672 | * As per sysfs_kf_seq_show() the buf is max PAGE_SIZE. | ||
673 | */ | ||
674 | static ssize_t config_test_show_str(struct mutex *config_mutex, | ||
675 | char *dst, | ||
676 | char *src) | ||
677 | { | ||
678 | int len; | ||
679 | |||
680 | mutex_lock(config_mutex); | ||
681 | len = snprintf(dst, PAGE_SIZE, "%s\n", src); | ||
682 | mutex_unlock(config_mutex); | ||
683 | |||
684 | return len; | ||
685 | } | ||
686 | |||
687 | static ssize_t config_test_driver_show(struct device *dev, | ||
688 | struct device_attribute *attr, | ||
689 | char *buf) | ||
690 | { | ||
691 | struct kmod_test_device *test_dev = dev_to_test_dev(dev); | ||
692 | struct test_config *config = &test_dev->config; | ||
693 | |||
694 | return config_test_show_str(&test_dev->config_mutex, buf, | ||
695 | config->test_driver); | ||
696 | } | ||
697 | static DEVICE_ATTR(config_test_driver, 0644, config_test_driver_show, | ||
698 | config_test_driver_store); | ||
699 | |||
700 | static ssize_t config_test_fs_store(struct device *dev, | ||
701 | struct device_attribute *attr, | ||
702 | const char *buf, size_t count) | ||
703 | { | ||
704 | struct kmod_test_device *test_dev = dev_to_test_dev(dev); | ||
705 | struct test_config *config = &test_dev->config; | ||
706 | int copied; | ||
707 | |||
708 | mutex_lock(&test_dev->config_mutex); | ||
709 | |||
710 | kfree_const(config->test_fs); | ||
711 | config->test_fs = NULL; | ||
712 | |||
713 | copied = config_copy_test_fs(config, buf, count); | ||
714 | mutex_unlock(&test_dev->config_mutex); | ||
715 | |||
716 | return copied; | ||
717 | } | ||
718 | |||
719 | static ssize_t config_test_fs_show(struct device *dev, | ||
720 | struct device_attribute *attr, | ||
721 | char *buf) | ||
722 | { | ||
723 | struct kmod_test_device *test_dev = dev_to_test_dev(dev); | ||
724 | struct test_config *config = &test_dev->config; | ||
725 | |||
726 | return config_test_show_str(&test_dev->config_mutex, buf, | ||
727 | config->test_fs); | ||
728 | } | ||
729 | static DEVICE_ATTR(config_test_fs, 0644, config_test_fs_show, | ||
730 | config_test_fs_store); | ||
731 | |||
732 | static int trigger_config_run_type(struct kmod_test_device *test_dev, | ||
733 | enum kmod_test_case test_case, | ||
734 | const char *test_str) | ||
735 | { | ||
736 | int copied = 0; | ||
737 | struct test_config *config = &test_dev->config; | ||
738 | |||
739 | mutex_lock(&test_dev->config_mutex); | ||
740 | |||
741 | switch (test_case) { | ||
742 | case TEST_KMOD_DRIVER: | ||
743 | kfree_const(config->test_driver); | ||
744 | config->test_driver = NULL; | ||
745 | copied = config_copy_test_driver_name(config, test_str, | ||
746 | strlen(test_str)); | ||
747 | break; | ||
748 | case TEST_KMOD_FS_TYPE: | ||
749 | break; | ||
750 | kfree_const(config->test_fs); | ||
751 | config->test_driver = NULL; | ||
752 | copied = config_copy_test_fs(config, test_str, | ||
753 | strlen(test_str)); | ||
754 | default: | ||
755 | mutex_unlock(&test_dev->config_mutex); | ||
756 | return -EINVAL; | ||
757 | } | ||
758 | |||
759 | config->test_case = test_case; | ||
760 | |||
761 | mutex_unlock(&test_dev->config_mutex); | ||
762 | |||
763 | if (copied <= 0 || copied != strlen(test_str)) { | ||
764 | test_dev->test_is_oom = true; | ||
765 | return -ENOMEM; | ||
766 | } | ||
767 | |||
768 | test_dev->test_is_oom = false; | ||
769 | |||
770 | return trigger_config_run(test_dev); | ||
771 | } | ||
772 | |||
773 | static void free_test_dev_info(struct kmod_test_device *test_dev) | ||
774 | { | ||
775 | vfree(test_dev->info); | ||
776 | test_dev->info = NULL; | ||
777 | } | ||
778 | |||
779 | static int kmod_config_sync_info(struct kmod_test_device *test_dev) | ||
780 | { | ||
781 | struct test_config *config = &test_dev->config; | ||
782 | |||
783 | free_test_dev_info(test_dev); | ||
784 | test_dev->info = vzalloc(config->num_threads * | ||
785 | sizeof(struct kmod_test_device_info)); | ||
786 | if (!test_dev->info) { | ||
787 | dev_err(test_dev->dev, "Cannot alloc test_dev info\n"); | ||
788 | return -ENOMEM; | ||
789 | } | ||
790 | |||
791 | return 0; | ||
792 | } | ||
793 | |||
794 | /* | ||
795 | * Old kernels may not have this, if you want to port this code to | ||
796 | * test it on older kernels. | ||
797 | */ | ||
798 | #ifdef get_kmod_umh_limit | ||
799 | static unsigned int kmod_init_test_thread_limit(void) | ||
800 | { | ||
801 | return get_kmod_umh_limit(); | ||
802 | } | ||
803 | #else | ||
804 | static unsigned int kmod_init_test_thread_limit(void) | ||
805 | { | ||
806 | return TEST_START_NUM_THREADS; | ||
807 | } | ||
808 | #endif | ||
809 | |||
810 | static int __kmod_config_init(struct kmod_test_device *test_dev) | ||
811 | { | ||
812 | struct test_config *config = &test_dev->config; | ||
813 | int ret = -ENOMEM, copied; | ||
814 | |||
815 | __kmod_config_free(config); | ||
816 | |||
817 | copied = config_copy_test_driver_name(config, TEST_START_DRIVER, | ||
818 | strlen(TEST_START_DRIVER)); | ||
819 | if (copied != strlen(TEST_START_DRIVER)) | ||
820 | goto err_out; | ||
821 | |||
822 | copied = config_copy_test_fs(config, TEST_START_TEST_FS, | ||
823 | strlen(TEST_START_TEST_FS)); | ||
824 | if (copied != strlen(TEST_START_TEST_FS)) | ||
825 | goto err_out; | ||
826 | |||
827 | config->num_threads = kmod_init_test_thread_limit(); | ||
828 | config->test_result = 0; | ||
829 | config->test_case = TEST_START_TEST_CASE; | ||
830 | |||
831 | ret = kmod_config_sync_info(test_dev); | ||
832 | if (ret) | ||
833 | goto err_out; | ||
834 | |||
835 | test_dev->test_is_oom = false; | ||
836 | |||
837 | return 0; | ||
838 | |||
839 | err_out: | ||
840 | test_dev->test_is_oom = true; | ||
841 | WARN_ON(test_dev->test_is_oom); | ||
842 | |||
843 | __kmod_config_free(config); | ||
844 | |||
845 | return ret; | ||
846 | } | ||
847 | |||
848 | static ssize_t reset_store(struct device *dev, | ||
849 | struct device_attribute *attr, | ||
850 | const char *buf, size_t count) | ||
851 | { | ||
852 | struct kmod_test_device *test_dev = dev_to_test_dev(dev); | ||
853 | int ret; | ||
854 | |||
855 | mutex_lock(&test_dev->trigger_mutex); | ||
856 | mutex_lock(&test_dev->config_mutex); | ||
857 | |||
858 | ret = __kmod_config_init(test_dev); | ||
859 | if (ret < 0) { | ||
860 | ret = -ENOMEM; | ||
861 | dev_err(dev, "could not alloc settings for config trigger: %d\n", | ||
862 | ret); | ||
863 | goto out; | ||
864 | } | ||
865 | |||
866 | dev_info(dev, "reset\n"); | ||
867 | ret = count; | ||
868 | |||
869 | out: | ||
870 | mutex_unlock(&test_dev->config_mutex); | ||
871 | mutex_unlock(&test_dev->trigger_mutex); | ||
872 | |||
873 | return ret; | ||
874 | } | ||
875 | static DEVICE_ATTR_WO(reset); | ||
876 | |||
877 | static int test_dev_config_update_uint_sync(struct kmod_test_device *test_dev, | ||
878 | const char *buf, size_t size, | ||
879 | unsigned int *config, | ||
880 | int (*test_sync)(struct kmod_test_device *test_dev)) | ||
881 | { | ||
882 | int ret; | ||
883 | long new; | ||
884 | unsigned int old_val; | ||
885 | |||
886 | ret = kstrtol(buf, 10, &new); | ||
887 | if (ret) | ||
888 | return ret; | ||
889 | |||
890 | if (new > UINT_MAX) | ||
891 | return -EINVAL; | ||
892 | |||
893 | mutex_lock(&test_dev->config_mutex); | ||
894 | |||
895 | old_val = *config; | ||
896 | *(unsigned int *)config = new; | ||
897 | |||
898 | ret = test_sync(test_dev); | ||
899 | if (ret) { | ||
900 | *(unsigned int *)config = old_val; | ||
901 | |||
902 | ret = test_sync(test_dev); | ||
903 | WARN_ON(ret); | ||
904 | |||
905 | mutex_unlock(&test_dev->config_mutex); | ||
906 | return -EINVAL; | ||
907 | } | ||
908 | |||
909 | mutex_unlock(&test_dev->config_mutex); | ||
910 | /* Always return full write size even if we didn't consume all */ | ||
911 | return size; | ||
912 | } | ||
913 | |||
914 | static int test_dev_config_update_uint_range(struct kmod_test_device *test_dev, | ||
915 | const char *buf, size_t size, | ||
916 | unsigned int *config, | ||
917 | unsigned int min, | ||
918 | unsigned int max) | ||
919 | { | ||
920 | int ret; | ||
921 | long new; | ||
922 | |||
923 | ret = kstrtol(buf, 10, &new); | ||
924 | if (ret) | ||
925 | return ret; | ||
926 | |||
927 | if (new < min || new > max || new > UINT_MAX) | ||
928 | return -EINVAL; | ||
929 | |||
930 | mutex_lock(&test_dev->config_mutex); | ||
931 | *config = new; | ||
932 | mutex_unlock(&test_dev->config_mutex); | ||
933 | |||
934 | /* Always return full write size even if we didn't consume all */ | ||
935 | return size; | ||
936 | } | ||
937 | |||
938 | static int test_dev_config_update_int(struct kmod_test_device *test_dev, | ||
939 | const char *buf, size_t size, | ||
940 | int *config) | ||
941 | { | ||
942 | int ret; | ||
943 | long new; | ||
944 | |||
945 | ret = kstrtol(buf, 10, &new); | ||
946 | if (ret) | ||
947 | return ret; | ||
948 | |||
949 | if (new > INT_MAX || new < INT_MIN) | ||
950 | return -EINVAL; | ||
951 | |||
952 | mutex_lock(&test_dev->config_mutex); | ||
953 | *config = new; | ||
954 | mutex_unlock(&test_dev->config_mutex); | ||
955 | /* Always return full write size even if we didn't consume all */ | ||
956 | return size; | ||
957 | } | ||
958 | |||
959 | static ssize_t test_dev_config_show_int(struct kmod_test_device *test_dev, | ||
960 | char *buf, | ||
961 | int config) | ||
962 | { | ||
963 | int val; | ||
964 | |||
965 | mutex_lock(&test_dev->config_mutex); | ||
966 | val = config; | ||
967 | mutex_unlock(&test_dev->config_mutex); | ||
968 | |||
969 | return snprintf(buf, PAGE_SIZE, "%d\n", val); | ||
970 | } | ||
971 | |||
972 | static ssize_t test_dev_config_show_uint(struct kmod_test_device *test_dev, | ||
973 | char *buf, | ||
974 | unsigned int config) | ||
975 | { | ||
976 | unsigned int val; | ||
977 | |||
978 | mutex_lock(&test_dev->config_mutex); | ||
979 | val = config; | ||
980 | mutex_unlock(&test_dev->config_mutex); | ||
981 | |||
982 | return snprintf(buf, PAGE_SIZE, "%u\n", val); | ||
983 | } | ||
984 | |||
985 | static ssize_t test_result_store(struct device *dev, | ||
986 | struct device_attribute *attr, | ||
987 | const char *buf, size_t count) | ||
988 | { | ||
989 | struct kmod_test_device *test_dev = dev_to_test_dev(dev); | ||
990 | struct test_config *config = &test_dev->config; | ||
991 | |||
992 | return test_dev_config_update_int(test_dev, buf, count, | ||
993 | &config->test_result); | ||
994 | } | ||
995 | |||
996 | static ssize_t config_num_threads_store(struct device *dev, | ||
997 | struct device_attribute *attr, | ||
998 | const char *buf, size_t count) | ||
999 | { | ||
1000 | struct kmod_test_device *test_dev = dev_to_test_dev(dev); | ||
1001 | struct test_config *config = &test_dev->config; | ||
1002 | |||
1003 | return test_dev_config_update_uint_sync(test_dev, buf, count, | ||
1004 | &config->num_threads, | ||
1005 | kmod_config_sync_info); | ||
1006 | } | ||
1007 | |||
1008 | static ssize_t config_num_threads_show(struct device *dev, | ||
1009 | struct device_attribute *attr, | ||
1010 | char *buf) | ||
1011 | { | ||
1012 | struct kmod_test_device *test_dev = dev_to_test_dev(dev); | ||
1013 | struct test_config *config = &test_dev->config; | ||
1014 | |||
1015 | return test_dev_config_show_int(test_dev, buf, config->num_threads); | ||
1016 | } | ||
1017 | static DEVICE_ATTR(config_num_threads, 0644, config_num_threads_show, | ||
1018 | config_num_threads_store); | ||
1019 | |||
1020 | static ssize_t config_test_case_store(struct device *dev, | ||
1021 | struct device_attribute *attr, | ||
1022 | const char *buf, size_t count) | ||
1023 | { | ||
1024 | struct kmod_test_device *test_dev = dev_to_test_dev(dev); | ||
1025 | struct test_config *config = &test_dev->config; | ||
1026 | |||
1027 | return test_dev_config_update_uint_range(test_dev, buf, count, | ||
1028 | &config->test_case, | ||
1029 | __TEST_KMOD_INVALID + 1, | ||
1030 | __TEST_KMOD_MAX - 1); | ||
1031 | } | ||
1032 | |||
1033 | static ssize_t config_test_case_show(struct device *dev, | ||
1034 | struct device_attribute *attr, | ||
1035 | char *buf) | ||
1036 | { | ||
1037 | struct kmod_test_device *test_dev = dev_to_test_dev(dev); | ||
1038 | struct test_config *config = &test_dev->config; | ||
1039 | |||
1040 | return test_dev_config_show_uint(test_dev, buf, config->test_case); | ||
1041 | } | ||
1042 | static DEVICE_ATTR(config_test_case, 0644, config_test_case_show, | ||
1043 | config_test_case_store); | ||
1044 | |||
1045 | static ssize_t test_result_show(struct device *dev, | ||
1046 | struct device_attribute *attr, | ||
1047 | char *buf) | ||
1048 | { | ||
1049 | struct kmod_test_device *test_dev = dev_to_test_dev(dev); | ||
1050 | struct test_config *config = &test_dev->config; | ||
1051 | |||
1052 | return test_dev_config_show_int(test_dev, buf, config->test_result); | ||
1053 | } | ||
1054 | static DEVICE_ATTR(test_result, 0644, test_result_show, test_result_store); | ||
1055 | |||
1056 | #define TEST_KMOD_DEV_ATTR(name) &dev_attr_##name.attr | ||
1057 | |||
1058 | static struct attribute *test_dev_attrs[] = { | ||
1059 | TEST_KMOD_DEV_ATTR(trigger_config), | ||
1060 | TEST_KMOD_DEV_ATTR(config), | ||
1061 | TEST_KMOD_DEV_ATTR(reset), | ||
1062 | |||
1063 | TEST_KMOD_DEV_ATTR(config_test_driver), | ||
1064 | TEST_KMOD_DEV_ATTR(config_test_fs), | ||
1065 | TEST_KMOD_DEV_ATTR(config_num_threads), | ||
1066 | TEST_KMOD_DEV_ATTR(config_test_case), | ||
1067 | TEST_KMOD_DEV_ATTR(test_result), | ||
1068 | |||
1069 | NULL, | ||
1070 | }; | ||
1071 | |||
1072 | ATTRIBUTE_GROUPS(test_dev); | ||
1073 | |||
1074 | static int kmod_config_init(struct kmod_test_device *test_dev) | ||
1075 | { | ||
1076 | int ret; | ||
1077 | |||
1078 | mutex_lock(&test_dev->config_mutex); | ||
1079 | ret = __kmod_config_init(test_dev); | ||
1080 | mutex_unlock(&test_dev->config_mutex); | ||
1081 | |||
1082 | return ret; | ||
1083 | } | ||
1084 | |||
1085 | static struct kmod_test_device *alloc_test_dev_kmod(int idx) | ||
1086 | { | ||
1087 | int ret; | ||
1088 | struct kmod_test_device *test_dev; | ||
1089 | struct miscdevice *misc_dev; | ||
1090 | |||
1091 | test_dev = vzalloc(sizeof(struct kmod_test_device)); | ||
1092 | if (!test_dev) { | ||
1093 | pr_err("Cannot alloc test_dev\n"); | ||
1094 | goto err_out; | ||
1095 | } | ||
1096 | |||
1097 | mutex_init(&test_dev->config_mutex); | ||
1098 | mutex_init(&test_dev->trigger_mutex); | ||
1099 | mutex_init(&test_dev->thread_mutex); | ||
1100 | |||
1101 | init_completion(&test_dev->kthreads_done); | ||
1102 | |||
1103 | ret = kmod_config_init(test_dev); | ||
1104 | if (ret < 0) { | ||
1105 | pr_err("Cannot alloc kmod_config_init()\n"); | ||
1106 | goto err_out_free; | ||
1107 | } | ||
1108 | |||
1109 | test_dev->dev_idx = idx; | ||
1110 | misc_dev = &test_dev->misc_dev; | ||
1111 | |||
1112 | misc_dev->minor = MISC_DYNAMIC_MINOR; | ||
1113 | misc_dev->name = kasprintf(GFP_KERNEL, "test_kmod%d", idx); | ||
1114 | if (!misc_dev->name) { | ||
1115 | pr_err("Cannot alloc misc_dev->name\n"); | ||
1116 | goto err_out_free_config; | ||
1117 | } | ||
1118 | misc_dev->groups = test_dev_groups; | ||
1119 | |||
1120 | return test_dev; | ||
1121 | |||
1122 | err_out_free_config: | ||
1123 | free_test_dev_info(test_dev); | ||
1124 | kmod_config_free(test_dev); | ||
1125 | err_out_free: | ||
1126 | vfree(test_dev); | ||
1127 | test_dev = NULL; | ||
1128 | err_out: | ||
1129 | return NULL; | ||
1130 | } | ||
1131 | |||
1132 | static void free_test_dev_kmod(struct kmod_test_device *test_dev) | ||
1133 | { | ||
1134 | if (test_dev) { | ||
1135 | kfree_const(test_dev->misc_dev.name); | ||
1136 | test_dev->misc_dev.name = NULL; | ||
1137 | free_test_dev_info(test_dev); | ||
1138 | kmod_config_free(test_dev); | ||
1139 | vfree(test_dev); | ||
1140 | test_dev = NULL; | ||
1141 | } | ||
1142 | } | ||
1143 | |||
1144 | static struct kmod_test_device *register_test_dev_kmod(void) | ||
1145 | { | ||
1146 | struct kmod_test_device *test_dev = NULL; | ||
1147 | int ret; | ||
1148 | |||
1149 | mutex_unlock(®_dev_mutex); | ||
1150 | |||
1151 | /* int should suffice for number of devices, test for wrap */ | ||
1152 | if (unlikely(num_test_devs + 1) < 0) { | ||
1153 | pr_err("reached limit of number of test devices\n"); | ||
1154 | goto out; | ||
1155 | } | ||
1156 | |||
1157 | test_dev = alloc_test_dev_kmod(num_test_devs); | ||
1158 | if (!test_dev) | ||
1159 | goto out; | ||
1160 | |||
1161 | ret = misc_register(&test_dev->misc_dev); | ||
1162 | if (ret) { | ||
1163 | pr_err("could not register misc device: %d\n", ret); | ||
1164 | free_test_dev_kmod(test_dev); | ||
1165 | goto out; | ||
1166 | } | ||
1167 | |||
1168 | test_dev->dev = test_dev->misc_dev.this_device; | ||
1169 | list_add_tail(&test_dev->list, ®_test_devs); | ||
1170 | dev_info(test_dev->dev, "interface ready\n"); | ||
1171 | |||
1172 | num_test_devs++; | ||
1173 | |||
1174 | out: | ||
1175 | mutex_unlock(®_dev_mutex); | ||
1176 | |||
1177 | return test_dev; | ||
1178 | |||
1179 | } | ||
1180 | |||
1181 | static int __init test_kmod_init(void) | ||
1182 | { | ||
1183 | struct kmod_test_device *test_dev; | ||
1184 | int ret; | ||
1185 | |||
1186 | test_dev = register_test_dev_kmod(); | ||
1187 | if (!test_dev) { | ||
1188 | pr_err("Cannot add first test kmod device\n"); | ||
1189 | return -ENODEV; | ||
1190 | } | ||
1191 | |||
1192 | /* | ||
1193 | * With some work we might be able to gracefully enable | ||
1194 | * testing with this driver built-in, for now this seems | ||
1195 | * rather risky. For those willing to try have at it, | ||
1196 | * and enable the below. Good luck! If that works, try | ||
1197 | * lowering the init level for more fun. | ||
1198 | */ | ||
1199 | if (force_init_test) { | ||
1200 | ret = trigger_config_run_type(test_dev, | ||
1201 | TEST_KMOD_DRIVER, "tun"); | ||
1202 | if (WARN_ON(ret)) | ||
1203 | return ret; | ||
1204 | ret = trigger_config_run_type(test_dev, | ||
1205 | TEST_KMOD_FS_TYPE, "btrfs"); | ||
1206 | if (WARN_ON(ret)) | ||
1207 | return ret; | ||
1208 | } | ||
1209 | |||
1210 | return 0; | ||
1211 | } | ||
1212 | late_initcall(test_kmod_init); | ||
1213 | |||
1214 | static | ||
1215 | void unregister_test_dev_kmod(struct kmod_test_device *test_dev) | ||
1216 | { | ||
1217 | mutex_lock(&test_dev->trigger_mutex); | ||
1218 | mutex_lock(&test_dev->config_mutex); | ||
1219 | |||
1220 | test_dev_kmod_stop_tests(test_dev); | ||
1221 | |||
1222 | dev_info(test_dev->dev, "removing interface\n"); | ||
1223 | misc_deregister(&test_dev->misc_dev); | ||
1224 | kfree(&test_dev->misc_dev.name); | ||
1225 | |||
1226 | mutex_unlock(&test_dev->config_mutex); | ||
1227 | mutex_unlock(&test_dev->trigger_mutex); | ||
1228 | |||
1229 | free_test_dev_kmod(test_dev); | ||
1230 | } | ||
1231 | |||
1232 | static void __exit test_kmod_exit(void) | ||
1233 | { | ||
1234 | struct kmod_test_device *test_dev, *tmp; | ||
1235 | |||
1236 | mutex_lock(®_dev_mutex); | ||
1237 | list_for_each_entry_safe(test_dev, tmp, ®_test_devs, list) { | ||
1238 | list_del(&test_dev->list); | ||
1239 | unregister_test_dev_kmod(test_dev); | ||
1240 | } | ||
1241 | mutex_unlock(®_dev_mutex); | ||
1242 | } | ||
1243 | module_exit(test_kmod_exit); | ||
1244 | |||
1245 | MODULE_AUTHOR("Luis R. Rodriguez <mcgrof@kernel.org>"); | ||
1246 | MODULE_LICENSE("GPL"); | ||
@@ -2231,7 +2231,7 @@ int expand_upwards(struct vm_area_struct *vma, unsigned long address) | |||
2231 | 2231 | ||
2232 | /* Guard against exceeding limits of the address space. */ | 2232 | /* Guard against exceeding limits of the address space. */ |
2233 | address &= PAGE_MASK; | 2233 | address &= PAGE_MASK; |
2234 | if (address >= TASK_SIZE) | 2234 | if (address >= (TASK_SIZE & PAGE_MASK)) |
2235 | return -ENOMEM; | 2235 | return -ENOMEM; |
2236 | address += PAGE_SIZE; | 2236 | address += PAGE_SIZE; |
2237 | 2237 | ||
diff --git a/tools/testing/selftests/kmod/Makefile b/tools/testing/selftests/kmod/Makefile new file mode 100644 index 000000000000..fa2ccc5fb3de --- /dev/null +++ b/tools/testing/selftests/kmod/Makefile | |||
@@ -0,0 +1,11 @@ | |||
1 | # Makefile for kmod loading selftests | ||
2 | |||
3 | # No binaries, but make sure arg-less "make" doesn't trigger "run_tests" | ||
4 | all: | ||
5 | |||
6 | TEST_PROGS := kmod.sh | ||
7 | |||
8 | include ../lib.mk | ||
9 | |||
10 | # Nothing to clean up. | ||
11 | clean: | ||
diff --git a/tools/testing/selftests/kmod/config b/tools/testing/selftests/kmod/config new file mode 100644 index 000000000000..259f4fd6b5e2 --- /dev/null +++ b/tools/testing/selftests/kmod/config | |||
@@ -0,0 +1,7 @@ | |||
1 | CONFIG_TEST_KMOD=m | ||
2 | CONFIG_TEST_LKM=m | ||
3 | CONFIG_XFS_FS=m | ||
4 | |||
5 | # For the module parameter force_init_test is used | ||
6 | CONFIG_TUN=m | ||
7 | CONFIG_BTRFS_FS=m | ||
diff --git a/tools/testing/selftests/kmod/kmod.sh b/tools/testing/selftests/kmod/kmod.sh new file mode 100644 index 000000000000..8cecae9a8bca --- /dev/null +++ b/tools/testing/selftests/kmod/kmod.sh | |||
@@ -0,0 +1,615 @@ | |||
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 filesyste 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 | |||
65 | test_modprobe() | ||
66 | { | ||
67 | if [ ! -d $DIR ]; then | ||
68 | echo "$0: $DIR not present" >&2 | ||
69 | echo "You must have the following enabled in your kernel:" >&2 | ||
70 | cat $TEST_DIR/config >&2 | ||
71 | exit 1 | ||
72 | fi | ||
73 | } | ||
74 | |||
75 | function allow_user_defaults() | ||
76 | { | ||
77 | if [ -z $DEFAULT_KMOD_DRIVER ]; then | ||
78 | DEFAULT_KMOD_DRIVER="test_module" | ||
79 | fi | ||
80 | |||
81 | if [ -z $DEFAULT_KMOD_FS ]; then | ||
82 | DEFAULT_KMOD_FS="xfs" | ||
83 | fi | ||
84 | |||
85 | if [ -z $PROC_DIR ]; then | ||
86 | PROC_DIR="/proc/sys/kernel/" | ||
87 | fi | ||
88 | |||
89 | if [ -z $MODPROBE_LIMIT ]; then | ||
90 | MODPROBE_LIMIT=50 | ||
91 | fi | ||
92 | |||
93 | if [ -z $DIR ]; then | ||
94 | DIR="/sys/devices/virtual/misc/${TEST_DRIVER}0/" | ||
95 | fi | ||
96 | |||
97 | if [ -z $DEFAULT_NUM_TESTS ]; then | ||
98 | DEFAULT_NUM_TESTS=150 | ||
99 | fi | ||
100 | |||
101 | MODPROBE_LIMIT_FILE="${PROC_DIR}/kmod-limit" | ||
102 | } | ||
103 | |||
104 | test_reqs() | ||
105 | { | ||
106 | if ! which modprobe 2> /dev/null > /dev/null; then | ||
107 | echo "$0: You need modprobe installed" >&2 | ||
108 | exit 1 | ||
109 | fi | ||
110 | |||
111 | if ! which kmod 2> /dev/null > /dev/null; then | ||
112 | echo "$0: You need kmod installed" >&2 | ||
113 | exit 1 | ||
114 | fi | ||
115 | |||
116 | # kmod 19 has a bad bug where it returns 0 when modprobe | ||
117 | # gets called *even* if the module was not loaded due to | ||
118 | # some bad heuristics. For details see: | ||
119 | # | ||
120 | # A work around is possible in-kernel but its rather | ||
121 | # complex. | ||
122 | KMOD_VERSION=$(kmod --version | awk '{print $3}') | ||
123 | if [[ $KMOD_VERSION -le 19 ]]; then | ||
124 | echo "$0: You need at least kmod 20" >&2 | ||
125 | echo "kmod <= 19 is buggy, for details see:" >&2 | ||
126 | echo "http://git.kernel.org/cgit/utils/kernel/kmod/kmod.git/commit/libkmod/libkmod-module.c?id=fd44a98ae2eb5eb32161088954ab21e58e19dfc4" >&2 | ||
127 | exit 1 | ||
128 | fi | ||
129 | |||
130 | uid=$(id -u) | ||
131 | if [ $uid -ne 0 ]; then | ||
132 | echo $msg must be run as root >&2 | ||
133 | exit 0 | ||
134 | fi | ||
135 | } | ||
136 | |||
137 | function load_req_mod() | ||
138 | { | ||
139 | trap "test_modprobe" EXIT | ||
140 | |||
141 | if [ ! -d $DIR ]; then | ||
142 | # Alanis: "Oh isn't it ironic?" | ||
143 | modprobe $TEST_DRIVER | ||
144 | fi | ||
145 | } | ||
146 | |||
147 | test_finish() | ||
148 | { | ||
149 | echo "Test completed" | ||
150 | } | ||
151 | |||
152 | errno_name_to_val() | ||
153 | { | ||
154 | case "$1" in | ||
155 | # kmod calls modprobe and upon of a module not found | ||
156 | # modprobe returns just 1... However in the kernel we | ||
157 | # *sometimes* see 256... | ||
158 | MODULE_NOT_FOUND) | ||
159 | echo 256;; | ||
160 | SUCCESS) | ||
161 | echo 0;; | ||
162 | -EPERM) | ||
163 | echo -1;; | ||
164 | -ENOENT) | ||
165 | echo -2;; | ||
166 | -EINVAL) | ||
167 | echo -22;; | ||
168 | -ERR_ANY) | ||
169 | echo -123456;; | ||
170 | *) | ||
171 | echo invalid;; | ||
172 | esac | ||
173 | } | ||
174 | |||
175 | errno_val_to_name() | ||
176 | case "$1" in | ||
177 | 256) | ||
178 | echo MODULE_NOT_FOUND;; | ||
179 | 0) | ||
180 | echo SUCCESS;; | ||
181 | -1) | ||
182 | echo -EPERM;; | ||
183 | -2) | ||
184 | echo -ENOENT;; | ||
185 | -22) | ||
186 | echo -EINVAL;; | ||
187 | -123456) | ||
188 | echo -ERR_ANY;; | ||
189 | *) | ||
190 | echo invalid;; | ||
191 | esac | ||
192 | |||
193 | config_set_test_case_driver() | ||
194 | { | ||
195 | if ! echo -n 1 >$DIR/config_test_case; then | ||
196 | echo "$0: Unable to set to test case to driver" >&2 | ||
197 | exit 1 | ||
198 | fi | ||
199 | } | ||
200 | |||
201 | config_set_test_case_fs() | ||
202 | { | ||
203 | if ! echo -n 2 >$DIR/config_test_case; then | ||
204 | echo "$0: Unable to set to test case to fs" >&2 | ||
205 | exit 1 | ||
206 | fi | ||
207 | } | ||
208 | |||
209 | config_num_threads() | ||
210 | { | ||
211 | if ! echo -n $1 >$DIR/config_num_threads; then | ||
212 | echo "$0: Unable to set to number of threads" >&2 | ||
213 | exit 1 | ||
214 | fi | ||
215 | } | ||
216 | |||
217 | config_get_modprobe_limit() | ||
218 | { | ||
219 | if [[ -f ${MODPROBE_LIMIT_FILE} ]] ; then | ||
220 | MODPROBE_LIMIT=$(cat $MODPROBE_LIMIT_FILE) | ||
221 | fi | ||
222 | echo $MODPROBE_LIMIT | ||
223 | } | ||
224 | |||
225 | config_num_thread_limit_extra() | ||
226 | { | ||
227 | MODPROBE_LIMIT=$(config_get_modprobe_limit) | ||
228 | let EXTRA_LIMIT=$MODPROBE_LIMIT+$1 | ||
229 | config_num_threads $EXTRA_LIMIT | ||
230 | } | ||
231 | |||
232 | # For special characters use printf directly, | ||
233 | # refer to kmod_test_0001 | ||
234 | config_set_driver() | ||
235 | { | ||
236 | if ! echo -n $1 >$DIR/config_test_driver; then | ||
237 | echo "$0: Unable to set driver" >&2 | ||
238 | exit 1 | ||
239 | fi | ||
240 | } | ||
241 | |||
242 | config_set_fs() | ||
243 | { | ||
244 | if ! echo -n $1 >$DIR/config_test_fs; then | ||
245 | echo "$0: Unable to set driver" >&2 | ||
246 | exit 1 | ||
247 | fi | ||
248 | } | ||
249 | |||
250 | config_get_driver() | ||
251 | { | ||
252 | cat $DIR/config_test_driver | ||
253 | } | ||
254 | |||
255 | config_get_test_result() | ||
256 | { | ||
257 | cat $DIR/test_result | ||
258 | } | ||
259 | |||
260 | config_reset() | ||
261 | { | ||
262 | if ! echo -n "1" >"$DIR"/reset; then | ||
263 | echo "$0: reset shuld have worked" >&2 | ||
264 | exit 1 | ||
265 | fi | ||
266 | } | ||
267 | |||
268 | config_show_config() | ||
269 | { | ||
270 | echo "----------------------------------------------------" | ||
271 | cat "$DIR"/config | ||
272 | echo "----------------------------------------------------" | ||
273 | } | ||
274 | |||
275 | config_trigger() | ||
276 | { | ||
277 | if ! echo -n "1" >"$DIR"/trigger_config 2>/dev/null; then | ||
278 | echo "$1: FAIL - loading should have worked" | ||
279 | config_show_config | ||
280 | exit 1 | ||
281 | fi | ||
282 | echo "$1: OK! - loading kmod test" | ||
283 | } | ||
284 | |||
285 | config_trigger_want_fail() | ||
286 | { | ||
287 | if echo "1" > $DIR/trigger_config 2>/dev/null; then | ||
288 | echo "$1: FAIL - test case was expected to fail" | ||
289 | config_show_config | ||
290 | exit 1 | ||
291 | fi | ||
292 | echo "$1: OK! - kmod test case failed as expected" | ||
293 | } | ||
294 | |||
295 | config_expect_result() | ||
296 | { | ||
297 | RC=$(config_get_test_result) | ||
298 | RC_NAME=$(errno_val_to_name $RC) | ||
299 | |||
300 | ERRNO_NAME=$2 | ||
301 | ERRNO=$(errno_name_to_val $ERRNO_NAME) | ||
302 | |||
303 | if [[ $ERRNO_NAME = "-ERR_ANY" ]]; then | ||
304 | if [[ $RC -ge 0 ]]; then | ||
305 | echo "$1: FAIL, test expects $ERRNO_NAME - got $RC_NAME ($RC)" >&2 | ||
306 | config_show_config | ||
307 | exit 1 | ||
308 | fi | ||
309 | elif [[ $RC != $ERRNO ]]; then | ||
310 | echo "$1: FAIL, test expects $ERRNO_NAME ($ERRNO) - got $RC_NAME ($RC)" >&2 | ||
311 | config_show_config | ||
312 | exit 1 | ||
313 | fi | ||
314 | echo "$1: OK! - Return value: $RC ($RC_NAME), expected $ERRNO_NAME" | ||
315 | } | ||
316 | |||
317 | kmod_defaults_driver() | ||
318 | { | ||
319 | config_reset | ||
320 | modprobe -r $DEFAULT_KMOD_DRIVER | ||
321 | config_set_driver $DEFAULT_KMOD_DRIVER | ||
322 | } | ||
323 | |||
324 | kmod_defaults_fs() | ||
325 | { | ||
326 | config_reset | ||
327 | modprobe -r $DEFAULT_KMOD_FS | ||
328 | config_set_fs $DEFAULT_KMOD_FS | ||
329 | config_set_test_case_fs | ||
330 | } | ||
331 | |||
332 | kmod_test_0001_driver() | ||
333 | { | ||
334 | NAME='\000' | ||
335 | |||
336 | kmod_defaults_driver | ||
337 | config_num_threads 1 | ||
338 | printf '\000' >"$DIR"/config_test_driver | ||
339 | config_trigger ${FUNCNAME[0]} | ||
340 | config_expect_result ${FUNCNAME[0]} MODULE_NOT_FOUND | ||
341 | } | ||
342 | |||
343 | kmod_test_0001_fs() | ||
344 | { | ||
345 | NAME='\000' | ||
346 | |||
347 | kmod_defaults_fs | ||
348 | config_num_threads 1 | ||
349 | printf '\000' >"$DIR"/config_test_fs | ||
350 | config_trigger ${FUNCNAME[0]} | ||
351 | config_expect_result ${FUNCNAME[0]} -EINVAL | ||
352 | } | ||
353 | |||
354 | kmod_test_0001() | ||
355 | { | ||
356 | kmod_test_0001_driver | ||
357 | kmod_test_0001_fs | ||
358 | } | ||
359 | |||
360 | kmod_test_0002_driver() | ||
361 | { | ||
362 | NAME="nope-$DEFAULT_KMOD_DRIVER" | ||
363 | |||
364 | kmod_defaults_driver | ||
365 | config_set_driver $NAME | ||
366 | config_num_threads 1 | ||
367 | config_trigger ${FUNCNAME[0]} | ||
368 | config_expect_result ${FUNCNAME[0]} MODULE_NOT_FOUND | ||
369 | } | ||
370 | |||
371 | kmod_test_0002_fs() | ||
372 | { | ||
373 | NAME="nope-$DEFAULT_KMOD_FS" | ||
374 | |||
375 | kmod_defaults_fs | ||
376 | config_set_fs $NAME | ||
377 | config_trigger ${FUNCNAME[0]} | ||
378 | config_expect_result ${FUNCNAME[0]} -EINVAL | ||
379 | } | ||
380 | |||
381 | kmod_test_0002() | ||
382 | { | ||
383 | kmod_test_0002_driver | ||
384 | kmod_test_0002_fs | ||
385 | } | ||
386 | |||
387 | kmod_test_0003() | ||
388 | { | ||
389 | kmod_defaults_fs | ||
390 | config_num_threads 1 | ||
391 | config_trigger ${FUNCNAME[0]} | ||
392 | config_expect_result ${FUNCNAME[0]} SUCCESS | ||
393 | } | ||
394 | |||
395 | kmod_test_0004() | ||
396 | { | ||
397 | kmod_defaults_fs | ||
398 | config_num_threads 2 | ||
399 | config_trigger ${FUNCNAME[0]} | ||
400 | config_expect_result ${FUNCNAME[0]} SUCCESS | ||
401 | } | ||
402 | |||
403 | kmod_test_0005() | ||
404 | { | ||
405 | kmod_defaults_driver | ||
406 | config_trigger ${FUNCNAME[0]} | ||
407 | config_expect_result ${FUNCNAME[0]} SUCCESS | ||
408 | } | ||
409 | |||
410 | kmod_test_0006() | ||
411 | { | ||
412 | kmod_defaults_fs | ||
413 | config_trigger ${FUNCNAME[0]} | ||
414 | config_expect_result ${FUNCNAME[0]} SUCCESS | ||
415 | } | ||
416 | |||
417 | kmod_test_0007() | ||
418 | { | ||
419 | kmod_test_0005 | ||
420 | kmod_test_0006 | ||
421 | } | ||
422 | |||
423 | kmod_test_0008() | ||
424 | { | ||
425 | kmod_defaults_driver | ||
426 | MODPROBE_LIMIT=$(config_get_modprobe_limit) | ||
427 | let EXTRA=$MODPROBE_LIMIT/6 | ||
428 | config_num_thread_limit_extra $EXTRA | ||
429 | config_trigger ${FUNCNAME[0]} | ||
430 | config_expect_result ${FUNCNAME[0]} SUCCESS | ||
431 | } | ||
432 | |||
433 | kmod_test_0009() | ||
434 | { | ||
435 | kmod_defaults_fs | ||
436 | MODPROBE_LIMIT=$(config_get_modprobe_limit) | ||
437 | let EXTRA=$MODPROBE_LIMIT/4 | ||
438 | config_num_thread_limit_extra $EXTRA | ||
439 | config_trigger ${FUNCNAME[0]} | ||
440 | config_expect_result ${FUNCNAME[0]} SUCCESS | ||
441 | } | ||
442 | |||
443 | list_tests() | ||
444 | { | ||
445 | echo "Test ID list:" | ||
446 | echo | ||
447 | echo "TEST_ID x NUM_TEST" | ||
448 | echo "TEST_ID: Test ID" | ||
449 | echo "NUM_TESTS: Number of recommended times to run the test" | ||
450 | echo | ||
451 | echo "0001 x $(get_test_count 0001) - Simple test - 1 thread for empty string" | ||
452 | echo "0002 x $(get_test_count 0002) - Simple test - 1 thread for modules/filesystems that do not exist" | ||
453 | echo "0003 x $(get_test_count 0003) - Simple test - 1 thread for get_fs_type() only" | ||
454 | echo "0004 x $(get_test_count 0004) - Simple test - 2 threads for get_fs_type() only" | ||
455 | echo "0005 x $(get_test_count 0005) - multithreaded tests with default setup - request_module() only" | ||
456 | echo "0006 x $(get_test_count 0006) - multithreaded tests with default setup - get_fs_type() only" | ||
457 | echo "0007 x $(get_test_count 0007) - multithreaded tests with default setup test request_module() and get_fs_type()" | ||
458 | echo "0008 x $(get_test_count 0008) - multithreaded - push kmod_concurrent over max_modprobes for request_module()" | ||
459 | echo "0009 x $(get_test_count 0009) - multithreaded - push kmod_concurrent over max_modprobes for get_fs_type()" | ||
460 | } | ||
461 | |||
462 | usage() | ||
463 | { | ||
464 | NUM_TESTS=$(grep -o ' ' <<<"$ALL_TESTS" | grep -c .) | ||
465 | let NUM_TESTS=$NUM_TESTS+1 | ||
466 | MAX_TEST=$(printf "%04d\n" $NUM_TESTS) | ||
467 | echo "Usage: $0 [ -t <4-number-digit> ] | [ -w <4-number-digit> ] |" | ||
468 | echo " [ -s <4-number-digit> ] | [ -c <4-number-digit> <test- count>" | ||
469 | echo " [ all ] [ -h | --help ] [ -l ]" | ||
470 | echo "" | ||
471 | echo "Valid tests: 0001-$MAX_TEST" | ||
472 | echo "" | ||
473 | echo " all Runs all tests (default)" | ||
474 | echo " -t Run test ID the number amount of times is recommended" | ||
475 | echo " -w Watch test ID run until it runs into an error" | ||
476 | echo " -c Run test ID once" | ||
477 | echo " -s Run test ID x test-count number of times" | ||
478 | echo " -l List all test ID list" | ||
479 | echo " -h|--help Help" | ||
480 | echo | ||
481 | echo "If an error every occurs execution will immediately terminate." | ||
482 | echo "If you are adding a new test try using -w <test-ID> first to" | ||
483 | echo "make sure the test passes a series of tests." | ||
484 | echo | ||
485 | echo Example uses: | ||
486 | echo | ||
487 | echo "${TEST_NAME}.sh -- executes all tests" | ||
488 | echo "${TEST_NAME}.sh -t 0008 -- Executes test ID 0008 number of times is recomended" | ||
489 | echo "${TEST_NAME}.sh -w 0008 -- Watch test ID 0008 run until an error occurs" | ||
490 | echo "${TEST_NAME}.sh -s 0008 -- Run test ID 0008 once" | ||
491 | echo "${TEST_NAME}.sh -c 0008 3 -- Run test ID 0008 three times" | ||
492 | echo | ||
493 | list_tests | ||
494 | exit 1 | ||
495 | } | ||
496 | |||
497 | function test_num() | ||
498 | { | ||
499 | re='^[0-9]+$' | ||
500 | if ! [[ $1 =~ $re ]]; then | ||
501 | usage | ||
502 | fi | ||
503 | } | ||
504 | |||
505 | function get_test_count() | ||
506 | { | ||
507 | test_num $1 | ||
508 | TEST_DATA=$(echo $ALL_TESTS | awk '{print $'$1'}') | ||
509 | LAST_TWO=${TEST_DATA#*:*} | ||
510 | echo ${LAST_TWO%:*} | ||
511 | } | ||
512 | |||
513 | function get_test_enabled() | ||
514 | { | ||
515 | test_num $1 | ||
516 | TEST_DATA=$(echo $ALL_TESTS | awk '{print $'$1'}') | ||
517 | echo ${TEST_DATA#*:*:} | ||
518 | } | ||
519 | |||
520 | function run_all_tests() | ||
521 | { | ||
522 | for i in $ALL_TESTS ; do | ||
523 | TEST_ID=${i%:*:*} | ||
524 | ENABLED=$(get_test_enabled $TEST_ID) | ||
525 | TEST_COUNT=$(get_test_count $TEST_ID) | ||
526 | if [[ $ENABLED -eq "1" ]]; then | ||
527 | test_case $TEST_ID $TEST_COUNT | ||
528 | fi | ||
529 | done | ||
530 | } | ||
531 | |||
532 | function watch_log() | ||
533 | { | ||
534 | if [ $# -ne 3 ]; then | ||
535 | clear | ||
536 | fi | ||
537 | date | ||
538 | echo "Running test: $2 - run #$1" | ||
539 | } | ||
540 | |||
541 | function watch_case() | ||
542 | { | ||
543 | i=0 | ||
544 | while [ 1 ]; do | ||
545 | |||
546 | if [ $# -eq 1 ]; then | ||
547 | test_num $1 | ||
548 | watch_log $i ${TEST_NAME}_test_$1 | ||
549 | ${TEST_NAME}_test_$1 | ||
550 | else | ||
551 | watch_log $i all | ||
552 | run_all_tests | ||
553 | fi | ||
554 | let i=$i+1 | ||
555 | done | ||
556 | } | ||
557 | |||
558 | function test_case() | ||
559 | { | ||
560 | NUM_TESTS=$DEFAULT_NUM_TESTS | ||
561 | if [ $# -eq 2 ]; then | ||
562 | NUM_TESTS=$2 | ||
563 | fi | ||
564 | |||
565 | i=0 | ||
566 | while [ $i -lt $NUM_TESTS ]; do | ||
567 | test_num $1 | ||
568 | watch_log $i ${TEST_NAME}_test_$1 noclear | ||
569 | RUN_TEST=${TEST_NAME}_test_$1 | ||
570 | $RUN_TEST | ||
571 | let i=$i+1 | ||
572 | done | ||
573 | } | ||
574 | |||
575 | function parse_args() | ||
576 | { | ||
577 | if [ $# -eq 0 ]; then | ||
578 | run_all_tests | ||
579 | else | ||
580 | if [[ "$1" = "all" ]]; then | ||
581 | run_all_tests | ||
582 | elif [[ "$1" = "-w" ]]; then | ||
583 | shift | ||
584 | watch_case $@ | ||
585 | elif [[ "$1" = "-t" ]]; then | ||
586 | shift | ||
587 | test_num $1 | ||
588 | test_case $1 $(get_test_count $1) | ||
589 | elif [[ "$1" = "-c" ]]; then | ||
590 | shift | ||
591 | test_num $1 | ||
592 | test_num $2 | ||
593 | test_case $1 $2 | ||
594 | elif [[ "$1" = "-s" ]]; then | ||
595 | shift | ||
596 | test_case $1 1 | ||
597 | elif [[ "$1" = "-l" ]]; then | ||
598 | list_tests | ||
599 | elif [[ "$1" = "-h" || "$1" = "--help" ]]; then | ||
600 | usage | ||
601 | else | ||
602 | usage | ||
603 | fi | ||
604 | fi | ||
605 | } | ||
606 | |||
607 | test_reqs | ||
608 | allow_user_defaults | ||
609 | load_req_mod | ||
610 | |||
611 | trap "test_finish" EXIT | ||
612 | |||
613 | parse_args $@ | ||
614 | |||
615 | exit 0 | ||