Commit b1d0e4f535e10775cffde922208b49629169aeaa
Committed by
Linus Torvalds
1 parent
6a306e8b4c
Exists in
master
and in
4 other branches
mm: special mapping nopage
Convert special mapping install from nopage to fault. Because the "vm_file" is NULL for the special mapping, the generic VM code has messed up "vm_pgoff" thinking that it's an anonymous mapping and the offset does't matter. For that reason, we need to undo the vm_pgoff offset that got added into vmf->pgoff. [ We _really_ should clean that up - either by making this whole special mapping code just use a real file entry rather than that ugly array of "struct page" pointers, or by just making the VM code realize that even if vm_file is NULL it may not be a regular anonymous mmap. - Linus ] Signed-off-by: Nick Piggin <npiggin@suse.de> Cc: linux-mm@kvack.org Cc: linux-kernel@vger.kernel.org Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Showing 1 changed file with 16 additions and 9 deletions Side-by-side Diff
mm/mmap.c
... | ... | @@ -2165,24 +2165,31 @@ |
2165 | 2165 | } |
2166 | 2166 | |
2167 | 2167 | |
2168 | -static struct page *special_mapping_nopage(struct vm_area_struct *vma, | |
2169 | - unsigned long address, int *type) | |
2168 | +static int special_mapping_fault(struct vm_area_struct *vma, | |
2169 | + struct vm_fault *vmf) | |
2170 | 2170 | { |
2171 | + pgoff_t pgoff; | |
2171 | 2172 | struct page **pages; |
2172 | 2173 | |
2173 | - BUG_ON(address < vma->vm_start || address >= vma->vm_end); | |
2174 | + /* | |
2175 | + * special mappings have no vm_file, and in that case, the mm | |
2176 | + * uses vm_pgoff internally. So we have to subtract it from here. | |
2177 | + * We are allowed to do this because we are the mm; do not copy | |
2178 | + * this code into drivers! | |
2179 | + */ | |
2180 | + pgoff = vmf->pgoff - vma->vm_pgoff; | |
2174 | 2181 | |
2175 | - address -= vma->vm_start; | |
2176 | - for (pages = vma->vm_private_data; address > 0 && *pages; ++pages) | |
2177 | - address -= PAGE_SIZE; | |
2182 | + for (pages = vma->vm_private_data; pgoff && *pages; ++pages) | |
2183 | + pgoff--; | |
2178 | 2184 | |
2179 | 2185 | if (*pages) { |
2180 | 2186 | struct page *page = *pages; |
2181 | 2187 | get_page(page); |
2182 | - return page; | |
2188 | + vmf->page = page; | |
2189 | + return 0; | |
2183 | 2190 | } |
2184 | 2191 | |
2185 | - return NOPAGE_SIGBUS; | |
2192 | + return VM_FAULT_SIGBUS; | |
2186 | 2193 | } |
2187 | 2194 | |
2188 | 2195 | /* |
... | ... | @@ -2194,7 +2201,7 @@ |
2194 | 2201 | |
2195 | 2202 | static struct vm_operations_struct special_mapping_vmops = { |
2196 | 2203 | .close = special_mapping_close, |
2197 | - .nopage = special_mapping_nopage, | |
2204 | + .fault = special_mapping_fault, | |
2198 | 2205 | }; |
2199 | 2206 | |
2200 | 2207 | /* |