[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH 1 of 3] x86/mm/sharing: Clean ups for relinquishing shared pages on destroy
xen/arch/x86/domain.c | 16 ++++++++++++- xen/arch/x86/mm/mem_sharing.c | 45 +++++++++++++++++++++++++++++++++++++++ xen/arch/x86/mm/p2m.c | 4 +++ xen/include/asm-arm/mm.h | 4 +++ xen/include/asm-x86/domain.h | 1 + xen/include/asm-x86/mem_sharing.h | 10 ++++++++ xen/include/asm-x86/p2m.h | 4 +++ 7 files changed, 82 insertions(+), 2 deletions(-) When a domain is destroyed, its pages are freed in relinquish_resources in a preemptible mode, in the context of a synchronous domctl. P2m entries pointing to shared pages are, however, released during p2m cleanup in an RCU callback, and in non-preemptible mode. This is an O(n) operation for a very large n, which may include actually freeing shared pages for which the domain is the last holder. To improve responsiveness, move this operation to the preemtible portion of domain destruction, during the synchronous domain_kill hypercall. And remove the bulk of the work from the RCU callback. Signed-off-by: Andres Lagar-Cavilla <andres@xxxxxxxxxxxxxxxx> diff -r c74fe64aafeb -r 9cbdf6b230dc xen/arch/x86/domain.c --- a/xen/arch/x86/domain.c +++ b/xen/arch/x86/domain.c @@ -2132,10 +2132,22 @@ int domain_relinquish_resources(struct d } } - d->arch.relmem = RELMEM_xen; + d->arch.relmem = RELMEM_shared; /* fallthrough */ - /* Relinquish every page of memory. */ + case RELMEM_shared: + + if ( is_hvm_domain(d) ) + { + /* If the domain has shared pages, relinquish them allowing + * for preemption. */ + ret = relinquish_shared_pages(d); + if ( ret ) + return ret; + } + + d->arch.relmem = RELMEM_xen; + /* Fallthrough. Relinquish every page of memory. */ case RELMEM_xen: ret = relinquish_memory(d, &d->xenpage_list, ~0UL); if ( ret ) diff -r c74fe64aafeb -r 9cbdf6b230dc xen/arch/x86/mm/mem_sharing.c --- a/xen/arch/x86/mm/mem_sharing.c +++ b/xen/arch/x86/mm/mem_sharing.c @@ -33,6 +33,7 @@ #include <asm/mem_event.h> #include <asm/atomic.h> #include <xen/rcupdate.h> +#include <asm/event.h> #include "mm-locks.h" @@ -1034,6 +1035,50 @@ private_page_found: return 0; } +int relinquish_shared_pages(struct domain *d) +{ + int rc = 0; + struct p2m_domain *p2m = p2m_get_hostp2m(d); + unsigned long gfn, count = 0; + + if ( p2m == NULL ) + return 0; + + p2m_lock(p2m); + for (gfn = p2m->next_shared_gfn_to_relinquish; + gfn < p2m->max_mapped_pfn; gfn++ ) + { + p2m_access_t a; + p2m_type_t t; + mfn_t mfn; + if ( atomic_read(&d->shr_pages) == 0 ) + break; + mfn = p2m->get_entry(p2m, gfn, &t, &a, 0, NULL); + if ( mfn_valid(mfn) && (t == p2m_ram_shared) ) + { + /* Does not fail with ENOMEM given the DESTROY flag */ + BUG_ON(__mem_sharing_unshare_page(d, gfn, + MEM_SHARING_DESTROY_GFN)); + /* 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); + count++; + } + + /* Preempt every 2MiB. Arbitrary */ + if ( (count == 512) && hypercall_preempt_check() ) + { + p2m->next_shared_gfn_to_relinquish = gfn + 1; + rc = -EAGAIN; + break; + } + } + + p2m_unlock(p2m); + return rc; +} + int mem_sharing_memop(struct domain *d, xen_mem_sharing_op_t *mec) { int rc = 0; diff -r c74fe64aafeb -r 9cbdf6b230dc xen/arch/x86/mm/p2m.c --- a/xen/arch/x86/mm/p2m.c +++ b/xen/arch/x86/mm/p2m.c @@ -371,9 +371,13 @@ void p2m_teardown(struct p2m_domain *p2m p2m_lock(p2m); #ifdef __x86_64__ + /* Try to unshare any remaining shared p2m entries. Safeguard + * Since relinquish_shared_pages should have done the work. */ for ( gfn=0; gfn < p2m->max_mapped_pfn; gfn++ ) { p2m_access_t a; + if ( atomic_read(&d->shr_pages) == 0 ) + break; mfn = p2m->get_entry(p2m, gfn, &t, &a, 0, NULL); if ( mfn_valid(mfn) && (t == p2m_ram_shared) ) { diff -r c74fe64aafeb -r 9cbdf6b230dc xen/include/asm-arm/mm.h --- a/xen/include/asm-arm/mm.h +++ b/xen/include/asm-arm/mm.h @@ -251,6 +251,10 @@ int get_page(struct page_info *page, st static inline void put_gfn(struct domain *d, unsigned long gfn) {} static inline void mem_event_cleanup(struct domain *d) {} +static inline int relinquish_shared_pages(struct domain *d) +{ + return 0; +} #define INVALID_MFN (~0UL) diff -r c74fe64aafeb -r 9cbdf6b230dc xen/include/asm-x86/domain.h --- a/xen/include/asm-x86/domain.h +++ b/xen/include/asm-x86/domain.h @@ -296,6 +296,7 @@ struct arch_domain /* Continuable domain_relinquish_resources(). */ enum { RELMEM_not_started, + RELMEM_shared, RELMEM_xen, RELMEM_l4, RELMEM_l3, diff -r c74fe64aafeb -r 9cbdf6b230dc xen/include/asm-x86/mem_sharing.h --- a/xen/include/asm-x86/mem_sharing.h +++ b/xen/include/asm-x86/mem_sharing.h @@ -89,9 +89,19 @@ int mem_sharing_domctl(struct domain *d, int mem_sharing_audit(void); void mem_sharing_init(void); +/* Scans the p2m and relinquishes any shared pages, destroying + * those for which this domain holds the final reference. + * Preemptible. + */ +int relinquish_shared_pages(struct domain *d); + #else #define mem_sharing_init() do { } while (0) +static inline int relinquish_shared_pages(struct domain *d) +{ + return 0; +} #endif /* __x86_64__ */ diff -r c74fe64aafeb -r 9cbdf6b230dc xen/include/asm-x86/p2m.h --- a/xen/include/asm-x86/p2m.h +++ b/xen/include/asm-x86/p2m.h @@ -260,6 +260,10 @@ struct p2m_domain { /* Highest guest frame that's ever been mapped in the p2m */ unsigned long max_mapped_pfn; + /* When releasing shared gfn's in a preemptible manner, recall where + * to resume the search */ + unsigned long next_shared_gfn_to_relinquish; + /* Populate-on-demand variables * All variables are protected with the pod lock. We cannot rely on * the p2m lock if it's turned into a fine-grained lock. _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx http://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |