aboutsummaryrefslogtreecommitdiffstats
path: root/mm/mincore.c
diff options
context:
space:
mode:
Diffstat (limited to 'mm/mincore.c')
-rw-r--r--mm/mincore.c94
1 files changed, 81 insertions, 13 deletions
diff --git a/mm/mincore.c b/mm/mincore.c
index f0f91461a9f4..218099b5ed31 100644
--- a/mm/mincore.c
+++ b/mm/mincore.c
@@ -42,14 +42,72 @@ static int mincore_hugetlb(pte_t *pte, unsigned long hmask, unsigned long addr,
42 return 0; 42 return 0;
43} 43}
44 44
45static int mincore_unmapped_range(unsigned long addr, unsigned long end, 45/*
46 struct mm_walk *walk) 46 * Later we can get more picky about what "in core" means precisely.
47 * For now, simply check to see if the page is in the page cache,
48 * and is up to date; i.e. that no page-in operation would be required
49 * at this time if an application were to map and access this page.
50 */
51static unsigned char mincore_page(struct address_space *mapping, pgoff_t pgoff)
52{
53 unsigned char present = 0;
54 struct page *page;
55
56 /*
57 * When tmpfs swaps out a page from a file, any process mapping that
58 * file will not get a swp_entry_t in its pte, but rather it is like
59 * any other file mapping (ie. marked !present and faulted in with
60 * tmpfs's .fault). So swapped out tmpfs mappings are tested here.
61 */
62#ifdef CONFIG_SWAP
63 if (shmem_mapping(mapping)) {
64 page = find_get_entry(mapping, pgoff);
65 /*
66 * shmem/tmpfs may return swap: account for swapcache
67 * page too.
68 */
69 if (xa_is_value(page)) {
70 swp_entry_t swp = radix_to_swp_entry(page);
71 page = find_get_page(swap_address_space(swp),
72 swp_offset(swp));
73 }
74 } else
75 page = find_get_page(mapping, pgoff);
76#else
77 page = find_get_page(mapping, pgoff);
78#endif
79 if (page) {
80 present = PageUptodate(page);
81 put_page(page);
82 }
83
84 return present;
85}
86
87static int __mincore_unmapped_range(unsigned long addr, unsigned long end,
88 struct vm_area_struct *vma, unsigned char *vec)
47{ 89{
48 unsigned char *vec = walk->private;
49 unsigned long nr = (end - addr) >> PAGE_SHIFT; 90 unsigned long nr = (end - addr) >> PAGE_SHIFT;
91 int i;
50 92
51 memset(vec, 0, nr); 93 if (vma->vm_file) {
52 walk->private += nr; 94 pgoff_t pgoff;
95
96 pgoff = linear_page_index(vma, addr);
97 for (i = 0; i < nr; i++, pgoff++)
98 vec[i] = mincore_page(vma->vm_file->f_mapping, pgoff);
99 } else {
100 for (i = 0; i < nr; i++)
101 vec[i] = 0;
102 }
103 return nr;
104}
105
106static int mincore_unmapped_range(unsigned long addr, unsigned long end,
107 struct mm_walk *walk)
108{
109 walk->private += __mincore_unmapped_range(addr, end,
110 walk->vma, walk->private);
53 return 0; 111 return 0;
54} 112}
55 113
@@ -69,9 +127,8 @@ static int mincore_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end,
69 goto out; 127 goto out;
70 } 128 }
71 129
72 /* We'll consider a THP page under construction to be there */
73 if (pmd_trans_unstable(pmd)) { 130 if (pmd_trans_unstable(pmd)) {
74 memset(vec, 1, nr); 131 __mincore_unmapped_range(addr, end, vma, vec);
75 goto out; 132 goto out;
76 } 133 }
77 134
@@ -80,17 +137,28 @@ static int mincore_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end,
80 pte_t pte = *ptep; 137 pte_t pte = *ptep;
81 138
82 if (pte_none(pte)) 139 if (pte_none(pte))
83 *vec = 0; 140 __mincore_unmapped_range(addr, addr + PAGE_SIZE,
141 vma, vec);
84 else if (pte_present(pte)) 142 else if (pte_present(pte))
85 *vec = 1; 143 *vec = 1;
86 else { /* pte is a swap entry */ 144 else { /* pte is a swap entry */
87 swp_entry_t entry = pte_to_swp_entry(pte); 145 swp_entry_t entry = pte_to_swp_entry(pte);
88 146
89 /* 147 if (non_swap_entry(entry)) {
90 * migration or hwpoison entries are always 148 /*
91 * uptodate 149 * migration or hwpoison entries are always
92 */ 150 * uptodate
93 *vec = !!non_swap_entry(entry); 151 */
152 *vec = 1;
153 } else {
154#ifdef CONFIG_SWAP
155 *vec = mincore_page(swap_address_space(entry),
156 swp_offset(entry));
157#else
158 WARN_ON(1);
159 *vec = 1;
160#endif
161 }
94 } 162 }
95 vec++; 163 vec++;
96 } 164 }