Commit b634975c authored by Hugh Dickins's avatar Hugh Dickins Committed by Linus Torvalds

[PATCH] ptwalk: zeromap_page_range

Convert zeromap_page_range pagetable walkers to loops using p?d_addr_end.
Remove the redundant flush_tlb_range from afterwards: as its comment
noted, there's already a BUG_ON(!pte_none).
Signed-off-by: default avatarHugh Dickins <hugh@veritas.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent ccdb8d8d
......@@ -975,113 +975,78 @@ int get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
EXPORT_SYMBOL(get_user_pages);
static void zeromap_pte_range(struct mm_struct *mm, pte_t * pte,
unsigned long address,
unsigned long size, pgprot_t prot)
static int zeromap_pte_range(struct mm_struct *mm, pmd_t *pmd,
unsigned long addr, unsigned long end, pgprot_t prot)
{
unsigned long base, end;
pte_t *pte;
base = address & PMD_MASK;
address &= ~PMD_MASK;
end = address + size;
if (end > PMD_SIZE)
end = PMD_SIZE;
pte = pte_alloc_map(mm, pmd, addr);
if (!pte)
return -ENOMEM;
do {
pte_t zero_pte = pte_wrprotect(mk_pte(ZERO_PAGE(base+address), prot));
pte_t zero_pte = pte_wrprotect(mk_pte(ZERO_PAGE(addr), prot));
BUG_ON(!pte_none(*pte));
set_pte_at(mm, base+address, pte, zero_pte);
address += PAGE_SIZE;
pte++;
} while (address && (address < end));
set_pte_at(mm, addr, pte, zero_pte);
} while (pte++, addr += PAGE_SIZE, addr != end);
pte_unmap(pte - 1);
return 0;
}
static inline int zeromap_pmd_range(struct mm_struct *mm, pmd_t * pmd,
unsigned long address, unsigned long size, pgprot_t prot)
static inline int zeromap_pmd_range(struct mm_struct *mm, pud_t *pud,
unsigned long addr, unsigned long end, pgprot_t prot)
{
unsigned long base, end;
pmd_t *pmd;
unsigned long next;
base = address & PUD_MASK;
address &= ~PUD_MASK;
end = address + size;
if (end > PUD_SIZE)
end = PUD_SIZE;
pmd = pmd_alloc(mm, pud, addr);
if (!pmd)
return -ENOMEM;
do {
pte_t * pte = pte_alloc_map(mm, pmd, base + address);
if (!pte)
next = pmd_addr_end(addr, end);
if (zeromap_pte_range(mm, pmd, addr, next, prot))
return -ENOMEM;
zeromap_pte_range(mm, pte, base + address, end - address, prot);
pte_unmap(pte);
address = (address + PMD_SIZE) & PMD_MASK;
pmd++;
} while (address && (address < end));
} while (pmd++, addr = next, addr != end);
return 0;
}
static inline int zeromap_pud_range(struct mm_struct *mm, pud_t * pud,
unsigned long address,
unsigned long size, pgprot_t prot)
static inline int zeromap_pud_range(struct mm_struct *mm, pgd_t *pgd,
unsigned long addr, unsigned long end, pgprot_t prot)
{
unsigned long base, end;
int error = 0;
pud_t *pud;
unsigned long next;
base = address & PGDIR_MASK;
address &= ~PGDIR_MASK;
end = address + size;
if (end > PGDIR_SIZE)
end = PGDIR_SIZE;
pud = pud_alloc(mm, pgd, addr);
if (!pud)
return -ENOMEM;
do {
pmd_t * pmd = pmd_alloc(mm, pud, base + address);
error = -ENOMEM;
if (!pmd)
break;
error = zeromap_pmd_range(mm, pmd, base + address,
end - address, prot);
if (error)
break;
address = (address + PUD_SIZE) & PUD_MASK;
pud++;
} while (address && (address < end));
next = pud_addr_end(addr, end);
if (zeromap_pmd_range(mm, pud, addr, next, prot))
return -ENOMEM;
} while (pud++, addr = next, addr != end);
return 0;
}
int zeromap_page_range(struct vm_area_struct *vma, unsigned long address,
unsigned long size, pgprot_t prot)
int zeromap_page_range(struct vm_area_struct *vma,
unsigned long addr, unsigned long size, pgprot_t prot)
{
int i;
int error = 0;
pgd_t * pgd;
unsigned long beg = address;
unsigned long end = address + size;
pgd_t *pgd;
unsigned long next;
unsigned long end = addr + size;
struct mm_struct *mm = vma->vm_mm;
int err;
pgd = pgd_offset(mm, address);
flush_cache_range(vma, beg, end);
BUG_ON(address >= end);
BUG_ON(end > vma->vm_end);
BUG_ON(addr >= end);
pgd = pgd_offset(mm, addr);
flush_cache_range(vma, addr, end);
spin_lock(&mm->page_table_lock);
for (i = pgd_index(address); i <= pgd_index(end-1); i++) {
pud_t *pud = pud_alloc(mm, pgd, address);
error = -ENOMEM;
if (!pud)
break;
next = (address + PGDIR_SIZE) & PGDIR_MASK;
if (next <= beg || next > end)
next = end;
error = zeromap_pud_range(mm, pud, address,
next - address, prot);
if (error)
do {
next = pgd_addr_end(addr, end);
err = zeromap_pud_range(mm, pgd, addr, next, prot);
if (err)
break;
address = next;
pgd++;
}
/*
* Why flush? zeromap_pte_range has a BUG_ON for !pte_none()
*/
flush_tlb_range(vma, beg, end);
} while (pgd++, addr = next, addr != end);
spin_unlock(&mm->page_table_lock);
return error;
return err;
}
/*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment