diff options
-rw-r--r-- | fs/hugetlbfs/inode.c | 2 | ||||
-rw-r--r-- | include/linux/page-flags.h | 8 | ||||
-rw-r--r-- | mm/page-writeback.c | 32 | ||||
-rw-r--r-- | mm/truncate.c | 25 |
4 files changed, 20 insertions, 47 deletions
diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c index ed2c22340ad7..4f4cd132b571 100644 --- a/fs/hugetlbfs/inode.c +++ b/fs/hugetlbfs/inode.c | |||
@@ -176,7 +176,7 @@ static int hugetlbfs_commit_write(struct file *file, | |||
176 | 176 | ||
177 | static void truncate_huge_page(struct page *page) | 177 | static void truncate_huge_page(struct page *page) |
178 | { | 178 | { |
179 | clear_page_dirty(page); | 179 | cancel_dirty_page(page, /* No IO accounting for huge pages? */0); |
180 | ClearPageUptodate(page); | 180 | ClearPageUptodate(page); |
181 | remove_from_page_cache(page); | 181 | remove_from_page_cache(page); |
182 | put_page(page); | 182 | put_page(page); |
diff --git a/include/linux/page-flags.h b/include/linux/page-flags.h index 4830a3bedfb2..350878a2d848 100644 --- a/include/linux/page-flags.h +++ b/include/linux/page-flags.h | |||
@@ -253,15 +253,11 @@ static inline void SetPageUptodate(struct page *page) | |||
253 | 253 | ||
254 | struct page; /* forward declaration */ | 254 | struct page; /* forward declaration */ |
255 | 255 | ||
256 | int test_clear_page_dirty(struct page *page); | 256 | extern void cancel_dirty_page(struct page *page, unsigned int account_size); |
257 | |||
257 | int test_clear_page_writeback(struct page *page); | 258 | int test_clear_page_writeback(struct page *page); |
258 | int test_set_page_writeback(struct page *page); | 259 | int test_set_page_writeback(struct page *page); |
259 | 260 | ||
260 | static inline void clear_page_dirty(struct page *page) | ||
261 | { | ||
262 | test_clear_page_dirty(page); | ||
263 | } | ||
264 | |||
265 | static inline void set_page_writeback(struct page *page) | 261 | static inline void set_page_writeback(struct page *page) |
266 | { | 262 | { |
267 | test_set_page_writeback(page); | 263 | test_set_page_writeback(page); |
diff --git a/mm/page-writeback.c b/mm/page-writeback.c index 237107c1b084..b3a198c9248d 100644 --- a/mm/page-writeback.c +++ b/mm/page-writeback.c | |||
@@ -845,38 +845,6 @@ int set_page_dirty_lock(struct page *page) | |||
845 | EXPORT_SYMBOL(set_page_dirty_lock); | 845 | EXPORT_SYMBOL(set_page_dirty_lock); |
846 | 846 | ||
847 | /* | 847 | /* |
848 | * Clear a page's dirty flag, while caring for dirty memory accounting. | ||
849 | * Returns true if the page was previously dirty. | ||
850 | */ | ||
851 | int test_clear_page_dirty(struct page *page) | ||
852 | { | ||
853 | struct address_space *mapping = page_mapping(page); | ||
854 | unsigned long flags; | ||
855 | |||
856 | if (!mapping) | ||
857 | return TestClearPageDirty(page); | ||
858 | |||
859 | write_lock_irqsave(&mapping->tree_lock, flags); | ||
860 | if (TestClearPageDirty(page)) { | ||
861 | radix_tree_tag_clear(&mapping->page_tree, | ||
862 | page_index(page), PAGECACHE_TAG_DIRTY); | ||
863 | write_unlock_irqrestore(&mapping->tree_lock, flags); | ||
864 | /* | ||
865 | * We can continue to use `mapping' here because the | ||
866 | * page is locked, which pins the address_space | ||
867 | */ | ||
868 | if (mapping_cap_account_dirty(mapping)) { | ||
869 | page_mkclean(page); | ||
870 | dec_zone_page_state(page, NR_FILE_DIRTY); | ||
871 | } | ||
872 | return 1; | ||
873 | } | ||
874 | write_unlock_irqrestore(&mapping->tree_lock, flags); | ||
875 | return 0; | ||
876 | } | ||
877 | EXPORT_SYMBOL(test_clear_page_dirty); | ||
878 | |||
879 | /* | ||
880 | * Clear a page's dirty flag, while caring for dirty memory accounting. | 848 | * Clear a page's dirty flag, while caring for dirty memory accounting. |
881 | * Returns true if the page was previously dirty. | 849 | * Returns true if the page was previously dirty. |
882 | * | 850 | * |
diff --git a/mm/truncate.c b/mm/truncate.c index 9bfb8e853860..bf9e2965d666 100644 --- a/mm/truncate.c +++ b/mm/truncate.c | |||
@@ -51,6 +51,20 @@ static inline void truncate_partial_page(struct page *page, unsigned partial) | |||
51 | do_invalidatepage(page, partial); | 51 | do_invalidatepage(page, partial); |
52 | } | 52 | } |
53 | 53 | ||
54 | void cancel_dirty_page(struct page *page, unsigned int account_size) | ||
55 | { | ||
56 | /* If we're cancelling the page, it had better not be mapped any more */ | ||
57 | if (page_mapped(page)) { | ||
58 | static unsigned int warncount; | ||
59 | |||
60 | WARN_ON(++warncount < 5); | ||
61 | } | ||
62 | |||
63 | if (TestClearPageDirty(page) && account_size) | ||
64 | task_io_account_cancelled_write(account_size); | ||
65 | } | ||
66 | |||
67 | |||
54 | /* | 68 | /* |
55 | * If truncate cannot remove the fs-private metadata from the page, the page | 69 | * If truncate cannot remove the fs-private metadata from the page, the page |
56 | * becomes anonymous. It will be left on the LRU and may even be mapped into | 70 | * becomes anonymous. It will be left on the LRU and may even be mapped into |
@@ -70,8 +84,8 @@ truncate_complete_page(struct address_space *mapping, struct page *page) | |||
70 | if (PagePrivate(page)) | 84 | if (PagePrivate(page)) |
71 | do_invalidatepage(page, 0); | 85 | do_invalidatepage(page, 0); |
72 | 86 | ||
73 | if (test_clear_page_dirty(page)) | 87 | cancel_dirty_page(page, PAGE_CACHE_SIZE); |
74 | task_io_account_cancelled_write(PAGE_CACHE_SIZE); | 88 | |
75 | ClearPageUptodate(page); | 89 | ClearPageUptodate(page); |
76 | ClearPageMappedToDisk(page); | 90 | ClearPageMappedToDisk(page); |
77 | remove_from_page_cache(page); | 91 | remove_from_page_cache(page); |
@@ -350,7 +364,6 @@ int invalidate_inode_pages2_range(struct address_space *mapping, | |||
350 | for (i = 0; !ret && i < pagevec_count(&pvec); i++) { | 364 | for (i = 0; !ret && i < pagevec_count(&pvec); i++) { |
351 | struct page *page = pvec.pages[i]; | 365 | struct page *page = pvec.pages[i]; |
352 | pgoff_t page_index; | 366 | pgoff_t page_index; |
353 | int was_dirty; | ||
354 | 367 | ||
355 | lock_page(page); | 368 | lock_page(page); |
356 | if (page->mapping != mapping) { | 369 | if (page->mapping != mapping) { |
@@ -386,12 +399,8 @@ int invalidate_inode_pages2_range(struct address_space *mapping, | |||
386 | PAGE_CACHE_SIZE, 0); | 399 | PAGE_CACHE_SIZE, 0); |
387 | } | 400 | } |
388 | } | 401 | } |
389 | was_dirty = test_clear_page_dirty(page); | 402 | if (!invalidate_complete_page2(mapping, page)) |
390 | if (!invalidate_complete_page2(mapping, page)) { | ||
391 | if (was_dirty) | ||
392 | set_page_dirty(page); | ||
393 | ret = -EIO; | 403 | ret = -EIO; |
394 | } | ||
395 | unlock_page(page); | 404 | unlock_page(page); |
396 | } | 405 | } |
397 | pagevec_release(&pvec); | 406 | pagevec_release(&pvec); |