1 /**
2 * @file gatorfs.c
3 *
4 * @remark Copyright 2002 OProfile authors
5 * @remark Read the file COPYING
6 *
7 * @author John Levon
8 *
9 * A simple filesystem for configuration and
10 * access of oprofile.
11 */
13 #include <linux/init.h>
14 #include <linux/module.h>
15 #include <linux/fs.h>
16 #include <linux/pagemap.h>
17 #include <asm/uaccess.h>
19 #define gatorfs_MAGIC 0x24051020
20 #define TMPBUFSIZE 50
21 DEFINE_SPINLOCK(gatorfs_lock);
23 void gator_op_create_files(struct super_block *sb, struct dentry *root);
25 static struct inode *gatorfs_get_inode(struct super_block *sb, int mode)
26 {
27 struct inode *inode = new_inode(sb);
29 if (inode) {
30 inode->i_mode = mode;
31 inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
32 }
33 return inode;
34 }
36 static const struct super_operations s_ops = {
37 .statfs = simple_statfs,
38 .drop_inode = generic_delete_inode,
39 };
41 ssize_t gatorfs_str_to_user(char const *str, char __user *buf, size_t count, loff_t *offset)
42 {
43 return simple_read_from_buffer(buf, count, offset, str, strlen(str));
44 }
46 ssize_t gatorfs_ulong_to_user(unsigned long val, char __user *buf, size_t count, loff_t *offset)
47 {
48 char tmpbuf[TMPBUFSIZE];
49 size_t maxlen = snprintf(tmpbuf, TMPBUFSIZE, "%lu\n", val);
50 if (maxlen > TMPBUFSIZE)
51 maxlen = TMPBUFSIZE;
52 return simple_read_from_buffer(buf, count, offset, tmpbuf, maxlen);
53 }
55 int gatorfs_ulong_from_user(unsigned long *val, char const __user *buf, size_t count)
56 {
57 char tmpbuf[TMPBUFSIZE];
58 unsigned long flags;
60 if (!count)
61 return 0;
63 if (count > TMPBUFSIZE - 1)
64 return -EINVAL;
66 memset(tmpbuf, 0x0, TMPBUFSIZE);
68 if (copy_from_user(tmpbuf, buf, count))
69 return -EFAULT;
71 spin_lock_irqsave(&gatorfs_lock, flags);
72 *val = simple_strtoul(tmpbuf, NULL, 0);
73 spin_unlock_irqrestore(&gatorfs_lock, flags);
74 return 0;
75 }
77 static ssize_t ulong_read_file(struct file *file, char __user *buf, size_t count, loff_t *offset)
78 {
79 unsigned long *val = file->private_data;
80 return gatorfs_ulong_to_user(*val, buf, count, offset);
81 }
83 static ssize_t ulong_write_file(struct file *file, char const __user *buf, size_t count, loff_t *offset)
84 {
85 unsigned long *value = file->private_data;
86 int retval;
88 if (*offset)
89 return -EINVAL;
91 retval = gatorfs_ulong_from_user(value, buf, count);
93 if (retval)
94 return retval;
95 return count;
96 }
98 static int default_open(struct inode *inode, struct file *filp)
99 {
100 if (inode->i_private)
101 filp->private_data = inode->i_private;
102 return 0;
103 }
105 static const struct file_operations ulong_fops = {
106 .read = ulong_read_file,
107 .write = ulong_write_file,
108 .open = default_open,
109 };
111 static const struct file_operations ulong_ro_fops = {
112 .read = ulong_read_file,
113 .open = default_open,
114 };
116 static struct dentry *__gatorfs_create_file(struct super_block *sb,
117 struct dentry *root, char const *name, const struct file_operations *fops,
118 int perm)
119 {
120 struct dentry *dentry;
121 struct inode *inode;
123 dentry = d_alloc_name(root, name);
124 if (!dentry)
125 return NULL;
126 inode = gatorfs_get_inode(sb, S_IFREG | perm);
127 if (!inode) {
128 dput(dentry);
129 return NULL;
130 }
131 inode->i_fop = fops;
132 d_add(dentry, inode);
133 return dentry;
134 }
136 int gatorfs_create_ulong(struct super_block *sb, struct dentry *root,
137 char const *name, unsigned long *val)
138 {
139 struct dentry *d = __gatorfs_create_file(sb, root, name,
140 &ulong_fops, 0644);
141 if (!d)
142 return -EFAULT;
144 d->d_inode->i_private = val;
145 return 0;
146 }
148 int gatorfs_create_ro_ulong(struct super_block *sb, struct dentry *root,
149 char const *name, unsigned long *val)
150 {
151 struct dentry *d = __gatorfs_create_file(sb, root, name,
152 &ulong_ro_fops, 0444);
153 if (!d)
154 return -EFAULT;
156 d->d_inode->i_private = val;
157 return 0;
158 }
160 static ssize_t atomic_read_file(struct file *file, char __user *buf, size_t count, loff_t *offset)
161 {
162 atomic_t *val = file->private_data;
163 return gatorfs_ulong_to_user(atomic_read(val), buf, count, offset);
164 }
166 static const struct file_operations atomic_ro_fops = {
167 .read = atomic_read_file,
168 .open = default_open,
169 };
171 int gatorfs_create_ro_atomic(struct super_block *sb, struct dentry *root,
172 char const *name, atomic_t *val)
173 {
174 struct dentry *d = __gatorfs_create_file(sb, root, name,
175 &atomic_ro_fops, 0444);
176 if (!d)
177 return -EFAULT;
179 d->d_inode->i_private = val;
180 return 0;
181 }
183 int gatorfs_create_file(struct super_block *sb, struct dentry *root,
184 char const *name, const struct file_operations *fops)
185 {
186 if (!__gatorfs_create_file(sb, root, name, fops, 0644))
187 return -EFAULT;
188 return 0;
189 }
191 int gatorfs_create_file_perm(struct super_block *sb, struct dentry *root,
192 char const *name, const struct file_operations *fops, int perm)
193 {
194 if (!__gatorfs_create_file(sb, root, name, fops, perm))
195 return -EFAULT;
196 return 0;
197 }
199 struct dentry *gatorfs_mkdir(struct super_block *sb,
200 struct dentry *root, char const *name)
201 {
202 struct dentry *dentry;
203 struct inode *inode;
205 dentry = d_alloc_name(root, name);
206 if (!dentry)
207 return NULL;
208 inode = gatorfs_get_inode(sb, S_IFDIR | 0755);
209 if (!inode) {
210 dput(dentry);
211 return NULL;
212 }
213 inode->i_op = &simple_dir_inode_operations;
214 inode->i_fop = &simple_dir_operations;
215 d_add(dentry, inode);
216 return dentry;
217 }
219 static int gatorfs_fill_super(struct super_block *sb, void *data, int silent)
220 {
221 struct inode *root_inode;
222 struct dentry *root_dentry;
224 sb->s_blocksize = PAGE_CACHE_SIZE;
225 sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
226 sb->s_magic = gatorfs_MAGIC;
227 sb->s_op = &s_ops;
228 sb->s_time_gran = 1;
230 root_inode = gatorfs_get_inode(sb, S_IFDIR | 0755);
231 if (!root_inode)
232 return -ENOMEM;
233 root_inode->i_op = &simple_dir_inode_operations;
234 root_inode->i_fop = &simple_dir_operations;
235 root_dentry = d_alloc_root(root_inode);
236 if (!root_dentry) {
237 iput(root_inode);
238 return -ENOMEM;
239 }
241 sb->s_root = root_dentry;
243 gator_op_create_files(sb, root_dentry);
245 // FIXME: verify kill_litter_super removes our dentries
246 return 0;
247 }
249 static int gatorfs_get_sb(struct file_system_type *fs_type,
250 int flags, const char *dev_name, void *data, struct vfsmount *mnt)
251 {
252 return get_sb_single(fs_type, flags, data, gatorfs_fill_super, mnt);
253 }
255 static struct file_system_type gatorfs_type = {
256 .owner = THIS_MODULE,
257 .name = "gatorfs",
258 .get_sb = gatorfs_get_sb,
259 .kill_sb = kill_litter_super,
260 };
262 int __init gatorfs_register(void)
263 {
264 return register_filesystem(&gatorfs_type);
265 }
267 void gatorfs_unregister(void)
268 {
269 unregister_filesystem(&gatorfs_type);
270 }