@@ -247,21 +247,24 @@ int xen_kexec_status(uint64_t kexec_flags)
return ret;
}
-void xen_kexec_exec(uint64_t kexec_flags)
+int xen_kexec_exec(uint64_t kexec_flags)
{
xc_interface *xch;
uint8_t type = KEXEC_TYPE_DEFAULT;
+ int ret;
xch = xc_interface_open(NULL, NULL, 0);
if (!xch)
- return;
+ return -1;
if (kexec_flags & KEXEC_LIVE_UPDATE)
type = KEXEC_TYPE_LIVE_UPDATE;
- xc_kexec_exec(xch, type);
+ ret = xc_kexec_exec(xch, type);
xc_interface_close(xch);
+
+ return ret;
}
#else /* ! HAVE_LIBXENCTRL */
@@ -286,8 +289,9 @@ int xen_kexec_status(uint64_t kexec_flags)
return -1;
}
-void xen_kexec_exec(uint64_t kexec_flags)
+int xen_kexec_exec(uint64_t kexec_flags)
{
+ return -1;
}
#endif
@@ -902,13 +902,28 @@ static int my_shutdown(void)
}
/*
- * Exec the new kernel (reboot)
+ * Exec the new kernel. If successful, this triggers an immediate reboot
+ * and does not return, but Xen Live Update is an exception (more on this
+ * below).
*/
static int my_exec(void)
{
- if (xen_present())
- xen_kexec_exec(kexec_flags);
- else
+ if (xen_present()) {
+ int ret;
+
+ /*
+ * There are two cases in which the Xen hypercall may return:
+ * 1) An error occurred, e.g. the kexec image was not loaded.
+ * The exact error is indicated by errno.
+ * 2) Live Update was successfully scheduled. Note that unlike
+ * a normal kexec, Live Update happens asynchronously, i.e.
+ * the hypercall merely schedules the kexec operation and
+ * returns immediately.
+ */
+ ret = xen_kexec_exec(kexec_flags);
+ if ((kexec_flags & KEXEC_LIVE_UPDATE) && !ret)
+ return 0;
+ } else
reboot(LINUX_REBOOT_CMD_KEXEC);
/* I have failed if I make it here */
fprintf(stderr, "kexec failed: %s\n",
@@ -324,7 +324,7 @@ void cmdline_add_liveupdate(char **base);
int xen_present(void);
int xen_kexec_load(struct kexec_info *info);
int xen_kexec_unload(uint64_t kexec_flags);
-void xen_kexec_exec(uint64_t kexec_flags);
+int xen_kexec_exec(uint64_t kexec_flags);
int xen_kexec_status(uint64_t kexec_flags);
extern unsigned long long get_kernel_sym(const char *text);