From 427ad121c21479d1725ddaac1439c99d01e98ba1 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 28 Apr 2023 15:10:24 +0200 Subject: [PATCH 1/2] copy: don't call clone ioctls twice The btrfs name and the generic name have the same values, hence there's no point in bothering with the former. --- src/shared/copy.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/src/shared/copy.c b/src/shared/copy.c index 6a5a52309aa..90c6e2c0efd 100644 --- a/src/shared/copy.c +++ b/src/shared/copy.c @@ -1610,13 +1610,11 @@ int reflink(int infd, int outfd) { if (r < 0) return r; - /* FICLONE was introduced in Linux 4.5, so let's fall back to BTRFS_IOC_CLONE if it's not supported. */ + /* FICLONE was introduced in Linux 4.5 but it uses the same number as BTRFS_IOC_CLONE introduced earlier */ - r = ioctl(outfd, FICLONE, infd); - if (r < 0 && ERRNO_IS_NOT_SUPPORTED(errno)) - r = ioctl(outfd, BTRFS_IOC_CLONE, infd); + assert_cc(FICLONE == BTRFS_IOC_CLONE); - return RET_NERRNO(r); + return RET_NERRNO(ioctl(outfd, FICLONE, infd)); } assert_cc(sizeof(struct file_clone_range) == sizeof(struct btrfs_ioctl_clone_range_args)); @@ -1637,9 +1635,7 @@ int reflink_range(int infd, uint64_t in_offset, int outfd, uint64_t out_offset, if (r < 0) return r; - r = ioctl(outfd, FICLONERANGE, &args); - if (r < 0 && ERRNO_IS_NOT_SUPPORTED(errno)) - r = ioctl(outfd, BTRFS_IOC_CLONE_RANGE, &args); + assert_cc(FICLONERANGE == BTRFS_IOC_CLONE_RANGE); - return RET_NERRNO(r); + return RET_NERRNO(ioctl(outfd, FICLONERANGE, &args)); } From 535358ad2e0f844c77dbacff37ad456e8ffed8a2 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 28 Apr 2023 15:16:00 +0200 Subject: [PATCH 2/2] copy: shortcut reflink_range() to reflink() in some cases --- src/shared/copy.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/shared/copy.c b/src/shared/copy.c index 90c6e2c0efd..14b9b61d8a2 100644 --- a/src/shared/copy.c +++ b/src/shared/copy.c @@ -1631,6 +1631,12 @@ int reflink_range(int infd, uint64_t in_offset, int outfd, uint64_t out_offset, assert(infd >= 0); assert(outfd >= 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)) + return reflink(infd, outfd); + r = fd_verify_regular(outfd); if (r < 0) return r;