diff options
-rw-r--r-- | fs/buffer.c | 54 | ||||
-rw-r--r-- | mm/page-writeback.c | 1 | ||||
-rw-r--r-- | mm/truncate.c | 2 |
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) | |||
676 | EXPORT_SYMBOL(mark_buffer_dirty_inode); | 676 | EXPORT_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 | */ | ||
685 | static 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 | */ |
703 | int __set_page_dirty_buffers(struct page *page) | 736 | int __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 | } |
738 | EXPORT_SYMBOL(__set_page_dirty_buffers); | 757 | EXPORT_SYMBOL(__set_page_dirty_buffers); |
739 | 758 | ||
@@ -1132,8 +1151,9 @@ __getblk_slow(struct block_device *bdev, sector_t block, int size) | |||
1132 | */ | 1151 | */ |
1133 | void fastcall mark_buffer_dirty(struct buffer_head *bh) | 1152 | void 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 | ||