[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCH 0 of 2] Add libxc API that sets mem_access type for an array of gfns
On Fri, Apr 27, 2012 at 11:25 AM, Aravindh Puthiyaparambil <aravindh@xxxxxxxxxxxx> wrote: > On Fri, Apr 27, 2012 at 10:37 AM, Christian Limpach > <christian.limpach@xxxxxxxxx> wrote: >> On Thu, Apr 26, 2012 at 6:36 PM, Aravindh Puthiyaparambil >> <aravindh@xxxxxxxxxxxx> wrote: >>> >>> On Apr 26, 2012 6:06 PM, "Christian Limpach" <christian.limpach@xxxxxxxxx> >>> wrote: >>>> >>>> Maybe you can do something similar, for example passing in a hint >>>> whether ept_sync_domain needs to be done or not. In my case, the >>>> reasoning is that all the entries changed from hap_clean_vram_tracking >>>> are leaf entries, so ept_free_entry will never be called and thus >>>> ept_sync_domain can be deferred. I didn't think through/consider the >>>> iommu case since that code is commented out in my tree. >>> >>> I thought about doing that initially. But then in the bulk case I would >>> always have to call ept_sync_domain() to be on the safe side. But if the >>> iommu case forces me down that path, then I guess I have no choice. >> >> I think you should re-consider. It would avoid adding the extra >> wrapper, which makes this code a lot less readable. Plus it avoids >> the need for the old_entries array. >> >> Let me re-iterate: >> - if it's a leaf entry, then there's no need to call ept_free_entry >> - if you don't need to call ept_free_entry, then you can defer >> ept_sync_domain (subject to the iommu case) >> - you could pass in a pointer to a bool to indicate to the caller that >> ept_sync_domain was deferred and that the caller needs to do it, with >> a NULL pointer indicating that the caller doesn't support defer How does this look? changeset: 25257:2c05bdb052ea user: Aravindh Puthiyaparambil <aravindh@xxxxxxxxxxxx> date: Fri Apr 27 20:28:37 2012 -0700 summary: x86/mm: Add sync deferred option to p2m->set_entry() diff -r 9dda0efd8ce1 -r 2c05bdb052ea xen/arch/x86/mm/mem_sharing.c --- a/xen/arch/x86/mm/mem_sharing.c Fri Apr 27 17:57:55 2012 +0200 +++ b/xen/arch/x86/mm/mem_sharing.c Fri Apr 27 20:28:37 2012 -0700 @@ -1272,7 +1272,7 @@ int relinquish_shared_pages(struct domai /* Clear out the p2m entry so no one else may try to * unshare */ p2m->set_entry(p2m, gfn, _mfn(0), PAGE_ORDER_4K, - p2m_invalid, p2m_access_rwx); + p2m_invalid, p2m_access_rwx, NULL); count++; } diff -r 9dda0efd8ce1 -r 2c05bdb052ea xen/arch/x86/mm/p2m-ept.c --- a/xen/arch/x86/mm/p2m-ept.c Fri Apr 27 17:57:55 2012 +0200 +++ b/xen/arch/x86/mm/p2m-ept.c Fri Apr 27 20:28:37 2012 -0700 @@ -274,10 +274,13 @@ static int ept_next_level(struct p2m_dom /* * ept_set_entry() computes 'need_modify_vtd_table' for itself, * by observing whether any gfn->mfn translations are modified. + * If sync_deferred is not NULL, then the caller will take care of + * calling ept_sync_domain() in the cases where it can be deferred. */ static int ept_set_entry(struct p2m_domain *p2m, unsigned long gfn, mfn_t mfn, - unsigned int order, p2m_type_t p2mt, p2m_access_t p2ma) + unsigned int order, p2m_type_t p2mt, p2m_access_t p2ma, + bool_t *sync_deferred) { ept_entry_t *table, *ept_entry = NULL; unsigned long gfn_remainder = gfn; @@ -293,6 +296,7 @@ ept_set_entry(struct p2m_domain *p2m, un int needs_sync = 1; struct domain *d = p2m->domain; ept_entry_t old_entry = { .epte = 0 }; + bool_t _sync_deferred = 0; /* * the caller must make sure: @@ -309,6 +313,9 @@ ept_set_entry(struct p2m_domain *p2m, un (target == 1 && hvm_hap_has_2mb(d)) || (target == 0)); + if (sync_deferred) + *sync_deferred = 1; + table = map_domain_page(ept_get_asr(d)); for ( i = ept_get_wl(d); i > target; i-- ) @@ -346,7 +353,11 @@ ept_set_entry(struct p2m_domain *p2m, un /* No need to flush if the old entry wasn't valid */ if ( !is_epte_present(ept_entry) ) + { needs_sync = 0; + if ( sync_deferred ) + *sync_deferred = 0; + } /* If we're replacing a non-leaf entry with a leaf entry (1GiB or 2MiB), * the intermediate tables will be freed below after the ept flush @@ -385,6 +396,9 @@ ept_set_entry(struct p2m_domain *p2m, un ASSERT(is_epte_superpage(ept_entry)); + if ( sync_deferred ) + _sync_deferred = 1; + split_ept_entry = atomic_read_ept_entry(ept_entry); if ( !ept_split_super_page(p2m, &split_ept_entry, i, target) ) @@ -438,7 +452,7 @@ ept_set_entry(struct p2m_domain *p2m, un out: unmap_domain_page(table); - if ( needs_sync ) + if ( needs_sync && !_sync_deferred ) ept_sync_domain(p2m->domain); if ( rv && iommu_enabled && need_iommu(p2m->domain) && need_modify_vtd_table ) @@ -727,7 +741,8 @@ void ept_change_entry_emt_with_range(str order = level * EPT_TABLE_ORDER; if ( need_modify_ept_entry(p2m, gfn, mfn, e.ipat, e.emt, e.sa_p2mt) ) - ept_set_entry(p2m, gfn, mfn, order, e.sa_p2mt, e.access); + ept_set_entry(p2m, gfn, mfn, order, e.sa_p2mt, e.access, + NULL); gfn += trunk; break; } @@ -737,7 +752,7 @@ void ept_change_entry_emt_with_range(str else /* gfn assigned with 4k */ { if ( need_modify_ept_entry(p2m, gfn, mfn, e.ipat, e.emt, e.sa_p2mt) ) - ept_set_entry(p2m, gfn, mfn, order, e.sa_p2mt, e.access); + ept_set_entry(p2m, gfn, mfn, order, e.sa_p2mt, e.access, NULL); } } p2m_unlock(p2m); diff -r 9dda0efd8ce1 -r 2c05bdb052ea xen/arch/x86/mm/p2m-pt.c --- a/xen/arch/x86/mm/p2m-pt.c Fri Apr 27 17:57:55 2012 +0200 +++ b/xen/arch/x86/mm/p2m-pt.c Fri Apr 27 20:28:37 2012 -0700 @@ -291,7 +291,8 @@ p2m_next_level(struct p2m_domain *p2m, m // Returns 0 on error (out of memory) static int p2m_set_entry(struct p2m_domain *p2m, unsigned long gfn, mfn_t mfn, - unsigned int page_order, p2m_type_t p2mt, p2m_access_t p2ma) + unsigned int page_order, p2m_type_t p2mt, p2m_access_t p2ma, + bool_t *unused) { // XXX -- this might be able to be faster iff current->domain == d mfn_t table_mfn = pagetable_get_mfn(p2m_get_pagetable(p2m)); diff -r 9dda0efd8ce1 -r 2c05bdb052ea xen/arch/x86/mm/p2m.c --- a/xen/arch/x86/mm/p2m.c Fri Apr 27 17:57:55 2012 +0200 +++ b/xen/arch/x86/mm/p2m.c Fri Apr 27 20:28:37 2012 -0700 @@ -227,7 +227,7 @@ int set_p2m_entry(struct p2m_domain *p2m else order = 0; - if ( !p2m->set_entry(p2m, gfn, mfn, order, p2mt, p2ma) ) + if ( !p2m->set_entry(p2m, gfn, mfn, order, p2mt, p2ma, NULL) ) rc = 0; gfn += 1ul << order; if ( mfn_x(mfn) != INVALID_MFN ) @@ -1199,14 +1199,14 @@ bool_t p2m_mem_access_check(unsigned lon if ( access_w && p2ma == p2m_access_rx2rw ) { - p2m->set_entry(p2m, gfn, mfn, PAGE_ORDER_4K, p2mt, p2m_access_rw); + p2m->set_entry(p2m, gfn, mfn, PAGE_ORDER_4K, p2mt, p2m_access_rw, NULL); gfn_unlock(p2m, gfn, 0); return 1; } else if ( p2ma == p2m_access_n2rwx ) { ASSERT(access_w || access_r || access_x); - p2m->set_entry(p2m, gfn, mfn, PAGE_ORDER_4K, p2mt, p2m_access_rwx); + p2m->set_entry(p2m, gfn, mfn, PAGE_ORDER_4K, p2mt, p2m_access_rwx, NULL); } gfn_unlock(p2m, gfn, 0); @@ -1228,7 +1228,8 @@ bool_t p2m_mem_access_check(unsigned lon { /* A listener is not required, so clear the access restrictions */ gfn_lock(p2m, gfn, 0); - p2m->set_entry(p2m, gfn, mfn, PAGE_ORDER_4K, p2mt, p2m_access_rwx); + p2m->set_entry(p2m, gfn, mfn, PAGE_ORDER_4K, p2mt, + p2m_access_rwx, NULL); gfn_unlock(p2m, gfn, 0); } return 1; @@ -1292,6 +1293,7 @@ int p2m_set_mem_access(struct domain *d, p2m_type_t t; mfn_t mfn; int rc = 0; + bool_t sync_deferred = 1; /* N.B. _not_ static: initializer depends on p2m->default_access */ p2m_access_t memaccess[] = { @@ -1324,12 +1326,17 @@ int p2m_set_mem_access(struct domain *d, for ( pfn = start_pfn; pfn < start_pfn + nr; pfn++ ) { mfn = p2m->get_entry(p2m, pfn, &t, &_a, 0, NULL); - if ( p2m->set_entry(p2m, pfn, mfn, PAGE_ORDER_4K, t, a) == 0 ) + if ( p2m->set_entry(p2m, pfn, mfn, PAGE_ORDER_4K, t, a, &sync_deferred) + == 0 ) { rc = -ENOMEM; break; } } + + if ( sync_deferred ) + ept_sync_domain(p2m->domain); + p2m_unlock(p2m); return rc; } diff -r 9dda0efd8ce1 -r 2c05bdb052ea xen/include/asm-x86/p2m.h --- a/xen/include/asm-x86/p2m.h Fri Apr 27 17:57:55 2012 +0200 +++ b/xen/include/asm-x86/p2m.h Fri Apr 27 20:28:37 2012 -0700 @@ -231,7 +231,8 @@ struct p2m_domain { unsigned long gfn, mfn_t mfn, unsigned int page_order, p2m_type_t p2mt, - p2m_access_t p2ma); + p2m_access_t p2ma, + bool_t *sync_deferred); mfn_t (*get_entry )(struct p2m_domain *p2m, unsigned long gfn, p2m_type_t *p2mt, changeset: 25258:5a0d60bb536b user: Aravindh Puthiyaparambil <aravindh@xxxxxxxxxxxx> date: Fri Apr 27 21:10:59 2012 -0700 summary: mem_access: Add xc_hvm_mem_access_bulk() API diff -r 2c05bdb052ea -r 5a0d60bb536b tools/libxc/xc_misc.c --- a/tools/libxc/xc_misc.c Fri Apr 27 20:28:37 2012 -0700 +++ b/tools/libxc/xc_misc.c Fri Apr 27 21:10:59 2012 -0700 @@ -570,6 +570,57 @@ int xc_hvm_set_mem_access( return rc; } +int xc_hvm_set_mem_access_bulk( + xc_interface *xch, domid_t dom, hvmmem_access_t mem_access, + xen_pfn_t *arr, int *err, uint64_t nr) +{ + DECLARE_HYPERCALL; + DECLARE_HYPERCALL_BUFFER(struct xen_hvm_set_mem_access_bulk, arg); + DECLARE_HYPERCALL_BOUNCE(arr, sizeof(xen_pfn_t) * nr, + XC_HYPERCALL_BUFFER_BOUNCE_IN); + DECLARE_HYPERCALL_BOUNCE(err, sizeof(int) * nr, + XC_HYPERCALL_BUFFER_BOUNCE_OUT); + int rc; + + arg = xc_hypercall_buffer_alloc(xch, arg, sizeof(*arg)); + if ( arg == NULL ) + { + PERROR("Could not allocate memory for xc_hvm_set_mem_access_bulk hypercall"); + return -1; + } + + if ( xc_hypercall_bounce_pre(xch, arr) ) { + PERROR("Could not bounce arr for xc_hvm_set_mem_access_bulk hypercall"); + rc = -1; + goto out; + } + + if ( xc_hypercall_bounce_pre(xch, err) ) { + PERROR("Could not bounce err for xc_hvm_set_mem_access_bulk hypercall"); + rc = -1; + goto out; + } + + arg->domid = dom; + arg->hvmmem_access = mem_access; + arg->nr = nr; + set_xen_guest_handle(arg->arr, arr); + set_xen_guest_handle(arg->err, err); + + hypercall.op = __HYPERVISOR_hvm_op; + hypercall.arg[0] = HVMOP_set_mem_access_bulk; + hypercall.arg[1] = HYPERCALL_BUFFER_AS_ARG(arg); + + rc = do_xen_hypercall(xch, &hypercall); + +out: + xc_hypercall_buffer_free(xch, arg); + xc_hypercall_bounce_post(xch, arr); + xc_hypercall_bounce_post(xch, err); + + return rc; +} + int xc_hvm_get_mem_access( xc_interface *xch, domid_t dom, uint64_t pfn, hvmmem_access_t* mem_access) { diff -r 2c05bdb052ea -r 5a0d60bb536b tools/libxc/xenctrl.h --- a/tools/libxc/xenctrl.h Fri Apr 27 20:28:37 2012 -0700 +++ b/tools/libxc/xenctrl.h Fri Apr 27 21:10:59 2012 -0700 @@ -1568,6 +1568,17 @@ int xc_hvm_set_mem_access( xc_interface *xch, domid_t dom, hvmmem_access_t memaccess, uint64_t first_pfn, uint64_t nr); /* + * Set the arry of pfns to a specific access. + * When a pfn cannot be set to the specified access, its respective field in + * @err is set to the corresponding errno value. + * Allowed types are HVMMEM_access_default, HVMMEM_access_n, any combination of + * HVM_access_ + (rwx), and HVM_access_rx2rw + */ +int xc_hvm_set_mem_access_bulk( + xc_interface *xch, domid_t dom, hvmmem_access_t memaccess, + xen_pfn_t *arr, int *err, uint64_t num); + +/* * Gets the mem access for the given page (returned in memacess on success) */ int xc_hvm_get_mem_access( diff -r 2c05bdb052ea -r 5a0d60bb536b xen/arch/x86/hvm/hvm.c --- a/xen/arch/x86/hvm/hvm.c Fri Apr 27 20:28:37 2012 -0700 +++ b/xen/arch/x86/hvm/hvm.c Fri Apr 27 21:10:59 2012 -0700 @@ -4197,6 +4197,51 @@ long do_hvm_op(unsigned long op, XEN_GUE break; } + case HVMOP_set_mem_access_bulk: + { + struct xen_hvm_set_mem_access_bulk a; + struct domain *d; + xen_pfn_t *arr = 0; + int *err = 0; + + if ( copy_from_guest(&a, arg, 1) ) + return -EFAULT; + + rc = rcu_lock_remote_target_domain_by_id(a.domid, &d); + if ( rc != 0 ) + return rc; + + rc = -EINVAL; + + if ( !is_hvm_domain(d) ) + goto param_fail9; + + rc = -ENOMEM; + arr = xmalloc_array(xen_pfn_t, a.nr); + if (!arr) + goto param_fail9; + + err = xmalloc_array(int, a.nr); + if (!err) + goto param_fail9; + + if ( copy_from_guest(arr, a.arr, a.nr) ) + goto param_fail9; + + rc = p2m_set_access_bulk(d, arr, err, a.nr, a.hvmmem_access); + + if ( copy_to_guest(a.err, err, a.nr) ) + goto param_fail9; + + param_fail9: + rcu_unlock_domain(d); + if (arr) + xfree(arr); + if (err) + xfree(err); + break; + } + case HVMOP_get_mem_access: { struct xen_hvm_get_mem_access a; diff -r 2c05bdb052ea -r 5a0d60bb536b xen/arch/x86/mm/p2m.c --- a/xen/arch/x86/mm/p2m.c Fri Apr 27 20:28:37 2012 -0700 +++ b/xen/arch/x86/mm/p2m.c Fri Apr 27 21:10:59 2012 -0700 @@ -1341,6 +1341,61 @@ int p2m_set_mem_access(struct domain *d, return rc; } +int p2m_set_access_bulk(struct domain *d, xen_pfn_t *arr, int *err, + uint64_t nr, hvmmem_access_t access) +{ + struct p2m_domain *p2m = p2m_get_hostp2m(d); + unsigned long pfn; + p2m_access_t a, _a; + p2m_type_t t; + p2m_access_t memaccess[] = { + p2m_access_n, + p2m_access_r, + p2m_access_w, + p2m_access_rw, + p2m_access_x, + p2m_access_rx, + p2m_access_wx, + p2m_access_rwx, + p2m_access_rx2rw, + p2m_access_n2rwx, + p2m->default_access, + }; + mfn_t mfn; + int rc; + bool_t sync_deferred = 1; + + if ( (unsigned) access >= HVMMEM_access_default ) + return -EINVAL; + + a = memaccess[access]; + + p2m_lock(p2m); + + for ( pfn = 0; pfn < nr; pfn++ ) + { + if ( arr[pfn] > domain_get_maximum_gpfn(d) ) + { + err[pfn] = -EINVAL; + continue; + } + + mfn = p2m->get_entry(p2m, arr[pfn], &t, &_a, 0, NULL); + rc = p2m->set_entry(p2m, arr[pfn], mfn, PAGE_ORDER_4K, t, a, + &sync_deferred); + if ( rc == 0 ) + err[pfn] = -ENOMEM; + } + + if ( sync_deferred ) + ept_sync_domain(p2m->domain); + + p2m_unlock(p2m); + + return 0; +} + + /* Get access type for a pfn * If pfn == -1ul, gets the default access type */ int p2m_get_mem_access(struct domain *d, unsigned long pfn, diff -r 2c05bdb052ea -r 5a0d60bb536b xen/include/asm-x86/p2m.h --- a/xen/include/asm-x86/p2m.h Fri Apr 27 20:28:37 2012 -0700 +++ b/xen/include/asm-x86/p2m.h Fri Apr 27 21:10:59 2012 -0700 @@ -574,6 +574,11 @@ void p2m_mem_access_resume(struct domain int p2m_set_mem_access(struct domain *d, unsigned long start_pfn, uint32_t nr, hvmmem_access_t access); +/* Set access type for an array of pfns. set_mem_access success or failure is + * returned in the err array. */ +int p2m_set_access_bulk(struct domain *d, xen_pfn_t *arr, int *err, + uint64_t nr, hvmmem_access_t access); + /* Get access type for a pfn * If pfn == -1ul, gets the default access type */ int p2m_get_mem_access(struct domain *d, unsigned long pfn, @@ -589,7 +594,11 @@ static inline int p2m_set_mem_access(str unsigned long start_pfn, uint32_t nr, hvmmem_access_t access) { return -EINVAL; } -static inline int p2m_get_mem_access(struct domain *d, unsigned long pfn, +static inline int p2m_set_access_bulk(struct domain *d, xen_pfn_t *arr, + int *err, uint64_t nr, + hvmmem_access_t access) +{ return -EINVAL; } +static inline int p2m_get_mem_access(struct domain *d, unsigned long pfn, hvmmem_access_t *access) { return -EINVAL; } #endif diff -r 2c05bdb052ea -r 5a0d60bb536b xen/include/public/hvm/hvm_op.h --- a/xen/include/public/hvm/hvm_op.h Fri Apr 27 20:28:37 2012 -0700 +++ b/xen/include/public/hvm/hvm_op.h Fri Apr 27 21:10:59 2012 -0700 @@ -261,4 +261,22 @@ DEFINE_XEN_GUEST_HANDLE(xen_hvm_inject_m #endif /* defined(__XEN__) || defined(__XEN_TOOLS__) */ +#if defined(__XEN__) || defined(__XEN_TOOLS__) +#define HVMOP_set_mem_access_bulk 17 +/* Notify that a array of pfns is to have specific access types */ +struct xen_hvm_set_mem_access_bulk { + /* Domain to be updated. */ + domid_t domid; + /* Memory type */ + uint16_t hvmmem_access; /* hvm_access_t */ + /* Array of pfns */ + XEN_GUEST_HANDLE_64(xen_pfn_t) arr; + XEN_GUEST_HANDLE_64(int) err ; + /* Number of entries */ + uint64_t nr; +}; +typedef struct xen_hvm_set_mem_access_bulk xen_hvm_set_mem_access_bulk_t; +DEFINE_XEN_GUEST_HANDLE(xen_hvm_set_mem_access_bulk_t); +#endif + #endif /* __XEN_PUBLIC_HVM_HVM_OP_H__ */ _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx http://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |