Index: sys/kern/vfs_vnops.c =================================================================== --- sys/kern/vfs_vnops.c +++ sys/kern/vfs_vnops.c @@ -184,6 +184,22 @@ } args; }; +/* + * Structure used to pass arguments to vn_deallocate_impl(), to do either + * file- or vnode-based I/O calls. + */ +struct vn_deallocate_args { + enum { + VN_DEALLOCATE_FOP, + VN_DEALLOCATE_VOP + } kind; + struct vnode *vp; + struct ucred *active_cred; + struct ucred *file_cred; + int flags; + int ioflag; +}; + static int vn_io_fault1(struct vnode *vp, struct uio *uio, struct vn_io_fault_args *args, struct thread *td); @@ -3462,9 +3478,10 @@ } 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) +vn_deallocate_impl(struct vn_deallocate_args *args, off_t *offset, + off_t *length) { + struct ucred *cred; struct mount *mp; void *rl_cookie; off_t off, len; @@ -3472,14 +3489,16 @@ #ifdef AUDIT bool audited_vnode1 = false; #endif + struct vnode *vp; rl_cookie = NULL; error = 0; mp = NULL; off = *offset; len = *length; + vp = args->vp; - if ((ioflag & (IO_NODELOCKED | IO_RANGELOCKED)) == 0) + if ((args->ioflag & (IO_NODELOCKED | IO_RANGELOCKED)) == 0) rl_cookie = vn_rangelock_wlock(vp, off, off + len); while (len > 0 && error == 0) { /* @@ -3489,7 +3508,7 @@ * pass. */ - if ((ioflag & IO_NODELOCKED) == 0) { + if ((args->ioflag & IO_NODELOCKED) == 0) { bwillwrite(); if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0) @@ -3504,15 +3523,21 @@ #endif #ifdef MAC - if ((ioflag & IO_NOMACCHECK) == 0) - error = mac_vnode_check_write(active_cred, file_cred, - vp); + if ((args->ioflag & IO_NOMACCHECK) == 0) + error = mac_vnode_check_write(args->active_cred, + args->file_cred, vp); #endif - if (error == 0) - error = VOP_DEALLOCATE(vp, &off, &len, flags, ioflag, - active_cred); + if (error == 0) { + if (args->kind == VN_DEALLOCATE_VOP && + args->file_cred != NULL) + cred = args->file_cred; + else + cred = args->active_cred; + error = VOP_DEALLOCATE(vp, &off, &len, args->flags, + args->ioflag, cred); + } - if ((ioflag & IO_NODELOCKED) == 0) { + if ((args->ioflag & IO_NODELOCKED) == 0) { VOP_UNLOCK(vp); if (mp != NULL) { vn_finished_write(mp); @@ -3530,27 +3555,38 @@ return (error); } +/* + * If file_cred is non-NULL, it is chosen over active_cred. + */ int vn_deallocate(struct vnode *vp, off_t *offset, off_t *length, int flags, int ioflag, struct ucred *active_cred, struct ucred *file_cred) { + struct vn_deallocate_args args; + if (*offset < 0 || *length <= 0 || *length > OFF_MAX - *offset || flags != 0) return (EINVAL); if (vp->v_type != VREG) return (ENODEV); - return (vn_deallocate_impl(vp, offset, length, flags, ioflag, - active_cred, file_cred)); + args.vp = vp; + args.kind = VN_DEALLOCATE_VOP; + args.active_cred = active_cred; + args.file_cred = file_cred; + args.flags = flags; + args.ioflag = ioflag; + return (vn_deallocate_impl(&args, offset, length)); } static int vn_fspacectl(struct file *fp, int cmd, off_t *offset, off_t *length, int flags, struct ucred *active_cred, struct thread *td) { - int error; + struct vn_deallocate_args args; struct vnode *vp; int ioflag; + int error; vp = fp->f_vnode; @@ -3564,8 +3600,13 @@ switch (cmd) { case SPACECTL_DEALLOC: - error = vn_deallocate_impl(vp, offset, length, flags, ioflag, - active_cred, fp->f_cred); + args.vp = vp; + args.kind = VN_DEALLOCATE_FOP; + args.active_cred = active_cred; + args.file_cred = fp->f_cred; + args.flags = flags; + args.ioflag = ioflag; + error = vn_deallocate_impl(&args, offset, length); break; default: panic("vn_fspacectl: unknown cmd %d", cmd);