mirror of
https://github.com/xen-project/xen.git
synced 2026-10-29 18:50:05 +01:00
Implement x86 continuable domain destroy.
This patch addresses the following bug report. http://bugzilla.xensource.com/bugzilla/show_bug.cgi?id=1037 Signed-off-by: Isaku Yamahata <yamahata@valinux.co.jp>
This commit is contained in:
1 parent
87a39e42b8
commit
5e9e888e54
4 files changed
+104
-23
No files matched your search
+82
-20
@@ -437,6 +437,9 @@ int arch_domain_create(struct domain *d)
|
||||
int vcpuid, pdpt_order, paging_initialised = 0;
|
||||
int rc = -ENOMEM;
|
||||
|
||||
d->arch.relmem = RELMEM_not_started;
|
||||
INIT_LIST_HEAD(&d->arch.relmem_list);
|
||||
|
||||
pdpt_order = get_order_from_bytes(PDPT_L1_ENTRIES * sizeof(l1_pgentry_t));
|
||||
d->arch.mm_perdomain_pt = alloc_xenheap_pages(pdpt_order);
|
||||
if ( d->arch.mm_perdomain_pt == NULL )
|
||||
@@ -1599,12 +1602,13 @@ int hypercall_xlat_continuation(unsigned int *id, unsigned int mask, ...)
|
||||
}
|
||||
#endif
|
||||
|
||||
static void relinquish_memory(struct domain *d, struct list_head *list,
|
||||
unsigned long type)
|
||||
static int relinquish_memory(
|
||||
struct domain *d, struct list_head *list, unsigned long type)
|
||||
{
|
||||
struct list_head *ent;
|
||||
struct page_info *page;
|
||||
unsigned long x, y;
|
||||
int ret = 0;
|
||||
|
||||
/* Use a recursive lock, as we may enter 'free_domheap_page'. */
|
||||
spin_lock_recursive(&d->page_alloc_lock);
|
||||
@@ -1619,6 +1623,7 @@ static void relinquish_memory(struct domain *d, struct list_head *list,
|
||||
{
|
||||
/* Couldn't get a reference -- someone is freeing this page. */
|
||||
ent = ent->next;
|
||||
list_move_tail(&page->list, &d->arch.relmem_list);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1653,10 +1658,21 @@ static void relinquish_memory(struct domain *d, struct list_head *list,
|
||||
|
||||
/* Follow the list chain and /then/ potentially free the page. */
|
||||
ent = ent->next;
|
||||
list_move_tail(&page->list, &d->arch.relmem_list);
|
||||
put_page(page);
|
||||
|
||||
if ( hypercall_preempt_check() )
|
||||
{
|
||||
ret = -EAGAIN;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
list_splice_init(&d->arch.relmem_list, list);
|
||||
|
||||
out:
|
||||
spin_unlock_recursive(&d->page_alloc_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void vcpu_destroy_pagetables(struct vcpu *v)
|
||||
@@ -1719,35 +1735,81 @@ static void vcpu_destroy_pagetables(struct vcpu *v)
|
||||
|
||||
int domain_relinquish_resources(struct domain *d)
|
||||
{
|
||||
int ret;
|
||||
struct vcpu *v;
|
||||
|
||||
BUG_ON(!cpus_empty(d->domain_dirty_cpumask));
|
||||
|
||||
/* Tear down paging-assistance stuff. */
|
||||
paging_teardown(d);
|
||||
switch ( d->arch.relmem )
|
||||
{
|
||||
case RELMEM_not_started:
|
||||
/* Tear down paging-assistance stuff. */
|
||||
paging_teardown(d);
|
||||
|
||||
/* Drop the in-use references to page-table bases. */
|
||||
for_each_vcpu ( d, v )
|
||||
vcpu_destroy_pagetables(v);
|
||||
/* Drop the in-use references to page-table bases. */
|
||||
for_each_vcpu ( d, v )
|
||||
vcpu_destroy_pagetables(v);
|
||||
|
||||
/*
|
||||
* Relinquish GDT mappings. No need for explicit unmapping of the LDT as
|
||||
* it automatically gets squashed when the guest's mappings go away.
|
||||
*/
|
||||
for_each_vcpu(d, v)
|
||||
destroy_gdt(v);
|
||||
/*
|
||||
* Relinquish GDT mappings. No need for explicit unmapping of the LDT
|
||||
* as it automatically gets squashed when the guest's mappings go away.
|
||||
*/
|
||||
for_each_vcpu(d, v)
|
||||
destroy_gdt(v);
|
||||
|
||||
/* Relinquish every page of memory. */
|
||||
d->arch.relmem = RELMEM_xen_l4;
|
||||
/* fallthrough */
|
||||
|
||||
/* Relinquish every page of memory. */
|
||||
#if CONFIG_PAGING_LEVELS >= 4
|
||||
relinquish_memory(d, &d->xenpage_list, PGT_l4_page_table);
|
||||
relinquish_memory(d, &d->page_list, PGT_l4_page_table);
|
||||
case RELMEM_xen_l4:
|
||||
ret = relinquish_memory(d, &d->xenpage_list, PGT_l4_page_table);
|
||||
if ( ret )
|
||||
return ret;
|
||||
d->arch.relmem = RELMEM_dom_l4;
|
||||
/* fallthrough */
|
||||
case RELMEM_dom_l4:
|
||||
ret = relinquish_memory(d, &d->page_list, PGT_l4_page_table);
|
||||
if ( ret )
|
||||
return ret;
|
||||
d->arch.relmem = RELMEM_xen_l3;
|
||||
/* fallthrough */
|
||||
#endif
|
||||
|
||||
#if CONFIG_PAGING_LEVELS >= 3
|
||||
relinquish_memory(d, &d->xenpage_list, PGT_l3_page_table);
|
||||
relinquish_memory(d, &d->page_list, PGT_l3_page_table);
|
||||
case RELMEM_xen_l3:
|
||||
ret = relinquish_memory(d, &d->xenpage_list, PGT_l3_page_table);
|
||||
if ( ret )
|
||||
return ret;
|
||||
d->arch.relmem = RELMEM_dom_l3;
|
||||
/* fallthrough */
|
||||
case RELMEM_dom_l3:
|
||||
ret = relinquish_memory(d, &d->page_list, PGT_l3_page_table);
|
||||
if ( ret )
|
||||
return ret;
|
||||
d->arch.relmem = RELMEM_xen_l2;
|
||||
/* fallthrough */
|
||||
#endif
|
||||
relinquish_memory(d, &d->xenpage_list, PGT_l2_page_table);
|
||||
relinquish_memory(d, &d->page_list, PGT_l2_page_table);
|
||||
|
||||
case RELMEM_xen_l2:
|
||||
ret = relinquish_memory(d, &d->xenpage_list, PGT_l2_page_table);
|
||||
if ( ret )
|
||||
return ret;
|
||||
d->arch.relmem = RELMEM_dom_l2;
|
||||
/* fallthrough */
|
||||
case RELMEM_dom_l2:
|
||||
ret = relinquish_memory(d, &d->page_list, PGT_l2_page_table);
|
||||
if ( ret )
|
||||
return ret;
|
||||
d->arch.relmem = RELMEM_done;
|
||||
/* fallthrough */
|
||||
|
||||
case RELMEM_done:
|
||||
break;
|
||||
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
|
||||
/* Free page used by xen oprofile buffer. */
|
||||
free_xenoprof_pages(d);
|
||||
|
||||
@@ -257,10 +257,14 @@ long arch_do_domctl(
|
||||
break;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
spin_lock(&d->page_alloc_lock);
|
||||
|
||||
if ( unlikely(d->is_dying) ) {
|
||||
spin_unlock(&d->page_alloc_lock);
|
||||
goto getmemlist_out;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
list_ent = d->page_list.next;
|
||||
for ( i = 0; (i < max_pfns) && (list_ent != &d->page_list); i++ )
|
||||
{
|
||||
@@ -279,7 +283,7 @@ long arch_do_domctl(
|
||||
|
||||
domctl->u.getmemlist.num_pfns = i;
|
||||
copy_to_guest(u_domctl, domctl, 1);
|
||||
|
||||
getmemlist_out:
|
||||
rcu_unlock_domain(d);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -318,6 +318,7 @@ int domain_kill(struct domain *d)
|
||||
d->is_dying = DOMDYING_dying;
|
||||
evtchn_destroy(d);
|
||||
gnttab_release_mappings(d);
|
||||
/* fallthrough */
|
||||
case DOMDYING_dying:
|
||||
rc = domain_relinquish_resources(d);
|
||||
page_scrub_kick();
|
||||
@@ -329,6 +330,7 @@ int domain_kill(struct domain *d)
|
||||
d->is_dying = DOMDYING_dead;
|
||||
put_domain(d);
|
||||
send_guest_global_virq(dom0, VIRQ_DOM_EXC);
|
||||
/* fallthrough */
|
||||
case DOMDYING_dead:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -234,6 +234,19 @@ struct arch_domain
|
||||
bool_t is_32bit_pv;
|
||||
/* Is shared-info page in 32-bit format? */
|
||||
bool_t has_32bit_shinfo;
|
||||
|
||||
/* Continuable domain_relinquish_resources(). */
|
||||
enum {
|
||||
RELMEM_not_started,
|
||||
RELMEM_xen_l4,
|
||||
RELMEM_dom_l4,
|
||||
RELMEM_xen_l3,
|
||||
RELMEM_dom_l3,
|
||||
RELMEM_xen_l2,
|
||||
RELMEM_dom_l2,
|
||||
RELMEM_done,
|
||||
} relmem;
|
||||
struct list_head relmem_list;
|
||||
} __cacheline_aligned;
|
||||
|
||||
#ifdef CONFIG_X86_PAE
|
||||
|
||||