X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=mm%2Fmremap.c;h=0740146dcb220a3602270c642aad3f0df680ca1a;hb=6a77f38946aaee1cd85eeec6cf4229b204c15071;hp=92142f58b6febedadea827de136ac0226fa408f3;hpb=87fc8d1bb10cd459024a742c6a10961fefcef18f;p=linux-2.6.git diff --git a/mm/mremap.c b/mm/mremap.c index 92142f58b..0740146dc 100644 --- a/mm/mremap.c +++ b/mm/mremap.c @@ -16,6 +16,8 @@ #include #include #include +#include +#include #include #include @@ -25,19 +27,24 @@ static pte_t *get_one_pte_map_nested(struct mm_struct *mm, unsigned long addr) { pgd_t *pgd; + pud_t *pud; pmd_t *pmd; pte_t *pte = NULL; pgd = pgd_offset(mm, addr); if (pgd_none(*pgd)) goto end; - if (pgd_bad(*pgd)) { - pgd_ERROR(*pgd); - pgd_clear(pgd); + + pud = pud_offset(pgd, addr); + if (pud_none(*pud)) + goto end; + if (pud_bad(*pud)) { + pud_ERROR(*pud); + pud_clear(pud); goto end; } - pmd = pmd_offset(pgd, addr); + pmd = pmd_offset(pud, addr); if (pmd_none(*pmd)) goto end; if (pmd_bad(*pmd)) { @@ -58,12 +65,17 @@ end: static pte_t *get_one_pte_map(struct mm_struct *mm, unsigned long addr) { pgd_t *pgd; + pud_t *pud; pmd_t *pmd; pgd = pgd_offset(mm, addr); if (pgd_none(*pgd)) return NULL; - pmd = pmd_offset(pgd, addr); + + pud = pud_offset(pgd, addr); + if (pud_none(*pud)) + return NULL; + pmd = pmd_offset(pud, addr); if (!pmd_present(*pmd)) return NULL; return pte_offset_map(pmd, addr); @@ -71,10 +83,17 @@ static pte_t *get_one_pte_map(struct mm_struct *mm, unsigned long addr) static inline pte_t *alloc_one_pte_map(struct mm_struct *mm, unsigned long addr) { + pgd_t *pgd; + pud_t *pud; pmd_t *pmd; pte_t *pte = NULL; - pmd = pmd_alloc(mm, pgd_offset(mm, addr), addr); + pgd = pgd_offset(mm, addr); + + pud = pud_alloc(mm, pgd, addr); + if (!pud) + return NULL; + pmd = pmd_alloc(mm, pud, addr); if (pmd) pte = pte_alloc_map(mm, pmd, addr); return pte; @@ -82,7 +101,7 @@ static inline pte_t *alloc_one_pte_map(struct mm_struct *mm, unsigned long addr) static int move_one_page(struct vm_area_struct *vma, unsigned long old_addr, - unsigned long new_addr) + struct vm_area_struct *new_vma, unsigned long new_addr) { struct address_space *mapping = NULL; struct mm_struct *mm = vma->vm_mm; @@ -98,6 +117,9 @@ move_one_page(struct vm_area_struct *vma, unsigned long old_addr, */ mapping = vma->vm_file->f_mapping; spin_lock(&mapping->i_mmap_lock); + if (new_vma->vm_truncate_count && + new_vma->vm_truncate_count != vma->vm_truncate_count) + new_vma->vm_truncate_count = 0; } spin_lock(&mm->page_table_lock); @@ -144,8 +166,8 @@ move_one_page(struct vm_area_struct *vma, unsigned long old_addr, } static unsigned long move_page_tables(struct vm_area_struct *vma, - unsigned long new_addr, unsigned long old_addr, - unsigned long len) + unsigned long old_addr, struct vm_area_struct *new_vma, + unsigned long new_addr, unsigned long len) { unsigned long offset; @@ -157,7 +179,8 @@ static unsigned long move_page_tables(struct vm_area_struct *vma, * only a few pages.. This also makes error recovery easier. */ for (offset = 0; offset < len; offset += PAGE_SIZE) { - if (move_one_page(vma, old_addr+offset, new_addr+offset) < 0) + if (move_one_page(vma, old_addr + offset, + new_vma, new_addr + offset) < 0) break; cond_resched(); } @@ -188,14 +211,14 @@ static unsigned long move_vma(struct vm_area_struct *vma, if (!new_vma) return -ENOMEM; - moved_len = move_page_tables(vma, new_addr, old_addr, old_len); + moved_len = move_page_tables(vma, old_addr, new_vma, new_addr, old_len); if (moved_len < old_len) { /* * On error, move entries back from new area to old, * which will succeed since page tables still there, * and then proceed to unmap new area instead of old. */ - move_page_tables(new_vma, old_addr, new_addr, moved_len); + move_page_tables(new_vma, new_addr, vma, old_addr, moved_len); vma = new_vma; old_len = new_len; old_addr = new_addr; @@ -235,6 +258,9 @@ static unsigned long move_vma(struct vm_area_struct *vma, new_addr + new_len); } + acct_update_integrals(); + update_mem_hiwater(); + return new_addr; } @@ -330,7 +356,7 @@ unsigned long do_mremap(unsigned long addr, if (vma->vm_flags & VM_LOCKED) { unsigned long locked, lock_limit; locked = current->mm->locked_vm << PAGE_SHIFT; - lock_limit = current->rlim[RLIMIT_MEMLOCK].rlim_cur; + lock_limit = current->signal->rlim[RLIMIT_MEMLOCK].rlim_cur; locked += new_len - old_len; ret = -EAGAIN; if (locked > lock_limit && !capable(CAP_IPC_LOCK)) @@ -342,7 +368,7 @@ unsigned long do_mremap(unsigned long addr, } ret = -ENOMEM; if ((current->mm->total_vm << PAGE_SHIFT) + (new_len - old_len) - > current->rlim[RLIMIT_AS].rlim_cur) + > current->signal->rlim[RLIMIT_AS].rlim_cur) goto out; /* check context space, maybe only Private writable mapping? */ if (!vx_vmpages_avail(current->mm, (new_len - old_len) >> PAGE_SHIFT)) @@ -380,6 +406,8 @@ unsigned long do_mremap(unsigned long addr, make_pages_present(addr + old_len, addr + new_len); } + acct_update_integrals(); + update_mem_hiwater(); ret = addr; goto out; }