diff options
-rw-r--r-- | arch/um/Kconfig.debug | 9 | ||||
-rw-r--r-- | arch/um/defconfig | 1 | ||||
-rw-r--r-- | include/asm-um/thread_info.h | 9 | ||||
-rw-r--r-- | kernel/exit.c | 29 |
4 files changed, 48 insertions, 0 deletions
diff --git a/arch/um/Kconfig.debug b/arch/um/Kconfig.debug index 09c1aca6339f..c86f5eb29fd5 100644 --- a/arch/um/Kconfig.debug +++ b/arch/um/Kconfig.debug | |||
@@ -47,4 +47,13 @@ config GCOV | |||
47 | If you're involved in UML kernel development and want to use gcov, | 47 | If you're involved in UML kernel development and want to use gcov, |
48 | say Y. If you're unsure, say N. | 48 | say Y. If you're unsure, say N. |
49 | 49 | ||
50 | config DEBUG_STACK_USAGE | ||
51 | bool "Stack utilization instrumentation" | ||
52 | default N | ||
53 | help | ||
54 | Track the maximum kernel stack usage - this will look at each | ||
55 | kernel stack at process exit and log it if it's the deepest | ||
56 | stack seen so far. | ||
57 | |||
58 | This option will slow down process creation and destruction somewhat. | ||
50 | endmenu | 59 | endmenu |
diff --git a/arch/um/defconfig b/arch/um/defconfig index a54d0efecae1..e5b2df9e12de 100644 --- a/arch/um/defconfig +++ b/arch/um/defconfig | |||
@@ -527,3 +527,4 @@ CONFIG_FORCED_INLINING=y | |||
527 | # CONFIG_RCU_TORTURE_TEST is not set | 527 | # CONFIG_RCU_TORTURE_TEST is not set |
528 | # CONFIG_GPROF is not set | 528 | # CONFIG_GPROF is not set |
529 | # CONFIG_GCOV is not set | 529 | # CONFIG_GCOV is not set |
530 | # CONFIG_DEBUG_STACK_USAGE is not set | ||
diff --git a/include/asm-um/thread_info.h b/include/asm-um/thread_info.h index 07aa4e50e4d0..6e5fd5c892d0 100644 --- a/include/asm-um/thread_info.h +++ b/include/asm-um/thread_info.h | |||
@@ -52,10 +52,19 @@ static inline struct thread_info *current_thread_info(void) | |||
52 | return ti; | 52 | return ti; |
53 | } | 53 | } |
54 | 54 | ||
55 | #ifdef CONFIG_DEBUG_STACK_USAGE | ||
56 | |||
57 | #define alloc_thread_info(tsk) \ | ||
58 | ((struct thread_info *) __get_free_pages(GFP_KERNEL | __GFP_ZERO, \ | ||
59 | CONFIG_KERNEL_STACK_ORDER)) | ||
60 | #else | ||
61 | |||
55 | /* thread information allocation */ | 62 | /* thread information allocation */ |
56 | #define alloc_thread_info(tsk) \ | 63 | #define alloc_thread_info(tsk) \ |
57 | ((struct thread_info *) __get_free_pages(GFP_KERNEL, \ | 64 | ((struct thread_info *) __get_free_pages(GFP_KERNEL, \ |
58 | CONFIG_KERNEL_STACK_ORDER)) | 65 | CONFIG_KERNEL_STACK_ORDER)) |
66 | #endif | ||
67 | |||
59 | #define free_thread_info(ti) \ | 68 | #define free_thread_info(ti) \ |
60 | free_pages((unsigned long)(ti),CONFIG_KERNEL_STACK_ORDER) | 69 | free_pages((unsigned long)(ti),CONFIG_KERNEL_STACK_ORDER) |
61 | 70 | ||
diff --git a/kernel/exit.c b/kernel/exit.c index ca6a11b73023..64a5263c8c7b 100644 --- a/kernel/exit.c +++ b/kernel/exit.c | |||
@@ -858,6 +858,34 @@ static void exit_notify(struct task_struct *tsk) | |||
858 | release_task(tsk); | 858 | release_task(tsk); |
859 | } | 859 | } |
860 | 860 | ||
861 | #ifdef CONFIG_DEBUG_STACK_USAGE | ||
862 | static void check_stack_usage(void) | ||
863 | { | ||
864 | static DEFINE_SPINLOCK(low_water_lock); | ||
865 | static int lowest_to_date = THREAD_SIZE; | ||
866 | unsigned long *n = end_of_stack(current); | ||
867 | unsigned long free; | ||
868 | |||
869 | while (*n == 0) | ||
870 | n++; | ||
871 | free = (unsigned long)n - (unsigned long)end_of_stack(current); | ||
872 | |||
873 | if (free >= lowest_to_date) | ||
874 | return; | ||
875 | |||
876 | spin_lock(&low_water_lock); | ||
877 | if (free < lowest_to_date) { | ||
878 | printk(KERN_WARNING "%s used greatest stack depth: %lu bytes " | ||
879 | "left\n", | ||
880 | current->comm, free); | ||
881 | lowest_to_date = free; | ||
882 | } | ||
883 | spin_unlock(&low_water_lock); | ||
884 | } | ||
885 | #else | ||
886 | static inline void check_stack_usage(void) {} | ||
887 | #endif | ||
888 | |||
861 | fastcall NORET_TYPE void do_exit(long code) | 889 | fastcall NORET_TYPE void do_exit(long code) |
862 | { | 890 | { |
863 | struct task_struct *tsk = current; | 891 | struct task_struct *tsk = current; |
@@ -949,6 +977,7 @@ fastcall NORET_TYPE void do_exit(long code) | |||
949 | exit_sem(tsk); | 977 | exit_sem(tsk); |
950 | __exit_files(tsk); | 978 | __exit_files(tsk); |
951 | __exit_fs(tsk); | 979 | __exit_fs(tsk); |
980 | check_stack_usage(); | ||
952 | exit_thread(); | 981 | exit_thread(); |
953 | cpuset_exit(tsk); | 982 | cpuset_exit(tsk); |
954 | exit_keys(tsk); | 983 | exit_keys(tsk); |