xen: add support for canceled suspend

When running on Xen, it's possible that a suspend request to the hypervisor
fails (return from HYPERVISOR_suspend different than 0). This means that the
suspend hasn't succeed, and the resume procedure needs to properly handle this
case.

First of all, when such situation happens there's no need to reset the vector
callback, hypercall page, shared info, event channels or grant table, because
it's state is preserved. Also, the PV drivers don't need to be reset to the
initial state, since the connection with the backed has not been interrupted.

Submitted by:		Liuyingdong <liuyingdong@huawei.com>
Reviewed by:		royger
MFC after:		2 weeks
Differential revision:	https://reviews.freebsd.org/D9635
This commit is contained in:
Roger Pau Monné 2017-03-07 09:16:51 +00:00
parent acd63c37d6
commit 8dee0e9bd6
5 changed files with 35 additions and 5 deletions

View File

@ -1537,6 +1537,11 @@ xbd_resume(device_t dev)
{
struct xbd_softc *sc = device_get_softc(dev);
if (xen_suspend_cancelled) {
sc->xbd_state = XBD_STATE_CONNECTED;
return (0);
}
DPRINTK("xbd_resume: %s\n", xenbus_get_node(dev));
xbd_free(sc);

View File

@ -148,6 +148,7 @@ __FBSDID("$FreeBSD$");
#include <xen/xenbus/xenbusvar.h>
bool xen_suspend_cancelled;
/*--------------------------- Forward Declarations --------------------------*/
/** Function signature for shutdown event handlers. */
typedef void (xctrl_shutdown_handler_t)(void);
@ -196,7 +197,6 @@ xctrl_suspend()
#ifdef SMP
cpuset_t cpu_suspend_map;
#endif
int suspend_cancelled;
EVENTHANDLER_INVOKE(power_suspend_early);
stop_all_proc();
@ -267,16 +267,20 @@ xctrl_suspend()
intr_suspend();
xen_hvm_suspend();
suspend_cancelled = HYPERVISOR_suspend(0);
xen_suspend_cancelled = !!HYPERVISOR_suspend(0);
xen_hvm_resume(suspend_cancelled != 0);
intr_resume(suspend_cancelled != 0);
if (!xen_suspend_cancelled) {
xen_hvm_resume(false);
}
intr_resume(xen_suspend_cancelled != 0);
enable_intr();
/*
* Reset grant table info.
*/
gnttab_resume(NULL);
if (!xen_suspend_cancelled) {
gnttab_resume(NULL);
}
#ifdef SMP
if (!CPU_EMPTY(&cpu_suspend_map)) {

View File

@ -439,6 +439,20 @@ static int
netfront_resume(device_t dev)
{
struct netfront_info *info = device_get_softc(dev);
u_int i;
if (xen_suspend_cancelled) {
for (i = 0; i < info->num_queues; i++) {
XN_RX_LOCK(&info->rxq[i]);
XN_TX_LOCK(&info->txq[i]);
}
netfront_carrier_on(info);
for (i = 0; i < info->num_queues; i++) {
XN_RX_UNLOCK(&info->rxq[i]);
XN_TX_UNLOCK(&info->txq[i]);
}
return (0);
}
netif_disconnect_backend(info);
return (0);

View File

@ -56,6 +56,8 @@ extern char *console_page;
extern int xen_disable_pv_disks;
extern int xen_disable_pv_nics;
extern bool xen_suspend_cancelled;
enum xen_domain_type {
XEN_NATIVE, /* running on bare hardware */
XEN_PV_DOMAIN, /* running in a PV domain */

View File

@ -791,6 +791,11 @@ xenbusb_resume(device_t dev)
if (device_get_state(kids[i]) == DS_NOTPRESENT)
continue;
if (xen_suspend_cancelled) {
DEVICE_RESUME(kids[i]);
continue;
}
ivars = device_get_ivars(kids[i]);
xs_unregister_watch(&ivars->xd_otherend_watch);