2 * kernel/vserver/history.c
4 * Virtual Context History Backtrace
6 * Copyright (C) 2004-2007 Herbert Pƶtzl
8 * V0.01 basic structure
9 * V0.02 hash/unhash and trace
10 * V0.03 preemption fixes
14 #include <linux/errno.h>
15 #include <linux/module.h>
16 #include <linux/types.h>
17 #include <linux/ctype.h>
19 #include <asm/uaccess.h>
20 #include <asm/atomic.h>
21 #include <asm/unistd.h>
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>
29 #ifdef CONFIG_VSERVER_HISTORY
30 #define VXH_SIZE CONFIG_VSERVER_HISTORY_SIZE
38 struct _vx_hist_entry entry[VXH_SIZE+1];
42 DEFINE_PER_CPU(struct _vx_history, vx_history_buffer);
44 unsigned volatile int vxh_active = 1;
46 static atomic_t sequence = ATOMIC_INIT(0);
51 * requires disabled preemption */
53 struct _vx_hist_entry *vxh_advance(void *loc)
55 unsigned int cpu = smp_processor_id();
56 struct _vx_history *hist = &per_cpu(vx_history_buffer, cpu);
57 struct _vx_hist_entry *entry;
60 index = vxh_active ? (hist->counter++ % VXH_SIZE) : VXH_SIZE;
61 entry = &hist->entry[index];
63 entry->seq = atomic_inc_return(&sequence);
68 EXPORT_SYMBOL_GPL(vxh_advance);
71 #define VXH_LOC_FMTS "(#%04x,*%d):%p"
73 #define VXH_LOC_ARGS(e) (e)->seq, cpu, (e)->loc
76 #define VXH_VXI_FMTS "%p[#%d,%d.%d]"
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
83 void vxh_dump_entry(struct _vx_hist_entry *e, unsigned cpu)
87 printk( VXH_LOC_FMTS " oops \n", VXH_LOC_ARGS(e));
92 printk( VXH_LOC_FMTS " %s_vx_info " VXH_VXI_FMTS "\n",
94 (e->type==VXH_GET_VX_INFO)?"get":"put",
98 case VXH_INIT_VX_INFO:
100 case VXH_CLR_VX_INFO:
101 printk( VXH_LOC_FMTS " %s_vx_info " VXH_VXI_FMTS " @%p\n",
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);
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",
112 (e->type==VXH_CLAIM_VX_INFO)?"claim":"release",
113 VXH_VXI_ARGS(e), e->sc.data);
116 case VXH_ALLOC_VX_INFO:
117 case VXH_DEALLOC_VX_INFO:
118 printk( VXH_LOC_FMTS " %s_vx_info " VXH_VXI_FMTS "\n",
120 (e->type==VXH_ALLOC_VX_INFO)?"alloc":"dealloc",
124 case VXH_HASH_VX_INFO:
125 case VXH_UNHASH_VX_INFO:
126 printk( VXH_LOC_FMTS " __%s_vx_info " VXH_VXI_FMTS "\n",
128 (e->type==VXH_HASH_VX_INFO)?"hash":"unhash",
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",
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));
144 static void __vxh_dump_history(void)
148 printk("History:\tSEQ: %8x\tNR_CPUS: %d\n",
149 atomic_read(&sequence), NR_CPUS);
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];
158 vxh_dump_entry(entry, cpu);
163 void vxh_dump_history(void)
171 __vxh_dump_history();
175 /* vserver syscall commands below here */
178 int vc_dump_history(uint32_t id)
181 __vxh_dump_history();
188 int do_read_history(struct __user _vx_hist_entry *data,
189 int cpu, uint32_t *index, uint32_t *count)
192 struct _vx_history *hist = &per_cpu(vx_history_buffer, cpu);
193 int end = hist->counter;
194 int start = end - VXH_SIZE + 2;
197 /* special case: get current pos */
203 /* have we lost some data? */
207 for (pos = 0; (pos < *count) && (idx < end); pos++, idx++) {
208 struct _vx_hist_entry *entry =
209 &hist->entry[idx % VXH_SIZE];
211 /* send entry to userspace */
212 ret = copy_to_user (&data[pos], entry, sizeof(*entry));
216 /* save new index and count */
219 return ret ? ret : (*index < end);
222 int vc_read_history(uint32_t id, void __user *data)
224 struct vcmd_read_history_v0 vc_data;
230 if (copy_from_user (&vc_data, data, sizeof(vc_data)))
233 ret = do_read_history((struct __user _vx_hist_entry *)vc_data.data,
234 id, &vc_data.index, &vc_data.count);
236 if (copy_to_user (data, &vc_data, sizeof(vc_data)))
243 int vc_read_history_x32(uint32_t id, void __user *data)
245 struct vcmd_read_history_v0_x32 vc_data;
251 if (copy_from_user (&vc_data, data, sizeof(vc_data)))
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);
258 if (copy_to_user (data, &vc_data, sizeof(vc_data)))
263 #endif /* CONFIG_COMPAT */