linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [patch 0/6] mm: optimisations and page ref simplifications
@ 2006-01-19 19:22 Nick Piggin
  2006-01-19 19:22 ` [patch 1/6] mm: never ClearPageLRU released pages Nick Piggin
                   ` (5 more replies)
  0 siblings, 6 replies; 9+ messages in thread
From: Nick Piggin @ 2006-01-19 19:22 UTC (permalink / raw)
  To: Linus Torvalds, Andrew Morton
  Cc: Nick Piggin, Linux Memory Management, Linux Kernel Mailing List

In the following patchset (against 2.6.16-rc1-git2), patches 1-4 reduce
the number of locks and atomic operations required in some critical page
manipulation paths.

Patches 5 and 6 help simplify some tricky race avoidance code at the
cost of possibly a very minor performance hit in page reclaim on some
architectures. If they need any more justification they will be needed
for lockless pagecache.

Do these look OK?

Thanks,
Nick


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [patch 1/6] mm: never ClearPageLRU released pages
  2006-01-19 19:22 [patch 0/6] mm: optimisations and page ref simplifications Nick Piggin
@ 2006-01-19 19:22 ` Nick Piggin
  2006-01-19 19:23 ` [patch 2/6] mm: PageLRU no testset Nick Piggin
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 9+ messages in thread
From: Nick Piggin @ 2006-01-19 19:22 UTC (permalink / raw)
  To: Linus Torvalds, Andrew Morton
  Cc: Nick Piggin, Linux Memory Management, Linux Kernel Mailing List

If vmscan finds a zero refcount page on the lru list, never ClearPageLRU it.
This means the release code need not hold ->lru_lock to stabalise PageLRU,
so that lock may be skipped entirely when releasing !PageLRU pages (because
we know PageLRU won't have been temporarily cleared by vmscan, which
was previously guaranteed by holding the lock to synchroise against vmscan).

Signed-off-by: Nick Piggin <npiggin@suse.de>

