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 978796865bfc..0b4628999b77 100644 --- a/fs/btrfs/send.c +++ b/fs/btrfs/send.c @@ -5805,6 +5805,64 @@ static int changed_extent(struct send_ctx *sctx,  	int ret = 0;  	if (sctx->cur_ino != sctx->cmp_key->objectid) { + +		if (result == BTRFS_COMPARE_TREE_CHANGED) { +			struct extent_buffer *leaf_l; +			struct extent_buffer *leaf_r; +			struct btrfs_file_extent_item *ei_l; +			struct btrfs_file_extent_item *ei_r; + +			leaf_l = sctx->left_path->nodes[0]; +			leaf_r = sctx->right_path->nodes[0]; +			ei_l = btrfs_item_ptr(leaf_l, +					      sctx->left_path->slots[0], +					      struct btrfs_file_extent_item); +			ei_r = btrfs_item_ptr(leaf_r, +					      sctx->right_path->slots[0], +					      struct btrfs_file_extent_item); + +			/* +			 * We may have found an extent item that has changed +			 * only its disk_bytenr field and the corresponding +			 * inode item was not updated. This case happens due to +			 * very specific timings during relocation when a leaf +			 * that contains file extent items is COWed while +			 * relocation is ongoing and its in the stage where it +			 * updates data pointers. So when this happens we can +			 * safely ignore it since we know it's the same extent, +			 * but just at different logical and physical locations +			 * (when an extent is fully replaced with a new one, we +			 * know the generation number must have changed too, +			 * since snapshot creation implies committing the current +			 * transaction, and the inode item must have been updated +			 * as well). +			 * This replacement of the disk_bytenr happens at +			 * relocation.c:replace_file_extents() through +			 * relocation.c:btrfs_reloc_cow_block(). +			 */ +			if (btrfs_file_extent_generation(leaf_l, ei_l) == +			    btrfs_file_extent_generation(leaf_r, ei_r) && +			    btrfs_file_extent_ram_bytes(leaf_l, ei_l) == +			    btrfs_file_extent_ram_bytes(leaf_r, ei_r) && +			    btrfs_file_extent_compression(leaf_l, ei_l) == +			    btrfs_file_extent_compression(leaf_r, ei_r) && +			    btrfs_file_extent_encryption(leaf_l, ei_l) == +			    btrfs_file_extent_encryption(leaf_r, ei_r) && +			    btrfs_file_extent_other_encoding(leaf_l, ei_l) == +			    btrfs_file_extent_other_encoding(leaf_r, ei_r) && +			    btrfs_file_extent_type(leaf_l, ei_l) == +			    btrfs_file_extent_type(leaf_r, ei_r) && +			    btrfs_file_extent_disk_bytenr(leaf_l, ei_l) != +			    btrfs_file_extent_disk_bytenr(leaf_r, ei_r) && +			    btrfs_file_extent_disk_num_bytes(leaf_l, ei_l) == +			    btrfs_file_extent_disk_num_bytes(leaf_r, ei_r) && +			    btrfs_file_extent_offset(leaf_l, ei_l) == +			    btrfs_file_extent_offset(leaf_r, ei_r) && +			    btrfs_file_extent_num_bytes(leaf_l, ei_l) == +			    btrfs_file_extent_num_bytes(leaf_r, ei_r)) +				return 0; +		} +  		inconsistent_snapshot_error(sctx, result, "extent");  		return -EIO;  	} | 

