Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Andreas Sandberg and committed by
Linus Torvalds
e8569dd2 549543df

+16 -5
+16 -5
mm/hugetlb.c
··· 2346 2346 int cow; 2347 2347 struct hstate *h = hstate_vma(vma); 2348 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 2353 cow = (vma->vm_flags & (VM_SHARED | VM_MAYWRITE)) == VM_MAYWRITE; 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); 2351 2359 2352 2360 for (addr = vma->vm_start; addr < vma->vm_end; addr += sz) { 2353 2361 spinlock_t *src_ptl, *dst_ptl; ··· 2363 2355 if (!src_pte) 2364 2356 continue; 2365 2357 dst_pte = huge_pte_alloc(dst, addr, sz); 2366 - if (!dst_pte) 2367 - goto nomem; 2358 + if (!dst_pte) { 2359 + ret = -ENOMEM; 2360 + break; 2361 + } 2368 2362 2369 2363 /* If the pagetables are shared don't copy or take references */ 2370 2364 if (dst_pte == src_pte) ··· 2387 2377 spin_unlock(src_ptl); 2388 2378 spin_unlock(dst_ptl); 2389 2379 } 2390 - return 0; 2391 2380 2392 - nomem: 2393 - return -ENOMEM; 2381 + if (cow) 2382 + mmu_notifier_invalidate_range_end(src, mmun_start, mmun_end); 2383 + 2384 + return ret; 2394 2385 } 2395 2386 2396 2387 static int is_hugetlb_entry_migration(pte_t pte)