diff options
Diffstat (limited to 'fs/proc')
-rw-r--r-- | fs/proc/array.c | 4 | ||||
-rw-r--r-- | fs/proc/base.c | 189 | ||||
-rw-r--r-- | fs/proc/generic.c | 8 | ||||
-rw-r--r-- | fs/proc/inode.c | 2 | ||||
-rw-r--r-- | fs/proc/internal.h | 1 | ||||
-rw-r--r-- | fs/proc/root.c | 32 | ||||
-rw-r--r-- | fs/proc/task_mmu.c | 138 | ||||
-rw-r--r-- | fs/proc/task_nommu.c | 6 |
8 files changed, 233 insertions, 147 deletions
diff --git a/fs/proc/array.c b/fs/proc/array.c index 7c99c1cf7e5c..5e4f776b0917 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c | |||
@@ -489,8 +489,8 @@ static int do_task_stat(struct seq_file *m, struct pid_namespace *ns, | |||
489 | vsize, | 489 | vsize, |
490 | mm ? get_mm_rss(mm) : 0, | 490 | mm ? get_mm_rss(mm) : 0, |
491 | rsslim, | 491 | rsslim, |
492 | mm ? mm->start_code : 0, | 492 | mm ? (permitted ? mm->start_code : 1) : 0, |
493 | mm ? mm->end_code : 0, | 493 | mm ? (permitted ? mm->end_code : 1) : 0, |
494 | (permitted && mm) ? mm->start_stack : 0, | 494 | (permitted && mm) ? mm->start_stack : 0, |
495 | esp, | 495 | esp, |
496 | eip, | 496 | eip, |
diff --git a/fs/proc/base.c b/fs/proc/base.c index d49c4b5d2c3e..dfa532730e55 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c | |||
@@ -191,17 +191,20 @@ static int proc_root_link(struct inode *inode, struct path *path) | |||
191 | return result; | 191 | return result; |
192 | } | 192 | } |
193 | 193 | ||
194 | /* | 194 | static struct mm_struct *__check_mem_permission(struct task_struct *task) |
195 | * Return zero if current may access user memory in @task, -error if not. | ||
196 | */ | ||
197 | static int check_mem_permission(struct task_struct *task) | ||
198 | { | 195 | { |
196 | struct mm_struct *mm; | ||
197 | |||
198 | mm = get_task_mm(task); | ||
199 | if (!mm) | ||
200 | return ERR_PTR(-EINVAL); | ||
201 | |||
199 | /* | 202 | /* |
200 | * A task can always look at itself, in case it chooses | 203 | * A task can always look at itself, in case it chooses |
201 | * to use system calls instead of load instructions. | 204 | * to use system calls instead of load instructions. |
202 | */ | 205 | */ |
203 | if (task == current) | 206 | if (task == current) |
204 | return 0; | 207 | return mm; |
205 | 208 | ||
206 | /* | 209 | /* |
207 | * If current is actively ptrace'ing, and would also be | 210 | * If current is actively ptrace'ing, and would also be |
@@ -213,27 +216,53 @@ static int check_mem_permission(struct task_struct *task) | |||
213 | match = (tracehook_tracer_task(task) == current); | 216 | match = (tracehook_tracer_task(task) == current); |
214 | rcu_read_unlock(); | 217 | rcu_read_unlock(); |
215 | if (match && ptrace_may_access(task, PTRACE_MODE_ATTACH)) | 218 | if (match && ptrace_may_access(task, PTRACE_MODE_ATTACH)) |
216 | return 0; | 219 | return mm; |
217 | } | 220 | } |
218 | 221 | ||
219 | /* | 222 | /* |
220 | * Noone else is allowed. | 223 | * No one else is allowed. |
224 | */ | ||
225 | mmput(mm); | ||
226 | return ERR_PTR(-EPERM); | ||
227 | } | ||
228 | |||
229 | /* | ||
230 | * If current may access user memory in @task return a reference to the | ||
231 | * corresponding mm, otherwise ERR_PTR. | ||
232 | */ | ||
233 | static struct mm_struct *check_mem_permission(struct task_struct *task) | ||
234 | { | ||
235 | struct mm_struct *mm; | ||
236 | int err; | ||
237 | |||
238 | /* | ||
239 | * Avoid racing if task exec's as we might get a new mm but validate | ||
240 | * against old credentials. | ||
221 | */ | 241 | */ |
222 | return -EPERM; | 242 | err = mutex_lock_killable(&task->signal->cred_guard_mutex); |
243 | if (err) | ||
244 | return ERR_PTR(err); | ||
245 | |||
246 | mm = __check_mem_permission(task); | ||
247 | mutex_unlock(&task->signal->cred_guard_mutex); | ||
248 | |||
249 | return mm; | ||
223 | } | 250 | } |
224 | 251 | ||
225 | struct mm_struct *mm_for_maps(struct task_struct *task) | 252 | struct mm_struct *mm_for_maps(struct task_struct *task) |
226 | { | 253 | { |
227 | struct mm_struct *mm; | 254 | struct mm_struct *mm; |
255 | int err; | ||
228 | 256 | ||
229 | if (mutex_lock_killable(&task->signal->cred_guard_mutex)) | 257 | err = mutex_lock_killable(&task->signal->cred_guard_mutex); |
230 | return NULL; | 258 | if (err) |
259 | return ERR_PTR(err); | ||
231 | 260 | ||
232 | mm = get_task_mm(task); | 261 | mm = get_task_mm(task); |
233 | if (mm && mm != current->mm && | 262 | if (mm && mm != current->mm && |
234 | !ptrace_may_access(task, PTRACE_MODE_READ)) { | 263 | !ptrace_may_access(task, PTRACE_MODE_READ)) { |
235 | mmput(mm); | 264 | mmput(mm); |
236 | mm = NULL; | 265 | mm = ERR_PTR(-EACCES); |
237 | } | 266 | } |
238 | mutex_unlock(&task->signal->cred_guard_mutex); | 267 | mutex_unlock(&task->signal->cred_guard_mutex); |
239 | 268 | ||
@@ -279,9 +308,9 @@ out: | |||
279 | 308 | ||
280 | static int proc_pid_auxv(struct task_struct *task, char *buffer) | 309 | static int proc_pid_auxv(struct task_struct *task, char *buffer) |
281 | { | 310 | { |
282 | int res = 0; | 311 | struct mm_struct *mm = mm_for_maps(task); |
283 | struct mm_struct *mm = get_task_mm(task); | 312 | int res = PTR_ERR(mm); |
284 | if (mm) { | 313 | if (mm && !IS_ERR(mm)) { |
285 | unsigned int nwords = 0; | 314 | unsigned int nwords = 0; |
286 | do { | 315 | do { |
287 | nwords += 2; | 316 | nwords += 2; |
@@ -318,6 +347,23 @@ static int proc_pid_wchan(struct task_struct *task, char *buffer) | |||
318 | } | 347 | } |
319 | #endif /* CONFIG_KALLSYMS */ | 348 | #endif /* CONFIG_KALLSYMS */ |
320 | 349 | ||
350 | static int lock_trace(struct task_struct *task) | ||
351 | { | ||
352 | int err = mutex_lock_killable(&task->signal->cred_guard_mutex); | ||
353 | if (err) | ||
354 | return err; | ||
355 | if (!ptrace_may_access(task, PTRACE_MODE_ATTACH)) { | ||
356 | mutex_unlock(&task->signal->cred_guard_mutex); | ||
357 | return -EPERM; | ||
358 | } | ||
359 | return 0; | ||
360 | } | ||
361 | |||
362 | static void unlock_trace(struct task_struct *task) | ||
363 | { | ||
364 | mutex_unlock(&task->signal->cred_guard_mutex); | ||
365 | } | ||
366 | |||
321 | #ifdef CONFIG_STACKTRACE | 367 | #ifdef CONFIG_STACKTRACE |
322 | 368 | ||
323 | #define MAX_STACK_TRACE_DEPTH 64 | 369 | #define MAX_STACK_TRACE_DEPTH 64 |
@@ -327,6 +373,7 @@ static int proc_pid_stack(struct seq_file *m, struct pid_namespace *ns, | |||
327 | { | 373 | { |
328 | struct stack_trace trace; | 374 | struct stack_trace trace; |
329 | unsigned long *entries; | 375 | unsigned long *entries; |
376 | int err; | ||
330 | int i; | 377 | int i; |
331 | 378 | ||
332 | entries = kmalloc(MAX_STACK_TRACE_DEPTH * sizeof(*entries), GFP_KERNEL); | 379 | entries = kmalloc(MAX_STACK_TRACE_DEPTH * sizeof(*entries), GFP_KERNEL); |
@@ -337,15 +384,20 @@ static int proc_pid_stack(struct seq_file *m, struct pid_namespace *ns, | |||
337 | trace.max_entries = MAX_STACK_TRACE_DEPTH; | 384 | trace.max_entries = MAX_STACK_TRACE_DEPTH; |
338 | trace.entries = entries; | 385 | trace.entries = entries; |
339 | trace.skip = 0; | 386 | trace.skip = 0; |
340 | save_stack_trace_tsk(task, &trace); | ||
341 | 387 | ||
342 | for (i = 0; i < trace.nr_entries; i++) { | 388 | err = lock_trace(task); |
343 | seq_printf(m, "[<%p>] %pS\n", | 389 | if (!err) { |
344 | (void *)entries[i], (void *)entries[i]); | 390 | save_stack_trace_tsk(task, &trace); |
391 | |||
392 | for (i = 0; i < trace.nr_entries; i++) { | ||
393 | seq_printf(m, "[<%pK>] %pS\n", | ||
394 | (void *)entries[i], (void *)entries[i]); | ||
395 | } | ||
396 | unlock_trace(task); | ||
345 | } | 397 | } |
346 | kfree(entries); | 398 | kfree(entries); |
347 | 399 | ||
348 | return 0; | 400 | return err; |
349 | } | 401 | } |
350 | #endif | 402 | #endif |
351 | 403 | ||
@@ -508,18 +560,22 @@ static int proc_pid_syscall(struct task_struct *task, char *buffer) | |||
508 | { | 560 | { |
509 | long nr; | 561 | long nr; |
510 | unsigned long args[6], sp, pc; | 562 | unsigned long args[6], sp, pc; |
563 | int res = lock_trace(task); | ||
564 | if (res) | ||
565 | return res; | ||
511 | 566 | ||
512 | if (task_current_syscall(task, &nr, args, 6, &sp, &pc)) | 567 | if (task_current_syscall(task, &nr, args, 6, &sp, &pc)) |
513 | return sprintf(buffer, "running\n"); | 568 | res = sprintf(buffer, "running\n"); |
514 | 569 | else if (nr < 0) | |
515 | if (nr < 0) | 570 | res = sprintf(buffer, "%ld 0x%lx 0x%lx\n", nr, sp, pc); |
516 | return sprintf(buffer, "%ld 0x%lx 0x%lx\n", nr, sp, pc); | 571 | else |
517 | 572 | res = sprintf(buffer, | |
518 | return sprintf(buffer, | ||
519 | "%ld 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx\n", | 573 | "%ld 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx\n", |
520 | nr, | 574 | nr, |
521 | args[0], args[1], args[2], args[3], args[4], args[5], | 575 | args[0], args[1], args[2], args[3], args[4], args[5], |
522 | sp, pc); | 576 | sp, pc); |
577 | unlock_trace(task); | ||
578 | return res; | ||
523 | } | 579 | } |
524 | #endif /* CONFIG_HAVE_ARCH_TRACEHOOK */ | 580 | #endif /* CONFIG_HAVE_ARCH_TRACEHOOK */ |
525 | 581 | ||
@@ -775,18 +831,14 @@ static ssize_t mem_read(struct file * file, char __user * buf, | |||
775 | if (!task) | 831 | if (!task) |
776 | goto out_no_task; | 832 | goto out_no_task; |
777 | 833 | ||
778 | if (check_mem_permission(task)) | ||
779 | goto out; | ||
780 | |||
781 | ret = -ENOMEM; | 834 | ret = -ENOMEM; |
782 | page = (char *)__get_free_page(GFP_TEMPORARY); | 835 | page = (char *)__get_free_page(GFP_TEMPORARY); |
783 | if (!page) | 836 | if (!page) |
784 | goto out; | 837 | goto out; |
785 | 838 | ||
786 | ret = 0; | 839 | mm = check_mem_permission(task); |
787 | 840 | ret = PTR_ERR(mm); | |
788 | mm = get_task_mm(task); | 841 | if (IS_ERR(mm)) |
789 | if (!mm) | ||
790 | goto out_free; | 842 | goto out_free; |
791 | 843 | ||
792 | ret = -EIO; | 844 | ret = -EIO; |
@@ -800,8 +852,8 @@ static ssize_t mem_read(struct file * file, char __user * buf, | |||
800 | int this_len, retval; | 852 | int this_len, retval; |
801 | 853 | ||
802 | this_len = (count > PAGE_SIZE) ? PAGE_SIZE : count; | 854 | this_len = (count > PAGE_SIZE) ? PAGE_SIZE : count; |
803 | retval = access_process_vm(task, src, page, this_len, 0); | 855 | retval = access_remote_vm(mm, src, page, this_len, 0); |
804 | if (!retval || check_mem_permission(task)) { | 856 | if (!retval) { |
805 | if (!ret) | 857 | if (!ret) |
806 | ret = -EIO; | 858 | ret = -EIO; |
807 | break; | 859 | break; |
@@ -829,10 +881,6 @@ out_no_task: | |||
829 | return ret; | 881 | return ret; |
830 | } | 882 | } |
831 | 883 | ||
832 | #define mem_write NULL | ||
833 | |||
834 | #ifndef mem_write | ||
835 | /* This is a security hazard */ | ||
836 | static ssize_t mem_write(struct file * file, const char __user *buf, | 884 | static ssize_t mem_write(struct file * file, const char __user *buf, |
837 | size_t count, loff_t *ppos) | 885 | size_t count, loff_t *ppos) |
838 | { | 886 | { |
@@ -840,18 +888,25 @@ static ssize_t mem_write(struct file * file, const char __user *buf, | |||
840 | char *page; | 888 | char *page; |
841 | struct task_struct *task = get_proc_task(file->f_path.dentry->d_inode); | 889 | struct task_struct *task = get_proc_task(file->f_path.dentry->d_inode); |
842 | unsigned long dst = *ppos; | 890 | unsigned long dst = *ppos; |
891 | struct mm_struct *mm; | ||
843 | 892 | ||
844 | copied = -ESRCH; | 893 | copied = -ESRCH; |
845 | if (!task) | 894 | if (!task) |
846 | goto out_no_task; | 895 | goto out_no_task; |
847 | 896 | ||
848 | if (check_mem_permission(task)) | 897 | mm = check_mem_permission(task); |
849 | goto out; | 898 | copied = PTR_ERR(mm); |
899 | if (IS_ERR(mm)) | ||
900 | goto out_task; | ||
901 | |||
902 | copied = -EIO; | ||
903 | if (file->private_data != (void *)((long)current->self_exec_id)) | ||
904 | goto out_mm; | ||
850 | 905 | ||
851 | copied = -ENOMEM; | 906 | copied = -ENOMEM; |
852 | page = (char *)__get_free_page(GFP_TEMPORARY); | 907 | page = (char *)__get_free_page(GFP_TEMPORARY); |
853 | if (!page) | 908 | if (!page) |
854 | goto out; | 909 | goto out_mm; |
855 | 910 | ||
856 | copied = 0; | 911 | copied = 0; |
857 | while (count > 0) { | 912 | while (count > 0) { |
@@ -862,7 +917,7 @@ static ssize_t mem_write(struct file * file, const char __user *buf, | |||
862 | copied = -EFAULT; | 917 | copied = -EFAULT; |
863 | break; | 918 | break; |
864 | } | 919 | } |
865 | retval = access_process_vm(task, dst, page, this_len, 1); | 920 | retval = access_remote_vm(mm, dst, page, this_len, 1); |
866 | if (!retval) { | 921 | if (!retval) { |
867 | if (!copied) | 922 | if (!copied) |
868 | copied = -EIO; | 923 | copied = -EIO; |
@@ -875,12 +930,13 @@ static ssize_t mem_write(struct file * file, const char __user *buf, | |||
875 | } | 930 | } |
876 | *ppos = dst; | 931 | *ppos = dst; |
877 | free_page((unsigned long) page); | 932 | free_page((unsigned long) page); |
878 | out: | 933 | out_mm: |
934 | mmput(mm); | ||
935 | out_task: | ||
879 | put_task_struct(task); | 936 | put_task_struct(task); |
880 | out_no_task: | 937 | out_no_task: |
881 | return copied; | 938 | return copied; |
882 | } | 939 | } |
883 | #endif | ||
884 | 940 | ||
885 | loff_t mem_lseek(struct file *file, loff_t offset, int orig) | 941 | loff_t mem_lseek(struct file *file, loff_t offset, int orig) |
886 | { | 942 | { |
@@ -917,20 +973,18 @@ static ssize_t environ_read(struct file *file, char __user *buf, | |||
917 | if (!task) | 973 | if (!task) |
918 | goto out_no_task; | 974 | goto out_no_task; |
919 | 975 | ||
920 | if (!ptrace_may_access(task, PTRACE_MODE_READ)) | ||
921 | goto out; | ||
922 | |||
923 | ret = -ENOMEM; | 976 | ret = -ENOMEM; |
924 | page = (char *)__get_free_page(GFP_TEMPORARY); | 977 | page = (char *)__get_free_page(GFP_TEMPORARY); |
925 | if (!page) | 978 | if (!page) |
926 | goto out; | 979 | goto out; |
927 | 980 | ||
928 | ret = 0; | ||
929 | 981 | ||
930 | mm = get_task_mm(task); | 982 | mm = mm_for_maps(task); |
931 | if (!mm) | 983 | ret = PTR_ERR(mm); |
984 | if (!mm || IS_ERR(mm)) | ||
932 | goto out_free; | 985 | goto out_free; |
933 | 986 | ||
987 | ret = 0; | ||
934 | while (count > 0) { | 988 | while (count > 0) { |
935 | int this_len, retval, max_len; | 989 | int this_len, retval, max_len; |
936 | 990 | ||
@@ -2748,8 +2802,12 @@ static int proc_tgid_io_accounting(struct task_struct *task, char *buffer) | |||
2748 | static int proc_pid_personality(struct seq_file *m, struct pid_namespace *ns, | 2802 | static int proc_pid_personality(struct seq_file *m, struct pid_namespace *ns, |
2749 | struct pid *pid, struct task_struct *task) | 2803 | struct pid *pid, struct task_struct *task) |
2750 | { | 2804 | { |
2751 | seq_printf(m, "%08x\n", task->personality); | 2805 | int err = lock_trace(task); |
2752 | return 0; | 2806 | if (!err) { |
2807 | seq_printf(m, "%08x\n", task->personality); | ||
2808 | unlock_trace(task); | ||
2809 | } | ||
2810 | return err; | ||
2753 | } | 2811 | } |
2754 | 2812 | ||
2755 | /* | 2813 | /* |
@@ -2768,7 +2826,7 @@ static const struct pid_entry tgid_base_stuff[] = { | |||
2768 | REG("environ", S_IRUSR, proc_environ_operations), | 2826 | REG("environ", S_IRUSR, proc_environ_operations), |
2769 | INF("auxv", S_IRUSR, proc_pid_auxv), | 2827 | INF("auxv", S_IRUSR, proc_pid_auxv), |
2770 | ONE("status", S_IRUGO, proc_pid_status), | 2828 | ONE("status", S_IRUGO, proc_pid_status), |
2771 | ONE("personality", S_IRUSR, proc_pid_personality), | 2829 | ONE("personality", S_IRUGO, proc_pid_personality), |
2772 | INF("limits", S_IRUGO, proc_pid_limits), | 2830 | INF("limits", S_IRUGO, proc_pid_limits), |
2773 | #ifdef CONFIG_SCHED_DEBUG | 2831 | #ifdef CONFIG_SCHED_DEBUG |
2774 | REG("sched", S_IRUGO|S_IWUSR, proc_pid_sched_operations), | 2832 | REG("sched", S_IRUGO|S_IWUSR, proc_pid_sched_operations), |
@@ -2778,7 +2836,7 @@ static const struct pid_entry tgid_base_stuff[] = { | |||
2778 | #endif | 2836 | #endif |
2779 | REG("comm", S_IRUGO|S_IWUSR, proc_pid_set_comm_operations), | 2837 | REG("comm", S_IRUGO|S_IWUSR, proc_pid_set_comm_operations), |
2780 | #ifdef CONFIG_HAVE_ARCH_TRACEHOOK | 2838 | #ifdef CONFIG_HAVE_ARCH_TRACEHOOK |
2781 | INF("syscall", S_IRUSR, proc_pid_syscall), | 2839 | INF("syscall", S_IRUGO, proc_pid_syscall), |
2782 | #endif | 2840 | #endif |
2783 | INF("cmdline", S_IRUGO, proc_pid_cmdline), | 2841 | INF("cmdline", S_IRUGO, proc_pid_cmdline), |
2784 | ONE("stat", S_IRUGO, proc_tgid_stat), | 2842 | ONE("stat", S_IRUGO, proc_tgid_stat), |
@@ -2797,7 +2855,7 @@ static const struct pid_entry tgid_base_stuff[] = { | |||
2797 | #ifdef CONFIG_PROC_PAGE_MONITOR | 2855 | #ifdef CONFIG_PROC_PAGE_MONITOR |
2798 | REG("clear_refs", S_IWUSR, proc_clear_refs_operations), | 2856 | REG("clear_refs", S_IWUSR, proc_clear_refs_operations), |
2799 | REG("smaps", S_IRUGO, proc_smaps_operations), | 2857 | REG("smaps", S_IRUGO, proc_smaps_operations), |
2800 | REG("pagemap", S_IRUSR, proc_pagemap_operations), | 2858 | REG("pagemap", S_IRUGO, proc_pagemap_operations), |
2801 | #endif | 2859 | #endif |
2802 | #ifdef CONFIG_SECURITY | 2860 | #ifdef CONFIG_SECURITY |
2803 | DIR("attr", S_IRUGO|S_IXUGO, proc_attr_dir_inode_operations, proc_attr_dir_operations), | 2861 | DIR("attr", S_IRUGO|S_IXUGO, proc_attr_dir_inode_operations, proc_attr_dir_operations), |
@@ -2806,7 +2864,7 @@ static const struct pid_entry tgid_base_stuff[] = { | |||
2806 | INF("wchan", S_IRUGO, proc_pid_wchan), | 2864 | INF("wchan", S_IRUGO, proc_pid_wchan), |
2807 | #endif | 2865 | #endif |
2808 | #ifdef CONFIG_STACKTRACE | 2866 | #ifdef CONFIG_STACKTRACE |
2809 | ONE("stack", S_IRUSR, proc_pid_stack), | 2867 | ONE("stack", S_IRUGO, proc_pid_stack), |
2810 | #endif | 2868 | #endif |
2811 | #ifdef CONFIG_SCHEDSTATS | 2869 | #ifdef CONFIG_SCHEDSTATS |
2812 | INF("schedstat", S_IRUGO, proc_pid_schedstat), | 2870 | INF("schedstat", S_IRUGO, proc_pid_schedstat), |
@@ -3066,11 +3124,16 @@ static int proc_pid_fill_cache(struct file *filp, void *dirent, filldir_t filldi | |||
3066 | /* for the /proc/ directory itself, after non-process stuff has been done */ | 3124 | /* for the /proc/ directory itself, after non-process stuff has been done */ |
3067 | int proc_pid_readdir(struct file * filp, void * dirent, filldir_t filldir) | 3125 | int proc_pid_readdir(struct file * filp, void * dirent, filldir_t filldir) |
3068 | { | 3126 | { |
3069 | unsigned int nr = filp->f_pos - FIRST_PROCESS_ENTRY; | 3127 | unsigned int nr; |
3070 | struct task_struct *reaper = get_proc_task(filp->f_path.dentry->d_inode); | 3128 | struct task_struct *reaper; |
3071 | struct tgid_iter iter; | 3129 | struct tgid_iter iter; |
3072 | struct pid_namespace *ns; | 3130 | struct pid_namespace *ns; |
3073 | 3131 | ||
3132 | if (filp->f_pos >= PID_MAX_LIMIT + TGID_OFFSET) | ||
3133 | goto out_no_task; | ||
3134 | nr = filp->f_pos - FIRST_PROCESS_ENTRY; | ||
3135 | |||
3136 | reaper = get_proc_task(filp->f_path.dentry->d_inode); | ||
3074 | if (!reaper) | 3137 | if (!reaper) |
3075 | goto out_no_task; | 3138 | goto out_no_task; |
3076 | 3139 | ||
@@ -3108,14 +3171,14 @@ static const struct pid_entry tid_base_stuff[] = { | |||
3108 | REG("environ", S_IRUSR, proc_environ_operations), | 3171 | REG("environ", S_IRUSR, proc_environ_operations), |
3109 | INF("auxv", S_IRUSR, proc_pid_auxv), | 3172 | INF("auxv", S_IRUSR, proc_pid_auxv), |
3110 | ONE("status", S_IRUGO, proc_pid_status), | 3173 | ONE("status", S_IRUGO, proc_pid_status), |
3111 | ONE("personality", S_IRUSR, proc_pid_personality), | 3174 | ONE("personality", S_IRUGO, proc_pid_personality), |
3112 | INF("limits", S_IRUGO, proc_pid_limits), | 3175 | INF("limits", S_IRUGO, proc_pid_limits), |
3113 | #ifdef CONFIG_SCHED_DEBUG | 3176 | #ifdef CONFIG_SCHED_DEBUG |
3114 | REG("sched", S_IRUGO|S_IWUSR, proc_pid_sched_operations), | 3177 | REG("sched", S_IRUGO|S_IWUSR, proc_pid_sched_operations), |
3115 | #endif | 3178 | #endif |
3116 | REG("comm", S_IRUGO|S_IWUSR, proc_pid_set_comm_operations), | 3179 | REG("comm", S_IRUGO|S_IWUSR, proc_pid_set_comm_operations), |
3117 | #ifdef CONFIG_HAVE_ARCH_TRACEHOOK | 3180 | #ifdef CONFIG_HAVE_ARCH_TRACEHOOK |
3118 | INF("syscall", S_IRUSR, proc_pid_syscall), | 3181 | INF("syscall", S_IRUGO, proc_pid_syscall), |
3119 | #endif | 3182 | #endif |
3120 | INF("cmdline", S_IRUGO, proc_pid_cmdline), | 3183 | INF("cmdline", S_IRUGO, proc_pid_cmdline), |
3121 | ONE("stat", S_IRUGO, proc_tid_stat), | 3184 | ONE("stat", S_IRUGO, proc_tid_stat), |
@@ -3133,7 +3196,7 @@ static const struct pid_entry tid_base_stuff[] = { | |||
3133 | #ifdef CONFIG_PROC_PAGE_MONITOR | 3196 | #ifdef CONFIG_PROC_PAGE_MONITOR |
3134 | REG("clear_refs", S_IWUSR, proc_clear_refs_operations), | 3197 | REG("clear_refs", S_IWUSR, proc_clear_refs_operations), |
3135 | REG("smaps", S_IRUGO, proc_smaps_operations), | 3198 | REG("smaps", S_IRUGO, proc_smaps_operations), |
3136 | REG("pagemap", S_IRUSR, proc_pagemap_operations), | 3199 | REG("pagemap", S_IRUGO, proc_pagemap_operations), |
3137 | #endif | 3200 | #endif |
3138 | #ifdef CONFIG_SECURITY | 3201 | #ifdef CONFIG_SECURITY |
3139 | DIR("attr", S_IRUGO|S_IXUGO, proc_attr_dir_inode_operations, proc_attr_dir_operations), | 3202 | DIR("attr", S_IRUGO|S_IXUGO, proc_attr_dir_inode_operations, proc_attr_dir_operations), |
@@ -3142,7 +3205,7 @@ static const struct pid_entry tid_base_stuff[] = { | |||
3142 | INF("wchan", S_IRUGO, proc_pid_wchan), | 3205 | INF("wchan", S_IRUGO, proc_pid_wchan), |
3143 | #endif | 3206 | #endif |
3144 | #ifdef CONFIG_STACKTRACE | 3207 | #ifdef CONFIG_STACKTRACE |
3145 | ONE("stack", S_IRUSR, proc_pid_stack), | 3208 | ONE("stack", S_IRUGO, proc_pid_stack), |
3146 | #endif | 3209 | #endif |
3147 | #ifdef CONFIG_SCHEDSTATS | 3210 | #ifdef CONFIG_SCHEDSTATS |
3148 | INF("schedstat", S_IRUGO, proc_pid_schedstat), | 3211 | INF("schedstat", S_IRUGO, proc_pid_schedstat), |
@@ -3161,7 +3224,7 @@ static const struct pid_entry tid_base_stuff[] = { | |||
3161 | REG("oom_score_adj", S_IRUGO|S_IWUSR, proc_oom_score_adj_operations), | 3224 | REG("oom_score_adj", S_IRUGO|S_IWUSR, proc_oom_score_adj_operations), |
3162 | #ifdef CONFIG_AUDITSYSCALL | 3225 | #ifdef CONFIG_AUDITSYSCALL |
3163 | REG("loginuid", S_IWUSR|S_IRUGO, proc_loginuid_operations), | 3226 | REG("loginuid", S_IWUSR|S_IRUGO, proc_loginuid_operations), |
3164 | REG("sessionid", S_IRUSR, proc_sessionid_operations), | 3227 | REG("sessionid", S_IRUGO, proc_sessionid_operations), |
3165 | #endif | 3228 | #endif |
3166 | #ifdef CONFIG_FAULT_INJECTION | 3229 | #ifdef CONFIG_FAULT_INJECTION |
3167 | REG("make-it-fail", S_IRUGO|S_IWUSR, proc_fault_inject_operations), | 3230 | REG("make-it-fail", S_IRUGO|S_IWUSR, proc_fault_inject_operations), |
diff --git a/fs/proc/generic.c b/fs/proc/generic.c index 01e07f2a188f..f1281339b6fa 100644 --- a/fs/proc/generic.c +++ b/fs/proc/generic.c | |||
@@ -28,7 +28,7 @@ | |||
28 | 28 | ||
29 | DEFINE_SPINLOCK(proc_subdir_lock); | 29 | DEFINE_SPINLOCK(proc_subdir_lock); |
30 | 30 | ||
31 | static int proc_match(int len, const char *name, struct proc_dir_entry *de) | 31 | static int proc_match(unsigned int len, const char *name, struct proc_dir_entry *de) |
32 | { | 32 | { |
33 | if (de->namelen != len) | 33 | if (de->namelen != len) |
34 | return 0; | 34 | return 0; |
@@ -303,7 +303,7 @@ static int __xlate_proc_name(const char *name, struct proc_dir_entry **ret, | |||
303 | { | 303 | { |
304 | const char *cp = name, *next; | 304 | const char *cp = name, *next; |
305 | struct proc_dir_entry *de; | 305 | struct proc_dir_entry *de; |
306 | int len; | 306 | unsigned int len; |
307 | 307 | ||
308 | de = *ret; | 308 | de = *ret; |
309 | if (!de) | 309 | if (!de) |
@@ -602,7 +602,7 @@ static struct proc_dir_entry *__proc_create(struct proc_dir_entry **parent, | |||
602 | { | 602 | { |
603 | struct proc_dir_entry *ent = NULL; | 603 | struct proc_dir_entry *ent = NULL; |
604 | const char *fn = name; | 604 | const char *fn = name; |
605 | int len; | 605 | unsigned int len; |
606 | 606 | ||
607 | /* make sure name is valid */ | 607 | /* make sure name is valid */ |
608 | if (!name || !strlen(name)) goto out; | 608 | if (!name || !strlen(name)) goto out; |
@@ -786,7 +786,7 @@ void remove_proc_entry(const char *name, struct proc_dir_entry *parent) | |||
786 | struct proc_dir_entry **p; | 786 | struct proc_dir_entry **p; |
787 | struct proc_dir_entry *de = NULL; | 787 | struct proc_dir_entry *de = NULL; |
788 | const char *fn = name; | 788 | const char *fn = name; |
789 | int len; | 789 | unsigned int len; |
790 | 790 | ||
791 | spin_lock(&proc_subdir_lock); | 791 | spin_lock(&proc_subdir_lock); |
792 | if (__xlate_proc_name(name, &parent, &fn) != 0) { | 792 | if (__xlate_proc_name(name, &parent, &fn) != 0) { |
diff --git a/fs/proc/inode.c b/fs/proc/inode.c index d6a7ca1fdac5..d15aa1b1cc8f 100644 --- a/fs/proc/inode.c +++ b/fs/proc/inode.c | |||
@@ -46,8 +46,6 @@ static void proc_evict_inode(struct inode *inode) | |||
46 | } | 46 | } |
47 | } | 47 | } |
48 | 48 | ||
49 | struct vfsmount *proc_mnt; | ||
50 | |||
51 | static struct kmem_cache * proc_inode_cachep; | 49 | static struct kmem_cache * proc_inode_cachep; |
52 | 50 | ||
53 | static struct inode *proc_alloc_inode(struct super_block *sb) | 51 | static struct inode *proc_alloc_inode(struct super_block *sb) |
diff --git a/fs/proc/internal.h b/fs/proc/internal.h index 9ad561ded409..c03e8d3a3a5b 100644 --- a/fs/proc/internal.h +++ b/fs/proc/internal.h | |||
@@ -107,7 +107,6 @@ static inline struct proc_dir_entry *pde_get(struct proc_dir_entry *pde) | |||
107 | } | 107 | } |
108 | void pde_put(struct proc_dir_entry *pde); | 108 | void pde_put(struct proc_dir_entry *pde); |
109 | 109 | ||
110 | extern struct vfsmount *proc_mnt; | ||
111 | int proc_fill_super(struct super_block *); | 110 | int proc_fill_super(struct super_block *); |
112 | struct inode *proc_get_inode(struct super_block *, struct proc_dir_entry *); | 111 | struct inode *proc_get_inode(struct super_block *, struct proc_dir_entry *); |
113 | 112 | ||
diff --git a/fs/proc/root.c b/fs/proc/root.c index ef9fa8e24ad6..a9000e9cfee5 100644 --- a/fs/proc/root.c +++ b/fs/proc/root.c | |||
@@ -43,17 +43,6 @@ static struct dentry *proc_mount(struct file_system_type *fs_type, | |||
43 | struct pid_namespace *ns; | 43 | struct pid_namespace *ns; |
44 | struct proc_inode *ei; | 44 | struct proc_inode *ei; |
45 | 45 | ||
46 | if (proc_mnt) { | ||
47 | /* Seed the root directory with a pid so it doesn't need | ||
48 | * to be special in base.c. I would do this earlier but | ||
49 | * the only task alive when /proc is mounted the first time | ||
50 | * is the init_task and it doesn't have any pids. | ||
51 | */ | ||
52 | ei = PROC_I(proc_mnt->mnt_sb->s_root->d_inode); | ||
53 | if (!ei->pid) | ||
54 | ei->pid = find_get_pid(1); | ||
55 | } | ||
56 | |||
57 | if (flags & MS_KERNMOUNT) | 46 | if (flags & MS_KERNMOUNT) |
58 | ns = (struct pid_namespace *)data; | 47 | ns = (struct pid_namespace *)data; |
59 | else | 48 | else |
@@ -71,16 +60,16 @@ static struct dentry *proc_mount(struct file_system_type *fs_type, | |||
71 | return ERR_PTR(err); | 60 | return ERR_PTR(err); |
72 | } | 61 | } |
73 | 62 | ||
74 | ei = PROC_I(sb->s_root->d_inode); | ||
75 | if (!ei->pid) { | ||
76 | rcu_read_lock(); | ||
77 | ei->pid = get_pid(find_pid_ns(1, ns)); | ||
78 | rcu_read_unlock(); | ||
79 | } | ||
80 | |||
81 | sb->s_flags |= MS_ACTIVE; | 63 | sb->s_flags |= MS_ACTIVE; |
82 | } | 64 | } |
83 | 65 | ||
66 | ei = PROC_I(sb->s_root->d_inode); | ||
67 | if (!ei->pid) { | ||
68 | rcu_read_lock(); | ||
69 | ei->pid = get_pid(find_pid_ns(1, ns)); | ||
70 | rcu_read_unlock(); | ||
71 | } | ||
72 | |||
84 | return dget(sb->s_root); | 73 | return dget(sb->s_root); |
85 | } | 74 | } |
86 | 75 | ||
@@ -101,19 +90,20 @@ static struct file_system_type proc_fs_type = { | |||
101 | 90 | ||
102 | void __init proc_root_init(void) | 91 | void __init proc_root_init(void) |
103 | { | 92 | { |
93 | struct vfsmount *mnt; | ||
104 | int err; | 94 | int err; |
105 | 95 | ||
106 | proc_init_inodecache(); | 96 | proc_init_inodecache(); |
107 | err = register_filesystem(&proc_fs_type); | 97 | err = register_filesystem(&proc_fs_type); |
108 | if (err) | 98 | if (err) |
109 | return; | 99 | return; |
110 | proc_mnt = kern_mount_data(&proc_fs_type, &init_pid_ns); | 100 | mnt = kern_mount_data(&proc_fs_type, &init_pid_ns); |
111 | if (IS_ERR(proc_mnt)) { | 101 | if (IS_ERR(mnt)) { |
112 | unregister_filesystem(&proc_fs_type); | 102 | unregister_filesystem(&proc_fs_type); |
113 | return; | 103 | return; |
114 | } | 104 | } |
115 | 105 | ||
116 | init_pid_ns.proc_mnt = proc_mnt; | 106 | init_pid_ns.proc_mnt = mnt; |
117 | proc_symlink("mounts", NULL, "self/mounts"); | 107 | proc_symlink("mounts", NULL, "self/mounts"); |
118 | 108 | ||
119 | proc_net_init(); | 109 | proc_net_init(); |
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c index 60b914860f81..2e7addfd9803 100644 --- a/fs/proc/task_mmu.c +++ b/fs/proc/task_mmu.c | |||
@@ -1,5 +1,6 @@ | |||
1 | #include <linux/mm.h> | 1 | #include <linux/mm.h> |
2 | #include <linux/hugetlb.h> | 2 | #include <linux/hugetlb.h> |
3 | #include <linux/huge_mm.h> | ||
3 | #include <linux/mount.h> | 4 | #include <linux/mount.h> |
4 | #include <linux/seq_file.h> | 5 | #include <linux/seq_file.h> |
5 | #include <linux/highmem.h> | 6 | #include <linux/highmem.h> |
@@ -7,6 +8,7 @@ | |||
7 | #include <linux/slab.h> | 8 | #include <linux/slab.h> |
8 | #include <linux/pagemap.h> | 9 | #include <linux/pagemap.h> |
9 | #include <linux/mempolicy.h> | 10 | #include <linux/mempolicy.h> |
11 | #include <linux/rmap.h> | ||
10 | #include <linux/swap.h> | 12 | #include <linux/swap.h> |
11 | #include <linux/swapops.h> | 13 | #include <linux/swapops.h> |
12 | 14 | ||
@@ -119,14 +121,14 @@ static void *m_start(struct seq_file *m, loff_t *pos) | |||
119 | 121 | ||
120 | priv->task = get_pid_task(priv->pid, PIDTYPE_PID); | 122 | priv->task = get_pid_task(priv->pid, PIDTYPE_PID); |
121 | if (!priv->task) | 123 | if (!priv->task) |
122 | return NULL; | 124 | return ERR_PTR(-ESRCH); |
123 | 125 | ||
124 | mm = mm_for_maps(priv->task); | 126 | mm = mm_for_maps(priv->task); |
125 | if (!mm) | 127 | if (!mm || IS_ERR(mm)) |
126 | return NULL; | 128 | return mm; |
127 | down_read(&mm->mmap_sem); | 129 | down_read(&mm->mmap_sem); |
128 | 130 | ||
129 | tail_vma = get_gate_vma(priv->task); | 131 | tail_vma = get_gate_vma(priv->task->mm); |
130 | priv->tail_vma = tail_vma; | 132 | priv->tail_vma = tail_vma; |
131 | 133 | ||
132 | /* Start with last addr hint */ | 134 | /* Start with last addr hint */ |
@@ -180,7 +182,8 @@ static void m_stop(struct seq_file *m, void *v) | |||
180 | struct proc_maps_private *priv = m->private; | 182 | struct proc_maps_private *priv = m->private; |
181 | struct vm_area_struct *vma = v; | 183 | struct vm_area_struct *vma = v; |
182 | 184 | ||
183 | vma_stop(priv, vma); | 185 | if (!IS_ERR(vma)) |
186 | vma_stop(priv, vma); | ||
184 | if (priv->task) | 187 | if (priv->task) |
185 | put_task_struct(priv->task); | 188 | put_task_struct(priv->task); |
186 | } | 189 | } |
@@ -249,8 +252,8 @@ static void show_map_vma(struct seq_file *m, struct vm_area_struct *vma) | |||
249 | const char *name = arch_vma_name(vma); | 252 | const char *name = arch_vma_name(vma); |
250 | if (!name) { | 253 | if (!name) { |
251 | if (mm) { | 254 | if (mm) { |
252 | if (vma->vm_start <= mm->start_brk && | 255 | if (vma->vm_start <= mm->brk && |
253 | vma->vm_end >= mm->brk) { | 256 | vma->vm_end >= mm->start_brk) { |
254 | name = "[heap]"; | 257 | name = "[heap]"; |
255 | } else if (vma->vm_start <= mm->start_stack && | 258 | } else if (vma->vm_start <= mm->start_stack && |
256 | vma->vm_end >= mm->start_stack) { | 259 | vma->vm_end >= mm->start_stack) { |
@@ -277,7 +280,8 @@ static int show_map(struct seq_file *m, void *v) | |||
277 | show_map_vma(m, vma); | 280 | show_map_vma(m, vma); |
278 | 281 | ||
279 | if (m->count < m->size) /* vma is copied successfully */ | 282 | if (m->count < m->size) /* vma is copied successfully */ |
280 | m->version = (vma != get_gate_vma(task))? vma->vm_start: 0; | 283 | m->version = (vma != get_gate_vma(task->mm)) |
284 | ? vma->vm_start : 0; | ||
281 | return 0; | 285 | return 0; |
282 | } | 286 | } |
283 | 287 | ||
@@ -329,58 +333,86 @@ struct mem_size_stats { | |||
329 | unsigned long private_dirty; | 333 | unsigned long private_dirty; |
330 | unsigned long referenced; | 334 | unsigned long referenced; |
331 | unsigned long anonymous; | 335 | unsigned long anonymous; |
336 | unsigned long anonymous_thp; | ||
332 | unsigned long swap; | 337 | unsigned long swap; |
333 | u64 pss; | 338 | u64 pss; |
334 | }; | 339 | }; |
335 | 340 | ||
336 | static int smaps_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end, | 341 | |
337 | struct mm_walk *walk) | 342 | static void smaps_pte_entry(pte_t ptent, unsigned long addr, |
343 | unsigned long ptent_size, struct mm_walk *walk) | ||
338 | { | 344 | { |
339 | struct mem_size_stats *mss = walk->private; | 345 | struct mem_size_stats *mss = walk->private; |
340 | struct vm_area_struct *vma = mss->vma; | 346 | struct vm_area_struct *vma = mss->vma; |
341 | pte_t *pte, ptent; | ||
342 | spinlock_t *ptl; | ||
343 | struct page *page; | 347 | struct page *page; |
344 | int mapcount; | 348 | int mapcount; |
345 | 349 | ||
346 | pte = pte_offset_map_lock(vma->vm_mm, pmd, addr, &ptl); | 350 | if (is_swap_pte(ptent)) { |
347 | for (; addr != end; pte++, addr += PAGE_SIZE) { | 351 | mss->swap += ptent_size; |
348 | ptent = *pte; | 352 | return; |
349 | 353 | } | |
350 | if (is_swap_pte(ptent)) { | ||
351 | mss->swap += PAGE_SIZE; | ||
352 | continue; | ||
353 | } | ||
354 | 354 | ||
355 | if (!pte_present(ptent)) | 355 | if (!pte_present(ptent)) |
356 | continue; | 356 | return; |
357 | |||
358 | page = vm_normal_page(vma, addr, ptent); | ||
359 | if (!page) | ||
360 | return; | ||
361 | |||
362 | if (PageAnon(page)) | ||
363 | mss->anonymous += ptent_size; | ||
364 | |||
365 | mss->resident += ptent_size; | ||
366 | /* Accumulate the size in pages that have been accessed. */ | ||
367 | if (pte_young(ptent) || PageReferenced(page)) | ||
368 | mss->referenced += ptent_size; | ||
369 | mapcount = page_mapcount(page); | ||
370 | if (mapcount >= 2) { | ||
371 | if (pte_dirty(ptent) || PageDirty(page)) | ||
372 | mss->shared_dirty += ptent_size; | ||
373 | else | ||
374 | mss->shared_clean += ptent_size; | ||
375 | mss->pss += (ptent_size << PSS_SHIFT) / mapcount; | ||
376 | } else { | ||
377 | if (pte_dirty(ptent) || PageDirty(page)) | ||
378 | mss->private_dirty += ptent_size; | ||
379 | else | ||
380 | mss->private_clean += ptent_size; | ||
381 | mss->pss += (ptent_size << PSS_SHIFT); | ||
382 | } | ||
383 | } | ||
357 | 384 | ||
358 | page = vm_normal_page(vma, addr, ptent); | 385 | static int smaps_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end, |
359 | if (!page) | 386 | struct mm_walk *walk) |
360 | continue; | 387 | { |
388 | struct mem_size_stats *mss = walk->private; | ||
389 | struct vm_area_struct *vma = mss->vma; | ||
390 | pte_t *pte; | ||
391 | spinlock_t *ptl; | ||
361 | 392 | ||
362 | if (PageAnon(page)) | 393 | spin_lock(&walk->mm->page_table_lock); |
363 | mss->anonymous += PAGE_SIZE; | 394 | if (pmd_trans_huge(*pmd)) { |
364 | 395 | if (pmd_trans_splitting(*pmd)) { | |
365 | mss->resident += PAGE_SIZE; | 396 | spin_unlock(&walk->mm->page_table_lock); |
366 | /* Accumulate the size in pages that have been accessed. */ | 397 | wait_split_huge_page(vma->anon_vma, pmd); |
367 | if (pte_young(ptent) || PageReferenced(page)) | ||
368 | mss->referenced += PAGE_SIZE; | ||
369 | mapcount = page_mapcount(page); | ||
370 | if (mapcount >= 2) { | ||
371 | if (pte_dirty(ptent) || PageDirty(page)) | ||
372 | mss->shared_dirty += PAGE_SIZE; | ||
373 | else | ||
374 | mss->shared_clean += PAGE_SIZE; | ||
375 | mss->pss += (PAGE_SIZE << PSS_SHIFT) / mapcount; | ||
376 | } else { | 398 | } else { |
377 | if (pte_dirty(ptent) || PageDirty(page)) | 399 | smaps_pte_entry(*(pte_t *)pmd, addr, |
378 | mss->private_dirty += PAGE_SIZE; | 400 | HPAGE_PMD_SIZE, walk); |
379 | else | 401 | spin_unlock(&walk->mm->page_table_lock); |
380 | mss->private_clean += PAGE_SIZE; | 402 | mss->anonymous_thp += HPAGE_PMD_SIZE; |
381 | mss->pss += (PAGE_SIZE << PSS_SHIFT); | 403 | return 0; |
382 | } | 404 | } |
405 | } else { | ||
406 | spin_unlock(&walk->mm->page_table_lock); | ||
383 | } | 407 | } |
408 | /* | ||
409 | * The mmap_sem held all the way back in m_start() is what | ||
410 | * keeps khugepaged out of here and from collapsing things | ||
411 | * in here. | ||
412 | */ | ||
413 | pte = pte_offset_map_lock(vma->vm_mm, pmd, addr, &ptl); | ||
414 | for (; addr != end; pte++, addr += PAGE_SIZE) | ||
415 | smaps_pte_entry(*pte, addr, PAGE_SIZE, walk); | ||
384 | pte_unmap_unlock(pte - 1, ptl); | 416 | pte_unmap_unlock(pte - 1, ptl); |
385 | cond_resched(); | 417 | cond_resched(); |
386 | return 0; | 418 | return 0; |
@@ -416,6 +448,7 @@ static int show_smap(struct seq_file *m, void *v) | |||
416 | "Private_Dirty: %8lu kB\n" | 448 | "Private_Dirty: %8lu kB\n" |
417 | "Referenced: %8lu kB\n" | 449 | "Referenced: %8lu kB\n" |
418 | "Anonymous: %8lu kB\n" | 450 | "Anonymous: %8lu kB\n" |
451 | "AnonHugePages: %8lu kB\n" | ||
419 | "Swap: %8lu kB\n" | 452 | "Swap: %8lu kB\n" |
420 | "KernelPageSize: %8lu kB\n" | 453 | "KernelPageSize: %8lu kB\n" |
421 | "MMUPageSize: %8lu kB\n" | 454 | "MMUPageSize: %8lu kB\n" |
@@ -429,6 +462,7 @@ static int show_smap(struct seq_file *m, void *v) | |||
429 | mss.private_dirty >> 10, | 462 | mss.private_dirty >> 10, |
430 | mss.referenced >> 10, | 463 | mss.referenced >> 10, |
431 | mss.anonymous >> 10, | 464 | mss.anonymous >> 10, |
465 | mss.anonymous_thp >> 10, | ||
432 | mss.swap >> 10, | 466 | mss.swap >> 10, |
433 | vma_kernel_pagesize(vma) >> 10, | 467 | vma_kernel_pagesize(vma) >> 10, |
434 | vma_mmu_pagesize(vma) >> 10, | 468 | vma_mmu_pagesize(vma) >> 10, |
@@ -436,7 +470,8 @@ static int show_smap(struct seq_file *m, void *v) | |||
436 | (unsigned long)(mss.pss >> (10 + PSS_SHIFT)) : 0); | 470 | (unsigned long)(mss.pss >> (10 + PSS_SHIFT)) : 0); |
437 | 471 | ||
438 | if (m->count < m->size) /* vma is copied successfully */ | 472 | if (m->count < m->size) /* vma is copied successfully */ |
439 | m->version = (vma != get_gate_vma(task)) ? vma->vm_start : 0; | 473 | m->version = (vma != get_gate_vma(task->mm)) |
474 | ? vma->vm_start : 0; | ||
440 | return 0; | 475 | return 0; |
441 | } | 476 | } |
442 | 477 | ||
@@ -467,6 +502,8 @@ static int clear_refs_pte_range(pmd_t *pmd, unsigned long addr, | |||
467 | spinlock_t *ptl; | 502 | spinlock_t *ptl; |
468 | struct page *page; | 503 | struct page *page; |
469 | 504 | ||
505 | split_huge_page_pmd(walk->mm, pmd); | ||
506 | |||
470 | pte = pte_offset_map_lock(vma->vm_mm, pmd, addr, &ptl); | 507 | pte = pte_offset_map_lock(vma->vm_mm, pmd, addr, &ptl); |
471 | for (; addr != end; pte++, addr += PAGE_SIZE) { | 508 | for (; addr != end; pte++, addr += PAGE_SIZE) { |
472 | ptent = *pte; | 509 | ptent = *pte; |
@@ -623,6 +660,8 @@ static int pagemap_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end, | |||
623 | pte_t *pte; | 660 | pte_t *pte; |
624 | int err = 0; | 661 | int err = 0; |
625 | 662 | ||
663 | split_huge_page_pmd(walk->mm, pmd); | ||
664 | |||
626 | /* find the first VMA at or above 'addr' */ | 665 | /* find the first VMA at or above 'addr' */ |
627 | vma = find_vma(walk->mm, addr); | 666 | vma = find_vma(walk->mm, addr); |
628 | for (; addr != end; addr += PAGE_SIZE) { | 667 | for (; addr != end; addr += PAGE_SIZE) { |
@@ -728,8 +767,9 @@ static ssize_t pagemap_read(struct file *file, char __user *buf, | |||
728 | if (!task) | 767 | if (!task) |
729 | goto out; | 768 | goto out; |
730 | 769 | ||
731 | ret = -EACCES; | 770 | mm = mm_for_maps(task); |
732 | if (!ptrace_may_access(task, PTRACE_MODE_READ)) | 771 | ret = PTR_ERR(mm); |
772 | if (!mm || IS_ERR(mm)) | ||
733 | goto out_task; | 773 | goto out_task; |
734 | 774 | ||
735 | ret = -EINVAL; | 775 | ret = -EINVAL; |
@@ -742,10 +782,6 @@ static ssize_t pagemap_read(struct file *file, char __user *buf, | |||
742 | if (!count) | 782 | if (!count) |
743 | goto out_task; | 783 | goto out_task; |
744 | 784 | ||
745 | mm = get_task_mm(task); | ||
746 | if (!mm) | ||
747 | goto out_task; | ||
748 | |||
749 | pm.len = PM_ENTRY_BYTES * (PAGEMAP_WALK_SIZE >> PAGE_SHIFT); | 785 | pm.len = PM_ENTRY_BYTES * (PAGEMAP_WALK_SIZE >> PAGE_SHIFT); |
750 | pm.buffer = kmalloc(pm.len, GFP_TEMPORARY); | 786 | pm.buffer = kmalloc(pm.len, GFP_TEMPORARY); |
751 | ret = -ENOMEM; | 787 | ret = -ENOMEM; |
diff --git a/fs/proc/task_nommu.c b/fs/proc/task_nommu.c index b535d3e5d5f1..980de547c070 100644 --- a/fs/proc/task_nommu.c +++ b/fs/proc/task_nommu.c | |||
@@ -199,13 +199,13 @@ static void *m_start(struct seq_file *m, loff_t *pos) | |||
199 | /* pin the task and mm whilst we play with them */ | 199 | /* pin the task and mm whilst we play with them */ |
200 | priv->task = get_pid_task(priv->pid, PIDTYPE_PID); | 200 | priv->task = get_pid_task(priv->pid, PIDTYPE_PID); |
201 | if (!priv->task) | 201 | if (!priv->task) |
202 | return NULL; | 202 | return ERR_PTR(-ESRCH); |
203 | 203 | ||
204 | mm = mm_for_maps(priv->task); | 204 | mm = mm_for_maps(priv->task); |
205 | if (!mm) { | 205 | if (!mm || IS_ERR(mm)) { |
206 | put_task_struct(priv->task); | 206 | put_task_struct(priv->task); |
207 | priv->task = NULL; | 207 | priv->task = NULL; |
208 | return NULL; | 208 | return mm; |
209 | } | 209 | } |
210 | down_read(&mm->mmap_sem); | 210 | down_read(&mm->mmap_sem); |
211 | 211 | ||