vserver 2.0 rc7
[linux-2.6.git] / kernel / vserver / history.c
1 /*
2  *  kernel/vserver/history.c
3  *
4  *  Virtual Context History Backtrace
5  *
6  *  Copyright (C) 2004-2005  Herbert Pƶtzl
7  *
8  *  V0.01  basic structure
9  *  V0.02  hash/unhash and trace
10  *  V0.03  preemption fixes
11  *
12  */
13
14 #include <linux/config.h>
15 #include <linux/errno.h>
16 #include <linux/module.h>
17 #include <linux/types.h>
18 #include <linux/ctype.h>
19
20 #include <asm/uaccess.h>
21 #include <asm/atomic.h>
22 #include <asm/unistd.h>
23
24 #include <linux/vserver/debug.h>
25
26
27 #ifdef  CONFIG_VSERVER_HISTORY
28 #define VXH_SIZE        CONFIG_VSERVER_HISTORY_SIZE
29 #else
30 #define VXH_SIZE        64
31 #endif
32
33 struct _vx_history {
34         unsigned int counter;
35
36         struct _vx_hist_entry entry[VXH_SIZE+1];
37 };
38
39
40 DEFINE_PER_CPU(struct _vx_history, vx_history_buffer);
41
42 unsigned volatile int vxh_active = 1;
43
44 static atomic_t sequence = ATOMIC_INIT(0);
45
46
47 /*      vxh_advance()
48
49         * requires disabled preemption                          */
50
51 struct _vx_hist_entry *vxh_advance(void *loc)
52 {
53         unsigned int cpu = smp_processor_id();
54         struct _vx_history *hist = &per_cpu(vx_history_buffer, cpu);
55         struct _vx_hist_entry *entry;
56         unsigned int index;
57
58         index = vxh_active ? (hist->counter++ % VXH_SIZE) : VXH_SIZE;
59         entry = &hist->entry[index];
60
61         entry->seq = atomic_inc_return(&sequence);
62         entry->loc = loc;
63         return entry;
64 }
65
66
67 #define VXH_LOC_FMTS    "(#%04x,*%d):%p"
68
69 #define VXH_LOC_ARGS(e) (e)->seq, cpu, (e)->loc
70
71
72 #define VXH_VXI_FMTS    "%p[#%d,%d.%d]"
73
74 #define VXH_VXI_ARGS(e) (e)->vxi.ptr,                   \
75                         (e)->vxi.ptr?(e)->vxi.xid:0,    \
76                         (e)->vxi.ptr?(e)->vxi.usecnt:0, \
77                         (e)->vxi.ptr?(e)->vxi.tasks:0
78
79 void    vxh_dump_entry(struct _vx_hist_entry *e, unsigned cpu)
80 {
81         switch (e->type) {
82         case VXH_THROW_OOPS:
83                 printk( VXH_LOC_FMTS " oops \n", VXH_LOC_ARGS(e));
84                 break;
85
86         case VXH_GET_VX_INFO:
87         case VXH_PUT_VX_INFO:
88                 printk( VXH_LOC_FMTS " %s_vx_info " VXH_VXI_FMTS "\n",
89                         VXH_LOC_ARGS(e),
90                         (e->type==VXH_GET_VX_INFO)?"get":"put",
91                         VXH_VXI_ARGS(e));
92                 break;
93
94         case VXH_INIT_VX_INFO:
95         case VXH_SET_VX_INFO:
96         case VXH_CLR_VX_INFO:
97                 printk( VXH_LOC_FMTS " %s_vx_info " VXH_VXI_FMTS " @%p\n",
98                         VXH_LOC_ARGS(e),
99                         (e->type==VXH_INIT_VX_INFO)?"init":
100                         ((e->type==VXH_SET_VX_INFO)?"set":"clr"),
101                         VXH_VXI_ARGS(e), e->sc.data);
102                 break;
103
104         case VXH_CLAIM_VX_INFO:
105         case VXH_RELEASE_VX_INFO:
106                 printk( VXH_LOC_FMTS " %s_vx_info " VXH_VXI_FMTS " @%p\n",
107                         VXH_LOC_ARGS(e),
108                         (e->type==VXH_CLAIM_VX_INFO)?"claim":"release",
109                         VXH_VXI_ARGS(e), e->sc.data);
110                 break;
111
112         case VXH_ALLOC_VX_INFO:
113         case VXH_DEALLOC_VX_INFO:
114                 printk( VXH_LOC_FMTS " %s_vx_info " VXH_VXI_FMTS "\n",
115                         VXH_LOC_ARGS(e),
116                         (e->type==VXH_ALLOC_VX_INFO)?"alloc":"dealloc",
117                         VXH_VXI_ARGS(e));
118                 break;
119
120         case VXH_HASH_VX_INFO:
121         case VXH_UNHASH_VX_INFO:
122                 printk( VXH_LOC_FMTS " __%s_vx_info " VXH_VXI_FMTS "\n",
123                         VXH_LOC_ARGS(e),
124                         (e->type==VXH_HASH_VX_INFO)?"hash":"unhash",
125                         VXH_VXI_ARGS(e));
126                 break;
127
128         case VXH_LOC_VX_INFO:
129         case VXH_LOOKUP_VX_INFO:
130         case VXH_CREATE_VX_INFO:
131                 printk( VXH_LOC_FMTS " __%s_vx_info [#%d] -> " VXH_VXI_FMTS "\n",
132                         VXH_LOC_ARGS(e),
133                         (e->type==VXH_CREATE_VX_INFO)?"create":
134                         ((e->type==VXH_LOC_VX_INFO)?"loc":"lookup"),
135                         e->ll.arg, VXH_VXI_ARGS(e));
136                 break;
137         }
138 }
139
140 static void __vxh_dump_history(void)
141 {
142         unsigned int i,j;
143
144         printk("History:\tSEQ: %8x\tNR_CPUS: %d\n",
145                 atomic_read(&sequence), NR_CPUS);
146
147         for (i=0; i < VXH_SIZE; i++) {
148                 for (j=0; j < NR_CPUS; j++) {
149                         struct _vx_history *hist =
150                                 &per_cpu(vx_history_buffer, j);
151                         unsigned int index = (hist->counter-i) % VXH_SIZE;
152                         struct _vx_hist_entry *entry = &hist->entry[index];
153
154                         vxh_dump_entry(entry, j);
155                 }
156         }
157 }
158
159 void    vxh_dump_history(void)
160 {
161         vxh_active = 0;
162 #ifdef CONFIG_SMP
163         local_irq_enable();
164         smp_send_stop();
165         local_irq_disable();
166 #endif
167         __vxh_dump_history();
168 }
169
170
171 /* vserver syscall commands below here */
172
173
174 int     vc_dump_history(uint32_t id)
175 {
176         vxh_active = 0;
177         __vxh_dump_history();
178         vxh_active = 1;
179
180         return 0;
181 }
182
183 EXPORT_SYMBOL_GPL(vxh_advance);
184