[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] Add generic_page_range() -- generic page table operation.
# HG changeset patch # User akw27@xxxxxxxxxxxxxxxxxxxxxx # Node ID 4ec947baae75285fcc7426b3ea618ae764c816e0 # Parent f2e0bbec3bf9661192f29861a237b9aca2d68a33 Add generic_page_range() -- generic page table operation. Linux has several instances of repeated code to do updates to a range of PTEs. Mapping memory between domains in Xen also tends to need to do this quite frequently, to ensure page tables have been constructed and to look up PTE addresses when making mapping-related hypercalls. This patch adds a generic PTE walk-and-fill operation that takes a function pointer to call on leaf entries. direct_remap_area_pages() is updated to use the new call, ass are abuses of __direct_remap_area_pages. This patch also introduces two new helper functions for working with page tables when mapping memory between domains: create_lookup_pte_addr() returns the machine address of a PTE, allocating intermediate page tables as necessary. touch_pte_range() ensures that page tables exist for a virtual address range. Many of the existing linux page table operations (e.g. zap/remap/etc) could be modified to use this interface, which would potentially shorten up mm/memory.c a bit. diff -r f2e0bbec3bf9 -r 4ec947baae75 linux-2.6-xen-sparse/arch/xen/i386/mm/ioremap.c --- a/linux-2.6-xen-sparse/arch/xen/i386/mm/ioremap.c Mon Aug 15 12:41:57 2005 +++ b/linux-2.6-xen-sparse/arch/xen/i386/mm/ioremap.c Mon Aug 15 13:16:04 2005 @@ -298,90 +298,20 @@ #define direct_mk_pte_phys(physpage, pgprot) \ __direct_mk_pte((physpage) >> PAGE_SHIFT, pgprot) -static inline void direct_remap_area_pte(pte_t *pte, - unsigned long address, - unsigned long size, - mmu_update_t **v) -{ - unsigned long end; - - address &= ~PMD_MASK; - end = address + size; - if (end > PMD_SIZE) - end = PMD_SIZE; - if (address >= end) - BUG(); - - do { - (*v)->ptr = virt_to_machine(pte); - (*v)++; - address += PAGE_SIZE; - pte++; - } while (address && (address < end)); -} - -static inline int direct_remap_area_pmd(struct mm_struct *mm, - pmd_t *pmd, - unsigned long address, - unsigned long size, - mmu_update_t **v) -{ - unsigned long end; - - address &= ~PGDIR_MASK; - end = address + size; - if (end > PGDIR_SIZE) - end = PGDIR_SIZE; - if (address >= end) - BUG(); - do { - pte_t *pte = (mm == &init_mm) ? - pte_alloc_kernel(mm, pmd, address) : - pte_alloc_map(mm, pmd, address); - if (!pte) - return -ENOMEM; - direct_remap_area_pte(pte, address, end - address, v); - pte_unmap(pte); - address = (address + PMD_SIZE) & PMD_MASK; - pmd++; - } while (address && (address < end)); - return 0; -} - -int __direct_remap_area_pages(struct mm_struct *mm, - unsigned long address, - unsigned long size, - mmu_update_t *v) -{ - pgd_t * dir; - unsigned long end = address + size; - int error; - - dir = pgd_offset(mm, address); - if (address >= end) - BUG(); - spin_lock(&mm->page_table_lock); - do { - pud_t *pud; - pmd_t *pmd; - - error = -ENOMEM; - pud = pud_alloc(mm, dir, address); - if (!pud) - break; - pmd = pmd_alloc(mm, pud, address); - if (!pmd) - break; - error = 0; - direct_remap_area_pmd(mm, pmd, address, end - address, &v); - address = (address + PGDIR_SIZE) & PGDIR_MASK; - dir++; - - } while (address && (address < end)); - spin_unlock(&mm->page_table_lock); - return error; -} - + +static int direct_remap_area_pte_fn(pte_t *pte, + struct page *pte_page, + unsigned long address, + void *data) +{ + mmu_update_t **v = (mmu_update_t **)data; + + (*v)->ptr = (pfn_to_mfn(page_to_pfn(pte_page)) << PAGE_SHIFT) + | ((unsigned long)pte & ~PAGE_MASK); + (*v)++; + + return 0; +} int direct_remap_area_pages(struct mm_struct *mm, unsigned long address, @@ -393,7 +323,7 @@ int i; unsigned long start_address; #define MAX_DIRECTMAP_MMU_QUEUE 130 - mmu_update_t u[MAX_DIRECTMAP_MMU_QUEUE], *v = u; + mmu_update_t u[MAX_DIRECTMAP_MMU_QUEUE], *v = u, *w = u; start_address = address; @@ -402,10 +332,9 @@ for (i = 0; i < size; i += PAGE_SIZE) { if ((v - u) == MAX_DIRECTMAP_MMU_QUEUE) { /* Fill in the PTE pointers. */ - __direct_remap_area_pages(mm, - start_address, - address-start_address, - u); + generic_page_range(mm, start_address, + address-start_address, + direct_remap_area_pte_fn, &w); if (HYPERVISOR_mmu_update(u, v - u, NULL, domid) < 0) return -EFAULT; @@ -426,10 +355,9 @@ if (v != u) { /* get the ptep's filled in */ - __direct_remap_area_pages(mm, - start_address, - address-start_address, - u); + generic_page_range(mm, start_address, + address-start_address, + direct_remap_area_pte_fn, &w); if (unlikely(HYPERVISOR_mmu_update(u, v - u, NULL, domid) < 0)) return -EFAULT; } @@ -440,3 +368,34 @@ } EXPORT_SYMBOL(direct_remap_area_pages); + +int create_lookup_pte_addr(struct mm_struct *mm, + unsigned long address, + unsigned long *ptep) +{ + int f(pte_t *pte, struct page *pte_page, unsigned long addr, void *data) + { + unsigned long *ptep = (unsigned long *)data; + if (ptep) *ptep = (pfn_to_mfn(page_to_pfn(pte_page)) << PAGE_SHIFT) + | ((unsigned long)pte & ~PAGE_MASK); + return 0; + } + + return generic_page_range(mm, address, PAGE_SIZE, f, ptep); +} + +EXPORT_SYMBOL(create_lookup_pte_addr); + +int touch_pte_range(struct mm_struct *mm, + unsigned long address, + unsigned long size) +{ + int f(pte_t *pte, struct page *pte_page, unsigned long addr, void *data) + { + return 0; + } + + return generic_page_range(mm, address, size, f, NULL); +} + +EXPORT_SYMBOL(touch_pte_range); diff -r f2e0bbec3bf9 -r 4ec947baae75 linux-2.6-xen-sparse/arch/xen/x86_64/mm/ioremap.c --- a/linux-2.6-xen-sparse/arch/xen/x86_64/mm/ioremap.c Mon Aug 15 12:41:57 2005 +++ b/linux-2.6-xen-sparse/arch/xen/x86_64/mm/ioremap.c Mon Aug 15 13:16:04 2005 @@ -464,3 +464,34 @@ } EXPORT_SYMBOL(direct_remap_area_pages); + +int create_lookup_pte_addr(struct mm_struct *mm, + unsigned long address, + unsigned long *ptep) +{ + int f(pte_t *pte, struct page *pte_page, unsigned long addr, void *data) + { + unsigned long *ptep = (unsigned long *)data; + if (ptep) *ptep = (pfn_to_mfn(page_to_pfn(pte_page)) << PAGE_SHIFT) + | ((unsigned long)pte & ~PAGE_MASK); + return 0; + } + + return generic_page_range(mm, address, PAGE_SIZE, f, ptep); +} + +EXPORT_SYMBOL(create_lookup_pte_addr); + +int touch_pte_range(struct mm_struct *mm, + unsigned long address, + unsigned long size) +{ + int f(pte_t *pte, struct page *pte_page, unsigned long addr, void *data) + { + return 0; + } + + return generic_page_range(mm, address, size, f, NULL); +} + +EXPORT_SYMBOL(touch_pte_range); diff -r f2e0bbec3bf9 -r 4ec947baae75 linux-2.6-xen-sparse/drivers/xen/privcmd/privcmd.c --- a/linux-2.6-xen-sparse/drivers/xen/privcmd/privcmd.c Mon Aug 15 12:41:57 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/privcmd/privcmd.c Mon Aug 15 13:16:04 2005 @@ -139,7 +139,7 @@ privcmd_mmapbatch_t m; struct vm_area_struct *vma = NULL; unsigned long *p, addr; - unsigned long mfn; + unsigned long mfn, ptep; int i; if ( copy_from_user(&m, (void *)data, sizeof(m)) ) @@ -163,12 +163,12 @@ if ( get_user(mfn, p) ) return -EFAULT; + ret = create_lookup_pte_addr(vma->vm_mm, addr, &ptep); + if (ret) + goto batch_err; + u.val = (mfn << PAGE_SHIFT) | pgprot_val(vma->vm_page_prot); - - __direct_remap_area_pages(vma->vm_mm, - addr, - PAGE_SIZE, - &u); + u.ptr = ptep; if ( unlikely(HYPERVISOR_mmu_update(&u, 1, NULL, m.dom) < 0) ) put_user(0xF0000000 | mfn, p); diff -r f2e0bbec3bf9 -r 4ec947baae75 linux-2.6-xen-sparse/include/asm-xen/asm-i386/pgtable.h --- a/linux-2.6-xen-sparse/include/asm-xen/asm-i386/pgtable.h Mon Aug 15 12:41:57 2005 +++ b/linux-2.6-xen-sparse/include/asm-xen/asm-i386/pgtable.h Mon Aug 15 13:16:04 2005 @@ -466,10 +466,12 @@ unsigned long size, pgprot_t prot, domid_t domid); -int __direct_remap_area_pages(struct mm_struct *mm, - unsigned long address, - unsigned long size, - mmu_update_t *v); +int create_lookup_pte_addr(struct mm_struct *mm, + unsigned long address, + unsigned long *ptep); +int touch_pte_range(struct mm_struct *mm, + unsigned long address, + unsigned long size); #define io_remap_page_range(vma,from,phys,size,prot) \ direct_remap_area_pages(vma->vm_mm,from,phys,size,prot,DOMID_IO) diff -r f2e0bbec3bf9 -r 4ec947baae75 linux-2.6-xen-sparse/include/asm-xen/asm-x86_64/pgtable.h --- a/linux-2.6-xen-sparse/include/asm-xen/asm-x86_64/pgtable.h Mon Aug 15 12:41:57 2005 +++ b/linux-2.6-xen-sparse/include/asm-xen/asm-x86_64/pgtable.h Mon Aug 15 13:16:04 2005 @@ -538,6 +538,12 @@ unsigned long address, unsigned long size, mmu_update_t *v); +int create_lookup_pte_addr(struct mm_struct *mm, + unsigned long address, + unsigned long *ptep); +int touch_pte_range(struct mm_struct *mm, + unsigned long address, + unsigned long size); #define io_remap_page_range(vma, vaddr, paddr, size, prot) \ direct_remap_area_pages((vma)->vm_mm,vaddr,paddr,size,prot,DOMID_IO) diff -r f2e0bbec3bf9 -r 4ec947baae75 linux-2.6-xen-sparse/include/linux/mm.h --- a/linux-2.6-xen-sparse/include/linux/mm.h Mon Aug 15 12:41:57 2005 +++ b/linux-2.6-xen-sparse/include/linux/mm.h Mon Aug 15 13:16:04 2005 @@ -817,6 +817,12 @@ int remap_pfn_range(struct vm_area_struct *, unsigned long, unsigned long, unsigned long, pgprot_t); +typedef int (*pte_fn_t)(pte_t *pte, struct page *pte_page, unsigned long addr, + void *data); +extern int generic_page_range(struct mm_struct *mm, unsigned long address, + unsigned long size, pte_fn_t fn, void *data); + + #ifdef CONFIG_PROC_FS void __vm_stat_account(struct mm_struct *, unsigned long, struct file *, long); #else diff -r f2e0bbec3bf9 -r 4ec947baae75 linux-2.6-xen-sparse/mm/memory.c --- a/linux-2.6-xen-sparse/mm/memory.c Mon Aug 15 12:41:57 2005 +++ b/linux-2.6-xen-sparse/mm/memory.c Mon Aug 15 13:16:04 2005 @@ -954,8 +954,10 @@ i++; start += PAGE_SIZE; len--; +printk(KERN_ALERT "HIT 0x%lx\n", start); continue; - } + } +else printk(KERN_ALERT "MISS 0x%lx\n", start); } if (!vma || (vma->vm_flags & VM_IO) @@ -1213,6 +1215,104 @@ } EXPORT_SYMBOL(remap_pfn_range); +static inline int generic_pte_range(struct mm_struct *mm, + pmd_t *pmd, + unsigned long addr, + unsigned long end, + pte_fn_t fn, void *data) +{ + pte_t *pte; + int err; + struct page *pte_page; + + pte = (mm == &init_mm) ? + pte_alloc_kernel(mm, pmd, addr) : + pte_alloc_map(mm, pmd, addr); + if (!pte) + return -ENOMEM; + + pte_page = pmd_page(*pmd); + + do { + err = fn(pte, pte_page, addr, data); + if (err) + break; + } while (pte++, addr += PAGE_SIZE, addr != end); + + if (mm != &init_mm) + pte_unmap(pte-1); + return err; + +} + +static inline int generic_pmd_range(struct mm_struct *mm, + pud_t *pud, + unsigned long addr, + unsigned long end, + pte_fn_t fn, void *data) +{ + pmd_t *pmd; + unsigned long next; + int err; + + pmd = pmd_alloc(mm, pud, addr); + if (!pmd) + return -ENOMEM; + do { + next = pmd_addr_end(addr, end); + err = generic_pte_range(mm, pmd, addr, next, fn, data); + if (err) + break; + } while (pmd++, addr = next, addr != end); + return err; +} + +static inline int generic_pud_range(struct mm_struct *mm, pgd_t *pgd, + unsigned long addr, + unsigned long end, + pte_fn_t fn, void *data) +{ + pud_t *pud; + unsigned long next; + int err; + + pud = pud_alloc(mm, pgd, addr); + if (!pud) + return -ENOMEM; + do { + next = pud_addr_end(addr, end); + err = generic_pmd_range(mm, pud, addr, next, fn, data); + if (err) + break; + } while (pud++, addr = next, addr != end); + return err; +} + +/* + * Scan a region of virtual memory, filling in page tables as necessary + * and calling a provided function on each leaf page table. + */ +int generic_page_range(struct mm_struct *mm, unsigned long addr, + unsigned long size, pte_fn_t fn, void *data) +{ + pgd_t *pgd; + unsigned long next; + unsigned long end = addr + size; + int err; + + BUG_ON(addr >= end); + pgd = pgd_offset(mm, addr); + spin_lock(&mm->page_table_lock); + do { + next = pgd_addr_end(addr, end); + err = generic_pud_range(mm, pgd, addr, next, fn, data); + if (err) + break; + } while (pgd++, addr = next, addr != end); + spin_unlock(&mm->page_table_lock); + return err; +} + /* * Do pte_mkwrite, but only if the vma says VM_WRITE. We do this when * servicing faults for write access. In the normal case, do always want _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |