From dea8fabf73b1017c396e6331d194bf5f139187c8 Mon Sep 17 00:00:00 2001 From: Mark Johnston Date: Tue, 23 Jul 2024 10:20:46 -0400 Subject: [PATCH] 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 Signed-off-by: Mark Johnston Reviewed-by: Alexander Motin Reviewed-by: Allan Jude Reviewed-by: Tino Reichardt Reviewed-by: Tony Hutter --- module/os/freebsd/zfs/zfs_vnops_os.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/module/os/freebsd/zfs/zfs_vnops_os.c b/module/os/freebsd/zfs/zfs_vnops_os.c index fd36dbd300..283f569631 100644 --- a/module/os/freebsd/zfs/zfs_vnops_os.c +++ b/module/os/freebsd/zfs/zfs_vnops_os.c @@ -6072,7 +6072,6 @@ zfs_freebsd_copy_file_range(struct vop_copy_file_range_args *ap) struct vnode *invp = ap->a_invp; struct vnode *outvp = ap->a_outvp; struct mount *mp; - struct uio io; int error; 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; #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), ap->a_outoffp, &len, ap->a_outcred); if (error == EXDEV || error == EAGAIN || error == EINVAL ||