aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/btrfs/send.c88
1 files changed, 86 insertions, 2 deletions
diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c
index 712922ea64d2..456c8901489b 100644
--- a/fs/btrfs/send.c
+++ b/fs/btrfs/send.c
@@ -5306,6 +5306,81 @@ out:
5306 return ret; 5306 return ret;
5307} 5307}
5308 5308
5309static int range_is_hole_in_parent(struct send_ctx *sctx,
5310 const u64 start,
5311 const u64 end)
5312{
5313 struct btrfs_path *path;
5314 struct btrfs_key key;
5315 struct btrfs_root *root = sctx->parent_root;
5316 u64 search_start = start;
5317 int ret;
5318
5319 path = alloc_path_for_send();
5320 if (!path)
5321 return -ENOMEM;
5322
5323 key.objectid = sctx->cur_ino;
5324 key.type = BTRFS_EXTENT_DATA_KEY;
5325 key.offset = search_start;
5326 ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
5327 if (ret < 0)
5328 goto out;
5329 if (ret > 0 && path->slots[0] > 0)
5330 path->slots[0]--;
5331
5332 while (search_start < end) {
5333 struct extent_buffer *leaf = path->nodes[0];
5334 int slot = path->slots[0];
5335 struct btrfs_file_extent_item *fi;
5336 u64 extent_end;
5337
5338 if (slot >= btrfs_header_nritems(leaf)) {
5339 ret = btrfs_next_leaf(root, path);
5340 if (ret < 0)
5341 goto out;
5342 else if (ret > 0)
5343 break;
5344 continue;
5345 }
5346
5347 btrfs_item_key_to_cpu(leaf, &key, slot);
5348 if (key.objectid < sctx->cur_ino ||
5349 key.type < BTRFS_EXTENT_DATA_KEY)
5350 goto next;
5351 if (key.objectid > sctx->cur_ino ||
5352 key.type > BTRFS_EXTENT_DATA_KEY ||
5353 key.offset >= end)
5354 break;
5355
5356 fi = btrfs_item_ptr(leaf, slot, struct btrfs_file_extent_item);
5357 if (btrfs_file_extent_type(leaf, fi) ==
5358 BTRFS_FILE_EXTENT_INLINE) {
5359 u64 size = btrfs_file_extent_inline_len(leaf, slot, fi);
5360
5361 extent_end = ALIGN(key.offset + size,
5362 root->fs_info->sectorsize);
5363 } else {
5364 extent_end = key.offset +
5365 btrfs_file_extent_num_bytes(leaf, fi);
5366 }
5367 if (extent_end <= start)
5368 goto next;
5369 if (btrfs_file_extent_disk_bytenr(leaf, fi) == 0) {
5370 search_start = extent_end;
5371 goto next;
5372 }
5373 ret = 0;
5374 goto out;
5375next:
5376 path->slots[0]++;
5377 }
5378 ret = 1;
5379out:
5380 btrfs_free_path(path);
5381 return ret;
5382}
5383
5309static int maybe_send_hole(struct send_ctx *sctx, struct btrfs_path *path, 5384static int maybe_send_hole(struct send_ctx *sctx, struct btrfs_path *path,
5310 struct btrfs_key *key) 5385 struct btrfs_key *key)
5311{ 5386{
@@ -5350,8 +5425,17 @@ static int maybe_send_hole(struct send_ctx *sctx, struct btrfs_path *path,
5350 return ret; 5425 return ret;
5351 } 5426 }
5352 5427
5353 if (sctx->cur_inode_last_extent < key->offset) 5428 if (sctx->cur_inode_last_extent < key->offset) {
5354 ret = send_hole(sctx, key->offset); 5429 ret = range_is_hole_in_parent(sctx,
5430 sctx->cur_inode_last_extent,
5431 key->offset);
5432 if (ret < 0)
5433 return ret;
5434 else if (ret == 0)
5435 ret = send_hole(sctx, key->offset);
5436 else
5437 ret = 0;
5438 }
5355 sctx->cur_inode_last_extent = extent_end; 5439 sctx->cur_inode_last_extent = extent_end;
5356 return ret; 5440 return ret;
5357} 5441}