mirror of
https://github.com/xen-project/xen.git
synced 2026-10-29 18:50:05 +01:00
Make XEN_DOMCTL_destroydomain hypercall preemptible, in a way that is
visible to the caller (via -EAGAIN return code). This prevents softlockup in dom0 kernel, due to the hypercall taking too long to execute on very large (multi-multi-gigabyte) domains. Signed-off-by: Isaku Yamahata <yamahata@valinux.co.jp> Signed-off-by: Keir Fraser <keir@xensource.com>
This commit is contained in:
1 parent
0269e41669
commit
e815cb4b18
8 files changed
+43
-40
No files matched your search
@@ -936,7 +936,7 @@ static void relinquish_memory(struct domain *d, struct list_head *list)
|
||||
spin_unlock_recursive(&d->page_alloc_lock);
|
||||
}
|
||||
|
||||
void domain_relinquish_resources(struct domain *d)
|
||||
int domain_relinquish_resources(struct domain *d)
|
||||
{
|
||||
/* Relinquish guest resources for VT-i domain. */
|
||||
if (d->vcpu[0] && VMX_DOMAIN(d->vcpu[0]))
|
||||
@@ -954,6 +954,8 @@ void domain_relinquish_resources(struct domain *d)
|
||||
|
||||
/* Free page used by xen oprofile buffer */
|
||||
free_xenoprof_pages(d);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned long
|
||||
|
||||
@@ -313,13 +313,13 @@ static void relinquish_memory(struct domain *d, struct list_head *list)
|
||||
spin_unlock_recursive(&d->page_alloc_lock);
|
||||
}
|
||||
|
||||
void domain_relinquish_resources(struct domain *d)
|
||||
int domain_relinquish_resources(struct domain *d)
|
||||
{
|
||||
relinquish_memory(d, &d->xenpage_list);
|
||||
relinquish_memory(d, &d->page_list);
|
||||
xfree(d->arch.foreign_mfns);
|
||||
xfree(d->arch.p2m);
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void arch_dump_domain_info(struct domain *d)
|
||||
|
||||
@@ -1717,7 +1717,7 @@ static void vcpu_destroy_pagetables(struct vcpu *v)
|
||||
v->arch.cr3 = 0;
|
||||
}
|
||||
|
||||
void domain_relinquish_resources(struct domain *d)
|
||||
int domain_relinquish_resources(struct domain *d)
|
||||
{
|
||||
struct vcpu *v;
|
||||
|
||||
@@ -1754,6 +1754,8 @@ void domain_relinquish_resources(struct domain *d)
|
||||
|
||||
if ( is_hvm_domain(d) )
|
||||
hvm_domain_relinquish_resources(d);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void arch_dump_domain_info(struct domain *d)
|
||||
|
||||
+27
-16
@@ -245,7 +245,7 @@ struct domain *domain_create(
|
||||
return d;
|
||||
|
||||
fail:
|
||||
d->is_dying = 1;
|
||||
d->is_dying = DOMDYING_dead;
|
||||
atomic_set(&d->refcnt, DOMAIN_DESTROYED);
|
||||
if ( init_status & INIT_arch )
|
||||
arch_domain_destroy(d);
|
||||
@@ -303,26 +303,37 @@ struct domain *rcu_lock_domain_by_id(domid_t dom)
|
||||
}
|
||||
|
||||
|
||||
void domain_kill(struct domain *d)
|
||||
int domain_kill(struct domain *d)
|
||||
{
|
||||
domain_pause(d);
|
||||
int rc = 0;
|
||||
|
||||
/* Already dying? Then bail. */
|
||||
if ( test_and_set_bool(d->is_dying) )
|
||||
if ( d == current->domain )
|
||||
return -EINVAL;
|
||||
|
||||
/* Protected by domctl_lock. */
|
||||
switch ( d->is_dying )
|
||||
{
|
||||
domain_unpause(d);
|
||||
return;
|
||||
case DOMDYING_alive:
|
||||
domain_pause(d);
|
||||
d->is_dying = DOMDYING_dying;
|
||||
evtchn_destroy(d);
|
||||
gnttab_release_mappings(d);
|
||||
case DOMDYING_dying:
|
||||
rc = domain_relinquish_resources(d);
|
||||
page_scrub_kick();
|
||||
if ( rc != 0 )
|
||||
{
|
||||
BUG_ON(rc != -EAGAIN);
|
||||
break;
|
||||
}
|
||||
d->is_dying = DOMDYING_dead;
|
||||
put_domain(d);
|
||||
send_guest_global_virq(dom0, VIRQ_DOM_EXC);
|
||||
case DOMDYING_dead:
|
||||
break;
|
||||
}
|
||||
|
||||
evtchn_destroy(d);
|
||||
gnttab_release_mappings(d);
|
||||
domain_relinquish_resources(d);
|
||||
put_domain(d);
|
||||
|
||||
/* Kick page scrubbing after domain_relinquish_resources(). */
|
||||
page_scrub_kick();
|
||||
|
||||
send_guest_global_virq(dom0, VIRQ_DOM_EXC);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
|
||||
+5
-16
@@ -114,10 +114,10 @@ void getdomaininfo(struct domain *d, struct xen_domctl_getdomaininfo *info)
|
||||
info->cpu_time = cpu_time;
|
||||
|
||||
info->flags = flags |
|
||||
(d->is_dying ? XEN_DOMINF_dying : 0) |
|
||||
(d->is_shut_down ? XEN_DOMINF_shutdown : 0) |
|
||||
(d->is_paused_by_controller ? XEN_DOMINF_paused : 0) |
|
||||
(d->debugger_attached ? XEN_DOMINF_debugged : 0) |
|
||||
((d->is_dying == DOMDYING_dead) ? XEN_DOMINF_dying : 0) |
|
||||
(d->is_shut_down ? XEN_DOMINF_shutdown : 0) |
|
||||
(d->is_paused_by_controller ? XEN_DOMINF_paused : 0) |
|
||||
(d->debugger_attached ? XEN_DOMINF_debugged : 0) |
|
||||
d->shutdown_code << XEN_DOMINF_shutdownshift;
|
||||
|
||||
if ( is_hvm_domain(d) )
|
||||
@@ -422,18 +422,7 @@ long do_domctl(XEN_GUEST_HANDLE(xen_domctl_t) u_domctl)
|
||||
ret = -ESRCH;
|
||||
if ( d != NULL )
|
||||
{
|
||||
ret = xsm_destroydomain(d);
|
||||
if ( ret )
|
||||
goto destroydomain_out;
|
||||
|
||||
ret = -EINVAL;
|
||||
if ( d != current->domain )
|
||||
{
|
||||
domain_kill(d);
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
destroydomain_out:
|
||||
ret = xsm_destroydomain(d) ? : domain_kill(d);
|
||||
rcu_unlock_domain(d);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,6 @@ struct p2m_entry;
|
||||
struct tlb_track;
|
||||
#endif
|
||||
|
||||
extern void domain_relinquish_resources(struct domain *);
|
||||
struct vcpu;
|
||||
extern void relinquish_vcpu_resources(struct vcpu *v);
|
||||
extern void vcpu_share_privregs_with_guest(struct vcpu *v);
|
||||
|
||||
@@ -45,7 +45,7 @@ void arch_domain_destroy(struct domain *d);
|
||||
int arch_set_info_guest(struct vcpu *, vcpu_guest_context_u);
|
||||
void arch_get_info_guest(struct vcpu *, vcpu_guest_context_u);
|
||||
|
||||
void domain_relinquish_resources(struct domain *d);
|
||||
int domain_relinquish_resources(struct domain *d);
|
||||
|
||||
void dump_pageframe_info(struct domain *d);
|
||||
|
||||
|
||||
@@ -194,7 +194,7 @@ struct domain
|
||||
/* Are any VCPUs polling event channels (SCHEDOP_poll)? */
|
||||
bool_t is_polling;
|
||||
/* Is this guest dying (i.e., a zombie)? */
|
||||
bool_t is_dying;
|
||||
enum { DOMDYING_alive, DOMDYING_dying, DOMDYING_dead } is_dying;
|
||||
/* Domain is paused by controller software? */
|
||||
bool_t is_paused_by_controller;
|
||||
|
||||
@@ -338,7 +338,7 @@ static inline struct domain *rcu_lock_current_domain(void)
|
||||
|
||||
struct domain *get_domain_by_id(domid_t dom);
|
||||
void domain_destroy(struct domain *d);
|
||||
void domain_kill(struct domain *d);
|
||||
int domain_kill(struct domain *d);
|
||||
void domain_shutdown(struct domain *d, u8 reason);
|
||||
void domain_resume(struct domain *d);
|
||||
void domain_pause_for_debugger(void);
|
||||
|
||||