diff options
author | Linus Torvalds <torvalds@woody.osdl.org> | 2006-12-19 18:21:59 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.osdl.org> | 2006-12-21 12:04:31 -0500 |
commit | 46d2277c796f9f4937bfa668c40b2e3f43e93dd0 (patch) | |
tree | cfde4d8c4b1d721455c978a53e70a55a6c73c3ef /fs | |
parent | 9bfb18392ef586467277fa25d8f3a7a93611f6df (diff) |
Clean up and make try_to_free_buffers() not race with dirty pages
This is preparatory work in our continuing saga on some hard-to-trigger
file corruption with shared writable mmap() after the dirty page
tracking changes (commit d08b3851da41d0ee60851f2c75b118e1f7a5fc89 etc)
were merged.
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/buffer.c | 18 |
1 files changed, 1 insertions, 17 deletions
diff --git a/fs/buffer.c b/fs/buffer.c index d1f1b54d3108..263f88e4dffb 100644 --- a/fs/buffer.c +++ b/fs/buffer.c | |||
@@ -2834,7 +2834,7 @@ int try_to_free_buffers(struct page *page) | |||
2834 | int ret = 0; | 2834 | int ret = 0; |
2835 | 2835 | ||
2836 | BUG_ON(!PageLocked(page)); | 2836 | BUG_ON(!PageLocked(page)); |
2837 | if (PageWriteback(page)) | 2837 | if (PageDirty(page) || PageWriteback(page)) |
2838 | return 0; | 2838 | return 0; |
2839 | 2839 | ||
2840 | if (mapping == NULL) { /* can this still happen? */ | 2840 | if (mapping == NULL) { /* can this still happen? */ |
@@ -2845,22 +2845,6 @@ int try_to_free_buffers(struct page *page) | |||
2845 | spin_lock(&mapping->private_lock); | 2845 | spin_lock(&mapping->private_lock); |
2846 | ret = drop_buffers(page, &buffers_to_free); | 2846 | ret = drop_buffers(page, &buffers_to_free); |
2847 | spin_unlock(&mapping->private_lock); | 2847 | spin_unlock(&mapping->private_lock); |
2848 | if (ret) { | ||
2849 | /* | ||
2850 | * If the filesystem writes its buffers by hand (eg ext3) | ||
2851 | * then we can have clean buffers against a dirty page. We | ||
2852 | * clean the page here; otherwise later reattachment of buffers | ||
2853 | * could encounter a non-uptodate page, which is unresolvable. | ||
2854 | * This only applies in the rare case where try_to_free_buffers | ||
2855 | * succeeds but the page is not freed. | ||
2856 | * | ||
2857 | * Also, during truncate, discard_buffer will have marked all | ||
2858 | * the page's buffers clean. We discover that here and clean | ||
2859 | * the page also. | ||
2860 | */ | ||
2861 | if (test_clear_page_dirty(page)) | ||
2862 | task_io_account_cancelled_write(PAGE_CACHE_SIZE); | ||
2863 | } | ||
2864 | out: | 2848 | out: |
2865 | if (buffers_to_free) { | 2849 | if (buffers_to_free) { |
2866 | struct buffer_head *bh = buffers_to_free; | 2850 | struct buffer_head *bh = buffers_to_free; |