Date: Wed, 28 Dec 2022 22:43:54 GMT From: Mateusz Guzik <mjg@FreeBSD.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org Subject: git: f45feecfb27c - main - vfs: add vn_getsize Message-ID: <202212282243.2BSMhsbr040685@gitrepo.freebsd.org>
next in thread | raw e-mail | index | archive | help
The branch main has been updated by mjg: URL: https://cgit.FreeBSD.org/src/commit/?id=f45feecfb27ca51067d6789eaa43547cadc4990b commit f45feecfb27ca51067d6789eaa43547cadc4990b Author: Mateusz Guzik <mjg@FreeBSD.org> AuthorDate: 2022-09-22 13:55:49 +0000 Commit: Mateusz Guzik <mjg@FreeBSD.org> CommitDate: 2022-12-28 22:43:49 +0000 vfs: add vn_getsize getattr is very expensive and in important cases only gets called to get the size. This can be optimized with a dedicated routine which obtains that statistic. As a step towards that goal make size-only consumers use a dedicated routine. Reviewed by: kib Differential Revision: https://reviews.freebsd.org/D37885 --- sys/kern/kern_sendfile.c | 4 +-- sys/kern/vfs_subr.c | 30 +++++++++++++++++++--- sys/kern/vfs_vnops.c | 66 ++++++++++++++++++++++-------------------------- sys/sys/vnode.h | 2 ++ sys/vm/vnode_pager.c | 4 +-- 5 files changed, 61 insertions(+), 45 deletions(-) diff --git a/sys/kern/kern_sendfile.c b/sys/kern/kern_sendfile.c index 96f95e4c841f..12842e3476e1 100644 --- a/sys/kern/kern_sendfile.c +++ b/sys/kern/kern_sendfile.c @@ -563,7 +563,6 @@ sendfile_getobj(struct thread *td, struct file *fp, vm_object_t *obj_res, struct vnode **vp_res, struct shmfd **shmfd_res, off_t *obj_size, int *bsize) { - struct vattr va; vm_object_t obj; struct vnode *vp; struct shmfd *shmfd; @@ -602,10 +601,9 @@ sendfile_getobj(struct thread *td, struct file *fp, vm_object_t *obj_res, VM_OBJECT_RLOCK(obj); *obj_size = obj->un_pager.vnp.vnp_size; } else { - error = VOP_GETATTR(vp, &va, td->td_ucred); + error = vn_getsize_locked(vp, obj_size, td->td_ucred); if (error != 0) goto out; - *obj_size = va.va_size; VM_OBJECT_RLOCK(obj); } } else if (fp->f_type == DTYPE_SHM) { diff --git a/sys/kern/vfs_subr.c b/sys/kern/vfs_subr.c index b3f12bb52928..d49f97a7060e 100644 --- a/sys/kern/vfs_subr.c +++ b/sys/kern/vfs_subr.c @@ -6377,7 +6377,7 @@ static int filt_vfsread(struct knote *kn, long hint) { struct vnode *vp = (struct vnode *)kn->kn_hook; - struct vattr va; + off_t size; int res; /* @@ -6391,11 +6391,11 @@ filt_vfsread(struct knote *kn, long hint) return (1); } - if (VOP_GETATTR(vp, &va, curthread->td_ucred)) + if (vn_getsize_locked(vp, &size, curthread->td_ucred) != 0) return (0); VI_LOCK(vp); - kn->kn_data = va.va_size - kn->kn_fp->f_offset; + kn->kn_data = size - kn->kn_fp->f_offset; res = (kn->kn_sfflags & NOTE_FILE_POLL) != 0 || kn->kn_data != 0; VI_UNLOCK(vp); return (res); @@ -7116,6 +7116,30 @@ vn_irflag_unset(struct vnode *vp, short tounset) VI_UNLOCK(vp); } +int +vn_getsize_locked(struct vnode *vp, off_t *size, struct ucred *cred) +{ + struct vattr vattr; + int error; + + ASSERT_VOP_LOCKED(vp, __func__); + error = VOP_GETATTR(vp, &vattr, cred); + if (__predict_true(error == 0)) + *size = vattr.va_size; + return (error); +} + +int +vn_getsize(struct vnode *vp, off_t *size, struct ucred *cred) +{ + int error; + + VOP_LOCK(vp, LK_SHARED); + error = vn_getsize_locked(vp, size, cred); + VOP_UNLOCK(vp); + return (error); +} + #ifdef INVARIANTS void vn_set_state_validate(struct vnode *vp, enum vstate state) diff --git a/sys/kern/vfs_vnops.c b/sys/kern/vfs_vnops.c index 4d8963100a43..f3a6360eb250 100644 --- a/sys/kern/vfs_vnops.c +++ b/sys/kern/vfs_vnops.c @@ -1690,9 +1690,9 @@ static int vn_ioctl(struct file *fp, u_long com, void *data, struct ucred *active_cred, struct thread *td) { - struct vattr vattr; struct vnode *vp; struct fiobmap2_arg *bmarg; + off_t size; int error; vp = fp->f_vnode; @@ -1701,11 +1701,9 @@ vn_ioctl(struct file *fp, u_long com, void *data, struct ucred *active_cred, case VREG: switch (com) { case FIONREAD: - vn_lock(vp, LK_SHARED | LK_RETRY); - error = VOP_GETATTR(vp, &vattr, active_cred); - VOP_UNLOCK(vp); + error = vn_getsize(vp, &size, active_cred); if (error == 0) - *(int *)data = vattr.va_size - fp->f_offset; + *(int *)data = size - fp->f_offset; return (error); case FIOBMAP2: bmarg = (struct fiobmap2_arg *)data; @@ -2558,7 +2556,7 @@ int vn_bmap_seekhole_locked(struct vnode *vp, u_long cmd, off_t *off, struct ucred *cred) { - struct vattr va; + off_t size; daddr_t bn, bnp; uint64_t bsize; off_t noff; @@ -2572,16 +2570,16 @@ vn_bmap_seekhole_locked(struct vnode *vp, u_long cmd, off_t *off, error = ENOTTY; goto out; } - error = VOP_GETATTR(vp, &va, cred); + error = vn_getsize_locked(vp, &size, cred); if (error != 0) goto out; noff = *off; - if (noff < 0 || noff >= va.va_size) { + if (noff < 0 || noff >= size) { error = ENXIO; goto out; } bsize = vp->v_mount->mnt_stat.f_iosize; - for (bn = noff / bsize; noff < va.va_size; bn++, noff += bsize - + for (bn = noff / bsize; noff < size; bn++, noff += bsize - noff % bsize) { error = VOP_BMAP(vp, bn, NULL, &bnp, NULL, NULL); if (error == EOPNOTSUPP) { @@ -2596,9 +2594,9 @@ vn_bmap_seekhole_locked(struct vnode *vp, u_long cmd, off_t *off, goto out; } } - if (noff > va.va_size) - noff = va.va_size; - /* noff == va.va_size. There is an implicit hole at the end of file. */ + if (noff > size) + noff = size; + /* noff == size. There is an implicit hole at the end of file. */ if (cmd == FIOSEEKDATA) error = ENXIO; out: @@ -2627,8 +2625,7 @@ vn_seek(struct file *fp, off_t offset, int whence, struct thread *td) { struct ucred *cred; struct vnode *vp; - struct vattr vattr; - off_t foffset, size; + off_t foffset, fsize, size; int error, noneg; cred = td->td_ucred; @@ -2647,10 +2644,8 @@ vn_seek(struct file *fp, off_t offset, int whence, struct thread *td) offset += foffset; break; case L_XTND: - vn_lock(vp, LK_SHARED | LK_RETRY); - error = VOP_GETATTR(vp, &vattr, cred); - VOP_UNLOCK(vp); - if (error) + error = vn_getsize(vp, &fsize, cred); + if (error != 0) break; /* @@ -2658,16 +2653,16 @@ vn_seek(struct file *fp, off_t offset, int whence, struct thread *td) * the media size and use that to determine the ending * offset. */ - if (vattr.va_size == 0 && vp->v_type == VCHR && + if (fsize == 0 && vp->v_type == VCHR && fo_ioctl(fp, DIOCGMEDIASIZE, &size, cred, td) == 0) - vattr.va_size = size; + fsize = size; if (noneg && - (vattr.va_size > OFF_MAX || - (offset > 0 && vattr.va_size > OFF_MAX - offset))) { + (fsize > OFF_MAX || + (offset > 0 && fsize > OFF_MAX - offset))) { error = EOVERFLOW; break; } - offset += vattr.va_size; + offset += fsize; break; case L_SET: break; @@ -3259,7 +3254,6 @@ vn_generic_copy_file_range(struct vnode *invp, off_t *inoffp, struct vnode *outvp, off_t *outoffp, size_t *lenp, unsigned int flags, struct ucred *incred, struct ucred *outcred, struct thread *fsize_td) { - struct vattr va, inva; struct mount *mp; off_t startoff, endoff, xfer, xfer2; u_long blksize; @@ -3267,6 +3261,7 @@ vn_generic_copy_file_range(struct vnode *invp, off_t *inoffp, bool cantseek, readzeros, eof, lastblock, holetoeof; ssize_t aresid, r = 0; size_t copylen, len, savlen; + off_t insize, outsize; char *dat; long holein, holeout; struct timespec curts, endts; @@ -3283,7 +3278,7 @@ vn_generic_copy_file_range(struct vnode *invp, off_t *inoffp, if (VOP_PATHCONF(invp, _PC_MIN_HOLE_SIZE, &holein) != 0) holein = 0; if (holein > 0) - error = VOP_GETATTR(invp, &inva, incred); + error = vn_getsize_locked(invp, &insize, incred); VOP_UNLOCK(invp); if (error != 0) goto out; @@ -3314,13 +3309,12 @@ vn_generic_copy_file_range(struct vnode *invp, off_t *inoffp, /* * Holes that are past EOF do not need to be written as a block * of zero bytes. So, truncate the output file as far as - * possible and then use va.va_size to decide if writing 0 + * possible and then use size to decide if writing 0 * bytes is necessary in the loop below. */ if (error == 0) - error = VOP_GETATTR(outvp, &va, outcred); - if (error == 0 && va.va_size > *outoffp && va.va_size <= - *outoffp + len) { + error = vn_getsize_locked(outvp, &outsize, outcred); + if (error == 0 && outsize > *outoffp && outsize <= *outoffp + len) { #ifdef MAC error = mac_vnode_check_write(curthread->td_ucred, outcred, outvp); @@ -3329,7 +3323,7 @@ vn_generic_copy_file_range(struct vnode *invp, off_t *inoffp, error = vn_truncate_locked(outvp, *outoffp, false, outcred); if (error == 0) - va.va_size = *outoffp; + outsize = *outoffp; } VOP_UNLOCK(outvp); } @@ -3409,7 +3403,7 @@ vn_generic_copy_file_range(struct vnode *invp, off_t *inoffp, error = VOP_IOCTL(invp, FIOSEEKDATA, &startoff, 0, incred, curthread); if (error == ENXIO) { - startoff = endoff = inva.va_size; + startoff = endoff = insize; eof = holetoeof = true; error = 0; } @@ -3434,9 +3428,9 @@ vn_generic_copy_file_range(struct vnode *invp, off_t *inoffp, if (startoff > *inoffp) { /* Found hole before data block. */ xfer = MIN(startoff - *inoffp, len); - if (*outoffp < va.va_size) { + if (*outoffp < outsize) { /* Must write 0s to punch hole. */ - xfer2 = MIN(va.va_size - *outoffp, + xfer2 = MIN(outsize - *outoffp, xfer); memset(dat, 0, MIN(xfer2, blksize)); error = vn_write_outvp(outvp, dat, @@ -3445,7 +3439,7 @@ vn_generic_copy_file_range(struct vnode *invp, off_t *inoffp, } if (error == 0 && *outoffp + xfer > - va.va_size && (xfer == len || holetoeof)) { + outsize && (xfer == len || holetoeof)) { /* Grow output file (hole at end). */ error = vn_write_outvp(outvp, dat, *outoffp, xfer, blksize, true, @@ -3515,12 +3509,12 @@ vn_generic_copy_file_range(struct vnode *invp, off_t *inoffp, false; if (xfer == len) lastblock = true; - if (!cantseek || *outoffp < va.va_size || + if (!cantseek || *outoffp < outsize || lastblock || !readzeros) error = vn_write_outvp(outvp, dat, *outoffp, xfer, blksize, readzeros && lastblock && - *outoffp >= va.va_size, false, + *outoffp >= outsize, false, outcred); if (error == 0) { *inoffp += xfer; diff --git a/sys/sys/vnode.h b/sys/sys/vnode.h index b3e67f6dcf31..04596a7184ee 100644 --- a/sys/sys/vnode.h +++ b/sys/sys/vnode.h @@ -1135,6 +1135,8 @@ int vn_chmod(struct file *fp, mode_t mode, struct ucred *active_cred, struct thread *td); int vn_chown(struct file *fp, uid_t uid, gid_t gid, struct ucred *active_cred, struct thread *td); +int vn_getsize_locked(struct vnode *vp, off_t *size, struct ucred *active_cred); +int vn_getsize(struct vnode *vp, off_t *size, struct ucred *active_cred); void vn_fsid(struct vnode *vp, struct vattr *va); diff --git a/sys/vm/vnode_pager.c b/sys/vm/vnode_pager.c index c9917ecc2589..56caf75d7f90 100644 --- a/sys/vm/vnode_pager.c +++ b/sys/vm/vnode_pager.c @@ -155,7 +155,6 @@ vnode_create_vobject(struct vnode *vp, off_t isize, struct thread *td) { vm_object_t object; vm_ooffset_t size = isize; - struct vattr va; bool last; if (!vn_isdisk(vp) && vn_canvmio(vp) == FALSE) @@ -169,9 +168,8 @@ vnode_create_vobject(struct vnode *vp, off_t isize, struct thread *td) if (vn_isdisk(vp)) { size = IDX_TO_OFF(INT_MAX); } else { - if (VOP_GETATTR(vp, &va, td->td_ucred)) + if (vn_getsize_locked(vp, &size, td->td_ucred) != 0) return (0); - size = va.va_size; } }
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202212282243.2BSMhsbr040685>