diff options
Diffstat (limited to 'fs/proc')
| -rw-r--r-- | fs/proc/Makefile | 2 | ||||
| -rw-r--r-- | fs/proc/array.c | 1 | ||||
| -rw-r--r-- | fs/proc/base.c | 100 | ||||
| -rw-r--r-- | fs/proc/generic.c | 119 | ||||
| -rw-r--r-- | fs/proc/inode.c | 6 | ||||
| -rw-r--r-- | fs/proc/internal.h | 18 | ||||
| -rw-r--r-- | fs/proc/kcore.c | 9 | ||||
| -rw-r--r-- | fs/proc/meminfo.c | 1 | ||||
| -rw-r--r-- | fs/proc/mmu.c | 60 | ||||
| -rw-r--r-- | fs/proc/namespaces.c | 12 | ||||
| -rw-r--r-- | fs/proc/root.c | 4 |
11 files changed, 211 insertions, 121 deletions
diff --git a/fs/proc/Makefile b/fs/proc/Makefile index 712f24db9600..ab30716584f5 100644 --- a/fs/proc/Makefile +++ b/fs/proc/Makefile | |||
| @@ -5,7 +5,7 @@ | |||
| 5 | obj-y += proc.o | 5 | obj-y += proc.o |
| 6 | 6 | ||
| 7 | proc-y := nommu.o task_nommu.o | 7 | proc-y := nommu.o task_nommu.o |
| 8 | proc-$(CONFIG_MMU) := mmu.o task_mmu.o | 8 | proc-$(CONFIG_MMU) := task_mmu.o |
| 9 | 9 | ||
| 10 | proc-y += inode.o root.o base.o generic.o array.o \ | 10 | proc-y += inode.o root.o base.o generic.o array.o \ |
| 11 | fd.o | 11 | fd.o |
diff --git a/fs/proc/array.c b/fs/proc/array.c index f7ed9ee46eb9..cbd0f1b324b9 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c | |||
| @@ -143,6 +143,7 @@ static const char * const task_state_array[] = { | |||
| 143 | "x (dead)", /* 64 */ | 143 | "x (dead)", /* 64 */ |
| 144 | "K (wakekill)", /* 128 */ | 144 | "K (wakekill)", /* 128 */ |
| 145 | "W (waking)", /* 256 */ | 145 | "W (waking)", /* 256 */ |
| 146 | "P (parked)", /* 512 */ | ||
| 146 | }; | 147 | }; |
| 147 | 148 | ||
| 148 | static inline const char *get_task_state(struct task_struct *tsk) | 149 | static inline const char *get_task_state(struct task_struct *tsk) |
diff --git a/fs/proc/base.c b/fs/proc/base.c index 69078c7cef1f..a19308604145 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c | |||
| @@ -86,6 +86,7 @@ | |||
| 86 | #include <linux/fs_struct.h> | 86 | #include <linux/fs_struct.h> |
| 87 | #include <linux/slab.h> | 87 | #include <linux/slab.h> |
| 88 | #include <linux/flex_array.h> | 88 | #include <linux/flex_array.h> |
| 89 | #include <linux/posix-timers.h> | ||
| 89 | #ifdef CONFIG_HARDWALL | 90 | #ifdef CONFIG_HARDWALL |
| 90 | #include <asm/hardwall.h> | 91 | #include <asm/hardwall.h> |
| 91 | #endif | 92 | #endif |
| @@ -2013,6 +2014,102 @@ static const struct file_operations proc_map_files_operations = { | |||
| 2013 | .llseek = default_llseek, | 2014 | .llseek = default_llseek, |
| 2014 | }; | 2015 | }; |
| 2015 | 2016 | ||
| 2017 | struct timers_private { | ||
| 2018 | struct pid *pid; | ||
| 2019 | struct task_struct *task; | ||
| 2020 | struct sighand_struct *sighand; | ||
| 2021 | struct pid_namespace *ns; | ||
| 2022 | unsigned long flags; | ||
| 2023 | }; | ||
| 2024 | |||
| 2025 | static void *timers_start(struct seq_file *m, loff_t *pos) | ||
| 2026 | { | ||
| 2027 | struct timers_private *tp = m->private; | ||
| 2028 | |||
| 2029 | tp->task = get_pid_task(tp->pid, PIDTYPE_PID); | ||
| 2030 | if (!tp->task) | ||
| 2031 | return ERR_PTR(-ESRCH); | ||
| 2032 | |||
| 2033 | tp->sighand = lock_task_sighand(tp->task, &tp->flags); | ||
| 2034 | if (!tp->sighand) | ||
| 2035 | return ERR_PTR(-ESRCH); | ||
| 2036 | |||
| 2037 | return seq_list_start(&tp->task->signal->posix_timers, *pos); | ||
| 2038 | } | ||
| 2039 | |||
| 2040 | static void *timers_next(struct seq_file *m, void *v, loff_t *pos) | ||
| 2041 | { | ||
| 2042 | struct timers_private *tp = m->private; | ||
| 2043 | return seq_list_next(v, &tp->task->signal->posix_timers, pos); | ||
| 2044 | } | ||
| 2045 | |||
| 2046 | static void timers_stop(struct seq_file *m, void *v) | ||
| 2047 | { | ||
| 2048 | struct timers_private *tp = m->private; | ||
| 2049 | |||
| 2050 | if (tp->sighand) { | ||
| 2051 | unlock_task_sighand(tp->task, &tp->flags); | ||
| 2052 | tp->sighand = NULL; | ||
| 2053 | } | ||
| 2054 | |||
| 2055 | if (tp->task) { | ||
| 2056 | put_task_struct(tp->task); | ||
| 2057 | tp->task = NULL; | ||
| 2058 | } | ||
| 2059 | } | ||
| 2060 | |||
| 2061 | static int show_timer(struct seq_file *m, void *v) | ||
| 2062 | { | ||
| 2063 | struct k_itimer *timer; | ||
| 2064 | struct timers_private *tp = m->private; | ||
| 2065 | int notify; | ||
| 2066 | static char *nstr[] = { | ||
| 2067 | [SIGEV_SIGNAL] = "signal", | ||
| 2068 | [SIGEV_NONE] = "none", | ||
| 2069 | [SIGEV_THREAD] = "thread", | ||
| 2070 | }; | ||
| 2071 | |||
| 2072 | timer = list_entry((struct list_head *)v, struct k_itimer, list); | ||
| 2073 | notify = timer->it_sigev_notify; | ||
| 2074 | |||
| 2075 | seq_printf(m, "ID: %d\n", timer->it_id); | ||
| 2076 | seq_printf(m, "signal: %d/%p\n", timer->sigq->info.si_signo, | ||
| 2077 | timer->sigq->info.si_value.sival_ptr); | ||
| 2078 | seq_printf(m, "notify: %s/%s.%d\n", | ||
| 2079 | nstr[notify & ~SIGEV_THREAD_ID], | ||
| 2080 | (notify & SIGEV_THREAD_ID) ? "tid" : "pid", | ||
| 2081 | pid_nr_ns(timer->it_pid, tp->ns)); | ||
| 2082 | |||
| 2083 | return 0; | ||
| 2084 | } | ||
| 2085 | |||
| 2086 | static const struct seq_operations proc_timers_seq_ops = { | ||
| 2087 | .start = timers_start, | ||
| 2088 | .next = timers_next, | ||
| 2089 | .stop = timers_stop, | ||
| 2090 | .show = show_timer, | ||
| 2091 | }; | ||
| 2092 | |||
| 2093 | static int proc_timers_open(struct inode *inode, struct file *file) | ||
| 2094 | { | ||
| 2095 | struct timers_private *tp; | ||
| 2096 | |||
| 2097 | tp = __seq_open_private(file, &proc_timers_seq_ops, | ||
| 2098 | sizeof(struct timers_private)); | ||
| 2099 | if (!tp) | ||
| 2100 | return -ENOMEM; | ||
| 2101 | |||
| 2102 | tp->pid = proc_pid(inode); | ||
| 2103 | tp->ns = inode->i_sb->s_fs_info; | ||
| 2104 | return 0; | ||
| 2105 | } | ||
| 2106 | |||
| 2107 | static const struct file_operations proc_timers_operations = { | ||
| 2108 | .open = proc_timers_open, | ||
| 2109 | .read = seq_read, | ||
| 2110 | .llseek = seq_lseek, | ||
| 2111 | .release = seq_release_private, | ||
| 2112 | }; | ||
| 2016 | #endif /* CONFIG_CHECKPOINT_RESTORE */ | 2113 | #endif /* CONFIG_CHECKPOINT_RESTORE */ |
| 2017 | 2114 | ||
| 2018 | static struct dentry *proc_pident_instantiate(struct inode *dir, | 2115 | static struct dentry *proc_pident_instantiate(struct inode *dir, |
| @@ -2583,6 +2680,9 @@ static const struct pid_entry tgid_base_stuff[] = { | |||
| 2583 | REG("gid_map", S_IRUGO|S_IWUSR, proc_gid_map_operations), | 2680 | REG("gid_map", S_IRUGO|S_IWUSR, proc_gid_map_operations), |
| 2584 | REG("projid_map", S_IRUGO|S_IWUSR, proc_projid_map_operations), | 2681 | REG("projid_map", S_IRUGO|S_IWUSR, proc_projid_map_operations), |
| 2585 | #endif | 2682 | #endif |
| 2683 | #ifdef CONFIG_CHECKPOINT_RESTORE | ||
| 2684 | REG("timers", S_IRUGO, proc_timers_operations), | ||
| 2685 | #endif | ||
| 2586 | }; | 2686 | }; |
| 2587 | 2687 | ||
| 2588 | static int proc_tgid_base_readdir(struct file * filp, | 2688 | static int proc_tgid_base_readdir(struct file * filp, |
diff --git a/fs/proc/generic.c b/fs/proc/generic.c index 4b3b3ffb52f1..21e1a8f1659d 100644 --- a/fs/proc/generic.c +++ b/fs/proc/generic.c | |||
| @@ -755,37 +755,8 @@ void pde_put(struct proc_dir_entry *pde) | |||
| 755 | free_proc_entry(pde); | 755 | free_proc_entry(pde); |
| 756 | } | 756 | } |
| 757 | 757 | ||
| 758 | /* | 758 | static void entry_rundown(struct proc_dir_entry *de) |
| 759 | * Remove a /proc entry and free it if it's not currently in use. | ||
| 760 | */ | ||
| 761 | void remove_proc_entry(const char *name, struct proc_dir_entry *parent) | ||
| 762 | { | 759 | { |
| 763 | struct proc_dir_entry **p; | ||
| 764 | struct proc_dir_entry *de = NULL; | ||
| 765 | const char *fn = name; | ||
| 766 | unsigned int len; | ||
| 767 | |||
| 768 | spin_lock(&proc_subdir_lock); | ||
| 769 | if (__xlate_proc_name(name, &parent, &fn) != 0) { | ||
| 770 | spin_unlock(&proc_subdir_lock); | ||
| 771 | return; | ||
| 772 | } | ||
| 773 | len = strlen(fn); | ||
| 774 | |||
| 775 | for (p = &parent->subdir; *p; p=&(*p)->next ) { | ||
| 776 | if (proc_match(len, fn, *p)) { | ||
| 777 | de = *p; | ||
| 778 | *p = de->next; | ||
| 779 | de->next = NULL; | ||
| 780 | break; | ||
| 781 | } | ||
| 782 | } | ||
| 783 | spin_unlock(&proc_subdir_lock); | ||
| 784 | if (!de) { | ||
| 785 | WARN(1, "name '%s'\n", name); | ||
| 786 | return; | ||
| 787 | } | ||
| 788 | |||
| 789 | spin_lock(&de->pde_unload_lock); | 760 | spin_lock(&de->pde_unload_lock); |
| 790 | /* | 761 | /* |
| 791 | * Stop accepting new callers into module. If you're | 762 | * Stop accepting new callers into module. If you're |
| @@ -817,6 +788,40 @@ void remove_proc_entry(const char *name, struct proc_dir_entry *parent) | |||
| 817 | spin_lock(&de->pde_unload_lock); | 788 | spin_lock(&de->pde_unload_lock); |
| 818 | } | 789 | } |
| 819 | spin_unlock(&de->pde_unload_lock); | 790 | spin_unlock(&de->pde_unload_lock); |
| 791 | } | ||
| 792 | |||
| 793 | /* | ||
| 794 | * Remove a /proc entry and free it if it's not currently in use. | ||
| 795 | */ | ||
| 796 | void remove_proc_entry(const char *name, struct proc_dir_entry *parent) | ||
| 797 | { | ||
| 798 | struct proc_dir_entry **p; | ||
| 799 | struct proc_dir_entry *de = NULL; | ||
| 800 | const char *fn = name; | ||
| 801 | unsigned int len; | ||
| 802 | |||
| 803 | spin_lock(&proc_subdir_lock); | ||
| 804 | if (__xlate_proc_name(name, &parent, &fn) != 0) { | ||
| 805 | spin_unlock(&proc_subdir_lock); | ||
| 806 | return; | ||
| 807 | } | ||
| 808 | len = strlen(fn); | ||
| 809 | |||
| 810 | for (p = &parent->subdir; *p; p=&(*p)->next ) { | ||
| 811 | if (proc_match(len, fn, *p)) { | ||
| 812 | de = *p; | ||
| 813 | *p = de->next; | ||
| 814 | de->next = NULL; | ||
| 815 | break; | ||
| 816 | } | ||
| 817 | } | ||
| 818 | spin_unlock(&proc_subdir_lock); | ||
| 819 | if (!de) { | ||
| 820 | WARN(1, "name '%s'\n", name); | ||
| 821 | return; | ||
| 822 | } | ||
| 823 | |||
| 824 | entry_rundown(de); | ||
| 820 | 825 | ||
| 821 | if (S_ISDIR(de->mode)) | 826 | if (S_ISDIR(de->mode)) |
| 822 | parent->nlink--; | 827 | parent->nlink--; |
| @@ -827,3 +832,57 @@ void remove_proc_entry(const char *name, struct proc_dir_entry *parent) | |||
| 827 | pde_put(de); | 832 | pde_put(de); |
| 828 | } | 833 | } |
| 829 | EXPORT_SYMBOL(remove_proc_entry); | 834 | EXPORT_SYMBOL(remove_proc_entry); |
| 835 | |||
| 836 | int remove_proc_subtree(const char *name, struct proc_dir_entry *parent) | ||
| 837 | { | ||
| 838 | struct proc_dir_entry **p; | ||
| 839 | struct proc_dir_entry *root = NULL, *de, *next; | ||
| 840 | const char *fn = name; | ||
| 841 | unsigned int len; | ||
| 842 | |||
| 843 | spin_lock(&proc_subdir_lock); | ||
| 844 | if (__xlate_proc_name(name, &parent, &fn) != 0) { | ||
| 845 | spin_unlock(&proc_subdir_lock); | ||
| 846 | return -ENOENT; | ||
| 847 | } | ||
| 848 | len = strlen(fn); | ||
| 849 | |||
| 850 | for (p = &parent->subdir; *p; p=&(*p)->next ) { | ||
| 851 | if (proc_match(len, fn, *p)) { | ||
| 852 | root = *p; | ||
| 853 | *p = root->next; | ||
| 854 | root->next = NULL; | ||
| 855 | break; | ||
| 856 | } | ||
| 857 | } | ||
| 858 | if (!root) { | ||
| 859 | spin_unlock(&proc_subdir_lock); | ||
| 860 | return -ENOENT; | ||
| 861 | } | ||
| 862 | de = root; | ||
| 863 | while (1) { | ||
| 864 | next = de->subdir; | ||
| 865 | if (next) { | ||
| 866 | de->subdir = next->next; | ||
| 867 | next->next = NULL; | ||
| 868 | de = next; | ||
| 869 | continue; | ||
| 870 | } | ||
| 871 | spin_unlock(&proc_subdir_lock); | ||
| 872 | |||
| 873 | entry_rundown(de); | ||
| 874 | next = de->parent; | ||
| 875 | if (S_ISDIR(de->mode)) | ||
| 876 | next->nlink--; | ||
| 877 | de->nlink = 0; | ||
| 878 | if (de == root) | ||
| 879 | break; | ||
| 880 | pde_put(de); | ||
| 881 | |||
| 882 | spin_lock(&proc_subdir_lock); | ||
| 883 | de = next; | ||
| 884 | } | ||
| 885 | pde_put(root); | ||
| 886 | return 0; | ||
| 887 | } | ||
| 888 | EXPORT_SYMBOL(remove_proc_subtree); | ||
diff --git a/fs/proc/inode.c b/fs/proc/inode.c index a86aebc9ba7c..869116c2afbe 100644 --- a/fs/proc/inode.c +++ b/fs/proc/inode.c | |||
| @@ -446,9 +446,10 @@ static const struct file_operations proc_reg_file_ops_no_compat = { | |||
| 446 | 446 | ||
| 447 | struct inode *proc_get_inode(struct super_block *sb, struct proc_dir_entry *de) | 447 | struct inode *proc_get_inode(struct super_block *sb, struct proc_dir_entry *de) |
| 448 | { | 448 | { |
| 449 | struct inode *inode = iget_locked(sb, de->low_ino); | 449 | struct inode *inode = new_inode_pseudo(sb); |
| 450 | 450 | ||
| 451 | if (inode && (inode->i_state & I_NEW)) { | 451 | if (inode) { |
| 452 | inode->i_ino = de->low_ino; | ||
| 452 | inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; | 453 | inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; |
| 453 | PROC_I(inode)->pde = de; | 454 | PROC_I(inode)->pde = de; |
| 454 | 455 | ||
| @@ -476,7 +477,6 @@ struct inode *proc_get_inode(struct super_block *sb, struct proc_dir_entry *de) | |||
| 476 | inode->i_fop = de->proc_fops; | 477 | inode->i_fop = de->proc_fops; |
| 477 | } | 478 | } |
| 478 | } | 479 | } |
| 479 | unlock_new_inode(inode); | ||
| 480 | } else | 480 | } else |
| 481 | pde_put(de); | 481 | pde_put(de); |
| 482 | return inode; | 482 | return inode; |
diff --git a/fs/proc/internal.h b/fs/proc/internal.h index 85ff3a4598b3..75710357a517 100644 --- a/fs/proc/internal.h +++ b/fs/proc/internal.h | |||
| @@ -30,24 +30,6 @@ extern int proc_net_init(void); | |||
| 30 | static inline int proc_net_init(void) { return 0; } | 30 | static inline int proc_net_init(void) { return 0; } |
| 31 | #endif | 31 | #endif |
| 32 | 32 | ||
| 33 | struct vmalloc_info { | ||
| 34 | unsigned long used; | ||
| 35 | unsigned long largest_chunk; | ||
| 36 | }; | ||
| 37 | |||
| 38 | #ifdef CONFIG_MMU | ||
| 39 | #define VMALLOC_TOTAL (VMALLOC_END - VMALLOC_START) | ||
| 40 | extern void get_vmalloc_info(struct vmalloc_info *vmi); | ||
| 41 | #else | ||
| 42 | |||
| 43 | #define VMALLOC_TOTAL 0UL | ||
| 44 | #define get_vmalloc_info(vmi) \ | ||
| 45 | do { \ | ||
| 46 | (vmi)->used = 0; \ | ||
| 47 | (vmi)->largest_chunk = 0; \ | ||
| 48 | } while(0) | ||
| 49 | #endif | ||
| 50 | |||
| 51 | extern int proc_tid_stat(struct seq_file *m, struct pid_namespace *ns, | 33 | extern int proc_tid_stat(struct seq_file *m, struct pid_namespace *ns, |
| 52 | struct pid *pid, struct task_struct *task); | 34 | struct pid *pid, struct task_struct *task); |
| 53 | extern int proc_tgid_stat(struct seq_file *m, struct pid_namespace *ns, | 35 | extern int proc_tgid_stat(struct seq_file *m, struct pid_namespace *ns, |
diff --git a/fs/proc/kcore.c b/fs/proc/kcore.c index eda6f017f272..f6a13f489e30 100644 --- a/fs/proc/kcore.c +++ b/fs/proc/kcore.c | |||
| @@ -15,6 +15,7 @@ | |||
| 15 | #include <linux/capability.h> | 15 | #include <linux/capability.h> |
| 16 | #include <linux/elf.h> | 16 | #include <linux/elf.h> |
| 17 | #include <linux/elfcore.h> | 17 | #include <linux/elfcore.h> |
| 18 | #include <linux/notifier.h> | ||
| 18 | #include <linux/vmalloc.h> | 19 | #include <linux/vmalloc.h> |
| 19 | #include <linux/highmem.h> | 20 | #include <linux/highmem.h> |
| 20 | #include <linux/printk.h> | 21 | #include <linux/printk.h> |
| @@ -564,7 +565,6 @@ static const struct file_operations proc_kcore_operations = { | |||
| 564 | .llseek = default_llseek, | 565 | .llseek = default_llseek, |
| 565 | }; | 566 | }; |
| 566 | 567 | ||
| 567 | #ifdef CONFIG_MEMORY_HOTPLUG | ||
| 568 | /* just remember that we have to update kcore */ | 568 | /* just remember that we have to update kcore */ |
| 569 | static int __meminit kcore_callback(struct notifier_block *self, | 569 | static int __meminit kcore_callback(struct notifier_block *self, |
| 570 | unsigned long action, void *arg) | 570 | unsigned long action, void *arg) |
| @@ -578,8 +578,11 @@ static int __meminit kcore_callback(struct notifier_block *self, | |||
| 578 | } | 578 | } |
| 579 | return NOTIFY_OK; | 579 | return NOTIFY_OK; |
| 580 | } | 580 | } |
| 581 | #endif | ||
| 582 | 581 | ||
| 582 | static struct notifier_block kcore_callback_nb __meminitdata = { | ||
| 583 | .notifier_call = kcore_callback, | ||
| 584 | .priority = 0, | ||
| 585 | }; | ||
| 583 | 586 | ||
| 584 | static struct kcore_list kcore_vmalloc; | 587 | static struct kcore_list kcore_vmalloc; |
| 585 | 588 | ||
| @@ -631,7 +634,7 @@ static int __init proc_kcore_init(void) | |||
| 631 | add_modules_range(); | 634 | add_modules_range(); |
| 632 | /* Store direct-map area from physical memory map */ | 635 | /* Store direct-map area from physical memory map */ |
| 633 | kcore_update_ram(); | 636 | kcore_update_ram(); |
| 634 | hotplug_memory_notifier(kcore_callback, 0); | 637 | register_hotmemory_notifier(&kcore_callback_nb); |
| 635 | 638 | ||
| 636 | return 0; | 639 | return 0; |
| 637 | } | 640 | } |
diff --git a/fs/proc/meminfo.c b/fs/proc/meminfo.c index 1efaaa19c4f3..5aa847a603c0 100644 --- a/fs/proc/meminfo.c +++ b/fs/proc/meminfo.c | |||
| @@ -11,6 +11,7 @@ | |||
| 11 | #include <linux/swap.h> | 11 | #include <linux/swap.h> |
| 12 | #include <linux/vmstat.h> | 12 | #include <linux/vmstat.h> |
| 13 | #include <linux/atomic.h> | 13 | #include <linux/atomic.h> |
| 14 | #include <linux/vmalloc.h> | ||
| 14 | #include <asm/page.h> | 15 | #include <asm/page.h> |
| 15 | #include <asm/pgtable.h> | 16 | #include <asm/pgtable.h> |
| 16 | #include "internal.h" | 17 | #include "internal.h" |
diff --git a/fs/proc/mmu.c b/fs/proc/mmu.c deleted file mode 100644 index 8ae221dfd010..000000000000 --- a/fs/proc/mmu.c +++ /dev/null | |||
| @@ -1,60 +0,0 @@ | |||
| 1 | /* mmu.c: mmu memory info files | ||
| 2 | * | ||
| 3 | * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved. | ||
| 4 | * Written by David Howells (dhowells@redhat.com) | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of the GNU General Public License | ||
| 8 | * as published by the Free Software Foundation; either version | ||
| 9 | * 2 of the License, or (at your option) any later version. | ||
| 10 | */ | ||
| 11 | #include <linux/spinlock.h> | ||
| 12 | #include <linux/vmalloc.h> | ||
| 13 | #include <linux/highmem.h> | ||
| 14 | #include <asm/pgtable.h> | ||
| 15 | #include "internal.h" | ||
| 16 | |||
| 17 | void get_vmalloc_info(struct vmalloc_info *vmi) | ||
| 18 | { | ||
| 19 | struct vm_struct *vma; | ||
| 20 | unsigned long free_area_size; | ||
| 21 | unsigned long prev_end; | ||
| 22 | |||
| 23 | vmi->used = 0; | ||
| 24 | |||
| 25 | if (!vmlist) { | ||
| 26 | vmi->largest_chunk = VMALLOC_TOTAL; | ||
| 27 | } | ||
| 28 | else { | ||
| 29 | vmi->largest_chunk = 0; | ||
| 30 | |||
| 31 | prev_end = VMALLOC_START; | ||
| 32 | |||
| 33 | read_lock(&vmlist_lock); | ||
| 34 | |||
| 35 | for (vma = vmlist; vma; vma = vma->next) { | ||
| 36 | unsigned long addr = (unsigned long) vma->addr; | ||
| 37 | |||
| 38 | /* | ||
| 39 | * Some archs keep another range for modules in vmlist | ||
| 40 | */ | ||
| 41 | if (addr < VMALLOC_START) | ||
| 42 | continue; | ||
| 43 | if (addr >= VMALLOC_END) | ||
| 44 | break; | ||
| 45 | |||
| 46 | vmi->used += vma->size; | ||
| 47 | |||
| 48 | free_area_size = addr - prev_end; | ||
| 49 | if (vmi->largest_chunk < free_area_size) | ||
| 50 | vmi->largest_chunk = free_area_size; | ||
| 51 | |||
| 52 | prev_end = vma->size + addr; | ||
| 53 | } | ||
| 54 | |||
| 55 | if (VMALLOC_END - prev_end > vmi->largest_chunk) | ||
| 56 | vmi->largest_chunk = VMALLOC_END - prev_end; | ||
| 57 | |||
| 58 | read_unlock(&vmlist_lock); | ||
| 59 | } | ||
| 60 | } | ||
diff --git a/fs/proc/namespaces.c b/fs/proc/namespaces.c index b7a47196c8c3..66b51c0383da 100644 --- a/fs/proc/namespaces.c +++ b/fs/proc/namespaces.c | |||
| @@ -118,7 +118,7 @@ static void *proc_ns_follow_link(struct dentry *dentry, struct nameidata *nd) | |||
| 118 | struct super_block *sb = inode->i_sb; | 118 | struct super_block *sb = inode->i_sb; |
| 119 | struct proc_inode *ei = PROC_I(inode); | 119 | struct proc_inode *ei = PROC_I(inode); |
| 120 | struct task_struct *task; | 120 | struct task_struct *task; |
| 121 | struct dentry *ns_dentry; | 121 | struct path ns_path; |
| 122 | void *error = ERR_PTR(-EACCES); | 122 | void *error = ERR_PTR(-EACCES); |
| 123 | 123 | ||
| 124 | task = get_proc_task(inode); | 124 | task = get_proc_task(inode); |
| @@ -128,14 +128,14 @@ static void *proc_ns_follow_link(struct dentry *dentry, struct nameidata *nd) | |||
| 128 | if (!ptrace_may_access(task, PTRACE_MODE_READ)) | 128 | if (!ptrace_may_access(task, PTRACE_MODE_READ)) |
| 129 | goto out_put_task; | 129 | goto out_put_task; |
| 130 | 130 | ||
| 131 | ns_dentry = proc_ns_get_dentry(sb, task, ei->ns_ops); | 131 | ns_path.dentry = proc_ns_get_dentry(sb, task, ei->ns_ops); |
| 132 | if (IS_ERR(ns_dentry)) { | 132 | if (IS_ERR(ns_path.dentry)) { |
| 133 | error = ERR_CAST(ns_dentry); | 133 | error = ERR_CAST(ns_path.dentry); |
| 134 | goto out_put_task; | 134 | goto out_put_task; |
| 135 | } | 135 | } |
| 136 | 136 | ||
| 137 | dput(nd->path.dentry); | 137 | ns_path.mnt = mntget(nd->path.mnt); |
| 138 | nd->path.dentry = ns_dentry; | 138 | nd_jump_link(nd, &ns_path); |
| 139 | error = NULL; | 139 | error = NULL; |
| 140 | 140 | ||
| 141 | out_put_task: | 141 | out_put_task: |
diff --git a/fs/proc/root.c b/fs/proc/root.c index c6e9fac26bac..9c7fab1d23f0 100644 --- a/fs/proc/root.c +++ b/fs/proc/root.c | |||
| @@ -16,6 +16,7 @@ | |||
| 16 | #include <linux/sched.h> | 16 | #include <linux/sched.h> |
| 17 | #include <linux/module.h> | 17 | #include <linux/module.h> |
| 18 | #include <linux/bitops.h> | 18 | #include <linux/bitops.h> |
| 19 | #include <linux/user_namespace.h> | ||
| 19 | #include <linux/mount.h> | 20 | #include <linux/mount.h> |
| 20 | #include <linux/pid_namespace.h> | 21 | #include <linux/pid_namespace.h> |
| 21 | #include <linux/parser.h> | 22 | #include <linux/parser.h> |
| @@ -108,6 +109,9 @@ static struct dentry *proc_mount(struct file_system_type *fs_type, | |||
| 108 | } else { | 109 | } else { |
| 109 | ns = task_active_pid_ns(current); | 110 | ns = task_active_pid_ns(current); |
| 110 | options = data; | 111 | options = data; |
| 112 | |||
| 113 | if (!current_user_ns()->may_mount_proc) | ||
| 114 | return ERR_PTR(-EPERM); | ||
| 111 | } | 115 | } |
| 112 | 116 | ||
| 113 | sb = sget(fs_type, proc_test_super, proc_set_super, flags, ns); | 117 | sb = sget(fs_type, proc_test_super, proc_set_super, flags, ns); |
