2 * @file oprofile_files.c
4 * @remark Copyright 2002 OProfile authors
5 * @remark Read the file COPYING
7 * @author John Levon <levon@movementarian.org>
9 * Modified by Aravind Menon for Xen
10 * These modifications are:
11 * Copyright (C) 2005 Hewlett-Packard Co.
15 #include <linux/oprofile.h>
16 #include <linux/jiffies.h>
17 #include <asm/uaccess.h>
18 #include <linux/ctype.h>
20 #include "event_buffer.h"
21 #include "oprofile_stats.h"
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
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;
34 #ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX
36 static ssize_t timeout_read(struct file *file, char __user *buf,
37 size_t count, loff_t *offset)
39 return oprofilefs_ulong_to_user(jiffies_to_msecs(oprofile_time_slice),
44 static ssize_t timeout_write(struct file *file, char const __user *buf,
45 size_t count, loff_t *offset)
53 retval = oprofilefs_ulong_from_user(&val, buf, count);
57 retval = oprofile_set_timeout(val);
65 static const struct file_operations timeout_fops = {
67 .write = timeout_write,
68 .llseek = default_llseek,
74 static ssize_t depth_read(struct file *file, char __user *buf, size_t count, loff_t *offset)
76 return oprofilefs_ulong_to_user(oprofile_backtrace_depth, buf, count,
81 static ssize_t depth_write(struct file *file, char const __user *buf, size_t count, loff_t *offset)
89 if (!oprofile_ops.backtrace)
92 retval = oprofilefs_ulong_from_user(&val, buf, count);
96 retval = oprofile_set_ulong(&oprofile_backtrace_depth, val);
104 static const struct file_operations depth_fops = {
106 .write = depth_write,
107 .llseek = default_llseek,
111 static ssize_t pointer_size_read(struct file *file, char __user *buf, size_t count, loff_t *offset)
113 return oprofilefs_ulong_to_user(sizeof(void *), buf, count, offset);
117 static const struct file_operations pointer_size_fops = {
118 .read = pointer_size_read,
119 .llseek = default_llseek,
123 static ssize_t cpu_type_read(struct file *file, char __user *buf, size_t count, loff_t *offset)
125 return oprofilefs_str_to_user(oprofile_ops.cpu_type, buf, count, offset);
129 static const struct file_operations cpu_type_fops = {
130 .read = cpu_type_read,
131 .llseek = default_llseek,
135 static ssize_t enable_read(struct file *file, char __user *buf, size_t count, loff_t *offset)
137 return oprofilefs_ulong_to_user(oprofile_started, buf, count, offset);
141 static ssize_t enable_write(struct file *file, char const __user *buf, size_t count, loff_t *offset)
149 retval = oprofilefs_ulong_from_user(&val, buf, count);
155 retval = oprofile_start();
165 static const struct file_operations enable_fops = {
167 .write = enable_write,
168 .llseek = default_llseek,
172 static ssize_t dump_write(struct file *file, char const __user *buf, size_t count, loff_t *offset)
174 wake_up_buffer_waiter();
179 static const struct file_operations dump_fops = {
181 .llseek = noop_llseek,
185 #include <linux/slab.h>
187 #define TMPBUFSIZE 512
191 int ids[MAX_OPROF_DOMAINS + 1];
193 int (*set)(int[], unsigned int);
195 #define DEFINE_DOMAIN_DATA(what) \
196 struct domain_data what##_domains = { \
197 .mutex = __MUTEX_INITIALIZER(what##_domains.mutex), \
198 .set = oprofile_set_##what \
201 static ssize_t domain_write(struct file *filp, char const __user *buf,
202 size_t count, loff_t *offset)
204 struct domain_data *dom = filp->private_data;
209 ssize_t retval = count;
213 if (count > TMPBUFSIZE - 1)
216 if (!(tmpbuf = kmalloc(TMPBUFSIZE, GFP_KERNEL)))
219 if (copy_from_user(tmpbuf, buf, count)) {
225 mutex_lock(&dom->mutex);
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);
233 while (ispunct(*endp) || isspace(*endp))
236 if (dom->ids[i] != val)
237 /* Overflow, force error below */
238 i = MAX_OPROF_DOMAINS + 1;
241 /* Force error on trailing junk */
242 dom->nr = *startp ? MAX_OPROF_DOMAINS + 1 : i;
246 if (dom->nr > MAX_OPROF_DOMAINS
247 || dom->set(dom->ids, dom->nr)) {
252 mutex_unlock(&dom->mutex);
256 static ssize_t domain_read(struct file *filp, char __user *buf,
257 size_t count, loff_t *offset)
259 struct domain_data *dom = filp->private_data;
265 if (!(tmpbuf = kmalloc(TMPBUFSIZE, GFP_KERNEL)))
268 mutex_lock(&dom->mutex);
271 for (i = 0; i < dom->nr; i++)
272 len += snprintf(tmpbuf + len,
273 len < TMPBUFSIZE ? TMPBUFSIZE - len : 0,
275 WARN_ON(len > TMPBUFSIZE);
276 if (len != 0 && len <= TMPBUFSIZE)
277 tmpbuf[len-1] = '\n';
279 mutex_unlock(&dom->mutex);
281 retval = simple_read_from_buffer(buf, count, offset, tmpbuf, len);
287 static DEFINE_DOMAIN_DATA(active);
289 static int adomain_open(struct inode *inode, struct file *filp)
291 filp->private_data = &active_domains;
295 static const struct file_operations active_domain_ops = {
296 .open = adomain_open,
298 .write = domain_write,
299 .llseek = default_llseek,
302 static DEFINE_DOMAIN_DATA(passive);
304 static int pdomain_open(struct inode *inode, struct file *filp)
306 filp->private_data = &passive_domains;
310 static const struct file_operations passive_domain_ops = {
311 .open = pdomain_open,
313 .write = domain_write,
314 .llseek = default_llseek,
317 #endif /* CONFIG_XEN */
319 void oprofile_create_files(struct super_block *sb, struct dentry *root)
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);
327 oprofilefs_create_file(sb, root, "enable", &enable_fops);
328 oprofilefs_create_file_perm(sb, root, "dump", &dump_fops, 0666);
330 oprofilefs_create_file(sb, root, "active_domains", &active_domain_ops);
331 oprofilefs_create_file(sb, root, "passive_domains", &passive_domain_ops);
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);
343 oprofile_create_stats_files(sb, root);
344 if (oprofile_ops.create_files)
345 oprofile_ops.create_files(sb, root);