1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * hung_task_tests.c - Sample code for testing hung tasks with mutex,
4  * semaphore, etc.
5  *
6  * Usage: Load this module and read `<debugfs>/hung_task/mutex`,
7  *        `<debugfs>/hung_task/semaphore`, etc., with 2 or more processes.
8  *
9  * This is for testing kernel hung_task error messages with various locking
10  * mechanisms (e.g., mutex, semaphore, etc.). Note that this may freeze
11  * your system or cause a panic. Use only for testing purposes.
12  */
13 
14 #include <linux/debugfs.h>
15 #include <linux/delay.h>
16 #include <linux/fs.h>
17 #include <linux/module.h>
18 #include <linux/mutex.h>
19 #include <linux/semaphore.h>
20 
21 #define HUNG_TASK_DIR		"hung_task"
22 #define HUNG_TASK_MUTEX_FILE	"mutex"
23 #define HUNG_TASK_SEM_FILE	"semaphore"
24 #define SLEEP_SECOND		256
25 
26 static const char dummy_string[] = "This is a dummy string.";
27 static DEFINE_MUTEX(dummy_mutex);
28 static DEFINE_SEMAPHORE(dummy_sem, 1);
29 static struct dentry *hung_task_dir;
30 
31 /* Mutex-based read function */
32 static ssize_t read_dummy_mutex(struct file *file, char __user *user_buf,
33 				size_t count, loff_t *ppos)
34 {
35 	/* Second task waits on mutex, entering uninterruptible sleep */
36 	guard(mutex)(&dummy_mutex);
37 
38 	/* First task sleeps here, interruptible */
39 	msleep_interruptible(SLEEP_SECOND * 1000);
40 
41 	return simple_read_from_buffer(user_buf, count, ppos, dummy_string,
42 				       sizeof(dummy_string));
43 }
44 
45 /* Semaphore-based read function */
46 static ssize_t read_dummy_semaphore(struct file *file, char __user *user_buf,
47 				    size_t count, loff_t *ppos)
48 {
49 	/* Second task waits on semaphore, entering uninterruptible sleep */
50 	down(&dummy_sem);
51 
52 	/* First task sleeps here, interruptible */
53 	msleep_interruptible(SLEEP_SECOND * 1000);
54 
55 	up(&dummy_sem);
56 
57 	return simple_read_from_buffer(user_buf, count, ppos, dummy_string,
58 				       sizeof(dummy_string));
59 }
60 
61 /* File operations for mutex */
62 static const struct file_operations hung_task_mutex_fops = {
63 	.read = read_dummy_mutex,
64 };
65 
66 /* File operations for semaphore */
67 static const struct file_operations hung_task_sem_fops = {
68 	.read = read_dummy_semaphore,
69 };
70 
71 static int __init hung_task_tests_init(void)
72 {
73 	hung_task_dir = debugfs_create_dir(HUNG_TASK_DIR, NULL);
74 	if (IS_ERR(hung_task_dir))
75 		return PTR_ERR(hung_task_dir);
76 
77 	/* Create debugfs files for mutex and semaphore tests */
78 	debugfs_create_file(HUNG_TASK_MUTEX_FILE, 0400, hung_task_dir, NULL,
79 			    &hung_task_mutex_fops);
80 	debugfs_create_file(HUNG_TASK_SEM_FILE, 0400, hung_task_dir, NULL,
81 			    &hung_task_sem_fops);
82 
83 	return 0;
84 }
85 
86 static void __exit hung_task_tests_exit(void)
87 {
88 	debugfs_remove_recursive(hung_task_dir);
89 }
90 
91 module_init(hung_task_tests_init);
92 module_exit(hung_task_tests_exit);
93 
94 MODULE_LICENSE("GPL");
95 MODULE_AUTHOR("Masami Hiramatsu <mhiramat@kernel.org>");
96 MODULE_AUTHOR("Zi Li <amaindex@outlook.com>");
97 MODULE_DESCRIPTION("Simple sleep under lock files for testing hung task");
98