Commit 21bd2dfd authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] 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.
parent 6c8dd336
...@@ -2159,14 +2159,6 @@ static void check_ttfb_buffer(struct page *page, struct buffer_head *bh) ...@@ -2159,14 +2159,6 @@ static void check_ttfb_buffer(struct page *page, struct buffer_head *bh)
* total exclusion from __set_page_dirty_buffers(). That is obtained with * total exclusion from __set_page_dirty_buffers(). That is obtained with
* i_bufferlist_lock. * 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. * try_to_free_buffers() is non-blocking.
*/ */
static inline int buffer_busy(struct buffer_head *bh) static inline int buffer_busy(struct buffer_head *bh)
...@@ -2222,8 +2214,17 @@ int try_to_free_buffers(struct page *page) ...@@ -2222,8 +2214,17 @@ int try_to_free_buffers(struct page *page)
inode = page->mapping->host; inode = page->mapping->host;
spin_lock(&inode->i_bufferlist_lock); spin_lock(&inode->i_bufferlist_lock);
ret = drop_buffers(page); 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); ClearPageDirty(page);
}
spin_unlock(&inode->i_bufferlist_lock); spin_unlock(&inode->i_bufferlist_lock);
return ret; return ret;
} }
......
...@@ -454,6 +454,9 @@ EXPORT_SYMBOL(write_one_page); ...@@ -454,6 +454,9 @@ EXPORT_SYMBOL(write_one_page);
* *
* FIXME: may need to call ->reservepage here as well. That's rather up to the * FIXME: may need to call ->reservepage here as well. That's rather up to the
* address_space though. * 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) int __set_page_dirty_buffers(struct page *page)
{ {
...@@ -470,7 +473,7 @@ int __set_page_dirty_buffers(struct page *page) ...@@ -470,7 +473,7 @@ int __set_page_dirty_buffers(struct page *page)
spin_lock(&inode->i_bufferlist_lock); spin_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 *head = page_buffers(page);
struct buffer_head *bh = head; struct buffer_head *bh = head;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment