From: Hu Tao <hutao@xxxxxxxxxxxxxx> Date: Tue, 11 Jan 2011 15:01:24 +0800 Subject: [PATCH 1/3] Cancel migration if user presses Ctrl-C when migration is in progress While migration is in progress and virsh is waiting for its completion, user may want to terminate the progress by pressing Ctrl-C. But virsh just exits on user's Ctrl-C leaving migration in background that user isn't even aware of. It's not reasonable. This patch changes the behaviour for migration. For other commands Ctrl-C still terminates virsh itself. --- tools/virsh.c | 127 ++++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 files changed, 116 insertions(+), 11 deletions(-) diff --git a/tools/virsh.c b/tools/virsh.c index aba7945..aba4fd1 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -31,6 +31,7 @@ #include <sys/stat.h> #include <inttypes.h> #include <signal.h> +#include <poll.h> #include <libxml/parser.h> #include <libxml/tree.h> @@ -54,6 +55,7 @@ #include "files.h" #include "../daemon/event.h" #include "configmake.h" +#include "threads.h" static char *progname; @@ -492,6 +494,15 @@ out: last_error = NULL; } +static bool intCatched = FALSE; + +static void vshCatchInt(int sig ATTRIBUTE_UNUSED, + siginfo_t *siginfo ATTRIBUTE_UNUSED, + void *context ATTRIBUTE_UNUSED) +{ + intCatched = TRUE; +} + /* * Detection of disconnections and automatic reconnection support */ @@ -3409,24 +3420,38 @@ static const vshCmdOptDef opts_migrate[] = { {NULL, 0, 0, NULL} }; -static int -cmdMigrate (vshControl *ctl, const vshCmd *cmd) +static void +doMigrate (void *opaque) { + char ret = '1'; virDomainPtr dom = NULL; const char *desturi; const char *migrateuri; const char *dname; - int flags = 0, found, ret = FALSE; + int flags = 0, found; + sigset_t sigmask, oldsigmask; + struct { + vshControl *ctl; + vshCmd *cmd; + int writefd; + } *data = opaque; + vshControl *ctl = data->ctl; + vshCmd *cmd = data->cmd; + + sigemptyset(&sigmask); + sigaddset(&sigmask, SIGINT); + if (pthread_sigmask(SIG_BLOCK, &sigmask, &oldsigmask) < 0) + goto out_sig; if (!vshConnectionUsability (ctl, ctl->conn)) - return FALSE; + goto out; if (!(dom = vshCommandOptDomain (ctl, cmd, NULL))) - return FALSE; + goto out; desturi = vshCommandOptString (cmd, "desturi", &found); if (!found) - goto done; + goto out; migrateuri = vshCommandOptString (cmd, "migrateuri", NULL); @@ -3460,29 +3485,109 @@ cmdMigrate (vshControl *ctl, const vshCmd *cmd) if (migrateuri != NULL) { vshError(ctl, "%s", _("migrate: Unexpected migrateuri for peer2peer/direct migration")); - goto done; + goto out; } if (virDomainMigrateToURI (dom, desturi, flags, dname, 0) == 0) - ret = TRUE; + ret = '0'; } else { /* For traditional live migration, connect to the destination host directly. */ virConnectPtr dconn = NULL; virDomainPtr ddom = NULL; dconn = virConnectOpenAuth (desturi, virConnectAuthPtrDefault, 0); - if (!dconn) goto done; + if (!dconn) goto out; ddom = virDomainMigrate (dom, dconn, flags, dname, migrateuri, 0); if (ddom) { virDomainFree(ddom); - ret = TRUE; + ret = '0'; } virConnectClose (dconn); } - done: +out: + pthread_sigmask(SIG_BLOCK, &oldsigmask, NULL); +out_sig: if (dom) virDomainFree (dom); + ignore_value(safewrite(data->writefd, &ret, sizeof(ret))); +} + +static int +cmdMigrate (vshControl *ctl, const vshCmd *cmd) +{ + virDomainPtr dom = NULL; + int p[2] = {-1, -1}; + int ret = -1; + virThread workerThread; + struct pollfd pollfd; + char retchar; + struct sigaction sig_action; + struct sigaction old_sig_action; + + struct { + vshControl *ctl; + const vshCmd *cmd; + int writefd; + } data; + + if (!(dom = vshCommandOptDomain (ctl, cmd, NULL))) + return FALSE; + + 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; + + intCatched = FALSE; + 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.events = POLLIN; + pollfd.revents = 0; + + ret = poll(&pollfd, 1, -1); + if (ret > 0) { + if (saferead(p[0], &retchar, sizeof(retchar)) > 0) { + if (retchar == '0') + ret = TRUE; + else + ret = FALSE; + } else + ret = FALSE; + } else if (ret < 0) { + if (errno == EINTR && intCatched) { + virDomainAbortJob(dom); + ret = FALSE; + intCatched = FALSE; + } + } else { + /* timed out */ + ret = FALSE; + } + + sigaction(SIGINT, &old_sig_action, NULL); + + virThreadJoin(&workerThread); + +cleanup: + if (dom) + virDomainFree(dom); + if (p[0] != -1) { + close(p[0]); + close(p[1]); + } return ret; } -- 1.7.1 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list