diff -r bf74d9c31674 xen/arch/x86/mm/shadow/multi.c --- a/xen/arch/x86/mm/shadow/multi.c Mon Apr 12 07:23:21 2010 +0100 +++ b/xen/arch/x86/mm/shadow/multi.c Mon Apr 12 17:04:14 2010 +0100 @@ -241,6 +241,27 @@ return !mismatch; } +static int +shadow_check_gl1e(struct vcpu *v, walk_t *gw) +{ + guest_l1e_t *l1p = NULL; + guest_l1e_t nl1e; + + if ( mfn_valid(gw->l1mfn) ) + { + + /* Can't just pull-through because mfn may have changed */ + l1p = map_domain_page(mfn_x(gw->l1mfn)); + nl1e.l1 = l1p[guest_l1_table_offset(gw->va)].l1; + unmap_domain_page(l1p); + + return gw->l1e.l1 != nl1e.l1; + } + else + return 0; +} + + /* Remove write access permissions from a gwalk_t in a batch, and * return OR-ed result for TLB flush hint and need to rewalk the guest * pages. @@ -3237,6 +3258,15 @@ shadow_unlock(d); return 0; } + + /* Final check: if someone has synced a page, it's possible that + * our l1e is stale. Compare the entries, and rewalk if necessary. */ + if ( shadow_check_gl1e(v, &gw) ) + { + perfc_incr(shadow_inconsistent_gwalk); + shadow_unlock(d); + goto rewalk; + } #endif /* OOS */ /* Calculate the shadow entry and write it */