[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [xen-unstable] Domctls defined for all relevant memory sharing operations.
# HG changeset patch # User Keir Fraser <keir.fraser@xxxxxxxxxx> # Date 1261031276 0 # Node ID 68e964ec2c7bdb3b4f8997b3c027cedfaa2c7bb2 # Parent 8cf5bffd9663fc541be4d4a1b63630787739fd0d Domctls defined for all relevant memory sharing operations. Signed-off-by: Grzegorz Milos <Grzegorz.Milos@xxxxxxxxxx> --- xen/arch/x86/domain.c | 1 xen/arch/x86/domctl.c | 16 ++ xen/arch/x86/mm.c | 3 xen/arch/x86/mm/mem_sharing.c | 223 ++++++++++++++++++++++++++++++++++---- xen/common/domctl.c | 1 xen/include/asm-x86/hvm/domain.h | 1 xen/include/asm-x86/mem_sharing.h | 3 xen/include/public/domctl.h | 49 ++++++++ xen/include/public/memory.h | 7 + xen/include/xen/sched.h | 1 10 files changed, 283 insertions(+), 22 deletions(-) diff -r 8cf5bffd9663 -r 68e964ec2c7b xen/arch/x86/domain.c --- a/xen/arch/x86/domain.c Thu Dec 17 06:27:56 2009 +0000 +++ b/xen/arch/x86/domain.c Thu Dec 17 06:27:56 2009 +0000 @@ -404,6 +404,7 @@ int arch_domain_create(struct domain *d, is_hvm_domain(d) && hvm_funcs.hap_supported && (domcr_flags & DOMCRF_hap); + d->arch.hvm_domain.mem_sharing_enabled = 0; d->arch.s3_integrity = !!(domcr_flags & DOMCRF_s3_integrity); diff -r 8cf5bffd9663 -r 68e964ec2c7b xen/arch/x86/domctl.c --- a/xen/arch/x86/domctl.c Thu Dec 17 06:27:56 2009 +0000 +++ b/xen/arch/x86/domctl.c Thu Dec 17 06:27:56 2009 +0000 @@ -32,6 +32,7 @@ #include <xen/iommu.h> #include <asm/mem_event.h> #include <public/mem_event.h> +#include <asm/mem_sharing.h> #ifdef XEN_GDBSX_CONFIG #ifdef XEN_KDB_CONFIG @@ -1317,6 +1318,21 @@ long arch_do_domctl( } break; + case XEN_DOMCTL_mem_sharing_op: + { + struct domain *d; + + ret = -ESRCH; + d = rcu_lock_domain_by_id(domctl->domain); + if ( d != NULL ) + { + ret = mem_sharing_domctl(d, &domctl->u.mem_sharing_op); + rcu_unlock_domain(d); + copy_to_guest(u_domctl, domctl, 1); + } + } + break; + default: ret = -ENOSYS; break; diff -r 8cf5bffd9663 -r 68e964ec2c7b xen/arch/x86/mm.c --- a/xen/arch/x86/mm.c Thu Dec 17 06:27:56 2009 +0000 +++ b/xen/arch/x86/mm.c Thu Dec 17 06:27:56 2009 +0000 @@ -4503,6 +4503,9 @@ long arch_memory_op(int op, XEN_GUEST_HA return rc; } + case XENMEM_get_sharing_freed_pages: + return mem_sharing_get_nr_saved_mfns(); + default: return subarch_memory_op(op, arg); } diff -r 8cf5bffd9663 -r 68e964ec2c7b xen/arch/x86/mm/mem_sharing.c --- a/xen/arch/x86/mm/mem_sharing.c Thu Dec 17 06:27:56 2009 +0000 +++ b/xen/arch/x86/mm/mem_sharing.c Thu Dec 17 06:27:56 2009 +0000 @@ -24,11 +24,18 @@ #include <asm/string.h> #include <asm/p2m.h> #include <asm/mem_event.h> +#include <asm/atomic.h> #include <xen/domain_page.h> #include <xen/types.h> #include <xen/spinlock.h> #include <xen/mm.h> #include <xen/sched.h> + + +#define hap_enabled(d) \ + (is_hvm_domain(d) && (d)->arch.hvm_domain.hap_enabled) +#define mem_sharing_enabled(d) \ + (is_hvm_domain(d) && (d)->arch.hvm_domain.mem_sharing_enabled) #undef mfn_to_page #define mfn_to_page(_m) __mfn_to_page(mfn_x(_m)) @@ -38,6 +45,7 @@ #define page_to_mfn(_pg) _mfn(__page_to_mfn(_pg)) static shr_handle_t next_handle = 1; +static atomic_t nr_saved_mfns = ATOMIC_INIT(0); typedef struct shr_hash_entry { @@ -64,6 +72,17 @@ typedef struct shr_lock const char *locker_function; /* func that took it */ } shr_lock_t; static shr_lock_t shr_lock; + +/* Returns true if list has only one entry. O(1) complexity. */ +static inline int list_has_one_entry(struct list_head *head) +{ + return (head->next != head) && (head->next->next == head); +} + +static inline struct gfn_info* gfn_get_info(struct list_head *list) +{ + return list_entry(list->next, struct gfn_info, list); +} #define shr_lock_init(_i) \ do { \ @@ -97,8 +116,6 @@ static shr_lock_t shr_lock; spin_unlock(&shr_lock.lock); \ } while (0) - - static void mem_sharing_hash_init(void) { int i; @@ -123,9 +140,21 @@ static gfn_info_t *mem_sharing_gfn_alloc return xmalloc(gfn_info_t); } -static void mem_sharing_gfn_destroy(gfn_info_t *gfn_info) -{ - xfree(gfn_info); +static void mem_sharing_gfn_destroy(gfn_info_t *gfn, int was_shared) +{ + /* Decrement the number of pages, if the gfn was shared before */ + if(was_shared) + { + struct domain *d = get_domain_by_id(gfn->domain); + /* Domain may have been destroyed by now, if we are called from + * p2m_teardown */ + if(d) + { + atomic_dec(&d->shr_pages); + put_domain(d); + } + } + xfree(gfn); } static shr_hash_entry_t* mem_sharing_hash_lookup(shr_handle_t handle) @@ -219,6 +248,11 @@ static struct page_info* mem_sharing_all return page; } +unsigned int mem_sharing_get_nr_saved_mfns(void) +{ + return (unsigned int)atomic_read(&nr_saved_mfns); +} + int mem_sharing_sharing_resume(struct domain *d) { mem_event_response_t rsp; @@ -290,6 +324,61 @@ shared_entry_header(struct grant_table * return &shared_entry_v2(t, ref).hdr; } +static int mem_sharing_gref_to_gfn(struct domain *d, + grant_ref_t ref, + unsigned long *gfn) +{ + if(d->grant_table->gt_version < 1) + return -1; + + if (d->grant_table->gt_version == 1) + { + grant_entry_v1_t *sha1; + sha1 = &shared_entry_v1(d->grant_table, ref); + *gfn = sha1->frame; + return 0; + } + else + { + grant_entry_v2_t *sha2; + sha2 = &shared_entry_v2(d->grant_table, ref); + *gfn = sha2->full_page.frame; + return 0; + } + + return -2; +} + +/* Account for a GFN being shared/unshared. + * When sharing this function needs to be called _before_ gfn lists are merged + * together, but _after_ gfn is removed from the list when unsharing. + */ +static int mem_sharing_gfn_account(struct gfn_info *gfn, int sharing) +{ + struct domain *d; + + /* A) When sharing: + * if the gfn being shared is in > 1 long list, its already been + * accounted for + * B) When unsharing: + * if the list is longer than > 1, we don't have to account yet. + */ + if(list_has_one_entry(&gfn->list)) + { + d = get_domain_by_id(gfn->domain); + BUG_ON(!d); + if(sharing) + atomic_inc(&d->shr_pages); + else + atomic_dec(&d->shr_pages); + put_domain(d); + + return 1; + } + + return 0; +} + int mem_sharing_debug_gref(struct domain *d, grant_ref_t ref) { grant_entry_header_t *shah; @@ -302,21 +391,12 @@ int mem_sharing_debug_gref(struct domain d->domain_id, ref); return -1; } + mem_sharing_gref_to_gfn(d, ref, &gfn); shah = shared_entry_header(d->grant_table, ref); if (d->grant_table->gt_version == 1) - { - grant_entry_v1_t *sha1; - sha1 = &shared_entry_v1(d->grant_table, ref); status = shah->flags; - gfn = sha1->frame; - } else - { - grant_entry_v2_t *sha2; - sha2 = &shared_entry_v2(d->grant_table, ref); status = status_entry(d->grant_table, ref); - gfn = sha2->full_page.frame; - } printk("==> Grant [dom=%d,ref=%d], status=%x. ", d->domain_id, ref, status); @@ -381,7 +461,7 @@ int mem_sharing_nominate_page(struct dom * since no-one knew that the mfn was temporarily sharable */ ASSERT(page_make_private(d, page) == 0); mem_sharing_hash_destroy(hash_entry); - mem_sharing_gfn_destroy(gfn_info); + mem_sharing_gfn_destroy(gfn_info, 0); shr_unlock(); goto out; } @@ -415,14 +495,17 @@ int mem_sharing_share_pages(shr_handle_t shr_lock(); - ret = -1; + ret = XEN_DOMCTL_MEM_SHARING_S_HANDLE_INVALID; se = mem_sharing_hash_lookup(sh); if(se == NULL) goto err_out; - ret = -2; + ret = XEN_DOMCTL_MEM_SHARING_C_HANDLE_INVALID; ce = mem_sharing_hash_lookup(ch); if(ce == NULL) goto err_out; spage = mfn_to_page(se->mfn); cpage = mfn_to_page(ce->mfn); + /* gfn lists always have at least one entry => save to call list_entry */ + mem_sharing_gfn_account(gfn_get_info(&ce->gfns), 1); + mem_sharing_gfn_account(gfn_get_info(&se->gfns), 1); list_for_each_safe(le, te, &ce->gfns) { gfn = list_entry(le, struct gfn_info, list); @@ -440,6 +523,7 @@ int mem_sharing_share_pages(shr_handle_t } ASSERT(list_empty(&ce->gfns)); mem_sharing_hash_delete(ch); + atomic_inc(&nr_saved_mfns); /* Free the client page */ if(test_and_clear_bit(_PGC_allocated, &cpage->count_info)) put_page(cpage); @@ -491,8 +575,13 @@ gfn_found: * (possibly freeing the page), and exit early */ if(flags & MEM_SHARING_DESTROY_GFN) { - mem_sharing_gfn_destroy(gfn_info); - if(last_gfn) mem_sharing_hash_delete(handle); + mem_sharing_gfn_destroy(gfn_info, !last_gfn); + if(last_gfn) + mem_sharing_hash_delete(handle); + else + /* Even though we don't allocate a private page, we have to account + * for the MFN that originally backed this PFN. */ + atomic_dec(&nr_saved_mfns); shr_unlock(); put_page_and_type(page); if(last_gfn && @@ -528,8 +617,11 @@ gfn_found: private_page_found: /* We've got a private page, we can commit the gfn destruction */ - mem_sharing_gfn_destroy(gfn_info); - if(last_gfn) mem_sharing_hash_delete(handle); + mem_sharing_gfn_destroy(gfn_info, !last_gfn); + if(last_gfn) + mem_sharing_hash_delete(handle); + else + atomic_dec(&nr_saved_mfns); shr_unlock(); if(p2m_change_type(d, gfn, p2m_ram_shared, p2m_ram_rw) != @@ -544,6 +636,93 @@ private_page_found: return 0; } +int mem_sharing_domctl(struct domain *d, xen_domctl_mem_sharing_op_t *mec) +{ + int rc; + + switch(mec->op) + { + case XEN_DOMCTL_MEM_SHARING_OP_CONTROL: + { + rc = 0; + if(!hap_enabled(d)) + return -EINVAL; + d->arch.hvm_domain.mem_sharing_enabled = mec->enable; + return 0; + } + break; + + case XEN_DOMCTL_MEM_SHARING_OP_NOMINATE_GFN: + { + unsigned long gfn = mec->nominate.gfn; + shr_handle_t handle; + if(!mem_sharing_enabled(d)) + return -EINVAL; + rc = mem_sharing_nominate_page(d, gfn, 0, &handle); + mec->nominate.handle = handle; + } + break; + + case XEN_DOMCTL_MEM_SHARING_OP_NOMINATE_GREF: + { + grant_ref_t gref = mec->nominate.grant_ref; + unsigned long gfn; + shr_handle_t handle; + + if(!mem_sharing_enabled(d)) + return -EINVAL; + if(mem_sharing_gref_to_gfn(d, gref, &gfn) < 0) + return -EINVAL; + rc = mem_sharing_nominate_page(d, gfn, 3, &handle); + mec->nominate.handle = handle; + } + break; + + case XEN_DOMCTL_MEM_SHARING_OP_SHARE: + { + shr_handle_t sh = mec->share.source_handle; + shr_handle_t ch = mec->share.client_handle; + rc = mem_sharing_share_pages(sh, ch); + } + break; + + case XEN_DOMCTL_MEM_SHARING_OP_RESUME: + { + if(!mem_sharing_enabled(d)) + return -EINVAL; + rc = mem_sharing_sharing_resume(d); + } + break; + + case XEN_DOMCTL_MEM_SHARING_OP_DEBUG_GFN: + { + unsigned long gfn = mec->debug.gfn; + rc = mem_sharing_debug_gfn(d, gfn); + } + break; + + case XEN_DOMCTL_MEM_SHARING_OP_DEBUG_MFN: + { + unsigned long mfn = mec->debug.mfn; + rc = mem_sharing_debug_mfn(mfn); + } + break; + + case XEN_DOMCTL_MEM_SHARING_OP_DEBUG_GREF: + { + grant_ref_t gref = mec->debug.gref; + rc = mem_sharing_debug_gref(d, gref); + } + break; + + default: + rc = -ENOSYS; + break; + } + + return rc; +} + void mem_sharing_init(void) { printk("Initing memory sharing.\n"); diff -r 8cf5bffd9663 -r 68e964ec2c7b xen/common/domctl.c --- a/xen/common/domctl.c Thu Dec 17 06:27:56 2009 +0000 +++ b/xen/common/domctl.c Thu Dec 17 06:27:56 2009 +0000 @@ -136,6 +136,7 @@ void getdomaininfo(struct domain *d, str info->tot_pages = d->tot_pages; info->max_pages = d->max_pages; + info->shr_pages = atomic_read(&d->shr_pages); info->shared_info_frame = mfn_to_gmfn(d, __pa(d->shared_info)>>PAGE_SHIFT); BUG_ON(SHARED_M2P(info->shared_info_frame)); diff -r 8cf5bffd9663 -r 68e964ec2c7b xen/include/asm-x86/hvm/domain.h --- a/xen/include/asm-x86/hvm/domain.h Thu Dec 17 06:27:56 2009 +0000 +++ b/xen/include/asm-x86/hvm/domain.h Thu Dec 17 06:27:56 2009 +0000 @@ -90,6 +90,7 @@ struct hvm_domain { struct viridian_domain viridian; bool_t hap_enabled; + bool_t mem_sharing_enabled; bool_t qemu_mapcache_invalidate; bool_t is_s3_suspended; diff -r 8cf5bffd9663 -r 68e964ec2c7b xen/include/asm-x86/mem_sharing.h --- a/xen/include/asm-x86/mem_sharing.h Thu Dec 17 06:27:56 2009 +0000 +++ b/xen/include/asm-x86/mem_sharing.h Thu Dec 17 06:27:56 2009 +0000 @@ -27,6 +27,7 @@ typedef uint64_t shr_handle_t; +unsigned int mem_sharing_get_nr_saved_mfns(void); int mem_sharing_nominate_page(struct domain *d, unsigned long gfn, int expected_refcnt, @@ -38,6 +39,8 @@ int mem_sharing_unshare_page(struct doma uint16_t flags); int mem_sharing_sharing_resume(struct domain *d); int mem_sharing_cache_resize(struct domain *d, int new_size); +int mem_sharing_domctl(struct domain *d, + xen_domctl_mem_sharing_op_t *mec); void mem_sharing_init(void); #endif /* __MEM_SHARING_H__ */ diff -r 8cf5bffd9663 -r 68e964ec2c7b xen/include/public/domctl.h --- a/xen/include/public/domctl.h Thu Dec 17 06:27:56 2009 +0000 +++ b/xen/include/public/domctl.h Thu Dec 17 06:27:56 2009 +0000 @@ -33,6 +33,7 @@ #endif #include "xen.h" +#include "grant_table.h" #define XEN_DOMCTL_INTERFACE_VERSION 0x00000005 @@ -103,6 +104,7 @@ struct xen_domctl_getdomaininfo { uint32_t flags; /* XEN_DOMINF_* */ uint64_aligned_t tot_pages; uint64_aligned_t max_pages; + uint64_aligned_t shr_pages; uint64_aligned_t shared_info_frame; /* GMFN of shared_info struct */ uint64_aligned_t cpu_time; uint32_t nr_online_vcpus; /* Number of VCPUs currently online. */ @@ -726,6 +728,52 @@ struct xen_domctl_mem_event_op { }; typedef struct xen_domctl_mem_event_op xen_domctl_mem_event_op_t; DEFINE_XEN_GUEST_HANDLE(xen_domctl_mem_event_op_t); + +/* + * Memory sharing operations + */ +#define XEN_DOMCTL_mem_sharing_op 58 + +#define XEN_DOMCTL_MEM_SHARING_OP_CONTROL 0 +#define XEN_DOMCTL_MEM_SHARING_OP_NOMINATE_GFN 1 +#define XEN_DOMCTL_MEM_SHARING_OP_NOMINATE_GREF 2 +#define XEN_DOMCTL_MEM_SHARING_OP_SHARE 3 +#define XEN_DOMCTL_MEM_SHARING_OP_RESUME 4 +#define XEN_DOMCTL_MEM_SHARING_OP_DEBUG_GFN 5 +#define XEN_DOMCTL_MEM_SHARING_OP_DEBUG_MFN 6 +#define XEN_DOMCTL_MEM_SHARING_OP_DEBUG_GREF 7 + +#define XEN_DOMCTL_MEM_SHARING_S_HANDLE_INVALID (-10) +#define XEN_DOMCTL_MEM_SHARING_C_HANDLE_INVALID (-9) + +struct xen_domctl_mem_sharing_op { + uint8_t op; /* XEN_DOMCTL_MEM_EVENT_OP_* */ + + union { + int enable; /* for OP_CONTROL */ + + struct mem_sharing_op_nominate { /* for OP_NOMINATE */ + union { + unsigned long gfn; /* IN: gfn to nominate */ + uint32_t grant_ref; /* IN: grant ref to nominate */ + }; + uint64_t handle; /* OUT: the handle */ + } nominate; + struct mem_sharing_op_share { + uint64_t source_handle; /* IN: handle to the source page */ + uint64_t client_handle; /* IN: handle to the client page */ + } share; + struct mem_sharing_op_debug { + union { + unsigned long gfn; /* IN: gfn to debug */ + unsigned long mfn; /* IN: mfn to debug */ + grant_ref_t gref; /* IN: gref to debug */ + }; + } debug; + }; +}; +typedef struct xen_domctl_mem_sharing_op xen_domctl_mem_sharing_op_t; +DEFINE_XEN_GUEST_HANDLE(xen_domctl_mem_sharing_op_t); struct xen_domctl { @@ -772,6 +820,7 @@ struct xen_domctl { struct xen_domctl_subscribe subscribe; struct xen_domctl_debug_op debug_op; struct xen_domctl_mem_event_op mem_event_op; + struct xen_domctl_mem_sharing_op mem_sharing_op; #if defined(__i386__) || defined(__x86_64__) struct xen_domctl_cpuid cpuid; #endif diff -r 8cf5bffd9663 -r 68e964ec2c7b xen/include/public/memory.h --- a/xen/include/public/memory.h Thu Dec 17 06:27:56 2009 +0000 +++ b/xen/include/public/memory.h Thu Dec 17 06:27:56 2009 +0000 @@ -281,6 +281,13 @@ struct xen_pod_target { domid_t domid; }; typedef struct xen_pod_target xen_pod_target_t; + +/* + * Get the number of MFNs saved through memory sharing. + * The call never fails. + */ +#define XENMEM_get_sharing_freed_pages 18 + #endif /* __XEN_PUBLIC_MEMORY_H__ */ /* diff -r 8cf5bffd9663 -r 68e964ec2c7b xen/include/xen/sched.h --- a/xen/include/xen/sched.h Thu Dec 17 06:27:56 2009 +0000 +++ b/xen/include/xen/sched.h Thu Dec 17 06:27:56 2009 +0000 @@ -201,6 +201,7 @@ struct domain struct page_list_head xenpage_list; /* linked list (size xenheap_pages) */ unsigned int tot_pages; /* number of pages currently possesed */ unsigned int max_pages; /* maximum value for tot_pages */ + atomic_t shr_pages; /* number of shared pages */ unsigned int xenheap_pages; /* # pages allocated from Xen heap */ unsigned int max_vcpus; _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |