diff options
author | Andrea Bastoni <bastoni@cs.unc.edu> | 2010-05-30 19:16:45 -0400 |
---|---|---|
committer | Andrea Bastoni <bastoni@cs.unc.edu> | 2010-05-30 19:16:45 -0400 |
commit | ada47b5fe13d89735805b566185f4885f5a3f750 (patch) | |
tree | 644b88f8a71896307d71438e9b3af49126ffb22b /fs/proc | |
parent | 43e98717ad40a4ae64545b5ba047c7b86aa44f4f (diff) | |
parent | 3280f21d43ee541f97f8cda5792150d2dbec20d5 (diff) |
Merge branch 'wip-2.6.34' into old-private-masterarchived-private-master
Diffstat (limited to 'fs/proc')
-rw-r--r-- | fs/proc/array.c | 135 | ||||
-rw-r--r-- | fs/proc/base.c | 121 | ||||
-rw-r--r-- | fs/proc/generic.c | 60 | ||||
-rw-r--r-- | fs/proc/inode.c | 32 | ||||
-rw-r--r-- | fs/proc/internal.h | 10 | ||||
-rw-r--r-- | fs/proc/kcore.c | 3 | ||||
-rw-r--r-- | fs/proc/kmsg.c | 14 | ||||
-rw-r--r-- | fs/proc/nommu.c | 1 | ||||
-rw-r--r-- | fs/proc/page.c | 45 | ||||
-rw-r--r-- | fs/proc/proc_devtree.c | 49 | ||||
-rw-r--r-- | fs/proc/proc_net.c | 1 | ||||
-rw-r--r-- | fs/proc/proc_sysctl.c | 4 | ||||
-rw-r--r-- | fs/proc/root.c | 6 | ||||
-rw-r--r-- | fs/proc/stat.c | 20 | ||||
-rw-r--r-- | fs/proc/task_mmu.c | 155 | ||||
-rw-r--r-- | fs/proc/task_nommu.c | 9 | ||||
-rw-r--r-- | fs/proc/vmcore.c | 1 |
17 files changed, 325 insertions, 341 deletions
diff --git a/fs/proc/array.c b/fs/proc/array.c index 822c2d506518..885ab5513ac5 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c | |||
@@ -68,7 +68,6 @@ | |||
68 | #include <linux/hugetlb.h> | 68 | #include <linux/hugetlb.h> |
69 | #include <linux/pagemap.h> | 69 | #include <linux/pagemap.h> |
70 | #include <linux/swap.h> | 70 | #include <linux/swap.h> |
71 | #include <linux/slab.h> | ||
72 | #include <linux/smp.h> | 71 | #include <linux/smp.h> |
73 | #include <linux/signal.h> | 72 | #include <linux/signal.h> |
74 | #include <linux/highmem.h> | 73 | #include <linux/highmem.h> |
@@ -82,7 +81,6 @@ | |||
82 | #include <linux/pid_namespace.h> | 81 | #include <linux/pid_namespace.h> |
83 | #include <linux/ptrace.h> | 82 | #include <linux/ptrace.h> |
84 | #include <linux/tracehook.h> | 83 | #include <linux/tracehook.h> |
85 | #include <linux/swapops.h> | ||
86 | 84 | ||
87 | #include <asm/pgtable.h> | 85 | #include <asm/pgtable.h> |
88 | #include <asm/processor.h> | 86 | #include <asm/processor.h> |
@@ -134,13 +132,16 @@ static inline void task_name(struct seq_file *m, struct task_struct *p) | |||
134 | * simple bit tests. | 132 | * simple bit tests. |
135 | */ | 133 | */ |
136 | static const char *task_state_array[] = { | 134 | static const char *task_state_array[] = { |
137 | "R (running)", /* 0 */ | 135 | "R (running)", /* 0 */ |
138 | "S (sleeping)", /* 1 */ | 136 | "S (sleeping)", /* 1 */ |
139 | "D (disk sleep)", /* 2 */ | 137 | "D (disk sleep)", /* 2 */ |
140 | "T (stopped)", /* 4 */ | 138 | "T (stopped)", /* 4 */ |
141 | "T (tracing stop)", /* 8 */ | 139 | "t (tracing stop)", /* 8 */ |
142 | "Z (zombie)", /* 16 */ | 140 | "Z (zombie)", /* 16 */ |
143 | "X (dead)" /* 32 */ | 141 | "X (dead)", /* 32 */ |
142 | "x (dead)", /* 64 */ | ||
143 | "K (wakekill)", /* 128 */ | ||
144 | "W (waking)", /* 256 */ | ||
144 | }; | 145 | }; |
145 | 146 | ||
146 | static inline const char *get_task_state(struct task_struct *tsk) | 147 | static inline const char *get_task_state(struct task_struct *tsk) |
@@ -148,6 +149,8 @@ static inline const char *get_task_state(struct task_struct *tsk) | |||
148 | unsigned int state = (tsk->state & TASK_REPORT) | tsk->exit_state; | 149 | unsigned int state = (tsk->state & TASK_REPORT) | tsk->exit_state; |
149 | const char **p = &task_state_array[0]; | 150 | const char **p = &task_state_array[0]; |
150 | 151 | ||
152 | BUILD_BUG_ON(1 + ilog2(TASK_STATE_MAX) != ARRAY_SIZE(task_state_array)); | ||
153 | |||
151 | while (state) { | 154 | while (state) { |
152 | p++; | 155 | p++; |
153 | state >>= 1; | 156 | state >>= 1; |
@@ -265,8 +268,10 @@ static inline void task_sig(struct seq_file *m, struct task_struct *p) | |||
265 | blocked = p->blocked; | 268 | blocked = p->blocked; |
266 | collect_sigign_sigcatch(p, &ignored, &caught); | 269 | collect_sigign_sigcatch(p, &ignored, &caught); |
267 | num_threads = atomic_read(&p->signal->count); | 270 | num_threads = atomic_read(&p->signal->count); |
271 | rcu_read_lock(); /* FIXME: is this correct? */ | ||
268 | qsize = atomic_read(&__task_cred(p)->user->sigpending); | 272 | qsize = atomic_read(&__task_cred(p)->user->sigpending); |
269 | qlim = p->signal->rlim[RLIMIT_SIGPENDING].rlim_cur; | 273 | rcu_read_unlock(); |
274 | qlim = task_rlimit(p, RLIMIT_SIGPENDING); | ||
270 | unlock_task_sighand(p, &flags); | 275 | unlock_task_sighand(p, &flags); |
271 | } | 276 | } |
272 | 277 | ||
@@ -322,93 +327,15 @@ static inline void task_context_switch_counts(struct seq_file *m, | |||
322 | p->nivcsw); | 327 | p->nivcsw); |
323 | } | 328 | } |
324 | 329 | ||
325 | #ifdef CONFIG_MMU | 330 | static void task_cpus_allowed(struct seq_file *m, struct task_struct *task) |
326 | |||
327 | struct stack_stats { | ||
328 | struct vm_area_struct *vma; | ||
329 | unsigned long startpage; | ||
330 | unsigned long usage; | ||
331 | }; | ||
332 | |||
333 | static int stack_usage_pte_range(pmd_t *pmd, unsigned long addr, | ||
334 | unsigned long end, struct mm_walk *walk) | ||
335 | { | ||
336 | struct stack_stats *ss = walk->private; | ||
337 | struct vm_area_struct *vma = ss->vma; | ||
338 | pte_t *pte, ptent; | ||
339 | spinlock_t *ptl; | ||
340 | int ret = 0; | ||
341 | |||
342 | pte = pte_offset_map_lock(vma->vm_mm, pmd, addr, &ptl); | ||
343 | for (; addr != end; pte++, addr += PAGE_SIZE) { | ||
344 | ptent = *pte; | ||
345 | |||
346 | #ifdef CONFIG_STACK_GROWSUP | ||
347 | if (pte_present(ptent) || is_swap_pte(ptent)) | ||
348 | ss->usage = addr - ss->startpage + PAGE_SIZE; | ||
349 | #else | ||
350 | if (pte_present(ptent) || is_swap_pte(ptent)) { | ||
351 | ss->usage = ss->startpage - addr + PAGE_SIZE; | ||
352 | pte++; | ||
353 | ret = 1; | ||
354 | break; | ||
355 | } | ||
356 | #endif | ||
357 | } | ||
358 | pte_unmap_unlock(pte - 1, ptl); | ||
359 | cond_resched(); | ||
360 | return ret; | ||
361 | } | ||
362 | |||
363 | static inline unsigned long get_stack_usage_in_bytes(struct vm_area_struct *vma, | ||
364 | struct task_struct *task) | ||
365 | { | ||
366 | struct stack_stats ss; | ||
367 | struct mm_walk stack_walk = { | ||
368 | .pmd_entry = stack_usage_pte_range, | ||
369 | .mm = vma->vm_mm, | ||
370 | .private = &ss, | ||
371 | }; | ||
372 | |||
373 | if (!vma->vm_mm || is_vm_hugetlb_page(vma)) | ||
374 | return 0; | ||
375 | |||
376 | ss.vma = vma; | ||
377 | ss.startpage = task->stack_start & PAGE_MASK; | ||
378 | ss.usage = 0; | ||
379 | |||
380 | #ifdef CONFIG_STACK_GROWSUP | ||
381 | walk_page_range(KSTK_ESP(task) & PAGE_MASK, vma->vm_end, | ||
382 | &stack_walk); | ||
383 | #else | ||
384 | walk_page_range(vma->vm_start, (KSTK_ESP(task) & PAGE_MASK) + PAGE_SIZE, | ||
385 | &stack_walk); | ||
386 | #endif | ||
387 | return ss.usage; | ||
388 | } | ||
389 | |||
390 | static inline void task_show_stack_usage(struct seq_file *m, | ||
391 | struct task_struct *task) | ||
392 | { | ||
393 | struct vm_area_struct *vma; | ||
394 | struct mm_struct *mm = get_task_mm(task); | ||
395 | |||
396 | if (mm) { | ||
397 | down_read(&mm->mmap_sem); | ||
398 | vma = find_vma(mm, task->stack_start); | ||
399 | if (vma) | ||
400 | seq_printf(m, "Stack usage:\t%lu kB\n", | ||
401 | get_stack_usage_in_bytes(vma, task) >> 10); | ||
402 | |||
403 | up_read(&mm->mmap_sem); | ||
404 | mmput(mm); | ||
405 | } | ||
406 | } | ||
407 | #else | ||
408 | static void task_show_stack_usage(struct seq_file *m, struct task_struct *task) | ||
409 | { | 331 | { |
332 | seq_printf(m, "Cpus_allowed:\t"); | ||
333 | seq_cpumask(m, &task->cpus_allowed); | ||
334 | seq_printf(m, "\n"); | ||
335 | seq_printf(m, "Cpus_allowed_list:\t"); | ||
336 | seq_cpumask_list(m, &task->cpus_allowed); | ||
337 | seq_printf(m, "\n"); | ||
410 | } | 338 | } |
411 | #endif /* CONFIG_MMU */ | ||
412 | 339 | ||
413 | int proc_pid_status(struct seq_file *m, struct pid_namespace *ns, | 340 | int proc_pid_status(struct seq_file *m, struct pid_namespace *ns, |
414 | struct pid *pid, struct task_struct *task) | 341 | struct pid *pid, struct task_struct *task) |
@@ -424,12 +351,12 @@ int proc_pid_status(struct seq_file *m, struct pid_namespace *ns, | |||
424 | } | 351 | } |
425 | task_sig(m, task); | 352 | task_sig(m, task); |
426 | task_cap(m, task); | 353 | task_cap(m, task); |
354 | task_cpus_allowed(m, task); | ||
427 | cpuset_task_status_allowed(m, task); | 355 | cpuset_task_status_allowed(m, task); |
428 | #if defined(CONFIG_S390) | 356 | #if defined(CONFIG_S390) |
429 | task_show_regs(m, task); | 357 | task_show_regs(m, task); |
430 | #endif | 358 | #endif |
431 | task_context_switch_counts(m, task); | 359 | task_context_switch_counts(m, task); |
432 | task_show_stack_usage(m, task); | ||
433 | return 0; | 360 | return 0; |
434 | } | 361 | } |
435 | 362 | ||
@@ -491,24 +418,21 @@ static int do_task_stat(struct seq_file *m, struct pid_namespace *ns, | |||
491 | cutime = sig->cutime; | 418 | cutime = sig->cutime; |
492 | cstime = sig->cstime; | 419 | cstime = sig->cstime; |
493 | cgtime = sig->cgtime; | 420 | cgtime = sig->cgtime; |
494 | rsslim = sig->rlim[RLIMIT_RSS].rlim_cur; | 421 | rsslim = ACCESS_ONCE(sig->rlim[RLIMIT_RSS].rlim_cur); |
495 | 422 | ||
496 | /* add up live thread stats at the group level */ | 423 | /* add up live thread stats at the group level */ |
497 | if (whole) { | 424 | if (whole) { |
498 | struct task_cputime cputime; | ||
499 | struct task_struct *t = task; | 425 | struct task_struct *t = task; |
500 | do { | 426 | do { |
501 | min_flt += t->min_flt; | 427 | min_flt += t->min_flt; |
502 | maj_flt += t->maj_flt; | 428 | maj_flt += t->maj_flt; |
503 | gtime = cputime_add(gtime, task_gtime(t)); | 429 | gtime = cputime_add(gtime, t->gtime); |
504 | t = next_thread(t); | 430 | t = next_thread(t); |
505 | } while (t != task); | 431 | } while (t != task); |
506 | 432 | ||
507 | min_flt += sig->min_flt; | 433 | min_flt += sig->min_flt; |
508 | maj_flt += sig->maj_flt; | 434 | maj_flt += sig->maj_flt; |
509 | thread_group_cputime(task, &cputime); | 435 | thread_group_times(task, &utime, &stime); |
510 | utime = cputime.utime; | ||
511 | stime = cputime.stime; | ||
512 | gtime = cputime_add(gtime, sig->gtime); | 436 | gtime = cputime_add(gtime, sig->gtime); |
513 | } | 437 | } |
514 | 438 | ||
@@ -524,9 +448,8 @@ static int do_task_stat(struct seq_file *m, struct pid_namespace *ns, | |||
524 | if (!whole) { | 448 | if (!whole) { |
525 | min_flt = task->min_flt; | 449 | min_flt = task->min_flt; |
526 | maj_flt = task->maj_flt; | 450 | maj_flt = task->maj_flt; |
527 | utime = task_utime(task); | 451 | task_times(task, &utime, &stime); |
528 | stime = task_stime(task); | 452 | gtime = task->gtime; |
529 | gtime = task_gtime(task); | ||
530 | } | 453 | } |
531 | 454 | ||
532 | /* scale priority and nice values from timeslices to -20..20 */ | 455 | /* scale priority and nice values from timeslices to -20..20 */ |
@@ -571,7 +494,7 @@ static int do_task_stat(struct seq_file *m, struct pid_namespace *ns, | |||
571 | rsslim, | 494 | rsslim, |
572 | mm ? mm->start_code : 0, | 495 | mm ? mm->start_code : 0, |
573 | mm ? mm->end_code : 0, | 496 | mm ? mm->end_code : 0, |
574 | (permitted && mm) ? task->stack_start : 0, | 497 | (permitted && mm) ? mm->start_stack : 0, |
575 | esp, | 498 | esp, |
576 | eip, | 499 | eip, |
577 | /* The signal information here is obsolete. | 500 | /* The signal information here is obsolete. |
diff --git a/fs/proc/base.c b/fs/proc/base.c index af643b5aefe8..8418fcc0a6ab 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c | |||
@@ -81,6 +81,7 @@ | |||
81 | #include <linux/elf.h> | 81 | #include <linux/elf.h> |
82 | #include <linux/pid_namespace.h> | 82 | #include <linux/pid_namespace.h> |
83 | #include <linux/fs_struct.h> | 83 | #include <linux/fs_struct.h> |
84 | #include <linux/slab.h> | ||
84 | #include "internal.h" | 85 | #include "internal.h" |
85 | 86 | ||
86 | /* NOTE: | 87 | /* NOTE: |
@@ -442,12 +443,13 @@ static const struct file_operations proc_lstats_operations = { | |||
442 | unsigned long badness(struct task_struct *p, unsigned long uptime); | 443 | unsigned long badness(struct task_struct *p, unsigned long uptime); |
443 | static int proc_oom_score(struct task_struct *task, char *buffer) | 444 | static int proc_oom_score(struct task_struct *task, char *buffer) |
444 | { | 445 | { |
445 | unsigned long points; | 446 | unsigned long points = 0; |
446 | struct timespec uptime; | 447 | struct timespec uptime; |
447 | 448 | ||
448 | do_posix_clock_monotonic_gettime(&uptime); | 449 | do_posix_clock_monotonic_gettime(&uptime); |
449 | read_lock(&tasklist_lock); | 450 | read_lock(&tasklist_lock); |
450 | points = badness(task->group_leader, uptime.tv_sec); | 451 | if (pid_alive(task)) |
452 | points = badness(task, uptime.tv_sec); | ||
451 | read_unlock(&tasklist_lock); | 453 | read_unlock(&tasklist_lock); |
452 | return sprintf(buffer, "%lu\n", points); | 454 | return sprintf(buffer, "%lu\n", points); |
453 | } | 455 | } |
@@ -647,17 +649,11 @@ static int mounts_release(struct inode *inode, struct file *file) | |||
647 | static unsigned mounts_poll(struct file *file, poll_table *wait) | 649 | static unsigned mounts_poll(struct file *file, poll_table *wait) |
648 | { | 650 | { |
649 | struct proc_mounts *p = file->private_data; | 651 | struct proc_mounts *p = file->private_data; |
650 | struct mnt_namespace *ns = p->ns; | ||
651 | unsigned res = POLLIN | POLLRDNORM; | 652 | unsigned res = POLLIN | POLLRDNORM; |
652 | 653 | ||
653 | poll_wait(file, &ns->poll, wait); | 654 | poll_wait(file, &p->ns->poll, wait); |
654 | 655 | if (mnt_had_events(p)) | |
655 | spin_lock(&vfsmount_lock); | ||
656 | if (p->event != ns->event) { | ||
657 | p->event = ns->event; | ||
658 | res |= POLLERR | POLLPRI; | 656 | res |= POLLERR | POLLPRI; |
659 | } | ||
660 | spin_unlock(&vfsmount_lock); | ||
661 | 657 | ||
662 | return res; | 658 | return res; |
663 | } | 659 | } |
@@ -1095,8 +1091,12 @@ static ssize_t proc_loginuid_write(struct file * file, const char __user * buf, | |||
1095 | if (!capable(CAP_AUDIT_CONTROL)) | 1091 | if (!capable(CAP_AUDIT_CONTROL)) |
1096 | return -EPERM; | 1092 | return -EPERM; |
1097 | 1093 | ||
1098 | if (current != pid_task(proc_pid(inode), PIDTYPE_PID)) | 1094 | rcu_read_lock(); |
1095 | if (current != pid_task(proc_pid(inode), PIDTYPE_PID)) { | ||
1096 | rcu_read_unlock(); | ||
1099 | return -EPERM; | 1097 | return -EPERM; |
1098 | } | ||
1099 | rcu_read_unlock(); | ||
1100 | 1100 | ||
1101 | if (count >= PAGE_SIZE) | 1101 | if (count >= PAGE_SIZE) |
1102 | count = PAGE_SIZE - 1; | 1102 | count = PAGE_SIZE - 1; |
@@ -1265,6 +1265,72 @@ static const struct file_operations proc_pid_sched_operations = { | |||
1265 | 1265 | ||
1266 | #endif | 1266 | #endif |
1267 | 1267 | ||
1268 | static ssize_t comm_write(struct file *file, const char __user *buf, | ||
1269 | size_t count, loff_t *offset) | ||
1270 | { | ||
1271 | struct inode *inode = file->f_path.dentry->d_inode; | ||
1272 | struct task_struct *p; | ||
1273 | char buffer[TASK_COMM_LEN]; | ||
1274 | |||
1275 | memset(buffer, 0, sizeof(buffer)); | ||
1276 | if (count > sizeof(buffer) - 1) | ||
1277 | count = sizeof(buffer) - 1; | ||
1278 | if (copy_from_user(buffer, buf, count)) | ||
1279 | return -EFAULT; | ||
1280 | |||
1281 | p = get_proc_task(inode); | ||
1282 | if (!p) | ||
1283 | return -ESRCH; | ||
1284 | |||
1285 | if (same_thread_group(current, p)) | ||
1286 | set_task_comm(p, buffer); | ||
1287 | else | ||
1288 | count = -EINVAL; | ||
1289 | |||
1290 | put_task_struct(p); | ||
1291 | |||
1292 | return count; | ||
1293 | } | ||
1294 | |||
1295 | static int comm_show(struct seq_file *m, void *v) | ||
1296 | { | ||
1297 | struct inode *inode = m->private; | ||
1298 | struct task_struct *p; | ||
1299 | |||
1300 | p = get_proc_task(inode); | ||
1301 | if (!p) | ||
1302 | return -ESRCH; | ||
1303 | |||
1304 | task_lock(p); | ||
1305 | seq_printf(m, "%s\n", p->comm); | ||
1306 | task_unlock(p); | ||
1307 | |||
1308 | put_task_struct(p); | ||
1309 | |||
1310 | return 0; | ||
1311 | } | ||
1312 | |||
1313 | static int comm_open(struct inode *inode, struct file *filp) | ||
1314 | { | ||
1315 | int ret; | ||
1316 | |||
1317 | ret = single_open(filp, comm_show, NULL); | ||
1318 | if (!ret) { | ||
1319 | struct seq_file *m = filp->private_data; | ||
1320 | |||
1321 | m->private = inode; | ||
1322 | } | ||
1323 | return ret; | ||
1324 | } | ||
1325 | |||
1326 | static const struct file_operations proc_pid_set_comm_operations = { | ||
1327 | .open = comm_open, | ||
1328 | .read = seq_read, | ||
1329 | .write = comm_write, | ||
1330 | .llseek = seq_lseek, | ||
1331 | .release = single_release, | ||
1332 | }; | ||
1333 | |||
1268 | /* | 1334 | /* |
1269 | * We added or removed a vma mapping the executable. The vmas are only mapped | 1335 | * We added or removed a vma mapping the executable. The vmas are only mapped |
1270 | * during exec and are not mapped with the mmap system call. | 1336 | * during exec and are not mapped with the mmap system call. |
@@ -1353,7 +1419,6 @@ static void *proc_pid_follow_link(struct dentry *dentry, struct nameidata *nd) | |||
1353 | goto out; | 1419 | goto out; |
1354 | 1420 | ||
1355 | error = PROC_I(inode)->op.proc_get_link(inode, &nd->path); | 1421 | error = PROC_I(inode)->op.proc_get_link(inode, &nd->path); |
1356 | nd->last_type = LAST_BIND; | ||
1357 | out: | 1422 | out: |
1358 | return ERR_PTR(error); | 1423 | return ERR_PTR(error); |
1359 | } | 1424 | } |
@@ -2200,7 +2265,7 @@ static const struct inode_operations proc_attr_dir_inode_operations = { | |||
2200 | 2265 | ||
2201 | #endif | 2266 | #endif |
2202 | 2267 | ||
2203 | #if defined(USE_ELF_CORE_DUMP) && defined(CONFIG_ELF_CORE) | 2268 | #ifdef CONFIG_ELF_CORE |
2204 | static ssize_t proc_coredump_filter_read(struct file *file, char __user *buf, | 2269 | static ssize_t proc_coredump_filter_read(struct file *file, char __user *buf, |
2205 | size_t count, loff_t *ppos) | 2270 | size_t count, loff_t *ppos) |
2206 | { | 2271 | { |
@@ -2304,16 +2369,30 @@ static void *proc_self_follow_link(struct dentry *dentry, struct nameidata *nd) | |||
2304 | { | 2369 | { |
2305 | struct pid_namespace *ns = dentry->d_sb->s_fs_info; | 2370 | struct pid_namespace *ns = dentry->d_sb->s_fs_info; |
2306 | pid_t tgid = task_tgid_nr_ns(current, ns); | 2371 | pid_t tgid = task_tgid_nr_ns(current, ns); |
2307 | char tmp[PROC_NUMBUF]; | 2372 | char *name = ERR_PTR(-ENOENT); |
2308 | if (!tgid) | 2373 | if (tgid) { |
2309 | return ERR_PTR(-ENOENT); | 2374 | name = __getname(); |
2310 | sprintf(tmp, "%d", task_tgid_nr_ns(current, ns)); | 2375 | if (!name) |
2311 | return ERR_PTR(vfs_follow_link(nd,tmp)); | 2376 | name = ERR_PTR(-ENOMEM); |
2377 | else | ||
2378 | sprintf(name, "%d", tgid); | ||
2379 | } | ||
2380 | nd_set_link(nd, name); | ||
2381 | return NULL; | ||
2382 | } | ||
2383 | |||
2384 | static void proc_self_put_link(struct dentry *dentry, struct nameidata *nd, | ||
2385 | void *cookie) | ||
2386 | { | ||
2387 | char *s = nd_get_link(nd); | ||
2388 | if (!IS_ERR(s)) | ||
2389 | __putname(s); | ||
2312 | } | 2390 | } |
2313 | 2391 | ||
2314 | static const struct inode_operations proc_self_inode_operations = { | 2392 | static const struct inode_operations proc_self_inode_operations = { |
2315 | .readlink = proc_self_readlink, | 2393 | .readlink = proc_self_readlink, |
2316 | .follow_link = proc_self_follow_link, | 2394 | .follow_link = proc_self_follow_link, |
2395 | .put_link = proc_self_put_link, | ||
2317 | }; | 2396 | }; |
2318 | 2397 | ||
2319 | /* | 2398 | /* |
@@ -2504,6 +2583,7 @@ static const struct pid_entry tgid_base_stuff[] = { | |||
2504 | #ifdef CONFIG_SCHED_DEBUG | 2583 | #ifdef CONFIG_SCHED_DEBUG |
2505 | REG("sched", S_IRUGO|S_IWUSR, proc_pid_sched_operations), | 2584 | REG("sched", S_IRUGO|S_IWUSR, proc_pid_sched_operations), |
2506 | #endif | 2585 | #endif |
2586 | REG("comm", S_IRUGO|S_IWUSR, proc_pid_set_comm_operations), | ||
2507 | #ifdef CONFIG_HAVE_ARCH_TRACEHOOK | 2587 | #ifdef CONFIG_HAVE_ARCH_TRACEHOOK |
2508 | INF("syscall", S_IRUSR, proc_pid_syscall), | 2588 | INF("syscall", S_IRUSR, proc_pid_syscall), |
2509 | #endif | 2589 | #endif |
@@ -2556,7 +2636,7 @@ static const struct pid_entry tgid_base_stuff[] = { | |||
2556 | #ifdef CONFIG_FAULT_INJECTION | 2636 | #ifdef CONFIG_FAULT_INJECTION |
2557 | REG("make-it-fail", S_IRUGO|S_IWUSR, proc_fault_inject_operations), | 2637 | REG("make-it-fail", S_IRUGO|S_IWUSR, proc_fault_inject_operations), |
2558 | #endif | 2638 | #endif |
2559 | #if defined(USE_ELF_CORE_DUMP) && defined(CONFIG_ELF_CORE) | 2639 | #ifdef CONFIG_ELF_CORE |
2560 | REG("coredump_filter", S_IRUGO|S_IWUSR, proc_coredump_filter_operations), | 2640 | REG("coredump_filter", S_IRUGO|S_IWUSR, proc_coredump_filter_operations), |
2561 | #endif | 2641 | #endif |
2562 | #ifdef CONFIG_TASK_IO_ACCOUNTING | 2642 | #ifdef CONFIG_TASK_IO_ACCOUNTING |
@@ -2829,7 +2909,7 @@ out_no_task: | |||
2829 | */ | 2909 | */ |
2830 | static const struct pid_entry tid_base_stuff[] = { | 2910 | static const struct pid_entry tid_base_stuff[] = { |
2831 | DIR("fd", S_IRUSR|S_IXUSR, proc_fd_inode_operations, proc_fd_operations), | 2911 | DIR("fd", S_IRUSR|S_IXUSR, proc_fd_inode_operations, proc_fd_operations), |
2832 | DIR("fdinfo", S_IRUSR|S_IXUSR, proc_fdinfo_inode_operations, proc_fd_operations), | 2912 | DIR("fdinfo", S_IRUSR|S_IXUSR, proc_fdinfo_inode_operations, proc_fdinfo_operations), |
2833 | REG("environ", S_IRUSR, proc_environ_operations), | 2913 | REG("environ", S_IRUSR, proc_environ_operations), |
2834 | INF("auxv", S_IRUSR, proc_pid_auxv), | 2914 | INF("auxv", S_IRUSR, proc_pid_auxv), |
2835 | ONE("status", S_IRUGO, proc_pid_status), | 2915 | ONE("status", S_IRUGO, proc_pid_status), |
@@ -2838,6 +2918,7 @@ static const struct pid_entry tid_base_stuff[] = { | |||
2838 | #ifdef CONFIG_SCHED_DEBUG | 2918 | #ifdef CONFIG_SCHED_DEBUG |
2839 | REG("sched", S_IRUGO|S_IWUSR, proc_pid_sched_operations), | 2919 | REG("sched", S_IRUGO|S_IWUSR, proc_pid_sched_operations), |
2840 | #endif | 2920 | #endif |
2921 | REG("comm", S_IRUGO|S_IWUSR, proc_pid_set_comm_operations), | ||
2841 | #ifdef CONFIG_HAVE_ARCH_TRACEHOOK | 2922 | #ifdef CONFIG_HAVE_ARCH_TRACEHOOK |
2842 | INF("syscall", S_IRUSR, proc_pid_syscall), | 2923 | INF("syscall", S_IRUSR, proc_pid_syscall), |
2843 | #endif | 2924 | #endif |
diff --git a/fs/proc/generic.c b/fs/proc/generic.c index fa678abc9db1..43c127490606 100644 --- a/fs/proc/generic.c +++ b/fs/proc/generic.c | |||
@@ -13,6 +13,7 @@ | |||
13 | #include <linux/proc_fs.h> | 13 | #include <linux/proc_fs.h> |
14 | #include <linux/stat.h> | 14 | #include <linux/stat.h> |
15 | #include <linux/module.h> | 15 | #include <linux/module.h> |
16 | #include <linux/slab.h> | ||
16 | #include <linux/mount.h> | 17 | #include <linux/mount.h> |
17 | #include <linux/init.h> | 18 | #include <linux/init.h> |
18 | #include <linux/idr.h> | 19 | #include <linux/idr.h> |
@@ -291,19 +292,17 @@ static const struct inode_operations proc_file_inode_operations = { | |||
291 | * returns the struct proc_dir_entry for "/proc/tty/driver", and | 292 | * returns the struct proc_dir_entry for "/proc/tty/driver", and |
292 | * returns "serial" in residual. | 293 | * returns "serial" in residual. |
293 | */ | 294 | */ |
294 | static int xlate_proc_name(const char *name, | 295 | static int __xlate_proc_name(const char *name, struct proc_dir_entry **ret, |
295 | struct proc_dir_entry **ret, const char **residual) | 296 | const char **residual) |
296 | { | 297 | { |
297 | const char *cp = name, *next; | 298 | const char *cp = name, *next; |
298 | struct proc_dir_entry *de; | 299 | struct proc_dir_entry *de; |
299 | int len; | 300 | int len; |
300 | int rtn = 0; | ||
301 | 301 | ||
302 | de = *ret; | 302 | de = *ret; |
303 | if (!de) | 303 | if (!de) |
304 | de = &proc_root; | 304 | de = &proc_root; |
305 | 305 | ||
306 | spin_lock(&proc_subdir_lock); | ||
307 | while (1) { | 306 | while (1) { |
308 | next = strchr(cp, '/'); | 307 | next = strchr(cp, '/'); |
309 | if (!next) | 308 | if (!next) |
@@ -315,16 +314,25 @@ static int xlate_proc_name(const char *name, | |||
315 | break; | 314 | break; |
316 | } | 315 | } |
317 | if (!de) { | 316 | if (!de) { |
318 | rtn = -ENOENT; | 317 | WARN(1, "name '%s'\n", name); |
319 | goto out; | 318 | return -ENOENT; |
320 | } | 319 | } |
321 | cp += len + 1; | 320 | cp += len + 1; |
322 | } | 321 | } |
323 | *residual = cp; | 322 | *residual = cp; |
324 | *ret = de; | 323 | *ret = de; |
325 | out: | 324 | return 0; |
325 | } | ||
326 | |||
327 | static int xlate_proc_name(const char *name, struct proc_dir_entry **ret, | ||
328 | const char **residual) | ||
329 | { | ||
330 | int rv; | ||
331 | |||
332 | spin_lock(&proc_subdir_lock); | ||
333 | rv = __xlate_proc_name(name, ret, residual); | ||
326 | spin_unlock(&proc_subdir_lock); | 334 | spin_unlock(&proc_subdir_lock); |
327 | return rtn; | 335 | return rv; |
328 | } | 336 | } |
329 | 337 | ||
330 | static DEFINE_IDA(proc_inum_ida); | 338 | static DEFINE_IDA(proc_inum_ida); |
@@ -429,7 +437,7 @@ struct dentry *proc_lookup_de(struct proc_dir_entry *de, struct inode *dir, | |||
429 | unsigned int ino; | 437 | unsigned int ino; |
430 | 438 | ||
431 | ino = de->low_ino; | 439 | ino = de->low_ino; |
432 | de_get(de); | 440 | pde_get(de); |
433 | spin_unlock(&proc_subdir_lock); | 441 | spin_unlock(&proc_subdir_lock); |
434 | error = -EINVAL; | 442 | error = -EINVAL; |
435 | inode = proc_get_inode(dir->i_sb, ino, de); | 443 | inode = proc_get_inode(dir->i_sb, ino, de); |
@@ -445,7 +453,7 @@ out_unlock: | |||
445 | return NULL; | 453 | return NULL; |
446 | } | 454 | } |
447 | if (de) | 455 | if (de) |
448 | de_put(de); | 456 | pde_put(de); |
449 | return ERR_PTR(error); | 457 | return ERR_PTR(error); |
450 | } | 458 | } |
451 | 459 | ||
@@ -509,17 +517,17 @@ int proc_readdir_de(struct proc_dir_entry *de, struct file *filp, void *dirent, | |||
509 | struct proc_dir_entry *next; | 517 | struct proc_dir_entry *next; |
510 | 518 | ||
511 | /* filldir passes info to user space */ | 519 | /* filldir passes info to user space */ |
512 | de_get(de); | 520 | pde_get(de); |
513 | spin_unlock(&proc_subdir_lock); | 521 | spin_unlock(&proc_subdir_lock); |
514 | if (filldir(dirent, de->name, de->namelen, filp->f_pos, | 522 | if (filldir(dirent, de->name, de->namelen, filp->f_pos, |
515 | de->low_ino, de->mode >> 12) < 0) { | 523 | de->low_ino, de->mode >> 12) < 0) { |
516 | de_put(de); | 524 | pde_put(de); |
517 | goto out; | 525 | goto out; |
518 | } | 526 | } |
519 | spin_lock(&proc_subdir_lock); | 527 | spin_lock(&proc_subdir_lock); |
520 | filp->f_pos++; | 528 | filp->f_pos++; |
521 | next = de->next; | 529 | next = de->next; |
522 | de_put(de); | 530 | pde_put(de); |
523 | de = next; | 531 | de = next; |
524 | } while (de); | 532 | } while (de); |
525 | spin_unlock(&proc_subdir_lock); | 533 | spin_unlock(&proc_subdir_lock); |
@@ -662,6 +670,7 @@ struct proc_dir_entry *proc_symlink(const char *name, | |||
662 | } | 670 | } |
663 | return ent; | 671 | return ent; |
664 | } | 672 | } |
673 | EXPORT_SYMBOL(proc_symlink); | ||
665 | 674 | ||
666 | struct proc_dir_entry *proc_mkdir_mode(const char *name, mode_t mode, | 675 | struct proc_dir_entry *proc_mkdir_mode(const char *name, mode_t mode, |
667 | struct proc_dir_entry *parent) | 676 | struct proc_dir_entry *parent) |
@@ -700,6 +709,7 @@ struct proc_dir_entry *proc_mkdir(const char *name, | |||
700 | { | 709 | { |
701 | return proc_mkdir_mode(name, S_IRUGO | S_IXUGO, parent); | 710 | return proc_mkdir_mode(name, S_IRUGO | S_IXUGO, parent); |
702 | } | 711 | } |
712 | EXPORT_SYMBOL(proc_mkdir); | ||
703 | 713 | ||
704 | struct proc_dir_entry *create_proc_entry(const char *name, mode_t mode, | 714 | struct proc_dir_entry *create_proc_entry(const char *name, mode_t mode, |
705 | struct proc_dir_entry *parent) | 715 | struct proc_dir_entry *parent) |
@@ -728,6 +738,7 @@ struct proc_dir_entry *create_proc_entry(const char *name, mode_t mode, | |||
728 | } | 738 | } |
729 | return ent; | 739 | return ent; |
730 | } | 740 | } |
741 | EXPORT_SYMBOL(create_proc_entry); | ||
731 | 742 | ||
732 | struct proc_dir_entry *proc_create_data(const char *name, mode_t mode, | 743 | struct proc_dir_entry *proc_create_data(const char *name, mode_t mode, |
733 | struct proc_dir_entry *parent, | 744 | struct proc_dir_entry *parent, |
@@ -762,8 +773,9 @@ out_free: | |||
762 | out: | 773 | out: |
763 | return NULL; | 774 | return NULL; |
764 | } | 775 | } |
776 | EXPORT_SYMBOL(proc_create_data); | ||
765 | 777 | ||
766 | void free_proc_entry(struct proc_dir_entry *de) | 778 | static void free_proc_entry(struct proc_dir_entry *de) |
767 | { | 779 | { |
768 | unsigned int ino = de->low_ino; | 780 | unsigned int ino = de->low_ino; |
769 | 781 | ||
@@ -777,6 +789,12 @@ void free_proc_entry(struct proc_dir_entry *de) | |||
777 | kfree(de); | 789 | kfree(de); |
778 | } | 790 | } |
779 | 791 | ||
792 | void pde_put(struct proc_dir_entry *pde) | ||
793 | { | ||
794 | if (atomic_dec_and_test(&pde->count)) | ||
795 | free_proc_entry(pde); | ||
796 | } | ||
797 | |||
780 | /* | 798 | /* |
781 | * Remove a /proc entry and free it if it's not currently in use. | 799 | * Remove a /proc entry and free it if it's not currently in use. |
782 | */ | 800 | */ |
@@ -787,11 +805,13 @@ void remove_proc_entry(const char *name, struct proc_dir_entry *parent) | |||
787 | const char *fn = name; | 805 | const char *fn = name; |
788 | int len; | 806 | int len; |
789 | 807 | ||
790 | if (xlate_proc_name(name, &parent, &fn) != 0) | 808 | spin_lock(&proc_subdir_lock); |
809 | if (__xlate_proc_name(name, &parent, &fn) != 0) { | ||
810 | spin_unlock(&proc_subdir_lock); | ||
791 | return; | 811 | return; |
812 | } | ||
792 | len = strlen(fn); | 813 | len = strlen(fn); |
793 | 814 | ||
794 | spin_lock(&proc_subdir_lock); | ||
795 | for (p = &parent->subdir; *p; p=&(*p)->next ) { | 815 | for (p = &parent->subdir; *p; p=&(*p)->next ) { |
796 | if (proc_match(len, fn, *p)) { | 816 | if (proc_match(len, fn, *p)) { |
797 | de = *p; | 817 | de = *p; |
@@ -801,8 +821,10 @@ void remove_proc_entry(const char *name, struct proc_dir_entry *parent) | |||
801 | } | 821 | } |
802 | } | 822 | } |
803 | spin_unlock(&proc_subdir_lock); | 823 | spin_unlock(&proc_subdir_lock); |
804 | if (!de) | 824 | if (!de) { |
825 | WARN(1, "name '%s'\n", name); | ||
805 | return; | 826 | return; |
827 | } | ||
806 | 828 | ||
807 | spin_lock(&de->pde_unload_lock); | 829 | spin_lock(&de->pde_unload_lock); |
808 | /* | 830 | /* |
@@ -845,6 +867,6 @@ continue_removing: | |||
845 | WARN(de->subdir, KERN_WARNING "%s: removing non-empty directory " | 867 | WARN(de->subdir, KERN_WARNING "%s: removing non-empty directory " |
846 | "'%s/%s', leaking at least '%s'\n", __func__, | 868 | "'%s/%s', leaking at least '%s'\n", __func__, |
847 | de->parent->name, de->name, de->subdir->name); | 869 | de->parent->name, de->name, de->subdir->name); |
848 | if (atomic_dec_and_test(&de->count)) | 870 | pde_put(de); |
849 | free_proc_entry(de); | ||
850 | } | 871 | } |
872 | EXPORT_SYMBOL(remove_proc_entry); | ||
diff --git a/fs/proc/inode.c b/fs/proc/inode.c index d78ade305541..d35b23238fb1 100644 --- a/fs/proc/inode.c +++ b/fs/proc/inode.c | |||
@@ -18,35 +18,13 @@ | |||
18 | #include <linux/module.h> | 18 | #include <linux/module.h> |
19 | #include <linux/smp_lock.h> | 19 | #include <linux/smp_lock.h> |
20 | #include <linux/sysctl.h> | 20 | #include <linux/sysctl.h> |
21 | #include <linux/slab.h> | ||
21 | 22 | ||
22 | #include <asm/system.h> | 23 | #include <asm/system.h> |
23 | #include <asm/uaccess.h> | 24 | #include <asm/uaccess.h> |
24 | 25 | ||
25 | #include "internal.h" | 26 | #include "internal.h" |
26 | 27 | ||
27 | struct proc_dir_entry *de_get(struct proc_dir_entry *de) | ||
28 | { | ||
29 | atomic_inc(&de->count); | ||
30 | return de; | ||
31 | } | ||
32 | |||
33 | /* | ||
34 | * Decrements the use count and checks for deferred deletion. | ||
35 | */ | ||
36 | void de_put(struct proc_dir_entry *de) | ||
37 | { | ||
38 | if (!atomic_read(&de->count)) { | ||
39 | printk("de_put: entry %s already free!\n", de->name); | ||
40 | return; | ||
41 | } | ||
42 | |||
43 | if (atomic_dec_and_test(&de->count)) | ||
44 | free_proc_entry(de); | ||
45 | } | ||
46 | |||
47 | /* | ||
48 | * Decrement the use count of the proc_dir_entry. | ||
49 | */ | ||
50 | static void proc_delete_inode(struct inode *inode) | 28 | static void proc_delete_inode(struct inode *inode) |
51 | { | 29 | { |
52 | struct proc_dir_entry *de; | 30 | struct proc_dir_entry *de; |
@@ -59,7 +37,7 @@ static void proc_delete_inode(struct inode *inode) | |||
59 | /* Let go of any associated proc directory entry */ | 37 | /* Let go of any associated proc directory entry */ |
60 | de = PROC_I(inode)->pde; | 38 | de = PROC_I(inode)->pde; |
61 | if (de) | 39 | if (de) |
62 | de_put(de); | 40 | pde_put(de); |
63 | if (PROC_I(inode)->sysctl) | 41 | if (PROC_I(inode)->sysctl) |
64 | sysctl_head_put(PROC_I(inode)->sysctl); | 42 | sysctl_head_put(PROC_I(inode)->sysctl); |
65 | clear_inode(inode); | 43 | clear_inode(inode); |
@@ -480,7 +458,7 @@ struct inode *proc_get_inode(struct super_block *sb, unsigned int ino, | |||
480 | } | 458 | } |
481 | unlock_new_inode(inode); | 459 | unlock_new_inode(inode); |
482 | } else | 460 | } else |
483 | de_put(de); | 461 | pde_put(de); |
484 | return inode; | 462 | return inode; |
485 | } | 463 | } |
486 | 464 | ||
@@ -495,7 +473,7 @@ int proc_fill_super(struct super_block *s) | |||
495 | s->s_op = &proc_sops; | 473 | s->s_op = &proc_sops; |
496 | s->s_time_gran = 1; | 474 | s->s_time_gran = 1; |
497 | 475 | ||
498 | de_get(&proc_root); | 476 | pde_get(&proc_root); |
499 | root_inode = proc_get_inode(s, PROC_ROOT_INO, &proc_root); | 477 | root_inode = proc_get_inode(s, PROC_ROOT_INO, &proc_root); |
500 | if (!root_inode) | 478 | if (!root_inode) |
501 | goto out_no_root; | 479 | goto out_no_root; |
@@ -509,6 +487,6 @@ int proc_fill_super(struct super_block *s) | |||
509 | out_no_root: | 487 | out_no_root: |
510 | printk("proc_read_super: get root inode failed\n"); | 488 | printk("proc_read_super: get root inode failed\n"); |
511 | iput(root_inode); | 489 | iput(root_inode); |
512 | de_put(&proc_root); | 490 | pde_put(&proc_root); |
513 | return -ENOMEM; | 491 | return -ENOMEM; |
514 | } | 492 | } |
diff --git a/fs/proc/internal.h b/fs/proc/internal.h index 753ca37002c8..1f24a3eddd12 100644 --- a/fs/proc/internal.h +++ b/fs/proc/internal.h | |||
@@ -61,8 +61,6 @@ extern const struct file_operations proc_pagemap_operations; | |||
61 | extern const struct file_operations proc_net_operations; | 61 | extern const struct file_operations proc_net_operations; |
62 | extern const struct inode_operations proc_net_inode_operations; | 62 | extern const struct inode_operations proc_net_inode_operations; |
63 | 63 | ||
64 | void free_proc_entry(struct proc_dir_entry *de); | ||
65 | |||
66 | void proc_init_inodecache(void); | 64 | void proc_init_inodecache(void); |
67 | 65 | ||
68 | static inline struct pid *proc_pid(struct inode *inode) | 66 | static inline struct pid *proc_pid(struct inode *inode) |
@@ -101,8 +99,12 @@ unsigned long task_vsize(struct mm_struct *); | |||
101 | int task_statm(struct mm_struct *, int *, int *, int *, int *); | 99 | int task_statm(struct mm_struct *, int *, int *, int *, int *); |
102 | void task_mem(struct seq_file *, struct mm_struct *); | 100 | void task_mem(struct seq_file *, struct mm_struct *); |
103 | 101 | ||
104 | struct proc_dir_entry *de_get(struct proc_dir_entry *de); | 102 | static inline struct proc_dir_entry *pde_get(struct proc_dir_entry *pde) |
105 | void de_put(struct proc_dir_entry *de); | 103 | { |
104 | atomic_inc(&pde->count); | ||
105 | return pde; | ||
106 | } | ||
107 | void pde_put(struct proc_dir_entry *pde); | ||
106 | 108 | ||
107 | extern struct vfsmount *proc_mnt; | 109 | extern struct vfsmount *proc_mnt; |
108 | int proc_fill_super(struct super_block *); | 110 | int proc_fill_super(struct super_block *); |
diff --git a/fs/proc/kcore.c b/fs/proc/kcore.c index a44a7897fd4d..19979a2ce272 100644 --- a/fs/proc/kcore.c +++ b/fs/proc/kcore.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <linux/highmem.h> | 19 | #include <linux/highmem.h> |
20 | #include <linux/bootmem.h> | 20 | #include <linux/bootmem.h> |
21 | #include <linux/init.h> | 21 | #include <linux/init.h> |
22 | #include <linux/slab.h> | ||
22 | #include <asm/uaccess.h> | 23 | #include <asm/uaccess.h> |
23 | #include <asm/io.h> | 24 | #include <asm/io.h> |
24 | #include <linux/list.h> | 25 | #include <linux/list.h> |
@@ -490,7 +491,7 @@ read_kcore(struct file *file, char __user *buffer, size_t buflen, loff_t *fpos) | |||
490 | } | 491 | } |
491 | read_unlock(&kclist_lock); | 492 | read_unlock(&kclist_lock); |
492 | 493 | ||
493 | if (m == NULL) { | 494 | if (&m->list == &kclist_head) { |
494 | if (clear_user(buffer, tsz)) | 495 | if (clear_user(buffer, tsz)) |
495 | return -EFAULT; | 496 | return -EFAULT; |
496 | } else if (is_vmalloc_or_module_addr((void *)start)) { | 497 | } else if (is_vmalloc_or_module_addr((void *)start)) { |
diff --git a/fs/proc/kmsg.c b/fs/proc/kmsg.c index 7ca78346d3f0..cfe90a48a6e8 100644 --- a/fs/proc/kmsg.c +++ b/fs/proc/kmsg.c | |||
@@ -12,37 +12,37 @@ | |||
12 | #include <linux/poll.h> | 12 | #include <linux/poll.h> |
13 | #include <linux/proc_fs.h> | 13 | #include <linux/proc_fs.h> |
14 | #include <linux/fs.h> | 14 | #include <linux/fs.h> |
15 | #include <linux/syslog.h> | ||
15 | 16 | ||
16 | #include <asm/uaccess.h> | 17 | #include <asm/uaccess.h> |
17 | #include <asm/io.h> | 18 | #include <asm/io.h> |
18 | 19 | ||
19 | extern wait_queue_head_t log_wait; | 20 | extern wait_queue_head_t log_wait; |
20 | 21 | ||
21 | extern int do_syslog(int type, char __user *bug, int count); | ||
22 | |||
23 | static int kmsg_open(struct inode * inode, struct file * file) | 22 | static int kmsg_open(struct inode * inode, struct file * file) |
24 | { | 23 | { |
25 | return do_syslog(1,NULL,0); | 24 | return do_syslog(SYSLOG_ACTION_OPEN, NULL, 0, SYSLOG_FROM_FILE); |
26 | } | 25 | } |
27 | 26 | ||
28 | static int kmsg_release(struct inode * inode, struct file * file) | 27 | static int kmsg_release(struct inode * inode, struct file * file) |
29 | { | 28 | { |
30 | (void) do_syslog(0,NULL,0); | 29 | (void) do_syslog(SYSLOG_ACTION_CLOSE, NULL, 0, SYSLOG_FROM_FILE); |
31 | return 0; | 30 | return 0; |
32 | } | 31 | } |
33 | 32 | ||
34 | static ssize_t kmsg_read(struct file *file, char __user *buf, | 33 | static ssize_t kmsg_read(struct file *file, char __user *buf, |
35 | size_t count, loff_t *ppos) | 34 | size_t count, loff_t *ppos) |
36 | { | 35 | { |
37 | if ((file->f_flags & O_NONBLOCK) && !do_syslog(9, NULL, 0)) | 36 | if ((file->f_flags & O_NONBLOCK) && |
37 | !do_syslog(SYSLOG_ACTION_SIZE_UNREAD, NULL, 0, SYSLOG_FROM_FILE)) | ||
38 | return -EAGAIN; | 38 | return -EAGAIN; |
39 | return do_syslog(2, buf, count); | 39 | return do_syslog(SYSLOG_ACTION_READ, buf, count, SYSLOG_FROM_FILE); |
40 | } | 40 | } |
41 | 41 | ||
42 | static unsigned int kmsg_poll(struct file *file, poll_table *wait) | 42 | static unsigned int kmsg_poll(struct file *file, poll_table *wait) |
43 | { | 43 | { |
44 | poll_wait(file, &log_wait, wait); | 44 | poll_wait(file, &log_wait, wait); |
45 | if (do_syslog(9, NULL, 0)) | 45 | if (do_syslog(SYSLOG_ACTION_SIZE_UNREAD, NULL, 0, SYSLOG_FROM_FILE)) |
46 | return POLLIN | POLLRDNORM; | 46 | return POLLIN | POLLRDNORM; |
47 | return 0; | 47 | return 0; |
48 | } | 48 | } |
diff --git a/fs/proc/nommu.c b/fs/proc/nommu.c index 9fe7d7ebe115..b1822dde55c2 100644 --- a/fs/proc/nommu.c +++ b/fs/proc/nommu.c | |||
@@ -21,7 +21,6 @@ | |||
21 | #include <linux/mmzone.h> | 21 | #include <linux/mmzone.h> |
22 | #include <linux/pagemap.h> | 22 | #include <linux/pagemap.h> |
23 | #include <linux/swap.h> | 23 | #include <linux/swap.h> |
24 | #include <linux/slab.h> | ||
25 | #include <linux/smp.h> | 24 | #include <linux/smp.h> |
26 | #include <linux/seq_file.h> | 25 | #include <linux/seq_file.h> |
27 | #include <linux/hugetlb.h> | 26 | #include <linux/hugetlb.h> |
diff --git a/fs/proc/page.c b/fs/proc/page.c index 5033ce0d254b..180cf5a0bd67 100644 --- a/fs/proc/page.c +++ b/fs/proc/page.c | |||
@@ -8,6 +8,7 @@ | |||
8 | #include <linux/proc_fs.h> | 8 | #include <linux/proc_fs.h> |
9 | #include <linux/seq_file.h> | 9 | #include <linux/seq_file.h> |
10 | #include <linux/hugetlb.h> | 10 | #include <linux/hugetlb.h> |
11 | #include <linux/kernel-page-flags.h> | ||
11 | #include <asm/uaccess.h> | 12 | #include <asm/uaccess.h> |
12 | #include "internal.h" | 13 | #include "internal.h" |
13 | 14 | ||
@@ -71,52 +72,12 @@ static const struct file_operations proc_kpagecount_operations = { | |||
71 | * physical page flags. | 72 | * physical page flags. |
72 | */ | 73 | */ |
73 | 74 | ||
74 | /* These macros are used to decouple internal flags from exported ones */ | ||
75 | |||
76 | #define KPF_LOCKED 0 | ||
77 | #define KPF_ERROR 1 | ||
78 | #define KPF_REFERENCED 2 | ||
79 | #define KPF_UPTODATE 3 | ||
80 | #define KPF_DIRTY 4 | ||
81 | #define KPF_LRU 5 | ||
82 | #define KPF_ACTIVE 6 | ||
83 | #define KPF_SLAB 7 | ||
84 | #define KPF_WRITEBACK 8 | ||
85 | #define KPF_RECLAIM 9 | ||
86 | #define KPF_BUDDY 10 | ||
87 | |||
88 | /* 11-20: new additions in 2.6.31 */ | ||
89 | #define KPF_MMAP 11 | ||
90 | #define KPF_ANON 12 | ||
91 | #define KPF_SWAPCACHE 13 | ||
92 | #define KPF_SWAPBACKED 14 | ||
93 | #define KPF_COMPOUND_HEAD 15 | ||
94 | #define KPF_COMPOUND_TAIL 16 | ||
95 | #define KPF_HUGE 17 | ||
96 | #define KPF_UNEVICTABLE 18 | ||
97 | #define KPF_HWPOISON 19 | ||
98 | #define KPF_NOPAGE 20 | ||
99 | |||
100 | #define KPF_KSM 21 | ||
101 | |||
102 | /* kernel hacking assistances | ||
103 | * WARNING: subject to change, never rely on them! | ||
104 | */ | ||
105 | #define KPF_RESERVED 32 | ||
106 | #define KPF_MLOCKED 33 | ||
107 | #define KPF_MAPPEDTODISK 34 | ||
108 | #define KPF_PRIVATE 35 | ||
109 | #define KPF_PRIVATE_2 36 | ||
110 | #define KPF_OWNER_PRIVATE 37 | ||
111 | #define KPF_ARCH 38 | ||
112 | #define KPF_UNCACHED 39 | ||
113 | |||
114 | static inline u64 kpf_copy_bit(u64 kflags, int ubit, int kbit) | 75 | static inline u64 kpf_copy_bit(u64 kflags, int ubit, int kbit) |
115 | { | 76 | { |
116 | return ((kflags >> kbit) & 1) << ubit; | 77 | return ((kflags >> kbit) & 1) << ubit; |
117 | } | 78 | } |
118 | 79 | ||
119 | static u64 get_uflags(struct page *page) | 80 | u64 stable_page_flags(struct page *page) |
120 | { | 81 | { |
121 | u64 k; | 82 | u64 k; |
122 | u64 u; | 83 | u64 u; |
@@ -219,7 +180,7 @@ static ssize_t kpageflags_read(struct file *file, char __user *buf, | |||
219 | else | 180 | else |
220 | ppage = NULL; | 181 | ppage = NULL; |
221 | 182 | ||
222 | if (put_user(get_uflags(ppage), out)) { | 183 | if (put_user(stable_page_flags(ppage), out)) { |
223 | ret = -EFAULT; | 184 | ret = -EFAULT; |
224 | break; | 185 | break; |
225 | } | 186 | } |
diff --git a/fs/proc/proc_devtree.c b/fs/proc/proc_devtree.c index 7ba79a54948c..ce94801f48ca 100644 --- a/fs/proc/proc_devtree.c +++ b/fs/proc/proc_devtree.c | |||
@@ -7,44 +7,50 @@ | |||
7 | #include <linux/init.h> | 7 | #include <linux/init.h> |
8 | #include <linux/time.h> | 8 | #include <linux/time.h> |
9 | #include <linux/proc_fs.h> | 9 | #include <linux/proc_fs.h> |
10 | #include <linux/seq_file.h> | ||
10 | #include <linux/stat.h> | 11 | #include <linux/stat.h> |
11 | #include <linux/string.h> | 12 | #include <linux/string.h> |
13 | #include <linux/of.h> | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/slab.h> | ||
12 | #include <asm/prom.h> | 16 | #include <asm/prom.h> |
13 | #include <asm/uaccess.h> | 17 | #include <asm/uaccess.h> |
14 | #include "internal.h" | 18 | #include "internal.h" |
15 | 19 | ||
16 | #ifndef HAVE_ARCH_DEVTREE_FIXUPS | ||
17 | static inline void set_node_proc_entry(struct device_node *np, | 20 | static inline void set_node_proc_entry(struct device_node *np, |
18 | struct proc_dir_entry *de) | 21 | struct proc_dir_entry *de) |
19 | { | 22 | { |
20 | } | 23 | #ifdef HAVE_ARCH_DEVTREE_FIXUPS |
24 | np->pde = de; | ||
21 | #endif | 25 | #endif |
26 | } | ||
22 | 27 | ||
23 | static struct proc_dir_entry *proc_device_tree; | 28 | static struct proc_dir_entry *proc_device_tree; |
24 | 29 | ||
25 | /* | 30 | /* |
26 | * Supply data on a read from /proc/device-tree/node/property. | 31 | * Supply data on a read from /proc/device-tree/node/property. |
27 | */ | 32 | */ |
28 | static int property_read_proc(char *page, char **start, off_t off, | 33 | static int property_proc_show(struct seq_file *m, void *v) |
29 | int count, int *eof, void *data) | ||
30 | { | 34 | { |
31 | struct property *pp = data; | 35 | struct property *pp = m->private; |
32 | int n; | ||
33 | 36 | ||
34 | if (off >= pp->length) { | 37 | seq_write(m, pp->value, pp->length); |
35 | *eof = 1; | 38 | return 0; |
36 | return 0; | ||
37 | } | ||
38 | n = pp->length - off; | ||
39 | if (n > count) | ||
40 | n = count; | ||
41 | else | ||
42 | *eof = 1; | ||
43 | memcpy(page, (char *)pp->value + off, n); | ||
44 | *start = page; | ||
45 | return n; | ||
46 | } | 39 | } |
47 | 40 | ||
41 | static int property_proc_open(struct inode *inode, struct file *file) | ||
42 | { | ||
43 | return single_open(file, property_proc_show, PDE(inode)->data); | ||
44 | } | ||
45 | |||
46 | static const struct file_operations property_proc_fops = { | ||
47 | .owner = THIS_MODULE, | ||
48 | .open = property_proc_open, | ||
49 | .read = seq_read, | ||
50 | .llseek = seq_lseek, | ||
51 | .release = single_release, | ||
52 | }; | ||
53 | |||
48 | /* | 54 | /* |
49 | * For a node with a name like "gc@10", we make symlinks called "gc" | 55 | * For a node with a name like "gc@10", we make symlinks called "gc" |
50 | * and "@10" to it. | 56 | * and "@10" to it. |
@@ -63,10 +69,9 @@ __proc_device_tree_add_prop(struct proc_dir_entry *de, struct property *pp, | |||
63 | * Unfortunately proc_register puts each new entry | 69 | * Unfortunately proc_register puts each new entry |
64 | * at the beginning of the list. So we rearrange them. | 70 | * at the beginning of the list. So we rearrange them. |
65 | */ | 71 | */ |
66 | ent = create_proc_read_entry(name, | 72 | ent = proc_create_data(name, |
67 | strncmp(name, "security-", 9) | 73 | strncmp(name, "security-", 9) ? S_IRUGO : S_IRUSR, |
68 | ? S_IRUGO : S_IRUSR, de, | 74 | de, &property_proc_fops, pp); |
69 | property_read_proc, pp); | ||
70 | if (ent == NULL) | 75 | if (ent == NULL) |
71 | return NULL; | 76 | return NULL; |
72 | 77 | ||
diff --git a/fs/proc/proc_net.c b/fs/proc/proc_net.c index 04d1270f1c38..9020ac15baaa 100644 --- a/fs/proc/proc_net.c +++ b/fs/proc/proc_net.c | |||
@@ -14,6 +14,7 @@ | |||
14 | #include <linux/time.h> | 14 | #include <linux/time.h> |
15 | #include <linux/proc_fs.h> | 15 | #include <linux/proc_fs.h> |
16 | #include <linux/stat.h> | 16 | #include <linux/stat.h> |
17 | #include <linux/slab.h> | ||
17 | #include <linux/init.h> | 18 | #include <linux/init.h> |
18 | #include <linux/sched.h> | 19 | #include <linux/sched.h> |
19 | #include <linux/module.h> | 20 | #include <linux/module.h> |
diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c index f667e8aeabdf..6ff9981f0a18 100644 --- a/fs/proc/proc_sysctl.c +++ b/fs/proc/proc_sysctl.c | |||
@@ -48,7 +48,7 @@ out: | |||
48 | static struct ctl_table *find_in_table(struct ctl_table *p, struct qstr *name) | 48 | static struct ctl_table *find_in_table(struct ctl_table *p, struct qstr *name) |
49 | { | 49 | { |
50 | int len; | 50 | int len; |
51 | for ( ; p->ctl_name || p->procname; p++) { | 51 | for ( ; p->procname; p++) { |
52 | 52 | ||
53 | if (!p->procname) | 53 | if (!p->procname) |
54 | continue; | 54 | continue; |
@@ -218,7 +218,7 @@ static int scan(struct ctl_table_header *head, ctl_table *table, | |||
218 | void *dirent, filldir_t filldir) | 218 | void *dirent, filldir_t filldir) |
219 | { | 219 | { |
220 | 220 | ||
221 | for (; table->ctl_name || table->procname; table++, (*pos)++) { | 221 | for (; table->procname; table++, (*pos)++) { |
222 | int res; | 222 | int res; |
223 | 223 | ||
224 | /* Can't do anything without a proc name */ | 224 | /* Can't do anything without a proc name */ |
diff --git a/fs/proc/root.c b/fs/proc/root.c index b080b791d9e3..757c069f2a65 100644 --- a/fs/proc/root.c +++ b/fs/proc/root.c | |||
@@ -220,9 +220,3 @@ void pid_ns_release_proc(struct pid_namespace *ns) | |||
220 | { | 220 | { |
221 | mntput(ns->proc_mnt); | 221 | mntput(ns->proc_mnt); |
222 | } | 222 | } |
223 | |||
224 | EXPORT_SYMBOL(proc_symlink); | ||
225 | EXPORT_SYMBOL(proc_mkdir); | ||
226 | EXPORT_SYMBOL(create_proc_entry); | ||
227 | EXPORT_SYMBOL(proc_create_data); | ||
228 | EXPORT_SYMBOL(remove_proc_entry); | ||
diff --git a/fs/proc/stat.c b/fs/proc/stat.c index 7cc726c6d70a..bf31b03fc275 100644 --- a/fs/proc/stat.c +++ b/fs/proc/stat.c | |||
@@ -1,6 +1,5 @@ | |||
1 | #include <linux/cpumask.h> | 1 | #include <linux/cpumask.h> |
2 | #include <linux/fs.h> | 2 | #include <linux/fs.h> |
3 | #include <linux/gfp.h> | ||
4 | #include <linux/init.h> | 3 | #include <linux/init.h> |
5 | #include <linux/interrupt.h> | 4 | #include <linux/interrupt.h> |
6 | #include <linux/kernel_stat.h> | 5 | #include <linux/kernel_stat.h> |
@@ -27,7 +26,7 @@ static int show_stat(struct seq_file *p, void *v) | |||
27 | int i, j; | 26 | int i, j; |
28 | unsigned long jif; | 27 | unsigned long jif; |
29 | cputime64_t user, nice, system, idle, iowait, irq, softirq, steal; | 28 | cputime64_t user, nice, system, idle, iowait, irq, softirq, steal; |
30 | cputime64_t guest; | 29 | cputime64_t guest, guest_nice; |
31 | u64 sum = 0; | 30 | u64 sum = 0; |
32 | u64 sum_softirq = 0; | 31 | u64 sum_softirq = 0; |
33 | unsigned int per_softirq_sums[NR_SOFTIRQS] = {0}; | 32 | unsigned int per_softirq_sums[NR_SOFTIRQS] = {0}; |
@@ -36,7 +35,7 @@ static int show_stat(struct seq_file *p, void *v) | |||
36 | 35 | ||
37 | user = nice = system = idle = iowait = | 36 | user = nice = system = idle = iowait = |
38 | irq = softirq = steal = cputime64_zero; | 37 | irq = softirq = steal = cputime64_zero; |
39 | guest = cputime64_zero; | 38 | guest = guest_nice = cputime64_zero; |
40 | getboottime(&boottime); | 39 | getboottime(&boottime); |
41 | jif = boottime.tv_sec; | 40 | jif = boottime.tv_sec; |
42 | 41 | ||
@@ -51,6 +50,8 @@ static int show_stat(struct seq_file *p, void *v) | |||
51 | softirq = cputime64_add(softirq, kstat_cpu(i).cpustat.softirq); | 50 | softirq = cputime64_add(softirq, kstat_cpu(i).cpustat.softirq); |
52 | steal = cputime64_add(steal, kstat_cpu(i).cpustat.steal); | 51 | steal = cputime64_add(steal, kstat_cpu(i).cpustat.steal); |
53 | guest = cputime64_add(guest, kstat_cpu(i).cpustat.guest); | 52 | guest = cputime64_add(guest, kstat_cpu(i).cpustat.guest); |
53 | guest_nice = cputime64_add(guest_nice, | ||
54 | kstat_cpu(i).cpustat.guest_nice); | ||
54 | for_each_irq_nr(j) { | 55 | for_each_irq_nr(j) { |
55 | sum += kstat_irqs_cpu(j, i); | 56 | sum += kstat_irqs_cpu(j, i); |
56 | } | 57 | } |
@@ -65,7 +66,8 @@ static int show_stat(struct seq_file *p, void *v) | |||
65 | } | 66 | } |
66 | sum += arch_irq_stat(); | 67 | sum += arch_irq_stat(); |
67 | 68 | ||
68 | seq_printf(p, "cpu %llu %llu %llu %llu %llu %llu %llu %llu %llu\n", | 69 | seq_printf(p, "cpu %llu %llu %llu %llu %llu %llu %llu %llu %llu " |
70 | "%llu\n", | ||
69 | (unsigned long long)cputime64_to_clock_t(user), | 71 | (unsigned long long)cputime64_to_clock_t(user), |
70 | (unsigned long long)cputime64_to_clock_t(nice), | 72 | (unsigned long long)cputime64_to_clock_t(nice), |
71 | (unsigned long long)cputime64_to_clock_t(system), | 73 | (unsigned long long)cputime64_to_clock_t(system), |
@@ -74,7 +76,8 @@ static int show_stat(struct seq_file *p, void *v) | |||
74 | (unsigned long long)cputime64_to_clock_t(irq), | 76 | (unsigned long long)cputime64_to_clock_t(irq), |
75 | (unsigned long long)cputime64_to_clock_t(softirq), | 77 | (unsigned long long)cputime64_to_clock_t(softirq), |
76 | (unsigned long long)cputime64_to_clock_t(steal), | 78 | (unsigned long long)cputime64_to_clock_t(steal), |
77 | (unsigned long long)cputime64_to_clock_t(guest)); | 79 | (unsigned long long)cputime64_to_clock_t(guest), |
80 | (unsigned long long)cputime64_to_clock_t(guest_nice)); | ||
78 | for_each_online_cpu(i) { | 81 | for_each_online_cpu(i) { |
79 | 82 | ||
80 | /* Copy values here to work around gcc-2.95.3, gcc-2.96 */ | 83 | /* Copy values here to work around gcc-2.95.3, gcc-2.96 */ |
@@ -88,8 +91,10 @@ static int show_stat(struct seq_file *p, void *v) | |||
88 | softirq = kstat_cpu(i).cpustat.softirq; | 91 | softirq = kstat_cpu(i).cpustat.softirq; |
89 | steal = kstat_cpu(i).cpustat.steal; | 92 | steal = kstat_cpu(i).cpustat.steal; |
90 | guest = kstat_cpu(i).cpustat.guest; | 93 | guest = kstat_cpu(i).cpustat.guest; |
94 | guest_nice = kstat_cpu(i).cpustat.guest_nice; | ||
91 | seq_printf(p, | 95 | seq_printf(p, |
92 | "cpu%d %llu %llu %llu %llu %llu %llu %llu %llu %llu\n", | 96 | "cpu%d %llu %llu %llu %llu %llu %llu %llu %llu %llu " |
97 | "%llu\n", | ||
93 | i, | 98 | i, |
94 | (unsigned long long)cputime64_to_clock_t(user), | 99 | (unsigned long long)cputime64_to_clock_t(user), |
95 | (unsigned long long)cputime64_to_clock_t(nice), | 100 | (unsigned long long)cputime64_to_clock_t(nice), |
@@ -99,7 +104,8 @@ static int show_stat(struct seq_file *p, void *v) | |||
99 | (unsigned long long)cputime64_to_clock_t(irq), | 104 | (unsigned long long)cputime64_to_clock_t(irq), |
100 | (unsigned long long)cputime64_to_clock_t(softirq), | 105 | (unsigned long long)cputime64_to_clock_t(softirq), |
101 | (unsigned long long)cputime64_to_clock_t(steal), | 106 | (unsigned long long)cputime64_to_clock_t(steal), |
102 | (unsigned long long)cputime64_to_clock_t(guest)); | 107 | (unsigned long long)cputime64_to_clock_t(guest), |
108 | (unsigned long long)cputime64_to_clock_t(guest_nice)); | ||
103 | } | 109 | } |
104 | seq_printf(p, "intr %llu", (unsigned long long)sum); | 110 | seq_printf(p, "intr %llu", (unsigned long long)sum); |
105 | 111 | ||
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c index 2a1bef9203c6..47f5b145f56e 100644 --- a/fs/proc/task_mmu.c +++ b/fs/proc/task_mmu.c | |||
@@ -4,6 +4,7 @@ | |||
4 | #include <linux/seq_file.h> | 4 | #include <linux/seq_file.h> |
5 | #include <linux/highmem.h> | 5 | #include <linux/highmem.h> |
6 | #include <linux/ptrace.h> | 6 | #include <linux/ptrace.h> |
7 | #include <linux/slab.h> | ||
7 | #include <linux/pagemap.h> | 8 | #include <linux/pagemap.h> |
8 | #include <linux/mempolicy.h> | 9 | #include <linux/mempolicy.h> |
9 | #include <linux/swap.h> | 10 | #include <linux/swap.h> |
@@ -16,7 +17,7 @@ | |||
16 | 17 | ||
17 | void task_mem(struct seq_file *m, struct mm_struct *mm) | 18 | void task_mem(struct seq_file *m, struct mm_struct *mm) |
18 | { | 19 | { |
19 | unsigned long data, text, lib; | 20 | unsigned long data, text, lib, swap; |
20 | unsigned long hiwater_vm, total_vm, hiwater_rss, total_rss; | 21 | unsigned long hiwater_vm, total_vm, hiwater_rss, total_rss; |
21 | 22 | ||
22 | /* | 23 | /* |
@@ -36,6 +37,7 @@ void task_mem(struct seq_file *m, struct mm_struct *mm) | |||
36 | data = mm->total_vm - mm->shared_vm - mm->stack_vm; | 37 | data = mm->total_vm - mm->shared_vm - mm->stack_vm; |
37 | text = (PAGE_ALIGN(mm->end_code) - (mm->start_code & PAGE_MASK)) >> 10; | 38 | text = (PAGE_ALIGN(mm->end_code) - (mm->start_code & PAGE_MASK)) >> 10; |
38 | lib = (mm->exec_vm << (PAGE_SHIFT-10)) - text; | 39 | lib = (mm->exec_vm << (PAGE_SHIFT-10)) - text; |
40 | swap = get_mm_counter(mm, MM_SWAPENTS); | ||
39 | seq_printf(m, | 41 | seq_printf(m, |
40 | "VmPeak:\t%8lu kB\n" | 42 | "VmPeak:\t%8lu kB\n" |
41 | "VmSize:\t%8lu kB\n" | 43 | "VmSize:\t%8lu kB\n" |
@@ -46,7 +48,8 @@ void task_mem(struct seq_file *m, struct mm_struct *mm) | |||
46 | "VmStk:\t%8lu kB\n" | 48 | "VmStk:\t%8lu kB\n" |
47 | "VmExe:\t%8lu kB\n" | 49 | "VmExe:\t%8lu kB\n" |
48 | "VmLib:\t%8lu kB\n" | 50 | "VmLib:\t%8lu kB\n" |
49 | "VmPTE:\t%8lu kB\n", | 51 | "VmPTE:\t%8lu kB\n" |
52 | "VmSwap:\t%8lu kB\n", | ||
50 | hiwater_vm << (PAGE_SHIFT-10), | 53 | hiwater_vm << (PAGE_SHIFT-10), |
51 | (total_vm - mm->reserved_vm) << (PAGE_SHIFT-10), | 54 | (total_vm - mm->reserved_vm) << (PAGE_SHIFT-10), |
52 | mm->locked_vm << (PAGE_SHIFT-10), | 55 | mm->locked_vm << (PAGE_SHIFT-10), |
@@ -54,7 +57,8 @@ void task_mem(struct seq_file *m, struct mm_struct *mm) | |||
54 | total_rss << (PAGE_SHIFT-10), | 57 | total_rss << (PAGE_SHIFT-10), |
55 | data << (PAGE_SHIFT-10), | 58 | data << (PAGE_SHIFT-10), |
56 | mm->stack_vm << (PAGE_SHIFT-10), text, lib, | 59 | mm->stack_vm << (PAGE_SHIFT-10), text, lib, |
57 | (PTRS_PER_PTE*sizeof(pte_t)*mm->nr_ptes) >> 10); | 60 | (PTRS_PER_PTE*sizeof(pte_t)*mm->nr_ptes) >> 10, |
61 | swap << (PAGE_SHIFT-10)); | ||
58 | } | 62 | } |
59 | 63 | ||
60 | unsigned long task_vsize(struct mm_struct *mm) | 64 | unsigned long task_vsize(struct mm_struct *mm) |
@@ -65,11 +69,11 @@ unsigned long task_vsize(struct mm_struct *mm) | |||
65 | int task_statm(struct mm_struct *mm, int *shared, int *text, | 69 | int task_statm(struct mm_struct *mm, int *shared, int *text, |
66 | int *data, int *resident) | 70 | int *data, int *resident) |
67 | { | 71 | { |
68 | *shared = get_mm_counter(mm, file_rss); | 72 | *shared = get_mm_counter(mm, MM_FILEPAGES); |
69 | *text = (PAGE_ALIGN(mm->end_code) - (mm->start_code & PAGE_MASK)) | 73 | *text = (PAGE_ALIGN(mm->end_code) - (mm->start_code & PAGE_MASK)) |
70 | >> PAGE_SHIFT; | 74 | >> PAGE_SHIFT; |
71 | *data = mm->total_vm - mm->shared_vm; | 75 | *data = mm->total_vm - mm->shared_vm; |
72 | *resident = *shared + get_mm_counter(mm, anon_rss); | 76 | *resident = *shared + get_mm_counter(mm, MM_ANONPAGES); |
73 | return mm->total_vm; | 77 | return mm->total_vm; |
74 | } | 78 | } |
75 | 79 | ||
@@ -243,25 +247,6 @@ static void show_map_vma(struct seq_file *m, struct vm_area_struct *vma) | |||
243 | } else if (vma->vm_start <= mm->start_stack && | 247 | } else if (vma->vm_start <= mm->start_stack && |
244 | vma->vm_end >= mm->start_stack) { | 248 | vma->vm_end >= mm->start_stack) { |
245 | name = "[stack]"; | 249 | name = "[stack]"; |
246 | } else { | ||
247 | unsigned long stack_start; | ||
248 | struct proc_maps_private *pmp; | ||
249 | |||
250 | pmp = m->private; | ||
251 | stack_start = pmp->task->stack_start; | ||
252 | |||
253 | if (vma->vm_start <= stack_start && | ||
254 | vma->vm_end >= stack_start) { | ||
255 | pad_len_spaces(m, len); | ||
256 | seq_printf(m, | ||
257 | "[threadstack:%08lx]", | ||
258 | #ifdef CONFIG_STACK_GROWSUP | ||
259 | vma->vm_end - stack_start | ||
260 | #else | ||
261 | stack_start - vma->vm_start | ||
262 | #endif | ||
263 | ); | ||
264 | } | ||
265 | } | 250 | } |
266 | } else { | 251 | } else { |
267 | name = "[vdso]"; | 252 | name = "[vdso]"; |
@@ -361,12 +346,11 @@ static int smaps_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end, | |||
361 | if (!pte_present(ptent)) | 346 | if (!pte_present(ptent)) |
362 | continue; | 347 | continue; |
363 | 348 | ||
364 | mss->resident += PAGE_SIZE; | ||
365 | |||
366 | page = vm_normal_page(vma, addr, ptent); | 349 | page = vm_normal_page(vma, addr, ptent); |
367 | if (!page) | 350 | if (!page) |
368 | continue; | 351 | continue; |
369 | 352 | ||
353 | mss->resident += PAGE_SIZE; | ||
370 | /* Accumulate the size in pages that have been accessed. */ | 354 | /* Accumulate the size in pages that have been accessed. */ |
371 | if (pte_young(ptent) || PageReferenced(page)) | 355 | if (pte_young(ptent) || PageReferenced(page)) |
372 | mss->referenced += PAGE_SIZE; | 356 | mss->referenced += PAGE_SIZE; |
@@ -404,6 +388,7 @@ static int show_smap(struct seq_file *m, void *v) | |||
404 | 388 | ||
405 | memset(&mss, 0, sizeof mss); | 389 | memset(&mss, 0, sizeof mss); |
406 | mss.vma = vma; | 390 | mss.vma = vma; |
391 | /* mmap_sem is held in m_start */ | ||
407 | if (vma->vm_mm && !is_vm_hugetlb_page(vma)) | 392 | if (vma->vm_mm && !is_vm_hugetlb_page(vma)) |
408 | walk_page_range(vma->vm_start, vma->vm_end, &smaps_walk); | 393 | walk_page_range(vma->vm_start, vma->vm_end, &smaps_walk); |
409 | 394 | ||
@@ -550,7 +535,8 @@ const struct file_operations proc_clear_refs_operations = { | |||
550 | }; | 535 | }; |
551 | 536 | ||
552 | struct pagemapread { | 537 | struct pagemapread { |
553 | u64 __user *out, *end; | 538 | int pos, len; |
539 | u64 *buffer; | ||
554 | }; | 540 | }; |
555 | 541 | ||
556 | #define PM_ENTRY_BYTES sizeof(u64) | 542 | #define PM_ENTRY_BYTES sizeof(u64) |
@@ -573,10 +559,8 @@ struct pagemapread { | |||
573 | static int add_to_pagemap(unsigned long addr, u64 pfn, | 559 | static int add_to_pagemap(unsigned long addr, u64 pfn, |
574 | struct pagemapread *pm) | 560 | struct pagemapread *pm) |
575 | { | 561 | { |
576 | if (put_user(pfn, pm->out)) | 562 | pm->buffer[pm->pos++] = pfn; |
577 | return -EFAULT; | 563 | if (pm->pos >= pm->len) |
578 | pm->out++; | ||
579 | if (pm->out >= pm->end) | ||
580 | return PM_END_OF_BUFFER; | 564 | return PM_END_OF_BUFFER; |
581 | return 0; | 565 | return 0; |
582 | } | 566 | } |
@@ -650,6 +634,37 @@ static int pagemap_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end, | |||
650 | return err; | 634 | return err; |
651 | } | 635 | } |
652 | 636 | ||
637 | static u64 huge_pte_to_pagemap_entry(pte_t pte, int offset) | ||
638 | { | ||
639 | u64 pme = 0; | ||
640 | if (pte_present(pte)) | ||
641 | pme = PM_PFRAME(pte_pfn(pte) + offset) | ||
642 | | PM_PSHIFT(PAGE_SHIFT) | PM_PRESENT; | ||
643 | return pme; | ||
644 | } | ||
645 | |||
646 | /* This function walks within one hugetlb entry in the single call */ | ||
647 | static int pagemap_hugetlb_range(pte_t *pte, unsigned long hmask, | ||
648 | unsigned long addr, unsigned long end, | ||
649 | struct mm_walk *walk) | ||
650 | { | ||
651 | struct pagemapread *pm = walk->private; | ||
652 | int err = 0; | ||
653 | u64 pfn; | ||
654 | |||
655 | for (; addr != end; addr += PAGE_SIZE) { | ||
656 | int offset = (addr & ~hmask) >> PAGE_SHIFT; | ||
657 | pfn = huge_pte_to_pagemap_entry(*pte, offset); | ||
658 | err = add_to_pagemap(addr, pfn, pm); | ||
659 | if (err) | ||
660 | return err; | ||
661 | } | ||
662 | |||
663 | cond_resched(); | ||
664 | |||
665 | return err; | ||
666 | } | ||
667 | |||
653 | /* | 668 | /* |
654 | * /proc/pid/pagemap - an array mapping virtual pages to pfns | 669 | * /proc/pid/pagemap - an array mapping virtual pages to pfns |
655 | * | 670 | * |
@@ -674,21 +689,20 @@ static int pagemap_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end, | |||
674 | * determine which areas of memory are actually mapped and llseek to | 689 | * determine which areas of memory are actually mapped and llseek to |
675 | * skip over unmapped regions. | 690 | * skip over unmapped regions. |
676 | */ | 691 | */ |
692 | #define PAGEMAP_WALK_SIZE (PMD_SIZE) | ||
677 | static ssize_t pagemap_read(struct file *file, char __user *buf, | 693 | static ssize_t pagemap_read(struct file *file, char __user *buf, |
678 | size_t count, loff_t *ppos) | 694 | size_t count, loff_t *ppos) |
679 | { | 695 | { |
680 | struct task_struct *task = get_proc_task(file->f_path.dentry->d_inode); | 696 | struct task_struct *task = get_proc_task(file->f_path.dentry->d_inode); |
681 | struct page **pages, *page; | ||
682 | unsigned long uaddr, uend; | ||
683 | struct mm_struct *mm; | 697 | struct mm_struct *mm; |
684 | struct pagemapread pm; | 698 | struct pagemapread pm; |
685 | int pagecount; | ||
686 | int ret = -ESRCH; | 699 | int ret = -ESRCH; |
687 | struct mm_walk pagemap_walk = {}; | 700 | struct mm_walk pagemap_walk = {}; |
688 | unsigned long src; | 701 | unsigned long src; |
689 | unsigned long svpfn; | 702 | unsigned long svpfn; |
690 | unsigned long start_vaddr; | 703 | unsigned long start_vaddr; |
691 | unsigned long end_vaddr; | 704 | unsigned long end_vaddr; |
705 | int copied = 0; | ||
692 | 706 | ||
693 | if (!task) | 707 | if (!task) |
694 | goto out; | 708 | goto out; |
@@ -711,37 +725,15 @@ static ssize_t pagemap_read(struct file *file, char __user *buf, | |||
711 | if (!mm) | 725 | if (!mm) |
712 | goto out_task; | 726 | goto out_task; |
713 | 727 | ||
714 | 728 | pm.len = PM_ENTRY_BYTES * (PAGEMAP_WALK_SIZE >> PAGE_SHIFT); | |
715 | uaddr = (unsigned long)buf & PAGE_MASK; | 729 | pm.buffer = kmalloc(pm.len, GFP_TEMPORARY); |
716 | uend = (unsigned long)(buf + count); | ||
717 | pagecount = (PAGE_ALIGN(uend) - uaddr) / PAGE_SIZE; | ||
718 | ret = 0; | ||
719 | if (pagecount == 0) | ||
720 | goto out_mm; | ||
721 | pages = kcalloc(pagecount, sizeof(struct page *), GFP_KERNEL); | ||
722 | ret = -ENOMEM; | 730 | ret = -ENOMEM; |
723 | if (!pages) | 731 | if (!pm.buffer) |
724 | goto out_mm; | 732 | goto out_mm; |
725 | 733 | ||
726 | down_read(¤t->mm->mmap_sem); | ||
727 | ret = get_user_pages(current, current->mm, uaddr, pagecount, | ||
728 | 1, 0, pages, NULL); | ||
729 | up_read(¤t->mm->mmap_sem); | ||
730 | |||
731 | if (ret < 0) | ||
732 | goto out_free; | ||
733 | |||
734 | if (ret != pagecount) { | ||
735 | pagecount = ret; | ||
736 | ret = -EFAULT; | ||
737 | goto out_pages; | ||
738 | } | ||
739 | |||
740 | pm.out = (u64 __user *)buf; | ||
741 | pm.end = (u64 __user *)(buf + count); | ||
742 | |||
743 | pagemap_walk.pmd_entry = pagemap_pte_range; | 734 | pagemap_walk.pmd_entry = pagemap_pte_range; |
744 | pagemap_walk.pte_hole = pagemap_pte_hole; | 735 | pagemap_walk.pte_hole = pagemap_pte_hole; |
736 | pagemap_walk.hugetlb_entry = pagemap_hugetlb_range; | ||
745 | pagemap_walk.mm = mm; | 737 | pagemap_walk.mm = mm; |
746 | pagemap_walk.private = ± | 738 | pagemap_walk.private = ± |
747 | 739 | ||
@@ -760,23 +752,36 @@ static ssize_t pagemap_read(struct file *file, char __user *buf, | |||
760 | * user buffer is tracked in "pm", and the walk | 752 | * user buffer is tracked in "pm", and the walk |
761 | * will stop when we hit the end of the buffer. | 753 | * will stop when we hit the end of the buffer. |
762 | */ | 754 | */ |
763 | ret = walk_page_range(start_vaddr, end_vaddr, &pagemap_walk); | 755 | ret = 0; |
764 | if (ret == PM_END_OF_BUFFER) | 756 | while (count && (start_vaddr < end_vaddr)) { |
765 | ret = 0; | 757 | int len; |
766 | /* don't need mmap_sem for these, but this looks cleaner */ | 758 | unsigned long end; |
767 | *ppos += (char __user *)pm.out - buf; | 759 | |
768 | if (!ret) | 760 | pm.pos = 0; |
769 | ret = (char __user *)pm.out - buf; | 761 | end = start_vaddr + PAGEMAP_WALK_SIZE; |
770 | 762 | /* overflow ? */ | |
771 | out_pages: | 763 | if (end < start_vaddr || end > end_vaddr) |
772 | for (; pagecount; pagecount--) { | 764 | end = end_vaddr; |
773 | page = pages[pagecount-1]; | 765 | down_read(&mm->mmap_sem); |
774 | if (!PageReserved(page)) | 766 | ret = walk_page_range(start_vaddr, end, &pagemap_walk); |
775 | SetPageDirty(page); | 767 | up_read(&mm->mmap_sem); |
776 | page_cache_release(page); | 768 | start_vaddr = end; |
769 | |||
770 | len = min(count, PM_ENTRY_BYTES * pm.pos); | ||
771 | if (copy_to_user(buf, pm.buffer, len)) { | ||
772 | ret = -EFAULT; | ||
773 | goto out_free; | ||
774 | } | ||
775 | copied += len; | ||
776 | buf += len; | ||
777 | count -= len; | ||
777 | } | 778 | } |
779 | *ppos += copied; | ||
780 | if (!ret || ret == PM_END_OF_BUFFER) | ||
781 | ret = copied; | ||
782 | |||
778 | out_free: | 783 | out_free: |
779 | kfree(pages); | 784 | kfree(pm.buffer); |
780 | out_mm: | 785 | out_mm: |
781 | mmput(mm); | 786 | mmput(mm); |
782 | out_task: | 787 | out_task: |
diff --git a/fs/proc/task_nommu.c b/fs/proc/task_nommu.c index 8f5c05d3dbd3..46d4b5d72bd3 100644 --- a/fs/proc/task_nommu.c +++ b/fs/proc/task_nommu.c | |||
@@ -5,6 +5,7 @@ | |||
5 | #include <linux/fs_struct.h> | 5 | #include <linux/fs_struct.h> |
6 | #include <linux/mount.h> | 6 | #include <linux/mount.h> |
7 | #include <linux/ptrace.h> | 7 | #include <linux/ptrace.h> |
8 | #include <linux/slab.h> | ||
8 | #include <linux/seq_file.h> | 9 | #include <linux/seq_file.h> |
9 | #include "internal.h" | 10 | #include "internal.h" |
10 | 11 | ||
@@ -110,9 +111,13 @@ int task_statm(struct mm_struct *mm, int *shared, int *text, | |||
110 | } | 111 | } |
111 | } | 112 | } |
112 | 113 | ||
113 | size += (*text = mm->end_code - mm->start_code); | 114 | *text = (PAGE_ALIGN(mm->end_code) - (mm->start_code & PAGE_MASK)) |
114 | size += (*data = mm->start_stack - mm->start_data); | 115 | >> PAGE_SHIFT; |
116 | *data = (PAGE_ALIGN(mm->start_stack) - (mm->start_data & PAGE_MASK)) | ||
117 | >> PAGE_SHIFT; | ||
115 | up_read(&mm->mmap_sem); | 118 | up_read(&mm->mmap_sem); |
119 | size >>= PAGE_SHIFT; | ||
120 | size += *text + *data; | ||
116 | *resident = size; | 121 | *resident = size; |
117 | return size; | 122 | return size; |
118 | } | 123 | } |
diff --git a/fs/proc/vmcore.c b/fs/proc/vmcore.c index 0872afa58d39..9fbc99ec799a 100644 --- a/fs/proc/vmcore.c +++ b/fs/proc/vmcore.c | |||
@@ -12,6 +12,7 @@ | |||
12 | #include <linux/user.h> | 12 | #include <linux/user.h> |
13 | #include <linux/elf.h> | 13 | #include <linux/elf.h> |
14 | #include <linux/elfcore.h> | 14 | #include <linux/elfcore.h> |
15 | #include <linux/slab.h> | ||
15 | #include <linux/highmem.h> | 16 | #include <linux/highmem.h> |
16 | #include <linux/bootmem.h> | 17 | #include <linux/bootmem.h> |
17 | #include <linux/init.h> | 18 | #include <linux/init.h> |