diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2016-10-28 13:07:35 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-10-28 13:07:35 -0400 |
commit | f6167514c819cb7794e60cf36b9466598a789013 (patch) | |
tree | 53cd063b30ad8314d57f1a58a4c2d27b968a55f2 | |
parent | 2cd0b50a189febfe1855b13be98297a621864741 (diff) | |
parent | 570dd45042a7c8a7aba1ee029c5dd0f5ccf41b9b (diff) |
Merge branch 'for-linus-4.9' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux-btrfs
Pull btrfs fixes from Chris Mason:
"My patch fixes the btrfs list_head abuse that we tracked down during
Dave Jones' memory corruption investigation. With both Jens and my
patches in place, I'm no longer able to trigger problems.
Filipe is fixing a difficult old bug between snapshots, balance and
send. Dave is cooking a few more for the next rc, but these are tested
and ready"
* 'for-linus-4.9' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux-btrfs:
btrfs: fix races on root_log_ctx lists
btrfs: fix incremental send failure caused by balance
-rw-r--r-- | fs/btrfs/send.c | 58 | ||||
-rw-r--r-- | fs/btrfs/tree-log.c | 20 |
2 files changed, 64 insertions, 14 deletions
diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c index 01bc36cec26e..71261b459863 100644 --- a/fs/btrfs/send.c +++ b/fs/btrfs/send.c | |||
@@ -5805,6 +5805,64 @@ static int changed_extent(struct send_ctx *sctx, | |||
5805 | int ret = 0; | 5805 | int ret = 0; |
5806 | 5806 | ||
5807 | if (sctx->cur_ino != sctx->cmp_key->objectid) { | 5807 | if (sctx->cur_ino != sctx->cmp_key->objectid) { |
5808 | |||
5809 | if (result == BTRFS_COMPARE_TREE_CHANGED) { | ||
5810 | struct extent_buffer *leaf_l; | ||
5811 | struct extent_buffer *leaf_r; | ||
5812 | struct btrfs_file_extent_item *ei_l; | ||
5813 | struct btrfs_file_extent_item *ei_r; | ||
5814 | |||
5815 | leaf_l = sctx->left_path->nodes[0]; | ||
5816 | leaf_r = sctx->right_path->nodes[0]; | ||
5817 | ei_l = btrfs_item_ptr(leaf_l, | ||
5818 | sctx->left_path->slots[0], | ||
5819 | struct btrfs_file_extent_item); | ||
5820 | ei_r = btrfs_item_ptr(leaf_r, | ||
5821 | sctx->right_path->slots[0], | ||
5822 | struct btrfs_file_extent_item); | ||
5823 | |||
5824 | /* | ||
5825 | * We may have found an extent item that has changed | ||
5826 | * only its disk_bytenr field and the corresponding | ||
5827 | * inode item was not updated. This case happens due to | ||
5828 | * very specific timings during relocation when a leaf | ||
5829 | * that contains file extent items is COWed while | ||
5830 | * relocation is ongoing and its in the stage where it | ||
5831 | * updates data pointers. So when this happens we can | ||
5832 | * safely ignore it since we know it's the same extent, | ||
5833 | * but just at different logical and physical locations | ||
5834 | * (when an extent is fully replaced with a new one, we | ||
5835 | * know the generation number must have changed too, | ||
5836 | * since snapshot creation implies committing the current | ||
5837 | * transaction, and the inode item must have been updated | ||
5838 | * as well). | ||
5839 | * This replacement of the disk_bytenr happens at | ||
5840 | * relocation.c:replace_file_extents() through | ||
5841 | * relocation.c:btrfs_reloc_cow_block(). | ||
5842 | */ | ||
5843 | if (btrfs_file_extent_generation(leaf_l, ei_l) == | ||
5844 | btrfs_file_extent_generation(leaf_r, ei_r) && | ||
5845 | btrfs_file_extent_ram_bytes(leaf_l, ei_l) == | ||
5846 | btrfs_file_extent_ram_bytes(leaf_r, ei_r) && | ||
5847 | btrfs_file_extent_compression(leaf_l, ei_l) == | ||
5848 | btrfs_file_extent_compression(leaf_r, ei_r) && | ||
5849 | btrfs_file_extent_encryption(leaf_l, ei_l) == | ||
5850 | btrfs_file_extent_encryption(leaf_r, ei_r) && | ||
5851 | btrfs_file_extent_other_encoding(leaf_l, ei_l) == | ||
5852 | btrfs_file_extent_other_encoding(leaf_r, ei_r) && | ||
5853 | btrfs_file_extent_type(leaf_l, ei_l) == | ||
5854 | btrfs_file_extent_type(leaf_r, ei_r) && | ||
5855 | btrfs_file_extent_disk_bytenr(leaf_l, ei_l) != | ||
5856 | btrfs_file_extent_disk_bytenr(leaf_r, ei_r) && | ||
5857 | btrfs_file_extent_disk_num_bytes(leaf_l, ei_l) == | ||
5858 | btrfs_file_extent_disk_num_bytes(leaf_r, ei_r) && | ||
5859 | btrfs_file_extent_offset(leaf_l, ei_l) == | ||
5860 | btrfs_file_extent_offset(leaf_r, ei_r) && | ||
5861 | btrfs_file_extent_num_bytes(leaf_l, ei_l) == | ||
5862 | btrfs_file_extent_num_bytes(leaf_r, ei_r)) | ||
5863 | return 0; | ||
5864 | } | ||
5865 | |||
5808 | inconsistent_snapshot_error(sctx, result, "extent"); | 5866 | inconsistent_snapshot_error(sctx, result, "extent"); |
5809 | return -EIO; | 5867 | return -EIO; |
5810 | } | 5868 | } |
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index 528cae123dc9..3d33c4e41e5f 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c | |||
@@ -2713,14 +2713,12 @@ static inline void btrfs_remove_all_log_ctxs(struct btrfs_root *root, | |||
2713 | int index, int error) | 2713 | int index, int error) |
2714 | { | 2714 | { |
2715 | struct btrfs_log_ctx *ctx; | 2715 | struct btrfs_log_ctx *ctx; |
2716 | struct btrfs_log_ctx *safe; | ||
2716 | 2717 | ||
2717 | if (!error) { | 2718 | list_for_each_entry_safe(ctx, safe, &root->log_ctxs[index], list) { |
2718 | INIT_LIST_HEAD(&root->log_ctxs[index]); | 2719 | list_del_init(&ctx->list); |
2719 | return; | ||
2720 | } | ||
2721 | |||
2722 | list_for_each_entry(ctx, &root->log_ctxs[index], list) | ||
2723 | ctx->log_ret = error; | 2720 | ctx->log_ret = error; |
2721 | } | ||
2724 | 2722 | ||
2725 | INIT_LIST_HEAD(&root->log_ctxs[index]); | 2723 | INIT_LIST_HEAD(&root->log_ctxs[index]); |
2726 | } | 2724 | } |
@@ -2961,13 +2959,9 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, | |||
2961 | mutex_unlock(&root->log_mutex); | 2959 | mutex_unlock(&root->log_mutex); |
2962 | 2960 | ||
2963 | out_wake_log_root: | 2961 | out_wake_log_root: |
2964 | /* | 2962 | mutex_lock(&log_root_tree->log_mutex); |
2965 | * We needn't get log_mutex here because we are sure all | ||
2966 | * the other tasks are blocked. | ||
2967 | */ | ||
2968 | btrfs_remove_all_log_ctxs(log_root_tree, index2, ret); | 2963 | btrfs_remove_all_log_ctxs(log_root_tree, index2, ret); |
2969 | 2964 | ||
2970 | mutex_lock(&log_root_tree->log_mutex); | ||
2971 | log_root_tree->log_transid_committed++; | 2965 | log_root_tree->log_transid_committed++; |
2972 | atomic_set(&log_root_tree->log_commit[index2], 0); | 2966 | atomic_set(&log_root_tree->log_commit[index2], 0); |
2973 | mutex_unlock(&log_root_tree->log_mutex); | 2967 | mutex_unlock(&log_root_tree->log_mutex); |
@@ -2978,10 +2972,8 @@ out_wake_log_root: | |||
2978 | if (waitqueue_active(&log_root_tree->log_commit_wait[index2])) | 2972 | if (waitqueue_active(&log_root_tree->log_commit_wait[index2])) |
2979 | wake_up(&log_root_tree->log_commit_wait[index2]); | 2973 | wake_up(&log_root_tree->log_commit_wait[index2]); |
2980 | out: | 2974 | out: |
2981 | /* See above. */ | ||
2982 | btrfs_remove_all_log_ctxs(root, index1, ret); | ||
2983 | |||
2984 | mutex_lock(&root->log_mutex); | 2975 | mutex_lock(&root->log_mutex); |
2976 | btrfs_remove_all_log_ctxs(root, index1, ret); | ||
2985 | root->log_transid_committed++; | 2977 | root->log_transid_committed++; |
2986 | atomic_set(&root->log_commit[index1], 0); | 2978 | atomic_set(&root->log_commit[index1], 0); |
2987 | mutex_unlock(&root->log_mutex); | 2979 | mutex_unlock(&root->log_mutex); |