virsh: Refactor block job waiting in cmdBlockCommit

Reuse the vshBlockJobWait infrastructure to refactor cmdBlockCommit to
use the common code. This additionally fixes a bug when working with
new qemus, where when doing an active commit with --pivot the pivoting
would fail, since qemu reaches 100% completion but the job doesn't
switch to synchronized phase right away.
This commit is contained in:
Peter Krempa 2015-07-13 17:04:49 +02:00
parent 2e78276364
commit 7408403560

View File

@ -2026,20 +2026,13 @@ cmdBlockCommit(vshControl *ctl, const vshCmd *cmd)
bool blocking = vshCommandOptBool(cmd, "wait") || pivot || finish; bool blocking = vshCommandOptBool(cmd, "wait") || pivot || finish;
bool async = vshCommandOptBool(cmd, "async"); bool async = vshCommandOptBool(cmd, "async");
int timeout = 0; int timeout = 0;
struct sigaction sig_action;
struct sigaction old_sig_action;
sigset_t sigmask, oldsigmask;
struct timeval start;
struct timeval curr;
const char *path = NULL; const char *path = NULL;
const char *base = NULL; const char *base = NULL;
const char *top = NULL; const char *top = NULL;
bool quit = false;
int abort_flags = 0; int abort_flags = 0;
int status = -1;
int cb_id = -1;
unsigned int flags = 0; unsigned int flags = 0;
unsigned long bandwidth = 0; unsigned long bandwidth = 0;
vshBlockJobWaitDataPtr bjWait = NULL;
VSH_EXCLUSIVE_OPTIONS("pivot", "keep-overlay"); VSH_EXCLUSIVE_OPTIONS("pivot", "keep-overlay");
@ -2090,120 +2083,74 @@ cmdBlockCommit(vshControl *ctl, const vshCmd *cmd)
if (async) if (async)
abort_flags |= VIR_DOMAIN_BLOCK_JOB_ABORT_ASYNC; abort_flags |= VIR_DOMAIN_BLOCK_JOB_ABORT_ASYNC;
if (blocking) {
sigemptyset(&sigmask);
sigaddset(&sigmask, SIGINT);
intCaught = 0;
sig_action.sa_sigaction = vshCatchInt;
sig_action.sa_flags = SA_SIGINFO;
sigemptyset(&sig_action.sa_mask);
sigaction(SIGINT, &sig_action, &old_sig_action);
GETTIMEOFDAY(&start);
}
if (!(dom = vshCommandOptDomain(ctl, cmd, NULL))) if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
return false; return false;
virConnectDomainEventGenericCallback cb = if (blocking &&
VIR_DOMAIN_EVENT_CALLBACK(vshBlockJobStatusHandler); !(bjWait = vshBlockJobWaitInit(ctl, dom, path, _("Block commit"),
verbose, timeout, async)))
if ((cb_id = virConnectDomainEventRegisterAny(ctl->conn, goto cleanup;
dom,
VIR_DOMAIN_EVENT_ID_BLOCK_JOB,
cb,
&status,
NULL)) < 0)
vshResetLibvirtError();
if (virDomainBlockCommit(dom, path, base, top, bandwidth, flags) < 0) if (virDomainBlockCommit(dom, path, base, top, bandwidth, flags) < 0)
goto cleanup; goto cleanup;
if (!blocking) { if (!blocking) {
vshPrint(ctl, "%s", active ? if (active)
_("Active Block Commit started") : vshPrint(ctl, "%s", _("Active Block Commit started"));
_("Block Commit started")); else
vshPrint(ctl, "%s", _("Block Commit started"));
ret = true; ret = true;
goto cleanup; goto cleanup;
} }
while (blocking) { /* Execution continues here only if --wait or friends were specified */
virDomainBlockJobInfo info; switch (vshBlockJobWait(bjWait)) {
int result; case -1:
goto cleanup;
pthread_sigmask(SIG_BLOCK, &sigmask, &oldsigmask);
result = virDomainGetBlockJobInfo(dom, path, &info, 0); case VIR_DOMAIN_BLOCK_JOB_CANCELED:
pthread_sigmask(SIG_SETMASK, &oldsigmask, NULL); vshPrint(ctl, "\n%s", _("Commit aborted"));
if (result < 0) {
vshError(ctl, _("failed to query job for disk %s"), path);
goto cleanup; goto cleanup;
}
if (result == 0)
break; break;
if (verbose) case VIR_DOMAIN_BLOCK_JOB_FAILED:
vshPrintJobProgress(_("Block Commit"), vshPrint(ctl, "\n%s", _("Commit failed"));
info.end - info.cur, info.end); goto cleanup;
if (active && info.cur == info.end)
break; break;
GETTIMEOFDAY(&curr); case VIR_DOMAIN_BLOCK_JOB_READY:
if (intCaught || (timeout && case VIR_DOMAIN_BLOCK_JOB_COMPLETED:
(((int)(curr.tv_sec - start.tv_sec) * 1000 + break;
(int)(curr.tv_usec - start.tv_usec) / 1000) > }
timeout))) {
vshDebug(ctl, VSH_ERR_DEBUG, if (active) {
intCaught ? "interrupted" : "timeout"); if (pivot) {
intCaught = 0; abort_flags |= VIR_DOMAIN_BLOCK_JOB_ABORT_PIVOT;
timeout = 0;
status = VIR_DOMAIN_BLOCK_JOB_CANCELED;
if (virDomainBlockJobAbort(dom, path, abort_flags) < 0) { if (virDomainBlockJobAbort(dom, path, abort_flags) < 0) {
vshError(ctl, _("failed to abort job for disk %s"), path); vshError(ctl, _("failed to pivot job for disk %s"), path);
goto cleanup; goto cleanup;
} }
if (abort_flags & VIR_DOMAIN_BLOCK_JOB_ABORT_ASYNC)
break; vshPrint(ctl, "\n%s", _("Successfully pivoted"));
} else if (finish) {
if (virDomainBlockJobAbort(dom, path, abort_flags) < 0) {
vshError(ctl, _("failed to finish job for disk %s"), path);
goto cleanup;
}
vshPrint(ctl, "\n%s", _("Commit complete, overlay image kept"));
} else { } else {
usleep(500 * 1000); vshPrint(ctl, "\n%s", _("Now in synchronized phase"));
} }
} } else {
if (status == VIR_DOMAIN_BLOCK_JOB_CANCELED)
quit = true;
if (verbose && !quit) {
/* printf [100 %] */
vshPrintJobProgress(_("Block Commit"), 0, 1);
}
if (!quit && pivot) {
abort_flags |= VIR_DOMAIN_BLOCK_JOB_ABORT_PIVOT;
if (virDomainBlockJobAbort(dom, path, abort_flags) < 0) {
vshError(ctl, _("failed to pivot job for disk %s"), path);
goto cleanup;
}
} else if (finish && !quit &&
virDomainBlockJobAbort(dom, path, abort_flags) < 0) {
vshError(ctl, _("failed to finish job for disk %s"), path);
goto cleanup;
}
if (quit)
vshPrint(ctl, "\n%s", _("Commit aborted"));
else if (pivot)
vshPrint(ctl, "\n%s", _("Successfully pivoted"));
else if (!finish && active)
vshPrint(ctl, "\n%s", _("Now in synchronized phase"));
else
vshPrint(ctl, "\n%s", _("Commit complete")); vshPrint(ctl, "\n%s", _("Commit complete"));
}
ret = true; ret = true;
cleanup: cleanup:
virDomainFree(dom); virDomainFree(dom);
if (blocking) vshBlockJobWaitFree(bjWait);
sigaction(SIGINT, &old_sig_action, NULL);
if (cb_id >= 0)
virConnectDomainEventDeregisterAny(ctl->conn, cb_id);
return ret; return ret;
} }