Cleanup argument and return values for copy_bytes_full helpers (#43034)
Follow-up for #43004.
This commit is contained in:
@@ -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
@@ -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
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user