aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/buffer.c54
-rw-r--r--mm/page-writeback.c1
-rw-r--r--mm/truncate.c2
3 files changed, 39 insertions, 18 deletions
diff --git a/fs/buffer.c b/fs/buffer.c
index d654a3b6209e..0f9006714230 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -676,6 +676,39 @@ void mark_buffer_dirty_inode(struct buffer_head *bh, struct inode *inode)
676EXPORT_SYMBOL(mark_buffer_dirty_inode); 676EXPORT_SYMBOL(mark_buffer_dirty_inode);
677 677
678/* 678/*
679 * Mark the page dirty, and set it dirty in the radix tree, and mark the inode
680 * dirty.
681 *
682 * If warn is true, then emit a warning if the page is not uptodate and has
683 * not been truncated.
684 */
685static int __set_page_dirty(struct page *page,
686 struct address_space *mapping, int warn)
687{
688 if (unlikely(!mapping))
689 return !TestSetPageDirty(page);
690
691 if (TestSetPageDirty(page))
692 return 0;
693
694 write_lock_irq(&mapping->tree_lock);
695 if (page->mapping) { /* Race with truncate? */
696 WARN_ON_ONCE(warn && !PageUptodate(page));
697
698 if (mapping_cap_account_dirty(mapping)) {
699 __inc_zone_page_state(page, NR_FILE_DIRTY);
700 task_io_account_write(PAGE_CACHE_SIZE);
701 }
702 radix_tree_tag_set(&mapping->page_tree,
703 page_index(page), PAGECACHE_TAG_DIRTY);
704 }
705 write_unlock_irq(&mapping->tree_lock);
706 __mark_inode_dirty(mapping->host, I_DIRTY_PAGES);
707
708 return 1;
709}
710
711/*
679 * Add a page to the dirty page list. 712 * Add a page to the dirty page list.
680 * 713 *
681 * It is a sad fact of life that this function is called from several places 714 * It is a sad fact of life that this function is called from several places
@@ -702,7 +735,7 @@ EXPORT_SYMBOL(mark_buffer_dirty_inode);
702 */ 735 */
703int __set_page_dirty_buffers(struct page *page) 736int __set_page_dirty_buffers(struct page *page)
704{ 737{
705 struct address_space * const mapping = page_mapping(page); 738 struct address_space *mapping = page_mapping(page);
706 739
707 if (unlikely(!mapping)) 740 if (unlikely(!mapping))
708 return !TestSetPageDirty(page); 741 return !TestSetPageDirty(page);
@@ -719,21 +752,7 @@ int __set_page_dirty_buffers(struct page *page)
719 } 752 }
720 spin_unlock(&mapping->private_lock); 753 spin_unlock(&mapping->private_lock);
721 754
722 if (TestSetPageDirty(page)) 755 return __set_page_dirty(page, mapping, 1);
723 return 0;
724
725 write_lock_irq(&mapping->tree_lock);
726 if (page->mapping) { /* Race with truncate? */
727 if (mapping_cap_account_dirty(mapping)) {
728 __inc_zone_page_state(page, NR_FILE_DIRTY);
729 task_io_account_write(PAGE_CACHE_SIZE);
730 }
731 radix_tree_tag_set(&mapping->page_tree,
732 page_index(page), PAGECACHE_TAG_DIRTY);
733 }
734 write_unlock_irq(&mapping->tree_lock);
735 __mark_inode_dirty(mapping->host, I_DIRTY_PAGES);
736 return 1;
737} 756}
738EXPORT_SYMBOL(__set_page_dirty_buffers); 757EXPORT_SYMBOL(__set_page_dirty_buffers);
739 758
@@ -1132,8 +1151,9 @@ __getblk_slow(struct block_device *bdev, sector_t block, int size)
1132 */ 1151 */
1133void fastcall mark_buffer_dirty(struct buffer_head *bh) 1152void fastcall mark_buffer_dirty(struct buffer_head *bh)
1134{ 1153{
1154 WARN_ON_ONCE(!buffer_uptodate(bh));
1135 if (!buffer_dirty(bh) && !test_set_buffer_dirty(bh)) 1155 if (!buffer_dirty(bh) && !test_set_buffer_dirty(bh))
1136 __set_page_dirty_nobuffers(bh->b_page); 1156 __set_page_dirty(bh->b_page, page_mapping(bh->b_page), 0);
1137} 1157}
1138 1158
1139/* 1159/*
diff --git a/mm/page-writeback.c b/mm/page-writeback.c
index ea9da3bed3e9..886ea0d5a136 100644
--- a/mm/page-writeback.c
+++ b/mm/page-writeback.c
@@ -824,6 +824,7 @@ int __set_page_dirty_nobuffers(struct page *page)
824 mapping2 = page_mapping(page); 824 mapping2 = page_mapping(page);
825 if (mapping2) { /* Race with truncate? */ 825 if (mapping2) { /* Race with truncate? */
826 BUG_ON(mapping2 != mapping); 826 BUG_ON(mapping2 != mapping);
827 WARN_ON_ONCE(!PagePrivate(page) && !PageUptodate(page));
827 if (mapping_cap_account_dirty(mapping)) { 828 if (mapping_cap_account_dirty(mapping)) {
828 __inc_zone_page_state(page, NR_FILE_DIRTY); 829 __inc_zone_page_state(page, NR_FILE_DIRTY);
829 task_io_account_write(PAGE_CACHE_SIZE); 830 task_io_account_write(PAGE_CACHE_SIZE);
diff --git a/mm/truncate.c b/mm/truncate.c
index 7c994f2d6145..f47e46d1be3b 100644
--- a/mm/truncate.c
+++ b/mm/truncate.c
@@ -100,9 +100,9 @@ truncate_complete_page(struct address_space *mapping, struct page *page)
100 if (PagePrivate(page)) 100 if (PagePrivate(page))
101 do_invalidatepage(page, 0); 101 do_invalidatepage(page, 0);
102 102
103 remove_from_page_cache(page);
103 ClearPageUptodate(page); 104 ClearPageUptodate(page);
104 ClearPageMappedToDisk(page); 105 ClearPageMappedToDisk(page);
105 remove_from_page_cache(page);
106 page_cache_release(page); /* pagecache ref */ 106 page_cache_release(page); /* pagecache ref */
107} 107}
108 108