[Experimental][PATCH] putback_lru_page rework

!MAILaRCHIVE_VOTE_RePLACE
Previous message: [thread] [date] [author]
Next message: [thread] [date] [author]
To: Daisuke Nishimura <nishimura@...>
Cc: Andrew Morton <akpm@...>, Rik van Riel <riel@...>, Lee Schermerhorn <lee.schermerhorn@...>, Kosaki Motohiro <kosaki.motohiro@...>, Nick Piggin <npiggin@...>, <linux-mm@...>, <linux-kernel@...>, <kernel-testers@...>
Date: Wednesday, June 18, 2008 - 5:40 am

Lee-san, how about this ?
Tested on x86-64 and tried Nisimura-san's test at el. works good now.
-Kame
==
putback_lru_page()/unevictable page handling rework.

Now, putback_lru_page() requires that the page is locked.
And in some special case, implicitly unlock it.

This patch tries to make putback_lru_pages() to be lock_page() free.
(Of course, some callers must take the lock.)

The main reason that putback_lru_page() assumes that page is locked
is to avoid the change in page's status among Mlocked/Not-Mlocked.

Once it is added to unevictable list, the page is removed from
unevictable list only when page is munlocked. (there are other special
case. but we ignore the special case.)
So, status change during putback_lru_page() is fatal and page should 
be locked.

putback_lru_page() in this patch has a new concepts.
When it adds page to unevictable list, it checks the status is 
changed or not again. if changed, retry to putback.

This patche changes also caller side and cleaning up lock/unlock_page().

Signed-off-by: KAMEZAWA Hiroyuki <kamezawa.hiroy@jp.fujitsu.com>

---
 mm/internal.h |    2 -
 mm/migrate.c  |   23 +++----------
 mm/mlock.c    |   24 +++++++-------
 mm/vmscan.c   |   96 +++++++++++++++++++++++++---------------------------------
 4 files changed, 61 insertions(+), 84 deletions(-)

