diff options
Diffstat (limited to 'fs/proc/inode.c')
-rw-r--r-- | fs/proc/inode.c | 218 |
1 files changed, 218 insertions, 0 deletions
diff --git a/fs/proc/inode.c b/fs/proc/inode.c new file mode 100644 index 000000000000..133c28685105 --- /dev/null +++ b/fs/proc/inode.c | |||
@@ -0,0 +1,218 @@ | |||
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/smp_lock.h> | ||
18 | |||
19 | #include <asm/system.h> | ||
20 | #include <asm/uaccess.h> | ||
21 | |||
22 | extern void free_proc_entry(struct proc_dir_entry *); | ||
23 | |||
24 | static inline struct proc_dir_entry * de_get(struct proc_dir_entry *de) | ||
25 | { | ||
26 | if (de) | ||
27 | atomic_inc(&de->count); | ||
28 | return de; | ||
29 | } | ||
30 | |||
31 | /* | ||
32 | * Decrements the use count and checks for deferred deletion. | ||
33 | */ | ||
34 | static void de_put(struct proc_dir_entry *de) | ||
35 | { | ||
36 | if (de) { | ||
37 | lock_kernel(); | ||
38 | if (!atomic_read(&de->count)) { | ||
39 | printk("de_put: entry %s already free!\n", de->name); | ||
40 | unlock_kernel(); | ||
41 | return; | ||
42 | } | ||
43 | |||
44 | if (atomic_dec_and_test(&de->count)) { | ||
45 | if (de->deleted) { | ||
46 | printk("de_put: deferred delete of %s\n", | ||
47 | de->name); | ||
48 | free_proc_entry(de); | ||
49 | } | ||
50 | } | ||
51 | unlock_kernel(); | ||
52 | } | ||
53 | } | ||
54 | |||
55 | /* | ||
56 | * Decrement the use count of the proc_dir_entry. | ||
57 | */ | ||
58 | static void proc_delete_inode(struct inode *inode) | ||
59 | { | ||
60 | struct proc_dir_entry *de; | ||
61 | struct task_struct *tsk; | ||
62 | |||
63 | /* Let go of any associated process */ | ||
64 | tsk = PROC_I(inode)->task; | ||
65 | if (tsk) | ||
66 | put_task_struct(tsk); | ||
67 | |||
68 | /* Let go of any associated proc directory entry */ | ||
69 | de = PROC_I(inode)->pde; | ||
70 | if (de) { | ||
71 | if (de->owner) | ||
72 | module_put(de->owner); | ||
73 | de_put(de); | ||
74 | } | ||
75 | clear_inode(inode); | ||
76 | } | ||
77 | |||
78 | struct vfsmount *proc_mnt; | ||
79 | |||
80 | static void proc_read_inode(struct inode * inode) | ||
81 | { | ||
82 | inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; | ||
83 | } | ||
84 | |||
85 | static kmem_cache_t * proc_inode_cachep; | ||
86 | |||
87 | static struct inode *proc_alloc_inode(struct super_block *sb) | ||
88 | { | ||
89 | struct proc_inode *ei; | ||
90 | struct inode *inode; | ||
91 | |||
92 | ei = (struct proc_inode *)kmem_cache_alloc(proc_inode_cachep, SLAB_KERNEL); | ||
93 | if (!ei) | ||
94 | return NULL; | ||
95 | ei->task = NULL; | ||
96 | ei->type = 0; | ||
97 | ei->op.proc_get_link = NULL; | ||
98 | ei->pde = NULL; | ||
99 | inode = &ei->vfs_inode; | ||
100 | inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; | ||
101 | return inode; | ||
102 | } | ||
103 | |||
104 | static void proc_destroy_inode(struct inode *inode) | ||
105 | { | ||
106 | kmem_cache_free(proc_inode_cachep, PROC_I(inode)); | ||
107 | } | ||
108 | |||
109 | static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags) | ||
110 | { | ||
111 | struct proc_inode *ei = (struct proc_inode *) foo; | ||
112 | |||
113 | if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) == | ||
114 | SLAB_CTOR_CONSTRUCTOR) | ||
115 | inode_init_once(&ei->vfs_inode); | ||
116 | } | ||
117 | |||
118 | int __init proc_init_inodecache(void) | ||
119 | { | ||
120 | proc_inode_cachep = kmem_cache_create("proc_inode_cache", | ||
121 | sizeof(struct proc_inode), | ||
122 | 0, SLAB_RECLAIM_ACCOUNT, | ||
123 | init_once, NULL); | ||
124 | if (proc_inode_cachep == NULL) | ||
125 | return -ENOMEM; | ||
126 | return 0; | ||
127 | } | ||
128 | |||
129 | static int proc_remount(struct super_block *sb, int *flags, char *data) | ||
130 | { | ||
131 | *flags |= MS_NODIRATIME; | ||
132 | return 0; | ||
133 | } | ||
134 | |||
135 | static struct super_operations proc_sops = { | ||
136 | .alloc_inode = proc_alloc_inode, | ||
137 | .destroy_inode = proc_destroy_inode, | ||
138 | .read_inode = proc_read_inode, | ||
139 | .drop_inode = generic_delete_inode, | ||
140 | .delete_inode = proc_delete_inode, | ||
141 | .statfs = simple_statfs, | ||
142 | .remount_fs = proc_remount, | ||
143 | }; | ||
144 | |||
145 | struct inode *proc_get_inode(struct super_block *sb, unsigned int ino, | ||
146 | struct proc_dir_entry *de) | ||
147 | { | ||
148 | struct inode * inode; | ||
149 | |||
150 | /* | ||
151 | * Increment the use count so the dir entry can't disappear. | ||
152 | */ | ||
153 | de_get(de); | ||
154 | |||
155 | WARN_ON(de && de->deleted); | ||
156 | |||
157 | inode = iget(sb, ino); | ||
158 | if (!inode) | ||
159 | goto out_fail; | ||
160 | |||
161 | PROC_I(inode)->pde = de; | ||
162 | if (de) { | ||
163 | if (de->mode) { | ||
164 | inode->i_mode = de->mode; | ||
165 | inode->i_uid = de->uid; | ||
166 | inode->i_gid = de->gid; | ||
167 | } | ||
168 | if (de->size) | ||
169 | inode->i_size = de->size; | ||
170 | if (de->nlink) | ||
171 | inode->i_nlink = de->nlink; | ||
172 | if (!try_module_get(de->owner)) | ||
173 | goto out_fail; | ||
174 | if (de->proc_iops) | ||
175 | inode->i_op = de->proc_iops; | ||
176 | if (de->proc_fops) | ||
177 | inode->i_fop = de->proc_fops; | ||
178 | } | ||
179 | |||
180 | out: | ||
181 | return inode; | ||
182 | |||
183 | out_fail: | ||
184 | de_put(de); | ||
185 | goto out; | ||
186 | } | ||
187 | |||
188 | int proc_fill_super(struct super_block *s, void *data, int silent) | ||
189 | { | ||
190 | struct inode * root_inode; | ||
191 | |||
192 | s->s_flags |= MS_NODIRATIME; | ||
193 | s->s_blocksize = 1024; | ||
194 | s->s_blocksize_bits = 10; | ||
195 | s->s_magic = PROC_SUPER_MAGIC; | ||
196 | s->s_op = &proc_sops; | ||
197 | s->s_time_gran = 1; | ||
198 | |||
199 | root_inode = proc_get_inode(s, PROC_ROOT_INO, &proc_root); | ||
200 | if (!root_inode) | ||
201 | goto out_no_root; | ||
202 | /* | ||
203 | * Fixup the root inode's nlink value | ||
204 | */ | ||
205 | root_inode->i_nlink += nr_processes(); | ||
206 | root_inode->i_uid = 0; | ||
207 | root_inode->i_gid = 0; | ||
208 | s->s_root = d_alloc_root(root_inode); | ||
209 | if (!s->s_root) | ||
210 | goto out_no_root; | ||
211 | return 0; | ||
212 | |||
213 | out_no_root: | ||
214 | printk("proc_read_super: get root inode failed\n"); | ||
215 | iput(root_inode); | ||
216 | return -ENOMEM; | ||
217 | } | ||
218 | MODULE_LICENSE("GPL"); | ||