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