|
@@ -3233,7 +3233,7 @@ static int is_hugetlb_entry_hwpoisoned(pte_t pte)
|
|
|
int copy_hugetlb_page_range(struct mm_struct *dst, struct mm_struct *src,
|
|
|
struct vm_area_struct *vma)
|
|
|
{
|
|
|
- pte_t *src_pte, *dst_pte, entry;
|
|
|
+ pte_t *src_pte, *dst_pte, entry, dst_entry;
|
|
|
struct page *ptepage;
|
|
|
unsigned long addr;
|
|
|
int cow;
|
|
@@ -3261,15 +3261,30 @@ int copy_hugetlb_page_range(struct mm_struct *dst, struct mm_struct *src,
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
- /* If the pagetables are shared don't copy or take references */
|
|
|
- if (dst_pte == src_pte)
|
|
|
+ /*
|
|
|
+ * If the pagetables are shared don't copy or take references.
|
|
|
+ * dst_pte == src_pte is the common case of src/dest sharing.
|
|
|
+ *
|
|
|
+ * However, src could have 'unshared' and dst shares with
|
|
|
+ * another vma. If dst_pte !none, this implies sharing.
|
|
|
+ * Check here before taking page table lock, and once again
|
|
|
+ * after taking the lock below.
|
|
|
+ */
|
|
|
+ dst_entry = huge_ptep_get(dst_pte);
|
|
|
+ if ((dst_pte == src_pte) || !huge_pte_none(dst_entry))
|
|
|
continue;
|
|
|
|
|
|
dst_ptl = huge_pte_lock(h, dst, dst_pte);
|
|
|
src_ptl = huge_pte_lockptr(h, src, src_pte);
|
|
|
spin_lock_nested(src_ptl, SINGLE_DEPTH_NESTING);
|
|
|
entry = huge_ptep_get(src_pte);
|
|
|
- if (huge_pte_none(entry)) { /* skip none entry */
|
|
|
+ dst_entry = huge_ptep_get(dst_pte);
|
|
|
+ if (huge_pte_none(entry) || !huge_pte_none(dst_entry)) {
|
|
|
+ /*
|
|
|
+ * Skip if src entry none. Also, skip in the
|
|
|
+ * unlikely case dst entry !none as this implies
|
|
|
+ * sharing with another vma.
|
|
|
+ */
|
|
|
;
|
|
|
} else if (unlikely(is_hugetlb_entry_migration(entry) ||
|
|
|
is_hugetlb_entry_hwpoisoned(entry))) {
|