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

samples: enhance hung_task detector test with read-write semaphore support

Extend the hung_task detector test module to include read-write semaphore
support alongside existing mutex and semaphore tests. This module now
creates additional debugfs files under <debugfs>/hung_task, namely
'rw_semaphore_read' and 'rw_semaphore_write', in addition to 'mutex' and
'semaphore'. Reading these files with multiple processes triggers a
prolonged sleep (256 seconds) while holding the respective lock, enabling
hung_task detector testing for various locking mechanisms.

This change builds on the extensible hung_task_tests module, adding
read-write semaphore functionality to improve test coverage for kernel
locking primitives. The implementation ensures proper lock handling and
includes checks to prevent redundant data reads.

Usage is:

> cd /sys/kernel/debug/hung_task
> cat mutex & cat mutex # Test mutex blocking
> cat semaphore & cat semaphore # Test semaphore blocking
> cat rw_semaphore_write \
& cat rw_semaphore_read # Test rwsem blocking
> cat rw_semaphore_write \
& cat rw_semaphore_write # Test rwsem blocking

Update the Kconfig description to reflect the addition of read-write
semaphore debugfs files.

Link: https://lkml.kernel.org/r/20250627072924.36567-4-lance.yang@linux.dev
Signed-off-by: Zi Li <zi.li@linux.dev>
Suggested-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
Cc: Anna Schumaker <anna.schumaker@oracle.com>
Cc: Boqun Feng <boqun.feng@gmail.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Joel Granados <joel.granados@kernel.org>
Cc: John Stultz <jstultz@google.com>
Cc: Kent Overstreet <kent.overstreet@linux.dev>
Cc: Mingzhe Yang <mingzhe.yang@ly.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Sergey Senozhatsky <senozhatsky@chromium.org>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Tomasz Figa <tfiga@chromium.org>
Cc: Waiman Long <longman@redhat.com>
Cc: Will Deacon <will@kernel.org>
Cc: Yongliang Gao <leonylgao@tencent.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

authored by

Zi Li and committed by
Andrew Morton
4efec6c0 77da18de

