aboutsummaryrefslogtreecommitdiffstats
path: root/mm/hugetlb.c
diff options
context:
space:
mode:
Diffstat (limited to 'mm/hugetlb.c')
-rw-r--r--mm/hugetlb.c23
1 files changed, 19 insertions, 4 deletions
diff --git a/mm/hugetlb.c b/mm/hugetlb.c
index c007fb5fb8d5..7f2a28ab46d5 100644
--- a/mm/hugetlb.c
+++ b/mm/hugetlb.c
@@ -3233,7 +3233,7 @@ static int is_hugetlb_entry_hwpoisoned(pte_t pte)
3233int copy_hugetlb_page_range(struct mm_struct *dst, struct mm_struct *src, 3233int copy_hugetlb_page_range(struct mm_struct *dst, struct mm_struct *src,
3234 struct vm_area_struct *vma) 3234 struct vm_area_struct *vma)
3235{ 3235{
3236 pte_t *src_pte, *dst_pte, entry; 3236 pte_t *src_pte, *dst_pte, entry, dst_entry;
3237 struct page *ptepage; 3237 struct page *ptepage;
3238 unsigned long addr; 3238 unsigned long addr;
3239 int cow; 3239 int cow;
@@ -3261,15 +3261,30 @@ int copy_hugetlb_page_range(struct mm_struct *dst, struct mm_struct *src,
3261 break; 3261 break;
3262 } 3262 }
3263 3263
3264 /* If the pagetables are shared don't copy or take references */ 3264 /*
3265 if (dst_pte == src_pte) 3265 * If the pagetables are shared don't copy or take references.
3266 * dst_pte == src_pte is the common case of src/dest sharing.
3267 *
3268 * However, src could have 'unshared' and dst shares with
3269 * another vma. If dst_pte !none, this implies sharing.
3270 * Check here before taking page table lock, and once again
3271 * after taking the lock below.
3272 */
3273 dst_entry = huge_ptep_get(dst_pte);
3274 if ((dst_pte == src_pte) || !huge_pte_none(dst_entry))
3266 continue; 3275 continue;
3267 3276
3268 dst_ptl = huge_pte_lock(h, dst, dst_pte); 3277 dst_ptl = huge_pte_lock(h, dst, dst_pte);
3269 src_ptl = huge_pte_lockptr(h, src, src_pte); 3278 src_ptl = huge_pte_lockptr(h, src, src_pte);
3270 spin_lock_nested(src_ptl, SINGLE_DEPTH_NESTING); 3279 spin_lock_nested(src_ptl, SINGLE_DEPTH_NESTING);
3271 entry = huge_ptep_get(src_pte); 3280 entry = huge_ptep_get(src_pte);
3272 if (huge_pte_none(entry)) { /* skip none entry */ 3281 dst_entry = huge_ptep_get(dst_pte);
3282 if (huge_pte_none(entry) || !huge_pte_none(dst_entry)) {
3283 /*
3284 * Skip if src entry none. Also, skip in the
3285 * unlikely case dst entry !none as this implies
3286 * sharing with another vma.
3287 */
3273 ; 3288 ;
3274 } else if (unlikely(is_hugetlb_entry_migration(entry) || 3289 } else if (unlikely(is_hugetlb_entry_migration(entry) ||
3275 is_hugetlb_entry_hwpoisoned(entry))) { 3290 is_hugetlb_entry_hwpoisoned(entry))) {