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); |
