x86: unify pgd ctor/dtor
All pagetables need fundamentally the same setup and destruction, so just use the same code for everything. Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com> Cc: Andi Kleen <ak@suse.de> Signed-off-by: Ingo Molnar <mingo@elte.hu> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
This commit is contained in:
committed by
Ingo Molnar
parent
68db065c84
commit
85958b465c
@@ -59,50 +59,6 @@ static inline void pgd_list_del(pgd_t *pgd)
|
|||||||
list_del(&page->lru);
|
list_del(&page->lru);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_X86_64
|
|
||||||
pgd_t *pgd_alloc(struct mm_struct *mm)
|
|
||||||
{
|
|
||||||
unsigned boundary;
|
|
||||||
pgd_t *pgd = (pgd_t *)__get_free_page(GFP_KERNEL|__GFP_REPEAT);
|
|
||||||
unsigned long flags;
|
|
||||||
if (!pgd)
|
|
||||||
return NULL;
|
|
||||||
spin_lock_irqsave(&pgd_lock, flags);
|
|
||||||
pgd_list_add(pgd);
|
|
||||||
spin_unlock_irqrestore(&pgd_lock, flags);
|
|
||||||
/*
|
|
||||||
* Copy kernel pointers in from init.
|
|
||||||
* Could keep a freelist or slab cache of those because the kernel
|
|
||||||
* part never changes.
|
|
||||||
*/
|
|
||||||
boundary = pgd_index(__PAGE_OFFSET);
|
|
||||||
memset(pgd, 0, boundary * sizeof(pgd_t));
|
|
||||||
memcpy(pgd + boundary,
|
|
||||||
init_level4_pgt + boundary,
|
|
||||||
(PTRS_PER_PGD - boundary) * sizeof(pgd_t));
|
|
||||||
return pgd;
|
|
||||||
}
|
|
||||||
|
|
||||||
void pgd_free(struct mm_struct *mm, pgd_t *pgd)
|
|
||||||
{
|
|
||||||
unsigned long flags;
|
|
||||||
BUG_ON((unsigned long)pgd & (PAGE_SIZE-1));
|
|
||||||
spin_lock_irqsave(&pgd_lock, flags);
|
|
||||||
pgd_list_del(pgd);
|
|
||||||
spin_unlock_irqrestore(&pgd_lock, flags);
|
|
||||||
free_page((unsigned long)pgd);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
/*
|
|
||||||
* List of all pgd's needed for non-PAE so it can invalidate entries
|
|
||||||
* in both cached and uncached pgd's; not needed for PAE since the
|
|
||||||
* kernel pmd is shared. If PAE were not to share the pmd a similar
|
|
||||||
* tactic would be needed. This is essentially codepath-based locking
|
|
||||||
* against pageattr.c; it is the unique case in which a valid change
|
|
||||||
* of kernel pagetables can't be lazily synchronized by vmalloc faults.
|
|
||||||
* vmalloc faults work because attached pagetables are never freed.
|
|
||||||
* -- wli
|
|
||||||
*/
|
|
||||||
#define UNSHARED_PTRS_PER_PGD \
|
#define UNSHARED_PTRS_PER_PGD \
|
||||||
(SHARED_KERNEL_PMD ? KERNEL_PGD_BOUNDARY : PTRS_PER_PGD)
|
(SHARED_KERNEL_PMD ? KERNEL_PGD_BOUNDARY : PTRS_PER_PGD)
|
||||||
|
|
||||||
@@ -120,7 +76,8 @@ static void pgd_ctor(void *p)
|
|||||||
ptes in non-PAE, or shared PMD in PAE), then just copy the
|
ptes in non-PAE, or shared PMD in PAE), then just copy the
|
||||||
references from swapper_pg_dir. */
|
references from swapper_pg_dir. */
|
||||||
if (PAGETABLE_LEVELS == 2 ||
|
if (PAGETABLE_LEVELS == 2 ||
|
||||||
(PAGETABLE_LEVELS == 3 && SHARED_KERNEL_PMD)) {
|
(PAGETABLE_LEVELS == 3 && SHARED_KERNEL_PMD) ||
|
||||||
|
PAGETABLE_LEVELS == 4) {
|
||||||
clone_pgd_range(pgd + KERNEL_PGD_BOUNDARY,
|
clone_pgd_range(pgd + KERNEL_PGD_BOUNDARY,
|
||||||
swapper_pg_dir + KERNEL_PGD_BOUNDARY,
|
swapper_pg_dir + KERNEL_PGD_BOUNDARY,
|
||||||
KERNEL_PGD_PTRS);
|
KERNEL_PGD_PTRS);
|
||||||
@@ -149,6 +106,17 @@ static void pgd_dtor(void *pgd)
|
|||||||
spin_unlock_irqrestore(&pgd_lock, flags);
|
spin_unlock_irqrestore(&pgd_lock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* List of all pgd's needed for non-PAE so it can invalidate entries
|
||||||
|
* in both cached and uncached pgd's; not needed for PAE since the
|
||||||
|
* kernel pmd is shared. If PAE were not to share the pmd a similar
|
||||||
|
* tactic would be needed. This is essentially codepath-based locking
|
||||||
|
* against pageattr.c; it is the unique case in which a valid change
|
||||||
|
* of kernel pagetables can't be lazily synchronized by vmalloc faults.
|
||||||
|
* vmalloc faults work because attached pagetables are never freed.
|
||||||
|
* -- wli
|
||||||
|
*/
|
||||||
|
|
||||||
#ifdef CONFIG_X86_PAE
|
#ifdef CONFIG_X86_PAE
|
||||||
/*
|
/*
|
||||||
* Mop up any pmd pages which may still be attached to the pgd.
|
* Mop up any pmd pages which may still be attached to the pgd.
|
||||||
@@ -264,7 +232,6 @@ void pgd_free(struct mm_struct *mm, pgd_t *pgd)
|
|||||||
pgd_dtor(pgd);
|
pgd_dtor(pgd);
|
||||||
free_page((unsigned long)pgd);
|
free_page((unsigned long)pgd);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
int ptep_set_access_flags(struct vm_area_struct *vma,
|
int ptep_set_access_flags(struct vm_area_struct *vma,
|
||||||
unsigned long address, pte_t *ptep,
|
unsigned long address, pte_t *ptep,
|
||||||
|
@@ -438,6 +438,22 @@ static inline void ptep_set_wrprotect(struct mm_struct *mm,
|
|||||||
pte_update(mm, addr, ptep);
|
pte_update(mm, addr, ptep);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* clone_pgd_range(pgd_t *dst, pgd_t *src, int count);
|
||||||
|
*
|
||||||
|
* dst - pointer to pgd range anwhere on a pgd page
|
||||||
|
* src - ""
|
||||||
|
* count - the number of pgds to copy.
|
||||||
|
*
|
||||||
|
* dst and src can be on the same page, but the range must not overlap,
|
||||||
|
* and must not cross a page boundary.
|
||||||
|
*/
|
||||||
|
static inline void clone_pgd_range(pgd_t *dst, pgd_t *src, int count)
|
||||||
|
{
|
||||||
|
memcpy(dst, src, count * sizeof(pgd_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#include <asm-generic/pgtable.h>
|
#include <asm-generic/pgtable.h>
|
||||||
#endif /* __ASSEMBLY__ */
|
#endif /* __ASSEMBLY__ */
|
||||||
|
|
||||||
|
@@ -105,21 +105,6 @@ extern int pmd_bad(pmd_t pmd);
|
|||||||
# include <asm/pgtable-2level.h>
|
# include <asm/pgtable-2level.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
|
||||||
* clone_pgd_range(pgd_t *dst, pgd_t *src, int count);
|
|
||||||
*
|
|
||||||
* dst - pointer to pgd range anwhere on a pgd page
|
|
||||||
* src - ""
|
|
||||||
* count - the number of pgds to copy.
|
|
||||||
*
|
|
||||||
* dst and src can be on the same page, but the range must not overlap,
|
|
||||||
* and must not cross a page boundary.
|
|
||||||
*/
|
|
||||||
static inline void clone_pgd_range(pgd_t *dst, pgd_t *src, int count)
|
|
||||||
{
|
|
||||||
memcpy(dst, src, count * sizeof(pgd_t));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Macro to mark a page protection value as "uncacheable".
|
* Macro to mark a page protection value as "uncacheable".
|
||||||
* On processors which do not support it, this is a no-op.
|
* On processors which do not support it, this is a no-op.
|
||||||
|
@@ -24,7 +24,7 @@ extern void paging_init(void);
|
|||||||
|
|
||||||
#endif /* !__ASSEMBLY__ */
|
#endif /* !__ASSEMBLY__ */
|
||||||
|
|
||||||
#define SHARED_KERNEL_PMD 1
|
#define SHARED_KERNEL_PMD 0
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* PGDIR_SHIFT determines what a top-level page table entry can map
|
* PGDIR_SHIFT determines what a top-level page table entry can map
|
||||||
|
Reference in New Issue
Block a user