- if ((bp->b_flags & B_ASYNC) == 0 || nfs_numasync == 0)
- return (nfs_doio(bp));
- for (i = 0; i < NFS_MAXASYNCDAEMON; i++) {
- if (nfs_iodwant[i]) {
- dp = &nfs_bqueue;
- if (dp->b_actf == NULL) {
- dp->b_actl = bp;
- bp->b_actf = dp;
- } else {
- dp->b_actf->b_actl = bp;
- bp->b_actf = dp->b_actf;
- }
- dp->b_actf = bp;
- bp->b_actl = dp;
- fnd++;
- wakeup((caddr_t)&nfs_iodwant[i]);
- break;
- }
- }
- if (!fnd)
- error = nfs_doio(bp);
- return (error);
-}
-
-/*
- * Fun and games with i/o
- * Essentially play ubasetup() and disk interrupt service routine by
- * mapping the data buffer into kernel virtual space and doing the
- * nfs read or write rpc's from it.
- * If the nfsiod's are not running, this is just called from nfs_strategy(),
- * otherwise it is called by the nfsiods to do what would normally be
- * partially disk interrupt driven.
- */
-int
-nfs_doio(bp)
- register struct buf *bp;
-{
- register struct uio *uiop;
- register struct vnode *vp;
- struct nfsnode *np;
- struct ucred *cr;
- int error;
- struct uio uio;
- struct iovec io;
-
- vp = bp->b_vp;
- np = VTONFS(vp);
- uiop = &uio;
- uiop->uio_iov = &io;
- uiop->uio_iovcnt = 1;
- uiop->uio_segflg = UIO_SYSSPACE;
- uiop->uio_procp = bp->b_proc;
-
- /*
- * For phys i/o, map the b_addr into kernel virtual space using
- * the Nfsiomap pte's
- * Also, add a temporary b_rcred for reading using the process's uid
- * and a guess at a group
- */
- if (bp->b_flags & B_PHYS) {
- if (bp->b_flags & B_DIRTY)
- uiop->uio_procp = pageproc;
- cr = crcopy(uiop->uio_procp->p_ucred);
- /* mapping was already done by vmapbuf */
- io.iov_base = bp->b_un.b_addr;
-
- /*
- * And do the i/o rpc
- */
- io.iov_len = uiop->uio_resid = bp->b_bcount;
- uiop->uio_offset = bp->b_blkno * DEV_BSIZE;
- if (bp->b_flags & B_READ) {
- uiop->uio_rw = UIO_READ;
- nfsstats.read_physios++;
- bp->b_error = error = nfs_readrpc(vp, uiop, cr);
- (void) vnode_pager_uncache(vp);
- } else {
- uiop->uio_rw = UIO_WRITE;
- nfsstats.write_physios++;
- bp->b_error = error = nfs_writerpc(vp, uiop, cr);
- }
-
- /*
- * Finally, release pte's used by physical i/o
- */
- crfree(cr);
- } else {
- if (bp->b_flags & B_READ) {
- io.iov_len = uiop->uio_resid = bp->b_bcount;
- io.iov_base = bp->b_un.b_addr;
- uiop->uio_rw = UIO_READ;
- switch (vp->v_type) {
- case VREG:
- uiop->uio_offset = bp->b_blkno * DEV_BSIZE;
- nfsstats.read_bios++;
- error = nfs_readrpc(vp, uiop, bp->b_rcred);
- break;
- case VLNK:
- uiop->uio_offset = 0;
- nfsstats.readlink_bios++;
- error = nfs_readlinkrpc(vp, uiop, bp->b_rcred);
- break;
- case VDIR:
- uiop->uio_offset = bp->b_lblkno;
- nfsstats.readdir_bios++;
- if (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_RDIRALOOK)
- error = nfs_readdirlookrpc(vp, uiop, bp->b_rcred);
- else
- error = nfs_readdirrpc(vp, uiop, bp->b_rcred);
- /*
- * Save offset cookie in b_blkno.
- */
- bp->b_blkno = uiop->uio_offset;
- break;
- };
- bp->b_error = error;
- } else {
- io.iov_len = uiop->uio_resid = bp->b_dirtyend
- - bp->b_dirtyoff;
- uiop->uio_offset = (bp->b_blkno * DEV_BSIZE)
- + bp->b_dirtyoff;
- io.iov_base = bp->b_un.b_addr + bp->b_dirtyoff;
- uiop->uio_rw = UIO_WRITE;
- nfsstats.write_bios++;
- bp->b_error = error = nfs_writerpc(vp, uiop,
- bp->b_wcred);
- if (error) {
- np->n_error = error;
- np->n_flag |= NWRITEERR;
- }
- bp->b_dirtyoff = bp->b_dirtyend = 0;
- }
- }
- if (error)
- bp->b_flags |= B_ERROR;
- bp->b_resid = uiop->uio_resid;
- biodone(bp);