diff options
Diffstat (limited to 'mm/mincore.c')
| -rw-r--r-- | mm/mincore.c | 94 |
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 | ||
| 45 | static 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 | */ | ||
| 51 | static 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 | |||
| 87 | static 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 | |||
| 106 | static 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 | } |