Index: linux-2.6/mm/vmscan.c
===================================================================
--- linux-2.6.orig/mm/vmscan.c
+++ linux-2.6/mm/vmscan.c
@@ -823,21 +823,25 @@ static int isolate_lru_pages(int nr_to_s
 		page = lru_to_page(src);
 		prefetchw_prev_lru_page(page, src, flags);
 
-		if (!TestClearPageLRU(page))
-			BUG();
 		list_del(&page->lru);
-		if (get_page_testone(page)) {
+		if (unlikely(get_page_testone(page))) {
 			/*
 			 * It is being freed elsewhere
 			 */
 			__put_page(page);
-			SetPageLRU(page);
 			list_add(&page->lru, src);
 			continue;
-		} else {
-			list_add(&page->lru, dst);
-			nr_taken++;
 		}
+
+		/*
+		 * Be careful not to clear PageLRU until after we're sure
+		 * the page is not being freed elsewhere -- the page release
+		 * code relies on it.
+		 */
+		if (!TestClearPageLRU(page))
+			BUG();
+		list_add(&page->lru, dst);
+		nr_taken++;
 	}
 
 	*scanned = scan;
Index: linux-2.6/mm/swap.c
===================================================================
--- linux-2.6.orig/mm/swap.c
+++ linux-2.6/mm/swap.c
@@ -206,17 +206,18 @@ int lru_add_drain_all(void)
  */
 void fastcall __page_cache_release(struct page *page)
 {
-	unsigned long flags;
-	struct zone *zone = page_zone(page);
+	if (PageLRU(page)) {
+		unsigned long flags;
 
-	spin_lock_irqsave(&zone->lru_lock, flags);
-	if (TestClearPageLRU(page))
+		struct zone *zone = page_zone(page);
+		spin_lock_irqsave(&zone->lru_lock, flags);
+		if (!TestClearPageLRU(page))
+			BUG();
 		del_page_from_lru(zone, page);
-	if (page_count(page) != 0)
-		page = NULL;
-	spin_unlock_irqrestore(&zone->lru_lock, flags);
-	if (page)
-		free_hot_page(page);
+		spin_unlock_irqrestore(&zone->lru_lock, flags);
+	}
+
+	free_hot_page(page);
 }
 
 EXPORT_SYMBOL(__page_cache_release);
@@ -242,27 +243,30 @@ void release_pages(struct page **pages, 
 	pagevec_init(&pages_to_free, cold);
 	for (i = 0; i < nr; i++) {
 		struct page *page = pages[i];
-		struct zone *pagezone;
 
 		if (!put_page_testzero(page))
 			continue;
 
-		pagezone = page_zone(page);
-		if (pagezone != zone) {
-			if (zone)
-				spin_unlock_irq(&zone->lru_lock);
-			zone = pagezone;
-			spin_lock_irq(&zone->lru_lock);
-		}
-		if (TestClearPageLRU(page))
+		if (PageLRU(page)) {
+			struct zone *pagezone = page_zone(page);
+			if (pagezone != zone) {
+				if (zone)
+					spin_unlock_irq(&zone->lru_lock);
+				zone = pagezone;
+				spin_lock_irq(&zone->lru_lock);
+			}
+			if (!TestClearPageLRU(page))
+				BUG();
 			del_page_from_lru(zone, page);
-		if (page_count(page) == 0) {
-			if (!pagevec_add(&pages_to_free, page)) {
+		}
+
+		if (!pagevec_add(&pages_to_free, page)) {
+			if (zone) {
 				spin_unlock_irq(&zone->lru_lock);
-				__pagevec_free(&pages_to_free);
-				pagevec_reinit(&pages_to_free);
-				zone = NULL;	/* No lock is held */
+				zone = NULL;
 			}
+			__pagevec_free(&pages_to_free);
+			pagevec_reinit(&pages_to_free);
 		}
 	}
 	if (zone)

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [patch 2/6] mm: PageLRU no testset
  2006-01-19 19:22 [patch 0/6] mm: optimisations and page ref simplifications Nick Piggin
  2006-01-19 19:22 ` [patch 1/6] mm: never ClearPageLRU released pages Nick Piggin
@ 2006-01-19 19:23 ` Nick Piggin
  2006-01-19 19:23 ` [patch 3/6] mm: PageActive " Nick Piggin
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 9+ messages in thread
From: Nick Piggin @ 2006-01-19 19:23 UTC (permalink / raw)
  To: Linus Torvalds, Andrew Morton
  Cc: Nick Piggin, Linux Memory Management, Linux Kernel Mailing List

PG_lru is protected by zone->lru_lock. It does not need TestSet/TestClear
operations.

Signed-off-by: Nick Piggin <npiggin@suse.de>

Index: linux-2.6/mm/vmscan.c
===================================================================
--- linux-2.6.orig/mm/vmscan.c
+++ linux-2.6/mm/vmscan.c
@@ -780,9 +780,10 @@ int isolate_lru_page(struct page *page)
 	if (PageLRU(page)) {
 		struct zone *zone = page_zone(page);
 		spin_lock_irq(&zone->lru_lock);
-		if (TestClearPageLRU(page)) {
+		if (PageLRU(page)) {
 			ret = 1;
 			get_page(page);
+			ClearPageLRU(page);
 			if (PageActive(page))
 				del_page_from_active_list(zone, page);
 			else
@@ -823,6 +824,8 @@ static int isolate_lru_pages(int nr_to_s
 		page = lru_to_page(src);
 		prefetchw_prev_lru_page(page, src, flags);
 
+		BUG_ON(!PageLRU(page));
+
 		list_del(&page->lru);
 		if (unlikely(get_page_testone(page))) {
 			/*
@@ -838,8 +841,7 @@ static int isolate_lru_pages(int nr_to_s
 		 * the page is not being freed elsewhere -- the page release
 		 * code relies on it.
 		 */
-		if (!TestClearPageLRU(page))
-			BUG();
+		ClearPageLRU(page);
 		list_add(&page->lru, dst);
 		nr_taken++;
 	}
@@ -894,8 +896,8 @@ static void shrink_cache(struct zone *zo
 		 */
 		while (!list_empty(&page_list)) {
 			page = lru_to_page(&page_list);
-			if (TestSetPageLRU(page))
-				BUG();
+			BUG_ON(PageLRU(page));
+			SetPageLRU(page);
 			list_del(&page->lru);
 			if (PageActive(page))
 				add_page_to_active_list(zone, page);
@@ -1007,8 +1009,8 @@ refill_inactive_zone(struct zone *zone, 
 	while (!list_empty(&l_inactive)) {
 		page = lru_to_page(&l_inactive);
 		prefetchw_prev_lru_page(page, &l_inactive, flags);
-		if (TestSetPageLRU(page))
-			BUG();
+		BUG_ON(PageLRU(page));
+		SetPageLRU(page);
 		if (!TestClearPageActive(page))
 			BUG();
 		list_move(&page->lru, &zone->inactive_list);
@@ -1036,8 +1038,8 @@ refill_inactive_zone(struct zone *zone, 
 	while (!list_empty(&l_active)) {
 		page = lru_to_page(&l_active);
 		prefetchw_prev_lru_page(page, &l_active, flags);
-		if (TestSetPageLRU(page))
-			BUG();
+		BUG_ON(PageLRU(page));
+		SetPageLRU(page);
 		BUG_ON(!PageActive(page));
 		list_move(&page->lru, &zone->active_list);
 		pgmoved++;
Index: linux-2.6/mm/swap.c
===================================================================
--- linux-2.6.orig/mm/swap.c
+++ linux-2.6/mm/swap.c
@@ -211,8 +211,8 @@ void fastcall __page_cache_release(struc
 
 		struct zone *zone = page_zone(page);
 		spin_lock_irqsave(&zone->lru_lock, flags);
-		if (!TestClearPageLRU(page))
-			BUG();
+		BUG_ON(!PageLRU(page));
+		ClearPageLRU(page);
 		del_page_from_lru(zone, page);
 		spin_unlock_irqrestore(&zone->lru_lock, flags);
 	}
@@ -255,8 +255,8 @@ void release_pages(struct page **pages, 
 				zone = pagezone;
 				spin_lock_irq(&zone->lru_lock);
 			}
-			if (!TestClearPageLRU(page))
-				BUG();
+			BUG_ON(!PageLRU(page));
+			ClearPageLRU(page);
 			del_page_from_lru(zone, page);
 		}
 
@@ -335,8 +335,8 @@ void __pagevec_lru_add(struct pagevec *p
 			zone = pagezone;
 			spin_lock_irq(&zone->lru_lock);
 		}
-		if (TestSetPageLRU(page))
-			BUG();
+		BUG_ON(PageLRU(page));
+		SetPageLRU(page);
 		add_page_to_inactive_list(zone, page);
 	}
 	if (zone)
@@ -362,8 +362,8 @@ void __pagevec_lru_add_active(struct pag
 			zone = pagezone;
 			spin_lock_irq(&zone->lru_lock);
 		}
-		if (TestSetPageLRU(page))
-			BUG();
+		BUG_ON(PageLRU(page));
+		SetPageLRU(page);
 		if (TestSetPageActive(page))
 			BUG();
 		add_page_to_active_list(zone, page);
Index: linux-2.6/include/linux/page-flags.h
===================================================================
--- linux-2.6.orig/include/linux/page-flags.h
+++ linux-2.6/include/linux/page-flags.h
@@ -244,10 +244,9 @@ extern void __mod_page_state_offset(unsi
 #define __ClearPageDirty(page)	__clear_bit(PG_dirty, &(page)->flags)
 #define TestClearPageDirty(page) test_and_clear_bit(PG_dirty, &(page)->flags)
 
-#define SetPageLRU(page)	set_bit(PG_lru, &(page)->flags)
 #define PageLRU(page)		test_bit(PG_lru, &(page)->flags)
-#define TestSetPageLRU(page)	test_and_set_bit(PG_lru, &(page)->flags)
-#define TestClearPageLRU(page)	test_and_clear_bit(PG_lru, &(page)->flags)
+#define SetPageLRU(page)	set_bit(PG_lru, &(page)->flags)
+#define ClearPageLRU(page)	clear_bit(PG_lru, &(page)->flags)
 
 #define PageActive(page)	test_bit(PG_active, &(page)->flags)
 #define SetPageActive(page)	set_bit(PG_active, &(page)->flags)

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [patch 3/6] mm: PageActive no testset
  2006-01-19 19:22 [patch 0/6] mm: optimisations and page ref simplifications Nick Piggin
  2006-01-19 19:22 ` [patch 1/6] mm: never ClearPageLRU released pages Nick Piggin
  2006-01-19 19:23 ` [patch 2/6] mm: PageLRU no testset Nick Piggin
@ 2006-01-19 19:23 ` Nick Piggin
  2006-01-19 19:23 ` [patch 4/6] mm: less atomic ops Nick Piggin
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 9+ messages in thread
From: Nick Piggin @ 2006-01-19 19:23 UTC (permalink / raw)
  To: Linus Torvalds, Andrew Morton
  Cc: Nick Piggin, Linux Memory Management, Linux Kernel Mailing List

PG_active is protected by zone->lru_lock, it does not need TestSet/TestClear
operations.

Signed-off-by: Nick Piggin <npiggin@suse.de>

Index: linux-2.6/mm/vmscan.c
===================================================================
--- linux-2.6.orig/mm/vmscan.c
+++ linux-2.6/mm/vmscan.c
@@ -1011,8 +1011,9 @@ refill_inactive_zone(struct zone *zone, 
 		prefetchw_prev_lru_page(page, &l_inactive, flags);
 		BUG_ON(PageLRU(page));
 		SetPageLRU(page);
-		if (!TestClearPageActive(page))
-			BUG();
+		BUG_ON(!PageActive(page));
+		ClearPageActive(page);
+
 		list_move(&page->lru, &zone->inactive_list);
 		pgmoved++;
 		if (!pagevec_add(&pvec, page)) {
Index: linux-2.6/mm/swap.c
===================================================================
--- linux-2.6.orig/mm/swap.c
+++ linux-2.6/mm/swap.c
@@ -364,8 +364,8 @@ void __pagevec_lru_add_active(struct pag
 		}
 		BUG_ON(PageLRU(page));
 		SetPageLRU(page);
-		if (TestSetPageActive(page))
-			BUG();
+		BUG_ON(PageActive(page));
+		SetPageActive(page);
 		add_page_to_active_list(zone, page);
 	}
 	if (zone)
Index: linux-2.6/include/linux/page-flags.h
===================================================================
--- linux-2.6.orig/include/linux/page-flags.h
+++ linux-2.6/include/linux/page-flags.h
@@ -251,8 +251,6 @@ extern void __mod_page_state_offset(unsi
 #define PageActive(page)	test_bit(PG_active, &(page)->flags)
 #define SetPageActive(page)	set_bit(PG_active, &(page)->flags)
 #define ClearPageActive(page)	clear_bit(PG_active, &(page)->flags)
-#define TestClearPageActive(page) test_and_clear_bit(PG_active, &(page)->flags)
-#define TestSetPageActive(page) test_and_set_bit(PG_active, &(page)->flags)
 
 #define PageSlab(page)		test_bit(PG_slab, &(page)->flags)
 #define SetPageSlab(page)	set_bit(PG_slab, &(page)->flags)

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [patch 4/6] mm: less atomic ops
  2006-01-19 19:22 [patch 0/6] mm: optimisations and page ref simplifications Nick Piggin
                   ` (2 preceding siblings ...)
  2006-01-19 19:23 ` [patch 3/6] mm: PageActive " Nick Piggin
@ 2006-01-19 19:23 ` Nick Piggin
  2006-01-19 19:23 ` [patch 5/6] mm: simplify vmscan vs release refcounting Nick Piggin
  2006-01-19 19:23 ` [patch 6/6] mm: de-skew page refcounting Nick Piggin
  5 siblings, 0 replies; 9+ messages in thread
From: Nick Piggin @ 2006-01-19 19:23 UTC (permalink / raw)
  To: Linus Torvalds, Andrew Morton
  Cc: Nick Piggin, Linux Memory Management, Linux Kernel Mailing List

In the page release paths, we can be sure that nobody will mess with our
page->flags because the refcount has dropped to 0. So no need for atomic
operations here.

Signed-off-by: Nick Piggin <npiggin@suse.de>

Index: linux-2.6/include/linux/page-flags.h
===================================================================
--- linux-2.6.orig/include/linux/page-flags.h
+++ linux-2.6/include/linux/page-flags.h
@@ -247,10 +247,12 @@ extern void __mod_page_state_offset(unsi
 #define PageLRU(page)		test_bit(PG_lru, &(page)->flags)
 #define SetPageLRU(page)	set_bit(PG_lru, &(page)->flags)
 #define ClearPageLRU(page)	clear_bit(PG_lru, &(page)->flags)
+#define __ClearPageLRU(page)	__clear_bit(PG_lru, &(page)->flags)
 
 #define PageActive(page)	test_bit(PG_active, &(page)->flags)
 #define SetPageActive(page)	set_bit(PG_active, &(page)->flags)
 #define ClearPageActive(page)	clear_bit(PG_active, &(page)->flags)
+#define __ClearPageActive(page)	__clear_bit(PG_active, &(page)->flags)
 
 #define PageSlab(page)		test_bit(PG_slab, &(page)->flags)
 #define SetPageSlab(page)	set_bit(PG_slab, &(page)->flags)
Index: linux-2.6/mm/swap.c
===================================================================
--- linux-2.6.orig/mm/swap.c
+++ linux-2.6/mm/swap.c
@@ -212,7 +212,7 @@ void fastcall __page_cache_release(struc
 		struct zone *zone = page_zone(page);
 		spin_lock_irqsave(&zone->lru_lock, flags);
 		BUG_ON(!PageLRU(page));
-		ClearPageLRU(page);
+		__ClearPageLRU(page);
 		del_page_from_lru(zone, page);
 		spin_unlock_irqrestore(&zone->lru_lock, flags);
 	}
@@ -256,7 +256,7 @@ void release_pages(struct page **pages, 
 				spin_lock_irq(&zone->lru_lock);
 			}
 			BUG_ON(!PageLRU(page));
-			ClearPageLRU(page);
+			__ClearPageLRU(page);
 			del_page_from_lru(zone, page);
 		}
 
Index: linux-2.6/include/linux/mm_inline.h
===================================================================
--- linux-2.6.orig/include/linux/mm_inline.h
+++ linux-2.6/include/linux/mm_inline.h
@@ -32,7 +32,7 @@ del_page_from_lru(struct zone *zone, str
 {
 	list_del(&page->lru);
 	if (PageActive(page)) {
-		ClearPageActive(page);
+		__ClearPageActive(page);
 		zone->nr_active--;
 	} else {
 		zone->nr_inactive--;

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [patch 5/6] mm: simplify vmscan vs release refcounting
  2006-01-19 19:22 [patch 0/6] mm: optimisations and page ref simplifications Nick Piggin
                   ` (3 preceding siblings ...)
  2006-01-19 19:23 ` [patch 4/6] mm: less atomic ops Nick Piggin
@ 2006-01-19 19:23 ` Nick Piggin
  2006-01-19 19:35   ` Linus Torvalds
  2006-01-19 19:23 ` [patch 6/6] mm: de-skew page refcounting Nick Piggin
  5 siblings, 1 reply; 9+ messages in thread
From: Nick Piggin @ 2006-01-19 19:23 UTC (permalink / raw)
  To: Linus Torvalds, Andrew Morton
  Cc: Nick Piggin, Linux Memory Management, Linux Kernel Mailing List

The VM has an interesting race where a page refcount can drop to zero, but
it is still on the LRU lists for a short time. This was solved by testing
a 0->1 refcount transition when picking up pages from the LRU, and dropping
the refcount in that case.

Instead, use atomic_inc_not_zero to ensure we never pick up a 0 refcount
page from the LRU, thus a 0 refcount page will never have its refcount elevated
until it is allocated again. This simplifies the handling of the race
because vmscan now *never* touches the refcount of a released page.

Signed-off-by: Nick Piggin <npiggin@suse.de>

Index: linux-2.6/include/linux/mm.h
===================================================================
--- linux-2.6.orig/include/linux/mm.h
+++ linux-2.6/include/linux/mm.h
@@ -286,32 +286,26 @@ struct page {
  *
  * Also, many kernel routines increase the page count before a critical
  * routine so they can be sure the page doesn't go away from under them.
- *
- * Since 2.6.6 (approx), a free page has ->_count = -1.  This is so that we
- * can use atomic_add_negative(-1, page->_count) to detect when the page
- * becomes free and so that we can also use atomic_inc_and_test to atomically
- * detect when we just tried to grab a ref on a page which some other CPU has
- * already deemed to be freeable.
- *
- * NO code should make assumptions about this internal detail!  Use the provided
- * macros which retain the old rules: page_count(page) == 0 is a free page.
  */
 
 /*
  * Drop a ref, return true if the logical refcount fell to zero (the page has
  * no users)
  */
-#define put_page_testzero(p)				\
-	({						\
-		BUG_ON(page_count(p) == 0);		\
-		atomic_add_negative(-1, &(p)->_count);	\
-	})
+static inline int put_page_testzero(struct page *page)
+{
+	BUG_ON(atomic_read(&page->_count) == -1);
+	return atomic_dec_and_test(&page->_count);
+}
 
 /*
- * Grab a ref, return true if the page previously had a logical refcount of
- * zero.  ie: returns true if we just grabbed an already-deemed-to-be-free page
+ * Try to grab a ref unless the page has a refcount of zero, return false if
+ * that is the case.
  */
-#define get_page_testone(p)	atomic_inc_and_test(&(p)->_count)
+static inline int get_page_unless_zero(struct page *page)
+{
+	return atomic_add_unless(&page->_count, 1, -1);
+}
 
 #define set_page_count(p,v) 	atomic_set(&(p)->_count, (v) - 1)
 #define __put_page(p)		atomic_dec(&(p)->_count)
Index: linux-2.6/mm/vmscan.c
===================================================================
--- linux-2.6.orig/mm/vmscan.c
+++ linux-2.6/mm/vmscan.c
@@ -821,29 +821,26 @@ static int isolate_lru_pages(int nr_to_s
 	int scan = 0;
 
 	while (scan++ < nr_to_scan && !list_empty(src)) {
+		struct list_head *target;
 		page = lru_to_page(src);
 		prefetchw_prev_lru_page(page, src, flags);
 
 		BUG_ON(!PageLRU(page));
 
 		list_del(&page->lru);
-		if (unlikely(get_page_testone(page))) {
+		target = src;
+		if (likely(get_page_unless_zero(page))) {
 			/*
-			 * It is being freed elsewhere
+			 * Be careful not to clear PageLRU until after we're
+			 * sure the page is not being freed elsewhere -- the
+			 * page release code relies on it.
 			 */
-			__put_page(page);
-			list_add(&page->lru, src);
-			continue;
-		}
+			ClearPageLRU(page);
+			target = dst;
+			nr_taken++;
+		} /* else it is being freed elsewhere */
 
-		/*
-		 * Be careful not to clear PageLRU until after we're sure
-		 * the page is not being freed elsewhere -- the page release
-		 * code relies on it.
-		 */
-		ClearPageLRU(page);
-		list_add(&page->lru, dst);
-		nr_taken++;
+		list_add(&page->lru, target);
 	}
 
 	*scanned = scan;

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [patch 6/6] mm: de-skew page refcounting
  2006-01-19 19:22 [patch 0/6] mm: optimisations and page ref simplifications Nick Piggin
                   ` (4 preceding siblings ...)
  2006-01-19 19:23 ` [patch 5/6] mm: simplify vmscan vs release refcounting Nick Piggin
@ 2006-01-19 19:23 ` Nick Piggin
  5 siblings, 0 replies; 9+ messages in thread
From: Nick Piggin @ 2006-01-19 19:23 UTC (permalink / raw)
  To: Linus Torvalds, Andrew Morton
  Cc: Nick Piggin, Linux Memory Management, Linux Kernel Mailing List

atomic_add_unless (atomic_inc_not_zero) no longer requires an offset
refcount to function correctly.

Signed-off-by: Nick Piggin <npiggin@suse.de>

Index: linux-2.6/include/linux/mm.h
===================================================================
--- linux-2.6.orig/include/linux/mm.h
+++ linux-2.6/include/linux/mm.h
@@ -294,7 +294,7 @@ struct page {
  */
 static inline int put_page_testzero(struct page *page)
 {
-	BUG_ON(atomic_read(&page->_count) == -1);
+	BUG_ON(atomic_read(&page->_count) == 0);
 	return atomic_dec_and_test(&page->_count);
 }
 
@@ -304,10 +304,10 @@ static inline int put_page_testzero(stru
  */
 static inline int get_page_unless_zero(struct page *page)
 {
-	return atomic_add_unless(&page->_count, 1, -1);
+	return atomic_inc_not_zero(&page->_count);
 }
 
-#define set_page_count(p,v) 	atomic_set(&(p)->_count, (v) - 1)
+#define set_page_count(p,v) 	atomic_set(&(p)->_count, (v))
 #define __put_page(p)		atomic_dec(&(p)->_count)
 
 extern void FASTCALL(__page_cache_release(struct page *));
@@ -316,7 +316,7 @@ static inline int page_count(struct page
 {
 	if (PageCompound(page))
 		page = (struct page *)page_private(page);
-	return atomic_read(&page->_count) + 1;
+	return atomic_read(&page->_count);
 }
 
 static inline void get_page(struct page *page)

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [patch 5/6] mm: simplify vmscan vs release refcounting
  2006-01-19 19:23 ` [patch 5/6] mm: simplify vmscan vs release refcounting Nick Piggin
@ 2006-01-19 19:35   ` Linus Torvalds
  2006-01-19 19:53     ` Nick Piggin
  0 siblings, 1 reply; 9+ messages in thread
From: Linus Torvalds @ 2006-01-19 19:35 UTC (permalink / raw)
  To: Nick Piggin
  Cc: Andrew Morton, Linux Memory Management, Linux Kernel Mailing List



On Thu, 19 Jan 2006, Nick Piggin wrote:
>
> The VM has an interesting race where a page refcount can drop to zero, but
> it is still on the LRU lists for a short time. This was solved by testing
> a 0->1 refcount transition when picking up pages from the LRU, and dropping
> the refcount in that case.

Heh. Now you keep the count offset, but you also end up removing all the 
comments about it (still) being -1 for free. 

And your changelog talks about "atomic_inc_not_zero()" even though the 
code actually does

	atomic_add_unless(&page->_count, 1, -1);

which makes it pretty confusing ;)

I also think it's wrong - you've changed put_page_testzero() to use 
"atomic_dec_and_test()", even though the count is based on -1.

So this patch _only_ works together with the next one, and is invalid in 
many ways on its own. You should re-split the de-skew part correctly..

		Linus

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [patch 5/6] mm: simplify vmscan vs release refcounting
  2006-01-19 19:35   ` Linus Torvalds
@ 2006-01-19 19:53     ` Nick Piggin
  0 siblings, 0 replies; 9+ messages in thread
From: Nick Piggin @ 2006-01-19 19:53 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: Nick Piggin, Andrew Morton, Linux Memory Management,
	Linux Kernel Mailing List

On Thu, Jan 19, 2006 at 11:35:29AM -0800, Linus Torvalds wrote:
> 
> 
> On Thu, 19 Jan 2006, Nick Piggin wrote:
> >
> > The VM has an interesting race where a page refcount can drop to zero, but
> > it is still on the LRU lists for a short time. This was solved by testing
> > a 0->1 refcount transition when picking up pages from the LRU, and dropping
> > the refcount in that case.
> 
> Heh. Now you keep the count offset, but you also end up removing all the 
> comments about it (still) being -1 for free. 
> 
> And your changelog talks about "atomic_inc_not_zero()" even though the 
> code actually does
> 
> 	atomic_add_unless(&page->_count, 1, -1);
> 
> which makes it pretty confusing ;)
> 
> I also think it's wrong - you've changed put_page_testzero() to use 
> "atomic_dec_and_test()", even though the count is based on -1.
> 
> So this patch _only_ works together with the next one, and is invalid in 
> many ways on its own. You should re-split the de-skew part correctly..
> 

Man I'm really happy one of us is awake. Sorry, I'll resend the last two.

Nick

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2006-01-19 19:53 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2006-01-19 19:22 [patch 0/6] mm: optimisations and page ref simplifications Nick Piggin
2006-01-19 19:22 ` [patch 1/6] mm: never ClearPageLRU released pages Nick Piggin
2006-01-19 19:23 ` [patch 2/6] mm: PageLRU no testset Nick Piggin
2006-01-19 19:23 ` [patch 3/6] mm: PageActive " Nick Piggin
2006-01-19 19:23 ` [patch 4/6] mm: less atomic ops Nick Piggin
2006-01-19 19:23 ` [patch 5/6] mm: simplify vmscan vs release refcounting Nick Piggin
2006-01-19 19:35   ` Linus Torvalds
2006-01-19 19:53     ` Nick Piggin
2006-01-19 19:23 ` [patch 6/6] mm: de-skew page refcounting Nick Piggin

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).