File:  [DragonFly] / src / sys / vfs / nwfs / nwfs_io.c
Revision 1.9: download - view: text, annotated - select for diffs
Mon Nov 10 06:12:17 2003 UTC (11 years ago) by dillon
Branches: MAIN
CVS tags: HEAD
Fully synchronize sys/boot from FreeBSD-5.x, but add / to the module path
so /kernel will be found and loaded instead of /boot/kernel.  This will
give us all the capabilities of the FreeBSD-5 boot code including AMD64 and
ELF64 support.

As part of this work, rather then try to adjust ufs/fs.h and friends to get
UFS2 info I instead copied the fs.h and friends from FreeBSD-5 into the
sys/boot subtree

Additionally, import Peter Wemm's linker set improvements from FreeBSD-5.x.
They happen to be compatible with GCC 2.95.x and it allows very few changes
to be made to the boot code.

Additionally import a number of other elements from FreeBSD-5 including
sys/diskmbr.h separation.

    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.9 2003/11/10 06:12:17 dillon 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: 	struct nwmount *nmp = VTONWFS(vp);
   78: 	int error, count, i;
   79: 	struct dirent dp;
   80: 	struct nwnode *np = VTONW(vp);
   81: 	struct nw_entry_info fattr;
   82: 	struct vnode *newvp;
   83: 	struct componentname cn;
   84: 	ncpfid fid;
   85: 
   86: 	np = VTONW(vp);
   87: 	NCPVNDEBUG("dirname='%s'\n",np->n_name);
   88: 	if (uio->uio_resid < DE_SIZE || (uio->uio_offset < 0))
   89: 		return (EINVAL);
   90: 	error = 0;
   91: 	count = 0;
   92: 	i = uio->uio_offset / DE_SIZE; /* offset in directory */
   93: 	if (i == 0) {
   94: 		error = ncp_initsearch(vp, uio->uio_td, cred);
   95: 		if (error) {
   96: 			NCPVNDEBUG("cannot initialize search, error=%d",error);
   97: 			return( error );
   98: 		}
   99: 	}
  100: 
  101: 	for (; uio->uio_resid >= DE_SIZE; i++) {
  102: 		bzero((char *) &dp, DE_SIZE);
  103: 		dp.d_reclen = DE_SIZE;
  104: 		switch (i) {
  105: 		    case 0:		/* `.' */
  106: 		    case 1:		/* `..' */
  107: 			dp.d_fileno = (i == 0) ? np->n_fid.f_id : np->n_parent.f_id;
  108: 			if (!dp.d_fileno) dp.d_fileno = NWFS_ROOT_INO;
  109: 			dp.d_namlen = i + 1;
  110: 			dp.d_name[0] = '.';
  111: 			dp.d_name[1] = '.';
  112: 			dp.d_name[i + 1] = '\0';
  113: 			dp.d_type = DT_DIR;
  114: 			break;
  115: 		    default:
  116: 			error = ncp_search_for_file_or_subdir(nmp, &np->n_seq, &fattr, uio->uio_td, cred);
  117: 			if (error && error < 0x80) break;
  118: 			dp.d_fileno = fattr.dirEntNum;
  119: 			dp.d_type = (fattr.attributes & aDIR) ? DT_DIR : DT_REG;
  120: 			dp.d_namlen = fattr.nameLen;
  121: 			bcopy(fattr.entryName, dp.d_name, dp.d_namlen);
  122: 			dp.d_name[dp.d_namlen] = '\0';
  123: #if 0
  124: 			if (error && eofflag) {
  125: 			/*	*eofflag = 1;*/
  126: 			        break;
  127: 			}
  128: #endif
  129: 			break;
  130: 		}
  131: 		if (nwfs_fastlookup && !error && i > 1) {
  132: 			fid.f_id = fattr.dirEntNum;
  133: 			fid.f_parent = np->n_fid.f_id;
  134: 			error = nwfs_nget(vp->v_mount, fid, &fattr, vp, &newvp);
  135: 			if (!error) {
  136: 				VTONW(newvp)->n_ctime = VTONW(newvp)->n_vattr.va_ctime.tv_sec;
  137: 				cn.cn_nameptr = dp.d_name;
  138: 				cn.cn_namelen = dp.d_namlen;
  139: 			        cache_enter(vp, NCPNULL, newvp, &cn);
  140: 				vput(newvp);
  141: 			} else
  142: 				error = 0;
  143: 		}
  144: 		if (error >= 0x80) {
  145: 		    error = 0;
  146: 		    break;
  147: 		}
  148: 		if ((error = uiomove((caddr_t)&dp, DE_SIZE, uio)))
  149: 			break;
  150: 	}
  151: 
  152: 	uio->uio_offset = i * DE_SIZE;
  153: 	return (error);
  154: }
  155: 
  156: int
  157: nwfs_readvnode(struct vnode *vp, struct uio *uiop, struct ucred *cred) {
  158: 	struct nwmount *nmp = VFSTONWFS(vp->v_mount);
  159: 	struct nwnode *np = VTONW(vp);
  160: 	struct thread *td;
  161: 	struct vattr vattr;
  162: 	int error, biosize;
  163: 
  164: 	if (vp->v_type != VREG && vp->v_type != VDIR) {
  165: 		printf("%s: vn types other than VREG or VDIR are unsupported !\n",__FUNCTION__);
  166: 		return EIO;
  167: 	}
  168: 	if (uiop->uio_resid == 0) return 0;
  169: 	if (uiop->uio_offset < 0) return EINVAL;
  170: /*	if (uiop->uio_offset + uiop->uio_resid > nmp->nm_maxfilesize)
  171: 		return (EFBIG);*/
  172: 	td = uiop->uio_td;
  173: 	if (vp->v_type == VDIR) {
  174: 		error = nwfs_readvdir(vp, uiop, cred);
  175: 		return error;
  176: 	}
  177: 	biosize = NWFSTOCONN(nmp)->buffer_size;
  178: 	if (np->n_flag & NMODIFIED) {
  179: 		nwfs_attr_cacheremove(vp);
  180: 		error = VOP_GETATTR(vp, &vattr, td);
  181: 		if (error) return (error);
  182: 		np->n_mtime = vattr.va_mtime.tv_sec;
  183: 	} else {
  184: 		error = VOP_GETATTR(vp, &vattr, td);
  185: 		if (error) return (error);
  186: 		if (np->n_mtime != vattr.va_mtime.tv_sec) {
  187: 			error = nwfs_vinvalbuf(vp, V_SAVE, td, 1);
  188: 			if (error) return (error);
  189: 			np->n_mtime = vattr.va_mtime.tv_sec;
  190: 		}
  191: 	}
  192: 	error = ncp_read(NWFSTOCONN(nmp), &np->n_fh, uiop,cred);
  193: 	return (error);
  194: }
  195: 
  196: int
  197: nwfs_writevnode(vp, uiop, cred, ioflag)
  198: 	struct vnode *vp;
  199: 	struct uio *uiop;
  200: 	struct ucred *cred;
  201: 	int ioflag;
  202: {
  203: 	struct nwmount *nmp = VTONWFS(vp);
  204: 	struct nwnode *np = VTONW(vp);
  205: 	struct thread *td;
  206: /*	struct vattr vattr;*/
  207: 	int error = 0;
  208: 
  209: 	if (vp->v_type != VREG) {
  210: 		printf("%s: vn types other than VREG unsupported !\n",__FUNCTION__);
  211: 		return EIO;
  212: 	}
  213: 	NCPVNDEBUG("ofs=%d,resid=%d\n",(int)uiop->uio_offset, uiop->uio_resid);
  214: 	if (uiop->uio_offset < 0) return EINVAL;
  215: /*	if (uiop->uio_offset + uiop->uio_resid > nmp->nm_maxfilesize)
  216: 		return (EFBIG);*/
  217: 	td = uiop->uio_td;
  218: 	if (ioflag & (IO_APPEND | IO_SYNC)) {
  219: 		if (np->n_flag & NMODIFIED) {
  220: 			nwfs_attr_cacheremove(vp);
  221: 			error = nwfs_vinvalbuf(vp, V_SAVE, td, 1);
  222: 			if (error) return (error);
  223: 		}
  224: 		if (ioflag & IO_APPEND) {
  225: 		/* We can relay only on local information about file size,
  226: 		 * because until file is closed NetWare will not return
  227: 		 * the correct size. */
  228: #if notyet
  229: 			nwfs_attr_cacheremove(vp);
  230: 			error = VOP_GETATTR(vp, &vattr, td);
  231: 			if (error) return (error);
  232: #endif
  233: 			uiop->uio_offset = np->n_size;
  234: 		}
  235: 	}
  236: 	if (uiop->uio_resid == 0) return 0;
  237: 	if (td->td_proc && uiop->uio_offset + uiop->uio_resid > 
  238: 	    td->td_proc->p_rlimit[RLIMIT_FSIZE].rlim_cur) {
  239: 		psignal(td->td_proc, SIGXFSZ);
  240: 		return (EFBIG);
  241: 	}
  242: 	error = ncp_write(NWFSTOCONN(nmp), &np->n_fh, uiop, cred);
  243: 	NCPVNDEBUG("after: ofs=%d,resid=%d\n",(int)uiop->uio_offset, uiop->uio_resid);
  244: 	if (!error) {
  245: 		if (uiop->uio_offset > np->n_size) {
  246: 			np->n_vattr.va_size = np->n_size = uiop->uio_offset;
  247: 			vnode_pager_setsize(vp, np->n_size);
  248: 		}
  249: 	}
  250: 	return (error);
  251: }
  252: 
  253: /*
  254:  * Do an I/O operation to/from a cache block.
  255:  */
  256: int
  257: nwfs_doio(struct buf *bp, struct ucred *cr, struct thread *td)
  258: {
  259: 	struct uio *uiop;
  260: 	struct vnode *vp;
  261: 	struct nwnode *np;
  262: 	struct nwmount *nmp;
  263: 	int error = 0;
  264: 	struct uio uio;
  265: 	struct iovec io;
  266: 
  267: 	vp = bp->b_vp;
  268: 	np = VTONW(vp);
  269: 	nmp = VFSTONWFS(vp->v_mount);
  270: 	uiop = &uio;
  271: 	uiop->uio_iov = &io;
  272: 	uiop->uio_iovcnt = 1;
  273: 	uiop->uio_segflg = UIO_SYSSPACE;
  274: 	uiop->uio_td = td;
  275: 	if (bp->b_flags & B_READ) {
  276: 	    io.iov_len = uiop->uio_resid = bp->b_bcount;
  277: 	    io.iov_base = bp->b_data;
  278: 	    uiop->uio_rw = UIO_READ;
  279: 	    switch (vp->v_type) {
  280: 	      case VREG:
  281: 		uiop->uio_offset = ((off_t)bp->b_blkno) * DEV_BSIZE;
  282: 		error = ncp_read(NWFSTOCONN(nmp), &np->n_fh, uiop, cr);
  283: 		if (error)
  284: 			break;
  285: 		if (uiop->uio_resid) {
  286: 			int left = uiop->uio_resid;
  287: 			int nread = bp->b_bcount - left;
  288: 			if (left > 0)
  289: 			    bzero((char *)bp->b_data + nread, left);
  290: 		}
  291: 		break;
  292: /*	    case VDIR:
  293: 		nfsstats.readdir_bios++;
  294: 		uiop->uio_offset = ((u_quad_t)bp->b_lblkno) * NFS_DIRBLKSIZ;
  295: 		if (nmp->nm_flag & NFSMNT_RDIRPLUS) {
  296: 			error = nfs_readdirplusrpc(vp, uiop, cr);
  297: 			if (error == NFSERR_NOTSUPP)
  298: 				nmp->nm_flag &= ~NFSMNT_RDIRPLUS;
  299: 		}
  300: 		if ((nmp->nm_flag & NFSMNT_RDIRPLUS) == 0)
  301: 			error = nfs_readdirrpc(vp, uiop, cr);
  302: 		if (error == 0 && uiop->uio_resid == bp->b_bcount)
  303: 			bp->b_flags |= B_INVAL;
  304: 		break;
  305: */
  306: 	    default:
  307: 		printf("nwfs_doio:  type %x unexpected\n",vp->v_type);
  308: 		break;
  309: 	    };
  310: 	    if (error) {
  311: 		bp->b_flags |= B_ERROR;
  312: 		bp->b_error = error;
  313: 	    }
  314: 	} else { /* write */
  315: 	    if (((bp->b_blkno * DEV_BSIZE) + bp->b_dirtyend) > np->n_size)
  316: 		bp->b_dirtyend = np->n_size - (bp->b_blkno * DEV_BSIZE);
  317: 
  318: 	    if (bp->b_dirtyend > bp->b_dirtyoff) {
  319: 		io.iov_len = uiop->uio_resid = bp->b_dirtyend - bp->b_dirtyoff;
  320: 		uiop->uio_offset = ((off_t)bp->b_blkno) * DEV_BSIZE + bp->b_dirtyoff;
  321: 		io.iov_base = (char *)bp->b_data + bp->b_dirtyoff;
  322: 		uiop->uio_rw = UIO_WRITE;
  323: 		bp->b_flags |= B_WRITEINPROG;
  324: 		error = ncp_write(NWFSTOCONN(nmp), &np->n_fh, uiop, cr);
  325: 		bp->b_flags &= ~B_WRITEINPROG;
  326: 
  327: 		/*
  328: 		 * For an interrupted write, the buffer is still valid
  329: 		 * and the write hasn't been pushed to the server yet,
  330: 		 * so we can't set B_ERROR and report the interruption
  331: 		 * by setting B_EINTR. For the B_ASYNC case, B_EINTR
  332: 		 * is not relevant, so the rpc attempt is essentially
  333: 		 * a noop.  For the case of a V3 write rpc not being
  334: 		 * committed to stable storage, the block is still
  335: 		 * dirty and requires either a commit rpc or another
  336: 		 * write rpc with iomode == NFSV3WRITE_FILESYNC before
  337: 		 * the block is reused. This is indicated by setting
  338: 		 * the B_DELWRI and B_NEEDCOMMIT flags.
  339: 		 */
  340:     		if (error == EINTR
  341: 		    || (!error && (bp->b_flags & B_NEEDCOMMIT))) {
  342: 			int s;
  343: 
  344: 			s = splbio();
  345: 			bp->b_flags &= ~(B_INVAL|B_NOCACHE);
  346: 			if ((bp->b_flags & B_ASYNC) == 0)
  347: 			    bp->b_flags |= B_EINTR;
  348: 			if ((bp->b_flags & B_PAGING) == 0) {
  349: 			    bdirty(bp);
  350: 			    bp->b_flags &= ~B_DONE;
  351: 			}
  352: 			if ((bp->b_flags & B_ASYNC) == 0)
  353: 			    bp->b_flags |= B_EINTR;
  354: 			splx(s);
  355: 	    	} else {
  356: 			if (error) {
  357: 				bp->b_flags |= B_ERROR;
  358: 				bp->b_error /*= np->n_error */= error;
  359: /*				np->n_flag |= NWRITEERR;*/
  360: 			}
  361: 			bp->b_dirtyoff = bp->b_dirtyend = 0;
  362: 		}
  363: 	    } else {
  364: 		bp->b_resid = 0;
  365: 		biodone(bp);
  366: 		return (0);
  367: 	    }
  368: 	}
  369: 	bp->b_resid = uiop->uio_resid;
  370: 	biodone(bp);
  371: 	return (error);
  372: }
  373: 
  374: /*
  375:  * Vnode op for VM getpages.
  376:  * Wish wish .... get rid from multiple IO routines
  377:  */
  378: int
  379: nwfs_getpages(ap)
  380: 	struct vop_getpages_args /* {
  381: 		struct vnode *a_vp;
  382: 		vm_page_t *a_m;
  383: 		int a_count;
  384: 		int a_reqpage;
  385: 		vm_ooffset_t a_offset;
  386: 	} */ *ap;
  387: {
  388: #ifndef NWFS_RWCACHE
  389: 	return vnode_pager_generic_getpages(ap->a_vp, ap->a_m, ap->a_count,
  390: 		ap->a_reqpage);
  391: #else
  392: 	int i, error, nextoff, size, toff, npages, count;
  393: 	struct uio uio;
  394: 	struct iovec iov;
  395: 	vm_offset_t kva;
  396: 	struct buf *bp;
  397: 	struct vnode *vp;
  398: 	struct thread *td = curthread;	/* XXX */
  399: 	struct ucred *cred;
  400: 	struct nwmount *nmp;
  401: 	struct nwnode *np;
  402: 	vm_page_t *pages;
  403: 
  404: 	KKASSERT(td->td_proc);
  405: 	cred = td->td_proc->p_ucred;
  406: 
  407: 	vp = ap->a_vp;
  408: 	np = VTONW(vp);
  409: 	nmp = VFSTONWFS(vp->v_mount);
  410: 	pages = ap->a_m;
  411: 	count = ap->a_count;
  412: 
  413: 	if (vp->v_object == NULL) {
  414: 		printf("nwfs_getpages: called with non-merged cache vnode??\n");
  415: 		return VM_PAGER_ERROR;
  416: 	}
  417: 
  418: 	bp = getpbuf(&nwfs_pbuf_freecnt);
  419: 	npages = btoc(count);
  420: 	kva = (vm_offset_t) bp->b_data;
  421: 	pmap_qenter(kva, pages, npages);
  422: 
  423: 	iov.iov_base = (caddr_t) kva;
  424: 	iov.iov_len = count;
  425: 	uio.uio_iov = &iov;
  426: 	uio.uio_iovcnt = 1;
  427: 	uio.uio_offset = IDX_TO_OFF(pages[0]->pindex);
  428: 	uio.uio_resid = count;
  429: 	uio.uio_segflg = UIO_SYSSPACE;
  430: 	uio.uio_rw = UIO_READ;
  431: 	uio.uio_td = td;
  432: 
  433: 	error = ncp_read(NWFSTOCONN(nmp), &np->n_fh, &uio,cred);
  434: 	pmap_qremove(kva, npages);
  435: 
  436: 	relpbuf(bp, &nwfs_pbuf_freecnt);
  437: 
  438: 	if (error && (uio.uio_resid == count)) {
  439: 		printf("nwfs_getpages: error %d\n",error);
  440: 		for (i = 0; i < npages; i++) {
  441: 			if (ap->a_reqpage != i)
  442: 				vnode_pager_freepage(pages[i]);
  443: 		}
  444: 		return VM_PAGER_ERROR;
  445: 	}
  446: 
  447: 	size = count - uio.uio_resid;
  448: 
  449: 	for (i = 0, toff = 0; i < npages; i++, toff = nextoff) {
  450: 		vm_page_t m;
  451: 		nextoff = toff + PAGE_SIZE;
  452: 		m = pages[i];
  453: 
  454: 		m->flags &= ~PG_ZERO;
  455: 
  456: 		if (nextoff <= size) {
  457: 			m->valid = VM_PAGE_BITS_ALL;
  458: 			m->dirty = 0;
  459: 		} else {
  460: 			int nvalid = ((size + DEV_BSIZE - 1) - toff) & ~(DEV_BSIZE - 1);
  461: 			vm_page_set_validclean(m, 0, nvalid);
  462: 		}
  463: 		
  464: 		if (i != ap->a_reqpage) {
  465: 			/*
  466: 			 * Whether or not to leave the page activated is up in
  467: 			 * the air, but we should put the page on a page queue
  468: 			 * somewhere (it already is in the object).  Result:
  469: 			 * It appears that emperical results show that
  470: 			 * deactivating pages is best.
  471: 			 */
  472: 
  473: 			/*
  474: 			 * Just in case someone was asking for this page we
  475: 			 * now tell them that it is ok to use.
  476: 			 */
  477: 			if (!error) {
  478: 				if (m->flags & PG_WANTED)
  479: 					vm_page_activate(m);
  480: 				else
  481: 					vm_page_deactivate(m);
  482: 				vm_page_wakeup(m);
  483: 			} else {
  484: 				vnode_pager_freepage(m);
  485: 			}
  486: 		}
  487: 	}
  488: 	return 0;
  489: #endif /* NWFS_RWCACHE */
  490: }
  491: 
  492: /*
  493:  * Vnode op for VM putpages.
  494:  * possible bug: all IO done in sync mode
  495:  * Note that vop_close always invalidate pages before close, so it's
  496:  * not necessary to open vnode.
  497:  */
  498: int
  499: nwfs_putpages(ap)
  500: 	struct vop_putpages_args /* {
  501: 		struct vnode *a_vp;
  502: 		vm_page_t *a_m;
  503: 		int a_count;
  504: 		int a_sync;
  505: 		int *a_rtvals;
  506: 		vm_ooffset_t a_offset;
  507: 	} */ *ap;
  508: {
  509: 	int error;
  510: 	struct thread *td = curthread;	/* XXX */
  511: 	struct vnode *vp = ap->a_vp;
  512: 	struct ucred *cred;
  513: 
  514: #ifndef NWFS_RWCACHE
  515: 	KKASSERT(td->td_proc);
  516: 	cred = td->td_proc->p_ucred;		/* XXX */
  517: 	VOP_OPEN(vp, FWRITE, cred, td);
  518: 	error = vnode_pager_generic_putpages(ap->a_vp, ap->a_m, ap->a_count,
  519: 		ap->a_sync, ap->a_rtvals);
  520: 	VOP_CLOSE(vp, FWRITE, cred, td);
  521: 	return error;
  522: #else
  523: 	struct uio uio;
  524: 	struct iovec iov;
  525: 	vm_offset_t kva;
  526: 	struct buf *bp;
  527: 	int i, npages, count;
  528: 	int *rtvals;
  529: 	struct nwmount *nmp;
  530: 	struct nwnode *np;
  531: 	vm_page_t *pages;
  532: 
  533: 	KKASSERT(td->td_proc);
  534: 	cred = td->td_proc->p_ucred;		/* XXX */
  535: 
  536: /*	VOP_OPEN(vp, FWRITE, cred, td);*/
  537: 	np = VTONW(vp);
  538: 	nmp = VFSTONWFS(vp->v_mount);
  539: 	pages = ap->a_m;
  540: 	count = ap->a_count;
  541: 	rtvals = ap->a_rtvals;
  542: 	npages = btoc(count);
  543: 
  544: 	for (i = 0; i < npages; i++) {
  545: 		rtvals[i] = VM_PAGER_AGAIN;
  546: 	}
  547: 
  548: 	bp = getpbuf(&nwfs_pbuf_freecnt);
  549: 	kva = (vm_offset_t) bp->b_data;
  550: 	pmap_qenter(kva, pages, npages);
  551: 
  552: 	iov.iov_base = (caddr_t) kva;
  553: 	iov.iov_len = count;
  554: 	uio.uio_iov = &iov;
  555: 	uio.uio_iovcnt = 1;
  556: 	uio.uio_offset = IDX_TO_OFF(pages[0]->pindex);
  557: 	uio.uio_resid = count;
  558: 	uio.uio_segflg = UIO_SYSSPACE;
  559: 	uio.uio_rw = UIO_WRITE;
  560: 	uio.uio_td = td;
  561: 	NCPVNDEBUG("ofs=%d,resid=%d\n",(int)uio.uio_offset, uio.uio_resid);
  562: 
  563: 	error = ncp_write(NWFSTOCONN(nmp), &np->n_fh, &uio, cred);
  564: /*	VOP_CLOSE(vp, FWRITE, cred, td);*/
  565: 	NCPVNDEBUG("paged write done: %d\n", error);
  566: 
  567: 	pmap_qremove(kva, npages);
  568: 	relpbuf(bp, &nwfs_pbuf_freecnt);
  569: 
  570: 	if (!error) {
  571: 		int nwritten = round_page(count - uio.uio_resid) / PAGE_SIZE;
  572: 		for (i = 0; i < nwritten; i++) {
  573: 			rtvals[i] = VM_PAGER_OK;
  574: 			pages[i]->dirty = 0;
  575: 		}
  576: 	}
  577: 	return rtvals[0];
  578: #endif /* NWFS_RWCACHE */
  579: }
  580: /*
  581:  * Flush and invalidate all dirty buffers. If another process is already
  582:  * doing the flush, just wait for completion.
  583:  */
  584: int
  585: nwfs_vinvalbuf(vp, flags, td, intrflg)
  586: 	struct vnode *vp;
  587: 	int flags;
  588: 	struct thread *td;
  589: 	int intrflg;
  590: {
  591: 	struct nwnode *np = VTONW(vp);
  592: /*	struct nwmount *nmp = VTONWFS(vp);*/
  593: 	int error = 0, slpflag, slptimeo;
  594: 
  595: 	if (vp->v_flag & VXLOCK) {
  596: 		return (0);
  597: 	}
  598: 	if (intrflg) {
  599: 		slpflag = PCATCH;
  600: 		slptimeo = 2 * hz;
  601: 	} else {
  602: 		slpflag = 0;
  603: 		slptimeo = 0;
  604: 	}
  605: 	while (np->n_flag & NFLUSHINPROG) {
  606: 		np->n_flag |= NFLUSHWANT;
  607: 		error = tsleep((caddr_t)&np->n_flag, 0, "nwfsvinv", slptimeo);
  608: 		error = ncp_chkintr(NWFSTOCONN(VTONWFS(vp)), td);
  609: 		if (error == EINTR && intrflg)
  610: 			return EINTR;
  611: 	}
  612: 	np->n_flag |= NFLUSHINPROG;
  613: 	error = vinvalbuf(vp, flags, td, slpflag, 0);
  614: 	while (error) {
  615: 		if (intrflg && (error == ERESTART || error == EINTR)) {
  616: 			np->n_flag &= ~NFLUSHINPROG;
  617: 			if (np->n_flag & NFLUSHWANT) {
  618: 				np->n_flag &= ~NFLUSHWANT;
  619: 				wakeup((caddr_t)&np->n_flag);
  620: 			}
  621: 			return EINTR;
  622: 		}
  623: 		error = vinvalbuf(vp, flags, td, slpflag, 0);
  624: 	}
  625: 	np->n_flag &= ~(NMODIFIED | NFLUSHINPROG);
  626: 	if (np->n_flag & NFLUSHWANT) {
  627: 		np->n_flag &= ~NFLUSHWANT;
  628: 		wakeup((caddr_t)&np->n_flag);
  629: 	}
  630: 	return (error);
  631: }