WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-changelog

[Xen-changelog] Add generic_page_range() -- generic page table operation

To: xen-changelog@xxxxxxxxxxxxxxxxxxx
Subject: [Xen-changelog] Add generic_page_range() -- generic page table operation.
From: Xen patchbot -unstable <patchbot-unstable@xxxxxxxxxxxxxxxxxxx>
Date: Mon, 15 Aug 2005 12:54:11 -0400
Delivery-date: Mon, 15 Aug 2005 16:56:57 +0000
Envelope-to: www-data@xxxxxxxxxxxxxxxxxxx
List-help: <mailto:xen-changelog-request@lists.xensource.com?subject=help>
List-id: BK change log <xen-changelog.lists.xensource.com>
List-post: <mailto:xen-changelog@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=unsubscribe>
Reply-to: xen-devel@xxxxxxxxxxxxxxxxxxx
Sender: xen-changelog-bounces@xxxxxxxxxxxxxxxxxxx
# 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

<Prev in Thread] Current Thread [Next in Thread>
  • [Xen-changelog] Add generic_page_range() -- generic page table operation., Xen patchbot -unstable <=