diff options
author | George Dunlap <gdunlap@xensource.com> | 2007-09-19 11:58:04 +0100 |
---|---|---|
committer | George Dunlap <gdunlap@xensource.com> | 2007-09-19 11:58:04 +0100 |
commit | f0ad89dd9dfe20f03c6b49845a04521086ef32a2 (patch) | |
tree | 18e4dc7053b30fc63ddbf0cc01c344a49dcb31bf | |
parent | c8822fb01990bf7f48c02d9cc159ea40655c7d16 (diff) | |
download | xen-f0ad89dd9dfe20f03c6b49845a04521086ef32a2.tar.gz xen-f0ad89dd9dfe20f03c6b49845a04521086ef32a2.tar.bz2 xen-f0ad89dd9dfe20f03c6b49845a04521086ef32a2.zip |
[shadow] Be smarter about what we check to avoid unnecessary brute-force searches
The old code checked only if the page was still a pagetable before
doing a brute-force search, rather than checking if it was still
shadowed as the type indicated. This meant that if a page was shadowed
as two different types, it was guaranteed to do a full brute-force search
even if all references could be found by up-pointers.
This checks the proper thing so that it will only do a brute-force if
necessary.
It also re-orders the unshadows so that higher levels are done first. In
many cases, lower-level shadows will be destroyed in the process of
higher-level shadows being destroyed, again saving brute-force searches.
-rw-r--r-- | xen/arch/x86/mm/shadow/common.c | 59 |
1 files changed, 31 insertions, 28 deletions
diff --git a/xen/arch/x86/mm/shadow/common.c b/xen/arch/x86/mm/shadow/common.c index 4d1bac1516..04bc55deb4 100644 --- a/xen/arch/x86/mm/shadow/common.c +++ b/xen/arch/x86/mm/shadow/common.c @@ -1981,7 +1981,6 @@ void sh_remove_shadows(struct vcpu *v, mfn_t gmfn, int fast, int all) { struct page_info *pg = mfn_to_page(gmfn); mfn_t smfn; - u32 sh_flags; int do_locking; unsigned char t; @@ -2065,42 +2064,46 @@ void sh_remove_shadows(struct vcpu *v, mfn_t gmfn, int fast, int all) /* Search for this shadow in all appropriate shadows */ perfc_incr(shadow_unshadow); - sh_flags = pg->shadow_flags; /* Lower-level shadows need to be excised from upper-level shadows. * This call to hash_foreach() looks dangerous but is in fact OK: each * call will remove at most one shadow, and terminate immediately when * it does remove it, so we never walk the hash after doing a deletion. */ -#define DO_UNSHADOW(_type) do { \ - t = (_type); \ - smfn = shadow_hash_lookup(v, mfn_x(gmfn), t); \ - if ( unlikely(!mfn_valid(smfn)) ) \ - { \ - SHADOW_ERROR(": gmfn %#lx has flags 0x%"PRIx32 \ - " but no type-0x%"PRIx32" shadow\n", \ - mfn_x(gmfn), sh_flags, t); \ - break; \ - } \ - if ( sh_type_is_pinnable(v, t) ) \ - sh_unpin(v, smfn); \ - else \ - sh_remove_shadow_via_pointer(v, smfn); \ - if ( (pg->count_info & PGC_page_table) && !fast ) \ - hash_foreach(v, masks[t], callbacks, smfn); \ +#define DO_UNSHADOW(_type) do { \ + t = (_type); \ + if( !(pg->count_info & PGC_page_table) \ + || !(pg->shadow_flags & (1 << t)) ) \ + break; \ + smfn = shadow_hash_lookup(v, mfn_x(gmfn), t); \ + if ( unlikely(!mfn_valid(smfn)) ) \ + { \ + SHADOW_ERROR(": gmfn %#lx has flags 0x%"PRIx32 \ + " but no type-0x%"PRIx32" shadow\n", \ + mfn_x(gmfn), (uint32_t)pg->shadow_flags, t); \ + break; \ + } \ + if ( sh_type_is_pinnable(v, t) ) \ + sh_unpin(v, smfn); \ + else \ + sh_remove_shadow_via_pointer(v, smfn); \ + if( !fast \ + && (pg->count_info & PGC_page_table) \ + && (pg->shadow_flags & (1 << t)) ) \ + hash_foreach(v, masks[t], callbacks, smfn); \ } while (0) - if ( sh_flags & SHF_L1_32 ) DO_UNSHADOW(SH_type_l1_32_shadow); - if ( sh_flags & SHF_L2_32 ) DO_UNSHADOW(SH_type_l2_32_shadow); + DO_UNSHADOW(SH_type_l2_32_shadow); + DO_UNSHADOW(SH_type_l1_32_shadow); #if CONFIG_PAGING_LEVELS >= 3 - if ( sh_flags & SHF_L1_PAE ) DO_UNSHADOW(SH_type_l1_pae_shadow); - if ( sh_flags & SHF_L2_PAE ) DO_UNSHADOW(SH_type_l2_pae_shadow); - if ( sh_flags & SHF_L2H_PAE ) DO_UNSHADOW(SH_type_l2h_pae_shadow); + DO_UNSHADOW(SH_type_l2h_pae_shadow); + DO_UNSHADOW(SH_type_l2_pae_shadow); + DO_UNSHADOW(SH_type_l1_pae_shadow); #if CONFIG_PAGING_LEVELS >= 4 - if ( sh_flags & SHF_L1_64 ) DO_UNSHADOW(SH_type_l1_64_shadow); - if ( sh_flags & SHF_L2_64 ) DO_UNSHADOW(SH_type_l2_64_shadow); - if ( sh_flags & SHF_L2H_64 ) DO_UNSHADOW(SH_type_l2h_64_shadow); - if ( sh_flags & SHF_L3_64 ) DO_UNSHADOW(SH_type_l3_64_shadow); - if ( sh_flags & SHF_L4_64 ) DO_UNSHADOW(SH_type_l4_64_shadow); + DO_UNSHADOW(SH_type_l4_64_shadow); + DO_UNSHADOW(SH_type_l3_64_shadow); + DO_UNSHADOW(SH_type_l2h_64_shadow); + DO_UNSHADOW(SH_type_l2_64_shadow); + DO_UNSHADOW(SH_type_l1_64_shadow); #endif #endif |