xen/domain: Introduce domain_teardown()

There is no common equivelent of domain_reliquish_resources(), which has
caused various pieces of common cleanup to live in inappropriate
places.

Perhaps most obviously, evtchn_destroy() is called for every continuation of
domain_reliquish_resources(), which can easily be thousands of times.

Create domain_teardown() to be a new top level facility, and call it from the
appropriate positions in domain_kill() and domain_create()'s error path.  The
intention is for this to supersede domain_reliquish_resources() in due course.

No change in behaviour yet.

Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
This commit is contained in:
Andrew Cooper committed 2020-12-22 14:31:34 +00:00
1 parent 8dfeef4794
commit 98d4d6d8a6
2 files changed
+68

No files matched your search

+60
View File
@@ -272,6 +272,59 @@ static int __init parse_extra_guest_irqs(const char *s)
}
custom_param("extra_guest_irqs", parse_extra_guest_irqs);
/*
* Release resources held by a domain. There may or may not be live
* references to the domain, and it may or may not be fully constructed.
*
* d->is_dying differing between DOMDYING_dying and DOMDYING_dead can be used
* to determine if live references to the domain exist, and also whether
* continuations are permitted.
*
* If d->is_dying is DOMDYING_dead, this must not return non-zero.
*/
static int domain_teardown(struct domain *d)
{
BUG_ON(!d->is_dying);
/*
* This hypercall can take minutes of wallclock time to complete. This
* logic implements a co-routine, stashing state in struct domain across
* hypercall continuation boundaries.
*/
switch ( d->teardown.val )
{
/*
* Record the current progress. Subsequent hypercall continuations
* will logically restart work from this point.
*
* PROGRESS() markers must not be in the middle of loops. The loop
* variable isn't preserved across a continuation.
*
* To avoid redundant work, there should be a marker before each
* function which may return -ERESTART.
*/
#define PROGRESS(x) \
d->teardown.val = PROG_ ## x; \
/* Fallthrough */ \
case PROG_ ## x
enum {
PROG_done = 1,
};
case 0:
PROGRESS(done):
break;
#undef PROGRESS
default:
BUG();
}
return 0;
}
/*
* Destroy a domain once all references to it have been dropped. Used either
* from the RCU path, or from the domain_create() error path before the domain
@@ -552,6 +605,10 @@ struct domain *domain_create(domid_t domid,
if ( init_status & INIT_watchdog )
watchdog_domain_destroy(d);
/* Must not hit a continuation in this context. */
if ( domain_teardown(d) )
ASSERT_UNREACHABLE();
_domain_destroy(d);
return ERR_PTR(err);
@@ -732,6 +789,9 @@ int domain_kill(struct domain *d)
domain_set_outstanding_pages(d, 0);
/* fallthrough */
case DOMDYING_dying:
rc = domain_teardown(d);
if ( rc )
break;
rc = evtchn_destroy(d);
if ( rc )
break;
+8
View File
@@ -525,6 +525,14 @@ struct domain
/* Argo interdomain communication support */
struct argo_domain *argo;
#endif
/*
* Continuation information for domain_teardown(). All fields entirely
* private.
*/
struct {
unsigned int val;
} teardown;
};
static inline struct page_list_head *page_to_list(
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.