1*4882a593Smuzhiyun /**
2*4882a593Smuzhiyun * @file oprofilefs.c
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * @remark Copyright 2002 OProfile authors
5*4882a593Smuzhiyun * @remark Read the file COPYING
6*4882a593Smuzhiyun *
7*4882a593Smuzhiyun * @author John Levon
8*4882a593Smuzhiyun *
9*4882a593Smuzhiyun * A simple filesystem for configuration and
10*4882a593Smuzhiyun * access of oprofile.
11*4882a593Smuzhiyun */
12*4882a593Smuzhiyun
13*4882a593Smuzhiyun #include <linux/init.h>
14*4882a593Smuzhiyun #include <linux/module.h>
15*4882a593Smuzhiyun #include <linux/oprofile.h>
16*4882a593Smuzhiyun #include <linux/fs.h>
17*4882a593Smuzhiyun #include <linux/fs_context.h>
18*4882a593Smuzhiyun #include <linux/pagemap.h>
19*4882a593Smuzhiyun #include <linux/uaccess.h>
20*4882a593Smuzhiyun
21*4882a593Smuzhiyun #include "oprof.h"
22*4882a593Smuzhiyun
23*4882a593Smuzhiyun #define OPROFILEFS_MAGIC 0x6f70726f
24*4882a593Smuzhiyun
25*4882a593Smuzhiyun DEFINE_RAW_SPINLOCK(oprofilefs_lock);
26*4882a593Smuzhiyun
oprofilefs_get_inode(struct super_block * sb,int mode)27*4882a593Smuzhiyun static struct inode *oprofilefs_get_inode(struct super_block *sb, int mode)
28*4882a593Smuzhiyun {
29*4882a593Smuzhiyun struct inode *inode = new_inode(sb);
30*4882a593Smuzhiyun
31*4882a593Smuzhiyun if (inode) {
32*4882a593Smuzhiyun inode->i_ino = get_next_ino();
33*4882a593Smuzhiyun inode->i_mode = mode;
34*4882a593Smuzhiyun inode->i_atime = inode->i_mtime = inode->i_ctime = current_time(inode);
35*4882a593Smuzhiyun }
36*4882a593Smuzhiyun return inode;
37*4882a593Smuzhiyun }
38*4882a593Smuzhiyun
39*4882a593Smuzhiyun
40*4882a593Smuzhiyun static const struct super_operations s_ops = {
41*4882a593Smuzhiyun .statfs = simple_statfs,
42*4882a593Smuzhiyun .drop_inode = generic_delete_inode,
43*4882a593Smuzhiyun };
44*4882a593Smuzhiyun
45*4882a593Smuzhiyun
oprofilefs_str_to_user(char const * str,char __user * buf,size_t count,loff_t * offset)46*4882a593Smuzhiyun ssize_t oprofilefs_str_to_user(char const *str, char __user *buf, size_t count, loff_t *offset)
47*4882a593Smuzhiyun {
48*4882a593Smuzhiyun return simple_read_from_buffer(buf, count, offset, str, strlen(str));
49*4882a593Smuzhiyun }
50*4882a593Smuzhiyun
51*4882a593Smuzhiyun
52*4882a593Smuzhiyun #define TMPBUFSIZE 50
53*4882a593Smuzhiyun
oprofilefs_ulong_to_user(unsigned long val,char __user * buf,size_t count,loff_t * offset)54*4882a593Smuzhiyun ssize_t oprofilefs_ulong_to_user(unsigned long val, char __user *buf, size_t count, loff_t *offset)
55*4882a593Smuzhiyun {
56*4882a593Smuzhiyun char tmpbuf[TMPBUFSIZE];
57*4882a593Smuzhiyun size_t maxlen = snprintf(tmpbuf, TMPBUFSIZE, "%lu\n", val);
58*4882a593Smuzhiyun if (maxlen > TMPBUFSIZE)
59*4882a593Smuzhiyun maxlen = TMPBUFSIZE;
60*4882a593Smuzhiyun return simple_read_from_buffer(buf, count, offset, tmpbuf, maxlen);
61*4882a593Smuzhiyun }
62*4882a593Smuzhiyun
63*4882a593Smuzhiyun
64*4882a593Smuzhiyun /*
65*4882a593Smuzhiyun * Note: If oprofilefs_ulong_from_user() returns 0, then *val remains
66*4882a593Smuzhiyun * unchanged and might be uninitialized. This follows write syscall
67*4882a593Smuzhiyun * implementation when count is zero: "If count is zero ... [and if]
68*4882a593Smuzhiyun * no errors are detected, 0 will be returned without causing any
69*4882a593Smuzhiyun * other effect." (man 2 write)
70*4882a593Smuzhiyun */
oprofilefs_ulong_from_user(unsigned long * val,char const __user * buf,size_t count)71*4882a593Smuzhiyun int oprofilefs_ulong_from_user(unsigned long *val, char const __user *buf, size_t count)
72*4882a593Smuzhiyun {
73*4882a593Smuzhiyun char tmpbuf[TMPBUFSIZE];
74*4882a593Smuzhiyun unsigned long flags;
75*4882a593Smuzhiyun
76*4882a593Smuzhiyun if (!count)
77*4882a593Smuzhiyun return 0;
78*4882a593Smuzhiyun
79*4882a593Smuzhiyun if (count > TMPBUFSIZE - 1)
80*4882a593Smuzhiyun return -EINVAL;
81*4882a593Smuzhiyun
82*4882a593Smuzhiyun memset(tmpbuf, 0x0, TMPBUFSIZE);
83*4882a593Smuzhiyun
84*4882a593Smuzhiyun if (copy_from_user(tmpbuf, buf, count))
85*4882a593Smuzhiyun return -EFAULT;
86*4882a593Smuzhiyun
87*4882a593Smuzhiyun raw_spin_lock_irqsave(&oprofilefs_lock, flags);
88*4882a593Smuzhiyun *val = simple_strtoul(tmpbuf, NULL, 0);
89*4882a593Smuzhiyun raw_spin_unlock_irqrestore(&oprofilefs_lock, flags);
90*4882a593Smuzhiyun return count;
91*4882a593Smuzhiyun }
92*4882a593Smuzhiyun
93*4882a593Smuzhiyun
ulong_read_file(struct file * file,char __user * buf,size_t count,loff_t * offset)94*4882a593Smuzhiyun static ssize_t ulong_read_file(struct file *file, char __user *buf, size_t count, loff_t *offset)
95*4882a593Smuzhiyun {
96*4882a593Smuzhiyun unsigned long *val = file->private_data;
97*4882a593Smuzhiyun return oprofilefs_ulong_to_user(*val, buf, count, offset);
98*4882a593Smuzhiyun }
99*4882a593Smuzhiyun
100*4882a593Smuzhiyun
ulong_write_file(struct file * file,char const __user * buf,size_t count,loff_t * offset)101*4882a593Smuzhiyun static ssize_t ulong_write_file(struct file *file, char const __user *buf, size_t count, loff_t *offset)
102*4882a593Smuzhiyun {
103*4882a593Smuzhiyun unsigned long value;
104*4882a593Smuzhiyun int retval;
105*4882a593Smuzhiyun
106*4882a593Smuzhiyun if (*offset)
107*4882a593Smuzhiyun return -EINVAL;
108*4882a593Smuzhiyun
109*4882a593Smuzhiyun retval = oprofilefs_ulong_from_user(&value, buf, count);
110*4882a593Smuzhiyun if (retval <= 0)
111*4882a593Smuzhiyun return retval;
112*4882a593Smuzhiyun
113*4882a593Smuzhiyun retval = oprofile_set_ulong(file->private_data, value);
114*4882a593Smuzhiyun if (retval)
115*4882a593Smuzhiyun return retval;
116*4882a593Smuzhiyun
117*4882a593Smuzhiyun return count;
118*4882a593Smuzhiyun }
119*4882a593Smuzhiyun
120*4882a593Smuzhiyun
121*4882a593Smuzhiyun static const struct file_operations ulong_fops = {
122*4882a593Smuzhiyun .read = ulong_read_file,
123*4882a593Smuzhiyun .write = ulong_write_file,
124*4882a593Smuzhiyun .open = simple_open,
125*4882a593Smuzhiyun .llseek = default_llseek,
126*4882a593Smuzhiyun };
127*4882a593Smuzhiyun
128*4882a593Smuzhiyun
129*4882a593Smuzhiyun static const struct file_operations ulong_ro_fops = {
130*4882a593Smuzhiyun .read = ulong_read_file,
131*4882a593Smuzhiyun .open = simple_open,
132*4882a593Smuzhiyun .llseek = default_llseek,
133*4882a593Smuzhiyun };
134*4882a593Smuzhiyun
135*4882a593Smuzhiyun
__oprofilefs_create_file(struct dentry * root,char const * name,const struct file_operations * fops,int perm,void * priv)136*4882a593Smuzhiyun static int __oprofilefs_create_file(struct dentry *root, char const *name,
137*4882a593Smuzhiyun const struct file_operations *fops, int perm, void *priv)
138*4882a593Smuzhiyun {
139*4882a593Smuzhiyun struct dentry *dentry;
140*4882a593Smuzhiyun struct inode *inode;
141*4882a593Smuzhiyun
142*4882a593Smuzhiyun if (!root)
143*4882a593Smuzhiyun return -ENOMEM;
144*4882a593Smuzhiyun
145*4882a593Smuzhiyun inode_lock(d_inode(root));
146*4882a593Smuzhiyun dentry = d_alloc_name(root, name);
147*4882a593Smuzhiyun if (!dentry) {
148*4882a593Smuzhiyun inode_unlock(d_inode(root));
149*4882a593Smuzhiyun return -ENOMEM;
150*4882a593Smuzhiyun }
151*4882a593Smuzhiyun inode = oprofilefs_get_inode(root->d_sb, S_IFREG | perm);
152*4882a593Smuzhiyun if (!inode) {
153*4882a593Smuzhiyun dput(dentry);
154*4882a593Smuzhiyun inode_unlock(d_inode(root));
155*4882a593Smuzhiyun return -ENOMEM;
156*4882a593Smuzhiyun }
157*4882a593Smuzhiyun inode->i_fop = fops;
158*4882a593Smuzhiyun inode->i_private = priv;
159*4882a593Smuzhiyun d_add(dentry, inode);
160*4882a593Smuzhiyun inode_unlock(d_inode(root));
161*4882a593Smuzhiyun return 0;
162*4882a593Smuzhiyun }
163*4882a593Smuzhiyun
164*4882a593Smuzhiyun
oprofilefs_create_ulong(struct dentry * root,char const * name,unsigned long * val)165*4882a593Smuzhiyun int oprofilefs_create_ulong(struct dentry *root,
166*4882a593Smuzhiyun char const *name, unsigned long *val)
167*4882a593Smuzhiyun {
168*4882a593Smuzhiyun return __oprofilefs_create_file(root, name,
169*4882a593Smuzhiyun &ulong_fops, 0644, val);
170*4882a593Smuzhiyun }
171*4882a593Smuzhiyun
172*4882a593Smuzhiyun
oprofilefs_create_ro_ulong(struct dentry * root,char const * name,unsigned long * val)173*4882a593Smuzhiyun int oprofilefs_create_ro_ulong(struct dentry *root,
174*4882a593Smuzhiyun char const *name, unsigned long *val)
175*4882a593Smuzhiyun {
176*4882a593Smuzhiyun return __oprofilefs_create_file(root, name,
177*4882a593Smuzhiyun &ulong_ro_fops, 0444, val);
178*4882a593Smuzhiyun }
179*4882a593Smuzhiyun
180*4882a593Smuzhiyun
atomic_read_file(struct file * file,char __user * buf,size_t count,loff_t * offset)181*4882a593Smuzhiyun static ssize_t atomic_read_file(struct file *file, char __user *buf, size_t count, loff_t *offset)
182*4882a593Smuzhiyun {
183*4882a593Smuzhiyun atomic_t *val = file->private_data;
184*4882a593Smuzhiyun return oprofilefs_ulong_to_user(atomic_read(val), buf, count, offset);
185*4882a593Smuzhiyun }
186*4882a593Smuzhiyun
187*4882a593Smuzhiyun
188*4882a593Smuzhiyun static const struct file_operations atomic_ro_fops = {
189*4882a593Smuzhiyun .read = atomic_read_file,
190*4882a593Smuzhiyun .open = simple_open,
191*4882a593Smuzhiyun .llseek = default_llseek,
192*4882a593Smuzhiyun };
193*4882a593Smuzhiyun
194*4882a593Smuzhiyun
oprofilefs_create_ro_atomic(struct dentry * root,char const * name,atomic_t * val)195*4882a593Smuzhiyun int oprofilefs_create_ro_atomic(struct dentry *root,
196*4882a593Smuzhiyun char const *name, atomic_t *val)
197*4882a593Smuzhiyun {
198*4882a593Smuzhiyun return __oprofilefs_create_file(root, name,
199*4882a593Smuzhiyun &atomic_ro_fops, 0444, val);
200*4882a593Smuzhiyun }
201*4882a593Smuzhiyun
202*4882a593Smuzhiyun
oprofilefs_create_file(struct dentry * root,char const * name,const struct file_operations * fops)203*4882a593Smuzhiyun int oprofilefs_create_file(struct dentry *root,
204*4882a593Smuzhiyun char const *name, const struct file_operations *fops)
205*4882a593Smuzhiyun {
206*4882a593Smuzhiyun return __oprofilefs_create_file(root, name, fops, 0644, NULL);
207*4882a593Smuzhiyun }
208*4882a593Smuzhiyun
209*4882a593Smuzhiyun
oprofilefs_create_file_perm(struct dentry * root,char const * name,const struct file_operations * fops,int perm)210*4882a593Smuzhiyun int oprofilefs_create_file_perm(struct dentry *root,
211*4882a593Smuzhiyun char const *name, const struct file_operations *fops, int perm)
212*4882a593Smuzhiyun {
213*4882a593Smuzhiyun return __oprofilefs_create_file(root, name, fops, perm, NULL);
214*4882a593Smuzhiyun }
215*4882a593Smuzhiyun
216*4882a593Smuzhiyun
oprofilefs_mkdir(struct dentry * parent,char const * name)217*4882a593Smuzhiyun struct dentry *oprofilefs_mkdir(struct dentry *parent, char const *name)
218*4882a593Smuzhiyun {
219*4882a593Smuzhiyun struct dentry *dentry;
220*4882a593Smuzhiyun struct inode *inode;
221*4882a593Smuzhiyun
222*4882a593Smuzhiyun inode_lock(d_inode(parent));
223*4882a593Smuzhiyun dentry = d_alloc_name(parent, name);
224*4882a593Smuzhiyun if (!dentry) {
225*4882a593Smuzhiyun inode_unlock(d_inode(parent));
226*4882a593Smuzhiyun return NULL;
227*4882a593Smuzhiyun }
228*4882a593Smuzhiyun inode = oprofilefs_get_inode(parent->d_sb, S_IFDIR | 0755);
229*4882a593Smuzhiyun if (!inode) {
230*4882a593Smuzhiyun dput(dentry);
231*4882a593Smuzhiyun inode_unlock(d_inode(parent));
232*4882a593Smuzhiyun return NULL;
233*4882a593Smuzhiyun }
234*4882a593Smuzhiyun inode->i_op = &simple_dir_inode_operations;
235*4882a593Smuzhiyun inode->i_fop = &simple_dir_operations;
236*4882a593Smuzhiyun d_add(dentry, inode);
237*4882a593Smuzhiyun inode_unlock(d_inode(parent));
238*4882a593Smuzhiyun return dentry;
239*4882a593Smuzhiyun }
240*4882a593Smuzhiyun
241*4882a593Smuzhiyun
oprofilefs_fill_super(struct super_block * sb,struct fs_context * fc)242*4882a593Smuzhiyun static int oprofilefs_fill_super(struct super_block *sb, struct fs_context *fc)
243*4882a593Smuzhiyun {
244*4882a593Smuzhiyun struct inode *root_inode;
245*4882a593Smuzhiyun
246*4882a593Smuzhiyun sb->s_blocksize = PAGE_SIZE;
247*4882a593Smuzhiyun sb->s_blocksize_bits = PAGE_SHIFT;
248*4882a593Smuzhiyun sb->s_magic = OPROFILEFS_MAGIC;
249*4882a593Smuzhiyun sb->s_op = &s_ops;
250*4882a593Smuzhiyun sb->s_time_gran = 1;
251*4882a593Smuzhiyun
252*4882a593Smuzhiyun root_inode = oprofilefs_get_inode(sb, S_IFDIR | 0755);
253*4882a593Smuzhiyun if (!root_inode)
254*4882a593Smuzhiyun return -ENOMEM;
255*4882a593Smuzhiyun root_inode->i_op = &simple_dir_inode_operations;
256*4882a593Smuzhiyun root_inode->i_fop = &simple_dir_operations;
257*4882a593Smuzhiyun sb->s_root = d_make_root(root_inode);
258*4882a593Smuzhiyun if (!sb->s_root)
259*4882a593Smuzhiyun return -ENOMEM;
260*4882a593Smuzhiyun
261*4882a593Smuzhiyun oprofile_create_files(sb->s_root);
262*4882a593Smuzhiyun
263*4882a593Smuzhiyun // FIXME: verify kill_litter_super removes our dentries
264*4882a593Smuzhiyun return 0;
265*4882a593Smuzhiyun }
266*4882a593Smuzhiyun
oprofilefs_get_tree(struct fs_context * fc)267*4882a593Smuzhiyun static int oprofilefs_get_tree(struct fs_context *fc)
268*4882a593Smuzhiyun {
269*4882a593Smuzhiyun return get_tree_single(fc, oprofilefs_fill_super);
270*4882a593Smuzhiyun }
271*4882a593Smuzhiyun
272*4882a593Smuzhiyun static const struct fs_context_operations oprofilefs_context_ops = {
273*4882a593Smuzhiyun .get_tree = oprofilefs_get_tree,
274*4882a593Smuzhiyun };
275*4882a593Smuzhiyun
oprofilefs_init_fs_context(struct fs_context * fc)276*4882a593Smuzhiyun static int oprofilefs_init_fs_context(struct fs_context *fc)
277*4882a593Smuzhiyun {
278*4882a593Smuzhiyun fc->ops = &oprofilefs_context_ops;
279*4882a593Smuzhiyun return 0;
280*4882a593Smuzhiyun }
281*4882a593Smuzhiyun
282*4882a593Smuzhiyun static struct file_system_type oprofilefs_type = {
283*4882a593Smuzhiyun .owner = THIS_MODULE,
284*4882a593Smuzhiyun .name = "oprofilefs",
285*4882a593Smuzhiyun .init_fs_context = oprofilefs_init_fs_context,
286*4882a593Smuzhiyun .kill_sb = kill_litter_super,
287*4882a593Smuzhiyun };
288*4882a593Smuzhiyun MODULE_ALIAS_FS("oprofilefs");
289*4882a593Smuzhiyun
290*4882a593Smuzhiyun
oprofilefs_register(void)291*4882a593Smuzhiyun int __init oprofilefs_register(void)
292*4882a593Smuzhiyun {
293*4882a593Smuzhiyun return register_filesystem(&oprofilefs_type);
294*4882a593Smuzhiyun }
295*4882a593Smuzhiyun
296*4882a593Smuzhiyun
oprofilefs_unregister(void)297*4882a593Smuzhiyun void __exit oprofilefs_unregister(void)
298*4882a593Smuzhiyun {
299*4882a593Smuzhiyun unregister_filesystem(&oprofilefs_type);
300*4882a593Smuzhiyun }
301