[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [RFC XEN PATCH 04/16] xen/x86: add XENMEM_populate_pmemmap to map host pmem pages to guest
XENMEM_populate_pmemmap is used by toolstack to map given host pmem pages to given guest pages. Only pages in the data area of a pmem region are allowed to be mapped to guest. Signed-off-by: Haozhong Zhang <haozhong.zhang@xxxxxxxxx> --- Cc: Ian Jackson <ian.jackson@xxxxxxxxxxxxx> Cc: Wei Liu <wei.liu2@xxxxxxxxxx> Cc: Jan Beulich <jbeulich@xxxxxxxx> Cc: Andrew Cooper <andrew.cooper3@xxxxxxxxxx> --- tools/libxc/include/xenctrl.h | 8 +++ tools/libxc/xc_domain.c | 14 +++++ xen/arch/x86/pmem.c | 123 ++++++++++++++++++++++++++++++++++++++++++ xen/common/domain.c | 3 ++ xen/common/memory.c | 31 +++++++++++ xen/include/public/memory.h | 14 ++++- xen/include/xen/pmem.h | 10 ++++ xen/include/xen/sched.h | 3 ++ 8 files changed, 205 insertions(+), 1 deletion(-) diff --git a/tools/libxc/include/xenctrl.h b/tools/libxc/include/xenctrl.h index 2c83544..46c71fc 100644 --- a/tools/libxc/include/xenctrl.h +++ b/tools/libxc/include/xenctrl.h @@ -2710,6 +2710,14 @@ int xc_livepatch_revert(xc_interface *xch, char *name, uint32_t timeout); int xc_livepatch_unload(xc_interface *xch, char *name, uint32_t timeout); int xc_livepatch_replace(xc_interface *xch, char *name, uint32_t timeout); +/** + * Map host pmem pages at PFNs @mfn ~ (@mfn + @nr_mfns - 1) to + * guest physical pages at guest PFNs @gpfn ~ (@gpfn + @nr_mfns - 1) + */ +int xc_domain_populate_pmemmap(xc_interface *xch, uint32_t domid, + xen_pfn_t mfn, xen_pfn_t gpfn, + unsigned int nr_mfns); + /* Compat shims */ #include "xenctrl_compat.h" diff --git a/tools/libxc/xc_domain.c b/tools/libxc/xc_domain.c index 296b852..81a90a1 100644 --- a/tools/libxc/xc_domain.c +++ b/tools/libxc/xc_domain.c @@ -2520,6 +2520,20 @@ int xc_domain_soft_reset(xc_interface *xch, domctl.domain = (domid_t)domid; return do_domctl(xch, &domctl); } + +int xc_domain_populate_pmemmap(xc_interface *xch, uint32_t domid, + xen_pfn_t mfn, xen_pfn_t gpfn, + unsigned int nr_mfns) +{ + struct xen_pmemmap pmemmap = { + .domid = domid, + .mfn = mfn, + .gpfn = gpfn, + .nr_mfns = nr_mfns, + }; + return do_memory_op(xch, XENMEM_populate_pmemmap, &pmemmap, sizeof(pmemmap)); +} + /* * Local variables: * mode: C diff --git a/xen/arch/x86/pmem.c b/xen/arch/x86/pmem.c index 70358ed..e4dc685 100644 --- a/xen/arch/x86/pmem.c +++ b/xen/arch/x86/pmem.c @@ -24,6 +24,9 @@ #include <xen/spinlock.h> #include <xen/pmem.h> #include <xen/iocap.h> +#include <xen/sched.h> +#include <xen/event.h> +#include <xen/paging.h> #include <asm-x86/mm.h> /* @@ -63,6 +66,48 @@ static int check_reserved_size(unsigned long rsv_mfns, unsigned long total_mfns) ((sizeof(*machine_to_phys_mapping) * total_mfns) >> PAGE_SHIFT); } +static int is_data_mfn(unsigned long mfn) +{ + struct list_head *cur; + int data = 0; + + ASSERT(spin_is_locked(&pmem_list_lock)); + + list_for_each(cur, &pmem_list) + { + struct pmem *pmem = list_entry(cur, struct pmem, link); + + if ( pmem->data_spfn <= mfn && mfn < pmem->data_epfn ) + { + data = 1; + break; + } + } + + return data; +} + +static int pmem_page_valid(struct page_info *page, struct domain *d) +{ + /* only data area can be mapped to guest */ + if ( !is_data_mfn(page_to_mfn(page)) ) + { + dprintk(XENLOG_DEBUG, "pmem: mfn 0x%lx is not a pmem data page\n", + page_to_mfn(page)); + return 0; + } + + /* inuse/offlined/offlining pmem page cannot be mapped to guest */ + if ( !page_state_is(page, free) ) + { + dprintk(XENLOG_DEBUG, "pmem: invalid page state of mfn 0x%lx: 0x%lx\n", + page_to_mfn(page), page->count_info & PGC_state); + return 0; + } + + return 1; +} + static int pmem_add_check(unsigned long spfn, unsigned long epfn, unsigned long rsv_spfn, unsigned long rsv_epfn, unsigned long data_spfn, unsigned long data_epfn) @@ -159,3 +204,81 @@ int pmem_add(unsigned long spfn, unsigned long epfn, out: return ret; } + +static int pmem_assign_pages(struct domain *d, + struct page_info *pg, unsigned int order) +{ + int rc = 0; + unsigned long i; + + spin_lock(&d->pmem_lock); + + if ( unlikely(d->is_dying) ) + { + rc = -EINVAL; + goto out; + } + + for ( i = 0; i < (1 << order); i++ ) + { + ASSERT(page_get_owner(&pg[i]) == NULL); + ASSERT((pg[i].count_info & ~(PGC_allocated | 1)) == 0); + page_set_owner(&pg[i], d); + smp_wmb(); + pg[i].count_info = PGC_allocated | 1; + page_list_add_tail(&pg[i], &d->pmem_page_list); + } + + out: + spin_unlock(&d->pmem_lock); + return rc; +} + +int pmem_populate(struct xen_pmemmap_args *args) +{ + struct domain *d = args->domain; + unsigned long i, mfn, gpfn; + struct page_info *page; + int rc = 0; + + if ( !has_hvm_container_domain(d) || !paging_mode_translate(d) ) + return -EINVAL; + + for ( i = args->nr_done, mfn = args->mfn + i, gpfn = args->gpfn + i; + i < args->nr_mfns; + i++, mfn++, gpfn++ ) + { + if ( i != args->nr_done && hypercall_preempt_check() ) + { + args->preempted = 1; + goto out; + } + + page = mfn_to_page(mfn); + + spin_lock(&pmem_list_lock); + if ( !pmem_page_valid(page, d) ) + { + dprintk(XENLOG_DEBUG, "pmem: MFN 0x%lx not a valid pmem page\n", mfn); + spin_unlock(&pmem_list_lock); + rc = -EINVAL; + goto out; + } + page->count_info = PGC_state_inuse; + spin_unlock(&pmem_list_lock); + + page->u.inuse.type_info = 0; + + guest_physmap_add_page(d, _gfn(gpfn), _mfn(mfn), 0); + if ( pmem_assign_pages(d, page, 0) ) + { + guest_physmap_remove_page(d, _gfn(gpfn), _mfn(mfn), 0); + rc = -EFAULT; + goto out; + } + } + + out: + args->nr_done = i; + return rc; +} diff --git a/xen/common/domain.c b/xen/common/domain.c index 3abaca9..8192548 100644 --- a/xen/common/domain.c +++ b/xen/common/domain.c @@ -288,6 +288,9 @@ struct domain *domain_create(domid_t domid, unsigned int domcr_flags, INIT_PAGE_LIST_HEAD(&d->page_list); INIT_PAGE_LIST_HEAD(&d->xenpage_list); + spin_lock_init_prof(d, pmem_lock); + INIT_PAGE_LIST_HEAD(&d->pmem_page_list); + spin_lock_init(&d->node_affinity_lock); d->node_affinity = NODE_MASK_ALL; d->auto_node_affinity = 1; diff --git a/xen/common/memory.c b/xen/common/memory.c index 21797ca..09cb1c9 100644 --- a/xen/common/memory.c +++ b/xen/common/memory.c @@ -24,6 +24,7 @@ #include <xen/numa.h> #include <xen/mem_access.h> #include <xen/trace.h> +#include <xen/pmem.h> #include <asm/current.h> #include <asm/hardirq.h> #include <asm/p2m.h> @@ -1329,6 +1330,36 @@ long do_memory_op(unsigned long cmd, XEN_GUEST_HANDLE_PARAM(void) arg) } #endif + case XENMEM_populate_pmemmap: + { + struct xen_pmemmap pmemmap; + struct xen_pmemmap_args args; + + if ( copy_from_guest(&pmemmap, arg, 1) ) + return -EFAULT; + + d = rcu_lock_domain_by_any_id(pmemmap.domid); + if ( !d ) + return -EINVAL; + + args.domain = d; + args.mfn = pmemmap.mfn; + args.gpfn = pmemmap.gpfn; + args.nr_mfns = pmemmap.nr_mfns; + args.nr_done = start_extent; + args.preempted = 0; + + rc = pmem_populate(&args); + rcu_unlock_domain(d); + + if ( !rc && args.preempted ) + return hypercall_create_continuation( + __HYPERVISOR_memory_op, "lh", + op | (args.nr_done << MEMOP_EXTENT_SHIFT), arg); + + break; + } + default: rc = arch_memory_op(cmd, arg); break; diff --git a/xen/include/public/memory.h b/xen/include/public/memory.h index 5bf840f..8c048fc 100644 --- a/xen/include/public/memory.h +++ b/xen/include/public/memory.h @@ -646,7 +646,19 @@ struct xen_vnuma_topology_info { typedef struct xen_vnuma_topology_info xen_vnuma_topology_info_t; DEFINE_XEN_GUEST_HANDLE(xen_vnuma_topology_info_t); -/* Next available subop number is 28 */ +#define XENMEM_populate_pmemmap 28 + +struct xen_pmemmap { + /* IN */ + domid_t domid; + xen_pfn_t mfn; + xen_pfn_t gpfn; + unsigned int nr_mfns; +}; +typedef struct xen_pmemmap xen_pmemmap_t; +DEFINE_XEN_GUEST_HANDLE(xen_pmemmap_t); + +/* Next available subop number is 29 */ #endif /* __XEN_PUBLIC_MEMORY_H__ */ diff --git a/xen/include/xen/pmem.h b/xen/include/xen/pmem.h index a670ab8..60adf56 100644 --- a/xen/include/xen/pmem.h +++ b/xen/include/xen/pmem.h @@ -24,8 +24,18 @@ #include <xen/types.h> +struct xen_pmemmap_args { + struct domain *domain; + xen_pfn_t mfn; + xen_pfn_t gpfn; + unsigned int nr_mfns; + unsigned int nr_done; + int preempted; +}; + int pmem_add(unsigned long spfn, unsigned long epfn, unsigned long rsv_spfn, unsigned long rsv_epfn, unsigned long data_spfn, unsigned long data_epfn); +int pmem_populate(struct xen_pmemmap_args *args); #endif /* __XEN_PMEM_H__ */ diff --git a/xen/include/xen/sched.h b/xen/include/xen/sched.h index 1fbda87..3c66225 100644 --- a/xen/include/xen/sched.h +++ b/xen/include/xen/sched.h @@ -329,6 +329,9 @@ struct domain atomic_t shr_pages; /* number of shared pages */ atomic_t paged_pages; /* number of paged-out pages */ + spinlock_t pmem_lock; /* protect all following pmem_ fields */ + struct page_list_head pmem_page_list; /* linked list of pmem pages */ + /* Scheduling. */ void *sched_priv; /* scheduler-specific data */ struct cpupool *cpupool; -- 2.10.1 _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx https://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |