Skip to content

Commit

Permalink
xen: avoid hypercalls when updating unpinned pud/pmd
Browse files Browse the repository at this point in the history
When operating on an unpinned pagetable (ie, one under construction or
destruction), it isn't necessary to use a hypercall to update a
pud/pmd entry.  Jan Beulich observed that a similar optimisation
avoided many thousands of hypercalls while doing a kernel build.

One tricky part is that early in the kernel boot there's no page
structure, so we can't check to see if the page is pinned.  In that
case, we just always use the hypercall.

Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com>
Cc: Jan Beulich <jbeulich@novell.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
  • Loading branch information
Jeremy Fitzhardinge authored and Ingo Molnar committed Jun 2, 2008
1 parent 15ce600 commit e2426cf
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 11 deletions.
14 changes: 11 additions & 3 deletions arch/x86/xen/enlighten.c
Original file line number Diff line number Diff line change
Expand Up @@ -901,6 +901,14 @@ static __init void xen_pagetable_setup_done(pgd_t *base)
pin_pagetable_pfn(MMUEXT_PIN_L3_TABLE, PFN_DOWN(__pa(base)));
}

static __init void xen_post_allocator_init(void)
{
pv_mmu_ops.set_pmd = xen_set_pmd;
pv_mmu_ops.set_pud = xen_set_pud;

xen_mark_init_mm_pinned();
}

/* This is called once we have the cpu_possible_map */
void xen_setup_vcpu_info_placement(void)
{
Expand Down Expand Up @@ -988,7 +996,7 @@ static const struct pv_init_ops xen_init_ops __initdata = {
.banner = xen_banner,
.memory_setup = xen_memory_setup,
.arch_setup = xen_arch_setup,
.post_allocator_init = xen_mark_init_mm_pinned,
.post_allocator_init = xen_post_allocator_init,
};

static const struct pv_time_ops xen_time_ops __initdata = {
Expand Down Expand Up @@ -1100,7 +1108,7 @@ static const struct pv_mmu_ops xen_mmu_ops __initdata = {

.set_pte = NULL, /* see xen_pagetable_setup_* */
.set_pte_at = xen_set_pte_at,
.set_pmd = xen_set_pmd,
.set_pmd = xen_set_pmd_hyper,

.pte_val = xen_pte_val,
.pte_flags = native_pte_val,
Expand All @@ -1111,7 +1119,7 @@ static const struct pv_mmu_ops xen_mmu_ops __initdata = {

.set_pte_atomic = xen_set_pte_atomic,
.set_pte_present = xen_set_pte_at,
.set_pud = xen_set_pud,
.set_pud = xen_set_pud_hyper,
.pte_clear = xen_pte_clear,
.pmd_clear = xen_pmd_clear,

Expand Down
39 changes: 35 additions & 4 deletions arch/x86/xen/mmu.c
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,14 @@ void make_lowmem_page_readwrite(void *vaddr)
}


void xen_set_pmd(pmd_t *ptr, pmd_t val)
static bool page_pinned(void *ptr)
{
struct page *page = virt_to_page(ptr);

return PagePinned(page);
}

void xen_set_pmd_hyper(pmd_t *ptr, pmd_t val)
{
struct multicall_space mcs;
struct mmu_update *u;
Expand All @@ -241,6 +248,18 @@ void xen_set_pmd(pmd_t *ptr, pmd_t val)
preempt_enable();
}

void xen_set_pmd(pmd_t *ptr, pmd_t val)
{
/* If page is not pinned, we can just update the entry
directly */
if (!page_pinned(ptr)) {
*ptr = val;
return;
}

xen_set_pmd_hyper(ptr, val);
}

/*
* Associate a virtual page frame with a given physical page frame
* and protection flags for that frame.
Expand Down Expand Up @@ -348,7 +367,7 @@ pmdval_t xen_pmd_val(pmd_t pmd)
return ret;
}

void xen_set_pud(pud_t *ptr, pud_t val)
void xen_set_pud_hyper(pud_t *ptr, pud_t val)
{
struct multicall_space mcs;
struct mmu_update *u;
Expand All @@ -366,6 +385,18 @@ void xen_set_pud(pud_t *ptr, pud_t val)
preempt_enable();
}

void xen_set_pud(pud_t *ptr, pud_t val)
{
/* If page is not pinned, we can just update the entry
directly */
if (!page_pinned(ptr)) {
*ptr = val;
return;
}

xen_set_pud_hyper(ptr, val);
}

void xen_set_pte(pte_t *ptep, pte_t pte)
{
ptep->pte_high = pte.pte_high;
Expand All @@ -387,7 +418,7 @@ void xen_pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep)

void xen_pmd_clear(pmd_t *pmdp)
{
xen_set_pmd(pmdp, __pmd(0));
set_pmd(pmdp, __pmd(0));
}

pmd_t xen_make_pmd(pmdval_t pmd)
Expand Down Expand Up @@ -758,7 +789,7 @@ void xen_exit_mmap(struct mm_struct *mm)
spin_lock(&mm->page_table_lock);

/* pgd may not be pinned in the error exit path of execve */
if (PagePinned(virt_to_page(mm->pgd)))
if (page_pinned(mm->pgd))
xen_pgd_unpin(mm->pgd);

spin_unlock(&mm->page_table_lock);
Expand Down
8 changes: 4 additions & 4 deletions arch/x86/xen/mmu.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,6 @@ enum pt_level {

void set_pte_mfn(unsigned long vaddr, unsigned long pfn, pgprot_t flags);

void xen_set_pte(pte_t *ptep, pte_t pteval);
void xen_set_pte_at(struct mm_struct *mm, unsigned long addr,
pte_t *ptep, pte_t pteval);
void xen_set_pmd(pmd_t *pmdp, pmd_t pmdval);

void xen_activate_mm(struct mm_struct *prev, struct mm_struct *next);
void xen_dup_mmap(struct mm_struct *oldmm, struct mm_struct *mm);
Expand All @@ -45,10 +41,14 @@ pte_t xen_make_pte(pteval_t);
pmd_t xen_make_pmd(pmdval_t);
pgd_t xen_make_pgd(pgdval_t);

void xen_set_pte(pte_t *ptep, pte_t pteval);
void xen_set_pte_at(struct mm_struct *mm, unsigned long addr,
pte_t *ptep, pte_t pteval);
void xen_set_pte_atomic(pte_t *ptep, pte_t pte);
void xen_set_pmd(pmd_t *pmdp, pmd_t pmdval);
void xen_set_pud(pud_t *ptr, pud_t val);
void xen_set_pmd_hyper(pmd_t *pmdp, pmd_t pmdval);
void xen_set_pud_hyper(pud_t *ptr, pud_t val);
void xen_pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep);
void xen_pmd_clear(pmd_t *pmdp);

Expand Down

0 comments on commit e2426cf

Please sign in to comment.