|
@@ -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;
|
|
|
}
|