# HG changeset patch
# User Keir Fraser <keir.fraser@xxxxxxxxxx>
# Date 1285009903 -3600
# Node ID 7167d6dd5c7c6597ca8e2ce416295b44fb1bcf65
# Parent 9cebb977e9d8ec1356344e619d73fb66ff8cfad1
x86: Retry do_mmu_update() a few times when called on a pte whose type is in
flux.
This can really happen -- all our PV Linux kernels have a race
between vmalloc_sync_all() and pgdir pinning/unpinning. The former is
protected by pgd_lock while the latter by mm->page_table_lock. Hence
they can happen concurrently, and vmalloc_sync_all() can attempt to
set_pmd() on a page directory which is in the process of being
pinned. This can confuse the hypervisor which may see a type change,
and hence fail do_mmu_update(). Until this patch. :-)
Signed-off-by: Keir Fraser <keir.fraser@xxxxxxxxxx>
---
xen/arch/x86/mm.c | 7 +++++++
1 files changed, 7 insertions(+)
diff -r 9cebb977e9d8 -r 7167d6dd5c7c xen/arch/x86/mm.c
--- a/xen/arch/x86/mm.c Mon Sep 20 18:53:18 2010 +0100
+++ b/xen/arch/x86/mm.c Mon Sep 20 20:11:43 2010 +0100
@@ -3414,6 +3414,7 @@ int do_mmu_update(
case MMU_NORMAL_PT_UPDATE:
case MMU_PT_UPDATE_PRESERVE_AD:
{
+ unsigned int retries = 0;
p2m_type_t p2mt;
rc = xsm_mmu_normal_update(d, pg_owner, req.val);
@@ -3445,6 +3446,7 @@ int do_mmu_update(
(unsigned long)(req.ptr & ~PAGE_MASK));
page = mfn_to_page(mfn);
+ retry:
if ( page_lock(page) )
{
switch ( page->u.inuse.type_info & PGT_type_mask )
@@ -3601,6 +3603,11 @@ int do_mmu_update(
v, va, req.val, _mfn(mfn));
put_page_type(page);
}
+ else if ( retries++ < 5 )
+ {
+ /* Page type can be in flux, so we retry a few times. */
+ goto retry;
+ }
unmap_domain_page_with_cache(va, &mapcache);
put_page(page);
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|