aboutsummaryrefslogtreecommitdiffstats
path: root/fs/proc
diff options
context:
space:
mode:
authorIngo Molnar <mingo@elte.hu>2008-06-16 05:27:53 -0400
committerIngo Molnar <mingo@elte.hu>2008-06-16 05:27:53 -0400
commitc54f9da1c8ceee19436430afac0798a989eb886d (patch)
tree412f51c3f2641e4205b767cec95ce6107cd39d36 /fs/proc
parenta2eddfa95919a730e0e5ed17e9c303fe5ba249cd (diff)
parent066519068ad2fbe98c7f45552b1f592903a9c8c8 (diff)
Merge branch 'linus' into x86/irqstats
Diffstat (limited to 'fs/proc')
-rw-r--r--fs/proc/array.c2
-rw-r--r--fs/proc/base.c33
-rw-r--r--fs/proc/inode.c3
-rw-r--r--fs/proc/proc_misc.c8
-rw-r--r--fs/proc/task_mmu.c111
5 files changed, 96 insertions, 61 deletions
diff --git a/fs/proc/array.c b/fs/proc/array.c
index 9e3b8c33c24..797d775e035 100644
--- a/fs/proc/array.c
+++ b/fs/proc/array.c
@@ -288,7 +288,7 @@ static void render_cap_t(struct seq_file *m, const char *header,
288 seq_printf(m, "%s", header); 288 seq_printf(m, "%s", header);
289 CAP_FOR_EACH_U32(__capi) { 289 CAP_FOR_EACH_U32(__capi) {
290 seq_printf(m, "%08x", 290 seq_printf(m, "%08x",
291 a->cap[(_LINUX_CAPABILITY_U32S-1) - __capi]); 291 a->cap[(_KERNEL_CAPABILITY_U32S-1) - __capi]);
292 } 292 }
293 seq_printf(m, "\n"); 293 seq_printf(m, "\n");
294} 294}
diff --git a/fs/proc/base.c b/fs/proc/base.c
index c447e0743a3..3b455371e7f 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -127,6 +127,25 @@ struct pid_entry {
127 NULL, &proc_single_file_operations, \ 127 NULL, &proc_single_file_operations, \
128 { .proc_show = &proc_##OTYPE } ) 128 { .proc_show = &proc_##OTYPE } )
129 129
130/*
131 * Count the number of hardlinks for the pid_entry table, excluding the .
132 * and .. links.
133 */
134static unsigned int pid_entry_count_dirs(const struct pid_entry *entries,
135 unsigned int n)
136{
137 unsigned int i;
138 unsigned int count;
139
140 count = 0;
141 for (i = 0; i < n; ++i) {
142 if (S_ISDIR(entries[i].mode))
143 ++count;
144 }
145
146 return count;
147}
148
130int maps_protect; 149int maps_protect;
131EXPORT_SYMBOL(maps_protect); 150EXPORT_SYMBOL(maps_protect);
132 151
@@ -2585,10 +2604,9 @@ static struct dentry *proc_pid_instantiate(struct inode *dir,
2585 inode->i_op = &proc_tgid_base_inode_operations; 2604 inode->i_op = &proc_tgid_base_inode_operations;
2586 inode->i_fop = &proc_tgid_base_operations; 2605 inode->i_fop = &proc_tgid_base_operations;
2587 inode->i_flags|=S_IMMUTABLE; 2606 inode->i_flags|=S_IMMUTABLE;
2588 inode->i_nlink = 5; 2607
2589#ifdef CONFIG_SECURITY 2608 inode->i_nlink = 2 + pid_entry_count_dirs(tgid_base_stuff,
2590 inode->i_nlink += 1; 2609 ARRAY_SIZE(tgid_base_stuff));
2591#endif
2592 2610
2593 dentry->d_op = &pid_dentry_operations; 2611 dentry->d_op = &pid_dentry_operations;
2594 2612
@@ -2816,10 +2834,9 @@ static struct dentry *proc_task_instantiate(struct inode *dir,
2816 inode->i_op = &proc_tid_base_inode_operations; 2834 inode->i_op = &proc_tid_base_inode_operations;
2817 inode->i_fop = &proc_tid_base_operations; 2835 inode->i_fop = &proc_tid_base_operations;
2818 inode->i_flags|=S_IMMUTABLE; 2836 inode->i_flags|=S_IMMUTABLE;
2819 inode->i_nlink = 4; 2837
2820#ifdef CONFIG_SECURITY 2838 inode->i_nlink = 2 + pid_entry_count_dirs(tid_base_stuff,
2821 inode->i_nlink += 1; 2839 ARRAY_SIZE(tid_base_stuff));
2822#endif
2823 2840
2824 dentry->d_op = &pid_dentry_operations; 2841 dentry->d_op = &pid_dentry_operations;
2825 2842
diff --git a/fs/proc/inode.c b/fs/proc/inode.c
index 6f4e8dc97da..b08d1001791 100644
--- a/fs/proc/inode.c
+++ b/fs/proc/inode.c
@@ -425,7 +425,8 @@ struct inode *proc_get_inode(struct super_block *sb, unsigned int ino,
425 } 425 }
426 } 426 }
427 unlock_new_inode(inode); 427 unlock_new_inode(inode);
428 } 428 } else
429 module_put(de->owner);
429 return inode; 430 return inode;
430 431
431out_ino: 432out_ino:
diff --git a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c
index 903e617bec5..53cb3f89f2c 100644
--- a/fs/proc/proc_misc.c
+++ b/fs/proc/proc_misc.c
@@ -139,7 +139,7 @@ static int meminfo_read_proc(char *page, char **start, off_t off,
139#define K(x) ((x) << (PAGE_SHIFT - 10)) 139#define K(x) ((x) << (PAGE_SHIFT - 10))
140 si_meminfo(&i); 140 si_meminfo(&i);
141 si_swapinfo(&i); 141 si_swapinfo(&i);
142 committed = atomic_read(&vm_committed_space); 142 committed = atomic_long_read(&vm_committed_space);
143 allowed = ((totalram_pages - hugetlb_total_pages()) 143 allowed = ((totalram_pages - hugetlb_total_pages())
144 * sysctl_overcommit_ratio / 100) + total_swap_pages; 144 * sysctl_overcommit_ratio / 100) + total_swap_pages;
145 145
@@ -725,7 +725,7 @@ static ssize_t kpagecount_read(struct file *file, char __user *buf,
725 pfn = src / KPMSIZE; 725 pfn = src / KPMSIZE;
726 count = min_t(size_t, count, (max_pfn * KPMSIZE) - src); 726 count = min_t(size_t, count, (max_pfn * KPMSIZE) - src);
727 if (src & KPMMASK || count & KPMMASK) 727 if (src & KPMMASK || count & KPMMASK)
728 return -EIO; 728 return -EINVAL;
729 729
730 while (count > 0) { 730 while (count > 0) {
731 ppage = NULL; 731 ppage = NULL;
@@ -735,7 +735,7 @@ static ssize_t kpagecount_read(struct file *file, char __user *buf,
735 if (!ppage) 735 if (!ppage)
736 pcount = 0; 736 pcount = 0;
737 else 737 else
738 pcount = atomic_read(&ppage->_count); 738 pcount = page_mapcount(ppage);
739 739
740 if (put_user(pcount, out++)) { 740 if (put_user(pcount, out++)) {
741 ret = -EFAULT; 741 ret = -EFAULT;
@@ -791,7 +791,7 @@ static ssize_t kpageflags_read(struct file *file, char __user *buf,
791 pfn = src / KPMSIZE; 791 pfn = src / KPMSIZE;
792 count = min_t(unsigned long, count, (max_pfn * KPMSIZE) - src); 792 count = min_t(unsigned long, count, (max_pfn * KPMSIZE) - src);
793 if (src & KPMMASK || count & KPMMASK) 793 if (src & KPMMASK || count & KPMMASK)
794 return -EIO; 794 return -EINVAL;
795 795
796 while (count > 0) { 796 while (count > 0) {
797 ppage = NULL; 797 ppage = NULL;
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
index 88717c0f941..ab8ccc9d14f 100644
--- a/fs/proc/task_mmu.c
+++ b/fs/proc/task_mmu.c
@@ -315,9 +315,9 @@ struct mem_size_stats {
315}; 315};
316 316
317static int smaps_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end, 317static int smaps_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end,
318 void *private) 318 struct mm_walk *walk)
319{ 319{
320 struct mem_size_stats *mss = private; 320 struct mem_size_stats *mss = walk->private;
321 struct vm_area_struct *vma = mss->vma; 321 struct vm_area_struct *vma = mss->vma;
322 pte_t *pte, ptent; 322 pte_t *pte, ptent;
323 spinlock_t *ptl; 323 spinlock_t *ptl;
@@ -365,19 +365,21 @@ static int smaps_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end,
365 return 0; 365 return 0;
366} 366}
367 367
368static struct mm_walk smaps_walk = { .pmd_entry = smaps_pte_range };
369
370static int show_smap(struct seq_file *m, void *v) 368static int show_smap(struct seq_file *m, void *v)
371{ 369{
372 struct vm_area_struct *vma = v; 370 struct vm_area_struct *vma = v;
373 struct mem_size_stats mss; 371 struct mem_size_stats mss;
374 int ret; 372 int ret;
373 struct mm_walk smaps_walk = {
374 .pmd_entry = smaps_pte_range,
375 .mm = vma->vm_mm,
376 .private = &mss,
377 };
375 378
376 memset(&mss, 0, sizeof mss); 379 memset(&mss, 0, sizeof mss);
377 mss.vma = vma; 380 mss.vma = vma;
378 if (vma->vm_mm && !is_vm_hugetlb_page(vma)) 381 if (vma->vm_mm && !is_vm_hugetlb_page(vma))
379 walk_page_range(vma->vm_mm, vma->vm_start, vma->vm_end, 382 walk_page_range(vma->vm_start, vma->vm_end, &smaps_walk);
380 &smaps_walk, &mss);
381 383
382 ret = show_map(m, v); 384 ret = show_map(m, v);
383 if (ret) 385 if (ret)
@@ -426,9 +428,9 @@ const struct file_operations proc_smaps_operations = {
426}; 428};
427 429
428static int clear_refs_pte_range(pmd_t *pmd, unsigned long addr, 430static int clear_refs_pte_range(pmd_t *pmd, unsigned long addr,
429 unsigned long end, void *private) 431 unsigned long end, struct mm_walk *walk)
430{ 432{
431 struct vm_area_struct *vma = private; 433 struct vm_area_struct *vma = walk->private;
432 pte_t *pte, ptent; 434 pte_t *pte, ptent;
433 spinlock_t *ptl; 435 spinlock_t *ptl;
434 struct page *page; 436 struct page *page;
@@ -452,8 +454,6 @@ static int clear_refs_pte_range(pmd_t *pmd, unsigned long addr,
452 return 0; 454 return 0;
453} 455}
454 456
455static struct mm_walk clear_refs_walk = { .pmd_entry = clear_refs_pte_range };
456
457static ssize_t clear_refs_write(struct file *file, const char __user *buf, 457static ssize_t clear_refs_write(struct file *file, const char __user *buf,
458 size_t count, loff_t *ppos) 458 size_t count, loff_t *ppos)
459{ 459{
@@ -476,11 +476,17 @@ static ssize_t clear_refs_write(struct file *file, const char __user *buf,
476 return -ESRCH; 476 return -ESRCH;
477 mm = get_task_mm(task); 477 mm = get_task_mm(task);
478 if (mm) { 478 if (mm) {
479 static struct mm_walk clear_refs_walk;
480 memset(&clear_refs_walk, 0, sizeof(clear_refs_walk));
481 clear_refs_walk.pmd_entry = clear_refs_pte_range;
482 clear_refs_walk.mm = mm;
479 down_read(&mm->mmap_sem); 483 down_read(&mm->mmap_sem);
480 for (vma = mm->mmap; vma; vma = vma->vm_next) 484 for (vma = mm->mmap; vma; vma = vma->vm_next) {
485 clear_refs_walk.private = vma;
481 if (!is_vm_hugetlb_page(vma)) 486 if (!is_vm_hugetlb_page(vma))
482 walk_page_range(mm, vma->vm_start, vma->vm_end, 487 walk_page_range(vma->vm_start, vma->vm_end,
483 &clear_refs_walk, vma); 488 &clear_refs_walk);
489 }
484 flush_tlb_mm(mm); 490 flush_tlb_mm(mm);
485 up_read(&mm->mmap_sem); 491 up_read(&mm->mmap_sem);
486 mmput(mm); 492 mmput(mm);
@@ -496,7 +502,7 @@ const struct file_operations proc_clear_refs_operations = {
496}; 502};
497 503
498struct pagemapread { 504struct pagemapread {
499 char __user *out, *end; 505 u64 __user *out, *end;
500}; 506};
501 507
502#define PM_ENTRY_BYTES sizeof(u64) 508#define PM_ENTRY_BYTES sizeof(u64)
@@ -519,28 +525,18 @@ struct pagemapread {
519static int add_to_pagemap(unsigned long addr, u64 pfn, 525static int add_to_pagemap(unsigned long addr, u64 pfn,
520 struct pagemapread *pm) 526 struct pagemapread *pm)
521{ 527{
522 /*
523 * Make sure there's room in the buffer for an
524 * entire entry. Otherwise, only copy part of
525 * the pfn.
526 */
527 if (pm->out + PM_ENTRY_BYTES >= pm->end) {
528 if (copy_to_user(pm->out, &pfn, pm->end - pm->out))
529 return -EFAULT;
530 pm->out = pm->end;
531 return PM_END_OF_BUFFER;
532 }
533
534 if (put_user(pfn, pm->out)) 528 if (put_user(pfn, pm->out))
535 return -EFAULT; 529 return -EFAULT;
536 pm->out += PM_ENTRY_BYTES; 530 pm->out++;
531 if (pm->out >= pm->end)
532 return PM_END_OF_BUFFER;
537 return 0; 533 return 0;
538} 534}
539 535
540static int pagemap_pte_hole(unsigned long start, unsigned long end, 536static int pagemap_pte_hole(unsigned long start, unsigned long end,
541 void *private) 537 struct mm_walk *walk)
542{ 538{
543 struct pagemapread *pm = private; 539 struct pagemapread *pm = walk->private;
544 unsigned long addr; 540 unsigned long addr;
545 int err = 0; 541 int err = 0;
546 for (addr = start; addr < end; addr += PAGE_SIZE) { 542 for (addr = start; addr < end; addr += PAGE_SIZE) {
@@ -557,24 +553,45 @@ static u64 swap_pte_to_pagemap_entry(pte_t pte)
557 return swp_type(e) | (swp_offset(e) << MAX_SWAPFILES_SHIFT); 553 return swp_type(e) | (swp_offset(e) << MAX_SWAPFILES_SHIFT);
558} 554}
559 555
556static unsigned long pte_to_pagemap_entry(pte_t pte)
557{
558 unsigned long pme = 0;
559 if (is_swap_pte(pte))
560 pme = PM_PFRAME(swap_pte_to_pagemap_entry(pte))
561 | PM_PSHIFT(PAGE_SHIFT) | PM_SWAP;
562 else if (pte_present(pte))
563 pme = PM_PFRAME(pte_pfn(pte))
564 | PM_PSHIFT(PAGE_SHIFT) | PM_PRESENT;
565 return pme;
566}
567
560static int pagemap_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end, 568static int pagemap_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end,
561 void *private) 569 struct mm_walk *walk)
562{ 570{
563 struct pagemapread *pm = private; 571 struct vm_area_struct *vma;
572 struct pagemapread *pm = walk->private;
564 pte_t *pte; 573 pte_t *pte;
565 int err = 0; 574 int err = 0;
566 575
576 /* find the first VMA at or above 'addr' */
577 vma = find_vma(walk->mm, addr);
567 for (; addr != end; addr += PAGE_SIZE) { 578 for (; addr != end; addr += PAGE_SIZE) {
568 u64 pfn = PM_NOT_PRESENT; 579 u64 pfn = PM_NOT_PRESENT;
569 pte = pte_offset_map(pmd, addr); 580
570 if (is_swap_pte(*pte)) 581 /* check to see if we've left 'vma' behind
571 pfn = PM_PFRAME(swap_pte_to_pagemap_entry(*pte)) 582 * and need a new, higher one */
572 | PM_PSHIFT(PAGE_SHIFT) | PM_SWAP; 583 if (vma && (addr >= vma->vm_end))
573 else if (pte_present(*pte)) 584 vma = find_vma(walk->mm, addr);
574 pfn = PM_PFRAME(pte_pfn(*pte)) 585
575 | PM_PSHIFT(PAGE_SHIFT) | PM_PRESENT; 586 /* check that 'vma' actually covers this address,
576 /* unmap so we're not in atomic when we copy to userspace */ 587 * and that it isn't a huge page vma */
577 pte_unmap(pte); 588 if (vma && (vma->vm_start <= addr) &&
589 !is_vm_hugetlb_page(vma)) {
590 pte = pte_offset_map(pmd, addr);
591 pfn = pte_to_pagemap_entry(*pte);
592 /* unmap before userspace copy */
593 pte_unmap(pte);
594 }
578 err = add_to_pagemap(addr, pfn, pm); 595 err = add_to_pagemap(addr, pfn, pm);
579 if (err) 596 if (err)
580 return err; 597 return err;
@@ -634,7 +651,7 @@ static ssize_t pagemap_read(struct file *file, char __user *buf,
634 651
635 ret = -EINVAL; 652 ret = -EINVAL;
636 /* file position must be aligned */ 653 /* file position must be aligned */
637 if (*ppos % PM_ENTRY_BYTES) 654 if ((*ppos % PM_ENTRY_BYTES) || (count % PM_ENTRY_BYTES))
638 goto out_task; 655 goto out_task;
639 656
640 ret = 0; 657 ret = 0;
@@ -664,8 +681,8 @@ static ssize_t pagemap_read(struct file *file, char __user *buf,
664 goto out_pages; 681 goto out_pages;
665 } 682 }
666 683
667 pm.out = buf; 684 pm.out = (u64 *)buf;
668 pm.end = buf + count; 685 pm.end = (u64 *)(buf + count);
669 686
670 if (!ptrace_may_attach(task)) { 687 if (!ptrace_may_attach(task)) {
671 ret = -EIO; 688 ret = -EIO;
@@ -685,14 +702,14 @@ static ssize_t pagemap_read(struct file *file, char __user *buf,
685 * user buffer is tracked in "pm", and the walk 702 * user buffer is tracked in "pm", and the walk
686 * will stop when we hit the end of the buffer. 703 * will stop when we hit the end of the buffer.
687 */ 704 */
688 ret = walk_page_range(mm, start_vaddr, end_vaddr, 705 ret = walk_page_range(start_vaddr, end_vaddr,
689 &pagemap_walk, &pm); 706 &pagemap_walk);
690 if (ret == PM_END_OF_BUFFER) 707 if (ret == PM_END_OF_BUFFER)
691 ret = 0; 708 ret = 0;
692 /* don't need mmap_sem for these, but this looks cleaner */ 709 /* don't need mmap_sem for these, but this looks cleaner */
693 *ppos += pm.out - buf; 710 *ppos += (char *)pm.out - buf;
694 if (!ret) 711 if (!ret)
695 ret = pm.out - buf; 712 ret = (char *)pm.out - buf;
696 } 713 }
697 714
698out_pages: 715out_pages: