diff options
| author | Andreas Sandberg <andreas@sandberg.pp.se> | 2014-01-21 18:49:09 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-01-21 19:19:44 -0500 |
| commit | e8569dd299dbc7bac878325c0bdc7aa449eae479 (patch) | |
| tree | dd512bba20e9413ee8bf1a0eff169d9e017051ad | |
| parent | 549543dff797ae1081f61a69f8511c61806c3735 (diff) | |
mm/hugetlb.c: call MMU notifiers when copying a hugetlb page range
When copy_hugetlb_page_range() is called to copy a range of hugetlb
mappings, the secondary MMUs are not notified if there is a protection
downgrade, which breaks COW semantics in KVM.
This patch adds the necessary MMU notifier calls.
Signed-off-by: Andreas Sandberg <andreas@sandberg.pp.se>
Acked-by: Steve Capper <steve.capper@linaro.org>
Acked-by: Marc Zyngier <marc.zyngier@arm.com>
Cc: Mel Gorman <mgorman@suse.de>
Cc: Rik van Riel <riel@redhat.com>
Cc: Hugh Dickins <hughd@google.com>
Cc: Andrea Arcangeli <aarcange@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
| -rw-r--r-- | mm/hugetlb.c | 21 |
1 files changed, 16 insertions, 5 deletions
diff --git a/mm/hugetlb.c b/mm/hugetlb.c index f730b7a37590..1697ff0cc53a 100644 --- a/mm/hugetlb.c +++ b/mm/hugetlb.c | |||
| @@ -2346,17 +2346,27 @@ int copy_hugetlb_page_range(struct mm_struct *dst, struct mm_struct *src, | |||
| 2346 | int cow; | 2346 | int cow; |
| 2347 | struct hstate *h = hstate_vma(vma); | 2347 | struct hstate *h = hstate_vma(vma); |
| 2348 | unsigned long sz = huge_page_size(h); | 2348 | unsigned long sz = huge_page_size(h); |
| 2349 | unsigned long mmun_start; /* For mmu_notifiers */ | ||
| 2350 | unsigned long mmun_end; /* For mmu_notifiers */ | ||
| 2351 | int ret = 0; | ||
| 2349 | 2352 | ||
| 2350 | cow = (vma->vm_flags & (VM_SHARED | VM_MAYWRITE)) == VM_MAYWRITE; | 2353 | cow = (vma->vm_flags & (VM_SHARED | VM_MAYWRITE)) == VM_MAYWRITE; |
| 2351 | 2354 | ||
| 2355 | mmun_start = vma->vm_start; | ||
| 2356 | mmun_end = vma->vm_end; | ||
| 2357 | if (cow) | ||
| 2358 | mmu_notifier_invalidate_range_start(src, mmun_start, mmun_end); | ||
| 2359 | |||
| 2352 | for (addr = vma->vm_start; addr < vma->vm_end; addr += sz) { | 2360 | for (addr = vma->vm_start; addr < vma->vm_end; addr += sz) { |
| 2353 | spinlock_t *src_ptl, *dst_ptl; | 2361 | spinlock_t *src_ptl, *dst_ptl; |
| 2354 | src_pte = huge_pte_offset(src, addr); | 2362 | src_pte = huge_pte_offset(src, addr); |
| 2355 | if (!src_pte) | 2363 | if (!src_pte) |
| 2356 | continue; | 2364 | continue; |
| 2357 | dst_pte = huge_pte_alloc(dst, addr, sz); | 2365 | dst_pte = huge_pte_alloc(dst, addr, sz); |
| 2358 | if (!dst_pte) | 2366 | if (!dst_pte) { |
| 2359 | goto nomem; | 2367 | ret = -ENOMEM; |
| 2368 | break; | ||
| 2369 | } | ||
| 2360 | 2370 | ||
| 2361 | /* If the pagetables are shared don't copy or take references */ | 2371 | /* If the pagetables are shared don't copy or take references */ |
| 2362 | if (dst_pte == src_pte) | 2372 | if (dst_pte == src_pte) |
| @@ -2377,10 +2387,11 @@ int copy_hugetlb_page_range(struct mm_struct *dst, struct mm_struct *src, | |||
| 2377 | spin_unlock(src_ptl); | 2387 | spin_unlock(src_ptl); |
| 2378 | spin_unlock(dst_ptl); | 2388 | spin_unlock(dst_ptl); |
| 2379 | } | 2389 | } |
| 2380 | return 0; | ||
| 2381 | 2390 | ||
| 2382 | nomem: | 2391 | if (cow) |
| 2383 | return -ENOMEM; | 2392 | mmu_notifier_invalidate_range_end(src, mmun_start, mmun_end); |
| 2393 | |||
| 2394 | return ret; | ||
| 2384 | } | 2395 | } |
| 2385 | 2396 | ||
| 2386 | static int is_hugetlb_entry_migration(pte_t pte) | 2397 | static int is_hugetlb_entry_migration(pte_t pte) |
