diff options
Diffstat (limited to 'fs/proc')
-rw-r--r-- | fs/proc/array.c | 5 | ||||
-rw-r--r-- | fs/proc/base.c | 39 | ||||
-rw-r--r-- | fs/proc/generic.c | 34 | ||||
-rw-r--r-- | fs/proc/inode.c | 3 | ||||
-rw-r--r-- | fs/proc/internal.h | 2 | ||||
-rw-r--r-- | fs/proc/kcore.c | 2 | ||||
-rw-r--r-- | fs/proc/kmsg.c | 2 | ||||
-rw-r--r-- | fs/proc/proc_devtree.c | 101 | ||||
-rw-r--r-- | fs/proc/proc_misc.c | 43 | ||||
-rw-r--r-- | fs/proc/vmcore.c | 2 |
10 files changed, 196 insertions, 37 deletions
diff --git a/fs/proc/array.c b/fs/proc/array.c index 7eb1bd7f800c..7a76ad570230 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c | |||
@@ -330,7 +330,6 @@ static int do_task_stat(struct task_struct *task, char * buffer, int whole) | |||
330 | unsigned long min_flt = 0, maj_flt = 0; | 330 | unsigned long min_flt = 0, maj_flt = 0; |
331 | cputime_t cutime, cstime, utime, stime; | 331 | cputime_t cutime, cstime, utime, stime; |
332 | unsigned long rsslim = 0; | 332 | unsigned long rsslim = 0; |
333 | DEFINE_KTIME(it_real_value); | ||
334 | struct task_struct *t; | 333 | struct task_struct *t; |
335 | char tcomm[sizeof(task->comm)]; | 334 | char tcomm[sizeof(task->comm)]; |
336 | 335 | ||
@@ -386,7 +385,6 @@ static int do_task_stat(struct task_struct *task, char * buffer, int whole) | |||
386 | utime = cputime_add(utime, task->signal->utime); | 385 | utime = cputime_add(utime, task->signal->utime); |
387 | stime = cputime_add(stime, task->signal->stime); | 386 | stime = cputime_add(stime, task->signal->stime); |
388 | } | 387 | } |
389 | it_real_value = task->signal->real_timer.expires; | ||
390 | } | 388 | } |
391 | ppid = pid_alive(task) ? task->group_leader->real_parent->tgid : 0; | 389 | ppid = pid_alive(task) ? task->group_leader->real_parent->tgid : 0; |
392 | read_unlock(&tasklist_lock); | 390 | read_unlock(&tasklist_lock); |
@@ -413,7 +411,7 @@ static int do_task_stat(struct task_struct *task, char * buffer, int whole) | |||
413 | start_time = nsec_to_clock_t(start_time); | 411 | start_time = nsec_to_clock_t(start_time); |
414 | 412 | ||
415 | res = sprintf(buffer,"%d (%s) %c %d %d %d %d %d %lu %lu \ | 413 | res = sprintf(buffer,"%d (%s) %c %d %d %d %d %d %lu %lu \ |
416 | %lu %lu %lu %lu %lu %ld %ld %ld %ld %d %ld %llu %lu %ld %lu %lu %lu %lu %lu \ | 414 | %lu %lu %lu %lu %lu %ld %ld %ld %ld %d 0 %llu %lu %ld %lu %lu %lu %lu %lu \ |
417 | %lu %lu %lu %lu %lu %lu %lu %lu %d %d %lu %lu\n", | 415 | %lu %lu %lu %lu %lu %lu %lu %lu %d %d %lu %lu\n", |
418 | task->pid, | 416 | task->pid, |
419 | tcomm, | 417 | tcomm, |
@@ -435,7 +433,6 @@ static int do_task_stat(struct task_struct *task, char * buffer, int whole) | |||
435 | priority, | 433 | priority, |
436 | nice, | 434 | nice, |
437 | num_threads, | 435 | num_threads, |
438 | (long) ktime_to_clock_t(it_real_value), | ||
439 | start_time, | 436 | start_time, |
440 | vsize, | 437 | vsize, |
441 | mm ? get_mm_rss(mm) : 0, | 438 | mm ? get_mm_rss(mm) : 0, |
diff --git a/fs/proc/base.c b/fs/proc/base.c index 20feb7568deb..8f1f49ceebec 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c | |||
@@ -104,6 +104,7 @@ enum pid_directory_inos { | |||
104 | PROC_TGID_MAPS, | 104 | PROC_TGID_MAPS, |
105 | PROC_TGID_NUMA_MAPS, | 105 | PROC_TGID_NUMA_MAPS, |
106 | PROC_TGID_MOUNTS, | 106 | PROC_TGID_MOUNTS, |
107 | PROC_TGID_MOUNTSTATS, | ||
107 | PROC_TGID_WCHAN, | 108 | PROC_TGID_WCHAN, |
108 | #ifdef CONFIG_MMU | 109 | #ifdef CONFIG_MMU |
109 | PROC_TGID_SMAPS, | 110 | PROC_TGID_SMAPS, |
@@ -144,6 +145,7 @@ enum pid_directory_inos { | |||
144 | PROC_TID_MAPS, | 145 | PROC_TID_MAPS, |
145 | PROC_TID_NUMA_MAPS, | 146 | PROC_TID_NUMA_MAPS, |
146 | PROC_TID_MOUNTS, | 147 | PROC_TID_MOUNTS, |
148 | PROC_TID_MOUNTSTATS, | ||
147 | PROC_TID_WCHAN, | 149 | PROC_TID_WCHAN, |
148 | #ifdef CONFIG_MMU | 150 | #ifdef CONFIG_MMU |
149 | PROC_TID_SMAPS, | 151 | PROC_TID_SMAPS, |
@@ -201,6 +203,7 @@ static struct pid_entry tgid_base_stuff[] = { | |||
201 | E(PROC_TGID_ROOT, "root", S_IFLNK|S_IRWXUGO), | 203 | E(PROC_TGID_ROOT, "root", S_IFLNK|S_IRWXUGO), |
202 | E(PROC_TGID_EXE, "exe", S_IFLNK|S_IRWXUGO), | 204 | E(PROC_TGID_EXE, "exe", S_IFLNK|S_IRWXUGO), |
203 | E(PROC_TGID_MOUNTS, "mounts", S_IFREG|S_IRUGO), | 205 | E(PROC_TGID_MOUNTS, "mounts", S_IFREG|S_IRUGO), |
206 | E(PROC_TGID_MOUNTSTATS, "mountstats", S_IFREG|S_IRUSR), | ||
204 | #ifdef CONFIG_MMU | 207 | #ifdef CONFIG_MMU |
205 | E(PROC_TGID_SMAPS, "smaps", S_IFREG|S_IRUGO), | 208 | E(PROC_TGID_SMAPS, "smaps", S_IFREG|S_IRUGO), |
206 | #endif | 209 | #endif |
@@ -732,6 +735,38 @@ static struct file_operations proc_mounts_operations = { | |||
732 | .poll = mounts_poll, | 735 | .poll = mounts_poll, |
733 | }; | 736 | }; |
734 | 737 | ||
738 | extern struct seq_operations mountstats_op; | ||
739 | static int mountstats_open(struct inode *inode, struct file *file) | ||
740 | { | ||
741 | struct task_struct *task = proc_task(inode); | ||
742 | int ret = seq_open(file, &mountstats_op); | ||
743 | |||
744 | if (!ret) { | ||
745 | struct seq_file *m = file->private_data; | ||
746 | struct namespace *namespace; | ||
747 | task_lock(task); | ||
748 | namespace = task->namespace; | ||
749 | if (namespace) | ||
750 | get_namespace(namespace); | ||
751 | task_unlock(task); | ||
752 | |||
753 | if (namespace) | ||
754 | m->private = namespace; | ||
755 | else { | ||
756 | seq_release(inode, file); | ||
757 | ret = -EINVAL; | ||
758 | } | ||
759 | } | ||
760 | return ret; | ||
761 | } | ||
762 | |||
763 | static struct file_operations proc_mountstats_operations = { | ||
764 | .open = mountstats_open, | ||
765 | .read = seq_read, | ||
766 | .llseek = seq_lseek, | ||
767 | .release = mounts_release, | ||
768 | }; | ||
769 | |||
735 | #define PROC_BLOCK_SIZE (3*1024) /* 4K page size but our output routines use some slack for overruns */ | 770 | #define PROC_BLOCK_SIZE (3*1024) /* 4K page size but our output routines use some slack for overruns */ |
736 | 771 | ||
737 | static ssize_t proc_info_read(struct file * file, char __user * buf, | 772 | static ssize_t proc_info_read(struct file * file, char __user * buf, |
@@ -1730,6 +1765,10 @@ static struct dentry *proc_pident_lookup(struct inode *dir, | |||
1730 | inode->i_fop = &proc_smaps_operations; | 1765 | inode->i_fop = &proc_smaps_operations; |
1731 | break; | 1766 | break; |
1732 | #endif | 1767 | #endif |
1768 | case PROC_TID_MOUNTSTATS: | ||
1769 | case PROC_TGID_MOUNTSTATS: | ||
1770 | inode->i_fop = &proc_mountstats_operations; | ||
1771 | break; | ||
1733 | #ifdef CONFIG_SECURITY | 1772 | #ifdef CONFIG_SECURITY |
1734 | case PROC_TID_ATTR: | 1773 | case PROC_TID_ATTR: |
1735 | inode->i_nlink = 2; | 1774 | inode->i_nlink = 2; |
diff --git a/fs/proc/generic.c b/fs/proc/generic.c index 20e5c4509a43..4ba03009cf72 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; |
@@ -537,7 +560,7 @@ static void proc_kill_inodes(struct proc_dir_entry *de) | |||
537 | struct file * filp = list_entry(p, struct file, f_u.fu_list); | 560 | struct file * filp = list_entry(p, struct file, f_u.fu_list); |
538 | struct dentry * dentry = filp->f_dentry; | 561 | struct dentry * dentry = filp->f_dentry; |
539 | struct inode * inode; | 562 | struct inode * inode; |
540 | struct file_operations *fops; | 563 | const struct file_operations *fops; |
541 | 564 | ||
542 | if (dentry->d_op != &proc_dentry_operations) | 565 | if (dentry->d_op != &proc_dentry_operations) |
543 | continue; | 566 | continue; |
@@ -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/inode.c b/fs/proc/inode.c index 075d3e945602..722b9c463111 100644 --- a/fs/proc/inode.c +++ b/fs/proc/inode.c | |||
@@ -121,7 +121,8 @@ int __init proc_init_inodecache(void) | |||
121 | { | 121 | { |
122 | proc_inode_cachep = kmem_cache_create("proc_inode_cache", | 122 | proc_inode_cachep = kmem_cache_create("proc_inode_cache", |
123 | sizeof(struct proc_inode), | 123 | sizeof(struct proc_inode), |
124 | 0, SLAB_RECLAIM_ACCOUNT, | 124 | 0, (SLAB_RECLAIM_ACCOUNT| |
125 | SLAB_MEM_SPREAD), | ||
125 | init_once, NULL); | 126 | init_once, NULL); |
126 | if (proc_inode_cachep == NULL) | 127 | if (proc_inode_cachep == NULL) |
127 | return -ENOMEM; | 128 | return -ENOMEM; |
diff --git a/fs/proc/internal.h b/fs/proc/internal.h index 95a1cf32b838..0502f17b860d 100644 --- a/fs/proc/internal.h +++ b/fs/proc/internal.h | |||
@@ -30,7 +30,7 @@ do { \ | |||
30 | 30 | ||
31 | #endif | 31 | #endif |
32 | 32 | ||
33 | extern void create_seq_entry(char *name, mode_t mode, struct file_operations *f); | 33 | extern void create_seq_entry(char *name, mode_t mode, const struct file_operations *f); |
34 | extern int proc_exe_link(struct inode *, struct dentry **, struct vfsmount **); | 34 | extern int proc_exe_link(struct inode *, struct dentry **, struct vfsmount **); |
35 | extern int proc_tid_stat(struct task_struct *, char *); | 35 | extern int proc_tid_stat(struct task_struct *, char *); |
36 | extern int proc_tgid_stat(struct task_struct *, char *); | 36 | extern int proc_tgid_stat(struct task_struct *, char *); |
diff --git a/fs/proc/kcore.c b/fs/proc/kcore.c index adc2cd95169a..17f6e8fa1397 100644 --- a/fs/proc/kcore.c +++ b/fs/proc/kcore.c | |||
@@ -31,7 +31,7 @@ static int open_kcore(struct inode * inode, struct file * filp) | |||
31 | 31 | ||
32 | static ssize_t read_kcore(struct file *, char __user *, size_t, loff_t *); | 32 | static ssize_t read_kcore(struct file *, char __user *, size_t, loff_t *); |
33 | 33 | ||
34 | struct file_operations proc_kcore_operations = { | 34 | const struct file_operations proc_kcore_operations = { |
35 | .read = read_kcore, | 35 | .read = read_kcore, |
36 | .open = open_kcore, | 36 | .open = open_kcore, |
37 | }; | 37 | }; |
diff --git a/fs/proc/kmsg.c b/fs/proc/kmsg.c index 10d37bf25206..ff3b90b56e9d 100644 --- a/fs/proc/kmsg.c +++ b/fs/proc/kmsg.c | |||
@@ -47,7 +47,7 @@ static unsigned int kmsg_poll(struct file *file, poll_table *wait) | |||
47 | } | 47 | } |
48 | 48 | ||
49 | 49 | ||
50 | struct file_operations proc_kmsg_operations = { | 50 | const struct file_operations proc_kmsg_operations = { |
51 | .read = kmsg_read, | 51 | .read = kmsg_read, |
52 | .poll = kmsg_poll, | 52 | .poll = kmsg_poll, |
53 | .open = kmsg_open, | 53 | .open = kmsg_open, |
diff --git a/fs/proc/proc_devtree.c b/fs/proc/proc_devtree.c index 9bdd077d6f55..abdf068bc27f 100644 --- a/fs/proc/proc_devtree.c +++ b/fs/proc/proc_devtree.c | |||
@@ -52,7 +52,8 @@ static int property_read_proc(char *page, char **start, off_t off, | |||
52 | * Add a property to a node | 52 | * Add a property to a node |
53 | */ | 53 | */ |
54 | static struct proc_dir_entry * | 54 | static struct proc_dir_entry * |
55 | __proc_device_tree_add_prop(struct proc_dir_entry *de, struct property *pp) | 55 | __proc_device_tree_add_prop(struct proc_dir_entry *de, struct property *pp, |
56 | const char *name) | ||
56 | { | 57 | { |
57 | struct proc_dir_entry *ent; | 58 | struct proc_dir_entry *ent; |
58 | 59 | ||
@@ -60,14 +61,14 @@ __proc_device_tree_add_prop(struct proc_dir_entry *de, struct property *pp) | |||
60 | * Unfortunately proc_register puts each new entry | 61 | * Unfortunately proc_register puts each new entry |
61 | * at the beginning of the list. So we rearrange them. | 62 | * at the beginning of the list. So we rearrange them. |
62 | */ | 63 | */ |
63 | ent = create_proc_read_entry(pp->name, | 64 | ent = create_proc_read_entry(name, |
64 | strncmp(pp->name, "security-", 9) | 65 | strncmp(name, "security-", 9) |
65 | ? S_IRUGO : S_IRUSR, de, | 66 | ? S_IRUGO : S_IRUSR, de, |
66 | property_read_proc, pp); | 67 | property_read_proc, pp); |
67 | if (ent == NULL) | 68 | if (ent == NULL) |
68 | return NULL; | 69 | return NULL; |
69 | 70 | ||
70 | if (!strncmp(pp->name, "security-", 9)) | 71 | if (!strncmp(name, "security-", 9)) |
71 | ent->size = 0; /* don't leak number of password chars */ | 72 | ent->size = 0; /* don't leak number of password chars */ |
72 | else | 73 | else |
73 | ent->size = pp->length; | 74 | ent->size = pp->length; |
@@ -78,7 +79,7 @@ __proc_device_tree_add_prop(struct proc_dir_entry *de, struct property *pp) | |||
78 | 79 | ||
79 | void proc_device_tree_add_prop(struct proc_dir_entry *pde, struct property *prop) | 80 | void proc_device_tree_add_prop(struct proc_dir_entry *pde, struct property *prop) |
80 | { | 81 | { |
81 | __proc_device_tree_add_prop(pde, prop); | 82 | __proc_device_tree_add_prop(pde, prop, prop->name); |
82 | } | 83 | } |
83 | 84 | ||
84 | void proc_device_tree_remove_prop(struct proc_dir_entry *pde, | 85 | void proc_device_tree_remove_prop(struct proc_dir_entry *pde, |
@@ -106,6 +107,69 @@ void proc_device_tree_update_prop(struct proc_dir_entry *pde, | |||
106 | } | 107 | } |
107 | 108 | ||
108 | /* | 109 | /* |
110 | * Various dodgy firmware might give us nodes and/or properties with | ||
111 | * conflicting names. That's generally ok, except for exporting via /proc, | ||
112 | * so munge names here to ensure they're unique. | ||
113 | */ | ||
114 | |||
115 | static int duplicate_name(struct proc_dir_entry *de, const char *name) | ||
116 | { | ||
117 | struct proc_dir_entry *ent; | ||
118 | int found = 0; | ||
119 | |||
120 | spin_lock(&proc_subdir_lock); | ||
121 | |||
122 | for (ent = de->subdir; ent != NULL; ent = ent->next) { | ||
123 | if (strcmp(ent->name, name) == 0) { | ||
124 | found = 1; | ||
125 | break; | ||
126 | } | ||
127 | } | ||
128 | |||
129 | spin_unlock(&proc_subdir_lock); | ||
130 | |||
131 | return found; | ||
132 | } | ||
133 | |||
134 | static const char *fixup_name(struct device_node *np, struct proc_dir_entry *de, | ||
135 | const char *name) | ||
136 | { | ||
137 | char *fixed_name; | ||
138 | int fixup_len = strlen(name) + 2 + 1; /* name + #x + \0 */ | ||
139 | int i = 1, size; | ||
140 | |||
141 | realloc: | ||
142 | fixed_name = kmalloc(fixup_len, GFP_KERNEL); | ||
143 | if (fixed_name == NULL) { | ||
144 | printk(KERN_ERR "device-tree: Out of memory trying to fixup " | ||
145 | "name \"%s\"\n", name); | ||
146 | return name; | ||
147 | } | ||
148 | |||
149 | retry: | ||
150 | size = snprintf(fixed_name, fixup_len, "%s#%d", name, i); | ||
151 | size++; /* account for NULL */ | ||
152 | |||
153 | if (size > fixup_len) { | ||
154 | /* We ran out of space, free and reallocate. */ | ||
155 | kfree(fixed_name); | ||
156 | fixup_len = size; | ||
157 | goto realloc; | ||
158 | } | ||
159 | |||
160 | if (duplicate_name(de, fixed_name)) { | ||
161 | /* Multiple duplicates. Retry with a different offset. */ | ||
162 | i++; | ||
163 | goto retry; | ||
164 | } | ||
165 | |||
166 | printk(KERN_WARNING "device-tree: Duplicate name in %s, " | ||
167 | "renamed to \"%s\"\n", np->full_name, fixed_name); | ||
168 | |||
169 | return fixed_name; | ||
170 | } | ||
171 | |||
172 | /* | ||
109 | * Process a node, adding entries for its children and its properties. | 173 | * Process a node, adding entries for its children and its properties. |
110 | */ | 174 | */ |
111 | void proc_device_tree_add_node(struct device_node *np, | 175 | void proc_device_tree_add_node(struct device_node *np, |
@@ -118,35 +182,30 @@ void proc_device_tree_add_node(struct device_node *np, | |||
118 | 182 | ||
119 | set_node_proc_entry(np, de); | 183 | set_node_proc_entry(np, de); |
120 | for (child = NULL; (child = of_get_next_child(np, child));) { | 184 | for (child = NULL; (child = of_get_next_child(np, child));) { |
185 | /* Use everything after the last slash, or the full name */ | ||
121 | p = strrchr(child->full_name, '/'); | 186 | p = strrchr(child->full_name, '/'); |
122 | if (!p) | 187 | if (!p) |
123 | p = child->full_name; | 188 | p = child->full_name; |
124 | else | 189 | else |
125 | ++p; | 190 | ++p; |
191 | |||
192 | if (duplicate_name(de, p)) | ||
193 | p = fixup_name(np, de, p); | ||
194 | |||
126 | ent = proc_mkdir(p, de); | 195 | ent = proc_mkdir(p, de); |
127 | if (ent == 0) | 196 | if (ent == 0) |
128 | break; | 197 | break; |
129 | proc_device_tree_add_node(child, ent); | 198 | proc_device_tree_add_node(child, ent); |
130 | } | 199 | } |
131 | of_node_put(child); | 200 | of_node_put(child); |
201 | |||
132 | for (pp = np->properties; pp != 0; pp = pp->next) { | 202 | for (pp = np->properties; pp != 0; pp = pp->next) { |
133 | /* | 203 | p = pp->name; |
134 | * Yet another Apple device-tree bogosity: on some machines, | 204 | |
135 | * they have properties & nodes with the same name. Those | 205 | if (duplicate_name(de, p)) |
136 | * properties are quite unimportant for us though, thus we | 206 | p = fixup_name(np, de, p); |
137 | * simply "skip" them here, but we do have to check. | ||
138 | */ | ||
139 | for (ent = de->subdir; ent != NULL; ent = ent->next) | ||
140 | if (!strcmp(ent->name, pp->name)) | ||
141 | break; | ||
142 | if (ent != NULL) { | ||
143 | printk(KERN_WARNING "device-tree: property \"%s\" name" | ||
144 | " conflicts with node in %s\n", pp->name, | ||
145 | np->full_name); | ||
146 | continue; | ||
147 | } | ||
148 | 207 | ||
149 | ent = __proc_device_tree_add_prop(de, pp); | 208 | ent = __proc_device_tree_add_prop(de, pp, p); |
150 | if (ent == 0) | 209 | if (ent == 0) |
151 | break; | 210 | break; |
152 | } | 211 | } |
diff --git a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c index 1d24fead51a6..ef5a3323f4b5 100644 --- a/fs/proc/proc_misc.c +++ b/fs/proc/proc_misc.c | |||
@@ -312,7 +312,7 @@ static void *devinfo_next(struct seq_file *f, void *v, loff_t *pos) | |||
312 | case BLK_HDR: | 312 | case BLK_HDR: |
313 | info->state = BLK_LIST; | 313 | info->state = BLK_LIST; |
314 | (*pos)++; | 314 | (*pos)++; |
315 | break; | 315 | /*fallthrough*/ |
316 | case BLK_LIST: | 316 | case BLK_LIST: |
317 | if (get_blkdev_info(info->blkdev,&idummy,&ndummy)) { | 317 | if (get_blkdev_info(info->blkdev,&idummy,&ndummy)) { |
318 | /* | 318 | /* |
@@ -485,6 +485,40 @@ static struct file_operations proc_slabinfo_operations = { | |||
485 | .llseek = seq_lseek, | 485 | .llseek = seq_lseek, |
486 | .release = seq_release, | 486 | .release = seq_release, |
487 | }; | 487 | }; |
488 | |||
489 | #ifdef CONFIG_DEBUG_SLAB_LEAK | ||
490 | extern struct seq_operations slabstats_op; | ||
491 | static int slabstats_open(struct inode *inode, struct file *file) | ||
492 | { | ||
493 | unsigned long *n = kzalloc(PAGE_SIZE, GFP_KERNEL); | ||
494 | int ret = -ENOMEM; | ||
495 | if (n) { | ||
496 | ret = seq_open(file, &slabstats_op); | ||
497 | if (!ret) { | ||
498 | struct seq_file *m = file->private_data; | ||
499 | *n = PAGE_SIZE / (2 * sizeof(unsigned long)); | ||
500 | m->private = n; | ||
501 | n = NULL; | ||
502 | } | ||
503 | kfree(n); | ||
504 | } | ||
505 | return ret; | ||
506 | } | ||
507 | |||
508 | static int slabstats_release(struct inode *inode, struct file *file) | ||
509 | { | ||
510 | struct seq_file *m = file->private_data; | ||
511 | kfree(m->private); | ||
512 | return seq_release(inode, file); | ||
513 | } | ||
514 | |||
515 | static struct file_operations proc_slabstats_operations = { | ||
516 | .open = slabstats_open, | ||
517 | .read = seq_read, | ||
518 | .llseek = seq_lseek, | ||
519 | .release = slabstats_release, | ||
520 | }; | ||
521 | #endif | ||
488 | #endif | 522 | #endif |
489 | 523 | ||
490 | static int show_stat(struct seq_file *p, void *v) | 524 | static int show_stat(struct seq_file *p, void *v) |
@@ -500,7 +534,7 @@ static int show_stat(struct seq_file *p, void *v) | |||
500 | if (wall_to_monotonic.tv_nsec) | 534 | if (wall_to_monotonic.tv_nsec) |
501 | --jif; | 535 | --jif; |
502 | 536 | ||
503 | for_each_cpu(i) { | 537 | for_each_possible_cpu(i) { |
504 | int j; | 538 | int j; |
505 | 539 | ||
506 | user = cputime64_add(user, kstat_cpu(i).cpustat.user); | 540 | user = cputime64_add(user, kstat_cpu(i).cpustat.user); |
@@ -697,7 +731,7 @@ static struct file_operations proc_sysrq_trigger_operations = { | |||
697 | 731 | ||
698 | struct proc_dir_entry *proc_root_kcore; | 732 | struct proc_dir_entry *proc_root_kcore; |
699 | 733 | ||
700 | void create_seq_entry(char *name, mode_t mode, struct file_operations *f) | 734 | void create_seq_entry(char *name, mode_t mode, const struct file_operations *f) |
701 | { | 735 | { |
702 | struct proc_dir_entry *entry; | 736 | struct proc_dir_entry *entry; |
703 | entry = create_proc_entry(name, mode, NULL); | 737 | entry = create_proc_entry(name, mode, NULL); |
@@ -744,6 +778,9 @@ void __init proc_misc_init(void) | |||
744 | create_seq_entry("interrupts", 0, &proc_interrupts_operations); | 778 | create_seq_entry("interrupts", 0, &proc_interrupts_operations); |
745 | #ifdef CONFIG_SLAB | 779 | #ifdef CONFIG_SLAB |
746 | create_seq_entry("slabinfo",S_IWUSR|S_IRUGO,&proc_slabinfo_operations); | 780 | create_seq_entry("slabinfo",S_IWUSR|S_IRUGO,&proc_slabinfo_operations); |
781 | #ifdef CONFIG_DEBUG_SLAB_LEAK | ||
782 | create_seq_entry("slab_allocators", 0 ,&proc_slabstats_operations); | ||
783 | #endif | ||
747 | #endif | 784 | #endif |
748 | create_seq_entry("buddyinfo",S_IRUGO, &fragmentation_file_operations); | 785 | create_seq_entry("buddyinfo",S_IRUGO, &fragmentation_file_operations); |
749 | create_seq_entry("vmstat",S_IRUGO, &proc_vmstat_file_operations); | 786 | create_seq_entry("vmstat",S_IRUGO, &proc_vmstat_file_operations); |
diff --git a/fs/proc/vmcore.c b/fs/proc/vmcore.c index 4063fb32f78c..7efa73d44c9a 100644 --- a/fs/proc/vmcore.c +++ b/fs/proc/vmcore.c | |||
@@ -172,7 +172,7 @@ static int open_vmcore(struct inode *inode, struct file *filp) | |||
172 | return 0; | 172 | return 0; |
173 | } | 173 | } |
174 | 174 | ||
175 | struct file_operations proc_vmcore_operations = { | 175 | const struct file_operations proc_vmcore_operations = { |
176 | .read = read_vmcore, | 176 | .read = read_vmcore, |
177 | .open = open_vmcore, | 177 | .open = open_vmcore, |
178 | }; | 178 | }; |