Index: sys/kern/vfs_vnops.c =================================================================== --- sys/kern/vfs_vnops.c +++ sys/kern/vfs_vnops.c @@ -3461,11 +3461,18 @@ return (error); } +#define IO_VOPFCRED (1 << IO_SEQSHIFT) + +/* + * As this does not accept higher 16-bit in ioflag, the higher part is used + * to pass internal flags. + */ static int vn_deallocate_impl(struct vnode *vp, off_t *offset, off_t *length, int flags, int ioflag, struct ucred *active_cred, struct ucred *file_cred) { struct mount *mp; + struct ucred *cred; void *rl_cookie; off_t off, len; int error; @@ -3478,6 +3485,11 @@ mp = NULL; off = *offset; len = *length; + ioflag &= (1 << IO_SEQSHIFT) - 1; + if (file_cred != NOCRED && (ioflag & IO_VOPFCRED) != 0) + cred = file_cred; + else + cred = active_cred; if ((ioflag & (IO_NODELOCKED | IO_RANGELOCKED)) == 0) rl_cookie = vn_rangelock_wlock(vp, off, off + len); @@ -3510,7 +3522,7 @@ #endif if (error == 0) error = VOP_DEALLOCATE(vp, &off, &len, flags, ioflag, - active_cred); + cred); if ((ioflag & IO_NODELOCKED) == 0) { VOP_UNLOCK(vp); @@ -3530,16 +3542,21 @@ return (error); } +/* + * If file_cred is not NOCRED, it is chosen over active_cred. + * Sequential heuristic in ioflag is not accepted. + */ int vn_deallocate(struct vnode *vp, off_t *offset, off_t *length, int flags, int ioflag, struct ucred *active_cred, struct ucred *file_cred) { if (*offset < 0 || *length <= 0 || *length > OFF_MAX - *offset || - flags != 0) + flags != 0 || (ioflag >> IO_SEQSHIFT) != 0) return (EINVAL); if (vp->v_type != VREG) return (ENODEV); + ioflag |= IO_VOPFCRED; return (vn_deallocate_impl(vp, offset, length, flags, ioflag, active_cred, file_cred)); }