Merge tag 'v4.0-rc1' into x86/mm, to refresh the tree
authorIngo Molnar <mingo@kernel.org>
Tue, 24 Feb 2015 14:55:28 +0000 (15:55 +0100)
committerIngo Molnar <mingo@kernel.org>
Tue, 24 Feb 2015 14:55:28 +0000 (15:55 +0100)
Signed-off-by: Ingo Molnar <mingo@kernel.org>
1  2 
arch/x86/mm/pgtable.c

diff --combined arch/x86/mm/pgtable.c
index d223e1fe1dd2b47173c9b9a675cc856b7fe0cd70,7b22adaad4f1379a1195aec23b38a28a8db83f5c..5a7e5252c878bdcd2e45a11257adc15763cdea5f
@@@ -190,7 -190,7 +190,7 @@@ void pud_populate(struct mm_struct *mm
  
  #endif        /* CONFIG_X86_PAE */
  
- static void free_pmds(pmd_t *pmds[])
+ static void free_pmds(struct mm_struct *mm, pmd_t *pmds[])
  {
        int i;
  
                if (pmds[i]) {
                        pgtable_pmd_page_dtor(virt_to_page(pmds[i]));
                        free_page((unsigned long)pmds[i]);
+                       mm_dec_nr_pmds(mm);
                }
  }
  
- static int preallocate_pmds(pmd_t *pmds[])
+ static int preallocate_pmds(struct mm_struct *mm, pmd_t *pmds[])
  {
        int i;
        bool failed = false;
                        pmd = NULL;
                        failed = true;
                }
+               if (pmd)
+                       mm_inc_nr_pmds(mm);
                pmds[i] = pmd;
        }
  
        if (failed) {
-               free_pmds(pmds);
+               free_pmds(mm, pmds);
                return -ENOMEM;
        }
  
@@@ -246,6 -249,7 +249,7 @@@ static void pgd_mop_up_pmds(struct mm_s
  
                        paravirt_release_pmd(pgd_val(pgd) >> PAGE_SHIFT);
                        pmd_free(mm, pmd);
+                       mm_dec_nr_pmds(mm);
                }
        }
  }
@@@ -271,94 -275,19 +275,94 @@@ static void pgd_prepopulate_pmd(struct 
        }
  }
  
 +/*
 + * Xen paravirt assumes pgd table should be in one page. 64 bit kernel also
 + * assumes that pgd should be in one page.
 + *
 + * But kernel with PAE paging that is not running as a Xen domain
 + * only needs to allocate 32 bytes for pgd instead of one page.
 + */
 +#ifdef CONFIG_X86_PAE
 +
 +#include <linux/slab.h>
 +
 +#define PGD_SIZE      (PTRS_PER_PGD * sizeof(pgd_t))
 +#define PGD_ALIGN     32
 +
 +static struct kmem_cache *pgd_cache;
 +
 +static int __init pgd_cache_init(void)
 +{
 +      /*
 +       * When PAE kernel is running as a Xen domain, it does not use
 +       * shared kernel pmd. And this requires a whole page for pgd.
 +       */
 +      if (!SHARED_KERNEL_PMD)
 +              return 0;
 +
 +      /*
 +       * when PAE kernel is not running as a Xen domain, it uses
 +       * shared kernel pmd. Shared kernel pmd does not require a whole
 +       * page for pgd. We are able to just allocate a 32-byte for pgd.
 +       * During boot time, we create a 32-byte slab for pgd table allocation.
 +       */
 +      pgd_cache = kmem_cache_create("pgd_cache", PGD_SIZE, PGD_ALIGN,
 +                                    SLAB_PANIC, NULL);
 +      if (!pgd_cache)
 +              return -ENOMEM;
 +
 +      return 0;
 +}
 +core_initcall(pgd_cache_init);
 +
 +static inline pgd_t *_pgd_alloc(void)
 +{
 +      /*
 +       * If no SHARED_KERNEL_PMD, PAE kernel is running as a Xen domain.
 +       * We allocate one page for pgd.
 +       */
 +      if (!SHARED_KERNEL_PMD)
 +              return (pgd_t *)__get_free_page(PGALLOC_GFP);
 +
 +      /*
 +       * Now PAE kernel is not running as a Xen domain. We can allocate
 +       * a 32-byte slab for pgd to save memory space.
 +       */
 +      return kmem_cache_alloc(pgd_cache, PGALLOC_GFP);
 +}
 +
 +static inline void _pgd_free(pgd_t *pgd)
 +{
 +      if (!SHARED_KERNEL_PMD)
 +              free_page((unsigned long)pgd);
 +      else
 +              kmem_cache_free(pgd_cache, pgd);
 +}
 +#else
 +static inline pgd_t *_pgd_alloc(void)
 +{
 +      return (pgd_t *)__get_free_page(PGALLOC_GFP);
 +}
 +
 +static inline void _pgd_free(pgd_t *pgd)
 +{
 +      free_page((unsigned long)pgd);
 +}
 +#endif /* CONFIG_X86_PAE */
 +
  pgd_t *pgd_alloc(struct mm_struct *mm)
  {
        pgd_t *pgd;
        pmd_t *pmds[PREALLOCATED_PMDS];
  
 -      pgd = (pgd_t *)__get_free_page(PGALLOC_GFP);
 +      pgd = _pgd_alloc();
  
        if (pgd == NULL)
                goto out;
  
        mm->pgd = pgd;
  
-       if (preallocate_pmds(pmds) != 0)
+       if (preallocate_pmds(mm, pmds) != 0)
                goto out_free_pgd;
  
        if (paravirt_pgd_alloc(mm) != 0)
        return pgd;
  
  out_free_pmds:
-       free_pmds(pmds);
+       free_pmds(mm, pmds);
  out_free_pgd:
 -      free_page((unsigned long)pgd);
 +      _pgd_free(pgd);
  out:
        return NULL;
  }
@@@ -391,7 -320,7 +395,7 @@@ void pgd_free(struct mm_struct *mm, pgd
        pgd_mop_up_pmds(mm, pgd);
        pgd_dtor(pgd);
        paravirt_pgd_free(mm, pgd);
 -      free_page((unsigned long)pgd);
 +      _pgd_free(pgd);
  }
  
  /*