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

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
...@@ -50,6 +50,14 @@ static noinline void switch_commit_root(struct btrfs_root *root) ...@@ -50,6 +50,14 @@ static noinline void switch_commit_root(struct btrfs_root *root)
root->commit_root = btrfs_root_node(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 * 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) ...@@ -85,6 +93,10 @@ static noinline int join_transaction(struct btrfs_root *root, int type)
spin_unlock(&fs_info->trans_lock); spin_unlock(&fs_info->trans_lock);
return cur_trans->aborted; 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->use_count);
atomic_inc(&cur_trans->num_writers); atomic_inc(&cur_trans->num_writers);
cur_trans->num_joined++; cur_trans->num_joined++;
...@@ -360,8 +372,11 @@ start_transaction(struct btrfs_root *root, u64 num_items, int type, ...@@ -360,8 +372,11 @@ start_transaction(struct btrfs_root *root, u64 num_items, int type,
do { do {
ret = join_transaction(root, type); ret = join_transaction(root, type);
if (ret == -EBUSY) if (ret == -EBUSY) {
wait_current_trans(root); wait_current_trans(root);
if (unlikely(type == TRANS_ATTACH))
ret = -ENOENT;
}
} while (ret == -EBUSY); } while (ret == -EBUSY);
if (ret < 0) { if (ret < 0) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment