aboutsummaryrefslogtreecommitdiffstats
path: root/fs/proc/task_mmu.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/proc/task_mmu.c')
-rw-r--r--fs/proc/task_mmu.c68
1 files changed, 47 insertions, 21 deletions
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
index 49958cffbd8d..9dfb5ff24209 100644
--- a/fs/proc/task_mmu.c
+++ b/fs/proc/task_mmu.c
@@ -527,13 +527,21 @@ struct pagemapread {
527 char __user *out, *end; 527 char __user *out, *end;
528}; 528};
529 529
530#define PM_ENTRY_BYTES sizeof(u64) 530#define PM_ENTRY_BYTES sizeof(u64)
531#define PM_RESERVED_BITS 3 531#define PM_STATUS_BITS 3
532#define PM_RESERVED_OFFSET (64 - PM_RESERVED_BITS) 532#define PM_STATUS_OFFSET (64 - PM_STATUS_BITS)
533#define PM_RESERVED_MASK (((1LL<<PM_RESERVED_BITS)-1) << PM_RESERVED_OFFSET) 533#define PM_STATUS_MASK (((1LL << PM_STATUS_BITS) - 1) << PM_STATUS_OFFSET)
534#define PM_SPECIAL(nr) (((nr) << PM_RESERVED_OFFSET) | PM_RESERVED_MASK) 534#define PM_STATUS(nr) (((nr) << PM_STATUS_OFFSET) & PM_STATUS_MASK)
535#define PM_NOT_PRESENT PM_SPECIAL(1LL) 535#define PM_PSHIFT_BITS 6
536#define PM_SWAP PM_SPECIAL(2LL) 536#define PM_PSHIFT_OFFSET (PM_STATUS_OFFSET - PM_PSHIFT_BITS)
537#define PM_PSHIFT_MASK (((1LL << PM_PSHIFT_BITS) - 1) << PM_PSHIFT_OFFSET)
538#define PM_PSHIFT(x) (((u64) (x) << PM_PSHIFT_OFFSET) & PM_PSHIFT_MASK)
539#define PM_PFRAME_MASK ((1LL << PM_PSHIFT_OFFSET) - 1)
540#define PM_PFRAME(x) ((x) & PM_PFRAME_MASK)
541
542#define PM_PRESENT PM_STATUS(4LL)
543#define PM_SWAP PM_STATUS(2LL)
544#define PM_NOT_PRESENT PM_PSHIFT(PAGE_SHIFT)
537#define PM_END_OF_BUFFER 1 545#define PM_END_OF_BUFFER 1
538 546
539static int add_to_pagemap(unsigned long addr, u64 pfn, 547static int add_to_pagemap(unsigned long addr, u64 pfn,
@@ -574,7 +582,7 @@ static int pagemap_pte_hole(unsigned long start, unsigned long end,
574u64 swap_pte_to_pagemap_entry(pte_t pte) 582u64 swap_pte_to_pagemap_entry(pte_t pte)
575{ 583{
576 swp_entry_t e = pte_to_swp_entry(pte); 584 swp_entry_t e = pte_to_swp_entry(pte);
577 return PM_SWAP | swp_type(e) | (swp_offset(e) << MAX_SWAPFILES_SHIFT); 585 return swp_type(e) | (swp_offset(e) << MAX_SWAPFILES_SHIFT);
578} 586}
579 587
580static int pagemap_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end, 588static int pagemap_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end,
@@ -588,9 +596,11 @@ static int pagemap_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end,
588 u64 pfn = PM_NOT_PRESENT; 596 u64 pfn = PM_NOT_PRESENT;
589 pte = pte_offset_map(pmd, addr); 597 pte = pte_offset_map(pmd, addr);
590 if (is_swap_pte(*pte)) 598 if (is_swap_pte(*pte))
591 pfn = swap_pte_to_pagemap_entry(*pte); 599 pfn = PM_PFRAME(swap_pte_to_pagemap_entry(*pte))
600 | PM_PSHIFT(PAGE_SHIFT) | PM_SWAP;
592 else if (pte_present(*pte)) 601 else if (pte_present(*pte))
593 pfn = pte_pfn(*pte); 602 pfn = PM_PFRAME(pte_pfn(*pte))
603 | PM_PSHIFT(PAGE_SHIFT) | PM_PRESENT;
594 /* unmap so we're not in atomic when we copy to userspace */ 604 /* unmap so we're not in atomic when we copy to userspace */
595 pte_unmap(pte); 605 pte_unmap(pte);
596 err = add_to_pagemap(addr, pfn, pm); 606 err = add_to_pagemap(addr, pfn, pm);
@@ -611,12 +621,20 @@ static struct mm_walk pagemap_walk = {
611/* 621/*
612 * /proc/pid/pagemap - an array mapping virtual pages to pfns 622 * /proc/pid/pagemap - an array mapping virtual pages to pfns
613 * 623 *
614 * For each page in the address space, this file contains one 64-bit 624 * For each page in the address space, this file contains one 64-bit entry
615 * entry representing the corresponding physical page frame number 625 * consisting of the following:
616 * (PFN) if the page is present. If there is a swap entry for the 626 *
617 * physical page, then an encoding of the swap file number and the 627 * Bits 0-55 page frame number (PFN) if present
618 * page's offset into the swap file are returned. If no page is 628 * Bits 0-4 swap type if swapped
619 * present at all, PM_NOT_PRESENT is returned. This allows determining 629 * Bits 5-55 swap offset if swapped
630 * Bits 55-60 page shift (page size = 1<<page shift)
631 * Bit 61 reserved for future use
632 * Bit 62 page swapped
633 * Bit 63 page present
634 *
635 * If the page is not present but in swap, then the PFN contains an
636 * encoding of the swap file number and the page's offset into the
637 * swap. Unmapped pages return a null PFN. This allows determining
620 * precisely which pages are mapped (or in swap) and comparing mapped 638 * precisely which pages are mapped (or in swap) and comparing mapped
621 * pages between processes. 639 * pages between processes.
622 * 640 *
@@ -640,17 +658,17 @@ static ssize_t pagemap_read(struct file *file, char __user *buf,
640 658
641 ret = -EACCES; 659 ret = -EACCES;
642 if (!ptrace_may_attach(task)) 660 if (!ptrace_may_attach(task))
643 goto out; 661 goto out_task;
644 662
645 ret = -EINVAL; 663 ret = -EINVAL;
646 /* file position must be aligned */ 664 /* file position must be aligned */
647 if (*ppos % PM_ENTRY_BYTES) 665 if (*ppos % PM_ENTRY_BYTES)
648 goto out; 666 goto out_task;
649 667
650 ret = 0; 668 ret = 0;
651 mm = get_task_mm(task); 669 mm = get_task_mm(task);
652 if (!mm) 670 if (!mm)
653 goto out; 671 goto out_task;
654 672
655 ret = -ENOMEM; 673 ret = -ENOMEM;
656 uaddr = (unsigned long)buf & PAGE_MASK; 674 uaddr = (unsigned long)buf & PAGE_MASK;
@@ -658,7 +676,7 @@ static ssize_t pagemap_read(struct file *file, char __user *buf,
658 pagecount = (PAGE_ALIGN(uend) - uaddr) / PAGE_SIZE; 676 pagecount = (PAGE_ALIGN(uend) - uaddr) / PAGE_SIZE;
659 pages = kmalloc(pagecount * sizeof(struct page *), GFP_KERNEL); 677 pages = kmalloc(pagecount * sizeof(struct page *), GFP_KERNEL);
660 if (!pages) 678 if (!pages)
661 goto out_task; 679 goto out_mm;
662 680
663 down_read(&current->mm->mmap_sem); 681 down_read(&current->mm->mmap_sem);
664 ret = get_user_pages(current, current->mm, uaddr, pagecount, 682 ret = get_user_pages(current, current->mm, uaddr, pagecount,
@@ -668,6 +686,12 @@ static ssize_t pagemap_read(struct file *file, char __user *buf,
668 if (ret < 0) 686 if (ret < 0)
669 goto out_free; 687 goto out_free;
670 688
689 if (ret != pagecount) {
690 pagecount = ret;
691 ret = -EFAULT;
692 goto out_pages;
693 }
694
671 pm.out = buf; 695 pm.out = buf;
672 pm.end = buf + count; 696 pm.end = buf + count;
673 697
@@ -699,15 +723,17 @@ static ssize_t pagemap_read(struct file *file, char __user *buf,
699 ret = pm.out - buf; 723 ret = pm.out - buf;
700 } 724 }
701 725
726out_pages:
702 for (; pagecount; pagecount--) { 727 for (; pagecount; pagecount--) {
703 page = pages[pagecount-1]; 728 page = pages[pagecount-1];
704 if (!PageReserved(page)) 729 if (!PageReserved(page))
705 SetPageDirty(page); 730 SetPageDirty(page);
706 page_cache_release(page); 731 page_cache_release(page);
707 } 732 }
708 mmput(mm);
709out_free: 733out_free:
710 kfree(pages); 734 kfree(pages);
735out_mm:
736 mmput(mm);
711out_task: 737out_task:
712 put_task_struct(task); 738 put_task_struct(task);
713out: 739out: