Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 178260b2 authored by Miao Xie's avatar Miao Xie Committed by Josef Bacik
Browse files

Btrfs: fix the deadlock between the transaction start/attach and commit

Now btrfs_commit_transaction() does this

ret = btrfs_run_ordered_operations(root, 0)

which async flushes all inodes on the ordered operations list, it introduced
a deadlock that transaction-start task, transaction-commit task and the flush
workers waited for each other.
(See the following URL to get the detail
 http://marc.info/?l=linux-btrfs&m=136070705732646&w=2

)

As we know, if ->in_commit is set, it means someone is committing the
current transaction, we should not try to join it if we are not JOIN
or JOIN_NOLOCK, wait is the best choice for it. In this way, we can avoid
the above problem. In this way, there is another benefit: there is no new
transaction handle to block the transaction which is on the way of commit,
once we set ->in_commit.

Signed-off-by: default avatarMiao Xie <miaox@cn.fujitsu.com>
Signed-off-by: default avatarJosef Bacik <jbacik@fusionio.com>
parent 4b824906
Loading
Loading
Loading
Loading
+16 −1
Original line number Diff line number Diff line
@@ -50,6 +50,14 @@ static noinline void switch_commit_root(struct btrfs_root *root)
	root->commit_root = btrfs_root_node(root);
}

static inline int can_join_transaction(struct btrfs_transaction *trans,
				       int type)
{
	return !(trans->in_commit &&
		 type != TRANS_JOIN &&
		 type != TRANS_JOIN_NOLOCK);
}

/*
 * either allocate a new transaction or hop into the existing one
 */
@@ -85,6 +93,10 @@ static noinline int join_transaction(struct btrfs_root *root, int type)
			spin_unlock(&fs_info->trans_lock);
			return cur_trans->aborted;
		}
		if (!can_join_transaction(cur_trans, type)) {
			spin_unlock(&fs_info->trans_lock);
			return -EBUSY;
		}
		atomic_inc(&cur_trans->use_count);
		atomic_inc(&cur_trans->num_writers);
		cur_trans->num_joined++;
@@ -360,8 +372,11 @@ start_transaction(struct btrfs_root *root, u64 num_items, int type,

	do {
		ret = join_transaction(root, type);
		if (ret == -EBUSY)
		if (ret == -EBUSY) {
			wait_current_trans(root);
			if (unlikely(type == TRANS_ATTACH))
				ret = -ENOENT;
		}
	} while (ret == -EBUSY);

	if (ret < 0) {