diff options
Diffstat (limited to 'fs/buffer.c')
| -rw-r--r-- | fs/buffer.c | 51 | 
1 files changed, 26 insertions, 25 deletions
diff --git a/fs/buffer.c b/fs/buffer.c index 9ddb9fc7d923..eba6e4f621ce 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -77,7 +77,7 @@ EXPORT_SYMBOL(__lock_buffer);  void unlock_buffer(struct buffer_head *bh)  {  	clear_bit_unlock(BH_Lock, &bh->b_state); -	smp_mb__after_clear_bit(); +	smp_mb__after_atomic();  	wake_up_bit(&bh->b_state, BH_Lock);  }  EXPORT_SYMBOL(unlock_buffer); @@ -227,7 +227,7 @@ __find_get_block_slow(struct block_device *bdev, sector_t block)  	int all_mapped = 1;  	index = block >> (PAGE_CACHE_SHIFT - bd_inode->i_blkbits); -	page = find_get_page(bd_mapping, index); +	page = find_get_page_flags(bd_mapping, index, FGP_ACCESSED);  	if (!page)  		goto out; @@ -1366,12 +1366,13 @@ __find_get_block(struct block_device *bdev, sector_t block, unsigned size)  	struct buffer_head *bh = lookup_bh_lru(bdev, block, size);  	if (bh == NULL) { +		/* __find_get_block_slow will mark the page accessed */  		bh = __find_get_block_slow(bdev, block);  		if (bh)  			bh_lru_install(bh); -	} -	if (bh) +	} else  		touch_buffer(bh); +  	return bh;  }  EXPORT_SYMBOL(__find_get_block); @@ -1483,16 +1484,27 @@ EXPORT_SYMBOL(set_bh_page);  /*   * Called when truncating a buffer on a page completely.   */ + +/* Bits that are cleared during an invalidate */ +#define BUFFER_FLAGS_DISCARD \ +	(1 << BH_Mapped | 1 << BH_New | 1 << BH_Req | \ +	 1 << BH_Delay | 1 << BH_Unwritten) +  static void discard_buffer(struct buffer_head * bh)  { +	unsigned long b_state, b_state_old; +  	lock_buffer(bh);  	clear_buffer_dirty(bh);  	bh->b_bdev = NULL; -	clear_buffer_mapped(bh); -	clear_buffer_req(bh); -	clear_buffer_new(bh); -	clear_buffer_delay(bh); -	clear_buffer_unwritten(bh); +	b_state = bh->b_state; +	for (;;) { +		b_state_old = cmpxchg(&bh->b_state, b_state, +				      (b_state & ~BUFFER_FLAGS_DISCARD)); +		if (b_state_old == b_state) +			break; +		b_state = b_state_old; +	}  	unlock_buffer(bh);  } @@ -2879,10 +2891,9 @@ EXPORT_SYMBOL(block_truncate_page);  /*   * The generic ->writepage function for buffer-backed address_spaces - * this form passes in the end_io handler used to finish the IO.   */ -int block_write_full_page_endio(struct page *page, get_block_t *get_block, -			struct writeback_control *wbc, bh_end_io_t *handler) +int block_write_full_page(struct page *page, get_block_t *get_block, +			struct writeback_control *wbc)  {  	struct inode * const inode = page->mapping->host;  	loff_t i_size = i_size_read(inode); @@ -2892,7 +2903,7 @@ int block_write_full_page_endio(struct page *page, get_block_t *get_block,  	/* Is the page fully inside i_size? */  	if (page->index < end_index)  		return __block_write_full_page(inode, page, get_block, wbc, -					       handler); +					       end_buffer_async_write);  	/* Is the page fully outside i_size? (truncate in progress) */  	offset = i_size & (PAGE_CACHE_SIZE-1); @@ -2915,18 +2926,8 @@ int block_write_full_page_endio(struct page *page, get_block_t *get_block,  	 * writes to that region are not written out to the file."  	 */  	zero_user_segment(page, offset, PAGE_CACHE_SIZE); -	return __block_write_full_page(inode, page, get_block, wbc, handler); -} -EXPORT_SYMBOL(block_write_full_page_endio); - -/* - * The generic ->writepage function for buffer-backed address_spaces - */ -int block_write_full_page(struct page *page, get_block_t *get_block, -			struct writeback_control *wbc) -{ -	return block_write_full_page_endio(page, get_block, wbc, -					   end_buffer_async_write); +	return __block_write_full_page(inode, page, get_block, wbc, +							end_buffer_async_write);  }  EXPORT_SYMBOL(block_write_full_page);  |