From: Zbigniew Jędrzejewski-Szmek Date: Wed, 15 Jul 2026 10:39:30 +0000 (+0200) Subject: shared/copy: simplify return convention for try_reflink_copy_bytes X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=5efd4688a9b0541ab0453c415d72ee5c1accec83;p=thirdparty%2Fsystemd.git shared/copy: simplify return convention for try_reflink_copy_bytes Follow-up for 5a12005c834eab92d7c76d61c7090aa78b61cdfb. Also a rescue a comment from the discussion in the PR. --- diff --git a/src/repart/repart.c b/src/repart/repart.c index 7eadfe4a6af..002fb782be5 100644 --- a/src/repart/repart.c +++ b/src/repart/repart.c @@ -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), diff --git a/src/shared/copy.c b/src/shared/copy.c index 7a87842a344..ded40b524eb 100644 --- a/src/shared/copy.c +++ b/src/shared/copy.c @@ -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); 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)