diff options
-rw-r--r-- | fs/proc/generic.c | 32 | ||||
-rw-r--r-- | fs/proc/proc_devtree.c | 2 | ||||
-rw-r--r-- | include/linux/proc_fs.h | 3 |
3 files changed, 34 insertions, 3 deletions
diff --git a/fs/proc/generic.c b/fs/proc/generic.c index 20e5c4509a43..47b7a20d45eb 100644 --- a/fs/proc/generic.c +++ b/fs/proc/generic.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <linux/idr.h> | 19 | #include <linux/idr.h> |
20 | #include <linux/namei.h> | 20 | #include <linux/namei.h> |
21 | #include <linux/bitops.h> | 21 | #include <linux/bitops.h> |
22 | #include <linux/spinlock.h> | ||
22 | #include <asm/uaccess.h> | 23 | #include <asm/uaccess.h> |
23 | 24 | ||
24 | #include "internal.h" | 25 | #include "internal.h" |
@@ -29,6 +30,8 @@ static ssize_t proc_file_write(struct file *file, const char __user *buffer, | |||
29 | size_t count, loff_t *ppos); | 30 | size_t count, loff_t *ppos); |
30 | static loff_t proc_file_lseek(struct file *, loff_t, int); | 31 | static loff_t proc_file_lseek(struct file *, loff_t, int); |
31 | 32 | ||
33 | DEFINE_SPINLOCK(proc_subdir_lock); | ||
34 | |||
32 | int proc_match(int len, const char *name, struct proc_dir_entry *de) | 35 | int proc_match(int len, const char *name, struct proc_dir_entry *de) |
33 | { | 36 | { |
34 | if (de->namelen != len) | 37 | if (de->namelen != len) |
@@ -277,7 +280,9 @@ static int xlate_proc_name(const char *name, | |||
277 | const char *cp = name, *next; | 280 | const char *cp = name, *next; |
278 | struct proc_dir_entry *de; | 281 | struct proc_dir_entry *de; |
279 | int len; | 282 | int len; |
283 | int rtn = 0; | ||
280 | 284 | ||
285 | spin_lock(&proc_subdir_lock); | ||
281 | de = &proc_root; | 286 | de = &proc_root; |
282 | while (1) { | 287 | while (1) { |
283 | next = strchr(cp, '/'); | 288 | next = strchr(cp, '/'); |
@@ -289,13 +294,17 @@ static int xlate_proc_name(const char *name, | |||
289 | if (proc_match(len, cp, de)) | 294 | if (proc_match(len, cp, de)) |
290 | break; | 295 | break; |
291 | } | 296 | } |
292 | if (!de) | 297 | if (!de) { |
293 | return -ENOENT; | 298 | rtn = -ENOENT; |
299 | goto out; | ||
300 | } | ||
294 | cp += len + 1; | 301 | cp += len + 1; |
295 | } | 302 | } |
296 | *residual = cp; | 303 | *residual = cp; |
297 | *ret = de; | 304 | *ret = de; |
298 | return 0; | 305 | out: |
306 | spin_unlock(&proc_subdir_lock); | ||
307 | return rtn; | ||
299 | } | 308 | } |
300 | 309 | ||
301 | static DEFINE_IDR(proc_inum_idr); | 310 | static DEFINE_IDR(proc_inum_idr); |
@@ -380,6 +389,7 @@ struct dentry *proc_lookup(struct inode * dir, struct dentry *dentry, struct nam | |||
380 | int error = -ENOENT; | 389 | int error = -ENOENT; |
381 | 390 | ||
382 | lock_kernel(); | 391 | lock_kernel(); |
392 | spin_lock(&proc_subdir_lock); | ||
383 | de = PDE(dir); | 393 | de = PDE(dir); |
384 | if (de) { | 394 | if (de) { |
385 | for (de = de->subdir; de ; de = de->next) { | 395 | for (de = de->subdir; de ; de = de->next) { |
@@ -388,12 +398,15 @@ struct dentry *proc_lookup(struct inode * dir, struct dentry *dentry, struct nam | |||
388 | if (!memcmp(dentry->d_name.name, de->name, de->namelen)) { | 398 | if (!memcmp(dentry->d_name.name, de->name, de->namelen)) { |
389 | unsigned int ino = de->low_ino; | 399 | unsigned int ino = de->low_ino; |
390 | 400 | ||
401 | spin_unlock(&proc_subdir_lock); | ||
391 | error = -EINVAL; | 402 | error = -EINVAL; |
392 | inode = proc_get_inode(dir->i_sb, ino, de); | 403 | inode = proc_get_inode(dir->i_sb, ino, de); |
404 | spin_lock(&proc_subdir_lock); | ||
393 | break; | 405 | break; |
394 | } | 406 | } |
395 | } | 407 | } |
396 | } | 408 | } |
409 | spin_unlock(&proc_subdir_lock); | ||
397 | unlock_kernel(); | 410 | unlock_kernel(); |
398 | 411 | ||
399 | if (inode) { | 412 | if (inode) { |
@@ -447,11 +460,13 @@ int proc_readdir(struct file * filp, | |||
447 | filp->f_pos++; | 460 | filp->f_pos++; |
448 | /* fall through */ | 461 | /* fall through */ |
449 | default: | 462 | default: |
463 | spin_lock(&proc_subdir_lock); | ||
450 | de = de->subdir; | 464 | de = de->subdir; |
451 | i -= 2; | 465 | i -= 2; |
452 | for (;;) { | 466 | for (;;) { |
453 | if (!de) { | 467 | if (!de) { |
454 | ret = 1; | 468 | ret = 1; |
469 | spin_unlock(&proc_subdir_lock); | ||
455 | goto out; | 470 | goto out; |
456 | } | 471 | } |
457 | if (!i) | 472 | if (!i) |
@@ -461,12 +476,16 @@ int proc_readdir(struct file * filp, | |||
461 | } | 476 | } |
462 | 477 | ||
463 | do { | 478 | do { |
479 | /* filldir passes info to user space */ | ||
480 | spin_unlock(&proc_subdir_lock); | ||
464 | if (filldir(dirent, de->name, de->namelen, filp->f_pos, | 481 | if (filldir(dirent, de->name, de->namelen, filp->f_pos, |
465 | de->low_ino, de->mode >> 12) < 0) | 482 | de->low_ino, de->mode >> 12) < 0) |
466 | goto out; | 483 | goto out; |
484 | spin_lock(&proc_subdir_lock); | ||
467 | filp->f_pos++; | 485 | filp->f_pos++; |
468 | de = de->next; | 486 | de = de->next; |
469 | } while (de); | 487 | } while (de); |
488 | spin_unlock(&proc_subdir_lock); | ||
470 | } | 489 | } |
471 | ret = 1; | 490 | ret = 1; |
472 | out: unlock_kernel(); | 491 | out: unlock_kernel(); |
@@ -500,9 +519,13 @@ static int proc_register(struct proc_dir_entry * dir, struct proc_dir_entry * dp | |||
500 | if (i == 0) | 519 | if (i == 0) |
501 | return -EAGAIN; | 520 | return -EAGAIN; |
502 | dp->low_ino = i; | 521 | dp->low_ino = i; |
522 | |||
523 | spin_lock(&proc_subdir_lock); | ||
503 | dp->next = dir->subdir; | 524 | dp->next = dir->subdir; |
504 | dp->parent = dir; | 525 | dp->parent = dir; |
505 | dir->subdir = dp; | 526 | dir->subdir = dp; |
527 | spin_unlock(&proc_subdir_lock); | ||
528 | |||
506 | if (S_ISDIR(dp->mode)) { | 529 | if (S_ISDIR(dp->mode)) { |
507 | if (dp->proc_iops == NULL) { | 530 | if (dp->proc_iops == NULL) { |
508 | dp->proc_fops = &proc_dir_operations; | 531 | dp->proc_fops = &proc_dir_operations; |
@@ -694,6 +717,8 @@ void remove_proc_entry(const char *name, struct proc_dir_entry *parent) | |||
694 | if (!parent && xlate_proc_name(name, &parent, &fn) != 0) | 717 | if (!parent && xlate_proc_name(name, &parent, &fn) != 0) |
695 | goto out; | 718 | goto out; |
696 | len = strlen(fn); | 719 | len = strlen(fn); |
720 | |||
721 | spin_lock(&proc_subdir_lock); | ||
697 | for (p = &parent->subdir; *p; p=&(*p)->next ) { | 722 | for (p = &parent->subdir; *p; p=&(*p)->next ) { |
698 | if (!proc_match(len, fn, *p)) | 723 | if (!proc_match(len, fn, *p)) |
699 | continue; | 724 | continue; |
@@ -714,6 +739,7 @@ void remove_proc_entry(const char *name, struct proc_dir_entry *parent) | |||
714 | } | 739 | } |
715 | break; | 740 | break; |
716 | } | 741 | } |
742 | spin_unlock(&proc_subdir_lock); | ||
717 | out: | 743 | out: |
718 | return; | 744 | return; |
719 | } | 745 | } |
diff --git a/fs/proc/proc_devtree.c b/fs/proc/proc_devtree.c index 9bdd077d6f55..596b4b4f1cc8 100644 --- a/fs/proc/proc_devtree.c +++ b/fs/proc/proc_devtree.c | |||
@@ -136,9 +136,11 @@ void proc_device_tree_add_node(struct device_node *np, | |||
136 | * properties are quite unimportant for us though, thus we | 136 | * properties are quite unimportant for us though, thus we |
137 | * simply "skip" them here, but we do have to check. | 137 | * simply "skip" them here, but we do have to check. |
138 | */ | 138 | */ |
139 | spin_lock(&proc_subdir_lock); | ||
139 | for (ent = de->subdir; ent != NULL; ent = ent->next) | 140 | for (ent = de->subdir; ent != NULL; ent = ent->next) |
140 | if (!strcmp(ent->name, pp->name)) | 141 | if (!strcmp(ent->name, pp->name)) |
141 | break; | 142 | break; |
143 | spin_unlock(&proc_subdir_lock); | ||
142 | if (ent != NULL) { | 144 | if (ent != NULL) { |
143 | printk(KERN_WARNING "device-tree: property \"%s\" name" | 145 | printk(KERN_WARNING "device-tree: property \"%s\" name" |
144 | " conflicts with node in %s\n", pp->name, | 146 | " conflicts with node in %s\n", pp->name, |
diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h index aa6322d45198..6b12b0f661b4 100644 --- a/include/linux/proc_fs.h +++ b/include/linux/proc_fs.h | |||
@@ -4,6 +4,7 @@ | |||
4 | #include <linux/config.h> | 4 | #include <linux/config.h> |
5 | #include <linux/slab.h> | 5 | #include <linux/slab.h> |
6 | #include <linux/fs.h> | 6 | #include <linux/fs.h> |
7 | #include <linux/spinlock.h> | ||
7 | #include <asm/atomic.h> | 8 | #include <asm/atomic.h> |
8 | 9 | ||
9 | /* | 10 | /* |
@@ -92,6 +93,8 @@ extern struct proc_dir_entry *proc_bus; | |||
92 | extern struct proc_dir_entry *proc_root_driver; | 93 | extern struct proc_dir_entry *proc_root_driver; |
93 | extern struct proc_dir_entry *proc_root_kcore; | 94 | extern struct proc_dir_entry *proc_root_kcore; |
94 | 95 | ||
96 | extern spinlock_t proc_subdir_lock; | ||
97 | |||
95 | extern void proc_root_init(void); | 98 | extern void proc_root_init(void); |
96 | extern void proc_misc_init(void); | 99 | extern void proc_misc_init(void); |
97 | 100 | ||