patch-2.6.6-vs1.9.0
[linux-2.6.git] / fs / proc / inode.c
1 /*
2  *  linux/fs/proc/inode.c
3  *
4  *  Copyright (C) 1991, 1992  Linus Torvalds
5  */
6
7 #include <linux/time.h>
8 #include <linux/proc_fs.h>
9 #include <linux/kernel.h>
10 #include <linux/mm.h>
11 #include <linux/string.h>
12 #include <linux/stat.h>
13 #include <linux/file.h>
14 #include <linux/limits.h>
15 #include <linux/init.h>
16 #include <linux/module.h>
17 #include <linux/parser.h>
18 #include <linux/smp_lock.h>
19
20 #include <asm/system.h>
21 #include <asm/uaccess.h>
22
23 extern void free_proc_entry(struct proc_dir_entry *);
24
25 static inline struct proc_dir_entry * de_get(struct proc_dir_entry *de)
26 {
27         if (de)
28                 atomic_inc(&de->count);
29         return de;
30 }
31
32 /*
33  * Decrements the use count and checks for deferred deletion.
34  */
35 static void de_put(struct proc_dir_entry *de)
36 {
37         if (de) {       
38                 lock_kernel();          
39                 if (!atomic_read(&de->count)) {
40                         printk("de_put: entry %s already free!\n", de->name);
41                         unlock_kernel();
42                         return;
43                 }
44
45                 if (atomic_dec_and_test(&de->count)) {
46                         if (de->deleted) {
47                                 printk("de_put: deferred delete of %s\n",
48                                         de->name);
49                                 free_proc_entry(de);
50                         }
51                 }               
52                 unlock_kernel();
53         }
54 }
55
56 /*
57  * Decrement the use count of the proc_dir_entry.
58  */
59 static void proc_delete_inode(struct inode *inode)
60 {
61         struct proc_dir_entry *de;
62         struct task_struct *tsk;
63
64         /* Let go of any associated process */
65         tsk = PROC_I(inode)->task;
66         if (tsk)
67                 put_task_struct(tsk);
68
69         /* Let go of any associated proc directory entry */
70         de = PROC_I(inode)->pde;
71         if (de) {
72                 if (de->owner)
73                         module_put(de->owner);
74                 de_put(de);
75         }
76         clear_inode(inode);
77 }
78
79 struct vfsmount *proc_mnt;
80
81 static void proc_read_inode(struct inode * inode)
82 {
83         inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
84 }
85
86 static kmem_cache_t * proc_inode_cachep;
87
88 static struct inode *proc_alloc_inode(struct super_block *sb)
89 {
90         struct proc_inode *ei;
91         struct inode *inode;
92
93         ei = (struct proc_inode *)kmem_cache_alloc(proc_inode_cachep, SLAB_KERNEL);
94         if (!ei)
95                 return NULL;
96         ei->task = NULL;
97         ei->type = 0;
98         ei->op.proc_get_link = NULL;
99         ei->pde = NULL;
100         inode = &ei->vfs_inode;
101         inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
102         return inode;
103 }
104
105 static void proc_destroy_inode(struct inode *inode)
106 {
107         kmem_cache_free(proc_inode_cachep, PROC_I(inode));
108 }
109
110 static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
111 {
112         struct proc_inode *ei = (struct proc_inode *) foo;
113
114         if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
115             SLAB_CTOR_CONSTRUCTOR)
116                 inode_init_once(&ei->vfs_inode);
117 }
118  
119 int __init proc_init_inodecache(void)
120 {
121         proc_inode_cachep = kmem_cache_create("proc_inode_cache",
122                                              sizeof(struct proc_inode),
123                                              0, SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT,
124                                              init_once, NULL);
125         if (proc_inode_cachep == NULL)
126                 return -ENOMEM;
127         return 0;
128 }
129
130 static int proc_remount(struct super_block *sb, int *flags, char *data)
131 {
132         *flags |= MS_NODIRATIME;
133         return 0;
134 }
135
136 static struct super_operations proc_sops = { 
137         .alloc_inode    = proc_alloc_inode,
138         .destroy_inode  = proc_destroy_inode,
139         .read_inode     = proc_read_inode,
140         .drop_inode     = generic_delete_inode,
141         .delete_inode   = proc_delete_inode,
142         .statfs         = simple_statfs,
143         .remount_fs     = proc_remount,
144 };
145
146 enum {
147         Opt_uid, Opt_gid, Opt_err
148 };
149
150 static match_table_t tokens = {
151         {Opt_uid, "uid=%u"},
152         {Opt_gid, "gid=%u"},
153         {Opt_err, NULL}
154 };
155
156 static int parse_options(char *options,uid_t *uid,gid_t *gid)
157 {
158         char *p;
159         int option;
160
161         *uid = current->uid;
162         *gid = current->gid;
163         if (!options)
164                 return 1;
165
166         while ((p = strsep(&options, ",")) != NULL) {
167                 substring_t args[MAX_OPT_ARGS];
168                 int token;
169                 if (!*p)
170                         continue;
171
172                 token = match_token(p, tokens, args);
173                 switch (token) {
174                 case Opt_uid:
175                         if (match_int(args, &option))
176                                 return 0;
177                         *uid = option;
178                         break;
179                 case Opt_gid:
180                         if (match_int(args, &option))
181                                 return 0;
182                         *gid = option;
183                         break;
184                 default:
185                         return 0;
186                 }
187         }
188         return 1;
189 }
190
191 struct inode *proc_get_inode(struct super_block *sb, unsigned int ino,
192                                 struct proc_dir_entry *de)
193 {
194         struct inode * inode;
195
196         /*
197          * Increment the use count so the dir entry can't disappear.
198          */
199         de_get(de);
200
201         WARN_ON(de && de->deleted);
202
203         inode = iget(sb, ino);
204         if (!inode)
205                 goto out_fail;
206         
207         PROC_I(inode)->pde = de;
208         if (de) {
209                 if (de->mode) {
210                         inode->i_mode = de->mode;
211                         inode->i_uid = de->uid;
212                         inode->i_gid = de->gid;
213                 }
214                 if (de->vx_flags)
215                         PROC_I(inode)->vx_flags = de->vx_flags;
216                 if (de->size)
217                         inode->i_size = de->size;
218                 if (de->nlink)
219                         inode->i_nlink = de->nlink;
220                 if (!try_module_get(de->owner))
221                         goto out_fail;
222                 if (de->proc_iops)
223                         inode->i_op = de->proc_iops;
224                 if (de->proc_fops)
225                         inode->i_fop = de->proc_fops;
226         }
227
228 out:
229         return inode;
230
231 out_fail:
232         de_put(de);
233         goto out;
234 }                       
235
236 int proc_fill_super(struct super_block *s, void *data, int silent)
237 {
238         struct inode * root_inode;
239
240         s->s_flags |= MS_NODIRATIME;
241         s->s_blocksize = 1024;
242         s->s_blocksize_bits = 10;
243         s->s_magic = PROC_SUPER_MAGIC;
244         s->s_op = &proc_sops;
245         
246         root_inode = proc_get_inode(s, PROC_ROOT_INO, &proc_root);
247         if (!root_inode)
248                 goto out_no_root;
249         /*
250          * Fixup the root inode's nlink value
251          */
252         root_inode->i_nlink += nr_processes();
253         s->s_root = d_alloc_root(root_inode);
254         if (!s->s_root)
255                 goto out_no_root;
256         parse_options(data, &root_inode->i_uid, &root_inode->i_gid);
257         return 0;
258
259 out_no_root:
260         printk("proc_read_super: get root inode failed\n");
261         iput(root_inode);
262         return -ENOMEM;
263 }
264 MODULE_LICENSE("GPL");