diff options
| -rw-r--r-- | fs/btrfs/ctree.c | 17 | ||||
| -rw-r--r-- | fs/btrfs/ctree.h | 2 | ||||
| -rw-r--r-- | fs/btrfs/transaction.c | 8 |
3 files changed, 26 insertions, 1 deletions
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index 0fe615e4ea38..dede441bdeee 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c | |||
| @@ -514,10 +514,25 @@ static inline int should_cow_block(struct btrfs_trans_handle *trans, | |||
| 514 | struct btrfs_root *root, | 514 | struct btrfs_root *root, |
| 515 | struct extent_buffer *buf) | 515 | struct extent_buffer *buf) |
| 516 | { | 516 | { |
| 517 | /* ensure we can see the force_cow */ | ||
| 518 | smp_rmb(); | ||
| 519 | |||
| 520 | /* | ||
| 521 | * We do not need to cow a block if | ||
| 522 | * 1) this block is not created or changed in this transaction; | ||
| 523 | * 2) this block does not belong to TREE_RELOC tree; | ||
| 524 | * 3) the root is not forced COW. | ||
| 525 | * | ||
| 526 | * What is forced COW: | ||
| 527 | * when we create snapshot during commiting the transaction, | ||
| 528 | * after we've finished coping src root, we must COW the shared | ||
| 529 | * block to ensure the metadata consistency. | ||
| 530 | */ | ||
| 517 | if (btrfs_header_generation(buf) == trans->transid && | 531 | if (btrfs_header_generation(buf) == trans->transid && |
| 518 | !btrfs_header_flag(buf, BTRFS_HEADER_FLAG_WRITTEN) && | 532 | !btrfs_header_flag(buf, BTRFS_HEADER_FLAG_WRITTEN) && |
| 519 | !(root->root_key.objectid != BTRFS_TREE_RELOC_OBJECTID && | 533 | !(root->root_key.objectid != BTRFS_TREE_RELOC_OBJECTID && |
| 520 | btrfs_header_flag(buf, BTRFS_HEADER_FLAG_RELOC))) | 534 | btrfs_header_flag(buf, BTRFS_HEADER_FLAG_RELOC)) && |
| 535 | !root->force_cow) | ||
| 521 | return 0; | 536 | return 0; |
| 522 | return 1; | 537 | return 1; |
| 523 | } | 538 | } |
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index b9ba59ff9292..b1cb3c052484 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h | |||
| @@ -1271,6 +1271,8 @@ struct btrfs_root { | |||
| 1271 | * for stat. It may be used for more later | 1271 | * for stat. It may be used for more later |
| 1272 | */ | 1272 | */ |
| 1273 | dev_t anon_dev; | 1273 | dev_t anon_dev; |
| 1274 | |||
| 1275 | int force_cow; | ||
| 1274 | }; | 1276 | }; |
| 1275 | 1277 | ||
| 1276 | struct btrfs_ioctl_defrag_range_args { | 1278 | struct btrfs_ioctl_defrag_range_args { |
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index 6a0574e923bc..81376d94cd3c 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c | |||
| @@ -785,6 +785,10 @@ static noinline int commit_fs_roots(struct btrfs_trans_handle *trans, | |||
| 785 | 785 | ||
| 786 | btrfs_save_ino_cache(root, trans); | 786 | btrfs_save_ino_cache(root, trans); |
| 787 | 787 | ||
| 788 | /* see comments in should_cow_block() */ | ||
| 789 | root->force_cow = 0; | ||
| 790 | smp_wmb(); | ||
| 791 | |||
| 788 | if (root->commit_root != root->node) { | 792 | if (root->commit_root != root->node) { |
| 789 | mutex_lock(&root->fs_commit_mutex); | 793 | mutex_lock(&root->fs_commit_mutex); |
| 790 | switch_commit_root(root); | 794 | switch_commit_root(root); |
| @@ -947,6 +951,10 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, | |||
| 947 | btrfs_tree_unlock(old); | 951 | btrfs_tree_unlock(old); |
| 948 | free_extent_buffer(old); | 952 | free_extent_buffer(old); |
| 949 | 953 | ||
| 954 | /* see comments in should_cow_block() */ | ||
| 955 | root->force_cow = 1; | ||
| 956 | smp_wmb(); | ||
| 957 | |||
| 950 | btrfs_set_root_node(new_root_item, tmp); | 958 | btrfs_set_root_node(new_root_item, tmp); |
| 951 | /* record when the snapshot was created in key.offset */ | 959 | /* record when the snapshot was created in key.offset */ |
| 952 | key.offset = trans->transid; | 960 | key.offset = trans->transid; |
