aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--tools/libxl/libxl_bootloader.c43
-rw-r--r--tools/libxl/libxl_event.c47
-rw-r--r--tools/libxl/libxl_internal.h29
3 files changed, 108 insertions, 11 deletions
diff --git a/tools/libxl/libxl_bootloader.c b/tools/libxl/libxl_bootloader.c
index 8436c07e24..fb1302b61b 100644
--- a/tools/libxl/libxl_bootloader.c
+++ b/tools/libxl/libxl_bootloader.c
@@ -31,6 +31,7 @@ static void bootloader_keystrokes_copyfail(libxl__egc *egc,
libxl__datacopier_state *dc, int onwrite, int errnoval);
static void bootloader_display_copyfail(libxl__egc *egc,
libxl__datacopier_state *dc, int onwrite, int errnoval);
+static void bootloader_domaindeath(libxl__egc*, libxl__domaindeathcheck *dc);
static void bootloader_finished(libxl__egc *egc, libxl__ev_child *child,
pid_t pid, int status);
@@ -213,6 +214,7 @@ void libxl__bootloader_init(libxl__bootloader_state *bl)
bl->ptys[0].master = bl->ptys[0].slave = 0;
bl->ptys[1].master = bl->ptys[1].slave = 0;
libxl__ev_child_init(&bl->child);
+ libxl__domaindeathcheck_init(&bl->deathcheck);
bl->keystrokes.ao = bl->ao; libxl__datacopier_init(&bl->keystrokes);
bl->display.ao = bl->ao; libxl__datacopier_init(&bl->display);
}
@@ -230,6 +232,7 @@ static void bootloader_cleanup(libxl__egc *egc, libxl__bootloader_state *bl)
free(bl->diskpath);
bl->diskpath = 0;
}
+ libxl__domaindeathcheck_stop(gc,&bl->deathcheck);
libxl__datacopier_kill(&bl->keystrokes);
libxl__datacopier_kill(&bl->display);
for (i=0; i<2; i++) {
@@ -256,6 +259,23 @@ static void bootloader_callback(libxl__egc *egc, libxl__bootloader_state *bl,
bl->callback(egc, bl, rc);
}
+/* might be called at any time, provided it's init'd */
+static void bootloader_abort(libxl__egc *egc,
+ libxl__bootloader_state *bl, int rc)
+{
+ STATE_AO_GC(bl->ao);
+ int r;
+
+ libxl__datacopier_kill(&bl->keystrokes);
+ libxl__datacopier_kill(&bl->display);
+ if (libxl__ev_child_inuse(&bl->child)) {
+ r = kill(bl->child.pid, SIGTERM);
+ if (r) LOGE(WARN, "after failure, failed to kill bootloader [%lu]",
+ (unsigned long)bl->child.pid);
+ }
+ bl->rc = rc;
+}
+
/*----- main flow of control -----*/
void libxl__bootloader_run(libxl__egc *egc, libxl__bootloader_state *bl)
@@ -377,6 +397,12 @@ static void bootloader_gotptys(libxl__egc *egc, libxl__openpty_state *op)
goto out;
}
+ bl->deathcheck.what = "stopping bootloader";
+ bl->deathcheck.domid = bl->domid;
+ bl->deathcheck.callback = bootloader_domaindeath;
+ rc = libxl__domaindeathcheck_start(gc, &bl->deathcheck);
+ if (rc) goto out;
+
if (bl->console_available)
bl->console_available(egc, bl);
@@ -454,18 +480,9 @@ static void bootloader_copyfail(libxl__egc *egc, const char *which,
libxl__bootloader_state *bl, int onwrite, int errnoval)
{
STATE_AO_GC(bl->ao);
- int r;
-
if (!onwrite && !errnoval)
LOG(ERROR, "unexpected eof copying %s", which);
- libxl__datacopier_kill(&bl->keystrokes);
- libxl__datacopier_kill(&bl->display);
- if (libxl__ev_child_inuse(&bl->child)) {
- r = kill(bl->child.pid, SIGTERM);
- if (r) LOGE(WARN, "after failure, failed to kill bootloader [%lu]",
- (unsigned long)bl->child.pid);
- }
- bl->rc = ERROR_FAIL;
+ bootloader_abort(egc, bl, ERROR_FAIL);
}
static void bootloader_keystrokes_copyfail(libxl__egc *egc,
libxl__datacopier_state *dc, int onwrite, int errnoval)
@@ -480,6 +497,12 @@ static void bootloader_display_copyfail(libxl__egc *egc,
bootloader_copyfail(egc, "bootloader output", bl, onwrite, errnoval);
}
+static void bootloader_domaindeath(libxl__egc *egc, libxl__domaindeathcheck *dc)
+{
+ libxl__bootloader_state *bl = CONTAINER_OF(dc, *bl, deathcheck);
+ bootloader_abort(egc, bl, ERROR_FAIL);
+}
+
static void bootloader_finished(libxl__egc *egc, libxl__ev_child *child,
pid_t pid, int status)
{
diff --git a/tools/libxl/libxl_event.c b/tools/libxl/libxl_event.c
index 63719b2b5d..03d0498020 100644
--- a/tools/libxl/libxl_event.c
+++ b/tools/libxl/libxl_event.c
@@ -589,6 +589,53 @@ int libxl__ev_devstate_wait(libxl__gc *gc, libxl__ev_devstate *ds,
}
/*
+ * domain death/destruction
+ */
+
+/*
+ * We use a xenstore watch on the domain's path, rather than using an
+ * @releaseDomain watch and asking the hypervisor. This is simpler
+ * because turning @releaseDomain into domain-specific information is
+ * complicated.
+ *
+ * It is also sufficient for our callers, which are generally trying
+ * to do cleanup of their own execution state on domain death, for the
+ * following reason: if the domain is destroyed then either (a) the
+ * entries in xenstore have already been deleted, in which case the
+ * test here works or (b) they have not in which case something has
+ * gone very badly wrong and we are going to leak those xenstore
+ * entries, in which case trying to avoid leaking other stuff is
+ * futile.
+ */
+
+static void domaindeathcheck_callback(libxl__egc *egc, libxl__ev_xswatch *w,
+ const char *watch_path, const char *event_path)
+{
+ libxl__domaindeathcheck *dc = CONTAINER_OF(w, *dc, watch);
+ EGC_GC;
+ const char *p = libxl__xs_read(gc, XBT_NULL, watch_path);
+ if (p) return;
+
+ if (errno!=ENOENT) {
+ LIBXL__EVENT_DISASTER(egc,"failed to read xenstore"
+ " for domain detach check", errno, 0);
+ return;
+ }
+
+ LOG(ERROR,"%s: domain %"PRIu32" removed (%s no longer in xenstore)",
+ dc->what, dc->domid, watch_path);
+ dc->callback(egc, dc);
+}
+
+int libxl__domaindeathcheck_start(libxl__gc *gc,
+ libxl__domaindeathcheck *dc)
+{
+ const char *path = GCSPRINTF("/local/domain/%"PRIu32, dc->domid);
+ return libxl__ev_xswatch_register(gc, &dc->watch,
+ domaindeathcheck_callback, path);
+}
+
+/*
* osevent poll
*/
diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h
index 83fabea6ef..f71e76a55b 100644
--- a/tools/libxl/libxl_internal.h
+++ b/tools/libxl/libxl_internal.h
@@ -866,6 +866,33 @@ _hidden int libxl__ev_devstate_wait(libxl__gc *gc, libxl__ev_devstate *ds,
const char *state_path,
int state, int milliseconds);
+/*
+ * libxl__ev_domaindeathcheck_register - arranges to call back (once)
+ * if the domain is destroyed. If the domain dies, we log a message
+ * of the form "<what>: <explanation of the situation, including the domid>".
+ */
+
+typedef struct libxl__domaindeathcheck libxl__domaindeathcheck;
+typedef void libxl___domaindeathcheck_callback(libxl__egc *egc,
+ libxl__domaindeathcheck*);
+
+struct libxl__domaindeathcheck {
+ /* must be filled in by caller, and remain valid: */
+ const char *what;
+ uint32_t domid;
+ libxl___domaindeathcheck_callback *callback;
+ /* private */
+ libxl__ev_xswatch watch;
+};
+
+_hidden int libxl__domaindeathcheck_start(libxl__gc *gc,
+ libxl__domaindeathcheck *dc);
+
+static inline void libxl__domaindeathcheck_init
+ (libxl__domaindeathcheck *dc) { libxl__ev_xswatch_init(&dc->watch); }
+static inline void libxl__domaindeathcheck_stop(libxl__gc *gc,
+ libxl__domaindeathcheck *dc) { libxl__ev_xswatch_deregister(gc,&dc->watch); }
+
/*
* libxl__try_phy_backend - Check if there's support for the passed
@@ -1738,6 +1765,7 @@ struct libxl__bootloader_state {
libxl__openpty_state openpty;
libxl__openpty_result ptys[2]; /* [0] is for bootloader */
libxl__ev_child child;
+ libxl__domaindeathcheck deathcheck;
int nargs, argsspace;
const char **args;
libxl__datacopier_state keystrokes, display;
@@ -1750,7 +1778,6 @@ _hidden void libxl__bootloader_init(libxl__bootloader_state *bl);
* If callback is passed rc==0, will have updated st->info appropriately */
_hidden void libxl__bootloader_run(libxl__egc*, libxl__bootloader_state *st);
-
/*----- Domain creation -----*/
typedef struct libxl__domain_create_state libxl__domain_create_state;