+77 -11
+3 -4
samples/Kconfig
··· 316 316 depends on DETECT_HUNG_TASK && DEBUG_FS 317 317 help 318 318 Build a module that provides debugfs files (e.g., mutex, semaphore, 319 - etc.) under <debugfs>/hung_task. If user reads one of these files, 320 - it will sleep long time (256 seconds) with holding a lock. Thus, 321 - if 2 or more processes read the same file concurrently, it will 322 - be detected by the hung_task watchdog. 319 + rw_semaphore_read, rw_semaphore_write) under <debugfs>/hung_task. 320 + Reading these files with multiple processes triggers hung task 321 + detection by holding locks for a long time (256 seconds). 323 322 324 323 source "samples/rust/Kconfig" 325 324
+74 -7
samples/hung_task/hung_task_tests.c
··· 4 4 * semaphore, etc. 5 5 * 6 6 * Usage: Load this module and read `<debugfs>/hung_task/mutex`, 7 - * `<debugfs>/hung_task/semaphore`, etc., with 2 or more processes. 7 + * `<debugfs>/hung_task/semaphore`, `<debugfs>/hung_task/rw_semaphore_read`, 8 + * `<debugfs>/hung_task/rw_semaphore_write`, etc., with 2 or more processes. 8 9 * 9 10 * 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. 11 + * mechanisms (e.g., mutex, semaphore, rw_semaphore_read, rw_semaphore_write, etc.). 12 + * Note that this may freeze your system or cause a panic. Use only for testing purposes. 12 13 */ 13 14 14 15 #include <linux/debugfs.h> ··· 18 17 #include <linux/module.h> 19 18 #include <linux/mutex.h> 20 19 #include <linux/semaphore.h> 20 + #include <linux/rwsem.h> 21 21 22 - #define HUNG_TASK_DIR "hung_task" 23 - #define HUNG_TASK_MUTEX_FILE "mutex" 24 - #define HUNG_TASK_SEM_FILE "semaphore" 25 - #define SLEEP_SECOND 256 22 + #define HUNG_TASK_DIR "hung_task" 23 + #define HUNG_TASK_MUTEX_FILE "mutex" 24 + #define HUNG_TASK_SEM_FILE "semaphore" 25 + #define HUNG_TASK_RWSEM_READ_FILE "rw_semaphore_read" 26 + #define HUNG_TASK_RWSEM_WRITE_FILE "rw_semaphore_write" 27 + #define SLEEP_SECOND 256 26 28 27 29 static const char dummy_string[] = "This is a dummy string."; 28 30 static DEFINE_MUTEX(dummy_mutex); 29 31 static DEFINE_SEMAPHORE(dummy_sem, 1); 32 + static DECLARE_RWSEM(dummy_rwsem); 30 33 static struct dentry *hung_task_dir; 31 34 32 35 /* Mutex-based read function */ 33 36 static ssize_t read_dummy_mutex(struct file *file, char __user *user_buf, 34 37 size_t count, loff_t *ppos) 35 38 { 39 + /* Check if data is already read */ 40 + if (*ppos >= sizeof(dummy_string)) 41 + return 0; 42 + 36 43 /* Second task waits on mutex, entering uninterruptible sleep */ 37 44 guard(mutex)(&dummy_mutex); 38 45 ··· 55 46 static ssize_t read_dummy_semaphore(struct file *file, char __user *user_buf, 56 47 size_t count, loff_t *ppos) 57 48 { 49 + /* Check if data is already read */ 50 + if (*ppos >= sizeof(dummy_string)) 51 + return 0; 52 + 58 53 /* Second task waits on semaphore, entering uninterruptible sleep */ 59 54 down(&dummy_sem); 60 55 ··· 66 53 msleep_interruptible(SLEEP_SECOND * 1000); 67 54 68 55 up(&dummy_sem); 56 + 57 + return simple_read_from_buffer(user_buf, count, ppos, dummy_string, 58 + sizeof(dummy_string)); 59 + } 60 + 61 + /* Read-write semaphore read function */ 62 + static ssize_t read_dummy_rwsem_read(struct file *file, char __user *user_buf, 63 + size_t count, loff_t *ppos) 64 + { 65 + /* Check if data is already read */ 66 + if (*ppos >= sizeof(dummy_string)) 67 + return 0; 68 + 69 + /* Acquires read lock, allowing concurrent readers but blocks if write lock is held */ 70 + down_read(&dummy_rwsem); 71 + 72 + /* Sleeps here, potentially triggering hung task detection if lock is held too long */ 73 + msleep_interruptible(SLEEP_SECOND * 1000); 74 + 75 + up_read(&dummy_rwsem); 76 + 77 + return simple_read_from_buffer(user_buf, count, ppos, dummy_string, 78 + sizeof(dummy_string)); 79 + } 80 + 81 + /* Read-write semaphore write function */ 82 + static ssize_t read_dummy_rwsem_write(struct file *file, char __user *user_buf, 83 + size_t count, loff_t *ppos) 84 + { 85 + /* Check if data is already read */ 86 + if (*ppos >= sizeof(dummy_string)) 87 + return 0; 88 + 89 + /* Acquires exclusive write lock, blocking all other readers and writers */ 90 + down_write(&dummy_rwsem); 91 + 92 + /* Sleeps here, potentially triggering hung task detection if lock is held too long */ 93 + msleep_interruptible(SLEEP_SECOND * 1000); 94 + 95 + up_write(&dummy_rwsem); 69 96 70 97 return simple_read_from_buffer(user_buf, count, ppos, dummy_string, 71 98 sizeof(dummy_string)); ··· 121 68 .read = read_dummy_semaphore, 122 69 }; 123 70 71 + /* File operations for rw_semaphore read */ 72 + static const struct file_operations hung_task_rwsem_read_fops = { 73 + .read = read_dummy_rwsem_read, 74 + }; 75 + 76 + /* File operations for rw_semaphore write */ 77 + static const struct file_operations hung_task_rwsem_write_fops = { 78 + .read = read_dummy_rwsem_write, 79 + }; 80 + 124 81 static int __init hung_task_tests_init(void) 125 82 { 126 83 hung_task_dir = debugfs_create_dir(HUNG_TASK_DIR, NULL); ··· 142 79 &hung_task_mutex_fops); 143 80 debugfs_create_file(HUNG_TASK_SEM_FILE, 0400, hung_task_dir, NULL, 144 81 &hung_task_sem_fops); 82 + debugfs_create_file(HUNG_TASK_RWSEM_READ_FILE, 0400, hung_task_dir, NULL, 83 + &hung_task_rwsem_read_fops); 84 + debugfs_create_file(HUNG_TASK_RWSEM_WRITE_FILE, 0400, hung_task_dir, NULL, 85 + &hung_task_rwsem_write_fops); 145 86 146 87 return 0; 147 88 }