|
@@ -2520,6 +2520,31 @@ static void set_huge_ptep_writable(struct vm_area_struct *vma,
|
|
update_mmu_cache(vma, address, ptep);
|
|
update_mmu_cache(vma, address, ptep);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static int is_hugetlb_entry_migration(pte_t pte)
|
|
|
|
+{
|
|
|
|
+ swp_entry_t swp;
|
|
|
|
+
|
|
|
|
+ if (huge_pte_none(pte) || pte_present(pte))
|
|
|
|
+ return 0;
|
|
|
|
+ swp = pte_to_swp_entry(pte);
|
|
|
|
+ if (non_swap_entry(swp) && is_migration_entry(swp))
|
|
|
|
+ return 1;
|
|
|
|
+ else
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int is_hugetlb_entry_hwpoisoned(pte_t pte)
|
|
|
|
+{
|
|
|
|
+ swp_entry_t swp;
|
|
|
|
+
|
|
|
|
+ if (huge_pte_none(pte) || pte_present(pte))
|
|
|
|
+ return 0;
|
|
|
|
+ swp = pte_to_swp_entry(pte);
|
|
|
|
+ if (non_swap_entry(swp) && is_hwpoison_entry(swp))
|
|
|
|
+ return 1;
|
|
|
|
+ else
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
|
|
int copy_hugetlb_page_range(struct mm_struct *dst, struct mm_struct *src,
|
|
int copy_hugetlb_page_range(struct mm_struct *dst, struct mm_struct *src,
|
|
struct vm_area_struct *vma)
|
|
struct vm_area_struct *vma)
|
|
@@ -2559,10 +2584,26 @@ int copy_hugetlb_page_range(struct mm_struct *dst, struct mm_struct *src,
|
|
dst_ptl = huge_pte_lock(h, dst, dst_pte);
|
|
dst_ptl = huge_pte_lock(h, dst, dst_pte);
|
|
src_ptl = huge_pte_lockptr(h, src, src_pte);
|
|
src_ptl = huge_pte_lockptr(h, src, src_pte);
|
|
spin_lock_nested(src_ptl, SINGLE_DEPTH_NESTING);
|
|
spin_lock_nested(src_ptl, SINGLE_DEPTH_NESTING);
|
|
- if (!huge_pte_none(huge_ptep_get(src_pte))) {
|
|
|
|
|
|
+ entry = huge_ptep_get(src_pte);
|
|
|
|
+ if (huge_pte_none(entry)) { /* skip none entry */
|
|
|
|
+ ;
|
|
|
|
+ } else if (unlikely(is_hugetlb_entry_migration(entry) ||
|
|
|
|
+ is_hugetlb_entry_hwpoisoned(entry))) {
|
|
|
|
+ swp_entry_t swp_entry = pte_to_swp_entry(entry);
|
|
|
|
+
|
|
|
|
+ if (is_write_migration_entry(swp_entry) && cow) {
|
|
|
|
+ /*
|
|
|
|
+ * COW mappings require pages in both
|
|
|
|
+ * parent and child to be set to read.
|
|
|
|
+ */
|
|
|
|
+ make_migration_entry_read(&swp_entry);
|
|
|
|
+ entry = swp_entry_to_pte(swp_entry);
|
|
|
|
+ set_huge_pte_at(src, addr, src_pte, entry);
|
|
|
|
+ }
|
|
|
|
+ set_huge_pte_at(dst, addr, dst_pte, entry);
|
|
|
|
+ } else {
|
|
if (cow)
|
|
if (cow)
|
|
huge_ptep_set_wrprotect(src, addr, src_pte);
|
|
huge_ptep_set_wrprotect(src, addr, src_pte);
|
|
- entry = huge_ptep_get(src_pte);
|
|
|
|
ptepage = pte_page(entry);
|
|
ptepage = pte_page(entry);
|
|
get_page(ptepage);
|
|
get_page(ptepage);
|
|
page_dup_rmap(ptepage);
|
|
page_dup_rmap(ptepage);
|
|
@@ -2578,32 +2619,6 @@ int copy_hugetlb_page_range(struct mm_struct *dst, struct mm_struct *src,
|
|
return ret;
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
|
|
-static int is_hugetlb_entry_migration(pte_t pte)
|
|
|
|
-{
|
|
|
|
- swp_entry_t swp;
|
|
|
|
-
|
|
|
|
- if (huge_pte_none(pte) || pte_present(pte))
|
|
|
|
- return 0;
|
|
|
|
- swp = pte_to_swp_entry(pte);
|
|
|
|
- if (non_swap_entry(swp) && is_migration_entry(swp))
|
|
|
|
- return 1;
|
|
|
|
- else
|
|
|
|
- return 0;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static int is_hugetlb_entry_hwpoisoned(pte_t pte)
|
|
|
|
-{
|
|
|
|
- swp_entry_t swp;
|
|
|
|
-
|
|
|
|
- if (huge_pte_none(pte) || pte_present(pte))
|
|
|
|
- return 0;
|
|
|
|
- swp = pte_to_swp_entry(pte);
|
|
|
|
- if (non_swap_entry(swp) && is_hwpoison_entry(swp))
|
|
|
|
- return 1;
|
|
|
|
- else
|
|
|
|
- return 0;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
void __unmap_hugepage_range(struct mmu_gather *tlb, struct vm_area_struct *vma,
|
|
void __unmap_hugepage_range(struct mmu_gather *tlb, struct vm_area_struct *vma,
|
|
unsigned long start, unsigned long end,
|
|
unsigned long start, unsigned long end,
|
|
struct page *ref_page)
|
|
struct page *ref_page)
|