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(¤t->mm->mmap_sem); 2996a60f1b3588aef6ddceaa14192df475d430cce45Johannes Weiner retval = do_mincore(start, min(pages, PAGE_SIZE), tmp); 3002f77d107050abc14bc393b34bdb7b91cf670c250Linus Torvalds up_read(¤t->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