Commit 85958b46 authored by Jeremy Fitzhardinge's avatar Jeremy Fitzhardinge Committed by Ingo Molnar
Browse files

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: default avatarJeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com>
Cc: Andi Kleen <ak@suse.de>
Signed-off-by: default avatarIngo Molnar <mingo@elte.hu>
Signed-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
parent 68db065c
Loading
Loading
Loading
Loading
+13 −46
Original line number Diff line number Diff line
@@ -59,50 +59,6 @@ static inline void pgd_list_del(pgd_t *pgd)
	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				\
	(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
	   references from swapper_pg_dir. */
	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,
				swapper_pg_dir + KERNEL_PGD_BOUNDARY,
				KERNEL_PGD_PTRS);
@@ -149,6 +106,17 @@ static void pgd_dtor(void *pgd)
	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
/*
 * 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);
	free_page((unsigned long)pgd);
}
#endif

int ptep_set_access_flags(struct vm_area_struct *vma,
			  unsigned long address, pte_t *ptep,
+16 −0
Original line number Diff line number Diff line
@@ -438,6 +438,22 @@ static inline void ptep_set_wrprotect(struct mm_struct *mm,
	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>
#endif	/* __ASSEMBLY__ */

+0 −15
Original line number Diff line number Diff line
@@ -105,21 +105,6 @@ extern int pmd_bad(pmd_t pmd);
# include <asm/pgtable-2level.h>
#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".
 * On processors which do not support it, this is a no-op.
+1 −1
Original line number Diff line number Diff line
@@ -24,7 +24,7 @@ extern void paging_init(void);

#endif /* !__ASSEMBLY__ */

#define SHARED_KERNEL_PMD	1
#define SHARED_KERNEL_PMD	0

/*
 * PGDIR_SHIFT determines what a top-level page table entry can map