[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [xen-unstable] This patch defines a new P2M type used for sharable/shared pages. It also
# HG changeset patch # User Keir Fraser <keir.fraser@xxxxxxxxxx> # Date 1261031276 0 # Node ID 7d841016536f4e5de66b387114c8e4ed67f76148 # Parent 3a3be3938b2c71d179330b10fcb187db00c837b2 This patch defines a new P2M type used for sharable/shared pages. It also implements the basic functions to nominate GFNs for sharing, and to break sharing (either by making page 'private' or creating private copy), mem_sharing_nominate_page() and mem_sharing_unshare_page() respectively. Note pages cannot be shared yet, because there is no efficient way to find all GFNs mapping to the two MFNs scheduled for sharing. Signed-off-by: Grzegorz Milos <Grzegorz.Milos@xxxxxxxxxx> --- tools/xenpaging/xenpaging.c | 4 xen/arch/x86/mm/Makefile | 1 xen/arch/x86/mm/mem_sharing.c | 268 ++++++++++++++++++++++++++++++++++++++ xen/arch/x86/mm/p2m.c | 41 +++++ xen/include/asm-x86/mem_sharing.h | 38 +++++ xen/include/asm-x86/p2m.h | 20 ++ xen/include/public/mem_event.h | 4 7 files changed, 369 insertions(+), 7 deletions(-) diff -r 3a3be3938b2c -r 7d841016536f tools/xenpaging/xenpaging.c --- a/tools/xenpaging/xenpaging.c Thu Dec 17 06:27:56 2009 +0000 +++ b/tools/xenpaging/xenpaging.c Thu Dec 17 06:27:56 2009 +0000 @@ -566,11 +566,11 @@ int main(int argc, char *argv[]) else { DPRINTF("page already populated (domain = %d; vcpu = %d; gfn = %lx; paused = %ld)\n", - paging->mem_event.domain_id, req.vcpu_id, req.gfn, req.flags & MEM_EVENT_FLAG_PAUSED); + paging->mem_event.domain_id, req.vcpu_id, req.gfn, req.flags & MEM_EVENT_FLAG_VCPU_PAUSED); /* Tell Xen to resume the vcpu */ /* XXX: Maybe just check if the vcpu was paused? */ - if ( req.flags & MEM_EVENT_FLAG_PAUSED ) + if ( req.flags & MEM_EVENT_FLAG_VCPU_PAUSED ) { /* Prepare the response */ rsp.gfn = req.gfn; diff -r 3a3be3938b2c -r 7d841016536f xen/arch/x86/mm/Makefile --- a/xen/arch/x86/mm/Makefile Thu Dec 17 06:27:56 2009 +0000 +++ b/xen/arch/x86/mm/Makefile Thu Dec 17 06:27:56 2009 +0000 @@ -8,6 +8,7 @@ obj-$(x86_64) += guest_walk_4.o obj-$(x86_64) += guest_walk_4.o obj-y += mem_event.o obj-y += mem_paging.o +obj-y += mem_sharing.o guest_walk_%.o: guest_walk.c Makefile $(CC) $(CFLAGS) -DGUEST_PAGING_LEVELS=$* -c $< -o $@ diff -r 3a3be3938b2c -r 7d841016536f xen/arch/x86/mm/mem_sharing.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xen/arch/x86/mm/mem_sharing.c Thu Dec 17 06:27:56 2009 +0000 @@ -0,0 +1,268 @@ +/****************************************************************************** + * arch/x86/mm/mem_sharing.c + * + * Memory sharing support. + * + * Copyright (c) 2009 Citrix (R&D) Ltd. (Grzegorz Milos) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <asm/page.h> +#include <asm/string.h> +#include <asm/p2m.h> +#include <asm/mem_event.h> +#include <xen/domain_page.h> + +#undef mfn_to_page +#define mfn_to_page(_m) __mfn_to_page(mfn_x(_m)) +#undef mfn_valid +#define mfn_valid(_mfn) __mfn_valid(mfn_x(_mfn)) +#undef page_to_mfn +#define page_to_mfn(_pg) _mfn(__page_to_mfn(_pg)) + + +static struct page_info* mem_sharing_alloc_page(struct domain *d, + unsigned long gfn, + int must_succeed) +{ + struct page_info* page; + struct vcpu *v = current; + mem_event_request_t req; + + page = alloc_domheap_page(d, 0); + if(page != NULL) return page; + + memset(&req, 0, sizeof(req)); + if(must_succeed) + { + /* We do not support 'must_succeed' any more. External operations such + * as grant table mappings may fail with OOM condition! + */ + BUG(); + } + else + { + /* All foreign attempts to unshare pages should be handled through + * 'must_succeed' case. */ + ASSERT(v->domain->domain_id == d->domain_id); + vcpu_pause_nosync(v); + req.flags |= MEM_EVENT_FLAG_VCPU_PAUSED; + } + + /* XXX: Need to reserve a request, not just check the ring! */ + if(mem_event_check_ring(d)) return page; + + req.flags |= MEM_EVENT_FLAG_OUT_OF_MEM; + req.gfn = gfn; + req.p2mt = p2m_ram_shared; + req.vcpu_id = v->vcpu_id; + mem_event_put_request(d, &req); + + return page; +} + +int mem_sharing_sharing_resume(struct domain *d) +{ + mem_event_response_t rsp; + + /* Get request off the ring */ + mem_event_get_response(d, &rsp); + + /* Unpause domain/vcpu */ + if( rsp.flags & MEM_EVENT_FLAG_VCPU_PAUSED ) + vcpu_unpause(d->vcpu[rsp.vcpu_id]); + if( rsp.flags & MEM_EVENT_FLAG_DOM_PAUSED ) + domain_unpause(d); + + return 0; +} + +int mem_sharing_debug_mfn(unsigned long mfn) +{ + struct page_info *page; + + if(!mfn_valid(_mfn(mfn))) + { + printk("Invalid MFN=%lx\n", mfn); + return -1; + } + page = mfn_to_page(_mfn(mfn)); + + printk("Debug page: MFN=%lx is ci=%lx, ti=%lx, owner_id=%d\n", + mfn_x(page_to_mfn(page)), + page->count_info, + page->u.inuse.type_info, + page_get_owner(page)->domain_id); + + return 0; +} + +int mem_sharing_debug_gfn(struct domain *d, unsigned long gfn) +{ + p2m_type_t p2mt; + mfn_t mfn; + struct page_info *page; + + mfn = gfn_to_mfn(d, gfn, &p2mt); + page = mfn_to_page(mfn); + + printk("Debug for domain=%d, gfn=%lx, ", + d->domain_id, + gfn); + return mem_sharing_debug_mfn(mfn_x(mfn)); +} + +#define SHGNT_PER_PAGE_V1 (PAGE_SIZE / sizeof(grant_entry_v1_t)) +#define shared_entry_v1(t, e) \ + ((t)->shared_v1[(e)/SHGNT_PER_PAGE_V1][(e)%SHGNT_PER_PAGE_V1]) +#define SHGNT_PER_PAGE_V2 (PAGE_SIZE / sizeof(grant_entry_v2_t)) +#define shared_entry_v2(t, e) \ + ((t)->shared_v2[(e)/SHGNT_PER_PAGE_V2][(e)%SHGNT_PER_PAGE_V2]) +#define STGNT_PER_PAGE (PAGE_SIZE / sizeof(grant_status_t)) +#define status_entry(t, e) \ + ((t)->status[(e)/STGNT_PER_PAGE][(e)%STGNT_PER_PAGE]) + +static grant_entry_header_t * +shared_entry_header(struct grant_table *t, grant_ref_t ref) +{ + ASSERT(t->gt_version != 0); + if (t->gt_version == 1) + return (grant_entry_header_t*)&shared_entry_v1(t, ref); + else + return &shared_entry_v2(t, ref).hdr; +} + +int mem_sharing_debug_gref(struct domain *d, grant_ref_t ref) +{ + grant_entry_header_t *shah; + uint16_t status; + unsigned long gfn; + + if(d->grant_table->gt_version < 1) + { + printk("Asked to debug [dom=%d,gref=%d], but not yet inited.\n", + d->domain_id, ref); + return -1; + } + 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); + + return mem_sharing_debug_gfn(d, gfn); +} + +int mem_sharing_nominate_page(struct domain *d, + unsigned long gfn, + int expected_refcnt) +{ + p2m_type_t p2mt; + mfn_t mfn; + struct page_info *page; + int ret; + + mfn = gfn_to_mfn(d, gfn, &p2mt); + + /* Check if mfn is valid */ + ret = -EINVAL; + if (!mfn_valid(mfn)) + goto out; + + /* Check p2m type */ + if (!p2m_is_sharable(p2mt)) + goto out; + + /* Try to convert the mfn to the sharable type */ + page = mfn_to_page(mfn); + ret = page_make_sharable(d, page, expected_refcnt); + if(ret) + goto out; + + /* Change the p2m type */ + if(p2m_change_type(d, gfn, p2mt, p2m_ram_shared) != p2mt) + { + /* This is unlikely, as the type must have changed since we've checked + * it a few lines above. + * The mfn needs to revert back to rw type. This should never fail, + * since no-one knew that the mfn was temporarily sharable */ + ASSERT(page_make_private(d, page) == 0); + goto out; + } + + ret = 0; + +out: + return ret; +} + +int mem_sharing_unshare_page(struct domain *d, + unsigned long gfn, + uint16_t flags) +{ + p2m_type_t p2mt; + mfn_t mfn; + struct page_info *page, *old_page; + void *s, *t; + int ret; + + mfn = gfn_to_mfn(d, gfn, &p2mt); + + page = mfn_to_page(mfn); + + ret = page_make_private(d, page); + if(ret == 0) goto private_page_found; + + old_page = page; + page = mem_sharing_alloc_page(d, gfn, flags & MEM_SHARING_MUST_SUCCEED); + BUG_ON(!page && (flags & MEM_SHARING_MUST_SUCCEED)); + if(!page) return -ENOMEM; + + s = map_domain_page(__page_to_mfn(old_page)); + t = map_domain_page(__page_to_mfn(page)); + memcpy(t, s, PAGE_SIZE); + unmap_domain_page(s); + unmap_domain_page(t); + + ASSERT(set_shared_p2m_entry(d, gfn, page_to_mfn(page)) != 0); + put_page_and_type(old_page); + +private_page_found: + if(p2m_change_type(d, gfn, p2m_ram_shared, p2m_ram_rw) != + p2m_ram_shared) + { + printk("Could not change p2m type.\n"); + BUG(); + } + + return 0; +} + + + diff -r 3a3be3938b2c -r 7d841016536f xen/arch/x86/mm/p2m.c --- a/xen/arch/x86/mm/p2m.c Thu Dec 17 06:27:56 2009 +0000 +++ b/xen/arch/x86/mm/p2m.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> #include <xen/event.h> /* Debugging and auditing of the P2M code? */ @@ -1629,8 +1630,17 @@ void p2m_teardown(struct domain *d) { struct page_info *pg; struct p2m_domain *p2m = d->arch.p2m; + unsigned long gfn; + p2m_type_t t; + mfn_t mfn; p2m_lock(p2m); + for(gfn=0; gfn < p2m->max_mapped_pfn; gfn++) + { + mfn = p2m->get_entry(d, gfn, &t, p2m_query); + if(mfn_valid(mfn) && (t == p2m_ram_shared)) + BUG_ON(mem_sharing_unshare_page(d, gfn, MEM_SHARING_DESTROY_GFN)); + } d->arch.phys_table = pagetable_null(); while ( (pg = page_list_remove_head(&p2m->pages)) ) @@ -2301,6 +2311,33 @@ clear_mmio_p2m_entry(struct domain *d, u return rc; } +int +set_shared_p2m_entry(struct domain *d, unsigned long gfn, mfn_t mfn) +{ + int rc = 0; + p2m_type_t ot; + mfn_t omfn; + + if ( !paging_mode_translate(d) ) + return 0; + + omfn = gfn_to_mfn_query(d, gfn, &ot); + /* At the moment we only allow p2m change if gfn has already been made + * sharable first */ + ASSERT(p2m_is_shared(ot)); + ASSERT(mfn_valid(omfn)); + /* XXX: M2P translations have to be handled properly for shared pages */ + set_gpfn_from_mfn(mfn_x(omfn), INVALID_M2P_ENTRY); + + P2M_DEBUG("set shared %lx %lx\n", gfn, mfn_x(mfn)); + rc = set_p2m_entry(d, gfn, mfn, 0, p2m_ram_shared); + if ( 0 == rc ) + gdprintk(XENLOG_ERR, + "set_mmio_p2m_entry: set_p2m_entry failed! mfn=%08lx\n", + gmfn_to_mfn(d, gfn)); + return rc; +} + int p2m_mem_paging_nominate(struct domain *d, unsigned long gfn) { struct page_info *page; @@ -2406,7 +2443,7 @@ void p2m_mem_paging_populate(struct doma if ( v->domain->domain_id == d->domain_id ) { vcpu_pause_nosync(v); - req.flags |= MEM_EVENT_FLAG_PAUSED; + req.flags |= MEM_EVENT_FLAG_VCPU_PAUSED; } /* Send request to pager */ @@ -2450,7 +2487,7 @@ void p2m_mem_paging_resume(struct domain p2m_unlock(d->arch.p2m); /* Unpause domain */ - if ( rsp.flags & MEM_EVENT_FLAG_PAUSED ) + if ( rsp.flags & MEM_EVENT_FLAG_VCPU_PAUSED ) vcpu_unpause(d->vcpu[rsp.vcpu_id]); /* Unpause any domains that were paused because the ring was full */ diff -r 3a3be3938b2c -r 7d841016536f xen/include/asm-x86/mem_sharing.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xen/include/asm-x86/mem_sharing.h Thu Dec 17 06:27:56 2009 +0000 @@ -0,0 +1,38 @@ +/****************************************************************************** + * include/asm-x86/mem_sharing.h + * + * Memory sharing support. + * + * Copyright (c) 2009 Citrix (R)&D) Ltd. (Grzegorz Milos) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef __MEM_SHARING_H__ +#define __MEM_SHARING_H__ + +#define sharing_supported(_d) \ + (is_hvm_domain(_d) && (_d)->arch.hvm_domain.hap_enabled) +int mem_sharing_nominate_page(struct domain *d, + unsigned long gfn, + int expected_refcnt); +#define MEM_SHARING_MUST_SUCCEED (1<<0) +#define MEM_SHARING_DESTROY_GFN (1<<1) +int mem_sharing_unshare_page(struct domain *d, + unsigned long gfn, + uint16_t flags); +int mem_sharing_sharing_resume(struct domain *d); +int mem_sharing_cache_resize(struct domain *d, int new_size); + +#endif /* __MEM_SHARING_H__ */ diff -r 3a3be3938b2c -r 7d841016536f xen/include/asm-x86/p2m.h --- a/xen/include/asm-x86/p2m.h Thu Dec 17 06:27:56 2009 +0000 +++ b/xen/include/asm-x86/p2m.h Thu Dec 17 06:27:56 2009 +0000 @@ -28,6 +28,7 @@ #include <xen/config.h> #include <xen/paging.h> +#include <asm/mem_sharing.h> /* * The phys_to_machine_mapping maps guest physical frame numbers @@ -80,6 +81,8 @@ typedef enum { p2m_ram_paged = 10, /* Memory that has been paged out */ p2m_ram_paging_in = 11, /* Memory that is being paged in */ p2m_ram_paging_in_start = 12, /* Memory that is being paged in */ + + p2m_ram_shared = 13, /* Shared or sharable memory */ } p2m_type_t; typedef enum { @@ -98,7 +101,8 @@ typedef enum { | p2m_to_mask(p2m_ram_paging_out) \ | p2m_to_mask(p2m_ram_paged) \ | p2m_to_mask(p2m_ram_paging_in_start) \ - | p2m_to_mask(p2m_ram_paging_in)) + | p2m_to_mask(p2m_ram_paging_in) \ + | p2m_to_mask(p2m_ram_shared)) /* Grant mapping types, which map to a real machine frame in another * VM */ @@ -112,7 +116,8 @@ typedef enum { /* Read-only types, which must have the _PAGE_RW bit clear in their PTEs */ #define P2M_RO_TYPES (p2m_to_mask(p2m_ram_logdirty) \ | p2m_to_mask(p2m_ram_ro) \ - | p2m_to_mask(p2m_grant_map_ro) ) + | p2m_to_mask(p2m_grant_map_ro) \ + | p2m_to_mask(p2m_ram_shared) ) #define P2M_MAGIC_TYPES (p2m_to_mask(p2m_populate_on_demand)) @@ -125,6 +130,12 @@ typedef enum { | p2m_to_mask(p2m_ram_paging_in)) #define P2M_PAGED_TYPES (p2m_to_mask(p2m_ram_paged)) + +/* Shared types */ +/* XXX: Sharable types could include p2m_ram_ro too, but we would need to + * reinit the type correctly after fault */ +#define P2M_SHARABLE_TYPES (p2m_to_mask(p2m_ram_rw)) +#define P2M_SHARED_TYPES (p2m_to_mask(p2m_ram_shared)) /* Useful predicates */ #define p2m_is_ram(_t) (p2m_to_mask(_t) & P2M_RAM_TYPES) @@ -140,6 +151,8 @@ typedef enum { #define p2m_is_pageable(_t) (p2m_to_mask(_t) & P2M_PAGEABLE_TYPES) #define p2m_is_paging(_t) (p2m_to_mask(_t) & P2M_PAGING_TYPES) #define p2m_is_paged(_t) (p2m_to_mask(_t) & P2M_PAGED_TYPES) +#define p2m_is_sharable(_t) (p2m_to_mask(_t) & P2M_SHARABLE_TYPES) +#define p2m_is_shared(_t) (p2m_to_mask(_t) & P2M_SHARED_TYPES) /* Populate-on-demand */ #define POPULATE_ON_DEMAND_MFN (1<<9) @@ -391,6 +404,9 @@ p2m_type_t p2m_change_type(struct domain /* Set mmio addresses in the p2m table (for pass-through) */ int set_mmio_p2m_entry(struct domain *d, unsigned long gfn, mfn_t mfn); int clear_mmio_p2m_entry(struct domain *d, unsigned long gfn); +/* Modify p2m table for shared gfn */ +int +set_shared_p2m_entry(struct domain *d, unsigned long gfn, mfn_t mfn); /* Check if a nominated gfn is valid to be paged out */ int p2m_mem_paging_nominate(struct domain *d, unsigned long gfn); diff -r 3a3be3938b2c -r 7d841016536f xen/include/public/mem_event.h --- a/xen/include/public/mem_event.h Thu Dec 17 06:27:56 2009 +0000 +++ b/xen/include/public/mem_event.h Thu Dec 17 06:27:56 2009 +0000 @@ -34,7 +34,9 @@ #define MEM_EVENT_MODE_SYNC_ALL (1 << 1) /* Memory event flags */ -#define MEM_EVENT_FLAG_PAUSED (1 << 0) +#define MEM_EVENT_FLAG_VCPU_PAUSED (1 << 0) +#define MEM_EVENT_FLAG_DOM_PAUSED (1 << 1) +#define MEM_EVENT_FLAG_OUT_OF_MEM (1 << 2) typedef struct mem_event_shared_page { _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |