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 If you're involved in UML kernel development and want to use gcov, say Y. If you're unsure, say N. +config DEBUG_STACK_USAGE + bool "Stack utilization instrumentation" + default N + help + Track the maximum kernel stack usage - this will look at each + kernel stack at process exit and log it if it's the deepest + stack seen so far. + + This option will slow down process creation and destruction somewhat. 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 # CONFIG_RCU_TORTURE_TEST is not set # CONFIG_GPROF is not set # CONFIG_GCOV is not set +# 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) return ti; } +#ifdef CONFIG_DEBUG_STACK_USAGE + +#define alloc_thread_info(tsk) \ + ((struct thread_info *) __get_free_pages(GFP_KERNEL | __GFP_ZERO, \ + CONFIG_KERNEL_STACK_ORDER)) +#else + /* thread information allocation */ #define alloc_thread_info(tsk) \ ((struct thread_info *) __get_free_pages(GFP_KERNEL, \ CONFIG_KERNEL_STACK_ORDER)) +#endif + #define free_thread_info(ti) \ free_pages((unsigned long)(ti),CONFIG_KERNEL_STACK_ORDER) 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) release_task(tsk); } +#ifdef CONFIG_DEBUG_STACK_USAGE +static void check_stack_usage(void) +{ + static DEFINE_SPINLOCK(low_water_lock); + static int lowest_to_date = THREAD_SIZE; + unsigned long *n = end_of_stack(current); + unsigned long free; + + while (*n == 0) + n++; + free = (unsigned long)n - (unsigned long)end_of_stack(current); + + if (free >= lowest_to_date) + return; + + spin_lock(&low_water_lock); + if (free < lowest_to_date) { + printk(KERN_WARNING "%s used greatest stack depth: %lu bytes " + "left\n", + current->comm, free); + lowest_to_date = free; + } + spin_unlock(&low_water_lock); +} +#else +static inline void check_stack_usage(void) {} +#endif + fastcall NORET_TYPE void do_exit(long code) { struct task_struct *tsk = current; @@ -949,6 +977,7 @@ fastcall NORET_TYPE void do_exit(long code) exit_sem(tsk); __exit_files(tsk); __exit_fs(tsk); + check_stack_usage(); exit_thread(); cpuset_exit(tsk); exit_keys(tsk); |