diff options
-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 | /* |