[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Re: Unable to recycle any page



On 12/06/2025 14:14, Michael Kelly wrote:
I have restructured vm_page_seg_pull_inactive_page() and vm_page_seg_pull_active_page() to search all appropriate lists and have been able to run the test case to completion many times without the 'vm_page warning' occurring with swap usage reaching up to ~500M in some instances. See appended patch. As usual, please feel free to alter before inclusion, make suggestions or reject as appropriate.
Patch replacement attached. Apologies for any inconvenience.
diff --git a/vm/vm_page.c b/vm/vm_page.c
index 6c5eba22..f07d6c78 100644
--- a/vm/vm_page.c
+++ b/vm/vm_page.c
@@ -555,24 +555,6 @@ vm_page_queue_remove(struct vm_page_queue *queue, struct vm_page *page)
     list_remove(&page->node);
 }
 
-static struct vm_page *
-vm_page_queue_first(struct vm_page_queue *queue, boolean_t external_only)
-{
-    struct vm_page *page;
-
-    if (!list_empty(&queue->external_pages)) {
-        page = list_first_entry(&queue->external_pages, struct vm_page, node);
-        return page;
-    }
-
-    if (!external_only && !list_empty(&queue->internal_pages)) {
-        page = list_first_entry(&queue->internal_pages, struct vm_page, node);
-        return page;
-    }
-
-    return NULL;
-}
-
 static struct vm_page_seg *
 vm_page_seg_get(unsigned short index)
 {
@@ -813,28 +795,53 @@ vm_page_seg_remove_inactive_page(struct vm_page_seg *seg, struct vm_page *page)
     vm_page_inactive_count--;
 }
 
+static inline struct list*
+vm_page_next_page_list(struct list* cur_page_list,
+		       struct vm_page_queue* queue,
+		       boolean_t external_only)
+{
+  return (external_only
+	  ? NULL
+	  : (cur_page_list == &queue->external_pages
+	     ? &queue->internal_pages
+	     : NULL));
+}
+
 /*
  * Attempt to pull an active page.
  *
  * If successful, the object containing the page is locked.
  */
+
 static struct vm_page *
 vm_page_seg_pull_active_page(struct vm_page_seg *seg, boolean_t external_only)
 {
     struct vm_page *page, *first;
+    struct list* page_list;
     boolean_t locked;
 
     first = NULL;
 
+    page_list = &seg->active_pages.external_pages;
+
     for (;;) {
-        page = vm_page_queue_first(&seg->active_pages, external_only);
 
-        if (page == NULL) {
+        page = (list_empty(page_list)
+		? NULL
+		: list_first_entry(page_list, struct vm_page, node));
+
+        if (page == NULL || page == first) {
+          page_list = vm_page_next_page_list(page_list, &seg->active_pages, external_only);
+
+          if (page_list == NULL)
             break;
+          else
+            {
+              first = NULL;
+              continue;
+            }
         } else if (first == NULL) {
             first = page;
-        } else if (first == page) {
-            break;
         }
 
         vm_page_seg_remove_active_page(seg, page);
@@ -868,19 +875,31 @@ static struct vm_page *
 vm_page_seg_pull_inactive_page(struct vm_page_seg *seg, boolean_t external_only)
 {
     struct vm_page *page, *first;
+    struct list* page_list;
     boolean_t locked;
 
     first = NULL;
 
+    page_list = &seg->inactive_pages.external_pages;
+
     for (;;) {
-        page = vm_page_queue_first(&seg->inactive_pages, external_only);
 
-        if (page == NULL) {
+        page = (list_empty(page_list)
+		? NULL
+		: list_first_entry(page_list, struct vm_page, node));
+
+        if (page == NULL || page == first) {
+          page_list = vm_page_next_page_list(page_list, &seg->inactive_pages, external_only);
+
+          if (page_list == NULL)
             break;
+          else
+            {
+              first = NULL;
+              continue;
+            }
         } else if (first == NULL) {
             first = page;
-        } else if (first == page) {
-            break;
         }
 
         vm_page_seg_remove_inactive_page(seg, page);

Reply to: