diff options
Diffstat (limited to 'fs/proc/inode.c')
-rw-r--r-- | fs/proc/inode.c | 283 |
1 files changed, 106 insertions, 177 deletions
diff --git a/fs/proc/inode.c b/fs/proc/inode.c index 869116c2afbe..073aea60cf8f 100644 --- a/fs/proc/inode.c +++ b/fs/proc/inode.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <linux/seq_file.h> | 22 | #include <linux/seq_file.h> |
23 | #include <linux/slab.h> | 23 | #include <linux/slab.h> |
24 | #include <linux/mount.h> | 24 | #include <linux/mount.h> |
25 | #include <linux/magic.h> | ||
25 | 26 | ||
26 | #include <asm/uaccess.h> | 27 | #include <asm/uaccess.h> |
27 | 28 | ||
@@ -50,8 +51,8 @@ static void proc_evict_inode(struct inode *inode) | |||
50 | sysctl_head_put(head); | 51 | sysctl_head_put(head); |
51 | } | 52 | } |
52 | /* Release any associated namespace */ | 53 | /* Release any associated namespace */ |
53 | ns_ops = PROC_I(inode)->ns_ops; | 54 | ns_ops = PROC_I(inode)->ns.ns_ops; |
54 | ns = PROC_I(inode)->ns; | 55 | ns = PROC_I(inode)->ns.ns; |
55 | if (ns_ops && ns) | 56 | if (ns_ops && ns) |
56 | ns_ops->put(ns); | 57 | ns_ops->put(ns); |
57 | } | 58 | } |
@@ -72,8 +73,8 @@ static struct inode *proc_alloc_inode(struct super_block *sb) | |||
72 | ei->pde = NULL; | 73 | ei->pde = NULL; |
73 | ei->sysctl = NULL; | 74 | ei->sysctl = NULL; |
74 | ei->sysctl_entry = NULL; | 75 | ei->sysctl_entry = NULL; |
75 | ei->ns = NULL; | 76 | ei->ns.ns = NULL; |
76 | ei->ns_ops = NULL; | 77 | ei->ns.ns_ops = NULL; |
77 | inode = &ei->vfs_inode; | 78 | inode = &ei->vfs_inode; |
78 | inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; | 79 | inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; |
79 | return inode; | 80 | return inode; |
@@ -129,96 +130,100 @@ static const struct super_operations proc_sops = { | |||
129 | .show_options = proc_show_options, | 130 | .show_options = proc_show_options, |
130 | }; | 131 | }; |
131 | 132 | ||
132 | static void __pde_users_dec(struct proc_dir_entry *pde) | 133 | enum {BIAS = -1U<<31}; |
134 | |||
135 | static inline int use_pde(struct proc_dir_entry *pde) | ||
136 | { | ||
137 | return atomic_inc_unless_negative(&pde->in_use); | ||
138 | } | ||
139 | |||
140 | static void unuse_pde(struct proc_dir_entry *pde) | ||
133 | { | 141 | { |
134 | pde->pde_users--; | 142 | if (atomic_dec_return(&pde->in_use) == BIAS) |
135 | if (pde->pde_unload_completion && pde->pde_users == 0) | ||
136 | complete(pde->pde_unload_completion); | 143 | complete(pde->pde_unload_completion); |
137 | } | 144 | } |
138 | 145 | ||
139 | void pde_users_dec(struct proc_dir_entry *pde) | 146 | /* pde is locked */ |
147 | static void close_pdeo(struct proc_dir_entry *pde, struct pde_opener *pdeo) | ||
140 | { | 148 | { |
141 | spin_lock(&pde->pde_unload_lock); | 149 | if (pdeo->closing) { |
142 | __pde_users_dec(pde); | 150 | /* somebody else is doing that, just wait */ |
143 | spin_unlock(&pde->pde_unload_lock); | 151 | DECLARE_COMPLETION_ONSTACK(c); |
152 | pdeo->c = &c; | ||
153 | spin_unlock(&pde->pde_unload_lock); | ||
154 | wait_for_completion(&c); | ||
155 | spin_lock(&pde->pde_unload_lock); | ||
156 | } else { | ||
157 | struct file *file; | ||
158 | pdeo->closing = 1; | ||
159 | spin_unlock(&pde->pde_unload_lock); | ||
160 | file = pdeo->file; | ||
161 | pde->proc_fops->release(file_inode(file), file); | ||
162 | spin_lock(&pde->pde_unload_lock); | ||
163 | list_del_init(&pdeo->lh); | ||
164 | if (pdeo->c) | ||
165 | complete(pdeo->c); | ||
166 | kfree(pdeo); | ||
167 | } | ||
168 | } | ||
169 | |||
170 | void proc_entry_rundown(struct proc_dir_entry *de) | ||
171 | { | ||
172 | DECLARE_COMPLETION_ONSTACK(c); | ||
173 | /* Wait until all existing callers into module are done. */ | ||
174 | de->pde_unload_completion = &c; | ||
175 | if (atomic_add_return(BIAS, &de->in_use) != BIAS) | ||
176 | wait_for_completion(&c); | ||
177 | |||
178 | spin_lock(&de->pde_unload_lock); | ||
179 | while (!list_empty(&de->pde_openers)) { | ||
180 | struct pde_opener *pdeo; | ||
181 | pdeo = list_first_entry(&de->pde_openers, struct pde_opener, lh); | ||
182 | close_pdeo(de, pdeo); | ||
183 | } | ||
184 | spin_unlock(&de->pde_unload_lock); | ||
144 | } | 185 | } |
145 | 186 | ||
146 | static loff_t proc_reg_llseek(struct file *file, loff_t offset, int whence) | 187 | static loff_t proc_reg_llseek(struct file *file, loff_t offset, int whence) |
147 | { | 188 | { |
148 | struct proc_dir_entry *pde = PDE(file_inode(file)); | 189 | struct proc_dir_entry *pde = PDE(file_inode(file)); |
149 | loff_t rv = -EINVAL; | 190 | loff_t rv = -EINVAL; |
150 | loff_t (*llseek)(struct file *, loff_t, int); | 191 | if (use_pde(pde)) { |
151 | 192 | loff_t (*llseek)(struct file *, loff_t, int); | |
152 | spin_lock(&pde->pde_unload_lock); | 193 | llseek = pde->proc_fops->llseek; |
153 | /* | 194 | if (!llseek) |
154 | * remove_proc_entry() is going to delete PDE (as part of module | 195 | llseek = default_llseek; |
155 | * cleanup sequence). No new callers into module allowed. | 196 | rv = llseek(file, offset, whence); |
156 | */ | 197 | unuse_pde(pde); |
157 | if (!pde->proc_fops) { | ||
158 | spin_unlock(&pde->pde_unload_lock); | ||
159 | return rv; | ||
160 | } | 198 | } |
161 | /* | ||
162 | * Bump refcount so that remove_proc_entry will wail for ->llseek to | ||
163 | * complete. | ||
164 | */ | ||
165 | pde->pde_users++; | ||
166 | /* | ||
167 | * Save function pointer under lock, to protect against ->proc_fops | ||
168 | * NULL'ifying right after ->pde_unload_lock is dropped. | ||
169 | */ | ||
170 | llseek = pde->proc_fops->llseek; | ||
171 | spin_unlock(&pde->pde_unload_lock); | ||
172 | |||
173 | if (!llseek) | ||
174 | llseek = default_llseek; | ||
175 | rv = llseek(file, offset, whence); | ||
176 | |||
177 | pde_users_dec(pde); | ||
178 | return rv; | 199 | return rv; |
179 | } | 200 | } |
180 | 201 | ||
181 | static ssize_t proc_reg_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) | 202 | static ssize_t proc_reg_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) |
182 | { | 203 | { |
204 | ssize_t (*read)(struct file *, char __user *, size_t, loff_t *); | ||
183 | struct proc_dir_entry *pde = PDE(file_inode(file)); | 205 | struct proc_dir_entry *pde = PDE(file_inode(file)); |
184 | ssize_t rv = -EIO; | 206 | ssize_t rv = -EIO; |
185 | ssize_t (*read)(struct file *, char __user *, size_t, loff_t *); | 207 | if (use_pde(pde)) { |
186 | 208 | read = pde->proc_fops->read; | |
187 | spin_lock(&pde->pde_unload_lock); | 209 | if (read) |
188 | if (!pde->proc_fops) { | 210 | rv = read(file, buf, count, ppos); |
189 | spin_unlock(&pde->pde_unload_lock); | 211 | unuse_pde(pde); |
190 | return rv; | ||
191 | } | 212 | } |
192 | pde->pde_users++; | ||
193 | read = pde->proc_fops->read; | ||
194 | spin_unlock(&pde->pde_unload_lock); | ||
195 | |||
196 | if (read) | ||
197 | rv = read(file, buf, count, ppos); | ||
198 | |||
199 | pde_users_dec(pde); | ||
200 | return rv; | 213 | return rv; |
201 | } | 214 | } |
202 | 215 | ||
203 | static ssize_t proc_reg_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) | 216 | static ssize_t proc_reg_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) |
204 | { | 217 | { |
218 | ssize_t (*write)(struct file *, const char __user *, size_t, loff_t *); | ||
205 | struct proc_dir_entry *pde = PDE(file_inode(file)); | 219 | struct proc_dir_entry *pde = PDE(file_inode(file)); |
206 | ssize_t rv = -EIO; | 220 | ssize_t rv = -EIO; |
207 | ssize_t (*write)(struct file *, const char __user *, size_t, loff_t *); | 221 | if (use_pde(pde)) { |
208 | 222 | write = pde->proc_fops->write; | |
209 | spin_lock(&pde->pde_unload_lock); | 223 | if (write) |
210 | if (!pde->proc_fops) { | 224 | rv = write(file, buf, count, ppos); |
211 | spin_unlock(&pde->pde_unload_lock); | 225 | unuse_pde(pde); |
212 | return rv; | ||
213 | } | 226 | } |
214 | pde->pde_users++; | ||
215 | write = pde->proc_fops->write; | ||
216 | spin_unlock(&pde->pde_unload_lock); | ||
217 | |||
218 | if (write) | ||
219 | rv = write(file, buf, count, ppos); | ||
220 | |||
221 | pde_users_dec(pde); | ||
222 | return rv; | 227 | return rv; |
223 | } | 228 | } |
224 | 229 | ||
@@ -227,20 +232,12 @@ static unsigned int proc_reg_poll(struct file *file, struct poll_table_struct *p | |||
227 | struct proc_dir_entry *pde = PDE(file_inode(file)); | 232 | struct proc_dir_entry *pde = PDE(file_inode(file)); |
228 | unsigned int rv = DEFAULT_POLLMASK; | 233 | unsigned int rv = DEFAULT_POLLMASK; |
229 | unsigned int (*poll)(struct file *, struct poll_table_struct *); | 234 | unsigned int (*poll)(struct file *, struct poll_table_struct *); |
230 | 235 | if (use_pde(pde)) { | |
231 | spin_lock(&pde->pde_unload_lock); | 236 | poll = pde->proc_fops->poll; |
232 | if (!pde->proc_fops) { | 237 | if (poll) |
233 | spin_unlock(&pde->pde_unload_lock); | 238 | rv = poll(file, pts); |
234 | return rv; | 239 | unuse_pde(pde); |
235 | } | 240 | } |
236 | pde->pde_users++; | ||
237 | poll = pde->proc_fops->poll; | ||
238 | spin_unlock(&pde->pde_unload_lock); | ||
239 | |||
240 | if (poll) | ||
241 | rv = poll(file, pts); | ||
242 | |||
243 | pde_users_dec(pde); | ||
244 | return rv; | 241 | return rv; |
245 | } | 242 | } |
246 | 243 | ||
@@ -249,20 +246,12 @@ static long proc_reg_unlocked_ioctl(struct file *file, unsigned int cmd, unsigne | |||
249 | struct proc_dir_entry *pde = PDE(file_inode(file)); | 246 | struct proc_dir_entry *pde = PDE(file_inode(file)); |
250 | long rv = -ENOTTY; | 247 | long rv = -ENOTTY; |
251 | long (*ioctl)(struct file *, unsigned int, unsigned long); | 248 | long (*ioctl)(struct file *, unsigned int, unsigned long); |
252 | 249 | if (use_pde(pde)) { | |
253 | spin_lock(&pde->pde_unload_lock); | 250 | ioctl = pde->proc_fops->unlocked_ioctl; |
254 | if (!pde->proc_fops) { | 251 | if (ioctl) |
255 | spin_unlock(&pde->pde_unload_lock); | 252 | rv = ioctl(file, cmd, arg); |
256 | return rv; | 253 | unuse_pde(pde); |
257 | } | 254 | } |
258 | pde->pde_users++; | ||
259 | ioctl = pde->proc_fops->unlocked_ioctl; | ||
260 | spin_unlock(&pde->pde_unload_lock); | ||
261 | |||
262 | if (ioctl) | ||
263 | rv = ioctl(file, cmd, arg); | ||
264 | |||
265 | pde_users_dec(pde); | ||
266 | return rv; | 255 | return rv; |
267 | } | 256 | } |
268 | 257 | ||
@@ -272,20 +261,12 @@ static long proc_reg_compat_ioctl(struct file *file, unsigned int cmd, unsigned | |||
272 | struct proc_dir_entry *pde = PDE(file_inode(file)); | 261 | struct proc_dir_entry *pde = PDE(file_inode(file)); |
273 | long rv = -ENOTTY; | 262 | long rv = -ENOTTY; |
274 | long (*compat_ioctl)(struct file *, unsigned int, unsigned long); | 263 | long (*compat_ioctl)(struct file *, unsigned int, unsigned long); |
275 | 264 | if (use_pde(pde)) { | |
276 | spin_lock(&pde->pde_unload_lock); | 265 | compat_ioctl = pde->proc_fops->compat_ioctl; |
277 | if (!pde->proc_fops) { | 266 | if (compat_ioctl) |
278 | spin_unlock(&pde->pde_unload_lock); | 267 | rv = compat_ioctl(file, cmd, arg); |
279 | return rv; | 268 | unuse_pde(pde); |
280 | } | 269 | } |
281 | pde->pde_users++; | ||
282 | compat_ioctl = pde->proc_fops->compat_ioctl; | ||
283 | spin_unlock(&pde->pde_unload_lock); | ||
284 | |||
285 | if (compat_ioctl) | ||
286 | rv = compat_ioctl(file, cmd, arg); | ||
287 | |||
288 | pde_users_dec(pde); | ||
289 | return rv; | 270 | return rv; |
290 | } | 271 | } |
291 | #endif | 272 | #endif |
@@ -295,20 +276,12 @@ static int proc_reg_mmap(struct file *file, struct vm_area_struct *vma) | |||
295 | struct proc_dir_entry *pde = PDE(file_inode(file)); | 276 | struct proc_dir_entry *pde = PDE(file_inode(file)); |
296 | int rv = -EIO; | 277 | int rv = -EIO; |
297 | int (*mmap)(struct file *, struct vm_area_struct *); | 278 | int (*mmap)(struct file *, struct vm_area_struct *); |
298 | 279 | if (use_pde(pde)) { | |
299 | spin_lock(&pde->pde_unload_lock); | 280 | mmap = pde->proc_fops->mmap; |
300 | if (!pde->proc_fops) { | 281 | if (mmap) |
301 | spin_unlock(&pde->pde_unload_lock); | 282 | rv = mmap(file, vma); |
302 | return rv; | 283 | unuse_pde(pde); |
303 | } | 284 | } |
304 | pde->pde_users++; | ||
305 | mmap = pde->proc_fops->mmap; | ||
306 | spin_unlock(&pde->pde_unload_lock); | ||
307 | |||
308 | if (mmap) | ||
309 | rv = mmap(file, vma); | ||
310 | |||
311 | pde_users_dec(pde); | ||
312 | return rv; | 285 | return rv; |
313 | } | 286 | } |
314 | 287 | ||
@@ -330,91 +303,47 @@ static int proc_reg_open(struct inode *inode, struct file *file) | |||
330 | * by hand in remove_proc_entry(). For this, save opener's credentials | 303 | * by hand in remove_proc_entry(). For this, save opener's credentials |
331 | * for later. | 304 | * for later. |
332 | */ | 305 | */ |
333 | pdeo = kmalloc(sizeof(struct pde_opener), GFP_KERNEL); | 306 | pdeo = kzalloc(sizeof(struct pde_opener), GFP_KERNEL); |
334 | if (!pdeo) | 307 | if (!pdeo) |
335 | return -ENOMEM; | 308 | return -ENOMEM; |
336 | 309 | ||
337 | spin_lock(&pde->pde_unload_lock); | 310 | if (!use_pde(pde)) { |
338 | if (!pde->proc_fops) { | ||
339 | spin_unlock(&pde->pde_unload_lock); | ||
340 | kfree(pdeo); | 311 | kfree(pdeo); |
341 | return -ENOENT; | 312 | return -ENOENT; |
342 | } | 313 | } |
343 | pde->pde_users++; | ||
344 | open = pde->proc_fops->open; | 314 | open = pde->proc_fops->open; |
345 | release = pde->proc_fops->release; | 315 | release = pde->proc_fops->release; |
346 | spin_unlock(&pde->pde_unload_lock); | ||
347 | 316 | ||
348 | if (open) | 317 | if (open) |
349 | rv = open(inode, file); | 318 | rv = open(inode, file); |
350 | 319 | ||
351 | spin_lock(&pde->pde_unload_lock); | ||
352 | if (rv == 0 && release) { | 320 | if (rv == 0 && release) { |
353 | /* To know what to release. */ | 321 | /* To know what to release. */ |
354 | pdeo->inode = inode; | ||
355 | pdeo->file = file; | 322 | pdeo->file = file; |
356 | /* Strictly for "too late" ->release in proc_reg_release(). */ | 323 | /* Strictly for "too late" ->release in proc_reg_release(). */ |
357 | pdeo->release = release; | 324 | spin_lock(&pde->pde_unload_lock); |
358 | list_add(&pdeo->lh, &pde->pde_openers); | 325 | list_add(&pdeo->lh, &pde->pde_openers); |
326 | spin_unlock(&pde->pde_unload_lock); | ||
359 | } else | 327 | } else |
360 | kfree(pdeo); | 328 | kfree(pdeo); |
361 | __pde_users_dec(pde); | ||
362 | spin_unlock(&pde->pde_unload_lock); | ||
363 | return rv; | ||
364 | } | ||
365 | |||
366 | static struct pde_opener *find_pde_opener(struct proc_dir_entry *pde, | ||
367 | struct inode *inode, struct file *file) | ||
368 | { | ||
369 | struct pde_opener *pdeo; | ||
370 | 329 | ||
371 | list_for_each_entry(pdeo, &pde->pde_openers, lh) { | 330 | unuse_pde(pde); |
372 | if (pdeo->inode == inode && pdeo->file == file) | 331 | return rv; |
373 | return pdeo; | ||
374 | } | ||
375 | return NULL; | ||
376 | } | 332 | } |
377 | 333 | ||
378 | static int proc_reg_release(struct inode *inode, struct file *file) | 334 | static int proc_reg_release(struct inode *inode, struct file *file) |
379 | { | 335 | { |
380 | struct proc_dir_entry *pde = PDE(inode); | 336 | struct proc_dir_entry *pde = PDE(inode); |
381 | int rv = 0; | ||
382 | int (*release)(struct inode *, struct file *); | ||
383 | struct pde_opener *pdeo; | 337 | struct pde_opener *pdeo; |
384 | |||
385 | spin_lock(&pde->pde_unload_lock); | 338 | spin_lock(&pde->pde_unload_lock); |
386 | pdeo = find_pde_opener(pde, inode, file); | 339 | list_for_each_entry(pdeo, &pde->pde_openers, lh) { |
387 | if (!pde->proc_fops) { | 340 | if (pdeo->file == file) { |
388 | /* | 341 | close_pdeo(pde, pdeo); |
389 | * Can't simply exit, __fput() will think that everything is OK, | 342 | break; |
390 | * and move on to freeing struct file. remove_proc_entry() will | 343 | } |
391 | * find slacker in opener's list and will try to do non-trivial | ||
392 | * things with struct file. Therefore, remove opener from list. | ||
393 | * | ||
394 | * But if opener is removed from list, who will ->release it? | ||
395 | */ | ||
396 | if (pdeo) { | ||
397 | list_del(&pdeo->lh); | ||
398 | spin_unlock(&pde->pde_unload_lock); | ||
399 | rv = pdeo->release(inode, file); | ||
400 | kfree(pdeo); | ||
401 | } else | ||
402 | spin_unlock(&pde->pde_unload_lock); | ||
403 | return rv; | ||
404 | } | ||
405 | pde->pde_users++; | ||
406 | release = pde->proc_fops->release; | ||
407 | if (pdeo) { | ||
408 | list_del(&pdeo->lh); | ||
409 | kfree(pdeo); | ||
410 | } | 344 | } |
411 | spin_unlock(&pde->pde_unload_lock); | 345 | spin_unlock(&pde->pde_unload_lock); |
412 | 346 | return 0; | |
413 | if (release) | ||
414 | rv = release(inode, file); | ||
415 | |||
416 | pde_users_dec(pde); | ||
417 | return rv; | ||
418 | } | 347 | } |
419 | 348 | ||
420 | static const struct file_operations proc_reg_file_ops = { | 349 | static const struct file_operations proc_reg_file_ops = { |
@@ -462,8 +391,8 @@ struct inode *proc_get_inode(struct super_block *sb, struct proc_dir_entry *de) | |||
462 | inode->i_size = de->size; | 391 | inode->i_size = de->size; |
463 | if (de->nlink) | 392 | if (de->nlink) |
464 | set_nlink(inode, de->nlink); | 393 | set_nlink(inode, de->nlink); |
465 | if (de->proc_iops) | 394 | WARN_ON(!de->proc_iops); |
466 | inode->i_op = de->proc_iops; | 395 | inode->i_op = de->proc_iops; |
467 | if (de->proc_fops) { | 396 | if (de->proc_fops) { |
468 | if (S_ISREG(inode->i_mode)) { | 397 | if (S_ISREG(inode->i_mode)) { |
469 | #ifdef CONFIG_COMPAT | 398 | #ifdef CONFIG_COMPAT |
@@ -506,5 +435,5 @@ int proc_fill_super(struct super_block *s) | |||
506 | return -ENOMEM; | 435 | return -ENOMEM; |
507 | } | 436 | } |
508 | 437 | ||
509 | return 0; | 438 | return proc_setup_self(s); |
510 | } | 439 | } |