aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs
diff options
context:
space:
mode:
authorMiao Xie <miaox@cn.fujitsu.com>2013-02-20 04:16:24 -0500
committerJosef Bacik <jbacik@fusionio.com>2013-02-20 13:00:03 -0500
commit178260b2c14969f29ba39a78df74ed485abc6203 (patch)
tree56bf3f573112f898f3439d6e0a11d76fbb925bb0 /fs/btrfs
parent4b82490649f5c8ecbf888752c325ea68831c497e (diff)
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: Miao Xie <miaox@cn.fujitsu.com> Signed-off-by: Josef Bacik <jbacik@fusionio.com>
Diffstat (limited to 'fs/btrfs')
-rw-r--r--fs/btrfs/transaction.c17
1 files changed, 16 insertions, 1 deletions
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c
index 425d5b57d377..5767ea1c0150 100644
--- a/fs/btrfs/transaction.c
+++ b/fs/btrfs/transaction.c
@@ -50,6 +50,14 @@ static noinline void switch_commit_root(struct btrfs_root *root)
50 root->commit_root = btrfs_root_node(root); 50 root->commit_root = btrfs_root_node(root);
51} 51}
52 52
53static inline int can_join_transaction(struct btrfs_transaction *trans,
54 int type)
55{
56 return !(trans->in_commit &&
57 type != TRANS_JOIN &&
58 type != TRANS_JOIN_NOLOCK);
59}
60
53/* 61/*
54 * either allocate a new transaction or hop into the existing one 62 * either allocate a new transaction or hop into the existing one
55 */ 63 */
@@ -85,6 +93,10 @@ loop:
85 spin_unlock(&fs_info->trans_lock); 93 spin_unlock(&fs_info->trans_lock);
86 return cur_trans->aborted; 94 return cur_trans->aborted;
87 } 95 }
96 if (!can_join_transaction(cur_trans, type)) {
97 spin_unlock(&fs_info->trans_lock);
98 return -EBUSY;
99 }
88 atomic_inc(&cur_trans->use_count); 100 atomic_inc(&cur_trans->use_count);
89 atomic_inc(&cur_trans->num_writers); 101 atomic_inc(&cur_trans->num_writers);
90 cur_trans->num_joined++; 102 cur_trans->num_joined++;
@@ -360,8 +372,11 @@ again:
360 372
361 do { 373 do {
362 ret = join_transaction(root, type); 374 ret = join_transaction(root, type);
363 if (ret == -EBUSY) 375 if (ret == -EBUSY) {
364 wait_current_trans(root); 376 wait_current_trans(root);
377 if (unlikely(type == TRANS_ATTACH))
378 ret = -ENOENT;
379 }
365 } while (ret == -EBUSY); 380 } while (ret == -EBUSY);
366 381
367 if (ret < 0) { 382 if (ret < 0) {