diff options
Diffstat (limited to 'mm/memory.c')
-rw-r--r-- | mm/memory.c | 43 |
1 files changed, 39 insertions, 4 deletions
diff --git a/mm/memory.c b/mm/memory.c index f9628e568c58..22e037e3364e 100644 --- a/mm/memory.c +++ b/mm/memory.c | |||
@@ -2180,6 +2180,42 @@ oom: | |||
2180 | return VM_FAULT_OOM; | 2180 | return VM_FAULT_OOM; |
2181 | } | 2181 | } |
2182 | 2182 | ||
2183 | /* | ||
2184 | * Handle write page faults for VM_MIXEDMAP or VM_PFNMAP for a VM_SHARED | ||
2185 | * mapping | ||
2186 | */ | ||
2187 | static int wp_pfn_shared(struct mm_struct *mm, | ||
2188 | struct vm_area_struct *vma, unsigned long address, | ||
2189 | pte_t *page_table, spinlock_t *ptl, pte_t orig_pte, | ||
2190 | pmd_t *pmd) | ||
2191 | { | ||
2192 | if (vma->vm_ops && vma->vm_ops->pfn_mkwrite) { | ||
2193 | struct vm_fault vmf = { | ||
2194 | .page = NULL, | ||
2195 | .pgoff = linear_page_index(vma, address), | ||
2196 | .virtual_address = (void __user *)(address & PAGE_MASK), | ||
2197 | .flags = FAULT_FLAG_WRITE | FAULT_FLAG_MKWRITE, | ||
2198 | }; | ||
2199 | int ret; | ||
2200 | |||
2201 | pte_unmap_unlock(page_table, ptl); | ||
2202 | ret = vma->vm_ops->pfn_mkwrite(vma, &vmf); | ||
2203 | if (ret & VM_FAULT_ERROR) | ||
2204 | return ret; | ||
2205 | page_table = pte_offset_map_lock(mm, pmd, address, &ptl); | ||
2206 | /* | ||
2207 | * We might have raced with another page fault while we | ||
2208 | * released the pte_offset_map_lock. | ||
2209 | */ | ||
2210 | if (!pte_same(*page_table, orig_pte)) { | ||
2211 | pte_unmap_unlock(page_table, ptl); | ||
2212 | return 0; | ||
2213 | } | ||
2214 | } | ||
2215 | return wp_page_reuse(mm, vma, address, page_table, ptl, orig_pte, | ||
2216 | NULL, 0, 0); | ||
2217 | } | ||
2218 | |||
2183 | static int wp_page_shared(struct mm_struct *mm, struct vm_area_struct *vma, | 2219 | static int wp_page_shared(struct mm_struct *mm, struct vm_area_struct *vma, |
2184 | unsigned long address, pte_t *page_table, | 2220 | unsigned long address, pte_t *page_table, |
2185 | pmd_t *pmd, spinlock_t *ptl, pte_t orig_pte, | 2221 | pmd_t *pmd, spinlock_t *ptl, pte_t orig_pte, |
@@ -2258,13 +2294,12 @@ static int do_wp_page(struct mm_struct *mm, struct vm_area_struct *vma, | |||
2258 | * VM_PFNMAP VMA. | 2294 | * VM_PFNMAP VMA. |
2259 | * | 2295 | * |
2260 | * We should not cow pages in a shared writeable mapping. | 2296 | * We should not cow pages in a shared writeable mapping. |
2261 | * Just mark the pages writable as we can't do any dirty | 2297 | * Just mark the pages writable and/or call ops->pfn_mkwrite. |
2262 | * accounting on raw pfn maps. | ||
2263 | */ | 2298 | */ |
2264 | if ((vma->vm_flags & (VM_WRITE|VM_SHARED)) == | 2299 | if ((vma->vm_flags & (VM_WRITE|VM_SHARED)) == |
2265 | (VM_WRITE|VM_SHARED)) | 2300 | (VM_WRITE|VM_SHARED)) |
2266 | return wp_page_reuse(mm, vma, address, page_table, ptl, | 2301 | return wp_pfn_shared(mm, vma, address, page_table, ptl, |
2267 | orig_pte, old_page, 0, 0); | 2302 | orig_pte, pmd); |
2268 | 2303 | ||
2269 | pte_unmap_unlock(page_table, ptl); | 2304 | pte_unmap_unlock(page_table, ptl); |
2270 | return wp_page_copy(mm, vma, address, page_table, pmd, | 2305 | return wp_page_copy(mm, vma, address, page_table, pmd, |