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 d654a3b6209..0f900671423 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)  EXPORT_SYMBOL(mark_buffer_dirty_inode);  /* + * Mark the page dirty, and set it dirty in the radix tree, and mark the inode + * dirty. + * + * If warn is true, then emit a warning if the page is not uptodate and has + * not been truncated. + */ +static int __set_page_dirty(struct page *page, +		struct address_space *mapping, int warn) +{ +	if (unlikely(!mapping)) +		return !TestSetPageDirty(page); + +	if (TestSetPageDirty(page)) +		return 0; + +	write_lock_irq(&mapping->tree_lock); +	if (page->mapping) {	/* Race with truncate? */ +		WARN_ON_ONCE(warn && !PageUptodate(page)); + +		if (mapping_cap_account_dirty(mapping)) { +			__inc_zone_page_state(page, NR_FILE_DIRTY); +			task_io_account_write(PAGE_CACHE_SIZE); +		} +		radix_tree_tag_set(&mapping->page_tree, +				page_index(page), PAGECACHE_TAG_DIRTY); +	} +	write_unlock_irq(&mapping->tree_lock); +	__mark_inode_dirty(mapping->host, I_DIRTY_PAGES); + +	return 1; +} + +/*   * Add a page to the dirty page list.   *   * 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);   */  int __set_page_dirty_buffers(struct page *page)  { -	struct address_space * const mapping = page_mapping(page); +	struct address_space *mapping = page_mapping(page);  	if (unlikely(!mapping))  		return !TestSetPageDirty(page); @@ -719,21 +752,7 @@ int __set_page_dirty_buffers(struct page *page)  	}  	spin_unlock(&mapping->private_lock); -	if (TestSetPageDirty(page)) -		return 0; - -	write_lock_irq(&mapping->tree_lock); -	if (page->mapping) {	/* Race with truncate? */ -		if (mapping_cap_account_dirty(mapping)) { -			__inc_zone_page_state(page, NR_FILE_DIRTY); -			task_io_account_write(PAGE_CACHE_SIZE); -		} -		radix_tree_tag_set(&mapping->page_tree, -				page_index(page), PAGECACHE_TAG_DIRTY); -	} -	write_unlock_irq(&mapping->tree_lock); -	__mark_inode_dirty(mapping->host, I_DIRTY_PAGES); -	return 1; +	return __set_page_dirty(page, mapping, 1);  }  EXPORT_SYMBOL(__set_page_dirty_buffers); @@ -1132,8 +1151,9 @@ __getblk_slow(struct block_device *bdev, sector_t block, int size)   */  void fastcall mark_buffer_dirty(struct buffer_head *bh)  { +	WARN_ON_ONCE(!buffer_uptodate(bh));  	if (!buffer_dirty(bh) && !test_set_buffer_dirty(bh)) -		__set_page_dirty_nobuffers(bh->b_page); +		__set_page_dirty(bh->b_page, page_mapping(bh->b_page), 0);  }  /* diff --git a/mm/page-writeback.c b/mm/page-writeback.c index ea9da3bed3e..886ea0d5a13 100644 --- a/mm/page-writeback.c +++ b/mm/page-writeback.c @@ -824,6 +824,7 @@ int __set_page_dirty_nobuffers(struct page *page)  		mapping2 = page_mapping(page);  		if (mapping2) { /* Race with truncate? */  			BUG_ON(mapping2 != mapping); +			WARN_ON_ONCE(!PagePrivate(page) && !PageUptodate(page));  			if (mapping_cap_account_dirty(mapping)) {  				__inc_zone_page_state(page, NR_FILE_DIRTY);  				task_io_account_write(PAGE_CACHE_SIZE); diff --git a/mm/truncate.c b/mm/truncate.c index 7c994f2d614..f47e46d1be3 100644 --- a/mm/truncate.c +++ b/mm/truncate.c @@ -100,9 +100,9 @@ truncate_complete_page(struct address_space *mapping, struct page *page)  	if (PagePrivate(page))  		do_invalidatepage(page, 0); +	remove_from_page_cache(page);  	ClearPageUptodate(page);  	ClearPageMappedToDisk(page); -	remove_from_page_cache(page);  	page_cache_release(page);	/* pagecache ref */  }  |