called do_watch_job. This can be later used in other job oriented commands like dump, save, managedsave to report progress and allow user to cancel via ^C. --- tools/virsh.c | 187 ++++++++++++++++++++++++++++++++++---------------------- 1 files changed, 113 insertions(+), 74 deletions(-) diff --git a/tools/virsh.c b/tools/virsh.c index 583ec6d..5f9a9ff 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -394,6 +394,27 @@ static char *editWriteToTempFile (vshControl *ctl, const char *doc); static int editFile (vshControl *ctl, const char *filename); static char *editReadBackFile (vshControl *ctl, const char *filename); +/* Typedefs, function prototypes for job progress reporting. + * There are used by some long lingering commands like + * migrate, dump, save, managedsave. + */ +typedef struct __vshCtrlData { + vshControl *ctl; + const vshCmd *cmd; + int writefd; +} vshCtrlData; + +typedef void (*jobWatchTimeoutFunc) (vshControl *ctl, virDomainPtr dom); + +static bool +do_watch_job(vshControl *ctl, + virDomainPtr dom, + bool verbose, + int pipe_fd, + int timeout, + jobWatchTimeoutFunc timeout_func, + const char *label); + static void *_vshMalloc(vshControl *ctl, size_t sz, const char *filename, int line); #define vshMalloc(_ctl, _sz) _vshMalloc(_ctl, _sz, __FILE__, __LINE__) @@ -5720,12 +5741,6 @@ static const vshCmdOptDef opts_migrate[] = { {NULL, 0, 0, NULL} }; -typedef struct __vshCtrlData { - vshControl *ctl; - const vshCmd *cmd; - int writefd; -} vshCtrlData; - static void doMigrate (void *opaque) { @@ -5858,75 +5873,44 @@ print_job_progress(const char *label, unsigned long long remaining, fflush(stderr); } +static void +on_migration_timeout(vshControl *ctl, + virDomainPtr dom) +{ + vshDebug(ctl, VSH_ERR_DEBUG, "suspend the domain " + "when migration timeouts\n"); + virDomainSuspend(dom); +} + static bool -cmdMigrate (vshControl *ctl, const vshCmd *cmd) +do_watch_job(vshControl *ctl, + virDomainPtr dom, + bool verbose, + int pipe_fd, + int timeout, + jobWatchTimeoutFunc timeout_func, + const char *label) { - virDomainPtr dom = NULL; - int p[2] = {-1, -1}; - int ret = -1; - bool functionReturn = false; - virThread workerThread; - struct pollfd pollfd; - char retchar; struct sigaction sig_action; struct sigaction old_sig_action; - virDomainJobInfo jobinfo; - bool verbose = false; - int timeout = 0; + struct pollfd pollfd; struct timeval start, curr; - bool live_flag = false; - vshCtrlData data; + virDomainJobInfo jobinfo; + int ret = -1; + char retchar; + bool functionReturn = false; sigset_t sigmask, oldsigmask; sigemptyset(&sigmask); sigaddset(&sigmask, SIGINT); - if (!(dom = vshCommandOptDomain(ctl, cmd, NULL))) - return false; - - if (vshCommandOptBool (cmd, "verbose")) - verbose = true; - - if (vshCommandOptBool (cmd, "live")) - live_flag = true; - if (vshCommandOptInt(cmd, "timeout", &timeout) > 0) { - if (! live_flag) { - vshError(ctl, "%s", _("migrate: Unexpected timeout for offline migration")); - goto cleanup; - } - - if (timeout < 1) { - vshError(ctl, "%s", _("migrate: Invalid timeout")); - goto cleanup; - } - - /* Ensure that we can multiply by 1000 without overflowing. */ - if (timeout > INT_MAX / 1000) { - vshError(ctl, "%s", _("migrate: Timeout is too big")); - goto cleanup; - } - } - - if (pipe(p) < 0) - goto cleanup; - - data.ctl = ctl; - data.cmd = cmd; - data.writefd = p[1]; - - if (virThreadCreate(&workerThread, - true, - doMigrate, - &data) < 0) - goto cleanup; - 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); - pollfd.fd = p[0]; + pollfd.fd = pipe_fd; pollfd.events = POLLIN; pollfd.revents = 0; @@ -5935,18 +5919,16 @@ cmdMigrate (vshControl *ctl, const vshCmd *cmd) repoll: ret = poll(&pollfd, 1, 500); if (ret > 0) { - if (saferead(p[0], &retchar, sizeof(retchar)) > 0) { - if (retchar == '0') { - functionReturn = true; + if (pollfd.revents & POLLIN && + saferead(pipe_fd, &retchar, sizeof(retchar)) > 0 && + retchar == '0') { if (verbose) { /* print [100 %] */ - print_job_progress("Migration", 0, 1); + print_job_progress(label, 0, 1); } - } else - functionReturn = false; - } else - functionReturn = false; - break; + break; + } + goto cleanup; } if (ret < 0) { @@ -5957,17 +5939,16 @@ repoll: } else goto repoll; } - functionReturn = false; - break; + goto cleanup; } GETTIMEOFDAY(&curr); if ( timeout && ((int)(curr.tv_sec - start.tv_sec) * 1000 + \ (int)(curr.tv_usec - start.tv_usec) / 1000) > timeout * 1000 ) { /* suspend the domain when migration timeouts. */ - vshDebug(ctl, VSH_ERR_DEBUG, - "suspend the domain when migration timeouts\n"); - virDomainSuspend(dom); + vshDebug(ctl, VSH_ERR_DEBUG, "%s timeout", label); + if (timeout_func) + (timeout_func)(ctl, dom); timeout = 0; } @@ -5976,12 +5957,70 @@ repoll: ret = virDomainGetJobInfo(dom, &jobinfo); pthread_sigmask(SIG_SETMASK, &oldsigmask, NULL); if (ret == 0) - print_job_progress("Migration", jobinfo.dataRemaining, + print_job_progress(label, jobinfo.dataRemaining, jobinfo.dataTotal); } } + functionReturn = true; + +cleanup: sigaction(SIGINT, &old_sig_action, NULL); + return functionReturn; +} + +static bool +cmdMigrate (vshControl *ctl, const vshCmd *cmd) +{ + virDomainPtr dom = NULL; + int p[2] = {-1, -1}; + virThread workerThread; + bool verbose = false; + bool functionReturn = false; + int timeout = 0; + bool live_flag = false; + vshCtrlData data; + + if (!(dom = vshCommandOptDomain(ctl, cmd, NULL))) + return false; + + if (vshCommandOptBool (cmd, "verbose")) + verbose = true; + + if (vshCommandOptBool (cmd, "live")) + live_flag = true; + if (vshCommandOptInt(cmd, "timeout", &timeout) > 0) { + if (! live_flag) { + vshError(ctl, "%s", _("migrate: Unexpected timeout for offline migration")); + goto cleanup; + } + + if (timeout < 1) { + vshError(ctl, "%s", _("migrate: Invalid timeout")); + goto cleanup; + } + + /* Ensure that we can multiply by 1000 without overflowing. */ + if (timeout > INT_MAX / 1000) { + vshError(ctl, "%s", _("migrate: Timeout is too big")); + goto cleanup; + } + } + + if (pipe(p) < 0) + goto cleanup; + + data.ctl = ctl; + data.cmd = cmd; + data.writefd = p[1]; + + if (virThreadCreate(&workerThread, + true, + doMigrate, + &data) < 0) + goto cleanup; + functionReturn = do_watch_job(ctl, dom, verbose, p[0], timeout, + on_migration_timeout, "Migration"); virThreadJoin(&workerThread); -- 1.7.3.4 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list