Whamcloud - gitweb
b=20595
[fs/lustre-release.git] / lustre / kernel_patches / patches / proc-sleep-2.6.16-sles10.patch
1
2 export blocking statistics in /proc/<pid>/task<tid>/sleep. Statistics
3 collection for given file is activated on the first read of
4 /proc/pid/sleep. When statistics collection is on on each context switch
5 current back-trace is built (through __builtin_return_address()). For each
6 monitored process there is a LRU list of such back-traces. Useful when trying
7 to understand where elapsed time is spent.
8
9 Signed-off-by: Nikita Danilov <nikita@clusterfs.com>
10
11
12  arch/i386/Kconfig.debug    |    9 +
13  arch/i386/kernel/entry.S   |    4 
14  arch/i386/kernel/process.c |   52 +++++
15  arch/i386/mm/fault.c       |    7 
16  fs/proc/base.c             |   15 +
17  fs/proc/proc_misc.c        |    7 
18  include/linux/sched.h      |    9 -
19  include/linux/sleep_info.h |   48 +++++
20  kernel/Makefile            |    1 
21  kernel/exit.c              |   10 -
22  kernel/fork.c              |   17 +
23  kernel/sched.c             |    4 
24  kernel/sleep_info.c        |  392 +++++++++++++++++++++++++++++++++++++++++++++
25  13 files changed, 560 insertions(+), 15 deletions(-)
26
27 Index: linux-2.6.16.60-0.37/Makefile
28 ===================================================================
29 --- linux-2.6.16.60-0.37.orig/Makefile  2009-03-24 05:46:28.000000000 -0700
30 +++ linux-2.6.16.60-0.37/Makefile       2009-06-02 23:34:02.000000000 -0600
31 @@ -493,6 +493,10 @@
32  CFLAGS         += -fomit-frame-pointer
33  endif
34  
35 +ifdef CONFIG_FRAME_POINTER_FORCE
36 +CFLAGS         += -fno-omit-frame-pointer
37 +endif
38 +
39  ifdef CONFIG_DEBUG_INFO
40  CFLAGS         += -g
41  endif
42 Index: linux-2.6.16.60-0.37/arch/i386/Kconfig.debug
43 ===================================================================
44 --- linux-2.6.16.60-0.37.orig/arch/i386/Kconfig.debug   2009-03-24 05:46:35.000000000 -0700
45 +++ linux-2.6.16.60-0.37/arch/i386/Kconfig.debug        2009-06-02 23:34:02.000000000 -0600
46 @@ -190,4 +190,13 @@
47           say N then kdb can only be used from a PC (AT) keyboard or a serial
48           console.
49  
50 +config PROC_SLEEP
51 +       bool "Export sleep statistics"
52 +       depends on DEBUG_KERNEL && FRAME_POINTER
53 +    default n
54 +    help
55 +      If you say Y here, new file /proc/pid/stack will appear that contains
56 +      call-traces where given process blocked most of the time. If unsure say
57 +      N.
58 +
59  endmenu
60 Index: linux-2.6.16.60-0.37/arch/x86_64/Kconfig.debug
61 ===================================================================
62 --- linux-2.6.16.60-0.37.orig/arch/x86_64/Kconfig.debug 2009-03-24 05:46:35.000000000 -0700
63 +++ linux-2.6.16.60-0.37/arch/x86_64/Kconfig.debug      2009-06-02 23:34:02.000000000 -0600
64 @@ -123,6 +123,21 @@
65           If you are not sure, say 0.  Read Documentation/kdb/dump.txt before
66           setting to 2.
67  
68 +config FRAME_POINTER
69 +       bool "Compile the kernel with frame pointers"
70 +       help
71 +        Compile the kernel with frame pointers. This may help for some
72 +        debugging with external debuggers. Note the standard oops backtracer
73 +        doesn't make use of this and the x86-64 kernel doesn't ensure a
74 +        consistent frame pointer through inline assembly (semaphores etc.)
75 +        Normally you should say N.
76 +
77 +config FRAME_POINTER_FORCE
78 +       bool "Compile the kernel with frame pointers"
79 +       depends on FRAME_POINTER
80 +       help
81 +        Enforce passing -fno-omit-frame-pointer to the compiler.
82 +
83  config IOMMU_DEBUG
84         depends on GART_IOMMU && DEBUG_KERNEL
85         bool "Enable IOMMU debugging"
86 @@ -149,4 +164,13 @@
87  #config X86_REMOTE_DEBUG
88  #       bool "kgdb debugging stub"
89  
90 +config PROC_SLEEP
91 +       bool "Export sleep statistics"
92 +       depends on DEBUG_KERNEL && FRAME_POINTER && FRAME_POINTER_FORCE
93 +    default n
94 +    help
95 +      If you say Y here, new file /proc/pid/stack will appear that contains
96 +      call-traces where given process blocked most of the time. If unsure say
97 +      N.
98 +
99  endmenu
100 Index: linux-2.6.16.60-0.37/fs/proc/base.c
101 ===================================================================
102 --- linux-2.6.16.60-0.37.orig/fs/proc/base.c    2009-03-24 05:46:34.000000000 -0700
103 +++ linux-2.6.16.60-0.37/fs/proc/base.c 2009-06-02 23:34:02.000000000 -0600
104 @@ -167,7 +167,9 @@
105  #endif
106         PROC_TID_OOM_SCORE,
107         PROC_TID_OOM_ADJUST,
108 -
109 +#ifdef CONFIG_PROC_SLEEP
110 +       PROC_TID_SLEEP,
111 +#endif
112         /* Add new entries before this */
113         PROC_TID_FD_DIR = 0x8000,       /* 0x8000-0xffff */
114  };
115 @@ -267,6 +269,9 @@
116  #ifdef CONFIG_AUDITSYSCALL
117         E(PROC_TID_LOGINUID, "loginuid", S_IFREG|S_IWUSR|S_IRUGO),
118  #endif
119 +#ifdef CONFIG_PROC_SLEEP
120 +       E(PROC_TID_SLEEP,      "sleep",   S_IFREG|S_IRUGO),
121 +#endif
122         {0,0,NULL,0}
123  };
124  
125 @@ -1546,6 +1551,10 @@
126         return ~0U;
127  }
128  
129 +#ifdef CONFIG_PROC_SLEEP
130 +extern struct file_operations proc_sleep_operations;
131 +#endif
132 +
133  /* SMP-safe */
134  static struct dentry *proc_lookupfd(struct inode * dir, struct dentry * dentry, struct nameidata *nd)
135  {
136 @@ -1885,6 +1894,11 @@
137                         inode->i_fop = &proc_loginuid_operations;
138                         break;
139  #endif
140 +#ifdef CONFIG_PROC_SLEEP
141 +               case PROC_TID_SLEEP:
142 +                       inode->i_fop = &proc_sleep_operations;
143 +                       break;
144 +#endif
145                 default:
146                         printk("procfs: impossible type (%d)",p->type);
147                         iput(inode);
148 Index: linux-2.6.16.60-0.37/fs/proc/proc_misc.c
149 ===================================================================
150 --- linux-2.6.16.60-0.37.orig/fs/proc/proc_misc.c       2009-03-24 05:46:28.000000000 -0700
151 +++ linux-2.6.16.60-0.37/fs/proc/proc_misc.c    2009-06-02 23:34:02.000000000 -0600
152 @@ -414,6 +414,11 @@
153         .release        = seq_release,
154  };
155  
156 +#ifdef CONFIG_PROC_SLEEP
157 +extern struct file_operations proc_global_sleep_operations;
158 +extern struct file_operations proc_global_stack_operations;
159 +#endif
160 +
161  extern struct seq_operations vmstat_op;
162  static int vmstat_open(struct inode *inode, struct file *file)
163  {
164 @@ -784,4 +789,8 @@
165         if (entry)
166                 entry->proc_fops = &proc_sysrq_trigger_operations;
167  #endif
168 +#ifdef CONFIG_PROC_SLEEP
169 +       create_seq_entry("sleep", 0, &proc_global_sleep_operations);
170 +       create_seq_entry("stacktrace", 0, &proc_global_stack_operations);
171 +#endif
172  }
173 Index: linux-2.6.16.60-0.37/include/linux/sched.h
174 ===================================================================
175 --- linux-2.6.16.60-0.37.orig/include/linux/sched.h     2009-03-24 05:46:36.000000000 -0700
176 +++ linux-2.6.16.60-0.37/include/linux/sched.h  2009-06-02 23:34:02.000000000 -0600
177 @@ -35,6 +35,7 @@
178  #include <linux/topology.h>
179  #include <linux/seccomp.h>
180  #include <linux/rcupdate.h>
181 +#include <linux/sleep_info.h>
182  
183  
184  struct exec_domain;
185 @@ -700,6 +701,8 @@
186         unsigned long ttwu_move_affine;
187         unsigned long ttwu_move_balance;
188  #endif
189 +       /* where this task blocked */
190 +       struct sleep_info sinfo;
191  };
192  
193  extern void partition_sched_domains(cpumask_t *partition1,
194 Index: linux-2.6.16.60-0.37/include/linux/sleep_info.h
195 ===================================================================
196 --- linux-2.6.16.60-0.37.orig/include/linux/sleep_info.h        2009-05-19 04:30:11.057558880 -0600
197 +++ linux-2.6.16.60-0.37/include/linux/sleep_info.h     2009-06-02 23:34:02.000000000 -0600
198 @@ -0,0 +1,50 @@
199 +#ifndef _LINUX_SLEEP_INFO_H
200 +#define _LINUX_SLEEP_INFO_H
201 +
202 +#ifdef __KERNEL__
203 +
204 +#include <linux/config.h>
205 +#include <linux/list.h>
206 +#include <linux/stddef.h>
207 +#include <linux/spinlock.h>
208 +
209 +#ifdef CONFIG_PROC_SLEEP
210 +
211 +struct __sleep_info;
212 +struct task_struct;
213 +
214 +struct sleep_info {
215 +       struct __sleep_info *p;
216 +       unsigned long long last_in;
217 +};
218 +
219 +void init_sleep_info(struct task_struct *tsk);
220 +void free_sleep_info(struct sleep_info *sinfo);
221 +
222 +void sleep_in_hook(struct task_struct *tsk);
223 +void sleep_ex_hook(struct task_struct *tsk);
224 +
225 +void stacktrace_record(void);
226 +
227 +extern struct file_operations proc_sleep_operations;
228 +
229 +/* CONFIG_PROC_SLEEP */
230 +#else
231 +
232 +struct sleep_info {};
233 +
234 +#define init_sleep_info(tsk)
235 +#define free_sleep_info(sinfo)
236 +
237 +#define sleep_in_hook(tsk)
238 +#define sleep_ex_hook(tsk)
239 +#define stacktrace_record()
240 +
241 +/* CONFIG_PROC_SLEEP */
242 +#endif
243 +
244 +/* __KERNEL__ */
245 +#endif
246 +
247 +/* _LINUX_SLEEP_INFO_H */
248 +#endif
249 Index: linux-2.6.16.60-0.37/kernel/Makefile
250 ===================================================================
251 --- linux-2.6.16.60-0.37.orig/kernel/Makefile   2009-03-24 05:46:32.000000000 -0700
252 +++ linux-2.6.16.60-0.37/kernel/Makefile        2009-06-02 23:34:02.000000000 -0600
253 @@ -38,6 +38,7 @@
254  obj-$(CONFIG_TASKSTATS) += taskstats.o tsacct.o
255  obj-$(CONFIG_PAGG) += pagg.o
256  obj-$(CONFIG_RELAY) += relay.o
257 +obj-$(CONFIG_PROC_SLEEP) += sleep_info.o
258  
259  ifneq ($(CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER),y)
260  # According to Alan Modra <alan@linuxcare.com.au>, the -fno-omit-frame-pointer is
261 Index: linux-2.6.16.60-0.37/kernel/exit.c
262 ===================================================================
263 --- linux-2.6.16.60-0.37.orig/kernel/exit.c     2009-03-24 05:46:32.000000000 -0700
264 +++ linux-2.6.16.60-0.37/kernel/exit.c  2009-06-02 23:34:02.000000000 -0600
265 @@ -39,6 +39,7 @@
266  #include <linux/mutex.h>
267  #include <linux/pagg.h>
268  #include <linux/audit.h> /* for audit_free() */
269 +#include <linux/sleep_info.h>
270  
271  #include <asm/uaccess.h>
272  #include <asm/unistd.h>
273 @@ -119,6 +120,7 @@
274         write_unlock_irq(&tasklist_lock);
275         spin_unlock(&p->proc_lock);
276         proc_pid_flush(proc_dentry);
277 +       free_sleep_info(&p->sinfo);
278         release_thread(p);
279         call_rcu(&p->rcu, delayed_put_task_struct);
280  
281 Index: linux-2.6.16.60-0.37/kernel/fork.c
282 ===================================================================
283 --- linux-2.6.16.60-0.37.orig/kernel/fork.c     2009-03-24 05:46:35.000000000 -0700
284 +++ linux-2.6.16.60-0.37/kernel/fork.c  2009-06-02 23:34:02.000000000 -0600
285 @@ -48,6 +48,7 @@
286  #include <linux/pagg.h>
287  #include <linux/delayacct.h>
288  #include <linux/taskstats_kern.h>
289 +#include <linux/sleep_info.h>
290  
291  #include <asm/pgtable.h>
292  #include <asm/pgalloc.h>
293 @@ -1247,6 +1248,8 @@
294         attach_pid(p, PIDTYPE_TGID, p->tgid);
295         attach_pid(p, PIDTYPE_PID, p->pid);
296  
297 +       init_sleep_info(p);
298 +
299         nr_threads++;
300         total_forks++;
301         spin_unlock(&current->sighand->siglock);
302 Index: linux-2.6.16.60-0.37/kernel/sched.c
303 ===================================================================
304 --- linux-2.6.16.60-0.37.orig/kernel/sched.c    2009-06-02 23:33:13.000000000 -0600
305 +++ linux-2.6.16.60-0.37/kernel/sched.c 2009-06-02 23:34:02.000000000 -0600
306 @@ -2971,6 +2971,8 @@
307         }
308         profile_hit(SCHED_PROFILING, __builtin_return_address(0));
309  
310 +       sleep_in_hook(current);
311 +
312  need_resched:
313         preempt_disable();
314         prev = current;
315 @@ -3173,6 +3175,8 @@
316         barrier();
317         if (unlikely(test_thread_flag(TIF_NEED_RESCHED)))
318                 goto need_resched;
319 +
320 +       sleep_ex_hook(current);
321  }
322  
323  EXPORT_SYMBOL(preempt_schedule);
324 Index: linux-2.6.16.60-0.37/kernel/sleep_info.c
325 ===================================================================
326 --- linux-2.6.16.60-0.37.orig/kernel/sleep_info.c       2009-05-19 04:30:11.057558880 -0600
327 +++ linux-2.6.16.60-0.37/kernel/sleep_info.c    2009-06-02 23:34:02.000000000 -0600
328 @@ -0,0 +1,431 @@
329 +#include <linux/config.h>
330 +#include <linux/sleep_info.h>
331 +#include <linux/seq_file.h>
332 +#include <linux/kallsyms.h>
333 +#include <linux/slab.h>
334 +#include <linux/sched.h>
335 +#include <linux/proc_fs.h>
336 +#include <linux/fs.h>
337 +#include <linux/module.h>
338 +#include <linux/hardirq.h>
339 +
340 +#include <asm/div64.h>
341 +#include <linux/errno.h>
342 +
343 +#ifdef CONFIG_PROC_SLEEP
344 +
345 +#define SLEEP_TRACES_DEF (32)
346 +#define GLOBAL_SLEEP_TRACES_DEF (512)
347 +#define SLEEP_TRACE_DEPTH (20)
348 +#define GLOBAL_STACK_TRACES_DEF (512)
349 +
350 +struct stack_trace {
351 +       unsigned nr;
352 +       unsigned long long total;
353 +       unsigned long long max;
354 +       struct list_head lru;
355 +       unsigned long hash;
356 +       int depth;
357 +       void *frame[SLEEP_TRACE_DEPTH];
358 +};
359 +
360 +struct __sleep_info {
361 +       spinlock_t lock;
362 +       int nr_traces;
363 +       struct list_head lru;
364 +       struct stack_trace traces[0];
365 +};
366 +
367 +static inline int valid_stack_ptr(struct thread_info *tinfo, void *p)
368 +{
369 +       return  p > (void *)tinfo &&
370 +               p < (void *)tinfo + THREAD_SIZE - 3;
371 +}
372 +
373 +static void fill_trace(struct stack_trace *trace)
374 +{
375 +       int                 i;
376 +       struct thread_info *tinfo = current_thread_info();
377 +       unsigned long       fp; /* frame pointer */
378 +
379 +       /* Grab fp right from our regs */
380 +#if defined(CONFIG_X86_64) && defined(CONFIG_FRAME_POINTER_FORCE)
381 +       asm ("movq %%rbp, %0" : "=r" (fp) : );
382 +#define FP_RETADDR_OFFSET (8)
383 +#elif defined(CONFIG_X86)
384 +       asm ("movl %%ebp, %0" : "=r" (fp) : );
385 +#define FP_RETADDR_OFFSET (4)
386 +#else
387 +#error Unsupported platform.
388 +#endif
389 +
390 +       for (i = -3; /* skip three innermost frames */
391 +            i < SLEEP_TRACE_DEPTH && valid_stack_ptr(tinfo, (void *)fp);
392 +            ++i, fp = *(unsigned long *)fp) {
393 +               if (i >= 0)
394 +                       trace->frame[i] = *(void **)(fp + FP_RETADDR_OFFSET);
395 +       }
396 +       trace->depth = max(i, 0);
397 +}
398 +
399 +static int stack_trace_eq(struct stack_trace *t1, struct stack_trace *t2)
400 +{
401 +       return
402 +               t1->hash == t2->hash && t1->depth == t2->depth &&
403 +               !memcmp(t1->frame, t2->frame, t1->depth * sizeof t1->frame[0]);
404 +}
405 +
406 +static unsigned long stack_trace_hash(struct stack_trace *trace)
407 +{
408 +       int i;
409 +       unsigned hash;
410 +
411 +       for (i = 0, hash = 0; i < trace->depth; ++ i)
412 +               hash += ((unsigned long)trace->frame[i]) >> 3;
413 +       return hash;
414 +}
415 +
416 +/* from sleepometer by Andrew Morton */
417 +static unsigned long long grab_time(void)
418 +{
419 +#if defined(CONFIG_X86) && !defined(CONFIG_X86_64)
420 +       /*
421 +        * do_gettimeofday() goes backwards sometimes :(.  Usethe TSC
422 +        */
423 +       unsigned long long ret;
424 +       extern unsigned long cpu_khz;
425 +
426 +       rdtscll(ret);
427 +       do_div(ret, cpu_khz / 1000);
428 +       return ret;
429 +#else
430 +       struct timeval now;
431 +       unsigned long long ret;
432 +
433 +       do_gettimeofday(&now);
434 +       ret = now.tv_sec;
435 +       ret *= 1000000;
436 +       ret += now.tv_usec;
437 +       return ret;
438 +#endif
439 +}
440 +
441 +static void zero_sleep_info(struct __sleep_info *info)
442 +{
443 +       int i;
444 +
445 +       INIT_LIST_HEAD(&info->lru);
446 +       for (i = 0; i < info->nr_traces; ++ i) {
447 +               struct stack_trace *trace;
448 +
449 +               trace = &info->traces[i];
450 +               trace->nr = 0;
451 +               trace->total = 0;
452 +               trace->max = 0;
453 +               trace->hash = 0;
454 +               list_add(&trace->lru, &info->lru);
455 +               memset(trace->frame, 0, sizeof trace->frame);
456 +       }
457 +}
458 +
459 +static int alloc_sleep_info(struct sleep_info *sinfo, int nr_traces)
460 +{
461 +       struct __sleep_info *result;
462 +
463 +       result = kmalloc(sizeof *result + nr_traces * sizeof result->traces[0],
464 +                        GFP_ATOMIC);
465 +       if (result == NULL)
466 +               return -ENOMEM;
467 +
468 +       sinfo->p = result;
469 +       sinfo->last_in = 0;
470 +       result->nr_traces = nr_traces;
471 +       spin_lock_init(&result->lock);
472 +       zero_sleep_info(result);
473 +       return 0;
474 +}
475 +
476 +void init_sleep_info(struct task_struct *tsk)
477 +{
478 +       tsk->sinfo.p = NULL;
479 +}
480 +
481 +void free_sleep_info(struct sleep_info *sinfo)
482 +{
483 +       kfree(sinfo->p);
484 +       sinfo->p = NULL;
485 +}
486 +
487 +void sleep_in_hook(struct task_struct *tsk)
488 +{
489 +       tsk->sinfo.last_in = grab_time();
490 +}
491 +
492 +void update_sinfo(struct __sleep_info *sinfo, unsigned long long last_in)
493 +{
494 +       if (sinfo != NULL && last_in != 0) {
495 +               unsigned long long  delta;
496 +               struct stack_trace  trace;
497 +               struct stack_trace *target;
498 +               int i;
499 +
500 +               delta = grab_time() - last_in;
501 +               fill_trace(&trace);
502 +               target = NULL; /* to shut gcc up */
503 +               trace.hash = stack_trace_hash(&trace);
504 +               spin_lock(&sinfo->lock);
505 +               for (i = 0; i < sinfo->nr_traces; ++ i) {
506 +                       target = &sinfo->traces[i];
507 +                       if (stack_trace_eq(&trace, target)) {
508 +                               ++ target->nr;
509 +                               target->total += delta;
510 +                               target->max = max(target->max, delta);
511 +                               break;
512 +                       }
513 +               }
514 +               if (i == sinfo->nr_traces) {
515 +                       target = container_of(sinfo->lru.prev,
516 +                                             struct stack_trace, lru);
517 +                       target->nr = 1;
518 +                       target->total = target->max = delta;
519 +                       target->hash = trace.hash;
520 +                       target->depth = trace.depth;
521 +                       memcpy(target->frame, trace.frame, sizeof target->frame);
522 +               }
523 +               list_move(&target->lru, &sinfo->lru);
524 +               spin_unlock(&sinfo->lock);
525 +       }
526 +}
527 +
528 +static struct sleep_info global_sinfo = {
529 +       .p = NULL
530 +};
531 +
532 +void sleep_ex_hook(struct task_struct *tsk)
533 +{
534 +       struct sleep_info *cur;
535 +
536 +       cur = &tsk->sinfo;
537 +       update_sinfo(cur->p, cur->last_in);
538 +       update_sinfo(global_sinfo.p, cur->last_in);
539 +       cur->last_in = 0;
540 +}
541 +
542 +static spinlock_t sleep_serializer = SPIN_LOCK_UNLOCKED;
543 +
544 +static void *sinfo_start(struct sleep_info *sinfo, int nr_traces, loff_t l)
545 +{
546 +       spin_lock(&sleep_serializer);
547 +       if (sinfo->p == NULL)
548 +               alloc_sleep_info(sinfo, nr_traces);
549 +       spin_unlock(&sleep_serializer);
550 +       if (sinfo->p == NULL)
551 +               return NULL;
552 +
553 +       if (l >= sinfo->p->nr_traces)
554 +               return NULL;
555 +       else
556 +               return &sinfo->p->traces[l];
557 +}
558 +
559 +static void *sinfo_next(struct sleep_info *sinfo, void *v, loff_t *pos)
560 +{
561 +       (*pos)++;
562 +
563 +       if (*pos >= sinfo->p->nr_traces)
564 +               return NULL;
565 +       else
566 +               return ((struct stack_trace *)v) + 1;
567 +}
568 +
569 +/*
570 + * seq_file methods for /proc/pid/sleep. No locking is needed here, because we
571 + * are iterating over sinfo->traces[] array rather than over sinfo->lru
572 + * list. Actually spin locking is not allowed, because we can schedule between
573 + * sleep_start() and sleep_stop().
574 + */
575 +
576 +static void *sleep_start(struct seq_file *m, loff_t *pos)
577 +{
578 +       struct task_struct *task;
579 +
580 +       task = m->private;
581 +       return sinfo_start(&task->sinfo, SLEEP_TRACES_DEF, *pos);
582 +}
583 +
584 +static void sleep_stop(struct seq_file *m, void *v)
585 +{
586 +}
587 +
588 +static void *sleep_next(struct seq_file *m, void *v, loff_t *pos)
589 +{
590 +       struct task_struct *task;
591 +
592 +       task = m->private;
593 +       return sinfo_next(&task->sinfo, v, pos);
594 +}
595 +
596 +static int show_sleep(struct seq_file *m, void *v)
597 +{
598 +       struct stack_trace *trace;
599 +       int i;
600 +
601 +       trace = v;
602 +       if (trace->nr == 0)
603 +               return 0;
604 +
605 +       seq_printf(m, "\n%u %llu %llu",
606 +                  trace->nr, trace->total, trace->max);
607 +       for (i = 0; i < trace->depth; ++ i) {
608 +               char         *module;
609 +               const char   *name;
610 +               char          namebuf[128];
611 +               unsigned long address;
612 +               unsigned long offset;
613 +               unsigned long size;
614 +
615 +               address = (unsigned long) trace->frame[i];
616 +               name = kallsyms_lookup(address, &size,
617 +                                      &offset, &module, namebuf);
618 +               seq_printf(m, "\n\t%i %#lx ", i, address);
619 +               if (name != NULL)
620 +                       seq_printf(m, "%s+%#lx/%#lx", name, offset, size);
621 +       }
622 +       seq_printf(m, "\n");
623 +       return 0;
624 +}
625 +
626 +struct seq_operations proc_pid_sleep_op = {
627 +       .start  = sleep_start,
628 +       .next   = sleep_next,
629 +       .stop   = sleep_stop,
630 +       .show   = show_sleep
631 +};
632 +
633 +static int sleep_open(struct inode *inode, struct file *file)
634 +{
635 +       struct task_struct *task = PROC_I(inode)->task;
636 +       int ret = seq_open(file, &proc_pid_sleep_op);
637 +       if (!ret) {
638 +               struct seq_file *m = file->private_data;
639 +               m->private = task;
640 +       }
641 +       return ret;
642 +}
643 +
644 +static void reset_sleep_info(struct sleep_info *sinfo, int nr_traces)
645 +{
646 +       spin_lock(&sleep_serializer);
647 +       if (sinfo->p == NULL)
648 +               alloc_sleep_info(sinfo, nr_traces);
649 +       if (sinfo->p != NULL)
650 +               zero_sleep_info(sinfo->p);
651 +       spin_unlock(&sleep_serializer);
652 +}
653 +
654 +static ssize_t sleep_write(struct file *file, const char __user *buffer,
655 +                          size_t count, loff_t *ppos)
656 +{
657 +       struct task_struct *tsk = PROC_I(file->f_dentry->d_inode)->task;
658 +
659 +       reset_sleep_info(&tsk->sinfo, SLEEP_TRACES_DEF);
660 +       return count;
661 +}
662 +
663 +struct file_operations proc_sleep_operations = {
664 +       .open           = sleep_open,
665 +       .read           = seq_read,
666 +       .llseek         = seq_lseek,
667 +       .release        = seq_release,
668 +       .write          = sleep_write
669 +};
670 +
671 +static void *global_sleep_start(struct seq_file *m, loff_t *pos)
672 +{
673 +       return sinfo_start(&global_sinfo, GLOBAL_SLEEP_TRACES_DEF, *pos);
674 +}
675 +
676 +static void *global_sleep_next(struct seq_file *m, void *v, loff_t *pos)
677 +{
678 +       return sinfo_next(&global_sinfo, v, pos);
679 +}
680 +
681 +
682 +struct seq_operations global_sleep_op = {
683 +       .start  = global_sleep_start,
684 +       .next   = global_sleep_next,
685 +       .stop   = sleep_stop,
686 +       .show   = show_sleep
687 +};
688 +
689 +static int global_sleep_open(struct inode *inode, struct file *file)
690 +{
691 +       return seq_open(file, &global_sleep_op);
692 +}
693 +
694 +static ssize_t global_sleep_write(struct file *file, const char __user *buffer,
695 +                                 size_t count, loff_t *ppos)
696 +{
697 +       reset_sleep_info(&global_sinfo, GLOBAL_SLEEP_TRACES_DEF);
698 +       return count;
699 +}
700 +
701 +struct file_operations proc_global_sleep_operations = {
702 +       .open           = global_sleep_open,
703 +       .read           = seq_read,
704 +       .llseek         = seq_lseek,
705 +       .release        = seq_release,
706 +       .write          = global_sleep_write
707 +};
708 +
709 +static struct sleep_info stack_sinfo = {
710 +       .p = NULL
711 +};
712 +
713 +static void *global_stack_start(struct seq_file *m, loff_t *pos)
714 +{
715 +       return sinfo_start(&stack_sinfo, GLOBAL_STACK_TRACES_DEF, *pos);
716 +}
717 +
718 +static void *global_stack_next(struct seq_file *m, void *v, loff_t *pos)
719 +{
720 +       return sinfo_next(&stack_sinfo, v, pos);
721 +}
722 +
723 +
724 +struct seq_operations global_stack_op = {
725 +       .start  = global_stack_start,
726 +       .next   = global_stack_next,
727 +       .stop   = sleep_stop,
728 +       .show   = show_sleep
729 +};
730 +
731 +static int global_stack_open(struct inode *inode, struct file *file)
732 +{
733 +       return seq_open(file, &global_stack_op);
734 +}
735 +
736 +static ssize_t global_stack_write(struct file *file, const char __user *buffer,
737 +                                 size_t count, loff_t *ppos)
738 +{
739 +       reset_sleep_info(&stack_sinfo, GLOBAL_STACK_TRACES_DEF);
740 +       return count;
741 +}
742 +
743 +struct file_operations proc_global_stack_operations = {
744 +       .open           = global_stack_open,
745 +       .read           = seq_read,
746 +       .llseek         = seq_lseek,
747 +       .release        = seq_release,
748 +       .write          = global_stack_write
749 +};
750 +
751 +void stacktrace_record(void)
752 +{
753 +       if (!in_interrupt())
754 +               update_sinfo(stack_sinfo.p, 1);
755 +}
756 +EXPORT_SYMBOL(stacktrace_record);
757 +
758 +/* CONFIG_PROC_SLEEP */
759 +#endif