|
@@ -1158,6 +1158,9 @@ struct backref_ctx {
|
|
|
/* may be truncated in case it's the last extent in a file */
|
|
|
u64 extent_len;
|
|
|
|
|
|
+ /* data offset in the file extent item */
|
|
|
+ u64 data_offset;
|
|
|
+
|
|
|
/* Just to check for bugs in backref resolving */
|
|
|
int found_itself;
|
|
|
};
|
|
@@ -1221,7 +1224,7 @@ static int __iterate_backrefs(u64 ino, u64 offset, u64 root, void *ctx_)
|
|
|
if (ret < 0)
|
|
|
return ret;
|
|
|
|
|
|
- if (offset + bctx->extent_len > i_size)
|
|
|
+ if (offset + bctx->data_offset + bctx->extent_len > i_size)
|
|
|
return 0;
|
|
|
|
|
|
/*
|
|
@@ -1363,6 +1366,19 @@ static int find_extent_clone(struct send_ctx *sctx,
|
|
|
backref_ctx->cur_offset = data_offset;
|
|
|
backref_ctx->found_itself = 0;
|
|
|
backref_ctx->extent_len = num_bytes;
|
|
|
+ /*
|
|
|
+ * For non-compressed extents iterate_extent_inodes() gives us extent
|
|
|
+ * offsets that already take into account the data offset, but not for
|
|
|
+ * compressed extents, since the offset is logical and not relative to
|
|
|
+ * the physical extent locations. We must take this into account to
|
|
|
+ * avoid sending clone offsets that go beyond the source file's size,
|
|
|
+ * which would result in the clone ioctl failing with -EINVAL on the
|
|
|
+ * receiving end.
|
|
|
+ */
|
|
|
+ if (compressed == BTRFS_COMPRESS_NONE)
|
|
|
+ backref_ctx->data_offset = 0;
|
|
|
+ else
|
|
|
+ backref_ctx->data_offset = btrfs_file_extent_offset(eb, fi);
|
|
|
|
|
|
/*
|
|
|
* The last extent of a file may be too large due to page alignment.
|