Blob Blame History Raw
From: Claudio Imbrenda <imbrenda@linux.ibm.com>
Subject: s390/kvm: fix deadlock when killed by oom
Patch-mainline: v4.19-rc1
Git-commit: 306d6c49ac9ded11114cb53b0925da52f2c2ada1
References: bnc#1113501, LTC#172235

Description:  kvm: fix deadlock when killed by oom
Symptom:      oom killer leaves processes in a deadlock state.
Problem:      The problem arises in the rare cases in which
              handle_mm_fault does not release the mm_sem.
Solution:     Correct the issue by manually relaese the mm_sem
              when needed.
Reproduction: Create numerous KVM guests so that the host starts
              swapping and memory becomes overcomitted and the oom
              killer is triggered.

Upstream-Description:

              s390/kvm: fix deadlock when killed by oom

              When the oom killer kills a userspace process in the page fault handler
              while in guest context, the fault handler fails to release the mm_sem
              if the FAULT_FLAG_RETRY_NOWAIT option is set. This leads to a deadlock
              when tearing down the mm when the process terminates. This bug can only
              happen when pfault is enabled, so only KVM clients are affected.

              The problem arises in the rare cases in which handle_mm_fault does not
              release the mm_sem. This patch fixes the issue by manually releasing
              the mm_sem when needed.

              Fixes: 24eb3a824c4f3 ("KVM: s390: Add FAULT_FLAG_RETRY_NOWAIT for guest fault")
              Cc: <stable@vger.kernel.org> # 3.15+
              Signed-off-by: Claudio Imbrenda <imbrenda@linux.vnet.ibm.com>
              Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>


Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
Acked-by: Petr Tesarik <ptesarik@suse.com>
---
 arch/s390/mm/fault.c |    2 ++
 1 file changed, 2 insertions(+)

--- a/arch/s390/mm/fault.c
+++ b/arch/s390/mm/fault.c
@@ -485,6 +485,8 @@ retry:
 	/* No reason to continue if interrupted by SIGKILL. */
 	if ((fault & VM_FAULT_RETRY) && fatal_signal_pending(current)) {
 		fault = VM_FAULT_SIGNAL;
+		if (flags & FAULT_FLAG_RETRY_NOWAIT)
+			goto out_up;
 		goto out;
 	}
 	if (unlikely(fault & VM_FAULT_ERROR))