int fp_read(file_t fp, void *buf, size_t nbytes, ssize_t *res, int all, enum uio_seg seg) { struct uio auio; struct iovec aiov; int error; int lastresid; if (res) *res = 0; if (nbytes > LONG_MAX) return (EINVAL); bzero(&auio, sizeof(auio)); aiov.iov_base = (caddr_t)buf; aiov.iov_len = nbytes; auio.uio_iov = &aiov; auio.uio_iovcnt = 1; auio.uio_offset = 0; auio.uio_resid = nbytes; auio.uio_rw = UIO_READ; auio.uio_segflg = seg; auio.uio_td = curthread; /* * If all is false call fo_read() once. * If all is true we attempt to read the entire request. We have to * break out of the loop if an unrecoverable error or EOF occurs. */ do { lastresid = auio.uio_resid; error = fo_read(fp, &auio, fp->f_cred, 0); } while (all && auio.uio_resid && ((error == 0 && auio.uio_resid != lastresid) || error == ERESTART || error == EINTR)); if (all && error == 0 && auio.uio_resid) error = ESPIPE; /* * If an error occured but some data was read, silently forget the * error. However, if this is a non-blocking descriptor and 'all' * was specified, return an error even if some data was read (this * is considered a bug in the caller for using an illegal combination * of 'all' and a non-blocking descriptor). */ if (error) { if (auio.uio_resid != nbytes) { if (error == ERESTART || error == EINTR) error = 0; if (error == EWOULDBLOCK && all == 0) error = 0; } } if (res) *res = nbytes - auio.uio_resid; return(error); }
/* * Our version of vn_rdwr, here "vp" is not actually a vnode, but a ptr * to the node allocated in getf(). We use the "fp" part of the node to * be able to issue IO. * You must call getf() before calling spl_vn_rdwr(). */ int spl_vn_rdwr(enum uio_rw rw, struct vnode *vp, caddr_t base, ssize_t len, offset_t offset, enum uio_seg seg, int ioflag, rlim64_t ulimit, /* meaningful only if rw is UIO_WRITE */ cred_t *cr, ssize_t *residp) { struct spl_fileproc *sfp = (struct spl_fileproc*)vp; uio_t *auio; int spacetype; int error=0; vfs_context_t vctx; spacetype = UIO_SEG_IS_USER_SPACE(seg) ? UIO_USERSPACE32 : UIO_SYSSPACE; vctx = vfs_context_create((vfs_context_t)0); auio = uio_create(1, 0, spacetype, rw); uio_reset(auio, offset, spacetype, rw); uio_addiov(auio, (uint64_t)(uintptr_t)base, len); if (rw == UIO_READ) { error = fo_read(sfp->f_fp, auio, ioflag, vctx); } else { error = fo_write(sfp->f_fp, auio, ioflag, vctx); sfp->f_writes = 1; } if (residp) { *residp = uio_resid(auio); } else { if (uio_resid(auio) && error == 0) error = EIO; } uio_free(auio); vfs_context_rele(vctx); return (error); }
/* * Read from filp inside kernel */ int kern_file_read (cfs_file_t *fp, void *buf, size_t nbyte, loff_t *pos) { struct uio auio; struct iovec aiov; struct proc *p = current_proc(); long cnt, error = 0; int flags = 0; CFS_DECL_CONE_DATA; aiov.iov_base = (caddr_t)buf; aiov.iov_len = nbyte; auio.uio_iov = &aiov; auio.uio_iovcnt = 1; if (pos != NULL) { auio.uio_offset = *pos; flags |= FOF_OFFSET; } else auio.uio_offset = (off_t)-1; if (nbyte > INT_MAX) return (EINVAL); auio.uio_resid = nbyte; auio.uio_rw = UIO_READ; auio.uio_segflg = UIO_SYSSPACE; auio.uio_procp = p; cnt = nbyte; CFS_CONE_IN; if ((error = fo_read(fp, &auio, fp->f_cred, flags, p)) != 0) { if (auio.uio_resid != cnt && (error == ERESTART || error == EINTR || error == EWOULDBLOCK)) error = 0; } CFS_CONE_EX; if (error != 0) cnt = -error; else cnt -= auio.uio_resid; if (pos != NULL) *pos += cnt; return cnt; }
/* * fp_*read() is meant to operate like the normal descriptor based syscalls * would. Note that if 'buf' points to user memory a UIO_USERSPACE * transfer will be used. */ int fp_pread(file_t fp, void *buf, size_t nbytes, off_t offset, ssize_t *res, enum uio_seg seg) { struct uio auio; struct iovec aiov; size_t count; int error; if (res) *res = 0; if (nbytes > LONG_MAX) return (EINVAL); bzero(&auio, sizeof(auio)); aiov.iov_base = (caddr_t)buf; aiov.iov_len = nbytes; auio.uio_iov = &aiov; auio.uio_iovcnt = 1; auio.uio_offset = offset; auio.uio_resid = nbytes; auio.uio_rw = UIO_READ; auio.uio_segflg = seg; auio.uio_td = curthread; count = nbytes; error = fo_read(fp, &auio, fp->f_cred, O_FOFFSET); if (error) { if (auio.uio_resid != nbytes && (error == ERESTART || error == EINTR || error == EWOULDBLOCK) ) { error = 0; } } count -= auio.uio_resid; if (res) *res = count; return(error); }