
On 07/15/2015 12:34 PM, Peter Krempa wrote:
Introduce helper function that will provide logic for waiting for block job completion so the 3 open coded places can be unified and improved.
This patch introduces the whole logic and uses it to fix cmdBlockJobPull. The vshBlockJobWait funtion provides common logic for block job waiting that should be robust enough to work across all previous versions of libvirt. Since virsh allows to pass user-provided strings as paths of block devices we can't reliably use block job events for detection of block job states so the function contains a great deal of fallback logic. --- tools/virsh-domain.c | 326 ++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 244 insertions(+), 82 deletions(-)
...
/* * "blockcommit" command */ @@ -2660,19 +2881,11 @@ cmdBlockPull(vshControl *ctl, const vshCmd *cmd) bool verbose = vshCommandOptBool(cmd, "verbose"); bool async = vshCommandOptBool(cmd, "async"); 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 *base = NULL; unsigned long bandwidth = 0; - bool quit = false; - int abort_flags = 0; - int status = -1; - int cb_id = -1; unsigned int flags = 0; + vshBlockJobWaitDataPtr bjWait = NULL;
VSH_REQUIRE_OPTION("verbose", "wait"); VSH_REQUIRE_OPTION("async", "wait"); @@ -2694,35 +2907,13 @@ cmdBlockPull(vshControl *ctl, const vshCmd *cmd) if (vshCommandOptBool(cmd, "keep-relative")) flags |= VIR_DOMAIN_BLOCK_REBASE_RELATIVE;
- if (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))) return false;
- virConnectDomainEventGenericCallback cb = - VIR_DOMAIN_EVENT_CALLBACK(vshBlockJobStatusHandler); - - if ((cb_id = virConnectDomainEventRegisterAny(ctl->conn, - dom, - VIR_DOMAIN_EVENT_ID_BLOCK_JOB, - cb, - &status, - NULL)) < 0) - vshResetLibvirtError(); + if (blocking && + !(bjWait = vshBlockJobWaitInit(ctl, dom, path, _("Block Pull"), verbose, + timeout, async))) + goto cleanup;
if (base || flags) { if (virDomainBlockRebase(dom, path, base, bandwidth, flags) < 0) @@ -2738,61 +2929,32 @@ cmdBlockPull(vshControl *ctl, const vshCmd *cmd) goto cleanup; }
- while (blocking) { - virDomainBlockJobInfo info; - int result; - - pthread_sigmask(SIG_BLOCK, &sigmask, &oldsigmask); - result = virDomainGetBlockJobInfo(dom, path, &info, 0); - pthread_sigmask(SIG_SETMASK, &oldsigmask, NULL); + /* Execution continues here only if --wait or friends were specifed */
specified This is also repeated in 12/13 and 13/13
+ switch (vshBlockJobWait(bjWait)) { + case -1: + goto cleanup;
- if (result < 0) { - vshError(ctl, _("failed to query job for disk %s"), path); + case VIR_DOMAIN_BLOCK_JOB_CANCELED: + vshPrint(ctl, "\n%s", _("Pull aborted")); goto cleanup; - } - if (result == 0) break;
- if (verbose) - vshPrintJobProgress(_("Block Pull"), info.end - info.cur, info.end); - - 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; - } - if (abort_flags & VIR_DOMAIN_BLOCK_JOB_ABORT_ASYNC) - break; - } else { - usleep(500 * 1000); - } - } - - if (status == VIR_DOMAIN_BLOCK_JOB_CANCELED) - quit = true; + case VIR_DOMAIN_BLOCK_JOB_FAILED: + vshPrint(ctl, "\n%s", _("Pull failed")); + goto cleanup; + break;
- if (verbose && !quit) { - /* printf [100 %] */ - vshPrintJobProgress(_("Block Pull"), 0, 1); + case VIR_DOMAIN_BLOCK_JOB_READY: + case VIR_DOMAIN_BLOCK_JOB_COMPLETED: + vshPrint(ctl, "\n%s", _("Pull complete")); + break; } - vshPrint(ctl, "\n%s", quit ? _("Pull aborted") : _("Pull complete"));
ret = true; + cleanup: virDomainFree(dom); - if (blocking) - sigaction(SIGINT, &old_sig_action, NULL); - if (cb_id >= 0) - virConnectDomainEventDeregisterAny(ctl->conn, cb_id); + vshBlockJobWaitFree(bjWait); return ret; }