fedora core 6 1.2949 + vserver 2.2.0
[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-2007  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/errno.h>
15 #include <linux/module.h>
16 #include <linux/types.h>
17 #include <linux/ctype.h>
18
19 #include <asm/uaccess.h>
20 #include <asm/atomic.h>
21 #include <asm/unistd.h>
22
23 #include <linux/vserver/context.h>
24 #include <linux/vserver/debug.h>
25 #include <linux/vserver/debug_cmd.h>
26 #include <linux/vserver/history.h>
27
28
29 #ifdef  CONFIG_VSERVER_HISTORY
30 #define VXH_SIZE        CONFIG_VSERVER_HISTORY_SIZE
31 #else
32 #define VXH_SIZE        64
33 #endif
34
35 struct _vx_history {
36         unsigned int counter;
37
38         struct _vx_hist_entry entry[VXH_SIZE+1];
39 };
40
41
42 DEFINE_PER_CPU(struct _vx_history, vx_history_buffer);
43
44 unsigned volatile int vxh_active = 1;
45
46 static atomic_t sequence = ATOMIC_INIT(0);
47
48
49 /*      vxh_advance()
50
51         * requires disabled preemption                          */
52
53 struct _vx_hist_entry *vxh_advance(void *loc)
54 {
55         unsigned int cpu = smp_processor_id();
56         struct _vx_history *hist = &per_cpu(vx_history_buffer, cpu);
57         struct _vx_hist_entry *entry;
58         unsigned int index;
59
60         index = vxh_active ? (hist->counter++ % VXH_SIZE) : VXH_SIZE;
61         entry = &hist->entry[index];
62
63         entry->seq = atomic_inc_return(&sequence);
64         entry->loc = loc;
65         return entry;
66 }
67
68 EXPORT_SYMBOL_GPL(vxh_advance);
69
70
71 #define VXH_LOC_FMTS    "(#%04x,*%d):%p"
72
73 #define VXH_LOC_ARGS(e) (e)->seq, cpu, (e)->loc
74
75
76 #define VXH_VXI_FMTS    "%p[#%d,%d.%d]"
77
78 #define VXH_VXI_ARGS(e) (e)->vxi.ptr,                   \
79                         (e)->vxi.ptr?(e)->vxi.xid:0,    \
80                         (e)->vxi.ptr?(e)->vxi.usecnt:0, \
81                         (e)->vxi.ptr?(e)->vxi.tasks:0
82
83 void    vxh_dump_entry(struct _vx_hist_entry *e, unsigned cpu)
84 {
85         switch (e->type) {
86         case VXH_THROW_OOPS:
87                 printk( VXH_LOC_FMTS " oops \n", VXH_LOC_ARGS(e));
88                 break;
89
90         case VXH_GET_VX_INFO:
91         case VXH_PUT_VX_INFO:
92                 printk( VXH_LOC_FMTS " %s_vx_info " VXH_VXI_FMTS "\n",
93                         VXH_LOC_ARGS(e),
94                         (e->type==VXH_GET_VX_INFO)?"get":"put",
95                         VXH_VXI_ARGS(e));
96                 break;
97
98         case VXH_INIT_VX_INFO:
99         case VXH_SET_VX_INFO:
100         case VXH_CLR_VX_INFO:
101                 printk( VXH_LOC_FMTS " %s_vx_info " VXH_VXI_FMTS " @%p\n",
102                         VXH_LOC_ARGS(e),
103                         (e->type==VXH_INIT_VX_INFO)?"init":
104                         ((e->type==VXH_SET_VX_INFO)?"set":"clr"),
105                         VXH_VXI_ARGS(e), e->sc.data);
106                 break;
107
108         case VXH_CLAIM_VX_INFO:
109         case VXH_RELEASE_VX_INFO:
110                 printk( VXH_LOC_FMTS " %s_vx_info " VXH_VXI_FMTS " @%p\n",
111                         VXH_LOC_ARGS(e),
112                         (e->type==VXH_CLAIM_VX_INFO)?"claim":"release",
113                         VXH_VXI_ARGS(e), e->sc.data);
114                 break;
115
116         case VXH_ALLOC_VX_INFO:
117         case VXH_DEALLOC_VX_INFO:
118                 printk( VXH_LOC_FMTS " %s_vx_info " VXH_VXI_FMTS "\n",
119                         VXH_LOC_ARGS(e),
120                         (e->type==VXH_ALLOC_VX_INFO)?"alloc":"dealloc",
121                         VXH_VXI_ARGS(e));
122                 break;
123
124         case VXH_HASH_VX_INFO:
125         case VXH_UNHASH_VX_INFO:
126                 printk( VXH_LOC_FMTS " __%s_vx_info " VXH_VXI_FMTS "\n",
127                         VXH_LOC_ARGS(e),
128                         (e->type==VXH_HASH_VX_INFO)?"hash":"unhash",
129                         VXH_VXI_ARGS(e));
130                 break;
131
132         case VXH_LOC_VX_INFO:
133         case VXH_LOOKUP_VX_INFO:
134         case VXH_CREATE_VX_INFO:
135                 printk( VXH_LOC_FMTS " __%s_vx_info [#%d] -> " VXH_VXI_FMTS "\n",
136                         VXH_LOC_ARGS(e),
137                         (e->type==VXH_CREATE_VX_INFO)?"create":
138                         ((e->type==VXH_LOC_VX_INFO)?"loc":"lookup"),
139                         e->ll.arg, VXH_VXI_ARGS(e));
140                 break;
141         }
142 }
143
144 static void __vxh_dump_history(void)
145 {
146         unsigned int i, cpu;
147
148         printk("History:\tSEQ: %8x\tNR_CPUS: %d\n",
149                 atomic_read(&sequence), NR_CPUS);
150
151         for (i=0; i < VXH_SIZE; i++) {
152                 for_each_online_cpu(cpu) {
153                         struct _vx_history *hist =
154                                 &per_cpu(vx_history_buffer, cpu);
155                         unsigned int index = (hist->counter-i) % VXH_SIZE;
156                         struct _vx_hist_entry *entry = &hist->entry[index];
157
158                         vxh_dump_entry(entry, cpu);
159                 }
160         }
161 }
162
163 void    vxh_dump_history(void)
164 {
165         vxh_active = 0;
166 #ifdef CONFIG_SMP
167         local_irq_enable();
168         smp_send_stop();
169         local_irq_disable();
170 #endif
171         __vxh_dump_history();
172 }
173
174
175 /* vserver syscall commands below here */
176
177
178 int vc_dump_history(uint32_t id)
179 {
180         vxh_active = 0;
181         __vxh_dump_history();
182         vxh_active = 1;
183
184         return 0;
185 }
186
187
188 int do_read_history(struct __user _vx_hist_entry *data,
189         int cpu, uint32_t *index, uint32_t *count)
190 {
191         int pos, ret = 0;
192         struct _vx_history *hist = &per_cpu(vx_history_buffer, cpu);
193         int end = hist->counter;
194         int start = end - VXH_SIZE + 2;
195         int idx = *index;
196
197         /* special case: get current pos */
198         if (!*count) {
199                 *index = end;
200                 return 0;
201         }
202
203         /* have we lost some data? */
204         if (idx < start)
205                 idx = start;
206
207         for (pos = 0; (pos < *count) && (idx < end); pos++, idx++) {
208                 struct _vx_hist_entry *entry =
209                         &hist->entry[idx % VXH_SIZE];
210
211                 /* send entry to userspace */
212                 ret = copy_to_user (&data[pos], entry, sizeof(*entry));
213                 if (ret)
214                         break;
215         }
216         /* save new index and count */
217         *index = idx;
218         *count = pos;
219         return ret ? ret : (*index < end);
220 }
221
222 int vc_read_history(uint32_t id, void __user *data)
223 {
224         struct vcmd_read_history_v0 vc_data;
225         int ret;
226
227         if (id >= NR_CPUS)
228                 return -EINVAL;
229
230         if (copy_from_user (&vc_data, data, sizeof(vc_data)))
231                 return -EFAULT;
232
233         ret = do_read_history((struct __user _vx_hist_entry *)vc_data.data,
234                 id, &vc_data.index, &vc_data.count);
235
236         if (copy_to_user (data, &vc_data, sizeof(vc_data)))
237                 return -EFAULT;
238         return ret;
239 }
240
241 #ifdef  CONFIG_COMPAT
242
243 int vc_read_history_x32(uint32_t id, void __user *data)
244 {
245         struct vcmd_read_history_v0_x32 vc_data;
246         int ret;
247
248         if (id >= NR_CPUS)
249                 return -EINVAL;
250
251         if (copy_from_user (&vc_data, data, sizeof(vc_data)))
252                 return -EFAULT;
253
254         ret = do_read_history((struct __user _vx_hist_entry *)
255                 compat_ptr(vc_data.data_ptr),
256                 id, &vc_data.index, &vc_data.count);
257
258         if (copy_to_user (data, &vc_data, sizeof(vc_data)))
259                 return -EFAULT;
260         return ret;
261 }
262
263 #endif  /* CONFIG_COMPAT */
264