FreeBSD: Correct _PC_MIN_HOLE_SIZE

The actual minimum hole size on ZFS is variable, but we always report
SPA_MINBLOCKSIZE, which is 512.  This may lead applications to believe
that they can reliably create holes at 512-byte boundaries and waste
resources trying to punch holes that ZFS ends up filling anyway.

* In the general case, if the vnode is a regular file, return its
  current block size, or the record size if the file is smaller than
  its own block size.  If the vnode is a directory, return the dataset
  record size.  If it is neither a regular file nor a directory,
  return EINVAL.

* In the control directory case, always return EINVAL.

Signed-off-by: Dag-Erling Smørgrav <des@FreeBSD.org>
Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Reviewed-by: Alexander Motin <alexander.motin@TrueNAS.com>
Closes #17750
This commit is contained in:
Dag-Erling Smørgrav 2025-10-08 15:13:22 +02:00 committed by GitHub
parent ea914e4a43
commit 6e5b836e9f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 16 additions and 4 deletions

View file

@ -764,8 +764,7 @@ zfsctl_common_pathconf(struct vop_pathconf_args *ap)
return (0);
case _PC_MIN_HOLE_SIZE:
*ap->a_retval = (int)SPA_MINBLOCKSIZE;
return (0);
return (EINVAL);
case _PC_ACL_EXTENDED:
*ap->a_retval = 0;

View file

@ -4118,6 +4118,7 @@ zfs_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr,
{
znode_t *zp;
zfsvfs_t *zfsvfs;
uint_t blksize, iosize;
int error;
switch (cmd) {
@ -4129,8 +4130,20 @@ zfs_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr,
*valp = 64;
return (0);
case _PC_MIN_HOLE_SIZE:
*valp = (int)SPA_MINBLOCKSIZE;
return (0);
iosize = vp->v_mount->mnt_stat.f_iosize;
if (vp->v_type == VREG) {
zp = VTOZ(vp);
blksize = zp->z_blksz;
if (zp->z_size <= blksize)
blksize = MAX(blksize, iosize);
*valp = (int)blksize;
return (0);
}
if (vp->v_type == VDIR) {
*valp = (int)iosize;
return (0);
}
return (EINVAL);
case _PC_ACL_EXTENDED:
#if 0 /* POSIX ACLs are not implemented for ZFS on FreeBSD yet. */
zp = VTOZ(vp);