diff --git a/tools/virsh.c b/tools/virsh.c index aa9c6795a6..02f2e0d1ca 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -2738,19 +2738,29 @@ static const vshCmdOptDef opts_managedsave[] = { {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")}, {"running", VSH_OT_BOOL, 0, N_("set domain to be running on next start")}, {"paused", VSH_OT_BOOL, 0, N_("set domain to be paused on next start")}, + {"verbose", VSH_OT_BOOL, 0, N_("display the progress of save")}, {NULL, 0, 0, NULL} }; -static bool -cmdManagedSave(vshControl *ctl, const vshCmd *cmd) +static void +doManagedsave(void *opaque) { - virDomainPtr dom; + char ret = '1'; + vshCtrlData *data = opaque; + vshControl *ctl = data->ctl; + const vshCmd *cmd = data->cmd; + virDomainPtr dom = NULL; const char *name; - bool ret = false; unsigned int flags = 0; + sigset_t sigmask, oldsigmask; + + 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 (vshCommandOptBool(cmd, "bypass-cache")) flags |= VIR_DOMAIN_SAVE_BYPASS_CACHE; @@ -2760,18 +2770,64 @@ cmdManagedSave(vshControl *ctl, const vshCmd *cmd) flags |= VIR_DOMAIN_SAVE_PAUSED; if (!(dom = vshCommandOptDomain(ctl, cmd, &name))) - return false; + goto out; if (virDomainManagedSave(dom, flags) < 0) { vshError(ctl, _("Failed to save domain %s state"), name); - goto cleanup; + goto out; } - vshPrint(ctl, _("Domain %s state saved by libvirt\n"), name); - ret = true; + ret = '0'; +out: + pthread_sigmask(SIG_SETMASK, &oldsigmask, NULL); +out_sig: + if (dom) + virDomainFree (dom); + ignore_value(safewrite(data->writefd, &ret, sizeof(ret))); +} + +static bool +cmdManagedSave(vshControl *ctl, const vshCmd *cmd) +{ + virDomainPtr dom; + int p[2] = { -1, -1}; + bool ret = false; + bool verbose = false; + const char *name = NULL; + vshCtrlData data; + virThread workerThread; + + if (!(dom = vshCommandOptDomain(ctl, cmd, &name))) + return false; + + if (vshCommandOptBool (cmd, "verbose")) + verbose = true; + + if (pipe(p) < 0) + goto cleanup; + + data.ctl = ctl; + data.cmd = cmd; + data.writefd = p[1]; + + if (virThreadCreate(&workerThread, + true, + doManagedsave, + &data) < 0) + goto cleanup; + + ret = vshWatchJob(ctl, dom, verbose, p[0], 0, + NULL, NULL, _("Managedsave")); + + virThreadJoin(&workerThread); + + if (ret) + vshPrint(ctl, _("\nDomain %s state saved by libvirt\n"), name); cleanup: virDomainFree(dom); + VIR_FORCE_CLOSE(p[0]); + VIR_FORCE_CLOSE(p[1]); return ret; } diff --git a/tools/virsh.pod b/tools/virsh.pod index 6ae78d3658..6c10245a87 100644 --- a/tools/virsh.pod +++ b/tools/virsh.pod @@ -737,7 +737,7 @@ The editor used can be supplied by the C<$VISUAL> or C<$EDITOR> environment variables, and defaults to C. =item B I [I<--bypass-cache>] -[{I<--running> | I<--paused>}] +[{I<--running> | I<--paused>}] [I<--verbose>] Save and destroy (stop) a running domain, so it can be restarted from the same state at a later time. When the virsh B command is next run for @@ -746,9 +746,9 @@ If I<--bypass-cache> is specified, the save will avoid the file system cache, although this may slow down the operation. The progress may be monitored using B virsh command and canceled -with B command (sent by another virsh instance). Interrupting -(usually with C) the virsh process which runs B command -is not enough to actually cancel the operation. +with B command (sent by another virsh instance). Another option +is to send SIGINT (usually with C) to the virsh process running +B command. I<--verbose> displays the progress of save. Normally, starting a managed save will decide between running or paused based on the state the domain was in when the save was done; passing