aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/send.c
diff options
context:
space:
mode:
authorChris Mason <chris.mason@fusionio.com>2012-08-07 16:25:13 -0400
committerChris Mason <chris.mason@fusionio.com>2012-10-01 15:19:00 -0400
commit74dd17fbe3d65829e75d84f00a9525b2ace93998 (patch)
tree84c7ffead9b44d2b7d73601aed5be7a5637e804b /fs/btrfs/send.c
parent6d85ed05e16e7ff747025c8374f23d7d81c98540 (diff)
Btrfs: fix btrfs send for inline items and compression
The btrfs send code was assuming the offset of the file item into the extent translated to bytes on disk. If we're compressed, this isn't true, and so it was off into extents owned by other files. It was also improperly handling inline extents. This solves a crash where we may have gone past the end of the file extent item by not testing early enough for an inline extent. It also solves problems where we have a whole between the end of the inline item and the start of the full extent. Signed-off-by: Chris Mason <chris.mason@fusionio.com>
Diffstat (limited to 'fs/btrfs/send.c')
-rw-r--r--fs/btrfs/send.c46
1 files changed, 33 insertions, 13 deletions
diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c
index d17d75ebc482..f22fdd41ff49 100644
--- a/fs/btrfs/send.c
+++ b/fs/btrfs/send.c
@@ -1149,6 +1149,7 @@ static int find_extent_clone(struct send_ctx *sctx,
1149 int ret; 1149 int ret;
1150 int extent_type; 1150 int extent_type;
1151 u64 logical; 1151 u64 logical;
1152 u64 disk_byte;
1152 u64 num_bytes; 1153 u64 num_bytes;
1153 u64 extent_item_pos; 1154 u64 extent_item_pos;
1154 struct btrfs_file_extent_item *fi; 1155 struct btrfs_file_extent_item *fi;
@@ -1157,6 +1158,7 @@ static int find_extent_clone(struct send_ctx *sctx,
1157 struct clone_root *cur_clone_root; 1158 struct clone_root *cur_clone_root;
1158 struct btrfs_key found_key; 1159 struct btrfs_key found_key;
1159 struct btrfs_path *tmp_path; 1160 struct btrfs_path *tmp_path;
1161 int compressed;
1160 u32 i; 1162 u32 i;
1161 1163
1162 tmp_path = alloc_path_for_send(); 1164 tmp_path = alloc_path_for_send();
@@ -1186,17 +1188,18 @@ static int find_extent_clone(struct send_ctx *sctx,
1186 ret = -ENOENT; 1188 ret = -ENOENT;
1187 goto out; 1189 goto out;
1188 } 1190 }
1191 compressed = btrfs_file_extent_compression(eb, fi);
1189 1192
1190 num_bytes = btrfs_file_extent_num_bytes(eb, fi); 1193 num_bytes = btrfs_file_extent_num_bytes(eb, fi);
1191 logical = btrfs_file_extent_disk_bytenr(eb, fi); 1194 disk_byte = btrfs_file_extent_disk_bytenr(eb, fi);
1192 if (logical == 0) { 1195 if (disk_byte == 0) {
1193 ret = -ENOENT; 1196 ret = -ENOENT;
1194 goto out; 1197 goto out;
1195 } 1198 }
1196 logical += btrfs_file_extent_offset(eb, fi); 1199 logical = disk_byte + btrfs_file_extent_offset(eb, fi);
1197 1200
1198 ret = extent_from_logical(sctx->send_root->fs_info, 1201 ret = extent_from_logical(sctx->send_root->fs_info,
1199 logical, tmp_path, &found_key); 1202 disk_byte, tmp_path, &found_key);
1200 btrfs_release_path(tmp_path); 1203 btrfs_release_path(tmp_path);
1201 1204
1202 if (ret < 0) 1205 if (ret < 0)
@@ -1234,10 +1237,16 @@ static int find_extent_clone(struct send_ctx *sctx,
1234 /* 1237 /*
1235 * Now collect all backrefs. 1238 * Now collect all backrefs.
1236 */ 1239 */
1240 if (compressed == BTRFS_COMPRESS_NONE)
1241 extent_item_pos = logical - found_key.objectid;
1242 else
1243 extent_item_pos = 0;
1244
1237 extent_item_pos = logical - found_key.objectid; 1245 extent_item_pos = logical - found_key.objectid;
1238 ret = iterate_extent_inodes(sctx->send_root->fs_info, 1246 ret = iterate_extent_inodes(sctx->send_root->fs_info,
1239 found_key.objectid, extent_item_pos, 1, 1247 found_key.objectid, extent_item_pos, 1,
1240 __iterate_backrefs, backref_ctx); 1248 __iterate_backrefs, backref_ctx);
1249
1241 if (ret < 0) 1250 if (ret < 0)
1242 goto out; 1251 goto out;
1243 1252
@@ -1246,8 +1255,8 @@ static int find_extent_clone(struct send_ctx *sctx,
1246 ret = -EIO; 1255 ret = -EIO;
1247 printk(KERN_ERR "btrfs: ERROR did not find backref in " 1256 printk(KERN_ERR "btrfs: ERROR did not find backref in "
1248 "send_root. inode=%llu, offset=%llu, " 1257 "send_root. inode=%llu, offset=%llu, "
1249 "logical=%llu\n", 1258 "disk_byte=%llu found extent=%llu\n",
1250 ino, data_offset, logical); 1259 ino, data_offset, disk_byte, found_key.objectid);
1251 goto out; 1260 goto out;
1252 } 1261 }
1253 1262
@@ -3678,10 +3687,17 @@ static int send_write_or_clone(struct send_ctx *sctx,
3678 ei = btrfs_item_ptr(path->nodes[0], path->slots[0], 3687 ei = btrfs_item_ptr(path->nodes[0], path->slots[0],
3679 struct btrfs_file_extent_item); 3688 struct btrfs_file_extent_item);
3680 type = btrfs_file_extent_type(path->nodes[0], ei); 3689 type = btrfs_file_extent_type(path->nodes[0], ei);
3681 if (type == BTRFS_FILE_EXTENT_INLINE) 3690 if (type == BTRFS_FILE_EXTENT_INLINE) {
3682 len = btrfs_file_extent_inline_len(path->nodes[0], ei); 3691 len = btrfs_file_extent_inline_len(path->nodes[0], ei);
3683 else 3692 /*
3693 * it is possible the inline item won't cover the whole page,
3694 * but there may be items after this page. Make
3695 * sure to send the whole thing
3696 */
3697 len = PAGE_CACHE_ALIGN(len);
3698 } else {
3684 len = btrfs_file_extent_num_bytes(path->nodes[0], ei); 3699 len = btrfs_file_extent_num_bytes(path->nodes[0], ei);
3700 }
3685 3701
3686 if (offset + len > sctx->cur_inode_size) 3702 if (offset + len > sctx->cur_inode_size)
3687 len = sctx->cur_inode_size - offset; 3703 len = sctx->cur_inode_size - offset;
@@ -3729,6 +3745,8 @@ static int is_extent_unchanged(struct send_ctx *sctx,
3729 u64 left_offset_fixed; 3745 u64 left_offset_fixed;
3730 u64 left_len; 3746 u64 left_len;
3731 u64 right_len; 3747 u64 right_len;
3748 u64 left_gen;
3749 u64 right_gen;
3732 u8 left_type; 3750 u8 left_type;
3733 u8 right_type; 3751 u8 right_type;
3734 3752
@@ -3738,17 +3756,17 @@ static int is_extent_unchanged(struct send_ctx *sctx,
3738 3756
3739 eb = left_path->nodes[0]; 3757 eb = left_path->nodes[0];
3740 slot = left_path->slots[0]; 3758 slot = left_path->slots[0];
3741
3742 ei = btrfs_item_ptr(eb, slot, struct btrfs_file_extent_item); 3759 ei = btrfs_item_ptr(eb, slot, struct btrfs_file_extent_item);
3743 left_type = btrfs_file_extent_type(eb, ei); 3760 left_type = btrfs_file_extent_type(eb, ei);
3744 left_disknr = btrfs_file_extent_disk_bytenr(eb, ei);
3745 left_len = btrfs_file_extent_num_bytes(eb, ei);
3746 left_offset = btrfs_file_extent_offset(eb, ei);
3747 3761
3748 if (left_type != BTRFS_FILE_EXTENT_REG) { 3762 if (left_type != BTRFS_FILE_EXTENT_REG) {
3749 ret = 0; 3763 ret = 0;
3750 goto out; 3764 goto out;
3751 } 3765 }
3766 left_disknr = btrfs_file_extent_disk_bytenr(eb, ei);
3767 left_len = btrfs_file_extent_num_bytes(eb, ei);
3768 left_offset = btrfs_file_extent_offset(eb, ei);
3769 left_gen = btrfs_file_extent_generation(eb, ei);
3752 3770
3753 /* 3771 /*
3754 * Following comments will refer to these graphics. L is the left 3772 * Following comments will refer to these graphics. L is the left
@@ -3804,6 +3822,7 @@ static int is_extent_unchanged(struct send_ctx *sctx,
3804 right_disknr = btrfs_file_extent_disk_bytenr(eb, ei); 3822 right_disknr = btrfs_file_extent_disk_bytenr(eb, ei);
3805 right_len = btrfs_file_extent_num_bytes(eb, ei); 3823 right_len = btrfs_file_extent_num_bytes(eb, ei);
3806 right_offset = btrfs_file_extent_offset(eb, ei); 3824 right_offset = btrfs_file_extent_offset(eb, ei);
3825 right_gen = btrfs_file_extent_generation(eb, ei);
3807 3826
3808 if (right_type != BTRFS_FILE_EXTENT_REG) { 3827 if (right_type != BTRFS_FILE_EXTENT_REG) {
3809 ret = 0; 3828 ret = 0;
@@ -3832,7 +3851,8 @@ static int is_extent_unchanged(struct send_ctx *sctx,
3832 * Check if we have the same extent. 3851 * Check if we have the same extent.
3833 */ 3852 */
3834 if (left_disknr != right_disknr || 3853 if (left_disknr != right_disknr ||
3835 left_offset_fixed != right_offset) { 3854 left_offset_fixed != right_offset ||
3855 left_gen != right_gen) {
3836 ret = 0; 3856 ret = 0;
3837 goto out; 3857 goto out;
3838 } 3858 }