Skip to content

Commit 019dea0

Browse files
authored
zfs_clone_range should return a descriptive error codes
Return the more descriptive error codes instead of `EXDEV` when the parameters don't match the requirements of the clone function. Updated the comments in `brt.c` accordingly. The first three errors are just invalid parameters, which zfs can not handle. The fourth error indicates that the block which should be cloned is created and cloned or modified in the same transaction group (`txg`). Reviewed-by: Brian Behlendorf <[email protected]> Reviewed-by: Rob Norris <[email protected]> Signed-off-by: Kay Pedersen <[email protected]> Closes #15148
1 parent 683edb3 commit 019dea0

File tree

4 files changed

+13
-12
lines changed

4 files changed

+13
-12
lines changed

module/os/freebsd/zfs/zfs_vnops_os.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6288,7 +6288,7 @@ zfs_freebsd_copy_file_range(struct vop_copy_file_range_args *ap)
62886288

62896289
error = zfs_clone_range(VTOZ(invp), ap->a_inoffp, VTOZ(outvp),
62906290
ap->a_outoffp, &len, ap->a_outcred);
6291-
if (error == EXDEV || error == EOPNOTSUPP)
6291+
if (error == EXDEV || error == EINVAL || error == EOPNOTSUPP)
62926292
goto bad_locked_fallback;
62936293
*ap->a_lenp = (size_t)len;
62946294
out_locked:

module/os/linux/zfs/zpl_file_range.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,15 +103,15 @@ zpl_copy_file_range(struct file *src_file, loff_t src_off,
103103
* Since Linux 5.3 the filesystem driver is responsible for executing
104104
* an appropriate fallback, and a generic fallback function is provided.
105105
*/
106-
if (ret == -EOPNOTSUPP || ret == -EXDEV)
106+
if (ret == -EOPNOTSUPP || ret == -EINVAL || ret == -EXDEV)
107107
ret = generic_copy_file_range(src_file, src_off, dst_file,
108108
dst_off, len, flags);
109109
#else
110110
/*
111111
* Before Linux 5.3 the filesystem has to return -EOPNOTSUPP to signal
112112
* to the kernel that it should fallback to a content copy.
113113
*/
114-
if (ret == -EXDEV)
114+
if (ret == -EINVAL || ret == -EXDEV)
115115
ret = -EOPNOTSUPP;
116116
#endif /* HAVE_VFS_GENERIC_COPY_FILE_RANGE */
117117

module/zfs/brt.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@
174174
* size_t len, unsigned int flags);
175175
*
176176
* Even though offsets and length represent bytes, they have to be
177-
* block-aligned or we will return the EXDEV error so the upper layer can
177+
* block-aligned or we will return an error so the upper layer can
178178
* fallback to the generic mechanism that will just copy the data.
179179
* Using copy_file_range(2) will call OS-independent zfs_clone_range() function.
180180
* This function was implemented based on zfs_write(), but instead of writing
@@ -192,9 +192,9 @@
192192
* Some special cases to consider and how we address them:
193193
* - The block we want to clone may have been created within the same
194194
* transaction group that we are trying to clone. Such block has no BP
195-
* allocated yet, so cannot be immediately cloned. We return EXDEV.
195+
* allocated yet, so cannot be immediately cloned. We return EAGAIN.
196196
* - The block we want to clone may have been modified within the same
197-
* transaction group. We return EXDEV.
197+
* transaction group. We return EAGAIN.
198198
* - A block may be cloned multiple times during one transaction group (that's
199199
* why pending list is actually a tree and not an append-only list - this
200200
* way we can figure out faster if this block is cloned for the first time

module/zfs/zfs_vnops.c

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1028,6 +1028,10 @@ zfs_exit_two(zfsvfs_t *zfsvfs1, zfsvfs_t *zfsvfs2, const char *tag)
10281028
*
10291029
* On success, the function return the number of bytes copied in *lenp.
10301030
* Note, it doesn't return how much bytes are left to be copied.
1031+
* On errors which are caused by any file system limitations or
1032+
* brt limitations `EINVAL` is returned. In the most cases a user
1033+
* requested bad parameters, it could be possible to clone the file but
1034+
* some parameters don't match the requirements.
10311035
*/
10321036
int
10331037
zfs_clone_range(znode_t *inzp, uint64_t *inoffp, znode_t *outzp,
@@ -1171,23 +1175,23 @@ zfs_clone_range(znode_t *inzp, uint64_t *inoffp, znode_t *outzp,
11711175
* We cannot clone into files with different block size.
11721176
*/
11731177
if (inblksz != outzp->z_blksz && outzp->z_size > inblksz) {
1174-
error = SET_ERROR(EXDEV);
1178+
error = SET_ERROR(EINVAL);
11751179
goto unlock;
11761180
}
11771181

11781182
/*
11791183
* Offsets and len must be at block boundries.
11801184
*/
11811185
if ((inoff % inblksz) != 0 || (outoff % inblksz) != 0) {
1182-
error = SET_ERROR(EXDEV);
1186+
error = SET_ERROR(EINVAL);
11831187
goto unlock;
11841188
}
11851189
/*
11861190
* Length must be multipe of blksz, except for the end of the file.
11871191
*/
11881192
if ((len % inblksz) != 0 &&
11891193
(len < inzp->z_size - inoff || len < outzp->z_size - outoff)) {
1190-
error = SET_ERROR(EXDEV);
1194+
error = SET_ERROR(EINVAL);
11911195
goto unlock;
11921196
}
11931197

@@ -1246,9 +1250,6 @@ zfs_clone_range(znode_t *inzp, uint64_t *inoffp, znode_t *outzp,
12461250
* in the current transaction group. Return an error,
12471251
* so the caller can fallback to just copying the data.
12481252
*/
1249-
if (error == EAGAIN) {
1250-
error = SET_ERROR(EXDEV);
1251-
}
12521253
break;
12531254
}
12541255
/*

0 commit comments

Comments
 (0)