diff options
Diffstat (limited to 'mm')
-rw-r--r-- | mm/hugetlb.c | 29 | ||||
-rw-r--r-- | mm/mprotect.c | 12 |
2 files changed, 34 insertions, 7 deletions
diff --git a/mm/hugetlb.c b/mm/hugetlb.c index 20117a4b8ab6..783098f6cf8e 100644 --- a/mm/hugetlb.c +++ b/mm/hugetlb.c | |||
@@ -565,3 +565,32 @@ int follow_hugetlb_page(struct mm_struct *mm, struct vm_area_struct *vma, | |||
565 | 565 | ||
566 | return i; | 566 | return i; |
567 | } | 567 | } |
568 | |||
569 | void hugetlb_change_protection(struct vm_area_struct *vma, | ||
570 | unsigned long address, unsigned long end, pgprot_t newprot) | ||
571 | { | ||
572 | struct mm_struct *mm = vma->vm_mm; | ||
573 | unsigned long start = address; | ||
574 | pte_t *ptep; | ||
575 | pte_t pte; | ||
576 | |||
577 | BUG_ON(address >= end); | ||
578 | flush_cache_range(vma, address, end); | ||
579 | |||
580 | spin_lock(&mm->page_table_lock); | ||
581 | for (; address < end; address += HPAGE_SIZE) { | ||
582 | ptep = huge_pte_offset(mm, address); | ||
583 | if (!ptep) | ||
584 | continue; | ||
585 | if (!pte_none(*ptep)) { | ||
586 | pte = huge_ptep_get_and_clear(mm, address, ptep); | ||
587 | pte = pte_mkhuge(pte_modify(pte, newprot)); | ||
588 | set_huge_pte_at(mm, address, ptep, pte); | ||
589 | lazy_mmu_prot_update(pte); | ||
590 | } | ||
591 | } | ||
592 | spin_unlock(&mm->page_table_lock); | ||
593 | |||
594 | flush_tlb_range(vma, start, end); | ||
595 | } | ||
596 | |||
diff --git a/mm/mprotect.c b/mm/mprotect.c index 653b8571c1ed..4c14d4289b61 100644 --- a/mm/mprotect.c +++ b/mm/mprotect.c | |||
@@ -124,7 +124,7 @@ mprotect_fixup(struct vm_area_struct *vma, struct vm_area_struct **pprev, | |||
124 | * a MAP_NORESERVE private mapping to writable will now reserve. | 124 | * a MAP_NORESERVE private mapping to writable will now reserve. |
125 | */ | 125 | */ |
126 | if (newflags & VM_WRITE) { | 126 | if (newflags & VM_WRITE) { |
127 | if (!(oldflags & (VM_ACCOUNT|VM_WRITE|VM_SHARED|VM_HUGETLB))) { | 127 | if (!(oldflags & (VM_ACCOUNT|VM_WRITE|VM_SHARED))) { |
128 | charged = nrpages; | 128 | charged = nrpages; |
129 | if (security_vm_enough_memory(charged)) | 129 | if (security_vm_enough_memory(charged)) |
130 | return -ENOMEM; | 130 | return -ENOMEM; |
@@ -166,7 +166,10 @@ success: | |||
166 | */ | 166 | */ |
167 | vma->vm_flags = newflags; | 167 | vma->vm_flags = newflags; |
168 | vma->vm_page_prot = newprot; | 168 | vma->vm_page_prot = newprot; |
169 | change_protection(vma, start, end, newprot); | 169 | if (is_vm_hugetlb_page(vma)) |
170 | hugetlb_change_protection(vma, start, end, newprot); | ||
171 | else | ||
172 | change_protection(vma, start, end, newprot); | ||
170 | vm_stat_account(mm, oldflags, vma->vm_file, -nrpages); | 173 | vm_stat_account(mm, oldflags, vma->vm_file, -nrpages); |
171 | vm_stat_account(mm, newflags, vma->vm_file, nrpages); | 174 | vm_stat_account(mm, newflags, vma->vm_file, nrpages); |
172 | return 0; | 175 | return 0; |
@@ -240,11 +243,6 @@ sys_mprotect(unsigned long start, size_t len, unsigned long prot) | |||
240 | 243 | ||
241 | /* Here we know that vma->vm_start <= nstart < vma->vm_end. */ | 244 | /* Here we know that vma->vm_start <= nstart < vma->vm_end. */ |
242 | 245 | ||
243 | if (is_vm_hugetlb_page(vma)) { | ||
244 | error = -EACCES; | ||
245 | goto out; | ||
246 | } | ||
247 | |||
248 | newflags = vm_flags | (vma->vm_flags & ~(VM_READ | VM_WRITE | VM_EXEC)); | 246 | newflags = vm_flags | (vma->vm_flags & ~(VM_READ | VM_WRITE | VM_EXEC)); |
249 | 247 | ||
250 | /* newflags >> 4 shift VM_MAY% in place of VM_% */ | 248 | /* newflags >> 4 shift VM_MAY% in place of VM_% */ |