File:  [DragonFly] / src / sys / vfs / nwfs / nwfs_io.c
Revision 1.10: download - view: text, annotated - select for diffs
Thu Apr 22 17:56:44 2004 UTC (10 years, 5 months ago) by cpressey
Branches: MAIN
CVS tags: HEAD, DragonFly_Snap29Sep2004, DragonFly_Snap13Sep2004, DragonFly_1_0_REL, DragonFly_1_0_RC1, DragonFly_1_0A_REL
Style(9) cleanup to src/sys/vfs, stage 13/21: nwfs.

- Convert K&R-style function definitions to ANSI style.

Submitted-by: Andre Nathan <andre@digirati.com.br>
Additional-reformatting-by: cpressey

    1: /*
    2:  * Copyright (c) 1999, Boris Popov
    3:  * All rights reserved.
    4:  *
    5:  * Redistribution and use in source and binary forms, with or without
    6:  * modification, are permitted provided that the following conditions
    7:  * are met:
    8:  * 1. Redistributions of source code must retain the above copyright
    9:  *    notice, this list of conditions and the following disclaimer.
   10:  * 2. Redistributions in binary form must reproduce the above copyright
   11:  *    notice, this list of conditions and the following disclaimer in the
   12:  *    documentation and/or other materials provided with the distribution.
   13:  * 3. All advertising materials mentioning features or use of this software
   14:  *    must display the following acknowledgement:
   15:  *    This product includes software developed by Boris Popov.
   16:  * 4. Neither the name of the author nor the names of any co-contributors
   17:  *    may be used to endorse or promote products derived from this software
   18:  *    without specific prior written permission.
   19:  *
   20:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   21:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   22:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   23:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   24:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   25:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   26:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   27:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   28:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   29:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   30:  * SUCH DAMAGE.
   31:  *
   32:  * $FreeBSD: src/sys/nwfs/nwfs_io.c,v 1.6.2.1 2000/10/25 02:11:10 bp Exp $
   33:  * $DragonFly: src/sys/vfs/nwfs/nwfs_io.c,v 1.10 2004/04/22 17:56:44 cpressey Exp $
   34:  *
   35:  */
   36: #include <sys/param.h>
   37: #include <sys/systm.h>
   38: #include <sys/resourcevar.h>	/* defines plimit structure in proc struct */
   39: #include <sys/kernel.h>
   40: #include <sys/buf.h>
   41: #include <sys/proc.h>
   42: #include <sys/mount.h>
   43: #include <sys/namei.h>
   44: #include <sys/vnode.h>
   45: #include <sys/dirent.h>
   46: #include <sys/signalvar.h>
   47: #include <sys/sysctl.h>
   48: 
   49: #include <vm/vm.h>
   50: #include <vm/vm_page.h>
   51: #include <vm/vm_extern.h>
   52: #include <vm/vm_object.h>
   53: #include <vm/vm_pager.h>
   54: #include <vm/vnode_pager.h>
   55: 
   56: #include <netproto/ncp/ncp.h>
   57: #include <netproto/ncp/ncp_conn.h>
   58: #include <netproto/ncp/ncp_subr.h>
   59: 
   60: #include "nwfs.h"
   61: #include "nwfs_node.h"
   62: #include "nwfs_subr.h"
   63: 
   64: static int nwfs_fastlookup = 1;
   65: 
   66: SYSCTL_DECL(_vfs_nwfs);
   67: SYSCTL_INT(_vfs_nwfs, OID_AUTO, fastlookup, CTLFLAG_RW, &nwfs_fastlookup, 0, "");
   68: 
   69: 
   70: extern int nwfs_pbuf_freecnt;
   71: 
   72: #define DE_SIZE	(sizeof(struct dirent))
   73: #define	NWFS_RWCACHE
   74: 
   75: static int
   76: nwfs_readvdir(struct vnode *vp, struct uio *uio, struct ucred *cred)
   77: {
   78: 	struct nwmount *nmp = VTONWFS(vp);
   79: 	int error, count, i;
   80: 	struct dirent dp;
   81: 	struct nwnode *np = VTONW(vp);
   82: 	struct nw_entry_info fattr;
   83: 	struct vnode *newvp;
   84: 	struct componentname cn;
   85: 	ncpfid fid;
   86: 
   87: 	np = VTONW(vp);
   88: 	NCPVNDEBUG("dirname='%s'\n",np->n_name);
   89: 	if (uio->uio_resid < DE_SIZE || (uio->uio_offset < 0))
   90: 		return (EINVAL);
   91: 	error = 0;
   92: 	count = 0;
   93: 	i = uio->uio_offset / DE_SIZE; /* offset in directory */
   94: 	if (i == 0) {
   95: 		error = ncp_initsearch(vp, uio->uio_td, cred);
   96: 		if (error) {
   97: 			NCPVNDEBUG("cannot initialize search, error=%d",error);
   98: 			return( error );
   99: 		}
  100: 	}
  101: 
  102: 	for (; uio->uio_resid >= DE_SIZE; i++) {
  103: 		bzero((char *) &dp, DE_SIZE);
  104: 		dp.d_reclen = DE_SIZE;
  105: 		switch (i) {
  106: 		    case 0:		/* `.' */
  107: 		    case 1:		/* `..' */
  108: 			dp.d_fileno = (i == 0) ? np->n_fid.f_id : np->n_parent.f_id;
  109: 			if (!dp.d_fileno) dp.d_fileno = NWFS_ROOT_INO;
  110: 			dp.d_namlen = i + 1;
  111: 			dp.d_name[0] = '.';
  112: 			dp.d_name[1] = '.';
  113: 			dp.d_name[i + 1] = '\0';
  114: 			dp.d_type = DT_DIR;
  115: 			break;
  116: 		    default:
  117: 			error = ncp_search_for_file_or_subdir(nmp, &np->n_seq, &fattr, uio->uio_td, cred);
  118: 			if (error && error < 0x80) break;
  119: 			dp.d_fileno = fattr.dirEntNum;
  120: 			dp.d_type = (fattr.attributes & aDIR) ? DT_DIR : DT_REG;
  121: 			dp.d_namlen = fattr.nameLen;
  122: 			bcopy(fattr.entryName, dp.d_name, dp.d_namlen);
  123: 			dp.d_name[dp.d_namlen] = '\0';
  124: #if 0
  125: 			if (error && eofflag) {
  126: 			/*	*eofflag = 1;*/
  127: 			        break;
  128: 			}
  129: #endif
  130: 			break;
  131: 		}
  132: 		if (nwfs_fastlookup && !error && i > 1) {
  133: 			fid.f_id = fattr.dirEntNum;
  134: 			fid.f_parent = np->n_fid.f_id;
  135: 			error = nwfs_nget(vp->v_mount, fid, &fattr, vp, &newvp);
  136: 			if (!error) {
  137: 				VTONW(newvp)->n_ctime = VTONW(newvp)->n_vattr.va_ctime.tv_sec;
  138: 				cn.cn_nameptr = dp.d_name;
  139: 				cn.cn_namelen = dp.d_namlen;
  140: 			        cache_enter(vp, NCPNULL, newvp, &cn);
  141: 				vput(newvp);
  142: 			} else
  143: 				error = 0;
  144: 		}
  145: 		if (error >= 0x80) {
  146: 		    error = 0;
  147: 		    break;
  148: 		}
  149: 		if ((error = uiomove((caddr_t)&dp, DE_SIZE, uio)))
  150: 			break;
  151: 	}
  152: 
  153: 	uio->uio_offset = i * DE_SIZE;
  154: 	return (error);
  155: }
  156: 
  157: int
  158: nwfs_readvnode(struct vnode *vp, struct uio *uiop, struct ucred *cred)
  159: {
  160: 	struct nwmount *nmp = VFSTONWFS(vp->v_mount);
  161: 	struct nwnode *np = VTONW(vp);
  162: 	struct thread *td;
  163: 	struct vattr vattr;
  164: 	int error, biosize;
  165: 
  166: 	if (vp->v_type != VREG && vp->v_type != VDIR) {
  167: 		printf("%s: vn types other than VREG or VDIR are unsupported !\n",__FUNCTION__);
  168: 		return EIO;
  169: 	}
  170: 	if (uiop->uio_resid == 0) return 0;
  171: 	if (uiop->uio_offset < 0) return EINVAL;
  172: /*	if (uiop->uio_offset + uiop->uio_resid > nmp->nm_maxfilesize)
  173: 		return (EFBIG);*/
  174: 	td = uiop->uio_td;
  175: 	if (vp->v_type == VDIR) {
  176: 		error = nwfs_readvdir(vp, uiop, cred);
  177: 		return error;
  178: 	}
  179: 	biosize = NWFSTOCONN(nmp)->buffer_size;
  180: 	if (np->n_flag & NMODIFIED) {
  181: 		nwfs_attr_cacheremove(vp);
  182: 		error = VOP_GETATTR(vp, &vattr, td);
  183: 		if (error) return (error);
  184: 		np->n_mtime = vattr.va_mtime.tv_sec;
  185: 	} else {
  186: 		error = VOP_GETATTR(vp, &vattr, td);
  187: 		if (error) return (error);
  188: 		if (np->n_mtime != vattr.va_mtime.tv_sec) {
  189: 			error = nwfs_vinvalbuf(vp, V_SAVE, td, 1);
  190: 			if (error) return (error);
  191: 			np->n_mtime = vattr.va_mtime.tv_sec;
  192: 		}
  193: 	}
  194: 	error = ncp_read(NWFSTOCONN(nmp), &np->n_fh, uiop,cred);
  195: 	return (error);
  196: }
  197: 
  198: int
  199: nwfs_writevnode(struct vnode *vp, struct uio *uiop, struct ucred *cred,
  200: 		int ioflag)
  201: {
  202: 	struct nwmount *nmp = VTONWFS(vp);
  203: 	struct nwnode *np = VTONW(vp);
  204: 	struct thread *td;
  205: /*	struct vattr vattr;*/
  206: 	int error = 0;
  207: 
  208: 	if (vp->v_type != VREG) {
  209: 		printf("%s: vn types other than VREG unsupported !\n",__FUNCTION__);
  210: 		return EIO;
  211: 	}
  212: 	NCPVNDEBUG("ofs=%d,resid=%d\n",(int)uiop->uio_offset, uiop->uio_resid);
  213: 	if (uiop->uio_offset < 0) return EINVAL;
  214: /*	if (uiop->uio_offset + uiop->uio_resid > nmp->nm_maxfilesize)
  215: 		return (EFBIG);*/
  216: 	td = uiop->uio_td;
  217: 	if (ioflag & (IO_APPEND | IO_SYNC)) {
  218: 		if (np->n_flag & NMODIFIED) {
  219: 			nwfs_attr_cacheremove(vp);
  220: 			error = nwfs_vinvalbuf(vp, V_SAVE, td, 1);
  221: 			if (error) return (error);
  222: 		}
  223: 		if (ioflag & IO_APPEND) {
  224: 		/* We can relay only on local information about file size,
  225: 		 * because until file is closed NetWare will not return
  226: 		 * the correct size. */
  227: #if notyet
  228: 			nwfs_attr_cacheremove(vp);
  229: 			error = VOP_GETATTR(vp, &vattr, td);
  230: 			if (error) return (error);
  231: #endif
  232: 			uiop->uio_offset = np->n_size;
  233: 		}
  234: 	}
  235: 	if (uiop->uio_resid == 0) return 0;
  236: 	if (td->td_proc && uiop->uio_offset + uiop->uio_resid > 
  237: 	    td->td_proc->p_rlimit[RLIMIT_FSIZE].rlim_cur) {
  238: 		psignal(td->td_proc, SIGXFSZ);
  239: 		return (EFBIG);
  240: 	}
  241: 	error = ncp_write(NWFSTOCONN(nmp), &np->n_fh, uiop, cred);
  242: 	NCPVNDEBUG("after: ofs=%d,resid=%d\n",(int)uiop->uio_offset, uiop->uio_resid);
  243: 	if (!error) {
  244: 		if (uiop->uio_offset > np->n_size) {
  245: 			np->n_vattr.va_size = np->n_size = uiop->uio_offset;
  246: 			vnode_pager_setsize(vp, np->n_size);
  247: 		}
  248: 	}
  249: 	return (error);
  250: }
  251: 
  252: /*
  253:  * Do an I/O operation to/from a cache block.
  254:  */
  255: int
  256: nwfs_doio(struct buf *bp, struct ucred *cr, struct thread *td)
  257: {
  258: 	struct uio *uiop;
  259: 	struct vnode *vp;
  260: 	struct nwnode *np;
  261: 	struct nwmount *nmp;
  262: 	int error = 0;
  263: 	struct uio uio;
  264: 	struct iovec io;
  265: 
  266: 	vp = bp->b_vp;
  267: 	np = VTONW(vp);
  268: 	nmp = VFSTONWFS(vp->v_mount);
  269: 	uiop = &uio;
  270: 	uiop->uio_iov = &io;
  271: 	uiop->uio_iovcnt = 1;
  272: 	uiop->uio_segflg = UIO_SYSSPACE;
  273: 	uiop->uio_td = td;
  274: 	if (bp->b_flags & B_READ) {
  275: 	    io.iov_len = uiop->uio_resid = bp->b_bcount;
  276: 	    io.iov_base = bp->b_data;
  277: 	    uiop->uio_rw = UIO_READ;
  278: 	    switch (vp->v_type) {
  279: 	      case VREG:
  280: 		uiop->uio_offset = ((off_t)bp->b_blkno) * DEV_BSIZE;
  281: 		error = ncp_read(NWFSTOCONN(nmp), &np->n_fh, uiop, cr);
  282: 		if (error)
  283: 			break;
  284: 		if (uiop->uio_resid) {
  285: 			int left = uiop->uio_resid;
  286: 			int nread = bp->b_bcount - left;
  287: 			if (left > 0)
  288: 			    bzero((char *)bp->b_data + nread, left);
  289: 		}
  290: 		break;
  291: /*	    case VDIR:
  292: 		nfsstats.readdir_bios++;
  293: 		uiop->uio_offset = ((u_quad_t)bp->b_lblkno) * NFS_DIRBLKSIZ;
  294: 		if (nmp->nm_flag & NFSMNT_RDIRPLUS) {
  295: 			error = nfs_readdirplusrpc(vp, uiop, cr);
  296: 			if (error == NFSERR_NOTSUPP)
  297: 				nmp->nm_flag &= ~NFSMNT_RDIRPLUS;
  298: 		}
  299: 		if ((nmp->nm_flag & NFSMNT_RDIRPLUS) == 0)
  300: 			error = nfs_readdirrpc(vp, uiop, cr);
  301: 		if (error == 0 && uiop->uio_resid == bp->b_bcount)
  302: 			bp->b_flags |= B_INVAL;
  303: 		break;
  304: */
  305: 	    default:
  306: 		printf("nwfs_doio:  type %x unexpected\n",vp->v_type);
  307: 		break;
  308: 	    };
  309: 	    if (error) {
  310: 		bp->b_flags |= B_ERROR;
  311: 		bp->b_error = error;
  312: 	    }
  313: 	} else { /* write */
  314: 	    if (((bp->b_blkno * DEV_BSIZE) + bp->b_dirtyend) > np->n_size)
  315: 		bp->b_dirtyend = np->n_size - (bp->b_blkno * DEV_BSIZE);
  316: 
  317: 	    if (bp->b_dirtyend > bp->b_dirtyoff) {
  318: 		io.iov_len = uiop->uio_resid = bp->b_dirtyend - bp->b_dirtyoff;
  319: 		uiop->uio_offset = ((off_t)bp->b_blkno) * DEV_BSIZE + bp->b_dirtyoff;
  320: 		io.iov_base = (char *)bp->b_data + bp->b_dirtyoff;
  321: 		uiop->uio_rw = UIO_WRITE;
  322: 		bp->b_flags |= B_WRITEINPROG;
  323: 		error = ncp_write(NWFSTOCONN(nmp), &np->n_fh, uiop, cr);
  324: 		bp->b_flags &= ~B_WRITEINPROG;
  325: 
  326: 		/*
  327: 		 * For an interrupted write, the buffer is still valid
  328: 		 * and the write hasn't been pushed to the server yet,
  329: 		 * so we can't set B_ERROR and report the interruption
  330: 		 * by setting B_EINTR. For the B_ASYNC case, B_EINTR
  331: 		 * is not relevant, so the rpc attempt is essentially
  332: 		 * a noop.  For the case of a V3 write rpc not being
  333: 		 * committed to stable storage, the block is still
  334: 		 * dirty and requires either a commit rpc or another
  335: 		 * write rpc with iomode == NFSV3WRITE_FILESYNC before
  336: 		 * the block is reused. This is indicated by setting
  337: 		 * the B_DELWRI and B_NEEDCOMMIT flags.
  338: 		 */
  339:     		if (error == EINTR
  340: 		    || (!error && (bp->b_flags & B_NEEDCOMMIT))) {
  341: 			int s;
  342: 
  343: 			s = splbio();
  344: 			bp->b_flags &= ~(B_INVAL|B_NOCACHE);
  345: 			if ((bp->b_flags & B_ASYNC) == 0)
  346: 			    bp->b_flags |= B_EINTR;
  347: 			if ((bp->b_flags & B_PAGING) == 0) {
  348: 			    bdirty(bp);
  349: 			    bp->b_flags &= ~B_DONE;
  350: 			}
  351: 			if ((bp->b_flags & B_ASYNC) == 0)
  352: 			    bp->b_flags |= B_EINTR;
  353: 			splx(s);
  354: 	    	} else {
  355: 			if (error) {
  356: 				bp->b_flags |= B_ERROR;
  357: 				bp->b_error /*= np->n_error */= error;
  358: /*				np->n_flag |= NWRITEERR;*/
  359: 			}
  360: 			bp->b_dirtyoff = bp->b_dirtyend = 0;
  361: 		}
  362: 	    } else {
  363: 		bp->b_resid = 0;
  364: 		biodone(bp);
  365: 		return (0);
  366: 	    }
  367: 	}
  368: 	bp->b_resid = uiop->uio_resid;
  369: 	biodone(bp);
  370: 	return (error);
  371: }
  372: 
  373: /*
  374:  * Vnode op for VM getpages.
  375:  * Wish wish .... get rid from multiple IO routines
  376:  *
  377:  * nwfs_getpages(struct vnode *a_vp, vm_page_t *a_m, int a_count,
  378:  *		 int a_reqpage, vm_ooffset_t a_offset)
  379:  */
  380: int
  381: nwfs_getpages(struct vop_getpages_args *ap)
  382: {
  383: #ifndef NWFS_RWCACHE
  384: 	return vnode_pager_generic_getpages(ap->a_vp, ap->a_m, ap->a_count,
  385: 		ap->a_reqpage);
  386: #else
  387: 	int i, error, nextoff, size, toff, npages, count;
  388: 	struct uio uio;
  389: 	struct iovec iov;
  390: 	vm_offset_t kva;
  391: 	struct buf *bp;
  392: 	struct vnode *vp;
  393: 	struct thread *td = curthread;	/* XXX */
  394: 	struct ucred *cred;
  395: 	struct nwmount *nmp;
  396: 	struct nwnode *np;
  397: 	vm_page_t *pages;
  398: 
  399: 	KKASSERT(td->td_proc);
  400: 	cred = td->td_proc->p_ucred;
  401: 
  402: 	vp = ap->a_vp;
  403: 	np = VTONW(vp);
  404: 	nmp = VFSTONWFS(vp->v_mount);
  405: 	pages = ap->a_m;
  406: 	count = ap->a_count;
  407: 
  408: 	if (vp->v_object == NULL) {
  409: 		printf("nwfs_getpages: called with non-merged cache vnode??\n");
  410: 		return VM_PAGER_ERROR;
  411: 	}
  412: 
  413: 	bp = getpbuf(&nwfs_pbuf_freecnt);
  414: 	npages = btoc(count);
  415: 	kva = (vm_offset_t) bp->b_data;
  416: 	pmap_qenter(kva, pages, npages);
  417: 
  418: 	iov.iov_base = (caddr_t) kva;
  419: 	iov.iov_len = count;
  420: 	uio.uio_iov = &iov;
  421: 	uio.uio_iovcnt = 1;
  422: 	uio.uio_offset = IDX_TO_OFF(pages[0]->pindex);
  423: 	uio.uio_resid = count;
  424: 	uio.uio_segflg = UIO_SYSSPACE;
  425: 	uio.uio_rw = UIO_READ;
  426: 	uio.uio_td = td;
  427: 
  428: 	error = ncp_read(NWFSTOCONN(nmp), &np->n_fh, &uio,cred);
  429: 	pmap_qremove(kva, npages);
  430: 
  431: 	relpbuf(bp, &nwfs_pbuf_freecnt);
  432: 
  433: 	if (error && (uio.uio_resid == count)) {
  434: 		printf("nwfs_getpages: error %d\n",error);
  435: 		for (i = 0; i < npages; i++) {
  436: 			if (ap->a_reqpage != i)
  437: 				vnode_pager_freepage(pages[i]);
  438: 		}
  439: 		return VM_PAGER_ERROR;
  440: 	}
  441: 
  442: 	size = count - uio.uio_resid;
  443: 
  444: 	for (i = 0, toff = 0; i < npages; i++, toff = nextoff) {
  445: 		vm_page_t m;
  446: 		nextoff = toff + PAGE_SIZE;
  447: 		m = pages[i];
  448: 
  449: 		m->flags &= ~PG_ZERO;
  450: 
  451: 		if (nextoff <= size) {
  452: 			m->valid = VM_PAGE_BITS_ALL;
  453: 			m->dirty = 0;
  454: 		} else {
  455: 			int nvalid = ((size + DEV_BSIZE - 1) - toff) & ~(DEV_BSIZE - 1);
  456: 			vm_page_set_validclean(m, 0, nvalid);
  457: 		}
  458: 		
  459: 		if (i != ap->a_reqpage) {
  460: 			/*
  461: 			 * Whether or not to leave the page activated is up in
  462: 			 * the air, but we should put the page on a page queue
  463: 			 * somewhere (it already is in the object).  Result:
  464: 			 * It appears that emperical results show that
  465: 			 * deactivating pages is best.
  466: 			 */
  467: 
  468: 			/*
  469: 			 * Just in case someone was asking for this page we
  470: 			 * now tell them that it is ok to use.
  471: 			 */
  472: 			if (!error) {
  473: 				if (m->flags & PG_WANTED)
  474: 					vm_page_activate(m);
  475: 				else
  476: 					vm_page_deactivate(m);
  477: 				vm_page_wakeup(m);
  478: 			} else {
  479: 				vnode_pager_freepage(m);
  480: 			}
  481: 		}
  482: 	}
  483: 	return 0;
  484: #endif /* NWFS_RWCACHE */
  485: }
  486: 
  487: /*
  488:  * Vnode op for VM putpages.
  489:  * possible bug: all IO done in sync mode
  490:  * Note that vop_close always invalidate pages before close, so it's
  491:  * not necessary to open vnode.
  492:  *
  493:  * nwfs_putpages(struct vnode *a_vp, vm_page_t *a_m, int a_count,
  494:  *		 int a_sync, int *a_rtvals, vm_ooffset_t a_offset)
  495:  */
  496: int
  497: nwfs_putpages(struct vop_putpages_args *ap)
  498: {
  499: 	int error;
  500: 	struct thread *td = curthread;	/* XXX */
  501: 	struct vnode *vp = ap->a_vp;
  502: 	struct ucred *cred;
  503: 
  504: #ifndef NWFS_RWCACHE
  505: 	KKASSERT(td->td_proc);
  506: 	cred = td->td_proc->p_ucred;		/* XXX */
  507: 	VOP_OPEN(vp, FWRITE, cred, td);
  508: 	error = vnode_pager_generic_putpages(ap->a_vp, ap->a_m, ap->a_count,
  509: 		ap->a_sync, ap->a_rtvals);
  510: 	VOP_CLOSE(vp, FWRITE, cred, td);
  511: 	return error;
  512: #else
  513: 	struct uio uio;
  514: 	struct iovec iov;
  515: 	vm_offset_t kva;
  516: 	struct buf *bp;
  517: 	int i, npages, count;
  518: 	int *rtvals;
  519: 	struct nwmount *nmp;
  520: 	struct nwnode *np;
  521: 	vm_page_t *pages;
  522: 
  523: 	KKASSERT(td->td_proc);
  524: 	cred = td->td_proc->p_ucred;		/* XXX */
  525: 
  526: /*	VOP_OPEN(vp, FWRITE, cred, td);*/
  527: 	np = VTONW(vp);
  528: 	nmp = VFSTONWFS(vp->v_mount);
  529: 	pages = ap->a_m;
  530: 	count = ap->a_count;
  531: 	rtvals = ap->a_rtvals;
  532: 	npages = btoc(count);
  533: 
  534: 	for (i = 0; i < npages; i++) {
  535: 		rtvals[i] = VM_PAGER_AGAIN;
  536: 	}
  537: 
  538: 	bp = getpbuf(&nwfs_pbuf_freecnt);
  539: 	kva = (vm_offset_t) bp->b_data;
  540: 	pmap_qenter(kva, pages, npages);
  541: 
  542: 	iov.iov_base = (caddr_t) kva;
  543: 	iov.iov_len = count;
  544: 	uio.uio_iov = &iov;
  545: 	uio.uio_iovcnt = 1;
  546: 	uio.uio_offset = IDX_TO_OFF(pages[0]->pindex);
  547: 	uio.uio_resid = count;
  548: 	uio.uio_segflg = UIO_SYSSPACE;
  549: 	uio.uio_rw = UIO_WRITE;
  550: 	uio.uio_td = td;
  551: 	NCPVNDEBUG("ofs=%d,resid=%d\n",(int)uio.uio_offset, uio.uio_resid);
  552: 
  553: 	error = ncp_write(NWFSTOCONN(nmp), &np->n_fh, &uio, cred);
  554: /*	VOP_CLOSE(vp, FWRITE, cred, td);*/
  555: 	NCPVNDEBUG("paged write done: %d\n", error);
  556: 
  557: 	pmap_qremove(kva, npages);
  558: 	relpbuf(bp, &nwfs_pbuf_freecnt);
  559: 
  560: 	if (!error) {
  561: 		int nwritten = round_page(count - uio.uio_resid) / PAGE_SIZE;
  562: 		for (i = 0; i < nwritten; i++) {
  563: 			rtvals[i] = VM_PAGER_OK;
  564: 			pages[i]->dirty = 0;
  565: 		}
  566: 	}
  567: 	return rtvals[0];
  568: #endif /* NWFS_RWCACHE */
  569: }
  570: /*
  571:  * Flush and invalidate all dirty buffers. If another process is already
  572:  * doing the flush, just wait for completion.
  573:  */
  574: int
  575: nwfs_vinvalbuf(struct vnode *vp, int flags, struct thread *td, int intrflg)
  576: {
  577: 	struct nwnode *np = VTONW(vp);
  578: /*	struct nwmount *nmp = VTONWFS(vp);*/
  579: 	int error = 0, slpflag, slptimeo;
  580: 
  581: 	if (vp->v_flag & VXLOCK) {
  582: 		return (0);
  583: 	}
  584: 	if (intrflg) {
  585: 		slpflag = PCATCH;
  586: 		slptimeo = 2 * hz;
  587: 	} else {
  588: 		slpflag = 0;
  589: 		slptimeo = 0;
  590: 	}
  591: 	while (np->n_flag & NFLUSHINPROG) {
  592: 		np->n_flag |= NFLUSHWANT;
  593: 		error = tsleep((caddr_t)&np->n_flag, 0, "nwfsvinv", slptimeo);
  594: 		error = ncp_chkintr(NWFSTOCONN(VTONWFS(vp)), td);
  595: 		if (error == EINTR && intrflg)
  596: 			return EINTR;
  597: 	}
  598: 	np->n_flag |= NFLUSHINPROG;
  599: 	error = vinvalbuf(vp, flags, td, slpflag, 0);
  600: 	while (error) {
  601: 		if (intrflg && (error == ERESTART || error == EINTR)) {
  602: 			np->n_flag &= ~NFLUSHINPROG;
  603: 			if (np->n_flag & NFLUSHWANT) {
  604: 				np->n_flag &= ~NFLUSHWANT;
  605: 				wakeup((caddr_t)&np->n_flag);
  606: 			}
  607: 			return EINTR;
  608: 		}
  609: 		error = vinvalbuf(vp, flags, td, slpflag, 0);
  610: 	}
  611: 	np->n_flag &= ~(NMODIFIED | NFLUSHINPROG);
  612: 	if (np->n_flag & NFLUSHWANT) {
  613: 		np->n_flag &= ~NFLUSHWANT;
  614: 		wakeup((caddr_t)&np->n_flag);
  615: 	}
  616: 	return (error);
  617: }