11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	linux/mm/mincore.c
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
42f77d107050abc14bc393b34bdb7b91cf670c250Linus Torvalds * Copyright (C) 1994-2006  Linus Torvalds
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The mincore() system call.
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/pagemap.h>
115a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/gfp.h>
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/mm.h>
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/mman.h>
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/syscalls.h>
1542da9cbd3eedde33a42acc2cb06f454814cf5de0Nick Piggin#include <linux/swap.h>
1642da9cbd3eedde33a42acc2cb06f454814cf5de0Nick Piggin#include <linux/swapops.h>
174f16fc107d9c9b8a72aa19b189a9216e90a7aaefNaoya Horiguchi#include <linux/hugetlb.h>
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/uaccess.h>
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/pgtable.h>
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22f488401076c5570130c018e573f450a9a6c43365Johannes Weinerstatic void mincore_hugetlb_page_range(struct vm_area_struct *vma,
2325ef0e50cca790370ad7838e3ad74db6a6a2d829Johannes Weiner				unsigned long addr, unsigned long end,
24f488401076c5570130c018e573f450a9a6c43365Johannes Weiner				unsigned char *vec)
25f488401076c5570130c018e573f450a9a6c43365Johannes Weiner{
26f488401076c5570130c018e573f450a9a6c43365Johannes Weiner#ifdef CONFIG_HUGETLB_PAGE
27f488401076c5570130c018e573f450a9a6c43365Johannes Weiner	struct hstate *h;
28f488401076c5570130c018e573f450a9a6c43365Johannes Weiner
29f488401076c5570130c018e573f450a9a6c43365Johannes Weiner	h = hstate_vma(vma);
30f488401076c5570130c018e573f450a9a6c43365Johannes Weiner	while (1) {
31f488401076c5570130c018e573f450a9a6c43365Johannes Weiner		unsigned char present;
32f488401076c5570130c018e573f450a9a6c43365Johannes Weiner		pte_t *ptep;
33f488401076c5570130c018e573f450a9a6c43365Johannes Weiner		/*
34f488401076c5570130c018e573f450a9a6c43365Johannes Weiner		 * Huge pages are always in RAM for now, but
35f488401076c5570130c018e573f450a9a6c43365Johannes Weiner		 * theoretically it needs to be checked.
36f488401076c5570130c018e573f450a9a6c43365Johannes Weiner		 */
37f488401076c5570130c018e573f450a9a6c43365Johannes Weiner		ptep = huge_pte_offset(current->mm,
38f488401076c5570130c018e573f450a9a6c43365Johannes Weiner				       addr & huge_page_mask(h));
39f488401076c5570130c018e573f450a9a6c43365Johannes Weiner		present = ptep && !huge_pte_none(huge_ptep_get(ptep));
40f488401076c5570130c018e573f450a9a6c43365Johannes Weiner		while (1) {
4125ef0e50cca790370ad7838e3ad74db6a6a2d829Johannes Weiner			*vec = present;
4225ef0e50cca790370ad7838e3ad74db6a6a2d829Johannes Weiner			vec++;
43f488401076c5570130c018e573f450a9a6c43365Johannes Weiner			addr += PAGE_SIZE;
4425ef0e50cca790370ad7838e3ad74db6a6a2d829Johannes Weiner			if (addr == end)
45f488401076c5570130c018e573f450a9a6c43365Johannes Weiner				return;
46f488401076c5570130c018e573f450a9a6c43365Johannes Weiner			/* check hugepage border */
47f488401076c5570130c018e573f450a9a6c43365Johannes Weiner			if (!(addr & ~huge_page_mask(h)))
48f488401076c5570130c018e573f450a9a6c43365Johannes Weiner				break;
49f488401076c5570130c018e573f450a9a6c43365Johannes Weiner		}
50f488401076c5570130c018e573f450a9a6c43365Johannes Weiner	}
51f488401076c5570130c018e573f450a9a6c43365Johannes Weiner#else
52f488401076c5570130c018e573f450a9a6c43365Johannes Weiner	BUG();
53f488401076c5570130c018e573f450a9a6c43365Johannes Weiner#endif
54f488401076c5570130c018e573f450a9a6c43365Johannes Weiner}
55f488401076c5570130c018e573f450a9a6c43365Johannes Weiner
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Later we can get more picky about what "in core" means precisely.
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * For now, simply check to see if the page is in the page cache,
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * and is up to date; i.e. that no page-in operation would be required
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * at this time if an application were to map and access this page.
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
6242da9cbd3eedde33a42acc2cb06f454814cf5de0Nick Pigginstatic unsigned char mincore_page(struct address_space *mapping, pgoff_t pgoff)
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char present = 0;
6542da9cbd3eedde33a42acc2cb06f454814cf5de0Nick Piggin	struct page *page;
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6742da9cbd3eedde33a42acc2cb06f454814cf5de0Nick Piggin	/*
6842da9cbd3eedde33a42acc2cb06f454814cf5de0Nick Piggin	 * When tmpfs swaps out a page from a file, any process mapping that
6942da9cbd3eedde33a42acc2cb06f454814cf5de0Nick Piggin	 * file will not get a swp_entry_t in its pte, but rather it is like
7042da9cbd3eedde33a42acc2cb06f454814cf5de0Nick Piggin	 * any other file mapping (ie. marked !present and faulted in with
713c18ddd160d1fcd46d1131d9ad6c594dd8e9af99Nick Piggin	 * tmpfs's .fault). So swapped out tmpfs mappings are tested here.
7242da9cbd3eedde33a42acc2cb06f454814cf5de0Nick Piggin	 */
7342da9cbd3eedde33a42acc2cb06f454814cf5de0Nick Piggin	page = find_get_page(mapping, pgoff);
7431475dd611209413bace21651a400afb91d0bd9dHugh Dickins#ifdef CONFIG_SWAP
758079b1c859c44f27d63da4951f5038a16589a563Hugh Dickins	/* shmem/tmpfs may return swap: account for swapcache page too. */
7631475dd611209413bace21651a400afb91d0bd9dHugh Dickins	if (radix_tree_exceptional_entry(page)) {
7731475dd611209413bace21651a400afb91d0bd9dHugh Dickins		swp_entry_t swap = radix_to_swp_entry(page);
7831475dd611209413bace21651a400afb91d0bd9dHugh Dickins		page = find_get_page(&swapper_space, swap.val);
7931475dd611209413bace21651a400afb91d0bd9dHugh Dickins	}
8031475dd611209413bace21651a400afb91d0bd9dHugh Dickins#endif
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (page) {
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		present = PageUptodate(page);
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		page_cache_release(page);
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return present;
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
89f488401076c5570130c018e573f450a9a6c43365Johannes Weinerstatic void mincore_unmapped_range(struct vm_area_struct *vma,
9025ef0e50cca790370ad7838e3ad74db6a6a2d829Johannes Weiner				unsigned long addr, unsigned long end,
91f488401076c5570130c018e573f450a9a6c43365Johannes Weiner				unsigned char *vec)
92f488401076c5570130c018e573f450a9a6c43365Johannes Weiner{
9325ef0e50cca790370ad7838e3ad74db6a6a2d829Johannes Weiner	unsigned long nr = (end - addr) >> PAGE_SHIFT;
94f488401076c5570130c018e573f450a9a6c43365Johannes Weiner	int i;
95f488401076c5570130c018e573f450a9a6c43365Johannes Weiner
96f488401076c5570130c018e573f450a9a6c43365Johannes Weiner	if (vma->vm_file) {
97f488401076c5570130c018e573f450a9a6c43365Johannes Weiner		pgoff_t pgoff;
98f488401076c5570130c018e573f450a9a6c43365Johannes Weiner
99f488401076c5570130c018e573f450a9a6c43365Johannes Weiner		pgoff = linear_page_index(vma, addr);
100f488401076c5570130c018e573f450a9a6c43365Johannes Weiner		for (i = 0; i < nr; i++, pgoff++)
101f488401076c5570130c018e573f450a9a6c43365Johannes Weiner			vec[i] = mincore_page(vma->vm_file->f_mapping, pgoff);
102f488401076c5570130c018e573f450a9a6c43365Johannes Weiner	} else {
103f488401076c5570130c018e573f450a9a6c43365Johannes Weiner		for (i = 0; i < nr; i++)
104f488401076c5570130c018e573f450a9a6c43365Johannes Weiner			vec[i] = 0;
105f488401076c5570130c018e573f450a9a6c43365Johannes Weiner	}
106f488401076c5570130c018e573f450a9a6c43365Johannes Weiner}
107f488401076c5570130c018e573f450a9a6c43365Johannes Weiner
108f488401076c5570130c018e573f450a9a6c43365Johannes Weinerstatic void mincore_pte_range(struct vm_area_struct *vma, pmd_t *pmd,
10925ef0e50cca790370ad7838e3ad74db6a6a2d829Johannes Weiner			unsigned long addr, unsigned long end,
110f488401076c5570130c018e573f450a9a6c43365Johannes Weiner			unsigned char *vec)
111f488401076c5570130c018e573f450a9a6c43365Johannes Weiner{
11225ef0e50cca790370ad7838e3ad74db6a6a2d829Johannes Weiner	unsigned long next;
113f488401076c5570130c018e573f450a9a6c43365Johannes Weiner	spinlock_t *ptl;
114f488401076c5570130c018e573f450a9a6c43365Johannes Weiner	pte_t *ptep;
115f488401076c5570130c018e573f450a9a6c43365Johannes Weiner
116f488401076c5570130c018e573f450a9a6c43365Johannes Weiner	ptep = pte_offset_map_lock(vma->vm_mm, pmd, addr, &ptl);
11725ef0e50cca790370ad7838e3ad74db6a6a2d829Johannes Weiner	do {
118f488401076c5570130c018e573f450a9a6c43365Johannes Weiner		pte_t pte = *ptep;
119f488401076c5570130c018e573f450a9a6c43365Johannes Weiner		pgoff_t pgoff;
120f488401076c5570130c018e573f450a9a6c43365Johannes Weiner
12125ef0e50cca790370ad7838e3ad74db6a6a2d829Johannes Weiner		next = addr + PAGE_SIZE;
122f488401076c5570130c018e573f450a9a6c43365Johannes Weiner		if (pte_none(pte))
12325ef0e50cca790370ad7838e3ad74db6a6a2d829Johannes Weiner			mincore_unmapped_range(vma, addr, next, vec);
124f488401076c5570130c018e573f450a9a6c43365Johannes Weiner		else if (pte_present(pte))
12525ef0e50cca790370ad7838e3ad74db6a6a2d829Johannes Weiner			*vec = 1;
126f488401076c5570130c018e573f450a9a6c43365Johannes Weiner		else if (pte_file(pte)) {
127f488401076c5570130c018e573f450a9a6c43365Johannes Weiner			pgoff = pte_to_pgoff(pte);
12825ef0e50cca790370ad7838e3ad74db6a6a2d829Johannes Weiner			*vec = mincore_page(vma->vm_file->f_mapping, pgoff);
129f488401076c5570130c018e573f450a9a6c43365Johannes Weiner		} else { /* pte is a swap entry */
130f488401076c5570130c018e573f450a9a6c43365Johannes Weiner			swp_entry_t entry = pte_to_swp_entry(pte);
131f488401076c5570130c018e573f450a9a6c43365Johannes Weiner
132f488401076c5570130c018e573f450a9a6c43365Johannes Weiner			if (is_migration_entry(entry)) {
133f488401076c5570130c018e573f450a9a6c43365Johannes Weiner				/* migration entries are always uptodate */
13425ef0e50cca790370ad7838e3ad74db6a6a2d829Johannes Weiner				*vec = 1;
135f488401076c5570130c018e573f450a9a6c43365Johannes Weiner			} else {
136f488401076c5570130c018e573f450a9a6c43365Johannes Weiner#ifdef CONFIG_SWAP
137f488401076c5570130c018e573f450a9a6c43365Johannes Weiner				pgoff = entry.val;
13825ef0e50cca790370ad7838e3ad74db6a6a2d829Johannes Weiner				*vec = mincore_page(&swapper_space, pgoff);
139f488401076c5570130c018e573f450a9a6c43365Johannes Weiner#else
140f488401076c5570130c018e573f450a9a6c43365Johannes Weiner				WARN_ON(1);
14125ef0e50cca790370ad7838e3ad74db6a6a2d829Johannes Weiner				*vec = 1;
142f488401076c5570130c018e573f450a9a6c43365Johannes Weiner#endif
143f488401076c5570130c018e573f450a9a6c43365Johannes Weiner			}
144f488401076c5570130c018e573f450a9a6c43365Johannes Weiner		}
14525ef0e50cca790370ad7838e3ad74db6a6a2d829Johannes Weiner		vec++;
14625ef0e50cca790370ad7838e3ad74db6a6a2d829Johannes Weiner	} while (ptep++, addr = next, addr != end);
147f488401076c5570130c018e573f450a9a6c43365Johannes Weiner	pte_unmap_unlock(ptep - 1, ptl);
148f488401076c5570130c018e573f450a9a6c43365Johannes Weiner}
149f488401076c5570130c018e573f450a9a6c43365Johannes Weiner
150e48293fd75b3aa67f43ad6e3d2ff397caa55d58bJohannes Weinerstatic void mincore_pmd_range(struct vm_area_struct *vma, pud_t *pud,
151e48293fd75b3aa67f43ad6e3d2ff397caa55d58bJohannes Weiner			unsigned long addr, unsigned long end,
152e48293fd75b3aa67f43ad6e3d2ff397caa55d58bJohannes Weiner			unsigned char *vec)
153e48293fd75b3aa67f43ad6e3d2ff397caa55d58bJohannes Weiner{
154e48293fd75b3aa67f43ad6e3d2ff397caa55d58bJohannes Weiner	unsigned long next;
155e48293fd75b3aa67f43ad6e3d2ff397caa55d58bJohannes Weiner	pmd_t *pmd;
156e48293fd75b3aa67f43ad6e3d2ff397caa55d58bJohannes Weiner
157e48293fd75b3aa67f43ad6e3d2ff397caa55d58bJohannes Weiner	pmd = pmd_offset(pud, addr);
158e48293fd75b3aa67f43ad6e3d2ff397caa55d58bJohannes Weiner	do {
159e48293fd75b3aa67f43ad6e3d2ff397caa55d58bJohannes Weiner		next = pmd_addr_end(addr, end);
1600ca1634d4143c3579273ca53b993df19f5c98e92Johannes Weiner		if (pmd_trans_huge(*pmd)) {
1610ca1634d4143c3579273ca53b993df19f5c98e92Johannes Weiner			if (mincore_huge_pmd(vma, pmd, addr, next, vec)) {
1620ca1634d4143c3579273ca53b993df19f5c98e92Johannes Weiner				vec += (next - addr) >> PAGE_SHIFT;
1630ca1634d4143c3579273ca53b993df19f5c98e92Johannes Weiner				continue;
1640ca1634d4143c3579273ca53b993df19f5c98e92Johannes Weiner			}
1650ca1634d4143c3579273ca53b993df19f5c98e92Johannes Weiner			/* fall through */
1660ca1634d4143c3579273ca53b993df19f5c98e92Johannes Weiner		}
167e48293fd75b3aa67f43ad6e3d2ff397caa55d58bJohannes Weiner		if (pmd_none_or_clear_bad(pmd))
168e48293fd75b3aa67f43ad6e3d2ff397caa55d58bJohannes Weiner			mincore_unmapped_range(vma, addr, next, vec);
169e48293fd75b3aa67f43ad6e3d2ff397caa55d58bJohannes Weiner		else
170e48293fd75b3aa67f43ad6e3d2ff397caa55d58bJohannes Weiner			mincore_pte_range(vma, pmd, addr, next, vec);
171e48293fd75b3aa67f43ad6e3d2ff397caa55d58bJohannes Weiner		vec += (next - addr) >> PAGE_SHIFT;
172e48293fd75b3aa67f43ad6e3d2ff397caa55d58bJohannes Weiner	} while (pmd++, addr = next, addr != end);
173e48293fd75b3aa67f43ad6e3d2ff397caa55d58bJohannes Weiner}
174e48293fd75b3aa67f43ad6e3d2ff397caa55d58bJohannes Weiner
175e48293fd75b3aa67f43ad6e3d2ff397caa55d58bJohannes Weinerstatic void mincore_pud_range(struct vm_area_struct *vma, pgd_t *pgd,
176e48293fd75b3aa67f43ad6e3d2ff397caa55d58bJohannes Weiner			unsigned long addr, unsigned long end,
177e48293fd75b3aa67f43ad6e3d2ff397caa55d58bJohannes Weiner			unsigned char *vec)
178e48293fd75b3aa67f43ad6e3d2ff397caa55d58bJohannes Weiner{
179e48293fd75b3aa67f43ad6e3d2ff397caa55d58bJohannes Weiner	unsigned long next;
180e48293fd75b3aa67f43ad6e3d2ff397caa55d58bJohannes Weiner	pud_t *pud;
181e48293fd75b3aa67f43ad6e3d2ff397caa55d58bJohannes Weiner
182e48293fd75b3aa67f43ad6e3d2ff397caa55d58bJohannes Weiner	pud = pud_offset(pgd, addr);
183e48293fd75b3aa67f43ad6e3d2ff397caa55d58bJohannes Weiner	do {
184e48293fd75b3aa67f43ad6e3d2ff397caa55d58bJohannes Weiner		next = pud_addr_end(addr, end);
185e48293fd75b3aa67f43ad6e3d2ff397caa55d58bJohannes Weiner		if (pud_none_or_clear_bad(pud))
186e48293fd75b3aa67f43ad6e3d2ff397caa55d58bJohannes Weiner			mincore_unmapped_range(vma, addr, next, vec);
187e48293fd75b3aa67f43ad6e3d2ff397caa55d58bJohannes Weiner		else
188e48293fd75b3aa67f43ad6e3d2ff397caa55d58bJohannes Weiner			mincore_pmd_range(vma, pud, addr, next, vec);
189e48293fd75b3aa67f43ad6e3d2ff397caa55d58bJohannes Weiner		vec += (next - addr) >> PAGE_SHIFT;
190e48293fd75b3aa67f43ad6e3d2ff397caa55d58bJohannes Weiner	} while (pud++, addr = next, addr != end);
191e48293fd75b3aa67f43ad6e3d2ff397caa55d58bJohannes Weiner}
192e48293fd75b3aa67f43ad6e3d2ff397caa55d58bJohannes Weiner
193e48293fd75b3aa67f43ad6e3d2ff397caa55d58bJohannes Weinerstatic void mincore_page_range(struct vm_area_struct *vma,
194e48293fd75b3aa67f43ad6e3d2ff397caa55d58bJohannes Weiner			unsigned long addr, unsigned long end,
195e48293fd75b3aa67f43ad6e3d2ff397caa55d58bJohannes Weiner			unsigned char *vec)
196e48293fd75b3aa67f43ad6e3d2ff397caa55d58bJohannes Weiner{
197e48293fd75b3aa67f43ad6e3d2ff397caa55d58bJohannes Weiner	unsigned long next;
198e48293fd75b3aa67f43ad6e3d2ff397caa55d58bJohannes Weiner	pgd_t *pgd;
199e48293fd75b3aa67f43ad6e3d2ff397caa55d58bJohannes Weiner
200e48293fd75b3aa67f43ad6e3d2ff397caa55d58bJohannes Weiner	pgd = pgd_offset(vma->vm_mm, addr);
201e48293fd75b3aa67f43ad6e3d2ff397caa55d58bJohannes Weiner	do {
202e48293fd75b3aa67f43ad6e3d2ff397caa55d58bJohannes Weiner		next = pgd_addr_end(addr, end);
203e48293fd75b3aa67f43ad6e3d2ff397caa55d58bJohannes Weiner		if (pgd_none_or_clear_bad(pgd))
204e48293fd75b3aa67f43ad6e3d2ff397caa55d58bJohannes Weiner			mincore_unmapped_range(vma, addr, next, vec);
205e48293fd75b3aa67f43ad6e3d2ff397caa55d58bJohannes Weiner		else
206e48293fd75b3aa67f43ad6e3d2ff397caa55d58bJohannes Weiner			mincore_pud_range(vma, pgd, addr, next, vec);
207e48293fd75b3aa67f43ad6e3d2ff397caa55d58bJohannes Weiner		vec += (next - addr) >> PAGE_SHIFT;
208e48293fd75b3aa67f43ad6e3d2ff397caa55d58bJohannes Weiner	} while (pgd++, addr = next, addr != end);
209e48293fd75b3aa67f43ad6e3d2ff397caa55d58bJohannes Weiner}
210e48293fd75b3aa67f43ad6e3d2ff397caa55d58bJohannes Weiner
2112f77d107050abc14bc393b34bdb7b91cf670c250Linus Torvalds/*
2122f77d107050abc14bc393b34bdb7b91cf670c250Linus Torvalds * Do a chunk of "sys_mincore()". We've already checked
2132f77d107050abc14bc393b34bdb7b91cf670c250Linus Torvalds * all the arguments, we hold the mmap semaphore: we should
2142f77d107050abc14bc393b34bdb7b91cf670c250Linus Torvalds * just return the amount of info we're asked for.
2152f77d107050abc14bc393b34bdb7b91cf670c250Linus Torvalds */
2166a60f1b3588aef6ddceaa14192df475d430cce45Johannes Weinerstatic long do_mincore(unsigned long addr, unsigned long pages, unsigned char *vec)
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2186a60f1b3588aef6ddceaa14192df475d430cce45Johannes Weiner	struct vm_area_struct *vma;
21925ef0e50cca790370ad7838e3ad74db6a6a2d829Johannes Weiner	unsigned long end;
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2216a60f1b3588aef6ddceaa14192df475d430cce45Johannes Weiner	vma = find_vma(current->mm, addr);
2224fb23e439ce09157d64b89a21061b9fc08f2b495Linus Torvalds	if (!vma || addr < vma->vm_start)
2234fb23e439ce09157d64b89a21061b9fc08f2b495Linus Torvalds		return -ENOMEM;
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
22525ef0e50cca790370ad7838e3ad74db6a6a2d829Johannes Weiner	end = min(vma->vm_end, addr + (pages << PAGE_SHIFT));
2266a60f1b3588aef6ddceaa14192df475d430cce45Johannes Weiner
2274f16fc107d9c9b8a72aa19b189a9216e90a7aaefNaoya Horiguchi	if (is_vm_hugetlb_page(vma)) {
22825ef0e50cca790370ad7838e3ad74db6a6a2d829Johannes Weiner		mincore_hugetlb_page_range(vma, addr, end, vec);
22925ef0e50cca790370ad7838e3ad74db6a6a2d829Johannes Weiner		return (end - addr) >> PAGE_SHIFT;
2304f16fc107d9c9b8a72aa19b189a9216e90a7aaefNaoya Horiguchi	}
2314f16fc107d9c9b8a72aa19b189a9216e90a7aaefNaoya Horiguchi
23225ef0e50cca790370ad7838e3ad74db6a6a2d829Johannes Weiner	end = pmd_addr_end(addr, end);
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
234e48293fd75b3aa67f43ad6e3d2ff397caa55d58bJohannes Weiner	if (is_vm_hugetlb_page(vma))
235e48293fd75b3aa67f43ad6e3d2ff397caa55d58bJohannes Weiner		mincore_hugetlb_page_range(vma, addr, end, vec);
236e48293fd75b3aa67f43ad6e3d2ff397caa55d58bJohannes Weiner	else
237e48293fd75b3aa67f43ad6e3d2ff397caa55d58bJohannes Weiner		mincore_page_range(vma, addr, end, vec);
23842da9cbd3eedde33a42acc2cb06f454814cf5de0Nick Piggin
23925ef0e50cca790370ad7838e3ad74db6a6a2d829Johannes Weiner	return (end - addr) >> PAGE_SHIFT;
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The mincore(2) system call.
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * mincore() returns the memory residency status of the pages in the
2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * current process's address space specified by [addr, addr + len).
2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The status is returned in a vector of bytes.  The least significant
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * bit of each byte is 1 if the referenced page is in memory, otherwise
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * it is zero.
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Because the status of a page can change after mincore() checks it
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * but before it returns to the application, the returned vector may
2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * contain stale information.  Only locked pages are guaranteed to
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * remain in memory.
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * return values:
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  zero    - success
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  -EFAULT - vec points to an illegal address
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  -EINVAL - addr is not a multiple of PAGE_CACHE_SIZE
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  -ENOMEM - Addresses in the range [addr, addr + len] are
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		invalid for the address space of this process, or
2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		specify one or more pages which are not currently
2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		mapped
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  -EAGAIN - A kernel resource was temporarily unavailable.
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
2663480b25743cb7404928d57efeaa3d085708b04c2Heiko CarstensSYSCALL_DEFINE3(mincore, unsigned long, start, size_t, len,
2673480b25743cb7404928d57efeaa3d085708b04c2Heiko Carstens		unsigned char __user *, vec)
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2692f77d107050abc14bc393b34bdb7b91cf670c250Linus Torvalds	long retval;
2702f77d107050abc14bc393b34bdb7b91cf670c250Linus Torvalds	unsigned long pages;
2712f77d107050abc14bc393b34bdb7b91cf670c250Linus Torvalds	unsigned char *tmp;
2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2732f77d107050abc14bc393b34bdb7b91cf670c250Linus Torvalds	/* Check the start address: needs to be page-aligned.. */
2742f77d107050abc14bc393b34bdb7b91cf670c250Linus Torvalds 	if (start & ~PAGE_CACHE_MASK)
2752f77d107050abc14bc393b34bdb7b91cf670c250Linus Torvalds		return -EINVAL;
2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2772f77d107050abc14bc393b34bdb7b91cf670c250Linus Torvalds	/* ..and we need to be passed a valid user-space range */
2782f77d107050abc14bc393b34bdb7b91cf670c250Linus Torvalds	if (!access_ok(VERIFY_READ, (void __user *) start, len))
2792f77d107050abc14bc393b34bdb7b91cf670c250Linus Torvalds		return -ENOMEM;
2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2812f77d107050abc14bc393b34bdb7b91cf670c250Linus Torvalds	/* This also avoids any overflows on PAGE_CACHE_ALIGN */
2822f77d107050abc14bc393b34bdb7b91cf670c250Linus Torvalds	pages = len >> PAGE_SHIFT;
2832f77d107050abc14bc393b34bdb7b91cf670c250Linus Torvalds	pages += (len & ~PAGE_MASK) != 0;
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2852f77d107050abc14bc393b34bdb7b91cf670c250Linus Torvalds	if (!access_ok(VERIFY_WRITE, vec, pages))
2862f77d107050abc14bc393b34bdb7b91cf670c250Linus Torvalds		return -EFAULT;
2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2882f77d107050abc14bc393b34bdb7b91cf670c250Linus Torvalds	tmp = (void *) __get_free_page(GFP_USER);
2892f77d107050abc14bc393b34bdb7b91cf670c250Linus Torvalds	if (!tmp)
2904fb23e439ce09157d64b89a21061b9fc08f2b495Linus Torvalds		return -EAGAIN;
2912f77d107050abc14bc393b34bdb7b91cf670c250Linus Torvalds
2922f77d107050abc14bc393b34bdb7b91cf670c250Linus Torvalds	retval = 0;
2932f77d107050abc14bc393b34bdb7b91cf670c250Linus Torvalds	while (pages) {
2942f77d107050abc14bc393b34bdb7b91cf670c250Linus Torvalds		/*
2952f77d107050abc14bc393b34bdb7b91cf670c250Linus Torvalds		 * Do at most PAGE_SIZE entries per iteration, due to
2962f77d107050abc14bc393b34bdb7b91cf670c250Linus Torvalds		 * the temporary buffer size.
2972f77d107050abc14bc393b34bdb7b91cf670c250Linus Torvalds		 */
2982f77d107050abc14bc393b34bdb7b91cf670c250Linus Torvalds		down_read(&current->mm->mmap_sem);
2996a60f1b3588aef6ddceaa14192df475d430cce45Johannes Weiner		retval = do_mincore(start, min(pages, PAGE_SIZE), tmp);
3002f77d107050abc14bc393b34bdb7b91cf670c250Linus Torvalds		up_read(&current->mm->mmap_sem);
3012f77d107050abc14bc393b34bdb7b91cf670c250Linus Torvalds
3022f77d107050abc14bc393b34bdb7b91cf670c250Linus Torvalds		if (retval <= 0)
3032f77d107050abc14bc393b34bdb7b91cf670c250Linus Torvalds			break;
3042f77d107050abc14bc393b34bdb7b91cf670c250Linus Torvalds		if (copy_to_user(vec, tmp, retval)) {
3052f77d107050abc14bc393b34bdb7b91cf670c250Linus Torvalds			retval = -EFAULT;
3062f77d107050abc14bc393b34bdb7b91cf670c250Linus Torvalds			break;
3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3082f77d107050abc14bc393b34bdb7b91cf670c250Linus Torvalds		pages -= retval;
3092f77d107050abc14bc393b34bdb7b91cf670c250Linus Torvalds		vec += retval;
3102f77d107050abc14bc393b34bdb7b91cf670c250Linus Torvalds		start += retval << PAGE_SHIFT;
3112f77d107050abc14bc393b34bdb7b91cf670c250Linus Torvalds		retval = 0;
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3132f77d107050abc14bc393b34bdb7b91cf670c250Linus Torvalds	free_page((unsigned long) tmp);
3142f77d107050abc14bc393b34bdb7b91cf670c250Linus Torvalds	return retval;
3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
316