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

sysfs: crash debugging

Print the name of the last-accessed sysfs file when we oops, to help track
down oopses which occur in sysfs store/read handlers. Because these oopses
tend to not leave any trace of the offending code in the stack traces.

Cc: Kay Sievers <kay.sievers@vrfy.org>
Cc: Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

authored by

Andrew Morton and committed by
Greg Kroah-Hartman
ae87221d e9432093

+23
+2
arch/x86/kernel/dumpstack_32.c
··· 13 13 #include <linux/kexec.h> 14 14 #include <linux/bug.h> 15 15 #include <linux/nmi.h> 16 + #include <linux/sysfs.h> 16 17 17 18 #include <asm/stacktrace.h> 18 19 ··· 344 343 printk("DEBUG_PAGEALLOC"); 345 344 #endif 346 345 printk("\n"); 346 + sysfs_printk_last_file(); 347 347 if (notify_die(DIE_OOPS, str, regs, err, 348 348 current->thread.trap_no, SIGSEGV) == NOTIFY_STOP) 349 349 return 1;
+2
arch/x86/kernel/dumpstack_64.c
··· 13 13 #include <linux/kexec.h> 14 14 #include <linux/bug.h> 15 15 #include <linux/nmi.h> 16 + #include <linux/sysfs.h> 16 17 17 18 #include <asm/stacktrace.h> 18 19 ··· 490 489 printk("DEBUG_PAGEALLOC"); 491 490 #endif 492 491 printk("\n"); 492 + sysfs_printk_last_file(); 493 493 if (notify_die(DIE_OOPS, str, regs, err, 494 494 current->thread.trap_no, SIGSEGV) == NOTIFY_STOP) 495 495 return 1;
+13
fs/sysfs/file.c
··· 19 19 #include <linux/poll.h> 20 20 #include <linux/list.h> 21 21 #include <linux/mutex.h> 22 + #include <linux/limits.h> 22 23 #include <asm/uaccess.h> 23 24 24 25 #include "sysfs.h" 26 + 27 + /* used in crash dumps to help with debugging */ 28 + static char last_sysfs_file[PATH_MAX]; 29 + void sysfs_printk_last_file(void) 30 + { 31 + printk(KERN_EMERG "last sysfs file: %s\n", last_sysfs_file); 32 + } 25 33 26 34 /* 27 35 * There's one sysfs_buffer for each open file and one ··· 336 328 struct sysfs_buffer *buffer; 337 329 struct sysfs_ops *ops; 338 330 int error = -EACCES; 331 + char *p; 332 + 333 + p = d_path(&file->f_path, last_sysfs_file, sizeof(last_sysfs_file)); 334 + if (p) 335 + memmove(last_sysfs_file, p, strlen(p) + 1); 339 336 340 337 /* need attr_sd for attr and ops, its parent for kobj */ 341 338 if (!sysfs_get_active_two(attr_sd))
+6
include/linux/sysfs.h
··· 119 119 120 120 void sysfs_notify(struct kobject *kobj, char *dir, char *attr); 121 121 122 + void sysfs_printk_last_file(void); 123 + 122 124 extern int __must_check sysfs_init(void); 123 125 124 126 #else /* CONFIG_SYSFS */ ··· 231 229 static inline int __must_check sysfs_init(void) 232 230 { 233 231 return 0; 232 + } 233 + 234 + static inline void sysfs_printk_last_file(void) 235 + { 234 236 } 235 237 236 238 #endif /* CONFIG_SYSFS */