@@ -1005,6 +1005,8 @@ int domain_relinquish_resources(struct domain *d)
BUG();
}
+ free_shared_info(d);
+
return 0;
}
@@ -690,7 +690,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);
@@ -2245,6 +2244,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. */