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

[PATCH] ptwalk: remap_pfn_range

Convert remap_pfn_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 2f6ea7b3
...@@ -1089,97 +1089,74 @@ int zeromap_page_range(struct vm_area_struct *vma, unsigned long address, ...@@ -1089,97 +1089,74 @@ int zeromap_page_range(struct vm_area_struct *vma, unsigned long address,
* mappings are removed. any references to nonexistent pages results * mappings are removed. any references to nonexistent pages results
* in null mappings (currently treated as "copy-on-access") * in null mappings (currently treated as "copy-on-access")
*/ */
static inline void static inline int remap_pte_range(struct mm_struct *mm, pmd_t *pmd,
remap_pte_range(struct mm_struct *mm, pte_t * pte, unsigned long addr, unsigned long end,
unsigned long address, unsigned long size,
unsigned long pfn, pgprot_t prot) unsigned long pfn, pgprot_t prot)
{ {
unsigned long base, end; pte_t *pte;
base = address & PMD_MASK; pte = pte_alloc_map(mm, pmd, addr);
address &= ~PMD_MASK; if (!pte)
end = address + size; return -ENOMEM;
if (end > PMD_SIZE)
end = PMD_SIZE;
do { do {
BUG_ON(!pte_none(*pte)); BUG_ON(!pte_none(*pte));
if (!pfn_valid(pfn) || PageReserved(pfn_to_page(pfn))) if (!pfn_valid(pfn) || PageReserved(pfn_to_page(pfn)))
set_pte_at(mm, base+address, pte, pfn_pte(pfn, prot)); set_pte_at(mm, addr, pte, pfn_pte(pfn, prot));
address += PAGE_SIZE;
pfn++; pfn++;
pte++; } while (pte++, addr += PAGE_SIZE, addr != end);
} while (address && (address < end)); pte_unmap(pte - 1);
return 0;
} }
static inline int static inline int remap_pmd_range(struct mm_struct *mm, pud_t *pud,
remap_pmd_range(struct mm_struct *mm, pmd_t * pmd, unsigned long address, unsigned long addr, unsigned long end,
unsigned long size, unsigned long pfn, pgprot_t prot) unsigned long pfn, pgprot_t prot)
{ {
unsigned long base, end; pmd_t *pmd;
unsigned long next;
base = address & PUD_MASK; pfn -= addr >> PAGE_SHIFT;
address &= ~PUD_MASK; pmd = pmd_alloc(mm, pud, addr);
end = address + size; if (!pmd)
if (end > PUD_SIZE) return -ENOMEM;
end = PUD_SIZE;
pfn -= (address >> PAGE_SHIFT);
do { do {
pte_t * pte = pte_alloc_map(mm, pmd, base + address); next = pmd_addr_end(addr, end);
if (!pte) if (remap_pte_range(mm, pmd, addr, next,
pfn + (addr >> PAGE_SHIFT), prot))
return -ENOMEM; return -ENOMEM;
remap_pte_range(mm, pte, base + address, end - address, } while (pmd++, addr = next, addr != end);
(address >> PAGE_SHIFT) + pfn, prot);
pte_unmap(pte);
address = (address + PMD_SIZE) & PMD_MASK;
pmd++;
} while (address && (address < end));
return 0; return 0;
} }
static inline int remap_pud_range(struct mm_struct *mm, pud_t * pud, static inline int remap_pud_range(struct mm_struct *mm, pgd_t *pgd,
unsigned long address, unsigned long size, unsigned long addr, unsigned long end,
unsigned long pfn, pgprot_t prot) unsigned long pfn, pgprot_t prot)
{ {
unsigned long base, end; pud_t *pud;
int error; unsigned long next;
base = address & PGDIR_MASK; pfn -= addr >> PAGE_SHIFT;
address &= ~PGDIR_MASK; pud = pud_alloc(mm, pgd, addr);
end = address + size; if (!pud)
if (end > PGDIR_SIZE) return -ENOMEM;
end = PGDIR_SIZE;
pfn -= address >> PAGE_SHIFT;
do { do {
pmd_t *pmd = pmd_alloc(mm, pud, base+address); next = pud_addr_end(addr, end);
error = -ENOMEM; if (remap_pmd_range(mm, pud, addr, next,
if (!pmd) pfn + (addr >> PAGE_SHIFT), prot))
break; return -ENOMEM;
error = remap_pmd_range(mm, pmd, base + address, end - address, } while (pud++, addr = next, addr != end);
(address >> PAGE_SHIFT) + pfn, prot); return 0;
if (error)
break;
address = (address + PUD_SIZE) & PUD_MASK;
pud++;
} while (address && (address < end));
return error;
} }
/* Note: this is only safe if the mm semaphore is held when called. */ /* Note: this is only safe if the mm semaphore is held when called. */
int remap_pfn_range(struct vm_area_struct *vma, unsigned long from, int remap_pfn_range(struct vm_area_struct *vma, unsigned long addr,
unsigned long pfn, unsigned long size, pgprot_t prot) unsigned long pfn, unsigned long size, pgprot_t prot)
{ {
int error = 0;
pgd_t *pgd; pgd_t *pgd;
unsigned long beg = from;
unsigned long end = from + size;
unsigned long next; unsigned long next;
unsigned long end = addr + size;
struct mm_struct *mm = vma->vm_mm; struct mm_struct *mm = vma->vm_mm;
int i; int err;
pfn -= from >> PAGE_SHIFT;
pgd = pgd_offset(mm, from);
flush_cache_range(vma, beg, end);
BUG_ON(from >= end);
/* /*
* Physically remapped pages are special. Tell the * Physically remapped pages are special. Tell the
...@@ -1191,31 +1168,21 @@ int remap_pfn_range(struct vm_area_struct *vma, unsigned long from, ...@@ -1191,31 +1168,21 @@ int remap_pfn_range(struct vm_area_struct *vma, unsigned long from,
*/ */
vma->vm_flags |= VM_IO | VM_RESERVED; vma->vm_flags |= VM_IO | VM_RESERVED;
BUG_ON(addr >= end);
pfn -= addr >> PAGE_SHIFT;
pgd = pgd_offset(mm, addr);
flush_cache_range(vma, addr, end);
spin_lock(&mm->page_table_lock); spin_lock(&mm->page_table_lock);
for (i = pgd_index(beg); i <= pgd_index(end-1); i++) { do {
pud_t *pud = pud_alloc(mm, pgd, from); next = pgd_addr_end(addr, end);
error = -ENOMEM; err = remap_pud_range(mm, pgd, addr, next,
if (!pud) pfn + (addr >> PAGE_SHIFT), prot);
break; if (err)
next = (from + PGDIR_SIZE) & PGDIR_MASK;
if (next > end || next <= from)
next = end;
error = remap_pud_range(mm, pud, from, end - from,
pfn + (from >> PAGE_SHIFT), prot);
if (error)
break; break;
from = next; } while (pgd++, addr = next, addr != end);
pgd++;
}
/*
* Why flush? remap_pte_range has a BUG_ON for !pte_none()
*/
flush_tlb_range(vma, beg, end);
spin_unlock(&mm->page_table_lock); spin_unlock(&mm->page_table_lock);
return err;
return error;
} }
EXPORT_SYMBOL(remap_pfn_range); EXPORT_SYMBOL(remap_pfn_range);
/* /*
......
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