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 static struct inode *gatorfs_get_inode(struct super_block *sb, int mode)
24 {
25 struct inode *inode = new_inode(sb);
27 if (inode) {
28 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)
29 inode->i_ino = get_next_ino();
30 #endif
31 inode->i_mode = mode;
32 inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
33 }
34 return inode;
35 }
37 static const struct super_operations s_ops = {
38 .statfs = simple_statfs,
39 .drop_inode = generic_delete_inode,
40 };
42 ssize_t gatorfs_str_to_user(char const *str, char __user *buf, size_t count, loff_t *offset)
43 {
44 return simple_read_from_buffer(buf, count, offset, str, strlen(str));
45 }
47 ssize_t gatorfs_ulong_to_user(unsigned long val, char __user *buf, size_t count, loff_t *offset)
48 {
49 char tmpbuf[TMPBUFSIZE];
50 size_t maxlen = snprintf(tmpbuf, TMPBUFSIZE, "%lu\n", val);
51 if (maxlen > TMPBUFSIZE)
52 maxlen = TMPBUFSIZE;
53 return simple_read_from_buffer(buf, count, offset, tmpbuf, maxlen);
54 }
56 int gatorfs_ulong_from_user(unsigned long *val, char const __user *buf, size_t count)
57 {
58 char tmpbuf[TMPBUFSIZE];
59 unsigned long flags;
61 if (!count)
62 return 0;
64 if (count > TMPBUFSIZE - 1)
65 return -EINVAL;
67 memset(tmpbuf, 0x0, TMPBUFSIZE);
69 if (copy_from_user(tmpbuf, buf, count))
70 return -EFAULT;
72 spin_lock_irqsave(&gatorfs_lock, flags);
73 *val = simple_strtoul(tmpbuf, NULL, 0);
74 spin_unlock_irqrestore(&gatorfs_lock, flags);
75 return 0;
76 }
78 static ssize_t ulong_read_file(struct file *file, char __user *buf, size_t count, loff_t *offset)
79 {
80 unsigned long *val = file->private_data;
81 return gatorfs_ulong_to_user(*val, buf, count, offset);
82 }
84 static ssize_t ulong_write_file(struct file *file, char const __user *buf, size_t count, loff_t *offset)
85 {
86 unsigned long *value = file->private_data;
87 int retval;
89 if (*offset)
90 return -EINVAL;
92 retval = gatorfs_ulong_from_user(value, buf, count);
94 if (retval)
95 return retval;
96 return count;
97 }
99 static int default_open(struct inode *inode, struct file *filp)
100 {
101 if (inode->i_private)
102 filp->private_data = inode->i_private;
103 return 0;
104 }
106 static const struct file_operations ulong_fops = {
107 .read = ulong_read_file,
108 .write = ulong_write_file,
109 .open = default_open,
110 };
112 static const struct file_operations ulong_ro_fops = {
113 .read = ulong_read_file,
114 .open = default_open,
115 };
117 static struct dentry *__gatorfs_create_file(struct super_block *sb,
118 struct dentry *root, char const *name, const struct file_operations *fops,
119 int perm)
120 {
121 struct dentry *dentry;
122 struct inode *inode;
124 dentry = d_alloc_name(root, name);
125 if (!dentry)
126 return NULL;
127 inode = gatorfs_get_inode(sb, S_IFREG | perm);
128 if (!inode) {
129 dput(dentry);
130 return NULL;
131 }
132 inode->i_fop = fops;
133 d_add(dentry, inode);
134 return dentry;
135 }
137 int gatorfs_create_ulong(struct super_block *sb, struct dentry *root,
138 char const *name, unsigned long *val)
139 {
140 struct dentry *d = __gatorfs_create_file(sb, root, name,
141 &ulong_fops, 0644);
142 if (!d)
143 return -EFAULT;
145 d->d_inode->i_private = val;
146 return 0;
147 }
149 int gatorfs_create_ro_ulong(struct super_block *sb, struct dentry *root,
150 char const *name, unsigned long *val)
151 {
152 struct dentry *d = __gatorfs_create_file(sb, root, name,
153 &ulong_ro_fops, 0444);
154 if (!d)
155 return -EFAULT;
157 d->d_inode->i_private = val;
158 return 0;
159 }
161 static ssize_t atomic_read_file(struct file *file, char __user *buf, size_t count, loff_t *offset)
162 {
163 atomic_t *val = file->private_data;
164 return gatorfs_ulong_to_user(atomic_read(val), buf, count, offset);
165 }
167 static const struct file_operations atomic_ro_fops = {
168 .read = atomic_read_file,
169 .open = default_open,
170 };
172 int gatorfs_create_ro_atomic(struct super_block *sb, struct dentry *root,
173 char const *name, atomic_t *val)
174 {
175 struct dentry *d = __gatorfs_create_file(sb, root, name,
176 &atomic_ro_fops, 0444);
177 if (!d)
178 return -EFAULT;
180 d->d_inode->i_private = val;
181 return 0;
182 }
184 int gatorfs_create_file(struct super_block *sb, struct dentry *root,
185 char const *name, const struct file_operations *fops)
186 {
187 if (!__gatorfs_create_file(sb, root, name, fops, 0644))
188 return -EFAULT;
189 return 0;
190 }
192 int gatorfs_create_file_perm(struct super_block *sb, struct dentry *root,
193 char const *name, const struct file_operations *fops, int perm)
194 {
195 if (!__gatorfs_create_file(sb, root, name, fops, perm))
196 return -EFAULT;
197 return 0;
198 }
200 struct dentry *gatorfs_mkdir(struct super_block *sb,
201 struct dentry *root, char const *name)
202 {
203 struct dentry *dentry;
204 struct inode *inode;
206 dentry = d_alloc_name(root, name);
207 if (!dentry)
208 return NULL;
209 inode = gatorfs_get_inode(sb, S_IFDIR | 0755);
210 if (!inode) {
211 dput(dentry);
212 return NULL;
213 }
214 inode->i_op = &simple_dir_inode_operations;
215 inode->i_fop = &simple_dir_operations;
216 d_add(dentry, inode);
217 return dentry;
218 }
220 static int gatorfs_fill_super(struct super_block *sb, void *data, int silent)
221 {
222 struct inode *root_inode;
223 struct dentry *root_dentry;
225 sb->s_blocksize = PAGE_CACHE_SIZE;
226 sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
227 sb->s_magic = gatorfs_MAGIC;
228 sb->s_op = &s_ops;
229 sb->s_time_gran = 1;
231 root_inode = gatorfs_get_inode(sb, S_IFDIR | 0755);
232 if (!root_inode)
233 return -ENOMEM;
234 root_inode->i_op = &simple_dir_inode_operations;
235 root_inode->i_fop = &simple_dir_operations;
236 root_dentry = d_alloc_root(root_inode);
237 if (!root_dentry) {
238 iput(root_inode);
239 return -ENOMEM;
240 }
242 sb->s_root = root_dentry;
244 gator_op_create_files(sb, root_dentry);
246 // FIXME: verify kill_litter_super removes our dentries
247 return 0;
248 }
250 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39)
251 static int gatorfs_get_sb(struct file_system_type *fs_type,
252 int flags, const char *dev_name, void *data, struct vfsmount *mnt)
253 {
254 return get_sb_single(fs_type, flags, data, gatorfs_fill_super, mnt);
255 }
256 #else
257 static struct dentry *gatorfs_mount(struct file_system_type *fs_type,
258 int flags, const char *dev_name, void *data)
259 {
260 return mount_nodev(fs_type, flags, data, gatorfs_fill_super);
261 }
262 #endif
264 static struct file_system_type gatorfs_type = {
265 .owner = THIS_MODULE,
266 .name = "gatorfs",
267 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 39)
268 .get_sb = gatorfs_get_sb,
269 #else
270 .mount = gatorfs_mount,
271 #endif
273 .kill_sb = kill_litter_super,
274 };
276 int __init gatorfs_register(void)
277 {
278 return register_filesystem(&gatorfs_type);
279 }
281 void gatorfs_unregister(void)
282 {
283 unregister_filesystem(&gatorfs_type);
284 }