xref: /OK3568_Linux_fs/kernel/drivers/oprofile/oprofilefs.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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