FreeBSD: Fix RLIMIT_FSIZE handling for block cloning
ZFS implements copy_file_range(2) using block cloning when possible. This implementation must respect the RLIMIT_FSIZE limit. zfs_clone_range() already checks the limit, so it is safe to remove this check in zfs_freebsd_copy_file_range(). Moreover, the removed check produces false positives: the length passed to copy_file_range(2) may be larger than the input file size; as the man page notes, "for best performance, call copy_file_range() with the largest len value possible." In particular, some existing code passes SSIZE_MAX there. The check in zfs_clone_range() clamps the length to the input file's size before checking, but the removed check uses the caller supplied length, so something like $ echo a > /tmp/foo $ limits -f 1024 cat /tmp/foo > /tmp/bar fails because FreeBSD's cat(1) uses copy_file_range(2) in the manner described above. Reported-by: Philip Paeps <philip@FreeBSD.org> Signed-off-by: Mark Johnston <markj@FreeBSD.org> Reviewed-by: Alexander Motin <mav@FreeBSD.org> Reviewed-by: Allan Jude <allan@klarasystems.com> Reviewed-by: Tino Reichardt <milky-zfs@mcmilk.de> Reviewed-by: Tony Hutter <hutter2@llnl.gov>
This commit is contained in:
parent
1f5bf91a85
commit
dea8fabf73
|
@ -6072,7 +6072,6 @@ zfs_freebsd_copy_file_range(struct vop_copy_file_range_args *ap)
|
||||||
struct vnode *invp = ap->a_invp;
|
struct vnode *invp = ap->a_invp;
|
||||||
struct vnode *outvp = ap->a_outvp;
|
struct vnode *outvp = ap->a_outvp;
|
||||||
struct mount *mp;
|
struct mount *mp;
|
||||||
struct uio io;
|
|
||||||
int error;
|
int error;
|
||||||
uint64_t len = *ap->a_lenp;
|
uint64_t len = *ap->a_lenp;
|
||||||
|
|
||||||
|
@ -6120,12 +6119,6 @@ zfs_freebsd_copy_file_range(struct vop_copy_file_range_args *ap)
|
||||||
goto out_locked;
|
goto out_locked;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
io.uio_offset = *ap->a_outoffp;
|
|
||||||
io.uio_resid = *ap->a_lenp;
|
|
||||||
error = vn_rlimit_fsize(outvp, &io, ap->a_fsizetd);
|
|
||||||
if (error != 0)
|
|
||||||
goto out_locked;
|
|
||||||
|
|
||||||
error = zfs_clone_range(VTOZ(invp), ap->a_inoffp, VTOZ(outvp),
|
error = zfs_clone_range(VTOZ(invp), ap->a_inoffp, VTOZ(outvp),
|
||||||
ap->a_outoffp, &len, ap->a_outcred);
|
ap->a_outoffp, &len, ap->a_outcred);
|
||||||
if (error == EXDEV || error == EAGAIN || error == EINVAL ||
|
if (error == EXDEV || error == EAGAIN || error == EINVAL ||
|
||||||
|
|
Loading…
Reference in New Issue