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 | ||
