/* * File table vnode read routine. */ static int vn_read(file_t *fp, off_t *offset, struct uio *uio, kauth_cred_t cred, int flags) { struct vnode *vp = (struct vnode *)fp->f_data; int error, ioflag, fflag; size_t count; ioflag = IO_ADV_ENCODE(fp->f_advice); fflag = fp->f_flag; if (fflag & FNONBLOCK) ioflag |= IO_NDELAY; if ((fflag & (FFSYNC | FRSYNC)) == (FFSYNC | FRSYNC)) ioflag |= IO_SYNC; if (fflag & FALTIO) ioflag |= IO_ALTSEMANTICS; if (fflag & FDIRECT) ioflag |= IO_DIRECT; vn_lock(vp, LK_SHARED | LK_RETRY); uio->uio_offset = *offset; count = uio->uio_resid; error = VOP_READ(vp, uio, ioflag, cred); if (flags & FOF_UPDATE_OFFSET) *offset += count - uio->uio_resid; VOP_UNLOCK(vp); return (error); }
/* * File table vnode write routine. */ static int vn_write(file_t *fp, off_t *offset, struct uio *uio, kauth_cred_t cred, int flags) { struct vnode *vp = (struct vnode *)fp->f_data; int error, ioflag, fflag; size_t count; ioflag = IO_ADV_ENCODE(fp->f_advice) | IO_UNIT; fflag = fp->f_flag; if (vp->v_type == VREG && (fflag & O_APPEND)) ioflag |= IO_APPEND; if (fflag & FNONBLOCK) ioflag |= IO_NDELAY; if (fflag & FFSYNC || (vp->v_mount && (vp->v_mount->mnt_flag & MNT_SYNCHRONOUS))) ioflag |= IO_SYNC; else if (fflag & FDSYNC) ioflag |= IO_DSYNC; if (fflag & FALTIO) ioflag |= IO_ALTSEMANTICS; if (fflag & FDIRECT) ioflag |= IO_DIRECT; vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); uio->uio_offset = *offset; count = uio->uio_resid; if ((error = enforce_rlimit_fsize(vp, uio, ioflag)) != 0) goto out; error = VOP_WRITE(vp, uio, ioflag, cred); if (flags & FOF_UPDATE_OFFSET) { if (ioflag & IO_APPEND) { /* * SUSv3 describes behaviour for count = 0 as following: * "Before any action ... is taken, and if nbyte is zero * and the file is a regular file, the write() function * ... in the absence of errors ... shall return zero * and have no other results." */ if (count) *offset = uio->uio_offset; } else *offset += count - uio->uio_resid; } out: VOP_UNLOCK(vp); return (error); }
/* * Handes the read/write request given in 'bp' using the vnode's VOP_READ * and VOP_WRITE operations. * * 'obp' is a pointer to the original request fed to the vnd device. */ static void handle_with_rdwr(struct vnd_softc *vnd, const struct buf *obp, struct buf *bp) { bool doread; off_t offset; size_t len, resid; struct vnode *vp; doread = bp->b_flags & B_READ; offset = obp->b_rawblkno * vnd->sc_dkdev.dk_label->d_secsize; len = bp->b_bcount; vp = vnd->sc_vp; #if defined(DEBUG) if (vnddebug & VDB_IO) printf("vnd (rdwr): vp %p, %s, rawblkno 0x%" PRIx64 ", secsize %d, offset %" PRIu64 ", bcount %d\n", vp, doread ? "read" : "write", obp->b_rawblkno, vnd->sc_dkdev.dk_label->d_secsize, offset, bp->b_bcount); #endif /* Issue the read or write operation. */ bp->b_error = vn_rdwr(doread ? UIO_READ : UIO_WRITE, vp, bp->b_data, len, offset, UIO_SYSSPACE, IO_ADV_ENCODE(POSIX_FADV_NOREUSE), vnd->sc_cred, &resid, NULL); bp->b_resid = resid; mutex_enter(vp->v_interlock); (void) VOP_PUTPAGES(vp, 0, 0, PGO_ALLPAGES | PGO_CLEANIT | PGO_FREE | PGO_SYNCIO); /* We need to increase the number of outputs on the vnode if * there was any write to it. */ if (!doread) { mutex_enter(vp->v_interlock); vp->v_numoutput++; mutex_exit(vp->v_interlock); } biodone(bp); }
/* * Read/write clusters from/to backing store. * For persistent snapshots must be called with cl == 0. off is the * offset into the snapshot. */ static int fss_bs_io(struct fss_softc *sc, fss_io_type rw, u_int32_t cl, off_t off, int len, void *data) { int error; off += FSS_CLTOB(sc, cl); vn_lock(sc->sc_bs_vp, LK_EXCLUSIVE|LK_RETRY); error = vn_rdwr((rw == FSS_READ ? UIO_READ : UIO_WRITE), sc->sc_bs_vp, data, len, off, UIO_SYSSPACE, IO_ADV_ENCODE(POSIX_FADV_NOREUSE) | IO_NODELOCKED, sc->sc_bs_lwp->l_cred, NULL, NULL); if (error == 0) { mutex_enter(sc->sc_bs_vp->v_interlock); error = VOP_PUTPAGES(sc->sc_bs_vp, trunc_page(off), round_page(off+len), PGO_CLEANIT | PGO_FREE | PGO_SYNCIO); } VOP_UNLOCK(sc->sc_bs_vp); return error; }