mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-01-05 04:25:19 +00:00
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:
parent
2e78276364
commit
7408403560
@ -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:
|
||||||
|
|
||||||
pthread_sigmask(SIG_BLOCK, &sigmask, &oldsigmask);
|
|
||||||
result = virDomainGetBlockJobInfo(dom, path, &info, 0);
|
|
||||||
pthread_sigmask(SIG_SETMASK, &oldsigmask, NULL);
|
|
||||||
|
|
||||||
if (result < 0) {
|
|
||||||
vshError(ctl, _("failed to query job for disk %s"), path);
|
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
|
||||||
if (result == 0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (verbose)
|
case VIR_DOMAIN_BLOCK_JOB_CANCELED:
|
||||||
vshPrintJobProgress(_("Block Commit"),
|
vshPrint(ctl, "\n%s", _("Commit aborted"));
|
||||||
info.end - info.cur, info.end);
|
|
||||||
if (active && info.cur == info.end)
|
|
||||||
break;
|
|
||||||
|
|
||||||
GETTIMEOFDAY(&curr);
|
|
||||||
if (intCaught || (timeout &&
|
|
||||||
(((int)(curr.tv_sec - start.tv_sec) * 1000 +
|
|
||||||
(int)(curr.tv_usec - start.tv_usec) / 1000) >
|
|
||||||
timeout))) {
|
|
||||||
vshDebug(ctl, VSH_ERR_DEBUG,
|
|
||||||
intCaught ? "interrupted" : "timeout");
|
|
||||||
intCaught = 0;
|
|
||||||
timeout = 0;
|
|
||||||
status = VIR_DOMAIN_BLOCK_JOB_CANCELED;
|
|
||||||
if (virDomainBlockJobAbort(dom, path, abort_flags) < 0) {
|
|
||||||
vshError(ctl, _("failed to abort job for disk %s"), path);
|
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
|
||||||
if (abort_flags & VIR_DOMAIN_BLOCK_JOB_ABORT_ASYNC)
|
|
||||||
break;
|
break;
|
||||||
} else {
|
|
||||||
usleep(500 * 1000);
|
case VIR_DOMAIN_BLOCK_JOB_FAILED:
|
||||||
}
|
vshPrint(ctl, "\n%s", _("Commit failed"));
|
||||||
|
goto cleanup;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case VIR_DOMAIN_BLOCK_JOB_READY:
|
||||||
|
case VIR_DOMAIN_BLOCK_JOB_COMPLETED:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (status == VIR_DOMAIN_BLOCK_JOB_CANCELED)
|
if (active) {
|
||||||
quit = true;
|
if (pivot) {
|
||||||
|
|
||||||
if (verbose && !quit) {
|
|
||||||
/* printf [100 %] */
|
|
||||||
vshPrintJobProgress(_("Block Commit"), 0, 1);
|
|
||||||
}
|
|
||||||
if (!quit && pivot) {
|
|
||||||
abort_flags |= VIR_DOMAIN_BLOCK_JOB_ABORT_PIVOT;
|
abort_flags |= VIR_DOMAIN_BLOCK_JOB_ABORT_PIVOT;
|
||||||
if (virDomainBlockJobAbort(dom, path, abort_flags) < 0) {
|
if (virDomainBlockJobAbort(dom, path, abort_flags) < 0) {
|
||||||
vshError(ctl, _("failed to pivot job for disk %s"), path);
|
vshError(ctl, _("failed to pivot job for disk %s"), path);
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
} else if (finish && !quit &&
|
|
||||||
virDomainBlockJobAbort(dom, path, abort_flags) < 0) {
|
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);
|
vshError(ctl, _("failed to finish job for disk %s"), path);
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
if (quit)
|
|
||||||
vshPrint(ctl, "\n%s", _("Commit aborted"));
|
vshPrint(ctl, "\n%s", _("Commit complete, overlay image kept"));
|
||||||
else if (pivot)
|
} else {
|
||||||
vshPrint(ctl, "\n%s", _("Successfully pivoted"));
|
|
||||||
else if (!finish && active)
|
|
||||||
vshPrint(ctl, "\n%s", _("Now in synchronized phase"));
|
vshPrint(ctl, "\n%s", _("Now in synchronized phase"));
|
||||||
else
|
}
|
||||||
|
} 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user