diff options
Diffstat (limited to 'mm/hugetlb.c')
-rw-r--r-- | mm/hugetlb.c | 23 |
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) | |||
3233 | int copy_hugetlb_page_range(struct mm_struct *dst, struct mm_struct *src, | 3233 | int 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))) { |