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