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
10#include <linux/fs.h>
11#include <linux/oprofile.h>
12
13#include "event_buffer.h"
14#include "oprofile_stats.h"
15#include "oprof.h"
16
17unsigned long fs_buffer_size = 131072;
18unsigned long fs_cpu_buffer_size = 8192;
19unsigned long fs_buffer_watershed = 32768;
20
21static ssize_t depth_read(struct file * file, char __user * buf, size_t count, loff_t * offset)
22{
23	return oprofilefs_ulong_to_user(backtrace_depth, buf, count, offset);
24}
25
26
27static ssize_t depth_write(struct file * file, char const __user * buf, size_t count, loff_t * offset)
28{
29	unsigned long val;
30	int retval;
31
32	if (*offset)
33		return -EINVAL;
34
35	retval = oprofilefs_ulong_from_user(&val, buf, count);
36	if (retval)
37		return retval;
38
39	retval = oprofile_set_backtrace(val);
40
41	if (retval)
42		return retval;
43	return count;
44}
45
46
47static const struct file_operations depth_fops = {
48	.read		= depth_read,
49	.write		= depth_write
50};
51
52
53static ssize_t pointer_size_read(struct file * file, char __user * buf, size_t count, loff_t * offset)
54{
55	return oprofilefs_ulong_to_user(sizeof(void *), buf, count, offset);
56}
57
58
59static const struct file_operations pointer_size_fops = {
60	.read		= pointer_size_read,
61};
62
63
64static ssize_t cpu_type_read(struct file * file, char __user * buf, size_t count, loff_t * offset)
65{
66	return oprofilefs_str_to_user(oprofile_ops.cpu_type, buf, count, offset);
67}
68
69
70static const struct file_operations cpu_type_fops = {
71	.read		= cpu_type_read,
72};
73
74
75static ssize_t enable_read(struct file * file, char __user * buf, size_t count, loff_t * offset)
76{
77	return oprofilefs_ulong_to_user(oprofile_started, buf, count, offset);
78}
79
80
81static ssize_t enable_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	retval = oprofilefs_ulong_from_user(&val, buf, count);
90	if (retval)
91		return retval;
92
93	if (val)
94		retval = oprofile_start();
95	else
96		oprofile_stop();
97
98	if (retval)
99		return retval;
100	return count;
101}
102
103
104static const struct file_operations enable_fops = {
105	.read		= enable_read,
106	.write		= enable_write,
107};
108
109
110static ssize_t dump_write(struct file * file, char const __user * buf, size_t count, loff_t * offset)
111{
112	wake_up_buffer_waiter();
113	return count;
114}
115
116
117static const struct file_operations dump_fops = {
118	.write		= dump_write,
119};
120
121void oprofile_create_files(struct super_block * sb, struct dentry * root)
122{
123	oprofilefs_create_file(sb, root, "enable", &enable_fops);
124	oprofilefs_create_file_perm(sb, root, "dump", &dump_fops, 0666);
125	oprofilefs_create_file(sb, root, "buffer", &event_buffer_fops);
126	oprofilefs_create_ulong(sb, root, "buffer_size", &fs_buffer_size);
127	oprofilefs_create_ulong(sb, root, "buffer_watershed", &fs_buffer_watershed);
128	oprofilefs_create_ulong(sb, root, "cpu_buffer_size", &fs_cpu_buffer_size);
129	oprofilefs_create_file(sb, root, "cpu_type", &cpu_type_fops);
130	oprofilefs_create_file(sb, root, "backtrace_depth", &depth_fops);
131	oprofilefs_create_file(sb, root, "pointer_size", &pointer_size_fops);
132	oprofile_create_stats_files(sb, root);
133	if (oprofile_ops.create_files)
134		oprofile_ops.create_files(sb, root);
135}
136