| @@ -675,6 +675,39 @@ void mark_buffer_dirty_inode(struct buffer_head *bh, struct inode *inode) · 674 unmodified lines |
| 675 | 675 | } |
| 676 | 676 | EXPORT_SYMBOL(mark_buffer_dirty_inode); |
| 677 | 677 | |
| 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 | + |
| 678 | 711 | /* |
| 679 | 712 | * Add a page to the dirty page list. |
| 680 | 713 | * |
| @@ -702,7 +735,7 @@ EXPORT_SYMBOL(mark_buffer_dirty_inode); · 21 unmodified lines |
| 702 | 735 | */ |
| 703 | 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 | 740 | if (unlikely(!mapping)) |
| 708 | 741 | return !TestSetPageDirty(page); |
| @@ -719,21 +752,7 @@ int __set_page_dirty_buffers(struct page *page) · 10 unmodified lines |
| 719 | 752 | } |
| 720 | 753 | spin_unlock(&mapping->private_lock); |
| 721 | 754 | |
| 722 | | − if (TestSetPageDirty(page)) |
| 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; |
| 755 | + return __set_page_dirty(page, mapping, 1); |
| 737 | 756 | } |
| 738 | 757 | EXPORT_SYMBOL(__set_page_dirty_buffers); |
| 739 | 758 | |
| @@ -1132,8 +1151,9 @@ __getblk_slow(struct block_device *bdev, sector_t block, int size) · 392 unmodified lines |
| 1132 | 1151 | */ |
| 1133 | 1152 | void fastcall mark_buffer_dirty(struct buffer_head *bh) |
| 1134 | 1153 | { |
| 1154 | + WARN_ON_ONCE(!buffer_uptodate(bh)); |
| 1135 | 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 | /* |