Skip to contentSkip to conversation

reduce swap due to shrink_mmap failures

PATCH New Roger Larsson 1 participant 2 messages Jun 8, 2000 – Jun 9, 2000

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

Hi,

This is an improved version that reduces failures due to calling it with no zones with pressure...

It has some problems related to latency
(as normal kernel) probably due to the maximum of 64 loops in do_try_to_free_pages...
[might it be time to back off some of earlier patches?]

It has survived several memory tests (mmap002) and with good performance in more normal situations. [it could 'scan' more before giving up in shrink_mmap]

/RogerL

--
Home page:
http://www.norran.net/nra02596/

usr/src/linux/mm/filemap.c renamed from usr/src/linux/mm/filemap.c.ac10 +59 -14
@@ -301,7 +301,7 @@
  */
 int shrink_mmap(int priority, int gfp_mask)
 {
-	int ret = 0, count, nr_dirty;
+	int ret = 0, count, nr_dirty, scan = 0;
 	struct list_head * page_lru;
 	struct page * page = NULL;
 	
@@ -310,20 +310,44 @@
 
 	/* we need pagemap_lru_lock for list_del() ... subtle code below */
 	spin_lock(&pagemap_lru_lock);
-	while (count > 0 && (page_lru = lru_cache.prev) != &lru_cache) {
+	page_lru = &lru_cache;
+	while (count > 0) {
+                page_lru = page_lru->prev;
+                if (page_lru == &lru_cache) {
+		  /* one whole run, ALL lru pages aged */
+		  scan++;
+		  if (scan < 2)
+		    continue;
+		  else
+		    /* a) no freeable pages in LRU
+		     * b) no zone with preasure
+		     */
+		    break;
+		}
+
 		page = list_entry(page_lru, struct page, lru);
-		list_del(page_lru);
 
 		if (PageTestandClearReferenced(page)) {
 			page->age += PG_AGE_ADV;
 			if (page->age > PG_AGE_MAX)
 				page->age = PG_AGE_MAX;
-			goto dispose_continue;
+			continue;
 		}
+
+		/*
+		 * Page is from a zone we don't care about.
+		 * Don't drop page cache entries in vain.
+		 * Note: placement allows pages to gain age during
+		 * fast scan, but not loose - avoids all pages
+		 * becoming zero.
+		 */
+		if (page->zone->free_pages > page->zone->pages_high)
+			continue;
+
 		page->age -= min(PG_AGE_DECL, page->age);
 
 		if (page->age)
-			goto dispose_continue;
+			continue;
 
 		count--;
 		/*
@@ -331,10 +355,34 @@
 		 * immediate tell are untouchable..
 		 */
 		if (!page->buffers && page_count(page) > 1)
-			goto dispose_continue;
+			continue;
 
 		if (TryLockPage(page))
-			goto dispose_continue;
+			continue;
+
+		/* Move header before unlock...
+		 * NOTE: the page to scan might move on while having
+		 * pagemap_lru unlocked. Avoid rescanning pages
+		 * by moving head and removing current.
+		 */
+
+		/*
+		 * Equivalent code follows
+		 *
+		 *   list_del(&lru_cache);
+		 *   list_add_tail(&lru_cache, page_lru);
+		 *   list_del(page_lru);
+		 */
+		if (lru_cache.prev == page_lru) {
+		  /* Handle case with only one page on lru...
+		   * also optimize if first page checked is suitable.
+		   */
+		  list_del(page_lru);
+		}
+		else {
+		  list_del(&lru_cache);
+		  __list_add(&lru_cache, page_lru->prev, page_lru->next);
+		}
 
 		/* Release the pagemap_lru lock even if the page is not yet
 		   queued in any lru queue since we have just locked down
@@ -361,13 +409,6 @@
 			}
 		}
 
-		/*
-		 * Page is from a zone we don't care about.
-		 * Don't drop page cache entries in vain.
-		 */
-		if (page->zone->free_pages > page->zone->pages_high)
-			goto unlock_continue;
-
 		/* Take the pagecache_lock spinlock held to avoid
 		   other tasks to notice the page while we are looking at its
 		   page count. If it's a pagecache-page we'll free it
@@ -424,7 +465,11 @@
 		UnlockPage(page);
 		page_cache_release(page);
 dispose_continue:
+		/* page_lru was deleted from list. Reinsert it at _new_
+		 * lru_cache location
+		 */
 		list_add(page_lru, &lru_cache);
+		page_lru =  &lru_cache;
 	}
 	goto out;
 
usr/src/linux/mm/vmscan.c renamed from usr/src/linux/mm/vmscan.c.ac10 +57 -20

127 lines not on this page · raw message