This commit was manufactured by cvs2svn to create tag
[linux-2.6.git] / kernel / ckrm / rbce / rbce_fs.c
1 /*
2  * This file is released under the GPL.
3  */
4 #include <linux/fs.h>
5 #include <linux/init.h>
6 #include <linux/errno.h>
7 #include <linux/proc_fs.h>
8 #include <linux/ctype.h>
9 #include <linux/module.h>
10 #include <linux/seq_file.h>
11 #include <linux/pagemap.h>
12 #include <linux/highmem.h>
13 #include <linux/string.h>
14 #include <linux/smp_lock.h>
15 #include <linux/mount.h>
16 #include <linux/backing-dev.h>
17 #include <asm/uaccess.h>
18 #include <linux/rcfs.h>
19
20 extern int rbce_enabled;
21 extern void get_rule(const char *, char *);
22 extern int rule_exists(const char *);
23 extern int change_rule(const char *, char *);
24 extern int delete_rule(const char *);
25 //extern int reclassify_pid(int);
26 extern int set_tasktag(int, char *);
27 extern int rename_rule(const char *, const char *);
28
29 extern int rcfs_register_engine(rbce_eng_callback_t * rcbs);
30 extern int rcfs_unregister_engine(rbce_eng_callback_t * rcbs);
31 extern int rcfs_mkroot(struct rcfs_magf *, int, struct dentry **);
32 extern int rcfs_rmroot(struct dentry *);
33
34 static int rbce_unlink(struct inode *, struct dentry *);
35
36 #include "info.h"
37 static ssize_t
38 rbce_write(struct file *file, const char __user * buf,
39            size_t len, loff_t * ppos)
40 {
41         char *line, *ptr;
42         int rc = 0, pid;
43
44         line = (char *)kmalloc(len + 1, GFP_KERNEL);
45         if (!line) {
46                 return -ENOMEM;
47         }
48         if (copy_from_user(line, buf, len)) {
49                 kfree(line);
50                 return -EFAULT;
51         }
52         line[len] = '\0';
53         ptr = line + strlen(line) - 1;
54         if (*ptr == '\n') {
55                 *ptr = '\0';
56         }
57 #if 0
58         if (!strcmp(file->f_dentry->d_name.name, "rbce_reclassify")) {
59                 pid = simple_strtol(line, NULL, 0);
60                 rc = reclassify_pid(pid);
61         } else
62 #endif
63         if (!strcmp(file->f_dentry->d_name.name, "rbce_tag")) {
64                 pid = simple_strtol(line, &ptr, 0);
65                 rc = set_tasktag(pid, ptr + 1); // expected syntax "pid tag"
66         } else if (!strcmp(file->f_dentry->d_name.name, "rbce_state")) {
67                 rbce_enabled = line[0] - '0';
68         } else if (!strcmp(file->f_dentry->d_name.name, "rbce_info")) {
69                 len = -EPERM;
70         } else {
71                 rc = change_rule(file->f_dentry->d_name.name, line);
72         }
73         if (rc) {
74                 len = rc;
75         }
76         // printk("kernel read |%s|\n", line);
77         // printk("kernel read-2 |%s|\n", line+1000);
78         // printk prints only 1024 bytes once :)
79         //
80         kfree(line);
81         return len;
82 }
83
84 static int rbce_show(struct seq_file *seq, void *offset)
85 {
86         struct file *file = (struct file *)seq->private;
87         char result[256];
88
89         memset(result, 0, 256);
90         if (!strcmp(file->f_dentry->d_name.name, "rbce_reclassify") ||
91             !strcmp(file->f_dentry->d_name.name, "rbce_tag")) {
92                 return -EPERM;
93         }
94         if (!strcmp(file->f_dentry->d_name.name, "rbce_state")) {
95                 seq_printf(seq, "%d\n", rbce_enabled);
96                 return 0;
97         }
98         if (!strcmp(file->f_dentry->d_name.name, "rbce_info")) {
99                 seq_printf(seq, info);
100                 return 0;
101         }
102
103         get_rule(file->f_dentry->d_name.name, result);
104         seq_printf(seq, "%s\n", result);
105         return 0;
106 }
107
108 static int rbce_open(struct inode *inode, struct file *file)
109 {
110         //printk("mnt_mountpoint %s\n", 
111         //              file->f_vfsmnt->mnt_mountpoint->d_name.name);
112         //printk("mnt_root %s\n", file->f_vfsmnt->mnt_root->d_name.name);
113         return single_open(file, rbce_show, file);
114 }
115
116 static int rbce_close(struct inode *ino, struct file *file)
117 {
118         const char *name = file->f_dentry->d_name.name;
119
120         if (strcmp(name, "rbce_reclassify") &&
121             strcmp(name, "rbce_state") &&
122             strcmp(name, "rbce_tag") && strcmp(name, "rbce_info")) {
123
124                 if (!rule_exists(name)) {
125                         // need more stuff to happen in the vfs layer
126                         rbce_unlink(file->f_dentry->d_parent->d_inode,
127                                     file->f_dentry);
128                 }
129         }
130         return single_release(ino, file);
131 }
132
133 #define RCFS_MAGIC 0x4feedbac
134
135 static struct file_operations rbce_file_operations;
136 static struct inode_operations rbce_file_inode_operations;
137 static struct inode_operations rbce_dir_inode_operations;
138
139 static struct inode *rbce_get_inode(struct inode *dir, int mode, dev_t dev)
140 {
141         struct inode *inode = new_inode(dir->i_sb);
142
143         if (inode) {
144                 inode->i_mode = mode;
145                 inode->i_uid = current->fsuid;
146                 inode->i_gid = current->fsgid;
147                 inode->i_blksize = PAGE_CACHE_SIZE;
148                 inode->i_blocks = 0;
149                 inode->i_mapping->a_ops = dir->i_mapping->a_ops;
150                 inode->i_mapping->backing_dev_info =
151                     dir->i_mapping->backing_dev_info;
152                 inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
153                 switch (mode & S_IFMT) {
154                 default:
155                         init_special_inode(inode, mode, dev);
156                         break;
157                 case S_IFREG:
158                         /* Treat as default assignment */
159                         inode->i_op = &rbce_file_inode_operations;
160                         inode->i_fop = &rbce_file_operations;
161                         break;
162                 case S_IFDIR:
163                         inode->i_op = &rbce_dir_inode_operations;
164                         inode->i_fop = &simple_dir_operations;
165
166                         /* directory inodes start off with i_nlink == 2 
167                            (for "." entry) */
168                         inode->i_nlink++;
169                         break;
170                 }
171         }
172         return inode;
173 }
174
175 /*
176  * File creation. Allocate an inode, and we're done..
177  */
178 /* SMP-safe */
179 static int
180 rbce_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
181 {
182         struct inode *inode = rbce_get_inode(dir, mode, dev);
183         int error = -ENOSPC;
184
185         if (inode) {
186                 if (dir->i_mode & S_ISGID) {
187                         inode->i_gid = dir->i_gid;
188                         if (S_ISDIR(mode))
189                                 inode->i_mode |= S_ISGID;
190                 }
191                 d_instantiate(dentry, inode);
192                 dget(dentry);   /* Extra count - pin the dentry in core */
193                 error = 0;
194
195         }
196         return error;
197 }
198
199 static int rbce_unlink(struct inode *dir, struct dentry *dentry)
200 {
201         struct inode *inode = dentry->d_inode;
202         int rc;
203
204         rc = delete_rule(dentry->d_name.name);
205         if (rc == 0) {
206                 if (dir) {
207                         dir->i_ctime = dir->i_mtime = CURRENT_TIME;
208                 }
209                 inode->i_ctime = CURRENT_TIME;
210                 inode->i_nlink--;
211                 dput(dentry);
212         }
213         return rc;
214 }
215
216 static int
217 rbce_rename(struct inode *old_dir, struct dentry *old_dentry,
218             struct inode *new_dir, struct dentry *new_dentry)
219 {
220         int rc;
221         struct inode *inode = old_dentry->d_inode;
222         struct dentry *old_d = list_entry(old_dir->i_dentry.next,
223                                           struct dentry, d_alias);
224         struct dentry *new_d = list_entry(new_dir->i_dentry.next,
225                                           struct dentry, d_alias);
226
227         // cannot rename any directory
228         if (S_ISDIR(old_dentry->d_inode->i_mode)) {
229                 return -EINVAL;
230         }
231         // cannot rename anything under /ce
232         if (!strcmp(old_d->d_name.name, "ce")) {
233                 return -EINVAL;
234         }
235         // cannot move anything to /ce
236         if (!strcmp(new_d->d_name.name, "ce")) {
237                 return -EINVAL;
238         }
239
240         rc = rename_rule(old_dentry->d_name.name, new_dentry->d_name.name);
241
242         if (!rc) {
243                 old_dir->i_ctime = old_dir->i_mtime = new_dir->i_ctime =
244                     new_dir->i_mtime = inode->i_ctime = CURRENT_TIME;
245         }
246         return rc;
247 }
248
249 // CE allows only the rules directory to be created
250 int rbce_mkdir(struct inode *dir, struct dentry *dentry, int mode)
251 {
252         int retval = -EINVAL;
253
254         struct dentry *pd =
255             list_entry(dir->i_dentry.next, struct dentry, d_alias);
256
257         // Allow only /rcfs/ce and ce/rules
258         if ((!strcmp(pd->d_name.name, "ce") &&
259              !strcmp(dentry->d_name.name, "rules")) ||
260             (!strcmp(pd->d_name.name, "/") &&
261              !strcmp(dentry->d_name.name, "ce"))) {
262
263                 if (!strcmp(dentry->d_name.name, "ce")) {
264                         try_module_get(THIS_MODULE);
265                 }
266                 retval = rbce_mknod(dir, dentry, mode | S_IFDIR, 0);
267                 if (!retval) {
268                         dir->i_nlink++;
269                 }
270         }
271
272         return retval;
273 }
274
275 // CE doesn't allow deletion of directory
276 int rbce_rmdir(struct inode *dir, struct dentry *dentry)
277 {
278         int rc;
279         // printk("removal of directory %s prohibited\n", dentry->d_name.name);
280         rc = simple_rmdir(dir, dentry);
281
282         if (!rc && !strcmp(dentry->d_name.name, "ce")) {
283                 module_put(THIS_MODULE);
284         }
285         return rc;
286 }
287
288 static int
289 rbce_create(struct inode *dir, struct dentry *dentry,
290             int mode, struct nameidata *nd)
291 {
292         struct dentry *pd =
293             list_entry(dir->i_dentry.next, struct dentry, d_alias);
294
295         // Under /ce only "rbce_reclassify", "rbce_state", "rbce_tag" and
296         // "rbce_info" are allowed
297         if (!strcmp(pd->d_name.name, "ce")) {
298                 if (strcmp(dentry->d_name.name, "rbce_reclassify") &&
299                     strcmp(dentry->d_name.name, "rbce_state") &&
300                     strcmp(dentry->d_name.name, "rbce_tag") &&
301                     strcmp(dentry->d_name.name, "rbce_info")) {
302                         return -EINVAL;
303                 }
304         }
305
306         return rbce_mknod(dir, dentry, mode | S_IFREG, 0);
307 }
308
309 static int rbce_link(struct dentry *old_d, struct inode *dir, struct dentry *d)
310 {
311         return -EINVAL;
312 }
313
314 static int
315 rbce_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
316 {
317         return -EINVAL;
318 }
319
320 /******************************* Magic files  ********************/
321
322 #define RBCE_NR_MAGF 6
323 struct rcfs_magf rbce_magf_files[RBCE_NR_MAGF] = {
324         {
325          .name = "ce",
326          .mode = RCFS_DEFAULT_DIR_MODE,
327          .i_op = &rbce_dir_inode_operations,
328          },
329         {
330          .name = "rbce_tag",
331          .mode = RCFS_DEFAULT_FILE_MODE,
332          .i_fop = &rbce_file_operations,
333          },
334         {
335          .name = "rbce_info",
336          .mode = RCFS_DEFAULT_FILE_MODE,
337          .i_fop = &rbce_file_operations,
338          },
339         {
340          .name = "rbce_state",
341          .mode = RCFS_DEFAULT_FILE_MODE,
342          .i_fop = &rbce_file_operations,
343          },
344         {
345          .name = "rbce_reclassify",
346          .mode = RCFS_DEFAULT_FILE_MODE,
347          .i_fop = &rbce_file_operations,
348          },
349         {
350          .name = "rules",
351          .mode = (RCFS_DEFAULT_DIR_MODE | S_IWUSR),
352          .i_fop = &simple_dir_operations,
353          .i_op = &rbce_dir_inode_operations,
354          }
355 };
356
357 static struct dentry *ce_root_dentry;
358
359 int rbce_create_magic(void)
360 {
361         int rc;
362
363         // Make root dentry
364         rc = rcfs_mkroot(rbce_magf_files, RBCE_NR_MAGF, &ce_root_dentry);
365         if ((!ce_root_dentry) || rc)
366                 return rc;
367
368         // Create magic files
369         if ((rc = rcfs_create_magic(ce_root_dentry, &rbce_magf_files[1],
370                                     RBCE_NR_MAGF - 1))) {
371                 printk(KERN_ERR "Failed to create c/rbce magic files."
372                        " Deleting c/rbce root\n");
373                 rcfs_rmroot(ce_root_dentry);
374                 return rc;
375         }
376
377         return rc;
378 }
379
380 int rbce_clear_magic(void)
381 {
382         int rc = 0;
383         if (ce_root_dentry)
384                 rc = rcfs_rmroot(ce_root_dentry);
385         return rc;
386 }
387
388 /******************************* File ops ********************/
389
390 static struct file_operations rbce_file_operations = {
391         .owner = THIS_MODULE,
392         .open = rbce_open,
393         .llseek = seq_lseek,
394         .read = seq_read,
395         .write = rbce_write,
396         .release = rbce_close,
397 };
398
399 static struct inode_operations rbce_file_inode_operations = {
400         .getattr = simple_getattr,
401 };
402
403 static struct inode_operations rbce_dir_inode_operations = {
404         .create = rbce_create,
405         .lookup = simple_lookup,
406         .link = rbce_link,
407         .unlink = rbce_unlink,
408         .symlink = rbce_symlink,
409         .mkdir = rbce_mkdir,
410         .rmdir = rbce_rmdir,
411         .mknod = rbce_mknod,
412         .rename = rbce_rename,
413         .getattr = simple_getattr,
414 };
415
416 #if 0
417 static void rbce_put_super(struct super_block *sb)
418 {
419         module_put(THIS_MODULE);
420         printk("rbce_put_super called\n");
421 }
422
423 static struct super_operations rbce_ops = {
424         .statfs = simple_statfs,
425         .drop_inode = generic_delete_inode,
426         .put_super = rbce_put_super,
427 };
428
429 static int rbce_fill_super(struct super_block *sb, void *data, int silent)
430 {
431         struct inode *inode;
432         struct dentry *root;
433
434         sb->s_blocksize = PAGE_CACHE_SIZE;
435         sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
436         sb->s_magic = RCFS_MAGIC;
437         sb->s_op = &rbce_ops;
438         inode = rbce_get_inode(sb, S_IFDIR | 0755, 0);
439         if (!inode)
440                 return -ENOMEM;
441
442         root = d_alloc_root(inode);
443         if (!root) {
444                 iput(inode);
445                 return -ENOMEM;
446         }
447         sb->s_root = root;
448
449         return 0;
450 }
451
452 static struct super_block *rbce_get_sb(struct file_system_type *fs_type,
453                                        int flags, const char *dev_name,
454                                        void *data)
455 {
456         struct super_block *sb =
457             get_sb_nodev(fs_type, flags, data, rbce_fill_super);
458         if (sb) {
459                 try_module_get(THIS_MODULE);
460         }
461         return sb;
462 }
463
464 static struct file_system_type rbce_fs_type = {
465         .name = "rbce",
466         .get_sb = rbce_get_sb,
467         .kill_sb = kill_litter_super,
468 };
469
470 static int
471 __init init_rbce_fs(void)
472 {
473         return register_filesystem(&rbce_fs_type);
474 }
475
476 static void
477 __exit exit_rbce_fs(void)
478 {
479         unregister_filesystem(&rbce_fs_type);
480 }
481
482 module_init(init_rbce_fs)
483     module_exit(exit_rbce_fs)
484     MODULE_LICENSE("GPL");
485 #endif