From: "Zhang, Yanmin" 2.6.16-rc3 uses hugetlb on-demand paging, but it doesn_t support hugetlb mprotect. Signed-off-by: Zhang Yanmin Cc: David Gibson Cc: "David S. Miller" Cc: Benjamin Herrenschmidt Cc: Paul Mackerras Cc: William Lee Irwin III Signed-off-by: Andrew Morton --- include/linux/hugetlb.h | 4 ++++ mm/hugetlb.c | 29 +++++++++++++++++++++++++++++ mm/mprotect.c | 18 +++++++++++------- 3 files changed, 44 insertions(+), 7 deletions(-) diff -puN include/linux/hugetlb.h~enable-mprotect-on-huge-pages include/linux/hugetlb.h --- devel/include/linux/hugetlb.h~enable-mprotect-on-huge-pages 2006-02-27 20:57:56.000000000 -0800 +++ devel-akpm/include/linux/hugetlb.h 2006-02-27 20:57:57.000000000 -0800 @@ -41,6 +41,8 @@ struct page *follow_huge_pmd(struct mm_s pmd_t *pmd, int write); int is_aligned_hugepage_range(unsigned long addr, unsigned long len); int pmd_huge(pmd_t pmd); +void hugetlb_change_protection(struct vm_area_struct *vma, + unsigned long address, unsigned long end, pgprot_t newprot); #ifndef ARCH_HAS_HUGEPAGE_ONLY_RANGE #define is_hugepage_only_range(mm, addr, len) 0 @@ -101,6 +103,8 @@ static inline unsigned long hugetlb_tota #define free_huge_page(p) ({ (void)(p); BUG(); }) #define hugetlb_fault(mm, vma, addr, write) ({ BUG(); 0; }) +#define hugetlb_change_protection(vma, address, end, newprot) + #ifndef HPAGE_MASK #define HPAGE_MASK PAGE_MASK /* Keep the compiler happy */ #define HPAGE_SIZE PAGE_SIZE diff -puN mm/hugetlb.c~enable-mprotect-on-huge-pages mm/hugetlb.c --- devel/mm/hugetlb.c~enable-mprotect-on-huge-pages 2006-02-27 20:57:56.000000000 -0800 +++ devel-akpm/mm/hugetlb.c 2006-02-27 20:57:57.000000000 -0800 @@ -565,3 +565,32 @@ int follow_hugetlb_page(struct mm_struct return i; } + +void hugetlb_change_protection(struct vm_area_struct *vma, + unsigned long address, unsigned long end, pgprot_t newprot) +{ + struct mm_struct *mm = vma->vm_mm; + unsigned long start = address; + pte_t *ptep; + pte_t pte; + + BUG_ON(address >= end); + flush_cache_range(vma, address, end); + + spin_lock(&mm->page_table_lock); + for (; address < end; address += HPAGE_SIZE) { + ptep = huge_pte_offset(mm, address); + if (!ptep) + continue; + if (!pte_none(*ptep)) { + pte = huge_ptep_get_and_clear(mm, address, ptep); + pte = pte_modify(pte, newprot); + set_huge_pte_at(mm, address, ptep, pte); + lazy_mmu_prot_update(pte); + } + } + spin_unlock(&mm->page_table_lock); + + flush_tlb_range(vma, start, end); +} + diff -puN mm/mprotect.c~enable-mprotect-on-huge-pages mm/mprotect.c --- devel/mm/mprotect.c~enable-mprotect-on-huge-pages 2006-02-27 20:57:57.000000000 -0800 +++ devel-akpm/mm/mprotect.c 2006-02-27 20:57:57.000000000 -0800 @@ -124,7 +124,7 @@ mprotect_fixup(struct vm_area_struct *vm * a MAP_NORESERVE private mapping to writable will now reserve. */ if (newflags & VM_WRITE) { - if (!(oldflags & (VM_ACCOUNT|VM_WRITE|VM_SHARED|VM_HUGETLB))) { + if (!(oldflags & (VM_ACCOUNT|VM_WRITE|VM_SHARED))) { charged = nrpages; if (security_vm_enough_memory(charged)) return -ENOMEM; @@ -166,7 +166,10 @@ success: */ vma->vm_flags = newflags; vma->vm_page_prot = newprot; - change_protection(vma, start, end, newprot); + if (is_vm_hugetlb_page(vma)) + hugetlb_change_protection(vma, start, end, newprot); + else + change_protection(vma, start, end, newprot); vm_stat_account(mm, oldflags, vma->vm_file, -nrpages); vm_stat_account(mm, newflags, vma->vm_file, nrpages); return 0; @@ -240,11 +243,6 @@ sys_mprotect(unsigned long start, size_t /* Here we know that vma->vm_start <= nstart < vma->vm_end. */ - if (is_vm_hugetlb_page(vma)) { - error = -EACCES; - goto out; - } - newflags = vm_flags | (vma->vm_flags & ~(VM_READ | VM_WRITE | VM_EXEC)); /* newflags >> 4 shift VM_MAY% in place of VM_% */ @@ -260,6 +258,12 @@ sys_mprotect(unsigned long start, size_t tmp = vma->vm_end; if (tmp > end) tmp = end; + if (is_vm_hugetlb_page(vma) && + is_aligned_hugepage_range(nstart, tmp - nstart)) { + error = -EINVAL; + goto out; + } + error = mprotect_fixup(vma, &prev, nstart, tmp, newflags); if (error) goto out; _