This commit was manufactured by cvs2svn to create branch 'vserver'.
[linux-2.6.git] / kernel / vserver / monitor.c
1 /*
2  *  kernel/vserver/monitor.c
3  *
4  *  Virtual Context Scheduler Monitor
5  *
6  *  Copyright (C) 2006-2007 Herbert Pƶtzl
7  *
8  *  V0.01  basic design
9  *
10  */
11
12 #include <linux/errno.h>
13 #include <linux/module.h>
14 #include <linux/types.h>
15 #include <linux/ctype.h>
16
17 #include <asm/uaccess.h>
18 #include <asm/atomic.h>
19 #include <asm/unistd.h>
20
21 #include <linux/vserver/monitor.h>
22 #include <linux/vserver/debug_cmd.h>
23
24
25 #ifdef  CONFIG_VSERVER_MONITOR
26 #define VXM_SIZE        CONFIG_VSERVER_MONITOR_SIZE
27 #else
28 #define VXM_SIZE        64
29 #endif
30
31 struct _vx_monitor {
32         unsigned int counter;
33
34         struct _vx_mon_entry entry[VXM_SIZE+1];
35 };
36
37
38 DEFINE_PER_CPU(struct _vx_monitor, vx_monitor_buffer);
39
40 unsigned volatile int vxm_active = 1;
41
42 static atomic_t sequence = ATOMIC_INIT(0);
43
44
45 /*      vxm_advance()
46
47         * requires disabled preemption                          */
48
49 struct _vx_mon_entry *vxm_advance(int cpu)
50 {
51         struct _vx_monitor *mon = &per_cpu(vx_monitor_buffer, cpu);
52         struct _vx_mon_entry *entry;
53         unsigned int index;
54
55         index = vxm_active ? (mon->counter++ % VXM_SIZE) : VXM_SIZE;
56         entry = &mon->entry[index];
57
58         entry->ev.seq = atomic_inc_return(&sequence);
59         entry->ev.jif = jiffies;
60         return entry;
61 }
62
63 EXPORT_SYMBOL_GPL(vxm_advance);
64
65
66 int do_read_monitor(struct __user _vx_mon_entry *data,
67         int cpu, uint32_t *index, uint32_t *count)
68 {
69         int pos, ret = 0;
70         struct _vx_monitor *mon = &per_cpu(vx_monitor_buffer, cpu);
71         int end = mon->counter;
72         int start = end - VXM_SIZE + 2;
73         int idx = *index;
74
75         /* special case: get current pos */
76         if (!*count) {
77                 *index = end;
78                 return 0;
79         }
80
81         /* have we lost some data? */
82         if (idx < start)
83                 idx = start;
84
85         for (pos = 0; (pos < *count) && (idx < end); pos++, idx++) {
86                 struct _vx_mon_entry *entry =
87                         &mon->entry[idx % VXM_SIZE];
88
89                 /* send entry to userspace */
90                 ret = copy_to_user (&data[pos], entry, sizeof(*entry));
91                 if (ret)
92                         break;
93         }
94         /* save new index and count */
95         *index = idx;
96         *count = pos;
97         return ret ? ret : (*index < end);
98 }
99
100 int vc_read_monitor(uint32_t id, void __user *data)
101 {
102         struct vcmd_read_monitor_v0 vc_data;
103         int ret;
104
105         if (id >= NR_CPUS)
106                 return -EINVAL;
107
108         if (copy_from_user (&vc_data, data, sizeof(vc_data)))
109                 return -EFAULT;
110
111         ret = do_read_monitor((struct __user _vx_mon_entry *)vc_data.data,
112                 id, &vc_data.index, &vc_data.count);
113
114         if (copy_to_user (data, &vc_data, sizeof(vc_data)))
115                 return -EFAULT;
116         return ret;
117 }
118
119 #ifdef  CONFIG_COMPAT
120
121 int vc_read_monitor_x32(uint32_t id, void __user *data)
122 {
123         struct vcmd_read_monitor_v0_x32 vc_data;
124         int ret;
125
126         if (id >= NR_CPUS)
127                 return -EINVAL;
128
129         if (copy_from_user (&vc_data, data, sizeof(vc_data)))
130                 return -EFAULT;
131
132         ret = do_read_monitor((struct __user _vx_mon_entry *)
133                 compat_ptr(vc_data.data_ptr),
134                 id, &vc_data.index, &vc_data.count);
135
136         if (copy_to_user (data, &vc_data, sizeof(vc_data)))
137                 return -EFAULT;
138         return ret;
139 }
140
141 #endif  /* CONFIG_COMPAT */
142