@@ -1006,6 +1006,8 @@ int domain_relinquish_resources(struct domain *d)
BUG();
}
+ free_shared_info(d);
+
return 0;
}
@@ -691,7 +691,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);
@@ -2246,6 +2245,8 @@ int domain_relinquish_resources(struct domain *d)
if ( is_hvm_domain(d) )
hvm_domain_relinquish_resources(d);
+ free_shared_info(d);
+
return 0;
}
@@ -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);
}
/*
@@ -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);
@@ -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. */
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 <pdurrant@amazon.com> --- Cc: Stefano Stabellini <sstabellini@kernel.org> Cc: Julien Grall <julien@xen.org> Cc: Volodymyr Babchuk <Volodymyr_Babchuk@epam.com> Cc: Andrew Cooper <andrew.cooper3@citrix.com> Cc: George Dunlap <george.dunlap@citrix.com> Cc: Ian Jackson <ian.jackson@eu.citrix.com> Cc: Jan Beulich <jbeulich@suse.com> Cc: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> Cc: Wei Liu <wl@xen.org> v2: - Addressed comments from Julien - Expanded the commit comment to explain why this patch is wanted --- xen/arch/arm/domain.c | 2 ++ xen/arch/x86/domain.c | 3 ++- xen/common/domain.c | 28 ++++++++++++++++++++++++---- xen/common/event_channel.c | 3 +++ xen/common/time.c | 15 +++++++++++++++ 5 files changed, 46 insertions(+), 5 deletions(-)