diff options
| author | Chris Mason <chris.mason@oracle.com> | 2012-05-06 07:23:47 -0400 | 
|---|---|---|
| committer | Chris Mason <chris.mason@oracle.com> | 2012-05-06 07:23:47 -0400 | 
| commit | b9fab919b748c7b39c19ff236ed6c5682c266dde (patch) | |
| tree | 49e5a6f8041a7f0a9be0c1a39cd9088e3faa1df2 /fs/btrfs/disk-io.c | |
| parent | ea9947b4395fa34666086b2fa6f686e94903e047 (diff) | |
| download | olio-linux-3.10-b9fab919b748c7b39c19ff236ed6c5682c266dde.tar.xz olio-linux-3.10-b9fab919b748c7b39c19ff236ed6c5682c266dde.zip  | |
Btrfs: avoid sleeping in verify_parent_transid while atomic
verify_parent_transid needs to lock the extent range to make
sure no IO is underway, and so it can safely clear the
uptodate bits if our checks fail.
But, a few callers are using it with spinlocks held.  Most
of the time, the generation numbers are going to match, and
we don't want to switch to a blocking lock just for the error
case.  This adds an atomic flag to verify_parent_transid,
and changes it to return EAGAIN if it needs to block to
properly verifiy things.
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/disk-io.c')
| -rw-r--r-- | fs/btrfs/disk-io.c | 18 | 
1 files changed, 13 insertions, 5 deletions
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index d0c969beaad..a7ffc88a7db 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -323,7 +323,8 @@ static int csum_tree_block(struct btrfs_root *root, struct extent_buffer *buf,   * in the wrong place.   */  static int verify_parent_transid(struct extent_io_tree *io_tree, -				 struct extent_buffer *eb, u64 parent_transid) +				 struct extent_buffer *eb, u64 parent_transid, +				 int atomic)  {  	struct extent_state *cached_state = NULL;  	int ret; @@ -331,6 +332,9 @@ static int verify_parent_transid(struct extent_io_tree *io_tree,  	if (!parent_transid || btrfs_header_generation(eb) == parent_transid)  		return 0; +	if (atomic) +		return -EAGAIN; +  	lock_extent_bits(io_tree, eb->start, eb->start + eb->len - 1,  			 0, &cached_state);  	if (extent_buffer_uptodate(eb) && @@ -372,7 +376,8 @@ static int btree_read_extent_buffer_pages(struct btrfs_root *root,  		ret = read_extent_buffer_pages(io_tree, eb, start,  					       WAIT_COMPLETE,  					       btree_get_extent, mirror_num); -		if (!ret && !verify_parent_transid(io_tree, eb, parent_transid)) +		if (!ret && !verify_parent_transid(io_tree, eb, +						   parent_transid, 0))  			break;  		/* @@ -1202,7 +1207,7 @@ static int __must_check find_and_setup_root(struct btrfs_root *tree_root,  	root->commit_root = NULL;  	root->node = read_tree_block(root, btrfs_root_bytenr(&root->root_item),  				     blocksize, generation); -	if (!root->node || !btrfs_buffer_uptodate(root->node, generation)) { +	if (!root->node || !btrfs_buffer_uptodate(root->node, generation, 0)) {  		free_extent_buffer(root->node);  		root->node = NULL;  		return -EIO; @@ -3143,7 +3148,8 @@ int close_ctree(struct btrfs_root *root)  	return 0;  } -int btrfs_buffer_uptodate(struct extent_buffer *buf, u64 parent_transid) +int btrfs_buffer_uptodate(struct extent_buffer *buf, u64 parent_transid, +			  int atomic)  {  	int ret;  	struct inode *btree_inode = buf->pages[0]->mapping->host; @@ -3153,7 +3159,9 @@ int btrfs_buffer_uptodate(struct extent_buffer *buf, u64 parent_transid)  		return ret;  	ret = verify_parent_transid(&BTRFS_I(btree_inode)->io_tree, buf, -				    parent_transid); +				    parent_transid, atomic); +	if (ret == -EAGAIN) +		return ret;  	return !ret;  }  |