aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/um/Kconfig.debug9
-rw-r--r--arch/um/defconfig1
-rw-r--r--include/asm-um/thread_info.h9
-rw-r--r--kernel/exit.c29
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
50config 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.
50endmenu 59endmenu
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
862static 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
886static inline void check_stack_usage(void) {}
887#endif
888
861fastcall NORET_TYPE void do_exit(long code) 889fastcall 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);