git: 0b29fd06dab2 - stable/13 - vm_fault: do not trigger OOM too early

From: Konstantin Belousov <kib_at_FreeBSD.org>
Date: Sun, 10 Oct 2021 09:24:29 UTC
The branch stable/13 has been updated by kib:

URL: https://cgit.FreeBSD.org/src/commit/?id=0b29fd06dab2c7ed97293adb82a7392f2ab3b4e2

commit 0b29fd06dab2c7ed97293adb82a7392f2ab3b4e2
Author:     Konstantin Belousov <kib@FreeBSD.org>
AuthorDate: 2021-10-04 06:36:02 +0000
Commit:     Konstantin Belousov <kib@FreeBSD.org>
CommitDate: 2021-10-10 09:22:58 +0000

    vm_fault: do not trigger OOM too early
    
    (cherry picked from commit 174aad047e12e8f30f9a5919ca1c08919441a217)
---
 sys/vm/vm_fault.c | 52 +++++++++++++++++++++++++++++++++++++---------------
 1 file changed, 37 insertions(+), 15 deletions(-)

diff --git a/sys/vm/vm_fault.c b/sys/vm/vm_fault.c
index 03ca297ea683..c0ac89e4b70f 100644
--- a/sys/vm/vm_fault.c
+++ b/sys/vm/vm_fault.c
@@ -125,7 +125,8 @@ struct faultstate {
 	vm_prot_t	fault_type;
 	vm_prot_t	prot;
 	int		fault_flags;
-	int		oom;
+	struct timeval	oom_start_time;
+	bool		oom_started;
 	boolean_t	wired;
 
 	/* Page reference for cow. */
@@ -1069,6 +1070,38 @@ vm_fault_zerofill(struct faultstate *fs)
 	vm_page_valid(fs->m);
 }
 
+/*
+ * Initiate page fault after timeout.  Returns true if caller should
+ * do vm_waitpfault() after the call.
+ */
+static bool
+vm_fault_allocate_oom(struct faultstate *fs)
+{
+	struct timeval now;
+
+	unlock_and_deallocate(fs);
+	if (vm_pfault_oom_attempts < 0)
+		return (true);
+	if (!fs->oom_started) {
+		fs->oom_started = true;
+		getmicrotime(&fs->oom_start_time);
+		return (true);
+	}
+
+	getmicrotime(&now);
+	timevalsub(&now, &fs->oom_start_time);
+	if (now.tv_sec < vm_pfault_oom_attempts * vm_pfault_oom_wait)
+		return (true);
+
+	if (bootverbose)
+		printf(
+	    "proc %d (%s) failed to alloc page on fault, starting OOM\n",
+		    curproc->p_pid, curproc->p_comm);
+	vm_pageout_oom(VM_OOM_MEM_PF);
+	fs->oom_started = false;
+	return (false);
+}
+
 /*
  * Allocate a page directly or via the object populate method.
  */
@@ -1132,22 +1165,11 @@ vm_fault_allocate(struct faultstate *fs)
 		fs->m = vm_page_alloc(fs->object, fs->pindex, alloc_req);
 	}
 	if (fs->m == NULL) {
-		unlock_and_deallocate(fs);
-		if (vm_pfault_oom_attempts < 0 ||
-		    fs->oom < vm_pfault_oom_attempts) {
-			fs->oom++;
+		if (vm_fault_allocate_oom(fs))
 			vm_waitpfault(dset, vm_pfault_oom_wait * hz);
-		} else 	{
-			if (bootverbose)
-				printf(
-		"proc %d (%s) failed to alloc page on fault, starting OOM\n",
-				    curproc->p_pid, curproc->p_comm);
-			vm_pageout_oom(VM_OOM_MEM_PF);
-			fs->oom = 0;
-		}
 		return (KERN_RESOURCE_SHORTAGE);
 	}
-	fs->oom = 0;
+	fs->oom_started = false;
 
 	return (KERN_NOT_RECEIVER);
 }
@@ -1296,7 +1318,7 @@ vm_fault(vm_map_t map, vm_offset_t vaddr, vm_prot_t fault_type,
 	fs.fault_flags = fault_flags;
 	fs.map = map;
 	fs.lookup_still_valid = false;
-	fs.oom = 0;
+	fs.oom_started = false;
 	faultcount = 0;
 	nera = -1;
 	hardfault = false;