diff options
Diffstat (limited to 'fs/btrfs/send.c')
-rw-r--r-- | fs/btrfs/send.c | 46 |
1 files changed, 33 insertions, 13 deletions
diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c index d17d75e..f22fdd4 100644 --- a/fs/btrfs/send.c +++ b/fs/btrfs/send.c @@ -1149,6 +1149,7 @@ static int find_extent_clone(struct send_ctx *sctx, int ret; int extent_type; u64 logical; + u64 disk_byte; u64 num_bytes; u64 extent_item_pos; struct btrfs_file_extent_item *fi; @@ -1157,6 +1158,7 @@ static int find_extent_clone(struct send_ctx *sctx, struct clone_root *cur_clone_root; struct btrfs_key found_key; struct btrfs_path *tmp_path; + int compressed; u32 i; tmp_path = alloc_path_for_send(); @@ -1186,17 +1188,18 @@ static int find_extent_clone(struct send_ctx *sctx, ret = -ENOENT; goto out; } + compressed = btrfs_file_extent_compression(eb, fi); num_bytes = btrfs_file_extent_num_bytes(eb, fi); - logical = btrfs_file_extent_disk_bytenr(eb, fi); - if (logical == 0) { + disk_byte = btrfs_file_extent_disk_bytenr(eb, fi); + if (disk_byte == 0) { ret = -ENOENT; goto out; } - logical += btrfs_file_extent_offset(eb, fi); + logical = disk_byte + btrfs_file_extent_offset(eb, fi); ret = extent_from_logical(sctx->send_root->fs_info, - logical, tmp_path, &found_key); + disk_byte, tmp_path, &found_key); btrfs_release_path(tmp_path); if (ret < 0) @@ -1234,10 +1237,16 @@ static int find_extent_clone(struct send_ctx *sctx, /* * Now collect all backrefs. */ + if (compressed == BTRFS_COMPRESS_NONE) + extent_item_pos = logical - found_key.objectid; + else + extent_item_pos = 0; + extent_item_pos = logical - found_key.objectid; ret = iterate_extent_inodes(sctx->send_root->fs_info, found_key.objectid, extent_item_pos, 1, __iterate_backrefs, backref_ctx); + if (ret < 0) goto out; @@ -1246,8 +1255,8 @@ static int find_extent_clone(struct send_ctx *sctx, ret = -EIO; printk(KERN_ERR "btrfs: ERROR did not find backref in " "send_root. inode=%llu, offset=%llu, " - "logical=%llu\n", - ino, data_offset, logical); + "disk_byte=%llu found extent=%llu\n", + ino, data_offset, disk_byte, found_key.objectid); goto out; } @@ -3678,10 +3687,17 @@ static int send_write_or_clone(struct send_ctx *sctx, ei = btrfs_item_ptr(path->nodes[0], path->slots[0], struct btrfs_file_extent_item); type = btrfs_file_extent_type(path->nodes[0], ei); - if (type == BTRFS_FILE_EXTENT_INLINE) + if (type == BTRFS_FILE_EXTENT_INLINE) { len = btrfs_file_extent_inline_len(path->nodes[0], ei); - else + /* + * it is possible the inline item won't cover the whole page, + * but there may be items after this page. Make + * sure to send the whole thing + */ + len = PAGE_CACHE_ALIGN(len); + } else { len = btrfs_file_extent_num_bytes(path->nodes[0], ei); + } if (offset + len > sctx->cur_inode_size) len = sctx->cur_inode_size - offset; @@ -3729,6 +3745,8 @@ static int is_extent_unchanged(struct send_ctx *sctx, u64 left_offset_fixed; u64 left_len; u64 right_len; + u64 left_gen; + u64 right_gen; u8 left_type; u8 right_type; @@ -3738,17 +3756,17 @@ static int is_extent_unchanged(struct send_ctx *sctx, eb = left_path->nodes[0]; slot = left_path->slots[0]; - ei = btrfs_item_ptr(eb, slot, struct btrfs_file_extent_item); left_type = btrfs_file_extent_type(eb, ei); - left_disknr = btrfs_file_extent_disk_bytenr(eb, ei); - left_len = btrfs_file_extent_num_bytes(eb, ei); - left_offset = btrfs_file_extent_offset(eb, ei); if (left_type != BTRFS_FILE_EXTENT_REG) { ret = 0; goto out; } + left_disknr = btrfs_file_extent_disk_bytenr(eb, ei); + left_len = btrfs_file_extent_num_bytes(eb, ei); + left_offset = btrfs_file_extent_offset(eb, ei); + left_gen = btrfs_file_extent_generation(eb, ei); /* * Following comments will refer to these graphics. L is the left @@ -3804,6 +3822,7 @@ static int is_extent_unchanged(struct send_ctx *sctx, right_disknr = btrfs_file_extent_disk_bytenr(eb, ei); right_len = btrfs_file_extent_num_bytes(eb, ei); right_offset = btrfs_file_extent_offset(eb, ei); + right_gen = btrfs_file_extent_generation(eb, ei); if (right_type != BTRFS_FILE_EXTENT_REG) { ret = 0; @@ -3832,7 +3851,8 @@ static int is_extent_unchanged(struct send_ctx *sctx, * Check if we have the same extent. */ if (left_disknr != right_disknr || - left_offset_fixed != right_offset) { + left_offset_fixed != right_offset || + left_gen != right_gen) { ret = 0; goto out; } |