diff options
Diffstat (limited to 'mm')
-rw-r--r-- | mm/hugetlb.c | 22 |
1 files changed, 19 insertions, 3 deletions
diff --git a/mm/hugetlb.c b/mm/hugetlb.c index ab79cd4dd23c..ce8cbb29860b 100644 --- a/mm/hugetlb.c +++ b/mm/hugetlb.c | |||
@@ -2071,6 +2071,14 @@ follow_huge_pud(struct mm_struct *mm, unsigned long address, | |||
2071 | return NULL; | 2071 | return NULL; |
2072 | } | 2072 | } |
2073 | 2073 | ||
2074 | static int huge_zeropage_ok(pte_t *ptep, int write, int shared) | ||
2075 | { | ||
2076 | if (!ptep || write || shared) | ||
2077 | return 0; | ||
2078 | else | ||
2079 | return huge_pte_none(huge_ptep_get(ptep)); | ||
2080 | } | ||
2081 | |||
2074 | int follow_hugetlb_page(struct mm_struct *mm, struct vm_area_struct *vma, | 2082 | int follow_hugetlb_page(struct mm_struct *mm, struct vm_area_struct *vma, |
2075 | struct page **pages, struct vm_area_struct **vmas, | 2083 | struct page **pages, struct vm_area_struct **vmas, |
2076 | unsigned long *position, int *length, int i, | 2084 | unsigned long *position, int *length, int i, |
@@ -2080,6 +2088,8 @@ int follow_hugetlb_page(struct mm_struct *mm, struct vm_area_struct *vma, | |||
2080 | unsigned long vaddr = *position; | 2088 | unsigned long vaddr = *position; |
2081 | int remainder = *length; | 2089 | int remainder = *length; |
2082 | struct hstate *h = hstate_vma(vma); | 2090 | struct hstate *h = hstate_vma(vma); |
2091 | int zeropage_ok = 0; | ||
2092 | int shared = vma->vm_flags & VM_SHARED; | ||
2083 | 2093 | ||
2084 | spin_lock(&mm->page_table_lock); | 2094 | spin_lock(&mm->page_table_lock); |
2085 | while (vaddr < vma->vm_end && remainder) { | 2095 | while (vaddr < vma->vm_end && remainder) { |
@@ -2092,8 +2102,11 @@ int follow_hugetlb_page(struct mm_struct *mm, struct vm_area_struct *vma, | |||
2092 | * first, for the page indexing below to work. | 2102 | * first, for the page indexing below to work. |
2093 | */ | 2103 | */ |
2094 | pte = huge_pte_offset(mm, vaddr & huge_page_mask(h)); | 2104 | pte = huge_pte_offset(mm, vaddr & huge_page_mask(h)); |
2105 | if (huge_zeropage_ok(pte, write, shared)) | ||
2106 | zeropage_ok = 1; | ||
2095 | 2107 | ||
2096 | if (!pte || huge_pte_none(huge_ptep_get(pte)) || | 2108 | if (!pte || |
2109 | (huge_pte_none(huge_ptep_get(pte)) && !zeropage_ok) || | ||
2097 | (write && !pte_write(huge_ptep_get(pte)))) { | 2110 | (write && !pte_write(huge_ptep_get(pte)))) { |
2098 | int ret; | 2111 | int ret; |
2099 | 2112 | ||
@@ -2113,8 +2126,11 @@ int follow_hugetlb_page(struct mm_struct *mm, struct vm_area_struct *vma, | |||
2113 | page = pte_page(huge_ptep_get(pte)); | 2126 | page = pte_page(huge_ptep_get(pte)); |
2114 | same_page: | 2127 | same_page: |
2115 | if (pages) { | 2128 | if (pages) { |
2116 | get_page(page); | 2129 | if (zeropage_ok) |
2117 | pages[i] = page + pfn_offset; | 2130 | pages[i] = ZERO_PAGE(0); |
2131 | else | ||
2132 | pages[i] = page + pfn_offset; | ||
2133 | get_page(pages[i]); | ||
2118 | } | 2134 | } |
2119 | 2135 | ||
2120 | if (vmas) | 2136 | if (vmas) |