mirror of https://gitee.com/openkylin/libvirt.git
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.
This commit is contained in:
parent
3fdc7895ec
commit
8e6d9860cd
126
tools/virsh.c
126
tools/virsh.c
|
@ -31,6 +31,7 @@
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
#include <poll.h>
|
||||||
|
|
||||||
#include <libxml/parser.h>
|
#include <libxml/parser.h>
|
||||||
#include <libxml/tree.h>
|
#include <libxml/tree.h>
|
||||||
|
@ -54,6 +55,7 @@
|
||||||
#include "files.h"
|
#include "files.h"
|
||||||
#include "../daemon/event.h"
|
#include "../daemon/event.h"
|
||||||
#include "configmake.h"
|
#include "configmake.h"
|
||||||
|
#include "threads.h"
|
||||||
|
|
||||||
static char *progname;
|
static char *progname;
|
||||||
|
|
||||||
|
@ -492,6 +494,15 @@ out:
|
||||||
last_error = NULL;
|
last_error = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static volatile sig_atomic_t intCaught = 0;
|
||||||
|
|
||||||
|
static void vshCatchInt(int sig ATTRIBUTE_UNUSED,
|
||||||
|
siginfo_t *siginfo ATTRIBUTE_UNUSED,
|
||||||
|
void *context ATTRIBUTE_UNUSED)
|
||||||
|
{
|
||||||
|
intCaught = 1;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Detection of disconnections and automatic reconnection support
|
* Detection of disconnections and automatic reconnection support
|
||||||
*/
|
*/
|
||||||
|
@ -3409,24 +3420,40 @@ static const vshCmdOptDef opts_migrate[] = {
|
||||||
{NULL, 0, 0, NULL}
|
{NULL, 0, 0, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
static int
|
typedef struct __vshCtrlData {
|
||||||
cmdMigrate (vshControl *ctl, const vshCmd *cmd)
|
vshControl *ctl;
|
||||||
|
const vshCmd *cmd;
|
||||||
|
int writefd;
|
||||||
|
} vshCtrlData;
|
||||||
|
|
||||||
|
static void
|
||||||
|
doMigrate (void *opaque)
|
||||||
{
|
{
|
||||||
|
char ret = '1';
|
||||||
virDomainPtr dom = NULL;
|
virDomainPtr dom = NULL;
|
||||||
const char *desturi;
|
const char *desturi;
|
||||||
const char *migrateuri;
|
const char *migrateuri;
|
||||||
const char *dname;
|
const char *dname;
|
||||||
int flags = 0, found, ret = FALSE;
|
int flags = 0, found;
|
||||||
|
sigset_t sigmask, oldsigmask;
|
||||||
|
vshCtrlData *data = opaque;
|
||||||
|
vshControl *ctl = data->ctl;
|
||||||
|
const 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))
|
if (!vshConnectionUsability (ctl, ctl->conn))
|
||||||
return FALSE;
|
goto out;
|
||||||
|
|
||||||
if (!(dom = vshCommandOptDomain (ctl, cmd, NULL)))
|
if (!(dom = vshCommandOptDomain (ctl, cmd, NULL)))
|
||||||
return FALSE;
|
goto out;
|
||||||
|
|
||||||
desturi = vshCommandOptString (cmd, "desturi", &found);
|
desturi = vshCommandOptString (cmd, "desturi", &found);
|
||||||
if (!found)
|
if (!found)
|
||||||
goto done;
|
goto out;
|
||||||
|
|
||||||
migrateuri = vshCommandOptString (cmd, "migrateuri", NULL);
|
migrateuri = vshCommandOptString (cmd, "migrateuri", NULL);
|
||||||
|
|
||||||
|
@ -3460,29 +3487,106 @@ cmdMigrate (vshControl *ctl, const vshCmd *cmd)
|
||||||
|
|
||||||
if (migrateuri != NULL) {
|
if (migrateuri != NULL) {
|
||||||
vshError(ctl, "%s", _("migrate: Unexpected migrateuri for peer2peer/direct migration"));
|
vshError(ctl, "%s", _("migrate: Unexpected migrateuri for peer2peer/direct migration"));
|
||||||
goto done;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (virDomainMigrateToURI (dom, desturi, flags, dname, 0) == 0)
|
if (virDomainMigrateToURI (dom, desturi, flags, dname, 0) == 0)
|
||||||
ret = TRUE;
|
ret = '0';
|
||||||
} else {
|
} else {
|
||||||
/* For traditional live migration, connect to the destination host directly. */
|
/* For traditional live migration, connect to the destination host directly. */
|
||||||
virConnectPtr dconn = NULL;
|
virConnectPtr dconn = NULL;
|
||||||
virDomainPtr ddom = NULL;
|
virDomainPtr ddom = NULL;
|
||||||
|
|
||||||
dconn = virConnectOpenAuth (desturi, virConnectAuthPtrDefault, 0);
|
dconn = virConnectOpenAuth (desturi, virConnectAuthPtrDefault, 0);
|
||||||
if (!dconn) goto done;
|
if (!dconn) goto out;
|
||||||
|
|
||||||
ddom = virDomainMigrate (dom, dconn, flags, dname, migrateuri, 0);
|
ddom = virDomainMigrate (dom, dconn, flags, dname, migrateuri, 0);
|
||||||
if (ddom) {
|
if (ddom) {
|
||||||
virDomainFree(ddom);
|
virDomainFree(ddom);
|
||||||
ret = TRUE;
|
ret = '0';
|
||||||
}
|
}
|
||||||
virConnectClose (dconn);
|
virConnectClose (dconn);
|
||||||
}
|
}
|
||||||
|
|
||||||
done:
|
out:
|
||||||
|
pthread_sigmask(SIG_SETMASK, &oldsigmask, NULL);
|
||||||
|
out_sig:
|
||||||
if (dom) virDomainFree (dom);
|
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;
|
||||||
|
|
||||||
|
vshCtrlData 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;
|
||||||
|
|
||||||
|
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.events = POLLIN;
|
||||||
|
pollfd.revents = 0;
|
||||||
|
|
||||||
|
repoll:
|
||||||
|
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) {
|
||||||
|
if (intCaught) {
|
||||||
|
virDomainAbortJob(dom);
|
||||||
|
ret = FALSE;
|
||||||
|
intCaught = 0;
|
||||||
|
} else
|
||||||
|
goto repoll;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* timed out */
|
||||||
|
ret = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
sigaction(SIGINT, &old_sig_action, NULL);
|
||||||
|
|
||||||
|
virThreadJoin(&workerThread);
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
virDomainFree(dom);
|
||||||
|
VIR_FORCE_CLOSE(p[0]);
|
||||||
|
VIR_FORCE_CLOSE(p[1]);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue