diff options
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) { |