1 /* 2 * linux/mm/fremap.c 3 * 4 * Explicit pagetable population and nonlinear (random) mappings support. 5 * 6 * started by Ingo Molnar, Copyright (C) 2002, 2003 7 */ 8 9 #include <linux/mm.h> 10 #include <linux/swap.h> 11 #include <linux/file.h> 12 #include <linux/mman.h> 13 #include <linux/pagemap.h> 14 #include <linux/swapops.h> 15 #include <linux/rmap.h> 16 #include <linux/module.h> 17 18 #include <asm/mmu_context.h> 19 #include <asm/cacheflush.h> 20 #include <asm/tlbflush.h> 21 22 static inline void zap_pte(struct mm_struct *mm, struct vm_area_struct *vma, 23 unsigned long addr, pte_t *ptep) 24 { 25 pte_t pte = *ptep; 26 27 if (pte_none(pte)) 28 return; 29 if (pte_present(pte)) { 30 unsigned long pfn = pte_pfn(pte); 31 32 flush_cache_page(vma, addr); 33 pte = ptep_clear_flush(vma, addr, ptep); 34 if (pfn_valid(pfn)) { 35 struct page *page = pfn_to_page(pfn); 36 if (!PageReserved(page)) { 37 if (pte_dirty(pte)) 38 set_page_dirty(page); 39 page_remove_rmap(page); 40 page_cache_release(page); 41 mm->rss--; 42 } 43 } 44 } else { 45 if (!pte_file(pte)) 46 free_swap_and_cache(pte_to_swp_entry(pte)); 47 pte_clear(ptep); 48 } 49 } 50 51 /* 52 * Install a file page to a given virtual memory address, release any 53 * previously existing mapping. 54 */ 55 int install_page(struct mm_struct *mm, struct vm_area_struct *vma, 56 unsigned long addr, struct page *page, pgprot_t prot) 57 { 58 struct inode *inode; 59 pgoff_t size; 60 int err = -ENOMEM; 61 pte_t *pte; 62 pgd_t *pgd; 63 pmd_t *pmd; 64 pte_t pte_val; 65 66 pgd = pgd_offset(mm, addr); 67 spin_lock(&mm->page_table_lock); 68 69 pmd = pmd_alloc(mm, pgd, addr); 70 if (!pmd) 71 goto err_unlock; 72 73 pte = pte_alloc_map(mm, pmd, addr); 74 if (!pte) 75 goto err_unlock; 76 77 /* 78 * This page may have been truncated. Tell the 79 * caller about it. 80 */ 81 err = -EINVAL; 82 inode = vma->vm_file->f_mapping->host; 83 size = (i_size_read(inode) + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; 84 if (!page->mapping || page->index >= size) 85 goto err_unlock; 86 87 zap_pte(mm, vma, addr, pte); 88 89 mm->rss++; 90 flush_icache_page(vma, page); 91 set_pte(pte, mk_pte(page, prot)); 92 page_add_file_rmap(page); 93 pte_val = *pte; 94 pte_unmap(pte); 95 update_mmu_cache(vma, addr, pte_val); 96 97 err = 0; 98 err_unlock: 99 spin_unlock(&mm->page_table_lock); 100 return err; 101 } 102 EXPORT_SYMBOL(install_page); 103 104 105 /* 106 * Install a file pte to a given virtual memory address, release any 107 * previously existing mapping. 108 */ 109 int install_file_pte(struct mm_struct *mm, struct vm_area_struct *vma, 110 unsigned long addr, unsigned long pgoff, pgprot_t prot) 111 { 112 int err = -ENOMEM; 113 pte_t *pte; 114 pgd_t *pgd; 115 pmd_t *pmd; 116 pte_t pte_val; 117 118 pgd = pgd_offset(mm, addr); 119 spin_lock(&mm->page_table_lock); 120 121 pmd = pmd_alloc(mm, pgd, addr); 122 if (!pmd) 123 goto err_unlock; 124 125 pte = pte_alloc_map(mm, pmd, addr); 126 if (!pte) 127 goto err_unlock; 128 129 zap_pte(mm, vma, addr, pte); 130 131 set_pte(pte, pgoff_to_pte(pgoff)); 132 pte_val = *pte; 133 pte_unmap(pte); 134 update_mmu_cache(vma, addr, pte_val); 135 spin_unlock(&mm->page_table_lock); 136 return 0; 137 138 err_unlock: 139 spin_unlock(&mm->page_table_lock); 140 return err; 141 } 142 143 144 /*** 145 * sys_remap_file_pages - remap arbitrary pages of a shared backing store 146 * file within an existing vma. 147 * @start: start of the remapped virtual memory range 148 * @size: size of the remapped virtual memory range 149 * @prot: new protection bits of the range 150 * @pgoff: to be mapped page of the backing store file 151 * @flags: 0 or MAP_NONBLOCKED - the later will cause no IO. 152 * 153 * this syscall works purely via pagetables, so it's the most efficient 154 * way to map the same (large) file into a given virtual window. Unlike 155 * mmap()/mremap() it does not create any new vmas. The new mappings are 156 * also safe across swapout. 157 * 158 * NOTE: the 'prot' parameter right now is ignored, and the vma's default 159 * protection is used. Arbitrary protections might be implemented in the 160 * future. 161 */ 162 asmlinkage long sys_remap_file_pages(unsigned long start, unsigned long size, 163 unsigned long __prot, unsigned long pgoff, unsigned long flags) 164 { 165 struct mm_struct *mm = current->mm; 166 struct address_space *mapping; 167 unsigned long end = start + size; 168 struct vm_area_struct *vma; 169 int err = -EINVAL; 170 int has_write_lock = 0; 171 172 if (__prot) 173 return err; 174 /* 175 * Sanitize the syscall parameters: 176 */ 177 start = start & PAGE_MASK; 178 size = size & PAGE_MASK; 179 180 /* Does the address range wrap, or is the span zero-sized? */ 181 if (start + size <= start) 182 return err; 183 184 /* Can we represent this offset inside this architecture's pte's? */ 185 #if PTE_FILE_MAX_BITS < BITS_PER_LONG 186 if (pgoff + (size >> PAGE_SHIFT) >= (1UL << PTE_FILE_MAX_BITS)) 187 return err; 188 #endif 189 190 /* We need down_write() to change vma->vm_flags. */ 191 down_read(&mm->mmap_sem); 192 retry: 193 vma = find_vma(mm, start); 194 195 /* 196 * Make sure the vma is shared, that it supports prefaulting, 197 * and that the remapped range is valid and fully within 198 * the single existing vma. vm_private_data is used as a 199 * swapout cursor in a VM_NONLINEAR vma (unless VM_RESERVED 200 * or VM_LOCKED, but VM_LOCKED could be revoked later on). 201 */ 202 if (vma && (vma->vm_flags & VM_SHARED) && 203 (!vma->vm_private_data || 204 (vma->vm_flags & (VM_NONLINEAR|VM_RESERVED))) && 205 vma->vm_ops && vma->vm_ops->populate && 206 end > start && start >= vma->vm_start && 207 end <= vma->vm_end) { 208 209 /* Must set VM_NONLINEAR before any pages are populated. */ 210 if (pgoff != linear_page_index(vma, start) && 211 !(vma->vm_flags & VM_NONLINEAR)) { 212 if (!has_write_lock) { 213 up_read(&mm->mmap_sem); 214 down_write(&mm->mmap_sem); 215 has_write_lock = 1; 216 goto retry; 217 } 218 mapping = vma->vm_file->f_mapping; 219 spin_lock(&mapping->i_mmap_lock); 220 flush_dcache_mmap_lock(mapping); 221 vma->vm_flags |= VM_NONLINEAR; 222 vma_prio_tree_remove(vma, &mapping->i_mmap); 223 vma_prio_tree_init(vma); 224 list_add_tail(&vma->shared.vm_set.list, 225 &mapping->i_mmap_nonlinear); 226 flush_dcache_mmap_unlock(mapping); 227 spin_unlock(&mapping->i_mmap_lock); 228 } 229 230 err = vma->vm_ops->populate(vma, start, size, 231 vma->vm_page_prot, 232 pgoff, flags & MAP_NONBLOCK); 233 234 /* 235 * We can't clear VM_NONLINEAR because we'd have to do 236 * it after ->populate completes, and that would prevent 237 * downgrading the lock. (Locks can't be upgraded). 238 */ 239 } 240 if (likely(!has_write_lock)) 241 up_read(&mm->mmap_sem); 242 else 243 up_write(&mm->mmap_sem); 244 245 return err; 246 } 247 248
This page was automatically generated by LXR 0.3.1. • Linux is a registered trademark of Linus Torvalds