diff options
-rw-r--r-- | fs/btrfs/ctree.h | 1 | ||||
-rw-r--r-- | fs/btrfs/disk-io.c | 36 | ||||
-rw-r--r-- | fs/btrfs/transaction.c | 157 | ||||
-rw-r--r-- | fs/btrfs/transaction.h | 16 |
4 files changed, 116 insertions, 94 deletions
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 905f7c6c82f3..fd62aa856d1b 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h | |||
@@ -1496,7 +1496,6 @@ struct btrfs_fs_info { | |||
1496 | int closing; | 1496 | int closing; |
1497 | int log_root_recovering; | 1497 | int log_root_recovering; |
1498 | int enospc_unlink; | 1498 | int enospc_unlink; |
1499 | int trans_no_join; | ||
1500 | 1499 | ||
1501 | u64 total_pinned; | 1500 | u64 total_pinned; |
1502 | 1501 | ||
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 885245f5acdc..b9eaa0f21144 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c | |||
@@ -1747,7 +1747,7 @@ static int transaction_kthread(void *arg) | |||
1747 | } | 1747 | } |
1748 | 1748 | ||
1749 | now = get_seconds(); | 1749 | now = get_seconds(); |
1750 | if (!cur->blocked && | 1750 | if (cur->state < TRANS_STATE_BLOCKED && |
1751 | (now < cur->start_time || now - cur->start_time < 30)) { | 1751 | (now < cur->start_time || now - cur->start_time < 30)) { |
1752 | spin_unlock(&root->fs_info->trans_lock); | 1752 | spin_unlock(&root->fs_info->trans_lock); |
1753 | delay = HZ * 5; | 1753 | delay = HZ * 5; |
@@ -2186,7 +2186,6 @@ int open_ctree(struct super_block *sb, | |||
2186 | fs_info->max_inline = 8192 * 1024; | 2186 | fs_info->max_inline = 8192 * 1024; |
2187 | fs_info->metadata_ratio = 0; | 2187 | fs_info->metadata_ratio = 0; |
2188 | fs_info->defrag_inodes = RB_ROOT; | 2188 | fs_info->defrag_inodes = RB_ROOT; |
2189 | fs_info->trans_no_join = 0; | ||
2190 | fs_info->free_chunk_space = 0; | 2189 | fs_info->free_chunk_space = 0; |
2191 | fs_info->tree_mod_log = RB_ROOT; | 2190 | fs_info->tree_mod_log = RB_ROOT; |
2192 | 2191 | ||
@@ -3958,19 +3957,14 @@ void btrfs_cleanup_one_transaction(struct btrfs_transaction *cur_trans, | |||
3958 | btrfs_block_rsv_release(root, &root->fs_info->trans_block_rsv, | 3957 | btrfs_block_rsv_release(root, &root->fs_info->trans_block_rsv, |
3959 | cur_trans->dirty_pages.dirty_bytes); | 3958 | cur_trans->dirty_pages.dirty_bytes); |
3960 | 3959 | ||
3961 | /* FIXME: cleanup wait for commit */ | 3960 | cur_trans->state = TRANS_STATE_COMMIT_START; |
3962 | cur_trans->in_commit = 1; | ||
3963 | cur_trans->blocked = 1; | ||
3964 | wake_up(&root->fs_info->transaction_blocked_wait); | 3961 | wake_up(&root->fs_info->transaction_blocked_wait); |
3965 | 3962 | ||
3966 | btrfs_evict_pending_snapshots(cur_trans); | 3963 | btrfs_evict_pending_snapshots(cur_trans); |
3967 | 3964 | ||
3968 | cur_trans->blocked = 0; | 3965 | cur_trans->state = TRANS_STATE_UNBLOCKED; |
3969 | wake_up(&root->fs_info->transaction_wait); | 3966 | wake_up(&root->fs_info->transaction_wait); |
3970 | 3967 | ||
3971 | cur_trans->commit_done = 1; | ||
3972 | wake_up(&cur_trans->commit_wait); | ||
3973 | |||
3974 | btrfs_destroy_delayed_inodes(root); | 3968 | btrfs_destroy_delayed_inodes(root); |
3975 | btrfs_assert_delayed_root_empty(root); | 3969 | btrfs_assert_delayed_root_empty(root); |
3976 | 3970 | ||
@@ -3979,6 +3973,9 @@ void btrfs_cleanup_one_transaction(struct btrfs_transaction *cur_trans, | |||
3979 | btrfs_destroy_pinned_extent(root, | 3973 | btrfs_destroy_pinned_extent(root, |
3980 | root->fs_info->pinned_extents); | 3974 | root->fs_info->pinned_extents); |
3981 | 3975 | ||
3976 | cur_trans->state =TRANS_STATE_COMPLETED; | ||
3977 | wake_up(&cur_trans->commit_wait); | ||
3978 | |||
3982 | /* | 3979 | /* |
3983 | memset(cur_trans, 0, sizeof(*cur_trans)); | 3980 | memset(cur_trans, 0, sizeof(*cur_trans)); |
3984 | kmem_cache_free(btrfs_transaction_cachep, cur_trans); | 3981 | kmem_cache_free(btrfs_transaction_cachep, cur_trans); |
@@ -4006,25 +4003,23 @@ static int btrfs_cleanup_transaction(struct btrfs_root *root) | |||
4006 | 4003 | ||
4007 | btrfs_destroy_delayed_refs(t, root); | 4004 | btrfs_destroy_delayed_refs(t, root); |
4008 | 4005 | ||
4009 | /* FIXME: cleanup wait for commit */ | 4006 | /* |
4010 | t->in_commit = 1; | 4007 | * FIXME: cleanup wait for commit |
4011 | t->blocked = 1; | 4008 | * We needn't acquire the lock here, because we are during |
4009 | * the umount, there is no other task which will change it. | ||
4010 | */ | ||
4011 | t->state = TRANS_STATE_COMMIT_START; | ||
4012 | smp_mb(); | 4012 | smp_mb(); |
4013 | if (waitqueue_active(&root->fs_info->transaction_blocked_wait)) | 4013 | if (waitqueue_active(&root->fs_info->transaction_blocked_wait)) |
4014 | wake_up(&root->fs_info->transaction_blocked_wait); | 4014 | wake_up(&root->fs_info->transaction_blocked_wait); |
4015 | 4015 | ||
4016 | btrfs_evict_pending_snapshots(t); | 4016 | btrfs_evict_pending_snapshots(t); |
4017 | 4017 | ||
4018 | t->blocked = 0; | 4018 | t->state = TRANS_STATE_UNBLOCKED; |
4019 | smp_mb(); | 4019 | smp_mb(); |
4020 | if (waitqueue_active(&root->fs_info->transaction_wait)) | 4020 | if (waitqueue_active(&root->fs_info->transaction_wait)) |
4021 | wake_up(&root->fs_info->transaction_wait); | 4021 | wake_up(&root->fs_info->transaction_wait); |
4022 | 4022 | ||
4023 | t->commit_done = 1; | ||
4024 | smp_mb(); | ||
4025 | if (waitqueue_active(&t->commit_wait)) | ||
4026 | wake_up(&t->commit_wait); | ||
4027 | |||
4028 | btrfs_destroy_delayed_inodes(root); | 4023 | btrfs_destroy_delayed_inodes(root); |
4029 | btrfs_assert_delayed_root_empty(root); | 4024 | btrfs_assert_delayed_root_empty(root); |
4030 | 4025 | ||
@@ -4036,6 +4031,11 @@ static int btrfs_cleanup_transaction(struct btrfs_root *root) | |||
4036 | btrfs_destroy_pinned_extent(root, | 4031 | btrfs_destroy_pinned_extent(root, |
4037 | root->fs_info->pinned_extents); | 4032 | root->fs_info->pinned_extents); |
4038 | 4033 | ||
4034 | t->state = TRANS_STATE_COMPLETED; | ||
4035 | smp_mb(); | ||
4036 | if (waitqueue_active(&t->commit_wait)) | ||
4037 | wake_up(&t->commit_wait); | ||
4038 | |||
4039 | atomic_set(&t->use_count, 0); | 4039 | atomic_set(&t->use_count, 0); |
4040 | list_del_init(&t->list); | 4040 | list_del_init(&t->list); |
4041 | memset(t, 0, sizeof(*t)); | 4041 | memset(t, 0, sizeof(*t)); |
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index 5e75ff486daf..eec8686416ca 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c | |||
@@ -34,6 +34,29 @@ | |||
34 | 34 | ||
35 | #define BTRFS_ROOT_TRANS_TAG 0 | 35 | #define BTRFS_ROOT_TRANS_TAG 0 |
36 | 36 | ||
37 | static unsigned int btrfs_blocked_trans_types[TRANS_STATE_MAX] = { | ||
38 | [TRANS_STATE_RUNNING] = 0U, | ||
39 | [TRANS_STATE_BLOCKED] = (__TRANS_USERSPACE | | ||
40 | __TRANS_START), | ||
41 | [TRANS_STATE_COMMIT_START] = (__TRANS_USERSPACE | | ||
42 | __TRANS_START | | ||
43 | __TRANS_ATTACH), | ||
44 | [TRANS_STATE_COMMIT_DOING] = (__TRANS_USERSPACE | | ||
45 | __TRANS_START | | ||
46 | __TRANS_ATTACH | | ||
47 | __TRANS_JOIN), | ||
48 | [TRANS_STATE_UNBLOCKED] = (__TRANS_USERSPACE | | ||
49 | __TRANS_START | | ||
50 | __TRANS_ATTACH | | ||
51 | __TRANS_JOIN | | ||
52 | __TRANS_JOIN_NOLOCK), | ||
53 | [TRANS_STATE_COMPLETED] = (__TRANS_USERSPACE | | ||
54 | __TRANS_START | | ||
55 | __TRANS_ATTACH | | ||
56 | __TRANS_JOIN | | ||
57 | __TRANS_JOIN_NOLOCK), | ||
58 | }; | ||
59 | |||
37 | static void put_transaction(struct btrfs_transaction *transaction) | 60 | static void put_transaction(struct btrfs_transaction *transaction) |
38 | { | 61 | { |
39 | WARN_ON(atomic_read(&transaction->use_count) == 0); | 62 | WARN_ON(atomic_read(&transaction->use_count) == 0); |
@@ -50,13 +73,6 @@ static noinline void switch_commit_root(struct btrfs_root *root) | |||
50 | root->commit_root = btrfs_root_node(root); | 73 | root->commit_root = btrfs_root_node(root); |
51 | } | 74 | } |
52 | 75 | ||
53 | static inline int can_join_transaction(struct btrfs_transaction *trans, | ||
54 | unsigned int type) | ||
55 | { | ||
56 | return !(trans->in_commit && | ||
57 | (type & TRANS_EXTWRITERS)); | ||
58 | } | ||
59 | |||
60 | static inline void extwriter_counter_inc(struct btrfs_transaction *trans, | 76 | static inline void extwriter_counter_inc(struct btrfs_transaction *trans, |
61 | unsigned int type) | 77 | unsigned int type) |
62 | { | 78 | { |
@@ -98,26 +114,13 @@ loop: | |||
98 | return -EROFS; | 114 | return -EROFS; |
99 | } | 115 | } |
100 | 116 | ||
101 | if (fs_info->trans_no_join) { | ||
102 | /* | ||
103 | * If we are JOIN_NOLOCK we're already committing a current | ||
104 | * transaction, we just need a handle to deal with something | ||
105 | * when committing the transaction, such as inode cache and | ||
106 | * space cache. It is a special case. | ||
107 | */ | ||
108 | if (type != TRANS_JOIN_NOLOCK) { | ||
109 | spin_unlock(&fs_info->trans_lock); | ||
110 | return -EBUSY; | ||
111 | } | ||
112 | } | ||
113 | |||
114 | cur_trans = fs_info->running_transaction; | 117 | cur_trans = fs_info->running_transaction; |
115 | if (cur_trans) { | 118 | if (cur_trans) { |
116 | if (cur_trans->aborted) { | 119 | if (cur_trans->aborted) { |
117 | spin_unlock(&fs_info->trans_lock); | 120 | spin_unlock(&fs_info->trans_lock); |
118 | return cur_trans->aborted; | 121 | return cur_trans->aborted; |
119 | } | 122 | } |
120 | if (!can_join_transaction(cur_trans, type)) { | 123 | if (btrfs_blocked_trans_types[cur_trans->state] & type) { |
121 | spin_unlock(&fs_info->trans_lock); | 124 | spin_unlock(&fs_info->trans_lock); |
122 | return -EBUSY; | 125 | return -EBUSY; |
123 | } | 126 | } |
@@ -136,6 +139,12 @@ loop: | |||
136 | if (type == TRANS_ATTACH) | 139 | if (type == TRANS_ATTACH) |
137 | return -ENOENT; | 140 | return -ENOENT; |
138 | 141 | ||
142 | /* | ||
143 | * JOIN_NOLOCK only happens during the transaction commit, so | ||
144 | * it is impossible that ->running_transaction is NULL | ||
145 | */ | ||
146 | BUG_ON(type == TRANS_JOIN_NOLOCK); | ||
147 | |||
139 | cur_trans = kmem_cache_alloc(btrfs_transaction_cachep, GFP_NOFS); | 148 | cur_trans = kmem_cache_alloc(btrfs_transaction_cachep, GFP_NOFS); |
140 | if (!cur_trans) | 149 | if (!cur_trans) |
141 | return -ENOMEM; | 150 | return -ENOMEM; |
@@ -144,7 +153,7 @@ loop: | |||
144 | if (fs_info->running_transaction) { | 153 | if (fs_info->running_transaction) { |
145 | /* | 154 | /* |
146 | * someone started a transaction after we unlocked. Make sure | 155 | * someone started a transaction after we unlocked. Make sure |
147 | * to redo the trans_no_join checks above | 156 | * to redo the checks above |
148 | */ | 157 | */ |
149 | kmem_cache_free(btrfs_transaction_cachep, cur_trans); | 158 | kmem_cache_free(btrfs_transaction_cachep, cur_trans); |
150 | goto loop; | 159 | goto loop; |
@@ -158,14 +167,12 @@ loop: | |||
158 | extwriter_counter_init(cur_trans, type); | 167 | extwriter_counter_init(cur_trans, type); |
159 | init_waitqueue_head(&cur_trans->writer_wait); | 168 | init_waitqueue_head(&cur_trans->writer_wait); |
160 | init_waitqueue_head(&cur_trans->commit_wait); | 169 | init_waitqueue_head(&cur_trans->commit_wait); |
161 | cur_trans->in_commit = 0; | 170 | cur_trans->state = TRANS_STATE_RUNNING; |
162 | cur_trans->blocked = 0; | ||
163 | /* | 171 | /* |
164 | * One for this trans handle, one so it will live on until we | 172 | * One for this trans handle, one so it will live on until we |
165 | * commit the transaction. | 173 | * commit the transaction. |
166 | */ | 174 | */ |
167 | atomic_set(&cur_trans->use_count, 2); | 175 | atomic_set(&cur_trans->use_count, 2); |
168 | cur_trans->commit_done = 0; | ||
169 | cur_trans->start_time = get_seconds(); | 176 | cur_trans->start_time = get_seconds(); |
170 | 177 | ||
171 | cur_trans->delayed_refs.root = RB_ROOT; | 178 | cur_trans->delayed_refs.root = RB_ROOT; |
@@ -188,7 +195,6 @@ loop: | |||
188 | "creating a fresh transaction\n"); | 195 | "creating a fresh transaction\n"); |
189 | atomic64_set(&fs_info->tree_mod_seq, 0); | 196 | atomic64_set(&fs_info->tree_mod_seq, 0); |
190 | 197 | ||
191 | spin_lock_init(&cur_trans->commit_lock); | ||
192 | spin_lock_init(&cur_trans->delayed_refs.lock); | 198 | spin_lock_init(&cur_trans->delayed_refs.lock); |
193 | atomic_set(&cur_trans->delayed_refs.procs_running_refs, 0); | 199 | atomic_set(&cur_trans->delayed_refs.procs_running_refs, 0); |
194 | atomic_set(&cur_trans->delayed_refs.ref_seq, 0); | 200 | atomic_set(&cur_trans->delayed_refs.ref_seq, 0); |
@@ -293,6 +299,12 @@ int btrfs_record_root_in_trans(struct btrfs_trans_handle *trans, | |||
293 | return 0; | 299 | return 0; |
294 | } | 300 | } |
295 | 301 | ||
302 | static inline int is_transaction_blocked(struct btrfs_transaction *trans) | ||
303 | { | ||
304 | return (trans->state >= TRANS_STATE_BLOCKED && | ||
305 | trans->state < TRANS_STATE_UNBLOCKED); | ||
306 | } | ||
307 | |||
296 | /* wait for commit against the current transaction to become unblocked | 308 | /* wait for commit against the current transaction to become unblocked |
297 | * when this is done, it is safe to start a new transaction, but the current | 309 | * when this is done, it is safe to start a new transaction, but the current |
298 | * transaction might not be fully on disk. | 310 | * transaction might not be fully on disk. |
@@ -303,12 +315,12 @@ static void wait_current_trans(struct btrfs_root *root) | |||
303 | 315 | ||
304 | spin_lock(&root->fs_info->trans_lock); | 316 | spin_lock(&root->fs_info->trans_lock); |
305 | cur_trans = root->fs_info->running_transaction; | 317 | cur_trans = root->fs_info->running_transaction; |
306 | if (cur_trans && cur_trans->blocked) { | 318 | if (cur_trans && is_transaction_blocked(cur_trans)) { |
307 | atomic_inc(&cur_trans->use_count); | 319 | atomic_inc(&cur_trans->use_count); |
308 | spin_unlock(&root->fs_info->trans_lock); | 320 | spin_unlock(&root->fs_info->trans_lock); |
309 | 321 | ||
310 | wait_event(root->fs_info->transaction_wait, | 322 | wait_event(root->fs_info->transaction_wait, |
311 | !cur_trans->blocked); | 323 | cur_trans->state >= TRANS_STATE_UNBLOCKED); |
312 | put_transaction(cur_trans); | 324 | put_transaction(cur_trans); |
313 | } else { | 325 | } else { |
314 | spin_unlock(&root->fs_info->trans_lock); | 326 | spin_unlock(&root->fs_info->trans_lock); |
@@ -432,7 +444,8 @@ again: | |||
432 | INIT_LIST_HEAD(&h->new_bgs); | 444 | INIT_LIST_HEAD(&h->new_bgs); |
433 | 445 | ||
434 | smp_mb(); | 446 | smp_mb(); |
435 | if (cur_trans->blocked && may_wait_transaction(root, type)) { | 447 | if (cur_trans->state >= TRANS_STATE_BLOCKED && |
448 | may_wait_transaction(root, type)) { | ||
436 | btrfs_commit_transaction(h, root); | 449 | btrfs_commit_transaction(h, root); |
437 | goto again; | 450 | goto again; |
438 | } | 451 | } |
@@ -536,7 +549,7 @@ btrfs_attach_transaction_barrier(struct btrfs_root *root) | |||
536 | static noinline void wait_for_commit(struct btrfs_root *root, | 549 | static noinline void wait_for_commit(struct btrfs_root *root, |
537 | struct btrfs_transaction *commit) | 550 | struct btrfs_transaction *commit) |
538 | { | 551 | { |
539 | wait_event(commit->commit_wait, commit->commit_done); | 552 | wait_event(commit->commit_wait, commit->state == TRANS_STATE_COMPLETED); |
540 | } | 553 | } |
541 | 554 | ||
542 | int btrfs_wait_for_commit(struct btrfs_root *root, u64 transid) | 555 | int btrfs_wait_for_commit(struct btrfs_root *root, u64 transid) |
@@ -572,8 +585,8 @@ int btrfs_wait_for_commit(struct btrfs_root *root, u64 transid) | |||
572 | spin_lock(&root->fs_info->trans_lock); | 585 | spin_lock(&root->fs_info->trans_lock); |
573 | list_for_each_entry_reverse(t, &root->fs_info->trans_list, | 586 | list_for_each_entry_reverse(t, &root->fs_info->trans_list, |
574 | list) { | 587 | list) { |
575 | if (t->in_commit) { | 588 | if (t->state >= TRANS_STATE_COMMIT_START) { |
576 | if (t->commit_done) | 589 | if (t->state == TRANS_STATE_COMPLETED) |
577 | break; | 590 | break; |
578 | cur_trans = t; | 591 | cur_trans = t; |
579 | atomic_inc(&cur_trans->use_count); | 592 | atomic_inc(&cur_trans->use_count); |
@@ -614,7 +627,8 @@ int btrfs_should_end_transaction(struct btrfs_trans_handle *trans, | |||
614 | int err; | 627 | int err; |
615 | 628 | ||
616 | smp_mb(); | 629 | smp_mb(); |
617 | if (cur_trans->blocked || cur_trans->delayed_refs.flushing) | 630 | if (cur_trans->state >= TRANS_STATE_BLOCKED || |
631 | cur_trans->delayed_refs.flushing) | ||
618 | return 1; | 632 | return 1; |
619 | 633 | ||
620 | updates = trans->delayed_ref_updates; | 634 | updates = trans->delayed_ref_updates; |
@@ -682,12 +696,15 @@ static int __btrfs_end_transaction(struct btrfs_trans_handle *trans, | |||
682 | btrfs_create_pending_block_groups(trans, root); | 696 | btrfs_create_pending_block_groups(trans, root); |
683 | 697 | ||
684 | if (lock && !atomic_read(&root->fs_info->open_ioctl_trans) && | 698 | if (lock && !atomic_read(&root->fs_info->open_ioctl_trans) && |
685 | should_end_transaction(trans, root)) { | 699 | should_end_transaction(trans, root) && |
686 | trans->transaction->blocked = 1; | 700 | ACCESS_ONCE(cur_trans->state) == TRANS_STATE_RUNNING) { |
687 | smp_wmb(); | 701 | spin_lock(&info->trans_lock); |
702 | if (cur_trans->state == TRANS_STATE_RUNNING) | ||
703 | cur_trans->state = TRANS_STATE_BLOCKED; | ||
704 | spin_unlock(&info->trans_lock); | ||
688 | } | 705 | } |
689 | 706 | ||
690 | if (lock && cur_trans->blocked && !cur_trans->in_commit) { | 707 | if (lock && ACCESS_ONCE(cur_trans->state) == TRANS_STATE_BLOCKED) { |
691 | if (throttle) { | 708 | if (throttle) { |
692 | /* | 709 | /* |
693 | * We may race with somebody else here so end up having | 710 | * We may race with somebody else here so end up having |
@@ -1343,20 +1360,26 @@ static void update_super_roots(struct btrfs_root *root) | |||
1343 | 1360 | ||
1344 | int btrfs_transaction_in_commit(struct btrfs_fs_info *info) | 1361 | int btrfs_transaction_in_commit(struct btrfs_fs_info *info) |
1345 | { | 1362 | { |
1363 | struct btrfs_transaction *trans; | ||
1346 | int ret = 0; | 1364 | int ret = 0; |
1365 | |||
1347 | spin_lock(&info->trans_lock); | 1366 | spin_lock(&info->trans_lock); |
1348 | if (info->running_transaction) | 1367 | trans = info->running_transaction; |
1349 | ret = info->running_transaction->in_commit; | 1368 | if (trans) |
1369 | ret = (trans->state >= TRANS_STATE_COMMIT_START); | ||
1350 | spin_unlock(&info->trans_lock); | 1370 | spin_unlock(&info->trans_lock); |
1351 | return ret; | 1371 | return ret; |
1352 | } | 1372 | } |
1353 | 1373 | ||
1354 | int btrfs_transaction_blocked(struct btrfs_fs_info *info) | 1374 | int btrfs_transaction_blocked(struct btrfs_fs_info *info) |
1355 | { | 1375 | { |
1376 | struct btrfs_transaction *trans; | ||
1356 | int ret = 0; | 1377 | int ret = 0; |
1378 | |||
1357 | spin_lock(&info->trans_lock); | 1379 | spin_lock(&info->trans_lock); |
1358 | if (info->running_transaction) | 1380 | trans = info->running_transaction; |
1359 | ret = info->running_transaction->blocked; | 1381 | if (trans) |
1382 | ret = is_transaction_blocked(trans); | ||
1360 | spin_unlock(&info->trans_lock); | 1383 | spin_unlock(&info->trans_lock); |
1361 | return ret; | 1384 | return ret; |
1362 | } | 1385 | } |
@@ -1368,7 +1391,8 @@ int btrfs_transaction_blocked(struct btrfs_fs_info *info) | |||
1368 | static void wait_current_trans_commit_start(struct btrfs_root *root, | 1391 | static void wait_current_trans_commit_start(struct btrfs_root *root, |
1369 | struct btrfs_transaction *trans) | 1392 | struct btrfs_transaction *trans) |
1370 | { | 1393 | { |
1371 | wait_event(root->fs_info->transaction_blocked_wait, trans->in_commit); | 1394 | wait_event(root->fs_info->transaction_blocked_wait, |
1395 | trans->state >= TRANS_STATE_COMMIT_START); | ||
1372 | } | 1396 | } |
1373 | 1397 | ||
1374 | /* | 1398 | /* |
@@ -1379,7 +1403,7 @@ static void wait_current_trans_commit_start_and_unblock(struct btrfs_root *root, | |||
1379 | struct btrfs_transaction *trans) | 1403 | struct btrfs_transaction *trans) |
1380 | { | 1404 | { |
1381 | wait_event(root->fs_info->transaction_wait, | 1405 | wait_event(root->fs_info->transaction_wait, |
1382 | trans->commit_done || (trans->in_commit && !trans->blocked)); | 1406 | trans->state >= TRANS_STATE_UNBLOCKED); |
1383 | } | 1407 | } |
1384 | 1408 | ||
1385 | /* | 1409 | /* |
@@ -1484,18 +1508,22 @@ static void cleanup_transaction(struct btrfs_trans_handle *trans, | |||
1484 | 1508 | ||
1485 | list_del_init(&cur_trans->list); | 1509 | list_del_init(&cur_trans->list); |
1486 | if (cur_trans == root->fs_info->running_transaction) { | 1510 | if (cur_trans == root->fs_info->running_transaction) { |
1487 | root->fs_info->trans_no_join = 1; | 1511 | cur_trans->state = TRANS_STATE_COMMIT_DOING; |
1488 | spin_unlock(&root->fs_info->trans_lock); | 1512 | spin_unlock(&root->fs_info->trans_lock); |
1489 | wait_event(cur_trans->writer_wait, | 1513 | wait_event(cur_trans->writer_wait, |
1490 | atomic_read(&cur_trans->num_writers) == 1); | 1514 | atomic_read(&cur_trans->num_writers) == 1); |
1491 | 1515 | ||
1492 | spin_lock(&root->fs_info->trans_lock); | 1516 | spin_lock(&root->fs_info->trans_lock); |
1493 | root->fs_info->running_transaction = NULL; | ||
1494 | } | 1517 | } |
1495 | spin_unlock(&root->fs_info->trans_lock); | 1518 | spin_unlock(&root->fs_info->trans_lock); |
1496 | 1519 | ||
1497 | btrfs_cleanup_one_transaction(trans->transaction, root); | 1520 | btrfs_cleanup_one_transaction(trans->transaction, root); |
1498 | 1521 | ||
1522 | spin_lock(&root->fs_info->trans_lock); | ||
1523 | if (cur_trans == root->fs_info->running_transaction) | ||
1524 | root->fs_info->running_transaction = NULL; | ||
1525 | spin_unlock(&root->fs_info->trans_lock); | ||
1526 | |||
1499 | put_transaction(cur_trans); | 1527 | put_transaction(cur_trans); |
1500 | put_transaction(cur_trans); | 1528 | put_transaction(cur_trans); |
1501 | 1529 | ||
@@ -1507,10 +1535,6 @@ static void cleanup_transaction(struct btrfs_trans_handle *trans, | |||
1507 | current->journal_info = NULL; | 1535 | current->journal_info = NULL; |
1508 | 1536 | ||
1509 | kmem_cache_free(btrfs_trans_handle_cachep, trans); | 1537 | kmem_cache_free(btrfs_trans_handle_cachep, trans); |
1510 | |||
1511 | spin_lock(&root->fs_info->trans_lock); | ||
1512 | root->fs_info->trans_no_join = 0; | ||
1513 | spin_unlock(&root->fs_info->trans_lock); | ||
1514 | } | 1538 | } |
1515 | 1539 | ||
1516 | static int btrfs_flush_all_pending_stuffs(struct btrfs_trans_handle *trans, | 1540 | static int btrfs_flush_all_pending_stuffs(struct btrfs_trans_handle *trans, |
@@ -1554,13 +1578,6 @@ static inline void btrfs_wait_delalloc_flush(struct btrfs_fs_info *fs_info) | |||
1554 | btrfs_wait_all_ordered_extents(fs_info, 1); | 1578 | btrfs_wait_all_ordered_extents(fs_info, 1); |
1555 | } | 1579 | } |
1556 | 1580 | ||
1557 | /* | ||
1558 | * btrfs_transaction state sequence: | ||
1559 | * in_commit = 0, blocked = 0 (initial) | ||
1560 | * in_commit = 1, blocked = 1 | ||
1561 | * blocked = 0 | ||
1562 | * commit_done = 1 | ||
1563 | */ | ||
1564 | int btrfs_commit_transaction(struct btrfs_trans_handle *trans, | 1581 | int btrfs_commit_transaction(struct btrfs_trans_handle *trans, |
1565 | struct btrfs_root *root) | 1582 | struct btrfs_root *root) |
1566 | { | 1583 | { |
@@ -1615,9 +1632,9 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, | |||
1615 | return ret; | 1632 | return ret; |
1616 | } | 1633 | } |
1617 | 1634 | ||
1618 | spin_lock(&cur_trans->commit_lock); | 1635 | spin_lock(&root->fs_info->trans_lock); |
1619 | if (cur_trans->in_commit) { | 1636 | if (cur_trans->state >= TRANS_STATE_COMMIT_START) { |
1620 | spin_unlock(&cur_trans->commit_lock); | 1637 | spin_unlock(&root->fs_info->trans_lock); |
1621 | atomic_inc(&cur_trans->use_count); | 1638 | atomic_inc(&cur_trans->use_count); |
1622 | ret = btrfs_end_transaction(trans, root); | 1639 | ret = btrfs_end_transaction(trans, root); |
1623 | 1640 | ||
@@ -1628,16 +1645,13 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, | |||
1628 | return ret; | 1645 | return ret; |
1629 | } | 1646 | } |
1630 | 1647 | ||
1631 | trans->transaction->in_commit = 1; | 1648 | cur_trans->state = TRANS_STATE_COMMIT_START; |
1632 | trans->transaction->blocked = 1; | ||
1633 | spin_unlock(&cur_trans->commit_lock); | ||
1634 | wake_up(&root->fs_info->transaction_blocked_wait); | 1649 | wake_up(&root->fs_info->transaction_blocked_wait); |
1635 | 1650 | ||
1636 | spin_lock(&root->fs_info->trans_lock); | ||
1637 | if (cur_trans->list.prev != &root->fs_info->trans_list) { | 1651 | if (cur_trans->list.prev != &root->fs_info->trans_list) { |
1638 | prev_trans = list_entry(cur_trans->list.prev, | 1652 | prev_trans = list_entry(cur_trans->list.prev, |
1639 | struct btrfs_transaction, list); | 1653 | struct btrfs_transaction, list); |
1640 | if (!prev_trans->commit_done) { | 1654 | if (prev_trans->state != TRANS_STATE_COMPLETED) { |
1641 | atomic_inc(&prev_trans->use_count); | 1655 | atomic_inc(&prev_trans->use_count); |
1642 | spin_unlock(&root->fs_info->trans_lock); | 1656 | spin_unlock(&root->fs_info->trans_lock); |
1643 | 1657 | ||
@@ -1673,10 +1687,10 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, | |||
1673 | /* | 1687 | /* |
1674 | * Ok now we need to make sure to block out any other joins while we | 1688 | * Ok now we need to make sure to block out any other joins while we |
1675 | * commit the transaction. We could have started a join before setting | 1689 | * commit the transaction. We could have started a join before setting |
1676 | * no_join so make sure to wait for num_writers to == 1 again. | 1690 | * COMMIT_DOING so make sure to wait for num_writers to == 1 again. |
1677 | */ | 1691 | */ |
1678 | spin_lock(&root->fs_info->trans_lock); | 1692 | spin_lock(&root->fs_info->trans_lock); |
1679 | root->fs_info->trans_no_join = 1; | 1693 | cur_trans->state = TRANS_STATE_COMMIT_DOING; |
1680 | spin_unlock(&root->fs_info->trans_lock); | 1694 | spin_unlock(&root->fs_info->trans_lock); |
1681 | wait_event(cur_trans->writer_wait, | 1695 | wait_event(cur_trans->writer_wait, |
1682 | atomic_read(&cur_trans->num_writers) == 1); | 1696 | atomic_read(&cur_trans->num_writers) == 1); |
@@ -1803,10 +1817,9 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, | |||
1803 | memcpy(root->fs_info->super_for_commit, root->fs_info->super_copy, | 1817 | memcpy(root->fs_info->super_for_commit, root->fs_info->super_copy, |
1804 | sizeof(*root->fs_info->super_copy)); | 1818 | sizeof(*root->fs_info->super_copy)); |
1805 | 1819 | ||
1806 | trans->transaction->blocked = 0; | ||
1807 | spin_lock(&root->fs_info->trans_lock); | 1820 | spin_lock(&root->fs_info->trans_lock); |
1821 | cur_trans->state = TRANS_STATE_UNBLOCKED; | ||
1808 | root->fs_info->running_transaction = NULL; | 1822 | root->fs_info->running_transaction = NULL; |
1809 | root->fs_info->trans_no_join = 0; | ||
1810 | spin_unlock(&root->fs_info->trans_lock); | 1823 | spin_unlock(&root->fs_info->trans_lock); |
1811 | mutex_unlock(&root->fs_info->reloc_mutex); | 1824 | mutex_unlock(&root->fs_info->reloc_mutex); |
1812 | 1825 | ||
@@ -1834,10 +1847,12 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, | |||
1834 | 1847 | ||
1835 | btrfs_finish_extent_commit(trans, root); | 1848 | btrfs_finish_extent_commit(trans, root); |
1836 | 1849 | ||
1837 | cur_trans->commit_done = 1; | ||
1838 | |||
1839 | root->fs_info->last_trans_committed = cur_trans->transid; | 1850 | root->fs_info->last_trans_committed = cur_trans->transid; |
1840 | 1851 | /* | |
1852 | * We needn't acquire the lock here because there is no other task | ||
1853 | * which can change it. | ||
1854 | */ | ||
1855 | cur_trans->state = TRANS_STATE_COMPLETED; | ||
1841 | wake_up(&cur_trans->commit_wait); | 1856 | wake_up(&cur_trans->commit_wait); |
1842 | 1857 | ||
1843 | spin_lock(&root->fs_info->trans_lock); | 1858 | spin_lock(&root->fs_info->trans_lock); |
diff --git a/fs/btrfs/transaction.h b/fs/btrfs/transaction.h index 0fc45e2a5139..66d2a6ccbf05 100644 --- a/fs/btrfs/transaction.h +++ b/fs/btrfs/transaction.h | |||
@@ -22,6 +22,16 @@ | |||
22 | #include "delayed-ref.h" | 22 | #include "delayed-ref.h" |
23 | #include "ctree.h" | 23 | #include "ctree.h" |
24 | 24 | ||
25 | enum btrfs_trans_state { | ||
26 | TRANS_STATE_RUNNING = 0, | ||
27 | TRANS_STATE_BLOCKED = 1, | ||
28 | TRANS_STATE_COMMIT_START = 2, | ||
29 | TRANS_STATE_COMMIT_DOING = 3, | ||
30 | TRANS_STATE_UNBLOCKED = 4, | ||
31 | TRANS_STATE_COMPLETED = 5, | ||
32 | TRANS_STATE_MAX = 6, | ||
33 | }; | ||
34 | |||
25 | struct btrfs_transaction { | 35 | struct btrfs_transaction { |
26 | u64 transid; | 36 | u64 transid; |
27 | /* | 37 | /* |
@@ -37,10 +47,8 @@ struct btrfs_transaction { | |||
37 | atomic_t num_writers; | 47 | atomic_t num_writers; |
38 | atomic_t use_count; | 48 | atomic_t use_count; |
39 | 49 | ||
40 | spinlock_t commit_lock; | 50 | /* Be protected by fs_info->trans_lock when we want to change it. */ |
41 | int in_commit; | 51 | enum btrfs_trans_state state; |
42 | int commit_done; | ||
43 | int blocked; | ||
44 | struct list_head list; | 52 | struct list_head list; |
45 | struct extent_io_tree dirty_pages; | 53 | struct extent_io_tree dirty_pages; |
46 | unsigned long start_time; | 54 | unsigned long start_time; |