From: Hu Tao <hutao(a)cn.fujitsu.com>
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