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 */ _