diff options
Diffstat (limited to 'mm/mprotect.c')
-rw-r--r-- | mm/mprotect.c | 20 |
1 files changed, 15 insertions, 5 deletions
diff --git a/mm/mprotect.c b/mm/mprotect.c index 4c513387309..5a688a2756b 100644 --- a/mm/mprotect.c +++ b/mm/mprotect.c | |||
@@ -78,7 +78,7 @@ static void change_pte_range(struct mm_struct *mm, pmd_t *pmd, | |||
78 | pte_unmap_unlock(pte - 1, ptl); | 78 | pte_unmap_unlock(pte - 1, ptl); |
79 | } | 79 | } |
80 | 80 | ||
81 | static inline void change_pmd_range(struct mm_struct *mm, pud_t *pud, | 81 | static inline void change_pmd_range(struct vm_area_struct *vma, pud_t *pud, |
82 | unsigned long addr, unsigned long end, pgprot_t newprot, | 82 | unsigned long addr, unsigned long end, pgprot_t newprot, |
83 | int dirty_accountable) | 83 | int dirty_accountable) |
84 | { | 84 | { |
@@ -88,13 +88,21 @@ static inline void change_pmd_range(struct mm_struct *mm, pud_t *pud, | |||
88 | pmd = pmd_offset(pud, addr); | 88 | pmd = pmd_offset(pud, addr); |
89 | do { | 89 | do { |
90 | next = pmd_addr_end(addr, end); | 90 | next = pmd_addr_end(addr, end); |
91 | if (pmd_trans_huge(*pmd)) { | ||
92 | if (next - addr != HPAGE_PMD_SIZE) | ||
93 | split_huge_page_pmd(vma->vm_mm, pmd); | ||
94 | else if (change_huge_pmd(vma, pmd, addr, newprot)) | ||
95 | continue; | ||
96 | /* fall through */ | ||
97 | } | ||
91 | if (pmd_none_or_clear_bad(pmd)) | 98 | if (pmd_none_or_clear_bad(pmd)) |
92 | continue; | 99 | continue; |
93 | change_pte_range(mm, pmd, addr, next, newprot, dirty_accountable); | 100 | change_pte_range(vma->vm_mm, pmd, addr, next, newprot, |
101 | dirty_accountable); | ||
94 | } while (pmd++, addr = next, addr != end); | 102 | } while (pmd++, addr = next, addr != end); |
95 | } | 103 | } |
96 | 104 | ||
97 | static inline void change_pud_range(struct mm_struct *mm, pgd_t *pgd, | 105 | static inline void change_pud_range(struct vm_area_struct *vma, pgd_t *pgd, |
98 | unsigned long addr, unsigned long end, pgprot_t newprot, | 106 | unsigned long addr, unsigned long end, pgprot_t newprot, |
99 | int dirty_accountable) | 107 | int dirty_accountable) |
100 | { | 108 | { |
@@ -106,7 +114,8 @@ static inline void change_pud_range(struct mm_struct *mm, pgd_t *pgd, | |||
106 | next = pud_addr_end(addr, end); | 114 | next = pud_addr_end(addr, end); |
107 | if (pud_none_or_clear_bad(pud)) | 115 | if (pud_none_or_clear_bad(pud)) |
108 | continue; | 116 | continue; |
109 | change_pmd_range(mm, pud, addr, next, newprot, dirty_accountable); | 117 | change_pmd_range(vma, pud, addr, next, newprot, |
118 | dirty_accountable); | ||
110 | } while (pud++, addr = next, addr != end); | 119 | } while (pud++, addr = next, addr != end); |
111 | } | 120 | } |
112 | 121 | ||
@@ -126,7 +135,8 @@ static void change_protection(struct vm_area_struct *vma, | |||
126 | next = pgd_addr_end(addr, end); | 135 | next = pgd_addr_end(addr, end); |
127 | if (pgd_none_or_clear_bad(pgd)) | 136 | if (pgd_none_or_clear_bad(pgd)) |
128 | continue; | 137 | continue; |
129 | change_pud_range(mm, pgd, addr, next, newprot, dirty_accountable); | 138 | change_pud_range(vma, pgd, addr, next, newprot, |
139 | dirty_accountable); | ||
130 | } while (pgd++, addr = next, addr != end); | 140 | } while (pgd++, addr = next, addr != end); |
131 | flush_tlb_range(vma, start, end); | 141 | flush_tlb_range(vma, start, end); |
132 | } | 142 | } |