aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/hugetlbfs/inode.c2
-rw-r--r--include/linux/page-flags.h8
-rw-r--r--mm/page-writeback.c32
-rw-r--r--mm/truncate.c25
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
177static void truncate_huge_page(struct page *page) 177static 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
254struct page; /* forward declaration */ 254struct page; /* forward declaration */
255 255
256int test_clear_page_dirty(struct page *page); 256extern void cancel_dirty_page(struct page *page, unsigned int account_size);
257
257int test_clear_page_writeback(struct page *page); 258int test_clear_page_writeback(struct page *page);
258int test_set_page_writeback(struct page *page); 259int test_set_page_writeback(struct page *page);
259 260
260static inline void clear_page_dirty(struct page *page)
261{
262 test_clear_page_dirty(page);
263}
264
265static inline void set_page_writeback(struct page *page) 261static 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)
845EXPORT_SYMBOL(set_page_dirty_lock); 845EXPORT_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 */
851int 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}
877EXPORT_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
54void 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);