diff options
Diffstat (limited to 'fs/btrfs/delayed-inode.c')
| -rw-r--r-- | fs/btrfs/delayed-inode.c | 147 | 
1 files changed, 100 insertions, 47 deletions
diff --git a/fs/btrfs/delayed-inode.c b/fs/btrfs/delayed-inode.c index 34836036f01..0b278b117cb 100644 --- a/fs/btrfs/delayed-inode.c +++ b/fs/btrfs/delayed-inode.c @@ -875,7 +875,6 @@ static int btrfs_insert_delayed_item(struct btrfs_trans_handle *trans,  				     struct btrfs_delayed_item *delayed_item)  {  	struct extent_buffer *leaf; -	struct btrfs_item *item;  	char *ptr;  	int ret; @@ -886,7 +885,6 @@ static int btrfs_insert_delayed_item(struct btrfs_trans_handle *trans,  	leaf = path->nodes[0]; -	item = btrfs_item_nr(leaf, path->slots[0]);  	ptr = btrfs_item_ptr(leaf, path->slots[0], char);  	write_extent_buffer(leaf, delayed_item->data, (unsigned long)ptr, @@ -1065,32 +1063,25 @@ static void btrfs_release_delayed_inode(struct btrfs_delayed_node *delayed_node)  	}  } -static int btrfs_update_delayed_inode(struct btrfs_trans_handle *trans, -				      struct btrfs_root *root, -				      struct btrfs_path *path, -				      struct btrfs_delayed_node *node) +static int __btrfs_update_delayed_inode(struct btrfs_trans_handle *trans, +					struct btrfs_root *root, +					struct btrfs_path *path, +					struct btrfs_delayed_node *node)  {  	struct btrfs_key key;  	struct btrfs_inode_item *inode_item;  	struct extent_buffer *leaf;  	int ret; -	mutex_lock(&node->mutex); -	if (!node->inode_dirty) { -		mutex_unlock(&node->mutex); -		return 0; -	} -  	key.objectid = node->inode_id;  	btrfs_set_key_type(&key, BTRFS_INODE_ITEM_KEY);  	key.offset = 0; +  	ret = btrfs_lookup_inode(trans, root, path, &key, 1);  	if (ret > 0) {  		btrfs_release_path(path); -		mutex_unlock(&node->mutex);  		return -ENOENT;  	} else if (ret < 0) { -		mutex_unlock(&node->mutex);  		return ret;  	} @@ -1105,11 +1096,47 @@ static int btrfs_update_delayed_inode(struct btrfs_trans_handle *trans,  	btrfs_delayed_inode_release_metadata(root, node);  	btrfs_release_delayed_inode(node); -	mutex_unlock(&node->mutex);  	return 0;  } +static inline int btrfs_update_delayed_inode(struct btrfs_trans_handle *trans, +					     struct btrfs_root *root, +					     struct btrfs_path *path, +					     struct btrfs_delayed_node *node) +{ +	int ret; + +	mutex_lock(&node->mutex); +	if (!node->inode_dirty) { +		mutex_unlock(&node->mutex); +		return 0; +	} + +	ret = __btrfs_update_delayed_inode(trans, root, path, node); +	mutex_unlock(&node->mutex); +	return ret; +} + +static inline int +__btrfs_commit_inode_delayed_items(struct btrfs_trans_handle *trans, +				   struct btrfs_path *path, +				   struct btrfs_delayed_node *node) +{ +	int ret; + +	ret = btrfs_insert_delayed_items(trans, path, node->root, node); +	if (ret) +		return ret; + +	ret = btrfs_delete_delayed_items(trans, path, node->root, node); +	if (ret) +		return ret; + +	ret = btrfs_update_delayed_inode(trans, node->root, path, node); +	return ret; +} +  /*   * Called when committing the transaction.   * Returns 0 on success. @@ -1119,7 +1146,6 @@ static int btrfs_update_delayed_inode(struct btrfs_trans_handle *trans,  static int __btrfs_run_delayed_items(struct btrfs_trans_handle *trans,  				     struct btrfs_root *root, int nr)  { -	struct btrfs_root *curr_root = root;  	struct btrfs_delayed_root *delayed_root;  	struct btrfs_delayed_node *curr_node, *prev_node;  	struct btrfs_path *path; @@ -1142,15 +1168,8 @@ static int __btrfs_run_delayed_items(struct btrfs_trans_handle *trans,  	curr_node = btrfs_first_delayed_node(delayed_root);  	while (curr_node && (!count || (count && nr--))) { -		curr_root = curr_node->root; -		ret = btrfs_insert_delayed_items(trans, path, curr_root, -						 curr_node); -		if (!ret) -			ret = btrfs_delete_delayed_items(trans, path, -						curr_root, curr_node); -		if (!ret) -			ret = btrfs_update_delayed_inode(trans, curr_root, -						path, curr_node); +		ret = __btrfs_commit_inode_delayed_items(trans, path, +							 curr_node);  		if (ret) {  			btrfs_release_delayed_node(curr_node);  			curr_node = NULL; @@ -1183,51 +1202,93 @@ int btrfs_run_delayed_items_nr(struct btrfs_trans_handle *trans,  	return __btrfs_run_delayed_items(trans, root, nr);  } -static int __btrfs_commit_inode_delayed_items(struct btrfs_trans_handle *trans, -					      struct btrfs_delayed_node *node) +int btrfs_commit_inode_delayed_items(struct btrfs_trans_handle *trans, +				     struct inode *inode)  { +	struct btrfs_delayed_node *delayed_node = btrfs_get_delayed_node(inode);  	struct btrfs_path *path;  	struct btrfs_block_rsv *block_rsv;  	int ret; +	if (!delayed_node) +		return 0; + +	mutex_lock(&delayed_node->mutex); +	if (!delayed_node->count) { +		mutex_unlock(&delayed_node->mutex); +		btrfs_release_delayed_node(delayed_node); +		return 0; +	} +	mutex_unlock(&delayed_node->mutex); +  	path = btrfs_alloc_path();  	if (!path)  		return -ENOMEM;  	path->leave_spinning = 1;  	block_rsv = trans->block_rsv; -	trans->block_rsv = &node->root->fs_info->delayed_block_rsv; +	trans->block_rsv = &delayed_node->root->fs_info->delayed_block_rsv; -	ret = btrfs_insert_delayed_items(trans, path, node->root, node); -	if (!ret) -		ret = btrfs_delete_delayed_items(trans, path, node->root, node); -	if (!ret) -		ret = btrfs_update_delayed_inode(trans, node->root, path, node); -	btrfs_free_path(path); +	ret = __btrfs_commit_inode_delayed_items(trans, path, delayed_node); +	btrfs_release_delayed_node(delayed_node); +	btrfs_free_path(path);  	trans->block_rsv = block_rsv; +  	return ret;  } -int btrfs_commit_inode_delayed_items(struct btrfs_trans_handle *trans, -				     struct inode *inode) +int btrfs_commit_inode_delayed_inode(struct inode *inode)  { +	struct btrfs_trans_handle *trans;  	struct btrfs_delayed_node *delayed_node = btrfs_get_delayed_node(inode); +	struct btrfs_path *path; +	struct btrfs_block_rsv *block_rsv;  	int ret;  	if (!delayed_node)  		return 0;  	mutex_lock(&delayed_node->mutex); -	if (!delayed_node->count) { +	if (!delayed_node->inode_dirty) {  		mutex_unlock(&delayed_node->mutex);  		btrfs_release_delayed_node(delayed_node);  		return 0;  	}  	mutex_unlock(&delayed_node->mutex); -	ret = __btrfs_commit_inode_delayed_items(trans, delayed_node); +	trans = btrfs_join_transaction(delayed_node->root); +	if (IS_ERR(trans)) { +		ret = PTR_ERR(trans); +		goto out; +	} + +	path = btrfs_alloc_path(); +	if (!path) { +		ret = -ENOMEM; +		goto trans_out; +	} +	path->leave_spinning = 1; + +	block_rsv = trans->block_rsv; +	trans->block_rsv = &delayed_node->root->fs_info->delayed_block_rsv; + +	mutex_lock(&delayed_node->mutex); +	if (delayed_node->inode_dirty) +		ret = __btrfs_update_delayed_inode(trans, delayed_node->root, +						   path, delayed_node); +	else +		ret = 0; +	mutex_unlock(&delayed_node->mutex); + +	btrfs_free_path(path); +	trans->block_rsv = block_rsv; +trans_out: +	btrfs_end_transaction(trans, delayed_node->root); +	btrfs_btree_balance_dirty(delayed_node->root); +out:  	btrfs_release_delayed_node(delayed_node); +  	return ret;  } @@ -1258,7 +1319,6 @@ static void btrfs_async_run_delayed_node_done(struct btrfs_work *work)  	struct btrfs_root *root;  	struct btrfs_block_rsv *block_rsv;  	int need_requeue = 0; -	int ret;  	async_node = container_of(work, struct btrfs_async_delayed_node, work); @@ -1277,14 +1337,7 @@ static void btrfs_async_run_delayed_node_done(struct btrfs_work *work)  	block_rsv = trans->block_rsv;  	trans->block_rsv = &root->fs_info->delayed_block_rsv; -	ret = btrfs_insert_delayed_items(trans, path, root, delayed_node); -	if (!ret) -		ret = btrfs_delete_delayed_items(trans, path, root, -						 delayed_node); - -	if (!ret) -		btrfs_update_delayed_inode(trans, root, path, delayed_node); - +	__btrfs_commit_inode_delayed_items(trans, path, delayed_node);  	/*  	 * Maybe new delayed items have been inserted, so we need requeue  	 * the work. Besides that, we must dequeue the empty delayed nodes  |