diff options
author | Miao Xie <miaox@cn.fujitsu.com> | 2013-02-20 04:16:24 -0500 |
---|---|---|
committer | Josef Bacik <jbacik@fusionio.com> | 2013-02-20 13:00:03 -0500 |
commit | 178260b2c14969f29ba39a78df74ed485abc6203 (patch) | |
tree | 56bf3f573112f898f3439d6e0a11d76fbb925bb0 /fs/btrfs | |
parent | 4b82490649f5c8ecbf888752c325ea68831c497e (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.c | 17 |
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 | ||
53 | static 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) { |