diff options
author | Nick Piggin <npiggin@suse.de> | 2008-02-08 19:15:19 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2008-02-08 21:57:39 -0500 |
commit | b1d0e4f535e10775cffde922208b49629169aeaa (patch) | |
tree | c5fa68fb25ffd2485da5de236fcf2b67d9df3dfd | |
parent | 6a306e8b4c81a1c1f538e390d92bfe80d04b254c (diff) |
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>
-rw-r--r-- | mm/mmap.c | 25 |
1 files changed, 16 insertions, 9 deletions
@@ -2165,24 +2165,31 @@ int may_expand_vm(struct mm_struct *mm, unsigned long npages) | |||
2165 | } | 2165 | } |
2166 | 2166 | ||
2167 | 2167 | ||
2168 | static struct page *special_mapping_nopage(struct vm_area_struct *vma, | 2168 | static int special_mapping_fault(struct vm_area_struct *vma, |
2169 | unsigned long address, int *type) | 2169 | struct vm_fault *vmf) |
2170 | { | 2170 | { |
2171 | pgoff_t pgoff; | ||
2171 | struct page **pages; | 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; | 2182 | for (pages = vma->vm_private_data; pgoff && *pages; ++pages) |
2176 | for (pages = vma->vm_private_data; address > 0 && *pages; ++pages) | 2183 | pgoff--; |
2177 | address -= PAGE_SIZE; | ||
2178 | 2184 | ||
2179 | if (*pages) { | 2185 | if (*pages) { |
2180 | struct page *page = *pages; | 2186 | struct page *page = *pages; |
2181 | get_page(page); | 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 @@ static void special_mapping_close(struct vm_area_struct *vma) | |||
2194 | 2201 | ||
2195 | static struct vm_operations_struct special_mapping_vmops = { | 2202 | static struct vm_operations_struct special_mapping_vmops = { |
2196 | .close = special_mapping_close, | 2203 | .close = special_mapping_close, |
2197 | .nopage = special_mapping_nopage, | 2204 | .fault = special_mapping_fault, |
2198 | }; | 2205 | }; |
2199 | 2206 | ||
2200 | /* | 2207 | /* |