decouple swapper_space treatment from other address_spaces
Subsystems (3)
PATCH 4/10 decouple swapper_space treatment from other address_spaces
swapper_space is different. Its pages are locked during writeout, it uses PAGE_SIZE rather than PAGE_CACHE_SIZE. Converting swap to look more like the other address_spaces is a separate project. This patch fully restores the old swap behaviour.
- Don't dirty swapcache page buffers in set_page_dirty().
Fixes a problem where __free_pte() runs set_page_dirty() and then immediately runs ClearPageDirty(). The pages ends up clean, with dirty buffers, and is unfreeable.
- Hence, don't mark the page clean if its buffers are clean - swap does not have page/buffers dirty state coherency.
=====================================
mm/page-writeback.c renamed from mm/page-writeback.c~clean-swap-page +4 -1
@@ -454,6 +454,9 @@ EXPORT_SYMBOL(write_one_page);* * FIXME: may need to call ->reservepage here as well. That's rather up to the * address_space though. +* +* For now, we treat swapper_space specially. It doesn't use the normal +* block a_ops. */ int __set_page_dirty_buffers (struct page *page) {
@@ -470,7 +473,7 @@ int __set_page_dirty_buffers(struct pagespin_lock (&inode->i_bufferlist_lock); -if (page_has_buffers (page)) { +if (page_has_buffers (page) && !PageSwapCache (page)) {struct buffer_head *head =page_buffers (page);struct buffer_head *bh = head;
fs/buffer.c renamed from fs/buffer.c~clean-swap-page +10 -9
@@ -2159,14 +2159,6 @@ static void check_ttfb_buffer(struct pag* total exclusion from __set_page_dirty_buffers(). That is obtained with * i_bufferlist_lock. * -* Nobody should be calling try_to_free_buffers against a page which is -* eligible for set_page_dirty() treatment anyway - the page is clearly -* not freeable. So we could just test page_count(page) here and complain -* then scram if it's wrong. -* -* If any buffer is not uptodate then the entire page is set not uptodate, -* as the partial uptodateness information is about to be lost. -* * try_to_free_buffers() is non-blocking. */ static inline int buffer_busy (struct buffer_head *bh)
@@ -2222,8 +2214,17 @@ int try_to_free_buffers(struct page *pag inode = page->mapping->host;spin_lock (&inode->i_bufferlist_lock); ret =drop_buffers (page); -if (ret) +if (ret && !PageSwapCache (page)) { +/* +* If the filesystem writes its buffers by hand (eg ext3) +* then we can have clean buffers against a dirty page. We +* clean the page here; otherwise later reattachment of buffers +* could encounter a non-uptodate page, which is unresolvable. +* This only applies in the rare case where try_to_free_buffers +* succeeds but the page is not freed. +*/ ClearPageDirty (page); + }spin_unlock (&inode->i_bufferlist_lock);return ret; }
-