Index: test-2.6.26-rc5-mm3/mm/vmscan.c
===================================================================
--- test-2.6.26-rc5-mm3.orig/mm/vmscan.c
+++ test-2.6.26-rc5-mm3/mm/vmscan.c
@@ -486,73 +486,63 @@ int remove_mapping(struct address_space 
  * Page may still be unevictable for other reasons.
  *
  * lru_lock must not be held, interrupts must be enabled.
- * Must be called with page locked.
- *
- * return 1 if page still locked [not truncated], else 0
  */
-int putback_lru_page(struct page *page)
+#ifdef CONFIG_UNEVICTABLE_LRU
+void putback_lru_page(struct page *page)
 {
 	int lru;
-	int ret = 1;
 	int was_unevictable;
 
-	VM_BUG_ON(!PageLocked(page));
 	VM_BUG_ON(PageLRU(page));
 
-	lru = !!TestClearPageActive(page);
 	was_unevictable = TestClearPageUnevictable(page); /* for page_evictable() */
 
-	if (unlikely(!page->mapping)) {
-		/*
-		 * page truncated.  drop lock as put_page() will
-		 * free the page.
-		 */
-		VM_BUG_ON(page_count(page) != 1);
-		unlock_page(page);
-		ret = 0;
-	} else if (page_evictable(page, NULL)) {
-		/*
-		 * For evictable pages, we can use the cache.
-		 * In event of a race, worst case is we end up with an
-		 * unevictable page on [in]active list.
-		 * We know how to handle that.
-		 */
+redo:
+	lru = !!TestClearPageActive(page);
+	if (page_evictable(page, NULL)) {
 		lru += page_is_file_cache(page);
 		lru_cache_add_lru(page, lru);
-		mem_cgroup_move_lists(page, lru);
-#ifdef CONFIG_UNEVICTABLE_LRU
-		if (was_unevictable)
-			count_vm_event(NORECL_PGRESCUED);
-#endif
 	} else {
-		/*
-		 * Put unevictable pages directly on zone's unevictable
-		 * list.
-		 */
+		lru = LRU_UNEVICTABLE;
 		add_page_to_unevictable_list(page);
-		mem_cgroup_move_lists(page, LRU_UNEVICTABLE);
-#ifdef CONFIG_UNEVICTABLE_LRU
-		if (!was_unevictable)
-			count_vm_event(NORECL_PGCULLED);
-#endif
 	}
+	mem_cgroup_move_lists(page, lru);
+
+	/*
+	 * page's status can change while we move it among lru. If an evictable
+	 * page is on unevictable list, it never be freed. To avoid that,
+	 * check after we added it to the list, again.
+	 */
+	if (lru == LRU_UNEVICTABLE && page_evictable(page, NULL)) {
+		if (!isolate_lru_page(page)) {
+			put_page(page);
+			goto redo;
+		}
+		/* This means someone else dropped this page from LRU
+		 * So, it will be freed or putback to LRU again. There is
+		 * nothing to do here.
+		 */
+	}
+
+	if (was_unevictable && lru != LRU_UNEVICTABLE)
+		count_vm_event(NORECL_PGRESCUED);
+	else if (!was_unevictable && lru == LRU_UNEVICTABLE)
+		count_vm_event(NORECL_PGCULLED);
 
 	put_page(page);		/* drop ref from isolate */
-	return ret;		/* ret => "page still locked" */
 }
-
-/*
- * Cull page that shrink_*_list() has detected to be unevictable
- * under page lock to close races with other tasks that might be making
- * the page evictable.  Avoid stranding an evictable page on the
- * unevictable list.
- */
-static void cull_unevictable_page(struct page *page)
+#else
+void putback_lru_page(struct page *page)
 {
-	lock_page(page);
-	if (putback_lru_page(page))
-		unlock_page(page);
+	int lru;
+	VM_BUG_ON(PageLRU(page));
+
+	lru = !!TestClearPageActive(page) + page_is_file_cache(page);
+	lru_cache_add_lru(page, lru);
+	mem_cgroup_move_lists(page, lru);
+	put_page(page);
 }
+#endif
 
 /*
  * shrink_page_list() returns the number of reclaimed pages
@@ -746,8 +736,8 @@ free_it:
 		continue;
 
 cull_mlocked:
-		if (putback_lru_page(page))
-			unlock_page(page);
+		unlock_page(page);
+		putback_lru_page(page);
 		continue;
 
 activate_locked:
@@ -1127,7 +1117,7 @@ static unsigned long shrink_inactive_lis
 			list_del(&page->lru);
 			if (unlikely(!page_evictable(page, NULL))) {
 				spin_unlock_irq(&zone->lru_lock);
-				cull_unevictable_page(page);
+				putback_lru_page(page);
 				spin_lock_irq(&zone->lru_lock);
 				continue;
 			}
@@ -1231,7 +1221,7 @@ static void shrink_active_list(unsigned 
 		list_del(&page->lru);
 
 		if (unlikely(!page_evictable(page, NULL))) {
-			cull_unevictable_page(page);
+			putback_lru_page(page);
 			continue;
 		}
 
@@ -2393,8 +2383,6 @@ int zone_reclaim(struct zone *zone, gfp_
 int page_evictable(struct page *page, struct vm_area_struct *vma)
 {
 
-	VM_BUG_ON(PageUnevictable(page));
-
 	if (mapping_unevictable(page_mapping(page)))
 		return 0;
 
Index: test-2.6.26-rc5-mm3/mm/mlock.c
===================================================================
--- test-2.6.26-rc5-mm3.orig/mm/mlock.c
+++ test-2.6.26-rc5-mm3/mm/mlock.c
@@ -55,7 +55,6 @@ EXPORT_SYMBOL(can_do_mlock);
  */
 void __clear_page_mlock(struct page *page)
 {
-	VM_BUG_ON(!PageLocked(page));	/* for LRU isolate/putback */
 
 	dec_zone_page_state(page, NR_MLOCK);
 	count_vm_event(NORECL_PGCLEARED);
@@ -79,7 +78,6 @@ void __clear_page_mlock(struct page *pag
  */
 void mlock_vma_page(struct page *page)
 {
-	BUG_ON(!PageLocked(page));
 
 	if (!TestSetPageMlocked(page)) {
 		inc_zone_page_state(page, NR_MLOCK);
@@ -109,7 +107,6 @@ void mlock_vma_page(struct page *page)
  */
 static void munlock_vma_page(struct page *page)
 {
-	BUG_ON(!PageLocked(page));
 
 	if (TestClearPageMlocked(page)) {
 		dec_zone_page_state(page, NR_MLOCK);
@@ -169,7 +166,8 @@ static int __mlock_vma_pages_range(struc
 
 		/*
 		 * get_user_pages makes pages present if we are
-		 * setting mlock.
+		 * setting mlock. and this extra reference count will
+		 * disable migration of this page.
 		 */
 		ret = get_user_pages(current, mm, addr,
 				min_t(int, nr_pages, ARRAY_SIZE(pages)),
@@ -197,14 +195,8 @@ static int __mlock_vma_pages_range(struc
 		for (i = 0; i < ret; i++) {
 			struct page *page = pages[i];
 
-			/*
-			 * page might be truncated or migrated out from under
-			 * us.  Check after acquiring page lock.
-			 */
-			lock_page(page);
-			if (page->mapping)
+			if (page_mapcount(page))
 				mlock_vma_page(page);
-			unlock_page(page);
 			put_page(page);		/* ref from get_user_pages() */
 
 			/*
@@ -240,6 +232,9 @@ static int __munlock_pte_handler(pte_t *
 	struct page *page;
 	pte_t pte;
 
+	/*
+	 * page is never be unmapped by page-reclaim. we lock this page now.
+	 */
 retry:
 	pte = *ptep;
 	/*
@@ -261,7 +256,15 @@ retry:
 		goto out;
 
 	lock_page(page);
-	if (!page->mapping) {
+	/*
+	 * Because we lock page here, we have to check 2 cases.
+	 * - the page is migrated.
+	 * - the page is truncated (file-cache only)
+	 * Note: Anonymous page doesn't clear page->mapping even if it
+	 * is removed from rmap.
+	 */
+	if (!page->mapping ||
+	     (PageAnon(page) && !page_mapcount(page))) {
 		unlock_page(page);
 		goto retry;
 	}
Index: test-2.6.26-rc5-mm3/mm/migrate.c
===================================================================
--- test-2.6.26-rc5-mm3.orig/mm/migrate.c
+++ test-2.6.26-rc5-mm3/mm/migrate.c
@@ -67,9 +67,7 @@ int putback_lru_pages(struct list_head *
 
 	list_for_each_entry_safe(page, page2, l, lru) {
 		list_del(&page->lru);
-		lock_page(page);
-		if (putback_lru_page(page))
-			unlock_page(page);
+		putback_lru_page(page);
 		count++;
 	}
 	return count;
@@ -571,7 +569,6 @@ static int fallback_migrate_page(struct 
 static int move_to_new_page(struct page *newpage, struct page *page)
 {
 	struct address_space *mapping;
-	int unlock = 1;
 	int rc;
 
 	/*
@@ -610,12 +607,11 @@ static int move_to_new_page(struct page 
 		 * Put back on LRU while holding page locked to
 		 * handle potential race with, e.g., munlock()
 		 */
-		unlock = putback_lru_page(newpage);
+		putback_lru_page(newpage);
 	} else
 		newpage->mapping = NULL;
 
-	if (unlock)
-		unlock_page(newpage);
+	unlock_page(newpage);
 
 	return rc;
 }
@@ -632,7 +628,6 @@ static int unmap_and_move(new_page_t get
 	struct page *newpage = get_new_page(page, private, &result);
 	int rcu_locked = 0;
 	int charge = 0;
-	int unlock = 1;
 
 	if (!newpage)
 		return -ENOMEM;
@@ -713,6 +708,7 @@ rcu_unlock:
 		rcu_read_unlock();
 
 unlock:
+	unlock_page(page);
 
 	if (rc != -EAGAIN) {
  		/*
@@ -722,18 +718,9 @@ unlock:
  		 * restored.
  		 */
  		list_del(&page->lru);
-		if (!page->mapping) {
-			VM_BUG_ON(page_count(page) != 1);
-			unlock_page(page);
-			put_page(page);		/* just free the old page */
-			goto end_migration;
-		} else
-			unlock = putback_lru_page(page);
+		putback_lru_page(page);
 	}
 
-	if (unlock)
-		unlock_page(page);
-
 end_migration:
 	if (!charge)
 		mem_cgroup_end_migration(newpage);
Index: test-2.6.26-rc5-mm3/mm/internal.h
===================================================================
--- test-2.6.26-rc5-mm3.orig/mm/internal.h
+++ test-2.6.26-rc5-mm3/mm/internal.h
@@ -43,7 +43,7 @@ static inline void __put_page(struct pag
  * in mm/vmscan.c:
  */
 extern int isolate_lru_page(struct page *page);
-extern int putback_lru_page(struct page *page);
+extern void putback_lru_page(struct page *page);
 
 /*
  * in mm/page_alloc.c

--
Previous message: [thread] [date] [author]
Next message: [thread] [date] [author]

Messages in current thread:
2.6.26-rc5-mm3, Andrew Morton, (Thu Jun 12, 1:59 am)
Re: 2.6.26-rc5-mm3: BUG large value for HugePages_Rsvd, Jon Tollefson, (Thu Jun 19, 12:27 pm)
Re: 2.6.26-rc5-mm3: BUG large value for HugePages_Rsvd, Andy Whitcroft, (Thu Jun 19, 1:16 pm)
Re: 2.6.26-rc5-mm3: BUG large value for HugePages_Rsvd, Jon Tollefson, (Thu Jun 19, 11:18 pm)
[BUG][PATCH -mm] avoid BUG() in __stop_machine_run(), Hidehiro Kawai, (Thu Jun 19, 2:59 am)
Re: [BUG][PATCH -mm] avoid BUG() in __stop_machine_run(), Rusty Russell, (Thu Jun 19, 6:12 am)
Re: [BUG][PATCH -mm] avoid BUG() in __stop_machine_run(), Jeremy Fitzhardinge, (Thu Jun 19, 11:51 am)
Re: [BUG][PATCH -mm] avoid BUG() in __stop_machine_run(), Rusty Russell, (Sun Jun 22, 11:55 pm)
[PATCH][RFC] fix kernel BUG at mm/migrate.c:719! in 2.6.26-r..., Daisuke Nishimura, (Tue Jun 17, 3:35 am)
Re: [PATCH][RFC] fix kernel BUG at mm/migrate.c:719! in 2.6...., KAMEZAWA Hiroyuki, (Tue Jun 17, 9:13 pm)
[PATCH] migration_entry_wait fix., KAMEZAWA Hiroyuki, (Tue Jun 17, 9:54 pm)
Re: [PATCH] migration_entry_wait fix., Nick Piggin, (Wed Jun 18, 1:35 am)
Re: [PATCH] migration_entry_wait fix., KAMEZAWA Hiroyuki, (Wed Jun 18, 2:04 am)
Re: [PATCH] migration_entry_wait fix., Nick Piggin, (Wed Jun 18, 2:42 am)
Re: [PATCH] migration_entry_wait fix., KAMEZAWA Hiroyuki, (Wed Jun 18, 2:52 am)
[PATCH -mm][BUGFIX] migration_entry_wait fix. v2, KAMEZAWA Hiroyuki, (Wed Jun 18, 3:29 am)
Re: [PATCH -mm][BUGFIX] migration_entry_wait fix. v2, Nick Piggin, (Wed Jun 18, 3:40 am)
Re: [PATCH -mm][BUGFIX] migration_entry_wait fix. v2, KOSAKI Motohiro, (Wed Jun 18, 3:26 am)
Re: [PATCH] migration_entry_wait fix., KOSAKI Motohiro, (Wed Jun 18, 1:26 am)
Re: [PATCH][RFC] fix kernel BUG at mm/migrate.c:719! in 2.6...., Daisuke Nishimura, (Tue Jun 17, 9:26 pm)
Re: [PATCH][RFC] fix kernel BUG at mm/migrate.c:719! in 2.6...., Daisuke Nishimura, (Tue Jun 17, 10:59 pm)
Re: [PATCH][RFC] fix kernel BUG at mm/migrate.c:719! in 2.6...., Daisuke Nishimura, (Tue Jun 17, 9:54 pm)
Re: [PATCH][RFC] fix kernel BUG at mm/migrate.c:719! in 2.6...., Daisuke Nishimura, (Wed Jun 18, 12:41 am)
[PATCH][-mm] remove redundant page-&gt;mapping check, KOSAKI Motohiro, (Wed Jun 18, 3:54 am)
Re: [PATCH][RFC] fix kernel BUG at mm/migrate.c:719! in 2.6...., KAMEZAWA Hiroyuki, (Wed Jun 18, 12:59 am)
[Bad page] trying to free locked page? (Re: [PATCH][RFC] fix..., Daisuke Nishimura, (Tue Jun 17, 3:47 am)
[Experimental][PATCH] putback_lru_page rework, KAMEZAWA Hiroyuki, (Wed Jun 18, 5:40 am)
Re: [Experimental][PATCH] putback_lru_page rework, Lee Schermerhorn, (Wed Jun 18, 2:21 pm)
Re: [Experimental][PATCH] putback_lru_page rework, KAMEZAWA Hiroyuki, (Wed Jun 18, 8:22 pm)
Re: [Experimental][PATCH] putback_lru_page rework, Lee Schermerhorn, (Thu Jun 19, 10:45 am)
Re: [Experimental][PATCH] putback_lru_page rework, KAMEZAWA Hiroyuki, (Thu Jun 19, 9:13 pm)
Re: [Experimental][PATCH] putback_lru_page rework, KOSAKI Motohiro, (Sat Jun 21, 4:39 am)
Re: [Experimental][PATCH] putback_lru_page rework, Lee Schermerhorn, (Fri Jun 20, 1:10 pm)
Re: [Experimental][PATCH] putback_lru_page rework, KOSAKI Motohiro, (Sat Jun 21, 4:41 am)
Re: [Experimental][PATCH] putback_lru_page rework, Lee Schermerhorn, (Fri Jun 20, 4:41 pm)
Re: [Experimental][PATCH] putback_lru_page rework, KOSAKI Motohiro, (Sat Jun 21, 4:56 am)
Re: [Experimental][PATCH] putback_lru_page rework, KAMEZAWA Hiroyuki, (Sun Jun 22, 8:30 pm)
Re: [Experimental][PATCH] putback_lru_page rework, KAMEZAWA Hiroyuki, (Thu Jun 19, 8:47 pm)
Re: Re: [Experimental][PATCH] putback_lru_page rework, Lee Schermerhorn, (Fri Jun 20, 12:24 pm)
Re: [Experimental][PATCH] putback_lru_page rework, Daisuke Nishimura, (Wed Jun 18, 10:50 am)
Re: [Experimental][PATCH] putback_lru_page rework, KOSAKI Motohiro, (Wed Jun 18, 7:36 am)
Re: [Experimental][PATCH] putback_lru_page rework, KAMEZAWA Hiroyuki, (Wed Jun 18, 7:55 am)
Re: [Experimental][PATCH] putback_lru_page rework, Daisuke Nishimura, (Thu Jun 19, 4:00 am)
Re: [Experimental][PATCH] putback_lru_page rework, KAMEZAWA Hiroyuki, (Thu Jun 19, 4:24 am)
Re: [Bad page] trying to free locked page? (Re: [PATCH][RFC]..., Daisuke Nishimura, (Tue Jun 17, 10:32 pm)
Re: [Bad page] trying to free locked page? (Re: [PATCH][RFC]..., KAMEZAWA Hiroyuki, (Tue Jun 17, 5:03 am)
Re: [Bad page] trying to free locked page? (Re: [PATCH][RFC]..., Daisuke Nishimura, (Tue Jun 17, 5:15 am)
Re: [Bad page] trying to free locked page? (Re: [PATCH][RFC]..., Daisuke Nishimura, (Tue Jun 17, 10:40 pm)
Re: 2.6.26-rc5-mm3, Byron Bradley, (Thu Jun 12, 7:32 pm)
Re: 2.6.26-rc5-mm3, Daniel Walker, (Wed Jun 18, 1:55 pm)
Re: 2.6.26-rc5-mm3, Ingo Molnar, (Thu Jun 19, 5:13 am)
Re: 2.6.26-rc5-mm3, Daniel Walker, (Thu Jun 19, 10:39 am)
Re: 2.6.26-rc5-mm3, Daniel Walker, (Thu Jun 12, 7:55 pm)
Re: 2.6.26-rc5-mm3, Byron Bradley, (Thu Jun 12, 8:04 pm)
[BUG] 2.6.26-rc5-mm3 kernel BUG at mm/filemap.c:575!, Kamalesh Babulal, (Thu Jun 12, 4:44 am)
Re: [BUG] 2.6.26-rc5-mm3 kernel BUG at mm/filemap.c:575!, Andrew Morton, (Fri Jun 13, 3:16 am)
Re: [BUG] 2.6.26-rc5-mm3 kernel BUG at mm/filemap.c:575!, Andrew Morton, (Thu Jun 12, 4:57 am)
Re: [BUG] 2.6.26-rc5-mm3 kernel BUG at mm/filemap.c:575!, KAMEZAWA Hiroyuki, (Thu Jun 12, 8:25 pm)
Re: [BUG] 2.6.26-rc5-mm3 kernel BUG at mm/filemap.c:575!, KAMEZAWA Hiroyuki, (Thu Jun 12, 7:20 am)
[PATCH] fix double unlock_page() in 2.6.26-rc5-mm3 kernel BU..., KAMEZAWA Hiroyuki, (Thu Jun 12, 9:44 pm)
Re: [PATCH] fix double unlock_page() in 2.6.26-rc5-mm3 kerne..., Lee Schermerhorn, (Fri Jun 13, 11:30 am)
Re: [PATCH] fix double unlock_page() in 2.6.26-rc5-mm3 kerne..., KAMEZAWA Hiroyuki, (Mon Jun 16, 10:32 pm)
Re: [PATCH] fix double unlock_page() in 2.6.26-rc5-mm3 kerne..., Lee Schermerhorn, (Tue Jun 17, 11:26 am)
Re: [PATCH] fix double unlock_page() in 2.6.26-rc5-mm3 kerne..., Lee Schermerhorn, (Mon Jun 16, 10:49 am)
Re: [PATCH] fix double unlock_page() in 2.6.26-rc5-mm3 kerne..., Kamalesh Babulal, (Sat Jun 14, 11:59 pm)
2.6.26-rc5-mm3: kernel BUG at mm/vmscan.c:510, Alexey Dobriyan, (Thu Jun 12, 3:58 am)
Re: 2.6.26-rc5-mm3: kernel BUG at mm/vmscan.c:510, Andrew Morton, (Thu Jun 12, 4:22 am)
Re: 2.6.26-rc5-mm3: kernel BUG at mm/vmscan.c:510, Alexey Dobriyan, (Thu Jun 12, 4:23 am)