direct-io.hg

changeset 11795:a0d33cc09333

[XEN] Heuristic for fast revoke-write-access in HIGHPTE linux guests

This adds a heuristic for speeding up revocation of write access to
pagetables for HIGHPTE linux kernels, which previously had to brute-force
search all L1 shadows.

Signed-off-by: Tim Deegan <Tim.Deegan@xensource.com>
author Tim Deegan <Tim.Deegan@xensource.com>
date Tue Oct 17 11:14:17 2006 +0100 (2006-10-17)
parents 37ee88ca1440
children 7ec648fdb392
files xen/arch/x86/mm/shadow/common.c xen/arch/x86/mm/shadow/multi.c xen/include/asm-x86/domain.h xen/include/asm-x86/perfc_defn.h
line diff
     1.1 --- a/xen/arch/x86/mm/shadow/common.c	Tue Oct 17 11:11:48 2006 +0100
     1.2 +++ b/xen/arch/x86/mm/shadow/common.c	Tue Oct 17 11:14:17 2006 +0100
     1.3 @@ -720,6 +720,15 @@ void shadow_free(struct domain *d, mfn_t
     1.4  
     1.5      for ( i = 0; i < 1<<order; i++ ) 
     1.6      {
     1.7 +#if SHADOW_OPTIMIZATIONS & SHOPT_WRITABLE_HEURISTIC
     1.8 +        struct vcpu *v;
     1.9 +        for_each_vcpu(d, v) 
    1.10 +        {
    1.11 +            /* No longer safe to look for a writeable mapping in this shadow */
    1.12 +            if ( v->arch.shadow.last_writeable_pte_smfn == mfn_x(smfn) + i ) 
    1.13 +                v->arch.shadow.last_writeable_pte_smfn = 0;
    1.14 +        }
    1.15 +#endif
    1.16          /* Strip out the type: this is now a free shadow page */
    1.17          pg[i].count_info = 0;
    1.18          /* Remember the TLB timestamp so we will know whether to flush 
    1.19 @@ -1820,12 +1829,11 @@ int shadow_remove_write_access(struct vc
    1.20          unsigned long gfn;
    1.21          /* Heuristic: there is likely to be only one writeable mapping,
    1.22           * and that mapping is likely to be in the current pagetable,
    1.23 -         * either in the guest's linear map (linux, windows) or in a
    1.24 -         * magic slot used to map high memory regions (linux HIGHTPTE) */
    1.25 +         * in the guest's linear map (on non-HIGHPTE linux and windows)*/
    1.26  
    1.27  #define GUESS(_a, _h) do {                                              \
    1.28 -            if ( v->arch.shadow.mode->guess_wrmap(v, (_a), gmfn) )          \
    1.29 -                perfc_incrc(shadow_writeable_h_ ## _h);                \
    1.30 +            if ( v->arch.shadow.mode->guess_wrmap(v, (_a), gmfn) )      \
    1.31 +                perfc_incrc(shadow_writeable_h_ ## _h);                 \
    1.32              if ( (pg->u.inuse.type_info & PGT_count_mask) == 0 )        \
    1.33                  return 1;                                               \
    1.34          } while (0)
    1.35 @@ -1875,9 +1883,35 @@ int shadow_remove_write_access(struct vc
    1.36  #endif /* CONFIG_PAGING_LEVELS >= 3 */
    1.37  
    1.38  #undef GUESS
    1.39 -
    1.40      }
    1.41 -#endif
    1.42 +
    1.43 +    if ( (pg->u.inuse.type_info & PGT_count_mask) == 0 )
    1.44 +        return 1;
    1.45 +
    1.46 +    /* Second heuristic: on HIGHPTE linux, there are two particular PTEs
    1.47 +     * (entries in the fixmap) where linux maps its pagetables.  Since
    1.48 +     * we expect to hit them most of the time, we start the search for
    1.49 +     * the writeable mapping by looking at the same MFN where the last
    1.50 +     * brute-force search succeeded. */
    1.51 +
    1.52 +    if ( v->arch.shadow.last_writeable_pte_smfn != 0 )
    1.53 +    {
    1.54 +        unsigned long old_count = (pg->u.inuse.type_info & PGT_count_mask);
    1.55 +        mfn_t last_smfn = _mfn(v->arch.shadow.last_writeable_pte_smfn);
    1.56 +        int shtype = (mfn_to_page(last_smfn)->count_info & PGC_SH_type_mask) 
    1.57 +            >> PGC_SH_type_shift;
    1.58 +
    1.59 +        if ( callbacks[shtype] ) 
    1.60 +            callbacks[shtype](v, last_smfn, gmfn);
    1.61 +
    1.62 +        if ( (pg->u.inuse.type_info & PGT_count_mask) != old_count )
    1.63 +            perfc_incrc(shadow_writeable_h_5);
    1.64 +    }
    1.65 +
    1.66 +    if ( (pg->u.inuse.type_info & PGT_count_mask) == 0 )
    1.67 +        return 1;
    1.68 +
    1.69 +#endif /* SHADOW_OPTIMIZATIONS & SHOPT_WRITABLE_HEURISTIC */
    1.70      
    1.71      /* Brute-force search of all the shadows, by walking the hash */
    1.72      perfc_incrc(shadow_writeable_bf);
     2.1 --- a/xen/arch/x86/mm/shadow/multi.c	Tue Oct 17 11:11:48 2006 +0100
     2.2 +++ b/xen/arch/x86/mm/shadow/multi.c	Tue Oct 17 11:14:17 2006 +0100
     2.3 @@ -196,7 +196,6 @@ delete_fl1_shadow_status(struct vcpu *v,
     2.4  {
     2.5      SHADOW_PRINTK("gfn=%"SH_PRI_gfn", type=%08x, smfn=%05lx\n",
     2.6                     gfn_x(gfn), PGC_SH_fl1_shadow, mfn_x(smfn));
     2.7 -
     2.8      shadow_hash_delete(v, gfn_x(gfn),
     2.9                          PGC_SH_fl1_shadow >> PGC_SH_type_shift, smfn);
    2.10  }
    2.11 @@ -3597,6 +3596,7 @@ int sh_remove_write_access(struct vcpu *
    2.12      shadow_l1e_t *sl1e;
    2.13      int done = 0;
    2.14      int flags;
    2.15 +    mfn_t base_sl1mfn = sl1mfn; /* Because sl1mfn changes in the foreach */
    2.16      
    2.17      SHADOW_FOREACH_L1E(sl1mfn, sl1e, 0, done, 
    2.18      {
    2.19 @@ -3606,6 +3606,10 @@ int sh_remove_write_access(struct vcpu *
    2.20               && (mfn_x(shadow_l1e_get_mfn(*sl1e)) == mfn_x(readonly_mfn)) )
    2.21          {
    2.22              shadow_set_l1e(v, sl1e, shadow_l1e_empty(), sl1mfn);
    2.23 +#if SHADOW_OPTIMIZATIONS & SHOPT_WRITABLE_HEURISTIC 
    2.24 +            /* Remember the last shadow that we shot a writeable mapping in */
    2.25 +            v->arch.shadow.last_writeable_pte_smfn = mfn_x(base_sl1mfn);
    2.26 +#endif
    2.27              if ( (mfn_to_page(readonly_mfn)->u.inuse.type_info
    2.28                    & PGT_count_mask) == 0 )
    2.29                  /* This breaks us cleanly out of the FOREACH macro */
     3.1 --- a/xen/include/asm-x86/domain.h	Tue Oct 17 11:11:48 2006 +0100
     3.2 +++ b/xen/include/asm-x86/domain.h	Tue Oct 17 11:14:17 2006 +0100
     3.3 @@ -142,6 +142,8 @@ struct shadow_vcpu {
     3.4      struct shadow_paging_mode *mode;
     3.5      /* Last MFN that we emulated a write to. */
     3.6      unsigned long last_emulated_mfn;
     3.7 +    /* MFN of the last shadow that we shot a writeable mapping in */
     3.8 +    unsigned long last_writeable_pte_smfn;
     3.9      /* HVM guest: paging enabled (CR0.PG)?  */
    3.10      unsigned int translate_enabled:1;
    3.11      /* Emulated fault needs to be propagated to guest? */
     4.1 --- a/xen/include/asm-x86/perfc_defn.h	Tue Oct 17 11:11:48 2006 +0100
     4.2 +++ b/xen/include/asm-x86/perfc_defn.h	Tue Oct 17 11:14:17 2006 +0100
     4.3 @@ -71,6 +71,7 @@ PERFCOUNTER_CPU(shadow_writeable_h_1,  "
     4.4  PERFCOUNTER_CPU(shadow_writeable_h_2,  "shadow writeable: 32pae w2k3")
     4.5  PERFCOUNTER_CPU(shadow_writeable_h_3,  "shadow writeable: 64b w2k3")
     4.6  PERFCOUNTER_CPU(shadow_writeable_h_4,  "shadow writeable: 32b linux low")
     4.7 +PERFCOUNTER_CPU(shadow_writeable_h_5,  "shadow writeable: 32b linux high")
     4.8  PERFCOUNTER_CPU(shadow_writeable_bf,   "shadow writeable brute-force")
     4.9  PERFCOUNTER_CPU(shadow_mappings,       "shadow removes all mappings")
    4.10  PERFCOUNTER_CPU(shadow_mappings_bf,    "shadow rm-mappings brute-force")