

Arrange for all dirty pagecache pages to be tagged as dirty within their
radix tree.


---

 25-akpm/fs/buffer.c                |    2 +
 25-akpm/include/linux/fs.h         |    7 +++++
 25-akpm/include/linux/page-flags.h |    2 +
 25-akpm/mm/page-writeback.c        |   46 ++++++++++++++++++++++++++++++++-----
 25-akpm/mm/swap_state.c            |    4 +--
 include/linux/mm.h                 |    0 
 6 files changed, 53 insertions(+), 8 deletions(-)

diff -puN fs/buffer.c~tag-dirty-pages fs/buffer.c
--- 25/fs/buffer.c~tag-dirty-pages	2004-04-03 03:00:11.454490208 -0800
+++ 25-akpm/fs/buffer.c	2004-04-03 03:00:11.466488384 -0800
@@ -873,6 +873,8 @@ int __set_page_dirty_buffers(struct page
 				inc_page_state(nr_dirty);
 			list_del(&page->list);
 			list_add(&page->list, &mapping->dirty_pages);
+			radix_tree_tag_set(&mapping->page_tree, page->index,
+						PAGECACHE_TAG_DIRTY);
 		}
 		spin_unlock_irq(&mapping->tree_lock);
 		__mark_inode_dirty(mapping->host, I_DIRTY_PAGES);
diff -puN include/linux/fs.h~tag-dirty-pages include/linux/fs.h
--- 25/include/linux/fs.h~tag-dirty-pages	2004-04-03 03:00:11.456489904 -0800
+++ 25-akpm/include/linux/fs.h	2004-04-03 03:00:11.467488232 -0800
@@ -365,6 +365,13 @@ struct block_device {
 };
 
 /*
+ * Radix-tre tags, for tagging dirty and writeback pages within the pagecache
+ * radix trees
+ */
+#define PAGECACHE_TAG_DIRTY	0
+#define PAGECACHE_TAG_WRITEBACK	1
+
+/*
  * Use sequence counter to get consistent i_size on 32-bit processors.
  */
 #if BITS_PER_LONG==32 && defined(CONFIG_SMP)
diff -puN mm/page-writeback.c~tag-dirty-pages mm/page-writeback.c
--- 25/mm/page-writeback.c~tag-dirty-pages	2004-04-03 03:00:11.457489752 -0800
+++ 25-akpm/mm/page-writeback.c	2004-04-03 03:00:11.469487928 -0800
@@ -522,6 +522,8 @@ int __set_page_dirty_nobuffers(struct pa
 					inc_page_state(nr_dirty);
 				list_del(&page->list);
 				list_add(&page->list, &mapping->dirty_pages);
+				radix_tree_tag_set(&mapping->page_tree,
+					page->index, PAGECACHE_TAG_DIRTY);
 			}
 			spin_unlock_irq(&mapping->tree_lock);
 			if (!PageSwapCache(page))
@@ -560,13 +562,45 @@ EXPORT_SYMBOL(set_page_dirty_lock);
  */
 int test_clear_page_dirty(struct page *page)
 {
-	if (TestClearPageDirty(page)) {
-		struct address_space *mapping = page->mapping;
+	struct address_space *mapping = page->mapping;
+	unsigned long flags;
 
-		if (mapping && !mapping->backing_dev_info->memory_backed)
-			dec_page_state(nr_dirty);
-		return 1;
+	if (mapping) {
+		spin_lock_irqsave(&mapping->tree_lock, flags);
+		if (TestClearPageDirty(page)) {
+			radix_tree_tag_clear(&mapping->page_tree, page->index,
+						PAGECACHE_TAG_DIRTY);
+			spin_unlock_irqrestore(&mapping->tree_lock, flags);
+			if (!mapping->backing_dev_info->memory_backed)
+				dec_page_state(nr_dirty);
+			return 1;
+		}
+		spin_unlock_irqrestore(&mapping->tree_lock, flags);
+		return 0;
 	}
-	return 0;
+	return TestClearPageDirty(page);
 }
 EXPORT_SYMBOL(test_clear_page_dirty);
+
+/*
+ * Clear a page's dirty flag while ignoring dirty memory accounting
+ */
+int __clear_page_dirty(struct page *page)
+{
+	struct address_space *mapping = page->mapping;
+
+	if (mapping) {
+		unsigned long flags;
+
+		spin_lock_irqsave(&mapping->tree_lock, flags);
+		if (TestClearPageDirty(page)) {
+			radix_tree_tag_clear(&mapping->page_tree, page->index,
+						PAGECACHE_TAG_DIRTY);
+			spin_unlock_irqrestore(&mapping->tree_lock, flags);
+			return 1;
+		}
+		spin_unlock_irqrestore(&mapping->tree_lock, flags);
+		return 0;
+	}
+	return TestClearPageDirty(page);
+}
diff -puN mm/swap_state.c~tag-dirty-pages mm/swap_state.c
--- 25/mm/swap_state.c~tag-dirty-pages	2004-04-03 03:00:11.458489600 -0800
+++ 25-akpm/mm/swap_state.c	2004-04-03 03:00:11.470487776 -0800
@@ -149,7 +149,7 @@ int add_to_swap(struct page * page)
 		switch (err) {
 		case 0:				/* Success */
 			SetPageUptodate(page);
-			ClearPageDirty(page);
+			__clear_page_dirty(page);
 			set_page_dirty(page);
 			INC_CACHE_INFO(add_total);
 			return 1;
@@ -246,7 +246,7 @@ int move_from_swap_cache(struct page *pa
 	if (!err) {
 		swap_free(entry);
 		/* shift page from clean_pages to dirty_pages list */
-		ClearPageDirty(page);
+		__clear_page_dirty(page);
 		set_page_dirty(page);
 	}
 	return err;
diff -puN include/linux/mm.h~tag-dirty-pages include/linux/mm.h
diff -puN include/linux/page-flags.h~tag-dirty-pages include/linux/page-flags.h
--- 25/include/linux/page-flags.h~tag-dirty-pages	2004-04-03 03:00:11.461489144 -0800
+++ 25-akpm/include/linux/page-flags.h	2004-04-03 03:00:11.470487776 -0800
@@ -318,4 +318,6 @@ static inline void clear_page_dirty(stru
 	test_clear_page_dirty(page);
 }
 
+int __clear_page_dirty(struct page *page);
+
 #endif	/* PAGE_FLAGS_H */

_
