diff options
Diffstat (limited to 'fs/btrfs/inode.c')
| -rw-r--r-- | fs/btrfs/inode.c | 84 | 
1 files changed, 57 insertions, 27 deletions
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 966ddcc4c63..116ab67a06d 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -93,6 +93,8 @@ static noinline int cow_file_range(struct inode *inode,  				   struct page *locked_page,  				   u64 start, u64 end, int *page_started,  				   unsigned long *nr_written, int unlock); +static noinline int btrfs_update_inode_fallback(struct btrfs_trans_handle *trans, +				struct btrfs_root *root, struct inode *inode);  static int btrfs_init_inode_security(struct btrfs_trans_handle *trans,  				     struct inode *inode,  struct inode *dir, @@ -1741,7 +1743,7 @@ static int btrfs_finish_ordered_io(struct inode *inode, u64 start, u64 end)  				trans = btrfs_join_transaction(root);  			BUG_ON(IS_ERR(trans));  			trans->block_rsv = &root->fs_info->delalloc_block_rsv; -			ret = btrfs_update_inode(trans, root, inode); +			ret = btrfs_update_inode_fallback(trans, root, inode);  			BUG_ON(ret);  		}  		goto out; @@ -1791,7 +1793,7 @@ static int btrfs_finish_ordered_io(struct inode *inode, u64 start, u64 end)  	ret = btrfs_ordered_update_i_size(inode, 0, ordered_extent);  	if (!ret || !test_bit(BTRFS_ORDERED_PREALLOC, &ordered_extent->flags)) { -		ret = btrfs_update_inode(trans, root, inode); +		ret = btrfs_update_inode_fallback(trans, root, inode);  		BUG_ON(ret);  	}  	ret = 0; @@ -2199,6 +2201,9 @@ int btrfs_orphan_cleanup(struct btrfs_root *root)  		if (ret)  			goto out;  	} +	/* release the path since we're done with it */ +	btrfs_release_path(path); +  	root->orphan_cleanup_state = ORPHAN_CLEANUP_DONE;  	if (root->orphan_block_rsv) @@ -2426,7 +2431,7 @@ static void fill_inode_item(struct btrfs_trans_handle *trans,  /*   * copy everything in the in-memory inode into the btree.   */ -noinline int btrfs_update_inode(struct btrfs_trans_handle *trans, +static noinline int btrfs_update_inode_item(struct btrfs_trans_handle *trans,  				struct btrfs_root *root, struct inode *inode)  {  	struct btrfs_inode_item *inode_item; @@ -2434,21 +2439,6 @@ noinline int btrfs_update_inode(struct btrfs_trans_handle *trans,  	struct extent_buffer *leaf;  	int ret; -	/* -	 * If the inode is a free space inode, we can deadlock during commit -	 * if we put it into the delayed code. -	 * -	 * The data relocation inode should also be directly updated -	 * without delay -	 */ -	if (!btrfs_is_free_space_inode(root, inode) -	    && root->root_key.objectid != BTRFS_DATA_RELOC_TREE_OBJECTID) { -		ret = btrfs_delayed_update_inode(trans, root, inode); -		if (!ret) -			btrfs_set_inode_last_trans(trans, inode); -		return ret; -	} -  	path = btrfs_alloc_path();  	if (!path)  		return -ENOMEM; @@ -2477,6 +2467,43 @@ failed:  }  /* + * copy everything in the in-memory inode into the btree. + */ +noinline int btrfs_update_inode(struct btrfs_trans_handle *trans, +				struct btrfs_root *root, struct inode *inode) +{ +	int ret; + +	/* +	 * If the inode is a free space inode, we can deadlock during commit +	 * if we put it into the delayed code. +	 * +	 * The data relocation inode should also be directly updated +	 * without delay +	 */ +	if (!btrfs_is_free_space_inode(root, inode) +	    && root->root_key.objectid != BTRFS_DATA_RELOC_TREE_OBJECTID) { +		ret = btrfs_delayed_update_inode(trans, root, inode); +		if (!ret) +			btrfs_set_inode_last_trans(trans, inode); +		return ret; +	} + +	return btrfs_update_inode_item(trans, root, inode); +} + +static noinline int btrfs_update_inode_fallback(struct btrfs_trans_handle *trans, +				struct btrfs_root *root, struct inode *inode) +{ +	int ret; + +	ret = btrfs_update_inode(trans, root, inode); +	if (ret == -ENOSPC) +		return btrfs_update_inode_item(trans, root, inode); +	return ret; +} + +/*   * unlink helper that gets used here in inode.c and in the tree logging   * recovery code.  It remove a link in a directory with a given name, and   * also drops the back refs in the inode to the directory @@ -5632,7 +5659,7 @@ again:  	if (test_bit(BTRFS_ORDERED_NOCOW, &ordered->flags)) {  		ret = btrfs_ordered_update_i_size(inode, 0, ordered);  		if (!ret) -			err = btrfs_update_inode(trans, root, inode); +			err = btrfs_update_inode_fallback(trans, root, inode);  		goto out;  	} @@ -5670,7 +5697,7 @@ again:  	add_pending_csums(trans, inode, ordered->file_offset, &ordered->list);  	ret = btrfs_ordered_update_i_size(inode, 0, ordered);  	if (!ret || !test_bit(BTRFS_ORDERED_PREALLOC, &ordered->flags)) -		btrfs_update_inode(trans, root, inode); +		btrfs_update_inode_fallback(trans, root, inode);  	ret = 0;  out_unlock:  	unlock_extent_cached(&BTRFS_I(inode)->io_tree, ordered->file_offset, @@ -6529,14 +6556,16 @@ end_trans:  		ret = btrfs_orphan_del(NULL, inode);  	} -	trans->block_rsv = &root->fs_info->trans_block_rsv; -	ret = btrfs_update_inode(trans, root, inode); -	if (ret && !err) -		err = ret; +	if (trans) { +		trans->block_rsv = &root->fs_info->trans_block_rsv; +		ret = btrfs_update_inode(trans, root, inode); +		if (ret && !err) +			err = ret; -	nr = trans->blocks_used; -	ret = btrfs_end_transaction_throttle(trans, root); -	btrfs_btree_balance_dirty(root, nr); +		nr = trans->blocks_used; +		ret = btrfs_end_transaction_throttle(trans, root); +		btrfs_btree_balance_dirty(root, nr); +	}  out:  	btrfs_free_block_rsv(root, rsv); @@ -6605,6 +6634,7 @@ struct inode *btrfs_alloc_inode(struct super_block *sb)  	ei->orphan_meta_reserved = 0;  	ei->dummy_inode = 0;  	ei->in_defrag = 0; +	ei->delalloc_meta_reserved = 0;  	ei->force_compress = BTRFS_COMPRESS_NONE;  	ei->delayed_node = NULL;  |