Update to 3.4-final.
[linux-flexiantxendom0-3.2.10.git] / drivers / oprofile / oprofile_files.c
1 /**
2  * @file oprofile_files.c
3  *
4  * @remark Copyright 2002 OProfile authors
5  * @remark Read the file COPYING
6  *
7  * @author John Levon <levon@movementarian.org>
8  *
9  * Modified by Aravind Menon for Xen
10  * These modifications are:
11  * Copyright (C) 2005 Hewlett-Packard Co.
12  */
13
14 #include <linux/fs.h>
15 #include <linux/oprofile.h>
16 #include <linux/jiffies.h>
17 #include <asm/uaccess.h>
18 #include <linux/ctype.h>
19
20 #include "event_buffer.h"
21 #include "oprofile_stats.h"
22 #include "oprof.h"
23
24 #define BUFFER_SIZE_DEFAULT             131072
25 #define CPU_BUFFER_SIZE_DEFAULT         8192
26 #define BUFFER_WATERSHED_DEFAULT        32768   /* FIXME: tune */
27 #define TIME_SLICE_DEFAULT              1
28
29 unsigned long oprofile_buffer_size;
30 unsigned long oprofile_cpu_buffer_size;
31 unsigned long oprofile_buffer_watershed;
32 unsigned long oprofile_time_slice;
33
34 #ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX
35
36 static ssize_t timeout_read(struct file *file, char __user *buf,
37                 size_t count, loff_t *offset)
38 {
39         return oprofilefs_ulong_to_user(jiffies_to_msecs(oprofile_time_slice),
40                                         buf, count, offset);
41 }
42
43
44 static ssize_t timeout_write(struct file *file, char const __user *buf,
45                 size_t count, loff_t *offset)
46 {
47         unsigned long val;
48         int retval;
49
50         if (*offset)
51                 return -EINVAL;
52
53         retval = oprofilefs_ulong_from_user(&val, buf, count);
54         if (retval <= 0)
55                 return retval;
56
57         retval = oprofile_set_timeout(val);
58
59         if (retval)
60                 return retval;
61         return count;
62 }
63
64
65 static const struct file_operations timeout_fops = {
66         .read           = timeout_read,
67         .write          = timeout_write,
68         .llseek         = default_llseek,
69 };
70
71 #endif
72
73
74 static ssize_t depth_read(struct file *file, char __user *buf, size_t count, loff_t *offset)
75 {
76         return oprofilefs_ulong_to_user(oprofile_backtrace_depth, buf, count,
77                                         offset);
78 }
79
80
81 static ssize_t depth_write(struct file *file, char const __user *buf, size_t count, loff_t *offset)
82 {
83         unsigned long val;
84         int retval;
85
86         if (*offset)
87                 return -EINVAL;
88
89         if (!oprofile_ops.backtrace)
90                 return -EINVAL;
91
92         retval = oprofilefs_ulong_from_user(&val, buf, count);
93         if (retval <= 0)
94                 return retval;
95
96         retval = oprofile_set_ulong(&oprofile_backtrace_depth, val);
97         if (retval)
98                 return retval;
99
100         return count;
101 }
102
103
104 static const struct file_operations depth_fops = {
105         .read           = depth_read,
106         .write          = depth_write,
107         .llseek         = default_llseek,
108 };
109
110
111 static ssize_t pointer_size_read(struct file *file, char __user *buf, size_t count, loff_t *offset)
112 {
113         return oprofilefs_ulong_to_user(sizeof(void *), buf, count, offset);
114 }
115
116
117 static const struct file_operations pointer_size_fops = {
118         .read           = pointer_size_read,
119         .llseek         = default_llseek,
120 };
121
122
123 static ssize_t cpu_type_read(struct file *file, char __user *buf, size_t count, loff_t *offset)
124 {
125         return oprofilefs_str_to_user(oprofile_ops.cpu_type, buf, count, offset);
126 }
127
128
129 static const struct file_operations cpu_type_fops = {
130         .read           = cpu_type_read,
131         .llseek         = default_llseek,
132 };
133
134
135 static ssize_t enable_read(struct file *file, char __user *buf, size_t count, loff_t *offset)
136 {
137         return oprofilefs_ulong_to_user(oprofile_started, buf, count, offset);
138 }
139
140
141 static ssize_t enable_write(struct file *file, char const __user *buf, size_t count, loff_t *offset)
142 {
143         unsigned long val;
144         int retval;
145
146         if (*offset)
147                 return -EINVAL;
148
149         retval = oprofilefs_ulong_from_user(&val, buf, count);
150         if (retval <= 0)
151                 return retval;
152
153         retval = 0;
154         if (val)
155                 retval = oprofile_start();
156         else
157                 oprofile_stop();
158
159         if (retval)
160                 return retval;
161         return count;
162 }
163
164
165 static const struct file_operations enable_fops = {
166         .read           = enable_read,
167         .write          = enable_write,
168         .llseek         = default_llseek,
169 };
170
171
172 static ssize_t dump_write(struct file *file, char const __user *buf, size_t count, loff_t *offset)
173 {
174         wake_up_buffer_waiter();
175         return count;
176 }
177
178
179 static const struct file_operations dump_fops = {
180         .write          = dump_write,
181         .llseek         = noop_llseek,
182 };
183
184 #ifdef CONFIG_XEN
185 #include <linux/slab.h>
186
187 #define TMPBUFSIZE 512
188
189 struct domain_data {
190     unsigned int nr;
191     int ids[MAX_OPROF_DOMAINS + 1];
192     struct mutex mutex;
193     int (*set)(int[], unsigned int);
194 };
195 #define DEFINE_DOMAIN_DATA(what) \
196         struct domain_data what##_domains = { \
197                 .mutex = __MUTEX_INITIALIZER(what##_domains.mutex), \
198                 .set = oprofile_set_##what \
199         }
200
201 static ssize_t domain_write(struct file *filp, char const __user *buf,
202                             size_t count, loff_t *offset)
203 {
204         struct domain_data *dom = filp->private_data;
205         char *tmpbuf;
206         char *startp, *endp;
207         int i;
208         unsigned long val;
209         ssize_t retval = count;
210
211         if (*offset)
212                 return -EINVAL;
213         if (count > TMPBUFSIZE - 1)
214                 return -EINVAL;
215
216         if (!(tmpbuf = kmalloc(TMPBUFSIZE, GFP_KERNEL)))
217                 return -ENOMEM;
218
219         if (copy_from_user(tmpbuf, buf, count)) {
220                 kfree(tmpbuf);
221                 return -EFAULT;
222         }
223         tmpbuf[count] = 0;
224
225         mutex_lock(&dom->mutex);
226
227         startp = tmpbuf;
228         /* Parse one more than MAX_OPROF_DOMAINS, for easy error checking */
229         for (i = 0; i <= MAX_OPROF_DOMAINS; i++) {
230                 val = simple_strtoul(startp, &endp, 0);
231                 if (endp == startp)
232                         break;
233                 while (ispunct(*endp) || isspace(*endp))
234                         endp++;
235                 dom->ids[i] = val;
236                 if (dom->ids[i] != val)
237                         /* Overflow, force error below */
238                         i = MAX_OPROF_DOMAINS + 1;
239                 startp = endp;
240         }
241         /* Force error on trailing junk */
242         dom->nr = *startp ? MAX_OPROF_DOMAINS + 1 : i;
243
244         kfree(tmpbuf);
245
246         if (dom->nr > MAX_OPROF_DOMAINS
247             || dom->set(dom->ids, dom->nr)) {
248                 dom->nr = 0;
249                 retval = -EINVAL;
250         }
251
252         mutex_unlock(&dom->mutex);
253         return retval;
254 }
255
256 static ssize_t domain_read(struct file *filp, char __user *buf,
257                             size_t count, loff_t *offset)
258 {
259         struct domain_data *dom = filp->private_data;
260         char *tmpbuf;
261         size_t len;
262         int i;
263         ssize_t retval;
264
265         if (!(tmpbuf = kmalloc(TMPBUFSIZE, GFP_KERNEL)))
266                 return -ENOMEM;
267
268         mutex_lock(&dom->mutex);
269
270         len = 0;
271         for (i = 0; i < dom->nr; i++)
272                 len += snprintf(tmpbuf + len,
273                                 len < TMPBUFSIZE ? TMPBUFSIZE - len : 0,
274                                 "%u ", dom->ids[i]);
275         WARN_ON(len > TMPBUFSIZE);
276         if (len != 0 && len <= TMPBUFSIZE)
277                 tmpbuf[len-1] = '\n';
278
279         mutex_unlock(&dom->mutex);
280
281         retval = simple_read_from_buffer(buf, count, offset, tmpbuf, len);
282
283         kfree(tmpbuf);
284         return retval;
285 }
286
287 static DEFINE_DOMAIN_DATA(active);
288
289 static int adomain_open(struct inode *inode, struct file *filp)
290 {
291         filp->private_data = &active_domains;
292         return 0;
293 }
294
295 static const struct file_operations active_domain_ops = {
296         .open           = adomain_open,
297         .read           = domain_read,
298         .write          = domain_write,
299         .llseek         = default_llseek,
300 };
301
302 static DEFINE_DOMAIN_DATA(passive);
303
304 static int pdomain_open(struct inode *inode, struct file *filp)
305 {
306         filp->private_data = &passive_domains;
307         return 0;
308 }
309
310 static const struct file_operations passive_domain_ops = {
311         .open           = pdomain_open,
312         .read           = domain_read,
313         .write          = domain_write,
314         .llseek         = default_llseek,
315 };
316
317 #endif /* CONFIG_XEN */
318
319 void oprofile_create_files(struct super_block *sb, struct dentry *root)
320 {
321         /* reinitialize default values */
322         oprofile_buffer_size =          BUFFER_SIZE_DEFAULT;
323         oprofile_cpu_buffer_size =      CPU_BUFFER_SIZE_DEFAULT;
324         oprofile_buffer_watershed =     BUFFER_WATERSHED_DEFAULT;
325         oprofile_time_slice =           msecs_to_jiffies(TIME_SLICE_DEFAULT);
326
327         oprofilefs_create_file(sb, root, "enable", &enable_fops);
328         oprofilefs_create_file_perm(sb, root, "dump", &dump_fops, 0666);
329 #ifdef CONFIG_XEN
330         oprofilefs_create_file(sb, root, "active_domains", &active_domain_ops);
331         oprofilefs_create_file(sb, root, "passive_domains", &passive_domain_ops);
332 #endif
333         oprofilefs_create_file(sb, root, "buffer", &event_buffer_fops);
334         oprofilefs_create_ulong(sb, root, "buffer_size", &oprofile_buffer_size);
335         oprofilefs_create_ulong(sb, root, "buffer_watershed", &oprofile_buffer_watershed);
336         oprofilefs_create_ulong(sb, root, "cpu_buffer_size", &oprofile_cpu_buffer_size);
337         oprofilefs_create_file(sb, root, "cpu_type", &cpu_type_fops);
338         oprofilefs_create_file(sb, root, "backtrace_depth", &depth_fops);
339         oprofilefs_create_file(sb, root, "pointer_size", &pointer_size_fops);
340 #ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX
341         oprofilefs_create_file(sb, root, "time_slice", &timeout_fops);
342 #endif
343         oprofile_create_stats_files(sb, root);
344         if (oprofile_ops.create_files)
345                 oprofile_ops.create_files(sb, root);
346 }