ia64/xen-unstable

changeset 18732:4413d53a8320

x86: highmem handling assistance hypercalls

While looking at the origin of very frequently executed hypercalls I
realized that the high page accessor functions in Linux would be good
candidates to handle in the hypervisor - clearing or copying to/from
a high page is a pretty frequent operation (provided there's enough
memory in the domain). While prior to the first submission I only
measured kernel builds (where the results are not hinting at a
meaningful improvement), I now found time to do a more specific
analysis: page clearing is being improved by about 20%, page copying
doesn't seem to significantly benefit (though that may be an effect of
the simplistic copy_page() implementation Xen currently uses) -
nevertheless I would think that if one function is supported by the
hypervisor, then the other should also be.

Signed-off-by: Jan Beulich <jbeulich@novell.com>
author Keir Fraser <keir.fraser@citrix.com>
date Mon Oct 27 13:29:35 2008 +0000 (2008-10-27)
parents 9bbb54fd9181
children 2a022ee37392
files xen/arch/x86/mm.c xen/arch/x86/x86_64/compat/mm.c xen/common/kernel.c xen/include/public/features.h xen/include/public/xen.h
line diff
     1.1 --- a/xen/arch/x86/mm.c	Mon Oct 27 13:27:33 2008 +0000
     1.2 +++ b/xen/arch/x86/mm.c	Mon Oct 27 13:29:35 2008 +0000
     1.3 @@ -2431,6 +2431,29 @@ static inline cpumask_t vcpumask_to_pcpu
     1.4      return pmask;
     1.5  }
     1.6  
     1.7 +#ifdef __i386__
     1.8 +static inline void *fixmap_domain_page(unsigned long mfn)
     1.9 +{
    1.10 +    unsigned int cpu = smp_processor_id();
    1.11 +    void *ptr = (void *)fix_to_virt(FIX_PAE_HIGHMEM_0 + cpu);
    1.12 +
    1.13 +    l1e_write(fix_pae_highmem_pl1e - cpu,
    1.14 +              l1e_from_pfn(mfn, __PAGE_HYPERVISOR));
    1.15 +    flush_tlb_one_local(ptr);
    1.16 +    return ptr;
    1.17 +}
    1.18 +static inline void fixunmap_domain_page(const void *ptr)
    1.19 +{
    1.20 +    unsigned int cpu = virt_to_fix((unsigned long)ptr) - FIX_PAE_HIGHMEM_0;
    1.21 +
    1.22 +    l1e_write(fix_pae_highmem_pl1e - cpu, l1e_empty());
    1.23 +    this_cpu(make_cr3_timestamp) = this_cpu(tlbflush_time);
    1.24 +}
    1.25 +#else
    1.26 +#define fixmap_domain_page(mfn) mfn_to_virt(mfn)
    1.27 +#define fixunmap_domain_page(ptr) ((void)(ptr))
    1.28 +#endif
    1.29 +
    1.30  int do_mmuext_op(
    1.31      XEN_GUEST_HANDLE(mmuext_op_t) uops,
    1.32      unsigned int count,
    1.33 @@ -2700,6 +2723,66 @@ int do_mmuext_op(
    1.34              break;
    1.35          }
    1.36  
    1.37 +        case MMUEXT_CLEAR_PAGE:
    1.38 +        {
    1.39 +            unsigned char *ptr;
    1.40 +
    1.41 +            okay = !get_page_and_type_from_pagenr(mfn, PGT_writable_page,
    1.42 +                                                  FOREIGNDOM, 0);
    1.43 +            if ( unlikely(!okay) )
    1.44 +            {
    1.45 +                MEM_LOG("Error while clearing mfn %lx", mfn);
    1.46 +                break;
    1.47 +            }
    1.48 +
    1.49 +            /* A page is dirtied when it's being cleared. */
    1.50 +            paging_mark_dirty(d, mfn);
    1.51 +
    1.52 +            ptr = fixmap_domain_page(mfn);
    1.53 +            clear_page(ptr);
    1.54 +            fixunmap_domain_page(ptr);
    1.55 +
    1.56 +            put_page_and_type(page);
    1.57 +            break;
    1.58 +        }
    1.59 +
    1.60 +        case MMUEXT_COPY_PAGE:
    1.61 +        {
    1.62 +            const unsigned char *src;
    1.63 +            unsigned char *dst;
    1.64 +            unsigned long src_mfn;
    1.65 +
    1.66 +            src_mfn = gmfn_to_mfn(FOREIGNDOM, op.arg2.src_mfn);
    1.67 +            okay = get_page_from_pagenr(src_mfn, FOREIGNDOM);
    1.68 +            if ( unlikely(!okay) )
    1.69 +            {
    1.70 +                MEM_LOG("Error while copying from mfn %lx", src_mfn);
    1.71 +                break;
    1.72 +            }
    1.73 +
    1.74 +            okay = !get_page_and_type_from_pagenr(mfn, PGT_writable_page,
    1.75 +                                                  FOREIGNDOM, 0);
    1.76 +            if ( unlikely(!okay) )
    1.77 +            {
    1.78 +                put_page(mfn_to_page(src_mfn));
    1.79 +                MEM_LOG("Error while copying to mfn %lx", mfn);
    1.80 +                break;
    1.81 +            }
    1.82 +
    1.83 +            /* A page is dirtied when it's being copied to. */
    1.84 +            paging_mark_dirty(d, mfn);
    1.85 +
    1.86 +            src = map_domain_page(src_mfn);
    1.87 +            dst = fixmap_domain_page(mfn);
    1.88 +            copy_page(dst, src);
    1.89 +            fixunmap_domain_page(dst);
    1.90 +            unmap_domain_page(src);
    1.91 +
    1.92 +            put_page_and_type(page);
    1.93 +            put_page(mfn_to_page(src_mfn));
    1.94 +            break;
    1.95 +        }
    1.96 +
    1.97          default:
    1.98              MEM_LOG("Invalid extended pt command 0x%x", op.cmd);
    1.99              rc = -ENOSYS;
     2.1 --- a/xen/arch/x86/x86_64/compat/mm.c	Mon Oct 27 13:27:33 2008 +0000
     2.2 +++ b/xen/arch/x86/x86_64/compat/mm.c	Mon Oct 27 13:29:35 2008 +0000
     2.3 @@ -231,6 +231,8 @@ int compat_mmuext_op(XEN_GUEST_HANDLE(mm
     2.4              case MMUEXT_PIN_L4_TABLE:
     2.5              case MMUEXT_UNPIN_TABLE:
     2.6              case MMUEXT_NEW_BASEPTR:
     2.7 +            case MMUEXT_CLEAR_PAGE:
     2.8 +            case MMUEXT_COPY_PAGE:
     2.9                  arg1 = XLAT_mmuext_op_arg1_mfn;
    2.10                  break;
    2.11              default:
    2.12 @@ -258,6 +260,9 @@ int compat_mmuext_op(XEN_GUEST_HANDLE(mm
    2.13              case MMUEXT_INVLPG_MULTI:
    2.14                  arg2 = XLAT_mmuext_op_arg2_vcpumask;
    2.15                  break;
    2.16 +            case MMUEXT_COPY_PAGE:
    2.17 +                arg2 = XLAT_mmuext_op_arg2_src_mfn;
    2.18 +                break;
    2.19              default:
    2.20                  arg2 = -1;
    2.21                  break;
     3.1 --- a/xen/common/kernel.c	Mon Oct 27 13:27:33 2008 +0000
     3.2 +++ b/xen/common/kernel.c	Mon Oct 27 13:29:35 2008 +0000
     3.3 @@ -221,7 +221,8 @@ DO(xen_version)(int cmd, XEN_GUEST_HANDL
     3.4                  fi.submap |= 1U << XENFEAT_supervisor_mode_kernel;
     3.5  #ifdef CONFIG_X86
     3.6              if ( !is_hvm_vcpu(current) )
     3.7 -                fi.submap |= 1U << XENFEAT_mmu_pt_update_preserve_ad;
     3.8 +                fi.submap |= (1U << XENFEAT_mmu_pt_update_preserve_ad) |
     3.9 +                             (1U << XENFEAT_highmem_assist);
    3.10  #endif
    3.11              break;
    3.12          default:
     4.1 --- a/xen/include/public/features.h	Mon Oct 27 13:27:33 2008 +0000
     4.2 +++ b/xen/include/public/features.h	Mon Oct 27 13:29:35 2008 +0000
     4.3 @@ -59,6 +59,9 @@
     4.4  /* x86: Does this Xen host support the MMU_PT_UPDATE_PRESERVE_AD hypercall? */
     4.5  #define XENFEAT_mmu_pt_update_preserve_ad  5
     4.6  
     4.7 +/* x86: Does this Xen host support the MMU_{CLEAR,COPY}_PAGE hypercall? */
     4.8 +#define XENFEAT_highmem_assist             6
     4.9 +
    4.10  #define XENFEAT_NR_SUBMAPS 1
    4.11  
    4.12  #endif /* __XEN_PUBLIC_FEATURES_H__ */
     5.1 --- a/xen/include/public/xen.h	Mon Oct 27 13:27:33 2008 +0000
     5.2 +++ b/xen/include/public/xen.h	Mon Oct 27 13:29:35 2008 +0000
     5.3 @@ -231,6 +231,13 @@ DEFINE_XEN_GUEST_HANDLE(xen_pfn_t);
     5.4   * cmd: MMUEXT_SET_LDT
     5.5   * linear_addr: Linear address of LDT base (NB. must be page-aligned).
     5.6   * nr_ents: Number of entries in LDT.
     5.7 + *
     5.8 + * cmd: MMUEXT_CLEAR_PAGE
     5.9 + * mfn: Machine frame number to be cleared.
    5.10 + *
    5.11 + * cmd: MMUEXT_COPY_PAGE
    5.12 + * mfn: Machine frame number of the destination page.
    5.13 + * src_mfn: Machine frame number of the source page.
    5.14   */
    5.15  #define MMUEXT_PIN_L1_TABLE      0
    5.16  #define MMUEXT_PIN_L2_TABLE      1
    5.17 @@ -247,12 +254,15 @@ DEFINE_XEN_GUEST_HANDLE(xen_pfn_t);
    5.18  #define MMUEXT_FLUSH_CACHE      12
    5.19  #define MMUEXT_SET_LDT          13
    5.20  #define MMUEXT_NEW_USER_BASEPTR 15
    5.21 +#define MMUEXT_CLEAR_PAGE       16
    5.22 +#define MMUEXT_COPY_PAGE        17
    5.23  
    5.24  #ifndef __ASSEMBLY__
    5.25  struct mmuext_op {
    5.26      unsigned int cmd;
    5.27      union {
    5.28 -        /* [UN]PIN_TABLE, NEW_BASEPTR, NEW_USER_BASEPTR */
    5.29 +        /* [UN]PIN_TABLE, NEW_BASEPTR, NEW_USER_BASEPTR
    5.30 +         * CLEAR_PAGE, COPY_PAGE */
    5.31          xen_pfn_t     mfn;
    5.32          /* INVLPG_LOCAL, INVLPG_ALL, SET_LDT */
    5.33          unsigned long linear_addr;
    5.34 @@ -266,6 +276,8 @@ struct mmuext_op {
    5.35  #else
    5.36          void *vcpumask;
    5.37  #endif
    5.38 +        /* COPY_PAGE */
    5.39 +        xen_pfn_t src_mfn;
    5.40      } arg2;
    5.41  };
    5.42  typedef struct mmuext_op mmuext_op_t;