x86/paravirt: add a pgd_alloc/free hooks
authorJeremy Fitzhardinge <jeremy@goop.org>
Wed, 25 Jun 2008 04:19:12 +0000 (00:19 -0400)
committerIngo Molnar <mingo@elte.hu>
Tue, 8 Jul 2008 11:11:01 +0000 (13:11 +0200)
Add hooks which are called at pgd_alloc/free time.  The pgd_alloc hook
may return an error code, which if non-zero, causes the pgd allocation
to be failed.  The hooks may be used to allocate/free auxillary
per-pgd information.

also fix:

> * Ingo Molnar <mingo@elte.hu> wrote:
>
>  include/asm/pgalloc.h: In function â€˜paravirt_pgd_free':
>  include/asm/pgalloc.h:14: error: parameter name omitted
>  arch/x86/kernel/entry_64.S: In file included from
>  arch/x86/kernel/traps_64.c:51:include/asm/pgalloc.h: In function â€˜paravirt_pgd_free':
>  include/asm/pgalloc.h:14: error: parameter name omitted

Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com>
Cc: xen-devel <xen-devel@lists.xensource.com>
Cc: Stephen Tweedie <sct@redhat.com>
Cc: Eduardo Habkost <ehabkost@redhat.com>
Cc: Mark McLoughlin <markmc@redhat.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
arch/x86/kernel/paravirt.c
arch/x86/mm/pgtable.c
arch/x86/xen/enlighten.c
include/asm-x86/paravirt.h
include/asm-x86/pgalloc.h

index e9b5045372129b15a9edbda594b0296c84843db1..78c9a1b9e6b011df976cd333d3bab2574c94af1b 100644 (file)
@@ -30,6 +30,7 @@
 #include <asm/setup.h>
 #include <asm/arch_hooks.h>
 #include <asm/time.h>
+#include <asm/pgalloc.h>
 #include <asm/irq.h>
 #include <asm/delay.h>
 #include <asm/fixmap.h>
@@ -366,6 +367,9 @@ struct pv_mmu_ops pv_mmu_ops = {
        .flush_tlb_single = native_flush_tlb_single,
        .flush_tlb_others = native_flush_tlb_others,
 
+       .pgd_alloc = __paravirt_pgd_alloc,
+       .pgd_free = paravirt_nop,
+
        .alloc_pte = paravirt_nop,
        .alloc_pmd = paravirt_nop,
        .alloc_pmd_clone = paravirt_nop,
index 45b99ac394802cd28ed9c7014ca8a392a4d5a943..418c4432fb390510c9070a50d96063c5dd3c72af 100644 (file)
@@ -215,13 +215,15 @@ pgd_t *pgd_alloc(struct mm_struct *mm)
 
        /* so that alloc_pmd can use it */
        mm->pgd = pgd;
-       if (pgd)
+       if (pgd) {
                pgd_ctor(pgd);
 
-       if (pgd && !pgd_prepopulate_pmd(mm, pgd)) {
-               pgd_dtor(pgd);
-               free_page((unsigned long)pgd);
-               pgd = NULL;
+               if (paravirt_pgd_alloc(mm) != 0 ||
+                   !pgd_prepopulate_pmd(mm, pgd)) {
+                       pgd_dtor(pgd);
+                       free_page((unsigned long)pgd);
+                       pgd = NULL;
+               }
        }
 
        return pgd;
@@ -231,6 +233,7 @@ void pgd_free(struct mm_struct *mm, pgd_t *pgd)
 {
        pgd_mop_up_pmds(mm, pgd);
        pgd_dtor(pgd);
+       paravirt_pgd_free(mm, pgd);
        free_page((unsigned long)pgd);
 }
 
index 76ad1efaf09e9da019674e20aae3c99ea45652fb..d62f14e2070808b5a8dfe2338c981060f02f89e5 100644 (file)
@@ -45,6 +45,7 @@
 #include <asm/pgtable.h>
 #include <asm/tlbflush.h>
 #include <asm/reboot.h>
+#include <asm/pgalloc.h>
 
 #include "xen-ops.h"
 #include "mmu.h"
@@ -1153,6 +1154,9 @@ static const struct pv_mmu_ops xen_mmu_ops __initdata = {
        .pte_update = paravirt_nop,
        .pte_update_defer = paravirt_nop,
 
+       .pgd_alloc = __paravirt_pgd_alloc,
+       .pgd_free = paravirt_nop,
+
        .alloc_pte = xen_alloc_pte_init,
        .release_pte = xen_release_pte_init,
        .alloc_pmd = xen_alloc_pte_init,
index 41f5447efd88490800808fc4efda819e1ac54f7a..5467e2cff4bca8c4cac68d4580d52e400d2e8417 100644 (file)
@@ -219,7 +219,14 @@ struct pv_mmu_ops {
        void (*flush_tlb_others)(const cpumask_t *cpus, struct mm_struct *mm,
                                 unsigned long va);
 
-       /* Hooks for allocating/releasing pagetable pages */
+       /* Hooks for allocating and freeing a pagetable top-level */
+       int  (*pgd_alloc)(struct mm_struct *mm);
+       void (*pgd_free)(struct mm_struct *mm, pgd_t *pgd);
+
+       /*
+        * Hooks for allocating/releasing pagetable pages when they're
+        * attached to a pagetable
+        */
        void (*alloc_pte)(struct mm_struct *mm, u32 pfn);
        void (*alloc_pmd)(struct mm_struct *mm, u32 pfn);
        void (*alloc_pmd_clone)(u32 pfn, u32 clonepfn, u32 start, u32 count);
@@ -925,6 +932,16 @@ static inline void flush_tlb_others(cpumask_t cpumask, struct mm_struct *mm,
        PVOP_VCALL3(pv_mmu_ops.flush_tlb_others, &cpumask, mm, va);
 }
 
+static inline int paravirt_pgd_alloc(struct mm_struct *mm)
+{
+       return PVOP_CALL1(int, pv_mmu_ops.pgd_alloc, mm);
+}
+
+static inline void paravirt_pgd_free(struct mm_struct *mm, pgd_t *pgd)
+{
+       PVOP_VCALL2(pv_mmu_ops.pgd_free, mm, pgd);
+}
+
 static inline void paravirt_alloc_pte(struct mm_struct *mm, unsigned pfn)
 {
        PVOP_VCALL2(pv_mmu_ops.alloc_pte, mm, pfn);
index 91e4641f3f319de6072c63b436c17fb252c9e5b6..d63ea431cb3bbc974bec3fa3b22e5afff0194c17 100644 (file)
@@ -5,9 +5,13 @@
 #include <linux/mm.h>          /* for struct page */
 #include <linux/pagemap.h>
 
+static inline int  __paravirt_pgd_alloc(struct mm_struct *mm) { return 0; }
+
 #ifdef CONFIG_PARAVIRT
 #include <asm/paravirt.h>
 #else
+#define paravirt_pgd_alloc(mm) __paravirt_pgd_alloc(mm)
+static inline void paravirt_pgd_free(struct mm_struct *mm, pgd_t *pgd) {}
 static inline void paravirt_alloc_pte(struct mm_struct *mm, unsigned long pfn) {}
 static inline void paravirt_alloc_pmd(struct mm_struct *mm, unsigned long pfn) {}
 static inline void paravirt_alloc_pmd_clone(unsigned long pfn, unsigned long clonepfn,