Cleanup argument and return values for copy_bytes_full helpers (#43034)

Follow-up for #43004.
This commit is contained in:
Yu Watanabe
2026-07-16 01:32:04 +09:00
committed by GitHub
3 changed files with 32 additions and 34 deletions
+6
View File
@@ -6371,6 +6371,12 @@ static int context_copy_blocks(Context *context) {
return log_error_errno(errno, "Failed to seek to copy blocks offset in %s: %m", p->copy_blocks_path);
}
/* We call copy_bytes_full() instead of copy_file_range() directly, because copy_file_range()
* needs to be called with a size limit to allow for progress updates. But we don't want that
* for cloning, we want one big massive reflink if possible, and unfortunately we can't know
* if copy_file_range() will do reflink or not, so we can't call it without the size limit.
* Hence, call copy_bytes_full(), which tries FICLONE/BTRFS_IOC_CLONE first to do one big
* clone, and then falls back to copying in chunks. */
r = copy_bytes_full(
p->copy_blocks_fd,
partition_target_fd(t),
+25 -33
View File
@@ -130,36 +130,31 @@ static int create_hole(int fd, off_t size) {
return 0;
}
/* Returns positive if the range was cloned, zero if cloning is unavailable, and negative if finalizing a
* successful clone failed. If the range was cloned, returns the copy_bytes_full() result in ret_copy_result. */
static int try_reflink_copy_bytes(
int fdf,
int fdt,
uint64_t max_bytes,
CopyFlags copy_flags,
int *ret_copy_result) {
CopyFlags copy_flags) {
off_t foffset, toffset;
int r;
assert(fdf >= 0);
assert(fdt >= 0);
assert(ret_copy_result);
if (max_bytes == 0)
return 0;
return -EOPNOTSUPP;
foffset = FLAGS_SET(copy_flags, COPY_SEEK0_SOURCE) ? 0 : lseek(fdf, 0, SEEK_CUR);
off_t foffset = FLAGS_SET(copy_flags, COPY_SEEK0_SOURCE) ? 0 : lseek(fdf, 0, SEEK_CUR);
if (foffset < 0)
return 0;
return -EOPNOTSUPP;
toffset = FLAGS_SET(copy_flags, COPY_SEEK0_TARGET) ? 0 : lseek(fdt, 0, SEEK_CUR);
off_t toffset = FLAGS_SET(copy_flags, COPY_SEEK0_TARGET) ? 0 : lseek(fdt, 0, SEEK_CUR);
if (toffset < 0)
return 0;
return -EOPNOTSUPP;
r = reflink_range(fdf, foffset, fdt, toffset, max_bytes == UINT64_MAX ? 0 : max_bytes);
r = reflink_range(fdf, foffset, fdt, toffset, max_bytes);
if (r < 0)
return 0;
return -EOPNOTSUPP;
if (max_bytes == UINT64_MAX) {
off_t end;
@@ -172,15 +167,11 @@ static int try_reflink_copy_bytes(
if (lseek(fdt, toffset + (end - foffset), SEEK_SET) < 0)
return -errno;
*ret_copy_result = 0; /* We copied to EOF. */
} else {
if (lseek(fdf, foffset + max_bytes, SEEK_SET) < 0)
return -errno;
if (lseek(fdt, toffset + max_bytes, SEEK_SET) < 0)
return -errno;
*ret_copy_result = 1; /* We copied the requested range. */
}
if (FLAGS_SET(copy_flags, COPY_VERIFY_LINKED)) {
@@ -189,7 +180,8 @@ static int try_reflink_copy_bytes(
return r;
}
return 1;
return max_bytes == UINT64_MAX ? 0 /* we copied until EOF */
: 1 /* we copied the requested range */;
}
int copy_bytes_full(
@@ -239,12 +231,9 @@ int copy_bytes_full(
lseek(fdt, 0, SEEK_SET) < 0)
return -errno;
int reflink_result = 0;
r = try_reflink_copy_bytes(fdf, fdt, max_bytes, copy_flags, &reflink_result);
if (r < 0)
r = try_reflink_copy_bytes(fdf, fdt, max_bytes, copy_flags);
if (r != -EOPNOTSUPP)
return r;
if (r > 0)
return reflink_result;
usec_t start_timestamp = USEC_INFINITY;
if (progress)
@@ -1759,22 +1748,19 @@ int reflink(int infd, int outfd) {
assert_cc(sizeof(struct file_clone_range) == sizeof(struct btrfs_ioctl_clone_range_args));
int reflink_range(int infd, uint64_t in_offset, int outfd, uint64_t out_offset, uint64_t sz) {
struct file_clone_range args = {
.src_fd = infd,
.src_offset = in_offset,
.src_length = sz,
.dest_offset = out_offset,
};
int reflink_range(int infd, uint64_t in_offset, int outfd, uint64_t out_offset, uint64_t size) {
int r;
assert(infd >= 0);
assert(outfd >= 0);
/* size==UINT64_MAX mean "clone everything". Translate to 0 for the kernel. */
if (size == UINT64_MAX)
size = 0;
/* Inside the kernel, FICLONE is identical to FICLONERANGE with offsets and size set to zero, let's
* simplify things and use the simple ioctl in that case. Also, do the same if the size is
* UINT64_MAX, which is how we usually encode "everything". */
if (in_offset == 0 && out_offset == 0 && IN_SET(sz, 0, UINT64_MAX))
* simplify things and use the simple ioctl in that case. */
if (in_offset == 0 && out_offset == 0 && size == 0)
return reflink(infd, outfd);
r = fd_verify_regular(outfd);
@@ -1783,5 +1769,11 @@ int reflink_range(int infd, uint64_t in_offset, int outfd, uint64_t out_offset,
assert_cc(FICLONERANGE == BTRFS_IOC_CLONE_RANGE);
struct file_clone_range args = {
.src_fd = infd,
.src_offset = in_offset,
.src_length = size,
.dest_offset = out_offset,
};
return RET_NERRNO(ioctl(outfd, FICLONERANGE, &args));
}
+1 -1
View File
@@ -109,4 +109,4 @@ static inline int copy_rights(int fdf, int fdt) {
int copy_xattr(int df, const char *from, int dt, const char *to, CopyFlags copy_flags);
int reflink(int infd, int outfd);
int reflink_range(int infd, uint64_t in_offset, int outfd, uint64_t out_offset, uint64_t sz);
int reflink_range(int infd, uint64_t in_offset, int outfd, uint64_t out_offset, uint64_t size);