diff options
-rw-r--r-- | fs/proc/task_mmu.c | 40 |
1 files changed, 22 insertions, 18 deletions
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c index ef6f6c62dfee..39d641292579 100644 --- a/fs/proc/task_mmu.c +++ b/fs/proc/task_mmu.c | |||
@@ -807,6 +807,7 @@ typedef struct { | |||
807 | struct pagemapread { | 807 | struct pagemapread { |
808 | int pos, len; | 808 | int pos, len; |
809 | pagemap_entry_t *buffer; | 809 | pagemap_entry_t *buffer; |
810 | bool v2; | ||
810 | }; | 811 | }; |
811 | 812 | ||
812 | #define PAGEMAP_WALK_SIZE (PMD_SIZE) | 813 | #define PAGEMAP_WALK_SIZE (PMD_SIZE) |
@@ -820,14 +821,16 @@ struct pagemapread { | |||
820 | #define PM_PSHIFT_BITS 6 | 821 | #define PM_PSHIFT_BITS 6 |
821 | #define PM_PSHIFT_OFFSET (PM_STATUS_OFFSET - PM_PSHIFT_BITS) | 822 | #define PM_PSHIFT_OFFSET (PM_STATUS_OFFSET - PM_PSHIFT_BITS) |
822 | #define PM_PSHIFT_MASK (((1LL << PM_PSHIFT_BITS) - 1) << PM_PSHIFT_OFFSET) | 823 | #define PM_PSHIFT_MASK (((1LL << PM_PSHIFT_BITS) - 1) << PM_PSHIFT_OFFSET) |
823 | #define PM_PSHIFT(x) (((u64) (x) << PM_PSHIFT_OFFSET) & PM_PSHIFT_MASK) | 824 | #define __PM_PSHIFT(x) (((u64) (x) << PM_PSHIFT_OFFSET) & PM_PSHIFT_MASK) |
824 | #define PM_PFRAME_MASK ((1LL << PM_PSHIFT_OFFSET) - 1) | 825 | #define PM_PFRAME_MASK ((1LL << PM_PSHIFT_OFFSET) - 1) |
825 | #define PM_PFRAME(x) ((x) & PM_PFRAME_MASK) | 826 | #define PM_PFRAME(x) ((x) & PM_PFRAME_MASK) |
827 | /* in "new" pagemap pshift bits are occupied with more status bits */ | ||
828 | #define PM_STATUS2(v2, x) (__PM_PSHIFT(v2 ? x : PAGE_SHIFT)) | ||
826 | 829 | ||
827 | #define PM_PRESENT PM_STATUS(4LL) | 830 | #define PM_PRESENT PM_STATUS(4LL) |
828 | #define PM_SWAP PM_STATUS(2LL) | 831 | #define PM_SWAP PM_STATUS(2LL) |
829 | #define PM_FILE PM_STATUS(1LL) | 832 | #define PM_FILE PM_STATUS(1LL) |
830 | #define PM_NOT_PRESENT PM_PSHIFT(PAGE_SHIFT) | 833 | #define PM_NOT_PRESENT(v2) PM_STATUS2(v2, 0) |
831 | #define PM_END_OF_BUFFER 1 | 834 | #define PM_END_OF_BUFFER 1 |
832 | 835 | ||
833 | static inline pagemap_entry_t make_pme(u64 val) | 836 | static inline pagemap_entry_t make_pme(u64 val) |
@@ -850,7 +853,7 @@ static int pagemap_pte_hole(unsigned long start, unsigned long end, | |||
850 | struct pagemapread *pm = walk->private; | 853 | struct pagemapread *pm = walk->private; |
851 | unsigned long addr; | 854 | unsigned long addr; |
852 | int err = 0; | 855 | int err = 0; |
853 | pagemap_entry_t pme = make_pme(PM_NOT_PRESENT); | 856 | pagemap_entry_t pme = make_pme(PM_NOT_PRESENT(pm->v2)); |
854 | 857 | ||
855 | for (addr = start; addr < end; addr += PAGE_SIZE) { | 858 | for (addr = start; addr < end; addr += PAGE_SIZE) { |
856 | err = add_to_pagemap(addr, &pme, pm); | 859 | err = add_to_pagemap(addr, &pme, pm); |
@@ -860,7 +863,7 @@ static int pagemap_pte_hole(unsigned long start, unsigned long end, | |||
860 | return err; | 863 | return err; |
861 | } | 864 | } |
862 | 865 | ||
863 | static void pte_to_pagemap_entry(pagemap_entry_t *pme, | 866 | static void pte_to_pagemap_entry(pagemap_entry_t *pme, struct pagemapread *pm, |
864 | struct vm_area_struct *vma, unsigned long addr, pte_t pte) | 867 | struct vm_area_struct *vma, unsigned long addr, pte_t pte) |
865 | { | 868 | { |
866 | u64 frame, flags; | 869 | u64 frame, flags; |
@@ -879,18 +882,18 @@ static void pte_to_pagemap_entry(pagemap_entry_t *pme, | |||
879 | if (is_migration_entry(entry)) | 882 | if (is_migration_entry(entry)) |
880 | page = migration_entry_to_page(entry); | 883 | page = migration_entry_to_page(entry); |
881 | } else { | 884 | } else { |
882 | *pme = make_pme(PM_NOT_PRESENT); | 885 | *pme = make_pme(PM_NOT_PRESENT(pm->v2)); |
883 | return; | 886 | return; |
884 | } | 887 | } |
885 | 888 | ||
886 | if (page && !PageAnon(page)) | 889 | if (page && !PageAnon(page)) |
887 | flags |= PM_FILE; | 890 | flags |= PM_FILE; |
888 | 891 | ||
889 | *pme = make_pme(PM_PFRAME(frame) | PM_PSHIFT(PAGE_SHIFT) | flags); | 892 | *pme = make_pme(PM_PFRAME(frame) | PM_STATUS2(pm->v2, 0) | flags); |
890 | } | 893 | } |
891 | 894 | ||
892 | #ifdef CONFIG_TRANSPARENT_HUGEPAGE | 895 | #ifdef CONFIG_TRANSPARENT_HUGEPAGE |
893 | static void thp_pmd_to_pagemap_entry(pagemap_entry_t *pme, | 896 | static void thp_pmd_to_pagemap_entry(pagemap_entry_t *pme, struct pagemapread *pm, |
894 | pmd_t pmd, int offset) | 897 | pmd_t pmd, int offset) |
895 | { | 898 | { |
896 | /* | 899 | /* |
@@ -900,12 +903,12 @@ static void thp_pmd_to_pagemap_entry(pagemap_entry_t *pme, | |||
900 | */ | 903 | */ |
901 | if (pmd_present(pmd)) | 904 | if (pmd_present(pmd)) |
902 | *pme = make_pme(PM_PFRAME(pmd_pfn(pmd) + offset) | 905 | *pme = make_pme(PM_PFRAME(pmd_pfn(pmd) + offset) |
903 | | PM_PSHIFT(PAGE_SHIFT) | PM_PRESENT); | 906 | | PM_STATUS2(pm->v2, 0) | PM_PRESENT); |
904 | else | 907 | else |
905 | *pme = make_pme(PM_NOT_PRESENT); | 908 | *pme = make_pme(PM_NOT_PRESENT(pm->v2)); |
906 | } | 909 | } |
907 | #else | 910 | #else |
908 | static inline void thp_pmd_to_pagemap_entry(pagemap_entry_t *pme, | 911 | static inline void thp_pmd_to_pagemap_entry(pagemap_entry_t *pme, struct pagemapread *pm, |
909 | pmd_t pmd, int offset) | 912 | pmd_t pmd, int offset) |
910 | { | 913 | { |
911 | } | 914 | } |
@@ -918,7 +921,7 @@ static int pagemap_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end, | |||
918 | struct pagemapread *pm = walk->private; | 921 | struct pagemapread *pm = walk->private; |
919 | pte_t *pte; | 922 | pte_t *pte; |
920 | int err = 0; | 923 | int err = 0; |
921 | pagemap_entry_t pme = make_pme(PM_NOT_PRESENT); | 924 | pagemap_entry_t pme = make_pme(PM_NOT_PRESENT(pm->v2)); |
922 | 925 | ||
923 | /* find the first VMA at or above 'addr' */ | 926 | /* find the first VMA at or above 'addr' */ |
924 | vma = find_vma(walk->mm, addr); | 927 | vma = find_vma(walk->mm, addr); |
@@ -928,7 +931,7 @@ static int pagemap_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end, | |||
928 | 931 | ||
929 | offset = (addr & ~PAGEMAP_WALK_MASK) >> | 932 | offset = (addr & ~PAGEMAP_WALK_MASK) >> |
930 | PAGE_SHIFT; | 933 | PAGE_SHIFT; |
931 | thp_pmd_to_pagemap_entry(&pme, *pmd, offset); | 934 | thp_pmd_to_pagemap_entry(&pme, pm, *pmd, offset); |
932 | err = add_to_pagemap(addr, &pme, pm); | 935 | err = add_to_pagemap(addr, &pme, pm); |
933 | if (err) | 936 | if (err) |
934 | break; | 937 | break; |
@@ -945,7 +948,7 @@ static int pagemap_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end, | |||
945 | * and need a new, higher one */ | 948 | * and need a new, higher one */ |
946 | if (vma && (addr >= vma->vm_end)) { | 949 | if (vma && (addr >= vma->vm_end)) { |
947 | vma = find_vma(walk->mm, addr); | 950 | vma = find_vma(walk->mm, addr); |
948 | pme = make_pme(PM_NOT_PRESENT); | 951 | pme = make_pme(PM_NOT_PRESENT(pm->v2)); |
949 | } | 952 | } |
950 | 953 | ||
951 | /* check that 'vma' actually covers this address, | 954 | /* check that 'vma' actually covers this address, |
@@ -953,7 +956,7 @@ static int pagemap_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end, | |||
953 | if (vma && (vma->vm_start <= addr) && | 956 | if (vma && (vma->vm_start <= addr) && |
954 | !is_vm_hugetlb_page(vma)) { | 957 | !is_vm_hugetlb_page(vma)) { |
955 | pte = pte_offset_map(pmd, addr); | 958 | pte = pte_offset_map(pmd, addr); |
956 | pte_to_pagemap_entry(&pme, vma, addr, *pte); | 959 | pte_to_pagemap_entry(&pme, pm, vma, addr, *pte); |
957 | /* unmap before userspace copy */ | 960 | /* unmap before userspace copy */ |
958 | pte_unmap(pte); | 961 | pte_unmap(pte); |
959 | } | 962 | } |
@@ -968,14 +971,14 @@ static int pagemap_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end, | |||
968 | } | 971 | } |
969 | 972 | ||
970 | #ifdef CONFIG_HUGETLB_PAGE | 973 | #ifdef CONFIG_HUGETLB_PAGE |
971 | static void huge_pte_to_pagemap_entry(pagemap_entry_t *pme, | 974 | static void huge_pte_to_pagemap_entry(pagemap_entry_t *pme, struct pagemapread *pm, |
972 | pte_t pte, int offset) | 975 | pte_t pte, int offset) |
973 | { | 976 | { |
974 | if (pte_present(pte)) | 977 | if (pte_present(pte)) |
975 | *pme = make_pme(PM_PFRAME(pte_pfn(pte) + offset) | 978 | *pme = make_pme(PM_PFRAME(pte_pfn(pte) + offset) |
976 | | PM_PSHIFT(PAGE_SHIFT) | PM_PRESENT); | 979 | | PM_STATUS2(pm->v2, 0) | PM_PRESENT); |
977 | else | 980 | else |
978 | *pme = make_pme(PM_NOT_PRESENT); | 981 | *pme = make_pme(PM_NOT_PRESENT(pm->v2)); |
979 | } | 982 | } |
980 | 983 | ||
981 | /* This function walks within one hugetlb entry in the single call */ | 984 | /* This function walks within one hugetlb entry in the single call */ |
@@ -989,7 +992,7 @@ static int pagemap_hugetlb_range(pte_t *pte, unsigned long hmask, | |||
989 | 992 | ||
990 | for (; addr != end; addr += PAGE_SIZE) { | 993 | for (; addr != end; addr += PAGE_SIZE) { |
991 | int offset = (addr & ~hmask) >> PAGE_SHIFT; | 994 | int offset = (addr & ~hmask) >> PAGE_SHIFT; |
992 | huge_pte_to_pagemap_entry(&pme, *pte, offset); | 995 | huge_pte_to_pagemap_entry(&pme, pm, *pte, offset); |
993 | err = add_to_pagemap(addr, &pme, pm); | 996 | err = add_to_pagemap(addr, &pme, pm); |
994 | if (err) | 997 | if (err) |
995 | return err; | 998 | return err; |
@@ -1051,6 +1054,7 @@ static ssize_t pagemap_read(struct file *file, char __user *buf, | |||
1051 | if (!count) | 1054 | if (!count) |
1052 | goto out_task; | 1055 | goto out_task; |
1053 | 1056 | ||
1057 | pm.v2 = false; | ||
1054 | pm.len = PM_ENTRY_BYTES * (PAGEMAP_WALK_SIZE >> PAGE_SHIFT); | 1058 | pm.len = PM_ENTRY_BYTES * (PAGEMAP_WALK_SIZE >> PAGE_SHIFT); |
1055 | pm.buffer = kmalloc(pm.len, GFP_TEMPORARY); | 1059 | pm.buffer = kmalloc(pm.len, GFP_TEMPORARY); |
1056 | ret = -ENOMEM; | 1060 | ret = -ENOMEM; |