git: 983723943a5b - main - vm_pageout: rewrite cluster()

From: Doug Moore <dougm_at_FreeBSD.org>
Date: Thu, 17 Apr 2025 15:54:13 UTC
The branch main has been updated by dougm:

URL: https://cgit.FreeBSD.org/src/commit/?id=983723943a5b7f1f249ba8f646b20e57ad524fed

commit 983723943a5b7f1f249ba8f646b20e57ad524fed
Author:     Doug Moore <dougm@FreeBSD.org>
AuthorDate: 2025-04-17 15:52:34 +0000
Commit:     Doug Moore <dougm@FreeBSD.org>
CommitDate: 2025-04-17 15:52:34 +0000

    vm_pageout: rewrite cluster()
    
    Implement vm_pageout_cluster using iterators instead of vm_page_next()
    and vm_page_prev(), and without gotos.
    
    Reviewed by:    kib
    Differential Revision:  https://reviews.freebsd.org/D49848
---
 sys/vm/vm_pageout.c | 64 +++++++++++++++++++++++++++--------------------------
 1 file changed, 33 insertions(+), 31 deletions(-)

diff --git a/sys/vm/vm_pageout.c b/sys/vm/vm_pageout.c
index e2efa11842b5..7b303d7d905f 100644
--- a/sys/vm/vm_pageout.c
+++ b/sys/vm/vm_pageout.c
@@ -108,6 +108,7 @@
 #include <vm/vm_pager.h>
 #include <vm/vm_phys.h>
 #include <vm/vm_pagequeue.h>
+#include <vm/vm_radix.h>
 #include <vm/swap_pager.h>
 #include <vm/vm_extern.h>
 #include <vm/uma.h>
@@ -366,15 +367,16 @@ vm_pageout_flushable(vm_page_t m)
 static int
 vm_pageout_cluster(vm_page_t m)
 {
+	struct pctrie_iter pages;
 	vm_page_t mc[2 * vm_pageout_page_count - 1];
-	int alignment, num_ends, page_base, pageout_count;
+	int alignment, page_base, pageout_count;
 
 	VM_OBJECT_ASSERT_WLOCKED(m->object);
 
 	vm_page_assert_xbusied(m);
 
+	vm_page_iter_init(&pages, m->object);
 	alignment = m->pindex % vm_pageout_page_count;
-	num_ends = 0;
 	page_base = nitems(mc) / 2;
 	pageout_count = 1;
 	mc[page_base] = m;
@@ -387,37 +389,37 @@ vm_pageout_cluster(vm_page_t m)
 	 * holes).  To solve this problem we do the reverse scan
 	 * first and attempt to align our cluster, then do a 
 	 * forward scan if room remains.
+	 *
+	 * If we are at an alignment boundary, stop here, and switch directions.
 	 */
-more:
-	m = mc[page_base];
-	while (pageout_count < vm_pageout_page_count) {
-		/*
-		 * If we are at an alignment boundary, and haven't reached the
-		 * last flushable page forward, stop here, and switch
-		 * directions.
-		 */
-		if (alignment == pageout_count - 1 && num_ends == 0)
-			break;
-
-		m = vm_page_prev(m);
-		if (m == NULL || !vm_pageout_flushable(m)) {
-			num_ends++;
-			break;
-		}
-		mc[--page_base] = m;
-		++pageout_count;
+	if (alignment > 0) {
+		pages.index = mc[page_base]->pindex;
+		do {
+			m = vm_radix_iter_prev(&pages);
+			if (m == NULL || !vm_pageout_flushable(m))
+				break;
+			mc[--page_base] = m;
+		} while (pageout_count++ < alignment);
 	}
-	m = mc[page_base + pageout_count - 1];
-	while (num_ends != 2 && pageout_count < vm_pageout_page_count) {
-		m = vm_page_next(m);
-		if (m == NULL || !vm_pageout_flushable(m)) {
-			if (num_ends++ == 0)
-				/* Resume the reverse scan. */
-				goto more;
-			break;
-		}
-		mc[page_base + pageout_count] = m;
-		++pageout_count;
+	if (pageout_count < vm_pageout_page_count) {
+		pages.index = mc[page_base + pageout_count - 1]->pindex;
+		do {
+			m = vm_radix_iter_next(&pages);
+			if (m == NULL || !vm_pageout_flushable(m))
+				break;
+			mc[page_base + pageout_count] = m;
+		} while (++pageout_count < vm_pageout_page_count);
+	}
+	if (pageout_count < vm_pageout_page_count &&
+	    alignment == nitems(mc) / 2 - page_base) {
+		/* Resume the reverse scan. */
+		pages.index = mc[page_base]->pindex;
+		do {
+			m = vm_radix_iter_prev(&pages);
+			if (m == NULL || !vm_pageout_flushable(m))
+				break;
+			mc[--page_base] = m;
+		} while (++pageout_count < vm_pageout_page_count);
 	}
 
 	return (vm_pageout_flush(&mc[page_base], pageout_count,