mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-08-28 11:31:16 +00:00
Move most of qemuProcessKill into virProcessKillPainfully
In the cgroups APIs we have a virCgroupKillPainfully function which does the loop sending SIGTERM, then SIGKILL and waiting for the process to exit. There is similar functionality for simple processes in qemuProcessKill, but it is tangled with the QEMU code. Untangle it to provide a virProcessKillPainfuly function Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
This commit is contained in:
parent
f1b4021b38
commit
8fd3823117
@ -1708,6 +1708,7 @@ virPidFileDeletePath;
|
|||||||
# virprocess.h
|
# virprocess.h
|
||||||
virProcessAbort;
|
virProcessAbort;
|
||||||
virProcessKill;
|
virProcessKill;
|
||||||
|
virProcessKillPainfully;
|
||||||
virProcessTranslateStatus;
|
virProcessTranslateStatus;
|
||||||
virProcessWait;
|
virProcessWait;
|
||||||
|
|
||||||
|
@ -2006,17 +2006,11 @@ qemuDomainDestroyFlags(virDomainPtr dom,
|
|||||||
* it now means the job will be released
|
* it now means the job will be released
|
||||||
*/
|
*/
|
||||||
if (flags & VIR_DOMAIN_DESTROY_GRACEFUL) {
|
if (flags & VIR_DOMAIN_DESTROY_GRACEFUL) {
|
||||||
if (qemuProcessKill(driver, vm, 0) < 0) {
|
if (qemuProcessKill(driver, vm, 0) < 0)
|
||||||
virReportError(VIR_ERR_OPERATION_FAILED, "%s",
|
|
||||||
_("failed to kill qemu process with SIGTERM"));
|
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if (qemuProcessKill(driver, vm, VIR_QEMU_PROCESS_KILL_FORCE) < 0) {
|
if (qemuProcessKill(driver, vm, VIR_QEMU_PROCESS_KILL_FORCE) < 0)
|
||||||
virReportError(VIR_ERR_OPERATION_FAILED, "%s",
|
|
||||||
_("failed to kill qemu process with SIGTERM"));
|
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We need to prevent monitor EOF callback from doing our work (and sending
|
/* We need to prevent monitor EOF callback from doing our work (and sending
|
||||||
|
@ -3877,9 +3877,7 @@ int
|
|||||||
qemuProcessKill(struct qemud_driver *driver,
|
qemuProcessKill(struct qemud_driver *driver,
|
||||||
virDomainObjPtr vm, unsigned int flags)
|
virDomainObjPtr vm, unsigned int flags)
|
||||||
{
|
{
|
||||||
int i, ret = -1;
|
int ret;
|
||||||
const char *signame = "TERM";
|
|
||||||
bool driver_unlocked = false;
|
|
||||||
|
|
||||||
VIR_DEBUG("vm=%s pid=%d flags=%x",
|
VIR_DEBUG("vm=%s pid=%d flags=%x",
|
||||||
vm->def->name, vm->pid, flags);
|
vm->def->name, vm->pid, flags);
|
||||||
@ -3891,78 +3889,27 @@ qemuProcessKill(struct qemud_driver *driver,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This loop sends SIGTERM (or SIGKILL if flags has
|
if ((flags & VIR_QEMU_PROCESS_KILL_NOWAIT)) {
|
||||||
* VIR_QEMU_PROCESS_KILL_FORCE and VIR_QEMU_PROCESS_KILL_NOWAIT),
|
virProcessKill(vm->pid,
|
||||||
* then waits a few iterations (10 seconds) to see if it dies. If
|
(flags & VIR_QEMU_PROCESS_KILL_FORCE) ?
|
||||||
* the qemu process still hasn't exited, and
|
SIGKILL : SIGTERM);
|
||||||
* VIR_QEMU_PROCESS_KILL_FORCE is requested, a SIGKILL will then
|
return 0;
|
||||||
* be sent, and qemuProcessKill will wait up to 5 seconds more for
|
|
||||||
* the process to exit before returning. Note that the FORCE mode
|
|
||||||
* could result in lost data in the guest, so it should only be
|
|
||||||
* used if the guest is hung and can't be destroyed in any other
|
|
||||||
* manner.
|
|
||||||
*/
|
|
||||||
for (i = 0 ; i < 75; i++) {
|
|
||||||
int signum;
|
|
||||||
if (i == 0) {
|
|
||||||
if ((flags & VIR_QEMU_PROCESS_KILL_FORCE) &&
|
|
||||||
(flags & VIR_QEMU_PROCESS_KILL_NOWAIT)) {
|
|
||||||
signum = SIGKILL; /* kill it immediately */
|
|
||||||
signame="KILL";
|
|
||||||
} else {
|
|
||||||
signum = SIGTERM; /* kindly suggest it should exit */
|
|
||||||
}
|
|
||||||
} else if ((i == 50) & (flags & VIR_QEMU_PROCESS_KILL_FORCE)) {
|
|
||||||
VIR_WARN("Timed out waiting after SIG%s to process %d, "
|
|
||||||
"sending SIGKILL", signame, vm->pid);
|
|
||||||
signum = SIGKILL; /* kill it after a grace period */
|
|
||||||
signame="KILL";
|
|
||||||
} else {
|
|
||||||
signum = 0; /* Just check for existence */
|
|
||||||
}
|
|
||||||
|
|
||||||
if (virProcessKill(vm->pid, signum) < 0) {
|
|
||||||
if (errno != ESRCH) {
|
|
||||||
char ebuf[1024];
|
|
||||||
VIR_WARN("Failed to terminate process %d with SIG%s: %s",
|
|
||||||
vm->pid, signame,
|
|
||||||
virStrerror(errno, ebuf, sizeof(ebuf)));
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
ret = 0;
|
|
||||||
goto cleanup; /* process is dead */
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i == 0 && (flags & VIR_QEMU_PROCESS_KILL_NOWAIT)) {
|
|
||||||
ret = 0;
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (driver && !driver_unlocked) {
|
|
||||||
/* THREADS.txt says we can't hold the driver lock while sleeping */
|
|
||||||
qemuDriverUnlock(driver);
|
|
||||||
driver_unlocked = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
usleep(200 * 1000);
|
|
||||||
}
|
}
|
||||||
VIR_WARN("Timed out waiting after SIG%s to process %d", signame, vm->pid);
|
|
||||||
cleanup:
|
if (driver)
|
||||||
if (driver_unlocked) {
|
qemuDriverUnlock(driver);
|
||||||
/* We had unlocked the driver, so re-lock it. THREADS.txt says
|
|
||||||
* we can't have the domain locked when locking the driver, so
|
ret = virProcessKillPainfully(vm->pid,
|
||||||
* we must first unlock the domain. BUT, before we can unlock
|
!!(flags & VIR_QEMU_PROCESS_KILL_FORCE));
|
||||||
* the domain, we need to add a ref to it in case there aren't
|
|
||||||
* any active jobs (analysis of all callers didn't reveal such
|
if (driver) {
|
||||||
* a case, but there are too many to maintain certainty, so we
|
|
||||||
* will do this as a precaution).
|
|
||||||
*/
|
|
||||||
virObjectRef(vm);
|
virObjectRef(vm);
|
||||||
virDomainObjUnlock(vm);
|
virDomainObjUnlock(vm);
|
||||||
qemuDriverLock(driver);
|
qemuDriverLock(driver);
|
||||||
virDomainObjLock(vm);
|
virDomainObjLock(vm);
|
||||||
virObjectUnref(vm);
|
virObjectUnref(vm);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -235,3 +235,60 @@ int virProcessKill(pid_t pid, int sig)
|
|||||||
return kill(pid, sig);
|
return kill(pid, sig);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Try to kill the process and verify it has exited
|
||||||
|
*
|
||||||
|
* Returns 0 if it was killed gracefully, 1 if it
|
||||||
|
* was killed forcably, -1 if it is still alive,
|
||||||
|
* or another error occurred.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
virProcessKillPainfully(pid_t pid, bool force)
|
||||||
|
{
|
||||||
|
int i, ret = -1;
|
||||||
|
const char *signame = "TERM";
|
||||||
|
|
||||||
|
VIR_DEBUG("vpid=%d force=%d", pid, force);
|
||||||
|
|
||||||
|
/* This loop sends SIGTERM, then waits a few iterations (10 seconds)
|
||||||
|
* to see if it dies. If the process still hasn't exited, and
|
||||||
|
* @force is requested, a SIGKILL will be sent, and this will
|
||||||
|
* wait upto 5 seconds more for the process to exit before
|
||||||
|
* returning.
|
||||||
|
*
|
||||||
|
* Note that setting @force could result in dataloss for the process.
|
||||||
|
*/
|
||||||
|
for (i = 0 ; i < 75; i++) {
|
||||||
|
int signum;
|
||||||
|
if (i == 0) {
|
||||||
|
signum = SIGTERM; /* kindly suggest it should exit */
|
||||||
|
} else if ((i == 50) & force) {
|
||||||
|
VIR_DEBUG("Timed out waiting after SIGTERM to process %d, "
|
||||||
|
"sending SIGKILL", pid);
|
||||||
|
signum = SIGKILL; /* kill it after a grace period */
|
||||||
|
signame = "KILL";
|
||||||
|
} else {
|
||||||
|
signum = 0; /* Just check for existence */
|
||||||
|
}
|
||||||
|
|
||||||
|
if (virProcessKill(pid, signum) < 0) {
|
||||||
|
if (errno != ESRCH) {
|
||||||
|
virReportSystemError(errno,
|
||||||
|
_("Failed to terminate process %d with SIG%s"),
|
||||||
|
pid, signame);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
ret = signum == SIGTERM ? 0 : 1;
|
||||||
|
goto cleanup; /* process is dead */
|
||||||
|
}
|
||||||
|
|
||||||
|
usleep(200 * 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
VIR_DEBUG("Timed out waiting after SIGKILL to process %d", pid);
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
@ -38,5 +38,7 @@ virProcessWait(pid_t pid, int *exitstatus)
|
|||||||
|
|
||||||
int virProcessKill(pid_t pid, int sig);
|
int virProcessKill(pid_t pid, int sig);
|
||||||
|
|
||||||
|
int virProcessKillPainfully(pid_t pid, bool force);
|
||||||
|
|
||||||
|
|
||||||
#endif /* __VIR_PROCESS_H__ */
|
#endif /* __VIR_PROCESS_H__ */
|
||||||
|
Loading…
Reference in New Issue
Block a user