Message ID | 20200309093511.1727-7-paul@xen.org (mailing list archive) |
---|---|
State | Superseded |
Headers | show |
Series | remove one more shared xenheap page: shared_info | expand |
> -----Original Message----- > From: paul@xen.org <paul@xen.org> > Sent: 09 March 2020 09:35 > To: xen-devel@lists.xenproject.org > Cc: Durrant, Paul <pdurrant@amazon.co.uk>; Paul Durrant <paul@xen.org>; Stefano Stabellini > <sstabellini@kernel.org>; Julien Grall <julien@xen.org>; Volodymyr Babchuk > <Volodymyr_Babchuk@epam.com>; Andrew Cooper <andrew.cooper3@citrix.com>; George Dunlap > <george.dunlap@citrix.com>; Ian Jackson <ian.jackson@eu.citrix.com>; Jan Beulich <jbeulich@suse.com>; > Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>; Wei Liu <wl@xen.org> > Subject: [PATCH v4 6/6] domain: use PGC_extra domheap page for shared_info > > From: Paul Durrant <pdurrant@amazon.com> > > Currently shared_info is a shared xenheap page but shared xenheap pages > complicate future plans for live-update of Xen so it is desirable to, > where possible, not use them [1]. This patch therefore converts shared_info > into a PGC_extra domheap page. This does entail freeing shared_info during > domain_relinquish_resources() rather than domain_destroy() so care is > needed to avoid de-referencing a NULL shared_info pointer hence some > extra checks of 'is_dying' are needed. > > NOTE: For Arm, the call to free_shared_info() in arch_domain_destroy() is > left in place since it is idempotent and called in the error path for > arch_domain_create(). > > [1] See https://lists.xenproject.org/archives/html/xen-devel/2020-02/msg02018.html > > Signed-off-by: Paul Durrant <paul@xen.org> I realise I forgot to fold in the new dump function for shared_info (needed since it will no longer feature in the dump of xen pages) so I will send a v5 of this series shortly. Paul
diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c index 5298d80bd2..741f6dd444 100644 --- a/xen/arch/arm/domain.c +++ b/xen/arch/arm/domain.c @@ -1005,6 +1005,8 @@ int domain_relinquish_resources(struct domain *d) BUG(); } + free_shared_info(d); + return 0; } diff --git a/xen/arch/x86/domain.c b/xen/arch/x86/domain.c index f6ed25e8ee..d962835f33 100644 --- a/xen/arch/x86/domain.c +++ b/xen/arch/x86/domain.c @@ -693,7 +693,6 @@ void arch_domain_destroy(struct domain *d) pv_domain_destroy(d); free_perdomain_mappings(d); - free_shared_info(d); cleanup_domain_irq_mapping(d); psr_domain_free(d); @@ -2249,6 +2248,8 @@ int domain_relinquish_resources(struct domain *d) if ( is_hvm_domain(d) ) hvm_domain_relinquish_resources(d); + free_shared_info(d); + return 0; } diff --git a/xen/common/domain.c b/xen/common/domain.c index ba7a905258..886206f648 100644 --- a/xen/common/domain.c +++ b/xen/common/domain.c @@ -1650,24 +1650,44 @@ int continue_hypercall_on_cpu( int alloc_shared_info(struct domain *d, unsigned int memflags) { - if ( (d->shared_info.virt = alloc_xenheap_pages(0, memflags)) == NULL ) + struct page_info *pg; + + pg = alloc_domheap_page(d, MEMF_no_refcount | memflags); + if ( !pg ) return -ENOMEM; - d->shared_info.mfn = virt_to_mfn(d->shared_info.virt); + if ( !get_page_and_type(pg, d, PGT_writable_page) ) + { + /* + * The domain should not be running at this point so there is + * no way we should reach this error path. + */ + ASSERT_UNREACHABLE(); + return -ENODATA; + } + + d->shared_info.mfn = page_to_mfn(pg); + d->shared_info.virt = __map_domain_page_global(pg); clear_page(d->shared_info.virt); - share_xen_page_with_guest(mfn_to_page(d->shared_info.mfn), d, SHARE_rw); return 0; } void free_shared_info(struct domain *d) { + struct page_info *pg; + if ( !d->shared_info.virt ) return; - free_xenheap_page(d->shared_info.virt); + unmap_domain_page_global(d->shared_info.virt); d->shared_info.virt = NULL; + + pg = mfn_to_page(d->shared_info.mfn); + + put_page_alloc_ref(pg); + put_page_and_type(pg); } /* diff --git a/xen/common/event_channel.c b/xen/common/event_channel.c index e86e2bfab0..a17422284d 100644 --- a/xen/common/event_channel.c +++ b/xen/common/event_channel.c @@ -1325,6 +1325,9 @@ void evtchn_destroy(struct domain *d) { unsigned int i; + /* This must be done before shared_info is freed */ + BUG_ON(!d->shared_info.virt); + /* After this barrier no new event-channel allocations can occur. */ BUG_ON(!d->is_dying); spin_barrier(&d->event_lock); diff --git a/xen/common/time.c b/xen/common/time.c index 58fa9abc40..ada02faf07 100644 --- a/xen/common/time.c +++ b/xen/common/time.c @@ -99,6 +99,18 @@ void update_domain_wallclock_time(struct domain *d) uint32_t *wc_version; uint64_t sec; + if ( d != current->domain ) + { + /* + * We need to check is_dying here as, if it is set, the + * shared_info may have been freed. To do this safely we need + * hold the domain lock. + */ + domain_lock(d); + if ( d->is_dying ) + goto unlock; + } + spin_lock(&wc_lock); wc_version = &shared_info(d, wc_version); @@ -121,6 +133,9 @@ void update_domain_wallclock_time(struct domain *d) *wc_version = version_update_end(*wc_version); spin_unlock(&wc_lock); + unlock: + if ( d != current->domain ) + domain_unlock(d); } /* Set clock to <secs,usecs> after 00:00:00 UTC, 1 January, 1970. */