diff options
Diffstat (limited to 'fs/btrfs/inode.c')
| -rw-r--r-- | fs/btrfs/inode.c | 41 | 
1 files changed, 26 insertions, 15 deletions
| diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 53ca025655fc..a79299a89b7d 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -1335,8 +1335,11 @@ next_slot:  		leaf = path->nodes[0];  		if (path->slots[0] >= btrfs_header_nritems(leaf)) {  			ret = btrfs_next_leaf(root, path); -			if (ret < 0) +			if (ret < 0) { +				if (cow_start != (u64)-1) +					cur_offset = cow_start;  				goto error; +			}  			if (ret > 0)  				break;  			leaf = path->nodes[0]; @@ -3385,6 +3388,11 @@ int btrfs_orphan_add(struct btrfs_trans_handle *trans,  		ret = btrfs_orphan_reserve_metadata(trans, inode);  		ASSERT(!ret);  		if (ret) { +			/* +			 * dec doesn't need spin_lock as ->orphan_block_rsv +			 * would be released only if ->orphan_inodes is +			 * zero. +			 */  			atomic_dec(&root->orphan_inodes);  			clear_bit(BTRFS_INODE_ORPHAN_META_RESERVED,  				  &inode->runtime_flags); @@ -3399,12 +3407,17 @@ int btrfs_orphan_add(struct btrfs_trans_handle *trans,  	if (insert >= 1) {  		ret = btrfs_insert_orphan_item(trans, root, btrfs_ino(inode));  		if (ret) { -			atomic_dec(&root->orphan_inodes);  			if (reserve) {  				clear_bit(BTRFS_INODE_ORPHAN_META_RESERVED,  					  &inode->runtime_flags);  				btrfs_orphan_release_metadata(inode);  			} +			/* +			 * btrfs_orphan_commit_root may race with us and set +			 * ->orphan_block_rsv to zero, in order to avoid that, +			 * decrease ->orphan_inodes after everything is done. +			 */ +			atomic_dec(&root->orphan_inodes);  			if (ret != -EEXIST) {  				clear_bit(BTRFS_INODE_HAS_ORPHAN_ITEM,  					  &inode->runtime_flags); @@ -3436,28 +3449,26 @@ static int btrfs_orphan_del(struct btrfs_trans_handle *trans,  {  	struct btrfs_root *root = inode->root;  	int delete_item = 0; -	int release_rsv = 0;  	int ret = 0; -	spin_lock(&root->orphan_lock);  	if (test_and_clear_bit(BTRFS_INODE_HAS_ORPHAN_ITEM,  			       &inode->runtime_flags))  		delete_item = 1; +	if (delete_item && trans) +		ret = btrfs_del_orphan_item(trans, root, btrfs_ino(inode)); +  	if (test_and_clear_bit(BTRFS_INODE_ORPHAN_META_RESERVED,  			       &inode->runtime_flags)) -		release_rsv = 1; -	spin_unlock(&root->orphan_lock); +		btrfs_orphan_release_metadata(inode); -	if (delete_item) { +	/* +	 * btrfs_orphan_commit_root may race with us and set ->orphan_block_rsv +	 * to zero, in order to avoid that, decrease ->orphan_inodes after +	 * everything is done. +	 */ +	if (delete_item)  		atomic_dec(&root->orphan_inodes); -		if (trans) -			ret = btrfs_del_orphan_item(trans, root, -						    btrfs_ino(inode)); -	} - -	if (release_rsv) -		btrfs_orphan_release_metadata(inode);  	return ret;  } @@ -5281,7 +5292,7 @@ void btrfs_evict_inode(struct inode *inode)  	trace_btrfs_inode_evict(inode);  	if (!root) { -		kmem_cache_free(btrfs_inode_cachep, BTRFS_I(inode)); +		clear_inode(inode);  		return;  	} |