int xc_suspend_evtchn_init(xc_interface *xch, xc_evtchn *xce, int domid, int port) { int rc, suspend_evtchn = -1; if (lock_suspend_event(xch, domid)) return -EINVAL; suspend_evtchn = xc_evtchn_bind_interdomain(xce, domid, port); if (suspend_evtchn < 0) { ERROR("failed to bind suspend event channel: %d", suspend_evtchn); goto cleanup; } rc = xc_domain_subscribe_for_suspend(xch, domid, port); if (rc < 0) { ERROR("failed to subscribe to domain: %d", rc); goto cleanup; } /* event channel is pending immediately after binding */ xc_await_suspend(xch, xce, suspend_evtchn); return suspend_evtchn; cleanup: xc_suspend_evtchn_release(xch, xce, domid, suspend_evtchn); return -1; }
static void domain_save_done(libxl__egc *egc, libxl__domain_save_state *dss, int rc) { STATE_AO_GC(dss->ao); /* Convenience aliases */ const uint32_t domid = dss->domid; libxl__domain_suspend_state *dsps = &dss->dsps; libxl__ev_evtchn_cancel(gc, &dsps->guest_evtchn); if (dsps->guest_evtchn.port > 0) xc_suspend_evtchn_release(CTX->xch, CTX->xce, domid, dsps->guest_evtchn.port, &dsps->guest_evtchn_lockfd); if (dss->remus) { /* * With Remus/COLO, if we reach this point, it means either * backup died or some network error occurred preventing us * from sending checkpoints. Teardown the network buffers and * release netlink resources. This is an async op. */ if (libxl_defbool_val(dss->remus->colo)) libxl__colo_save_teardown(egc, &dss->css, rc); else libxl__remus_teardown(egc, &dss->rs, rc); return; } dss->callback(egc, dss, rc); }
int xc_suspend_evtchn_init_sane(xc_interface *xch, xc_evtchn *xce, int domid, int port, int *lockfd) { int rc, suspend_evtchn = -1; if (lock_suspend_event(xch, domid, lockfd)) { errno = EINVAL; goto cleanup; } suspend_evtchn = xc_evtchn_bind_interdomain(xce, domid, port); if (suspend_evtchn < 0) { ERROR("failed to bind suspend event channel: %d", suspend_evtchn); goto cleanup; } rc = xc_domain_subscribe_for_suspend(xch, domid, port); if (rc < 0) { ERROR("failed to subscribe to domain: %d", rc); goto cleanup; } return suspend_evtchn; cleanup: xc_suspend_evtchn_release(xch, xce, domid, suspend_evtchn, lockfd); return -1; }
/* release suspend event channels bound to guest */ static void release_suspend_evtchn(checkpoint_state *s) { /* TODO: teach xen to clean up if port is unbound */ if (s->xce >= 0 && s->suspend_evtchn >= 0) { xc_suspend_evtchn_release(s->xce, s->suspend_evtchn); s->suspend_evtchn = -1; } }
static int suspend_guest(xc_interface *xch, xc_evtchn *xce, int domid, int *evtchn, int *lockfd) { int port, rc, suspend_evtchn = -1; *lockfd = -1; if (!evtchn) return -1; port = xs_suspend_evtchn_port(domid); if (port < 0) { fprintf(stderr, "DOM%d: No suspend port, try live migration\n", domid); goto failed; } suspend_evtchn = xc_suspend_evtchn_init_exclusive(xch, xce, domid, port, lockfd); if (suspend_evtchn < 0) { fprintf(stderr, "Suspend evtchn initialization failed\n"); goto failed; } *evtchn = suspend_evtchn; rc = xc_evtchn_notify(xce, suspend_evtchn); if (rc < 0) { fprintf(stderr, "Failed to notify suspend channel: errno %d\n", rc); goto failed; } if (xc_await_suspend(xch, xce, suspend_evtchn) < 0) { fprintf(stderr, "Suspend Failed\n"); goto failed; } return 0; failed: if (suspend_evtchn != -1) xc_suspend_evtchn_release(xch, xce, domid, suspend_evtchn, lockfd); return -1; }
static int hp_mem_offline_func(int argc, char *argv[]) { uint32_t status, domid; int ret; unsigned long mfn; if (argc != 1) { show_help(); return -1; } sscanf(argv[0], "%lx", &mfn); printf("Prepare to offline MEMORY mfn %lx\n", mfn); ret = xc_mark_page_offline(xch, mfn, mfn, &status); if (ret < 0) { fprintf(stderr, "Offlining page mfn %lx failed, error %x\n", mfn, ret); if (status & (PG_OFFLINE_XENPAGE | PG_OFFLINE_FAILED)) fprintf(stderr, "XEN_PAGE is not permitted be offlined\n"); else if (status & (PG_OFFLINE_FAILED | PG_OFFLINE_NOT_CONV_RAM)) fprintf(stderr, "RESERVED RAM is not permitted to be offlined\n"); } else { switch(status & PG_OFFLINE_STATUS_MASK) { case PG_OFFLINE_OFFLINED: { printf("Memory mfn %lx offlined successfully, current state is" " [PG_OFFLINE_OFFLINED]\n", mfn); if (status & PG_OFFLINE_BROKEN) printf("And this offlined PAGE is already marked broken" " before!\n"); break; } case PG_OFFLINE_FAILED: { fprintf(stderr, "Memory mfn %lx offline failed\n", mfn); if ( status & PG_OFFLINE_ANONYMOUS) fprintf(stderr, "the memory is an anonymous page!\n"); ret = -1; break; } case PG_OFFLINE_PENDING: { if (status & PG_OFFLINE_XENPAGE) { ret = -1; fprintf(stderr, "Memory mfn %lx offlined succssefully," "this page is xen page, current state is" " [PG_OFFLINE_PENDING, PG_OFFLINE_XENPAGE]\n", mfn); } else if (status & PG_OFFLINE_OWNED) { int result, suspend_evtchn = -1, suspend_lockfd = -1; xc_evtchn *xce; xce = xc_evtchn_open(NULL, 0); if (xce == NULL) { fprintf(stderr, "When exchange page, fail" " to open evtchn\n"); return -1; } domid = status >> PG_OFFLINE_OWNER_SHIFT; if (suspend_guest(xch, xce, domid, &suspend_evtchn, &suspend_lockfd)) { fprintf(stderr, "Failed to suspend guest %d for" " mfn %lx\n", domid, mfn); xc_evtchn_close(xce); return -1; } result = xc_exchange_page(xch, domid, mfn); /* Exchange page successfully */ if (result == 0) printf("Memory mfn %lx offlined successfully, this " "page is DOM%d page and being swapped " "successfully, current state is " "[PG_OFFLINE_OFFLINED, PG_OFFLINE_OWNED]\n", mfn, domid); else { ret = -1; fprintf(stderr, "Memory mfn %lx offlined successfully" " , this page is DOM%d page yet failed to be " "exchanged. current state is " "[PG_OFFLINE_PENDING, PG_OFFLINE_OWNED]\n", mfn, domid); } xc_domain_resume(xch, domid, 1); xc_suspend_evtchn_release(xch, xce, domid, suspend_evtchn, &suspend_lockfd); xc_evtchn_close(xce); } break; } }//end of switch }//end of if