diff options
Diffstat (limited to 'fs/btrfs/send.c')
-rw-r--r-- | fs/btrfs/send.c | 58 |
1 files changed, 58 insertions, 0 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 | } |