nfs_vnops.c revision 35823
1215334Sdougb/*
21638Srgrimes * Copyright (c) 1989, 1993
31638Srgrimes *	The Regents of the University of California.  All rights reserved.
41638Srgrimes *
51638Srgrimes * This code is derived from software contributed to Berkeley by
61638Srgrimes * Rick Macklem at The University of Guelph.
71638Srgrimes *
81638Srgrimes * Redistribution and use in source and binary forms, with or without
91638Srgrimes * modification, are permitted provided that the following conditions
101638Srgrimes * are met:
111638Srgrimes * 1. Redistributions of source code must retain the above copyright
121638Srgrimes *    notice, this list of conditions and the following disclaimer.
131638Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
141638Srgrimes *    notice, this list of conditions and the following disclaimer in the
151638Srgrimes *    documentation and/or other materials provided with the distribution.
161638Srgrimes * 3. All advertising materials mentioning features or use of this software
171638Srgrimes *    must display the following acknowledgement:
181638Srgrimes *	This product includes software developed by the University of
191638Srgrimes *	California, Berkeley and its contributors.
201638Srgrimes * 4. Neither the name of the University nor the names of its contributors
211638Srgrimes *    may be used to endorse or promote products derived from this software
221638Srgrimes *    without specific prior written permission.
231638Srgrimes *
241638Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
251638Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
261638Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
271638Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
281638Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
291638Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
301638Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
311638Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
321638Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
331638Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
341638Srgrimes * SUCH DAMAGE.
351638Srgrimes *
361638Srgrimes *	@(#)nfs_vnops.c	8.16 (Berkeley) 5/27/95
371638Srgrimes * $Id: nfs_vnops.c,v 1.83 1998/03/30 09:54:32 phk Exp $
381638Srgrimes */
391638Srgrimes
401638Srgrimes
411638Srgrimes/*
421638Srgrimes * vnode op calls for Sun NFS version 2 and 3
431638Srgrimes */
441638Srgrimes
451638Srgrimes#include "opt_inet.h"
461638Srgrimes
471638Srgrimes#include <sys/param.h>
481638Srgrimes#include <sys/kernel.h>
491638Srgrimes#include <sys/systm.h>
501638Srgrimes#include <sys/resourcevar.h>
511638Srgrimes#include <sys/proc.h>
521638Srgrimes#include <sys/mount.h>
531638Srgrimes#include <sys/buf.h>
541638Srgrimes#include <sys/malloc.h>
551638Srgrimes#include <sys/mbuf.h>
561638Srgrimes#include <sys/namei.h>
571638Srgrimes#include <sys/socket.h>
581638Srgrimes#include <sys/vnode.h>
591638Srgrimes#include <sys/dirent.h>
601638Srgrimes#include <sys/fcntl.h>
611638Srgrimes#include <sys/lockf.h>
621638Srgrimes
631638Srgrimes#include <vm/vm.h>
641638Srgrimes#include <vm/vm_extern.h>
651638Srgrimes#include <vm/vm_zone.h>
661638Srgrimes
671638Srgrimes#include <miscfs/fifofs/fifo.h>
681638Srgrimes#include <miscfs/specfs/specdev.h>
691638Srgrimes
701638Srgrimes#include <nfs/rpcv2.h>
711638Srgrimes#include <nfs/nfsproto.h>
721638Srgrimes#include <nfs/nfs.h>
731638Srgrimes#include <nfs/nfsnode.h>
741638Srgrimes#include <nfs/nfsmount.h>
751638Srgrimes#include <nfs/xdr_subs.h>
761638Srgrimes#include <nfs/nfsm_subs.h>
771638Srgrimes#include <nfs/nqnfs.h>
781638Srgrimes
791638Srgrimes#include <net/if.h>
801638Srgrimes#include <netinet/in.h>
811638Srgrimes#include <netinet/in_var.h>
821638Srgrimes
831638Srgrimes/* Defs */
841638Srgrimes#define	TRUE	1
851638Srgrimes#define	FALSE	0
861638Srgrimes
871638Srgrimes/*
881638Srgrimes * Ifdef for FreeBSD-current merged buffer cache. It is unfortunate that these
891638Srgrimes * calls are not in getblk() and brelse() so that they would not be necessary
901638Srgrimes * here.
911638Srgrimes */
921638Srgrimes#ifndef B_VMIO
931638Srgrimes#define vfs_busy_pages(bp, f)
941638Srgrimes#endif
951638Srgrimes
961638Srgrimesstatic int	nfsspec_read __P((struct vop_read_args *));
971638Srgrimesstatic int	nfsspec_write __P((struct vop_write_args *));
981638Srgrimesstatic int	nfsfifo_read __P((struct vop_read_args *));
991638Srgrimesstatic int	nfsfifo_write __P((struct vop_write_args *));
1001638Srgrimesstatic int	nfsspec_close __P((struct vop_close_args *));
1011638Srgrimesstatic int	nfsfifo_close __P((struct vop_close_args *));
1021638Srgrimes#define nfs_poll vop_nopoll
1031638Srgrimesstatic int	nfs_flush __P((struct vnode *,struct ucred *,int,struct proc *,int));
1041638Srgrimesstatic int	nfs_setattrrpc __P((struct vnode *,struct vattr *,struct ucred *,struct proc *));
1051638Srgrimesstatic	int	nfs_lookup __P((struct vop_lookup_args *));
1061638Srgrimesstatic	int	nfs_create __P((struct vop_create_args *));
1071638Srgrimesstatic	int	nfs_mknod __P((struct vop_mknod_args *));
1081638Srgrimesstatic	int	nfs_open __P((struct vop_open_args *));
1091638Srgrimesstatic	int	nfs_close __P((struct vop_close_args *));
1101638Srgrimesstatic	int	nfs_access __P((struct vop_access_args *));
1111638Srgrimesstatic	int	nfs_getattr __P((struct vop_getattr_args *));
1121638Srgrimesstatic	int	nfs_setattr __P((struct vop_setattr_args *));
1131638Srgrimesstatic	int	nfs_read __P((struct vop_read_args *));
1141638Srgrimesstatic	int	nfs_mmap __P((struct vop_mmap_args *));
1151638Srgrimesstatic	int	nfs_fsync __P((struct vop_fsync_args *));
1161638Srgrimesstatic	int	nfs_remove __P((struct vop_remove_args *));
1171638Srgrimesstatic	int	nfs_link __P((struct vop_link_args *));
1181638Srgrimesstatic	int	nfs_rename __P((struct vop_rename_args *));
1191638Srgrimesstatic	int	nfs_mkdir __P((struct vop_mkdir_args *));
1201638Srgrimesstatic	int	nfs_rmdir __P((struct vop_rmdir_args *));
1211638Srgrimesstatic	int	nfs_symlink __P((struct vop_symlink_args *));
1221638Srgrimesstatic	int	nfs_readdir __P((struct vop_readdir_args *));
1231638Srgrimesstatic	int	nfs_bmap __P((struct vop_bmap_args *));
1241638Srgrimesstatic	int	nfs_strategy __P((struct vop_strategy_args *));
1251638Srgrimesstatic	int	nfs_lookitup __P((struct vnode *,char *,int,struct ucred *,struct proc *,struct nfsnode **));
1261638Srgrimesstatic	int	nfs_sillyrename __P((struct vnode *,struct vnode *,struct componentname *));
1271638Srgrimesstatic int	nfsspec_access __P((struct vop_access_args *));
1281638Srgrimesstatic int	nfs_readlink __P((struct vop_readlink_args *));
1291638Srgrimesstatic int	nfs_print __P((struct vop_print_args *));
1301638Srgrimesstatic int	nfs_advlock __P((struct vop_advlock_args *));
1311638Srgrimesstatic int	nfs_bwrite __P((struct vop_bwrite_args *));
1321638Srgrimes/*
1331638Srgrimes * Global vfs data structures for nfs
1341638Srgrimes */
1351638Srgrimesvop_t **nfsv2_vnodeop_p;
1361638Srgrimesstatic struct vnodeopv_entry_desc nfsv2_vnodeop_entries[] = {
1371638Srgrimes	{ &vop_default_desc,		(vop_t *) vop_defaultop },
1381638Srgrimes	{ &vop_abortop_desc,		(vop_t *) nfs_abortop },
1391638Srgrimes	{ &vop_access_desc,		(vop_t *) nfs_access },
1401638Srgrimes	{ &vop_advlock_desc,		(vop_t *) nfs_advlock },
1411638Srgrimes	{ &vop_bmap_desc,		(vop_t *) nfs_bmap },
1421638Srgrimes	{ &vop_bwrite_desc,		(vop_t *) nfs_bwrite },
1431638Srgrimes	{ &vop_close_desc,		(vop_t *) nfs_close },
1441638Srgrimes	{ &vop_create_desc,		(vop_t *) nfs_create },
1451638Srgrimes	{ &vop_fsync_desc,		(vop_t *) nfs_fsync },
1461638Srgrimes	{ &vop_getattr_desc,		(vop_t *) nfs_getattr },
1471638Srgrimes	{ &vop_getpages_desc,		(vop_t *) nfs_getpages },
1481638Srgrimes	{ &vop_putpages_desc,		(vop_t *) nfs_putpages },
1491638Srgrimes	{ &vop_inactive_desc,		(vop_t *) nfs_inactive },
1501638Srgrimes	{ &vop_lease_desc,		(vop_t *) vop_null },
1511638Srgrimes	{ &vop_link_desc,		(vop_t *) nfs_link },
1521638Srgrimes	{ &vop_lock_desc,		(vop_t *) vop_sharedlock },
1531638Srgrimes	{ &vop_lookup_desc,		(vop_t *) nfs_lookup },
1541638Srgrimes	{ &vop_mkdir_desc,		(vop_t *) nfs_mkdir },
1551638Srgrimes	{ &vop_mknod_desc,		(vop_t *) nfs_mknod },
1561638Srgrimes	{ &vop_mmap_desc,		(vop_t *) nfs_mmap },
1571638Srgrimes	{ &vop_open_desc,		(vop_t *) nfs_open },
1581638Srgrimes	{ &vop_poll_desc,		(vop_t *) nfs_poll },
1591638Srgrimes	{ &vop_print_desc,		(vop_t *) nfs_print },
1601638Srgrimes	{ &vop_read_desc,		(vop_t *) nfs_read },
1611638Srgrimes	{ &vop_readdir_desc,		(vop_t *) nfs_readdir },
1621638Srgrimes	{ &vop_readlink_desc,		(vop_t *) nfs_readlink },
1631638Srgrimes	{ &vop_reclaim_desc,		(vop_t *) nfs_reclaim },
1641638Srgrimes	{ &vop_remove_desc,		(vop_t *) nfs_remove },
1651638Srgrimes	{ &vop_rename_desc,		(vop_t *) nfs_rename },
1661638Srgrimes	{ &vop_rmdir_desc,		(vop_t *) nfs_rmdir },
1671638Srgrimes	{ &vop_setattr_desc,		(vop_t *) nfs_setattr },
1681638Srgrimes	{ &vop_strategy_desc,		(vop_t *) nfs_strategy },
1691638Srgrimes	{ &vop_symlink_desc,		(vop_t *) nfs_symlink },
1701638Srgrimes	{ &vop_write_desc,		(vop_t *) nfs_write },
1711638Srgrimes	{ NULL, NULL }
1721638Srgrimes};
1731638Srgrimesstatic struct vnodeopv_desc nfsv2_vnodeop_opv_desc =
1741638Srgrimes	{ &nfsv2_vnodeop_p, nfsv2_vnodeop_entries };
1751638SrgrimesVNODEOP_SET(nfsv2_vnodeop_opv_desc);
1761638Srgrimes
1771638Srgrimes/*
1781638Srgrimes * Special device vnode ops
1791638Srgrimes */
1801638Srgrimesvop_t **spec_nfsv2nodeop_p;
1811638Srgrimesstatic struct vnodeopv_entry_desc nfsv2_specop_entries[] = {
1821638Srgrimes	{ &vop_default_desc,		(vop_t *) spec_vnoperate },
1831638Srgrimes	{ &vop_access_desc,		(vop_t *) nfsspec_access },
1841638Srgrimes	{ &vop_close_desc,		(vop_t *) nfsspec_close },
1851638Srgrimes	{ &vop_fsync_desc,		(vop_t *) nfs_fsync },
1861638Srgrimes	{ &vop_getattr_desc,		(vop_t *) nfs_getattr },
1871638Srgrimes	{ &vop_inactive_desc,		(vop_t *) nfs_inactive },
1881638Srgrimes	{ &vop_lock_desc,		(vop_t *) vop_sharedlock },
1891638Srgrimes	{ &vop_print_desc,		(vop_t *) nfs_print },
1901638Srgrimes	{ &vop_read_desc,		(vop_t *) nfsspec_read },
1911638Srgrimes	{ &vop_reclaim_desc,		(vop_t *) nfs_reclaim },
1921638Srgrimes	{ &vop_setattr_desc,		(vop_t *) nfs_setattr },
1931638Srgrimes	{ &vop_write_desc,		(vop_t *) nfsspec_write },
1941638Srgrimes	{ NULL, NULL }
1951638Srgrimes};
1961638Srgrimesstatic struct vnodeopv_desc spec_nfsv2nodeop_opv_desc =
1971638Srgrimes	{ &spec_nfsv2nodeop_p, nfsv2_specop_entries };
1981638SrgrimesVNODEOP_SET(spec_nfsv2nodeop_opv_desc);
1991638Srgrimes
2001638Srgrimesvop_t **fifo_nfsv2nodeop_p;
2011638Srgrimesstatic struct vnodeopv_entry_desc nfsv2_fifoop_entries[] = {
2021638Srgrimes	{ &vop_default_desc,		(vop_t *) fifo_vnoperate },
2031638Srgrimes	{ &vop_access_desc,		(vop_t *) nfsspec_access },
2041638Srgrimes	{ &vop_close_desc,		(vop_t *) nfsfifo_close },
2051638Srgrimes	{ &vop_fsync_desc,		(vop_t *) nfs_fsync },
2061638Srgrimes	{ &vop_getattr_desc,		(vop_t *) nfs_getattr },
2071638Srgrimes	{ &vop_inactive_desc,		(vop_t *) nfs_inactive },
2081638Srgrimes	{ &vop_lock_desc,		(vop_t *) vop_sharedlock },
2091638Srgrimes	{ &vop_print_desc,		(vop_t *) nfs_print },
2101638Srgrimes	{ &vop_read_desc,		(vop_t *) nfsfifo_read },
2111638Srgrimes	{ &vop_reclaim_desc,		(vop_t *) nfs_reclaim },
2121638Srgrimes	{ &vop_setattr_desc,		(vop_t *) nfs_setattr },
2131638Srgrimes	{ &vop_write_desc,		(vop_t *) nfsfifo_write },
2141638Srgrimes	{ NULL, NULL }
2151638Srgrimes};
2161638Srgrimesstatic struct vnodeopv_desc fifo_nfsv2nodeop_opv_desc =
2171638Srgrimes	{ &fifo_nfsv2nodeop_p, nfsv2_fifoop_entries };
2181638SrgrimesVNODEOP_SET(fifo_nfsv2nodeop_opv_desc);
2191638Srgrimes
2201638Srgrimesstatic int	nfs_commit __P((struct vnode *vp, u_quad_t offset, int cnt,
2211638Srgrimes				struct ucred *cred, struct proc *procp));
2221638Srgrimesstatic int	nfs_mknodrpc __P((struct vnode *dvp, struct vnode **vpp,
2231638Srgrimes				  struct componentname *cnp,
2241638Srgrimes				  struct vattr *vap));
2251638Srgrimesstatic int	nfs_removerpc __P((struct vnode *dvp, char *name, int namelen,
2261638Srgrimes				   struct ucred *cred, struct proc *proc));
2271638Srgrimesstatic int	nfs_renamerpc __P((struct vnode *fdvp, char *fnameptr,
2281638Srgrimes				   int fnamelen, struct vnode *tdvp,
2291638Srgrimes				   char *tnameptr, int tnamelen,
2301638Srgrimes				   struct ucred *cred, struct proc *proc));
2311638Srgrimesstatic int	nfs_renameit __P((struct vnode *sdvp,
2321638Srgrimes				  struct componentname *scnp,
2331638Srgrimes				  struct sillyrename *sp));
2341638Srgrimes
2351638Srgrimes/*
2361638Srgrimes * Global variables
2371638Srgrimes */
2381638Srgrimesextern u_long nfs_true, nfs_false;
2391638Srgrimesextern struct nfsstats nfsstats;
2401638Srgrimesextern nfstype nfsv3_type[9];
2411638Srgrimesstruct proc *nfs_iodwant[NFS_MAXASYNCDAEMON];
2421638Srgrimesstruct nfsmount *nfs_iodmount[NFS_MAXASYNCDAEMON];
2431638Srgrimesint nfs_numasync = 0;
2441638Srgrimes#define	DIRHDSIZ	(sizeof (struct dirent) - (MAXNAMLEN + 1))
2451638Srgrimes
2461638Srgrimes/*
2471638Srgrimes * nfs access vnode op.
2481638Srgrimes * For nfs version 2, just return ok. File accesses may fail later.
2491638Srgrimes * For nfs version 3, use the access rpc to check accessibility. If file modes
2501638Srgrimes * are changed on the server, accesses might still fail later.
2511638Srgrimes */
2521638Srgrimesstatic int
2531638Srgrimesnfs_access(ap)
2541638Srgrimes	struct vop_access_args /* {
2551638Srgrimes		struct vnode *a_vp;
2561638Srgrimes		int  a_mode;
2571638Srgrimes		struct ucred *a_cred;
2581638Srgrimes		struct proc *a_p;
2591638Srgrimes	} */ *ap;
2601638Srgrimes{
2611638Srgrimes	register struct vnode *vp = ap->a_vp;
2621638Srgrimes	register u_long *tl;
2631638Srgrimes	register caddr_t cp;
2641638Srgrimes	register int t1, t2;
2651638Srgrimes	caddr_t bpos, dpos, cp2;
2661638Srgrimes	int error = 0, attrflag;
2671638Srgrimes	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
2681638Srgrimes	u_long mode, rmode;
2691638Srgrimes	int v3 = NFS_ISV3(vp);
2701638Srgrimes
2711638Srgrimes	/*
2721638Srgrimes	 * Disallow write attempts on filesystems mounted read-only;
2731638Srgrimes	 * unless the file is a socket, fifo, or a block or character
2741638Srgrimes	 * device resident on the filesystem.
2751638Srgrimes	 */
2761638Srgrimes	if ((ap->a_mode & VWRITE) && (vp->v_mount->mnt_flag & MNT_RDONLY)) {
2771638Srgrimes		switch (vp->v_type) {
2781638Srgrimes		case VREG: case VDIR: case VLNK:
2791638Srgrimes			return (EROFS);
2801638Srgrimes		}
2811638Srgrimes	}
2821638Srgrimes	/*
2831638Srgrimes	 * For nfs v3, do an access rpc, otherwise you are stuck emulating
2841638Srgrimes	 * ufs_access() locally using the vattr. This may not be correct,
2851638Srgrimes	 * since the server may apply other access criteria such as
2861638Srgrimes	 * client uid-->server uid mapping that we do not know about, but
2871638Srgrimes	 * this is better than just returning anything that is lying about
2881638Srgrimes	 * in the cache.
2891638Srgrimes	 */
2901638Srgrimes	if (v3) {
2911638Srgrimes		nfsstats.rpccnt[NFSPROC_ACCESS]++;
2921638Srgrimes		nfsm_reqhead(vp, NFSPROC_ACCESS, NFSX_FH(v3) + NFSX_UNSIGNED);
2931638Srgrimes		nfsm_fhtom(vp, v3);
2941638Srgrimes		nfsm_build(tl, u_long *, NFSX_UNSIGNED);
2951638Srgrimes		if (ap->a_mode & VREAD)
2961638Srgrimes			mode = NFSV3ACCESS_READ;
2971856Sdg		else
2981638Srgrimes			mode = 0;
2991638Srgrimes		if (vp->v_type == VDIR) {
3001638Srgrimes			if (ap->a_mode & VWRITE)
3011638Srgrimes				mode |= (NFSV3ACCESS_MODIFY | NFSV3ACCESS_EXTEND |
3021638Srgrimes					 NFSV3ACCESS_DELETE);
3031638Srgrimes			if (ap->a_mode & VEXEC)
3041638Srgrimes				mode |= NFSV3ACCESS_LOOKUP;
3051638Srgrimes		} else {
3061638Srgrimes			if (ap->a_mode & VWRITE)
3071638Srgrimes				mode |= (NFSV3ACCESS_MODIFY | NFSV3ACCESS_EXTEND);
3081638Srgrimes			if (ap->a_mode & VEXEC)
3091638Srgrimes				mode |= NFSV3ACCESS_EXECUTE;
3101638Srgrimes		}
3111638Srgrimes		*tl = txdr_unsigned(mode);
3121638Srgrimes		nfsm_request(vp, NFSPROC_ACCESS, ap->a_p, ap->a_cred);
3131638Srgrimes		nfsm_postop_attr(vp, attrflag);
3141638Srgrimes		if (!error) {
3151638Srgrimes			nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
3161638Srgrimes			rmode = fxdr_unsigned(u_long, *tl);
3171638Srgrimes			/*
3181638Srgrimes			 * The NFS V3 spec does not clarify whether or not
3191638Srgrimes			 * the returned access bits can be a superset of
3201638Srgrimes			 * the ones requested, so...
3211638Srgrimes			 */
3221638Srgrimes			if ((rmode & mode) != mode)
3231638Srgrimes				error = EACCES;
3241638Srgrimes		}
3251638Srgrimes		nfsm_reqdone;
3261638Srgrimes		return (error);
3271638Srgrimes	} else {
3281638Srgrimes		if (error = nfsspec_access(ap))
3291638Srgrimes			return (error);
3301638Srgrimes
3311638Srgrimes		/*
3321638Srgrimes		 * Attempt to prevent a mapped root from accessing a file
3331638Srgrimes		 * which it shouldn't.  We try to read a byte from the file
3341638Srgrimes		 * if the user is root and the file is not zero length.
3351638Srgrimes		 * After calling nfsspec_access, we should have the correct
3361638Srgrimes		 * file size cached.
3371638Srgrimes		 */
3381638Srgrimes		if (ap->a_cred->cr_uid == 0 && (ap->a_mode & VREAD)
3391638Srgrimes		    && VTONFS(vp)->n_size > 0) {
3401638Srgrimes			struct iovec aiov;
3411638Srgrimes			struct uio auio;
3421638Srgrimes			char buf[1];
3431638Srgrimes
3441638Srgrimes			aiov.iov_base = buf;
3451638Srgrimes			aiov.iov_len = 1;
3461638Srgrimes			auio.uio_iov = &aiov;
3471638Srgrimes			auio.uio_iovcnt = 1;
3481638Srgrimes			auio.uio_offset = 0;
3491638Srgrimes			auio.uio_resid = 1;
3501638Srgrimes			auio.uio_segflg = UIO_SYSSPACE;
3511638Srgrimes			auio.uio_rw = UIO_READ;
3521638Srgrimes			auio.uio_procp = ap->a_p;
3531638Srgrimes
3541638Srgrimes			if (vp->v_type == VREG)
3551638Srgrimes				error = nfs_readrpc(vp, &auio, ap->a_cred);
3561638Srgrimes			else if (vp->v_type == VDIR) {
3571638Srgrimes				char* bp;
3581638Srgrimes				bp = malloc(NFS_DIRBLKSIZ, M_TEMP, M_WAITOK);
3591638Srgrimes				aiov.iov_base = bp;
3601638Srgrimes				aiov.iov_len = auio.uio_resid = NFS_DIRBLKSIZ;
3611638Srgrimes				error = nfs_readdirrpc(vp, &auio, ap->a_cred);
3621638Srgrimes				free(bp, M_TEMP);
3631638Srgrimes			} else if (vp->v_type = VLNK)
3641638Srgrimes				error = nfs_readlinkrpc(vp, &auio, ap->a_cred);
3651638Srgrimes			else
3661638Srgrimes				error = EACCES;
3671638Srgrimes		}
3681638Srgrimes		return (error);
3691638Srgrimes	}
3701638Srgrimes}
3711638Srgrimes
3721638Srgrimes/*
3731638Srgrimes * nfs open vnode op
3741638Srgrimes * Check to see if the type is ok
3751638Srgrimes * and that deletion is not in progress.
3761638Srgrimes * For paged in text files, you will need to flush the page cache
3771638Srgrimes * if consistency is lost.
3781638Srgrimes */
3791638Srgrimes/* ARGSUSED */
3801638Srgrimesstatic int
3811638Srgrimesnfs_open(ap)
3821638Srgrimes	struct vop_open_args /* {
3831638Srgrimes		struct vnode *a_vp;
3841638Srgrimes		int  a_mode;
3851638Srgrimes		struct ucred *a_cred;
3861638Srgrimes		struct proc *a_p;
3871638Srgrimes	} */ *ap;
3881638Srgrimes{
3891638Srgrimes	register struct vnode *vp = ap->a_vp;
3901638Srgrimes	struct nfsnode *np = VTONFS(vp);
3911638Srgrimes	struct nfsmount *nmp = VFSTONFS(vp->v_mount);
3921638Srgrimes	struct vattr vattr;
3931638Srgrimes	int error;
3941638Srgrimes
3951638Srgrimes	if (vp->v_type != VREG && vp->v_type != VDIR && vp->v_type != VLNK)
3961638Srgrimes{ printf("open eacces vtyp=%d\n",vp->v_type);
3971638Srgrimes		return (EACCES);
3981638Srgrimes}
3991638Srgrimes	/*
4001638Srgrimes	 * Get a valid lease. If cached data is stale, flush it.
4011638Srgrimes	 */
4021638Srgrimes	if (nmp->nm_flag & NFSMNT_NQNFS) {
4031638Srgrimes		if (NQNFS_CKINVALID(vp, np, ND_READ)) {
4041638Srgrimes		    do {
4051638Srgrimes			error = nqnfs_getlease(vp, ND_READ, ap->a_cred,
4061638Srgrimes			    ap->a_p);
4071638Srgrimes		    } while (error == NQNFS_EXPIRED);
4081638Srgrimes		    if (error) {
4091638Srgrimes			return (error);
4101638Srgrimes		    }
4111638Srgrimes		    if (np->n_lrev != np->n_brev ||
4121638Srgrimes			(np->n_flag & NQNFSNONCACHE)) {
4131638Srgrimes			if ((error = nfs_vinvalbuf(vp, V_SAVE, ap->a_cred,
4141856Sdg				ap->a_p, 1)) == EINTR) {
4151638Srgrimes				return (error);
4161638Srgrimes			}
4171638Srgrimes			np->n_brev = np->n_lrev;
4181638Srgrimes		    }
4191638Srgrimes		}
4201638Srgrimes	} else {
4211638Srgrimes		if (np->n_flag & NMODIFIED) {
4221638Srgrimes			if ((error = nfs_vinvalbuf(vp, V_SAVE, ap->a_cred,
4231638Srgrimes				ap->a_p, 1)) == EINTR) {
4241638Srgrimes				return (error);
4251638Srgrimes			}
4261638Srgrimes			np->n_attrstamp = 0;
4271638Srgrimes			if (vp->v_type == VDIR)
4281638Srgrimes				np->n_direofoffset = 0;
4291638Srgrimes			error = VOP_GETATTR(vp, &vattr, ap->a_cred, ap->a_p);
4301638Srgrimes			if (error) {
4311638Srgrimes				return (error);
4321638Srgrimes			}
4331638Srgrimes			np->n_mtime = vattr.va_mtime.tv_sec;
4341638Srgrimes		} else {
4351638Srgrimes			error = VOP_GETATTR(vp, &vattr, ap->a_cred, ap->a_p);
4361638Srgrimes			if (error) {
4371638Srgrimes				return (error);
4381638Srgrimes			}
4391638Srgrimes			if (np->n_mtime != vattr.va_mtime.tv_sec) {
4401638Srgrimes				if (vp->v_type == VDIR)
4411638Srgrimes					np->n_direofoffset = 0;
4421638Srgrimes				if ((error = nfs_vinvalbuf(vp, V_SAVE,
4431638Srgrimes					ap->a_cred, ap->a_p, 1)) == EINTR) {
4441638Srgrimes					return (error);
4451638Srgrimes				}
4461638Srgrimes				np->n_mtime = vattr.va_mtime.tv_sec;
4471638Srgrimes			}
4481638Srgrimes		}
4491638Srgrimes	}
4501638Srgrimes	if ((nmp->nm_flag & NFSMNT_NQNFS) == 0)
4511638Srgrimes		np->n_attrstamp = 0; /* For Open/Close consistency */
4521638Srgrimes	return (0);
4531638Srgrimes}
4541638Srgrimes
4551638Srgrimes/*
4561638Srgrimes * nfs close vnode op
4571638Srgrimes * What an NFS client should do upon close after writing is a debatable issue.
4581638Srgrimes * Most NFS clients push delayed writes to the server upon close, basically for
4591638Srgrimes * two reasons:
4601638Srgrimes * 1 - So that any write errors may be reported back to the client process
4611638Srgrimes *     doing the close system call. By far the two most likely errors are
4621638Srgrimes *     NFSERR_NOSPC and NFSERR_DQUOT to indicate space allocation failure.
4631638Srgrimes * 2 - To put a worst case upper bound on cache inconsistency between
4641638Srgrimes *     multiple clients for the file.
4651638Srgrimes * There is also a consistency problem for Version 2 of the protocol w.r.t.
4661638Srgrimes * not being able to tell if other clients are writing a file concurrently,
4671638Srgrimes * since there is no way of knowing if the changed modify time in the reply
4681638Srgrimes * is only due to the write for this client.
4691638Srgrimes * (NFS Version 3 provides weak cache consistency data in the reply that
4701638Srgrimes *  should be sufficient to detect and handle this case.)
4711638Srgrimes *
4721638Srgrimes * The current code does the following:
4731638Srgrimes * for NFS Version 2 - play it safe and flush/invalidate all dirty buffers
4741638Srgrimes * for NFS Version 3 - flush dirty buffers to the server but don't invalidate
4751638Srgrimes *                     or commit them (this satisfies 1 and 2 except for the
4761638Srgrimes *                     case where the server crashes after this close but
4771638Srgrimes *                     before the commit RPC, which is felt to be "good
4781638Srgrimes *                     enough". Changing the last argument to nfs_flush() to
4791638Srgrimes *                     a 1 would force a commit operation, if it is felt a
4801638Srgrimes *                     commit is necessary now.
4811638Srgrimes * for NQNFS         - do nothing now, since 2 is dealt with via leases and
4821638Srgrimes *                     1 should be dealt with via an fsync() system call for
4831638Srgrimes *                     cases where write errors are important.
4841638Srgrimes */
4851638Srgrimes/* ARGSUSED */
4861638Srgrimesstatic int
4871638Srgrimesnfs_close(ap)
4881638Srgrimes	struct vop_close_args /* {
4891638Srgrimes		struct vnodeop_desc *a_desc;
4901638Srgrimes		struct vnode *a_vp;
4911638Srgrimes		int  a_fflag;
4921638Srgrimes		struct ucred *a_cred;
4931638Srgrimes		struct proc *a_p;
4941638Srgrimes	} */ *ap;
4951638Srgrimes{
4961638Srgrimes	register struct vnode *vp = ap->a_vp;
4971638Srgrimes	register struct nfsnode *np = VTONFS(vp);
4981638Srgrimes	int error = 0;
4991638Srgrimes
5001638Srgrimes	if (vp->v_type == VREG) {
5011638Srgrimes	    if ((VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) == 0 &&
5021638Srgrimes		(np->n_flag & NMODIFIED)) {
5031638Srgrimes		if (NFS_ISV3(vp)) {
5041638Srgrimes		    error = nfs_flush(vp, ap->a_cred, MNT_WAIT, ap->a_p, 0);
5051638Srgrimes		    np->n_flag &= ~NMODIFIED;
5061638Srgrimes		} else
5071638Srgrimes		    error = nfs_vinvalbuf(vp, V_SAVE, ap->a_cred, ap->a_p, 1);
5081638Srgrimes		np->n_attrstamp = 0;
5091638Srgrimes	    }
5101638Srgrimes	    if (np->n_flag & NWRITEERR) {
5111638Srgrimes		np->n_flag &= ~NWRITEERR;
5121638Srgrimes		error = np->n_error;
5131638Srgrimes	    }
5141638Srgrimes	}
5151638Srgrimes	return (error);
5161638Srgrimes}
5171638Srgrimes
5181638Srgrimes/*
5191638Srgrimes * nfs getattr call from vfs.
5201638Srgrimes */
5211638Srgrimesstatic int
5221638Srgrimesnfs_getattr(ap)
5231638Srgrimes	struct vop_getattr_args /* {
5241638Srgrimes		struct vnode *a_vp;
5251638Srgrimes		struct vattr *a_vap;
5261638Srgrimes		struct ucred *a_cred;
5271638Srgrimes		struct proc *a_p;
5281638Srgrimes	} */ *ap;
5291638Srgrimes{
5301638Srgrimes	register struct vnode *vp = ap->a_vp;
5311638Srgrimes	register struct nfsnode *np = VTONFS(vp);
5321638Srgrimes	register caddr_t cp;
5331638Srgrimes	register u_long *tl;
5341638Srgrimes	register int t1, t2;
5351638Srgrimes	caddr_t bpos, dpos;
5361638Srgrimes	int error = 0;
5371638Srgrimes	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
5381638Srgrimes	int v3 = NFS_ISV3(vp);
5391638Srgrimes
5401638Srgrimes	/*
5411638Srgrimes	 * Update local times for special files.
5421638Srgrimes	 */
5431638Srgrimes	if (np->n_flag & (NACC | NUPD))
5441638Srgrimes		np->n_flag |= NCHG;
5451638Srgrimes	/*
5461638Srgrimes	 * First look in the cache.
5471638Srgrimes	 */
5481638Srgrimes	if (nfs_getattrcache(vp, ap->a_vap) == 0)
5491638Srgrimes		return (0);
5501638Srgrimes	nfsstats.rpccnt[NFSPROC_GETATTR]++;
5511638Srgrimes	nfsm_reqhead(vp, NFSPROC_GETATTR, NFSX_FH(v3));
5521638Srgrimes	nfsm_fhtom(vp, v3);
5531638Srgrimes	nfsm_request(vp, NFSPROC_GETATTR, ap->a_p, ap->a_cred);
5541638Srgrimes	if (!error)
5551638Srgrimes		nfsm_loadattr(vp, ap->a_vap);
5561638Srgrimes	nfsm_reqdone;
5571638Srgrimes	return (error);
5581638Srgrimes}
5591638Srgrimes
5601638Srgrimes/*
5611638Srgrimes * nfs setattr call.
5621638Srgrimes */
5631638Srgrimesstatic int
5641638Srgrimesnfs_setattr(ap)
5651638Srgrimes	struct vop_setattr_args /* {
5661638Srgrimes		struct vnodeop_desc *a_desc;
5671638Srgrimes		struct vnode *a_vp;
5681638Srgrimes		struct vattr *a_vap;
5691638Srgrimes		struct ucred *a_cred;
5701638Srgrimes		struct proc *a_p;
5711638Srgrimes	} */ *ap;
5721638Srgrimes{
5731638Srgrimes	register struct vnode *vp = ap->a_vp;
5741638Srgrimes	register struct nfsnode *np = VTONFS(vp);
5751638Srgrimes	register struct vattr *vap = ap->a_vap;
5761638Srgrimes	int error = 0;
5771638Srgrimes	u_quad_t tsize;
5781638Srgrimes
5791638Srgrimes#ifndef nolint
5801638Srgrimes	tsize = (u_quad_t)0;
5811638Srgrimes#endif
5821638Srgrimes	/*
5831638Srgrimes	 * Disallow write attempts if the filesystem is mounted read-only.
5841638Srgrimes	 */
5851638Srgrimes  	if ((vap->va_flags != VNOVAL || vap->va_uid != (uid_t)VNOVAL ||
5861638Srgrimes	    vap->va_gid != (gid_t)VNOVAL || vap->va_atime.tv_sec != VNOVAL ||
5871638Srgrimes	    vap->va_mtime.tv_sec != VNOVAL || vap->va_mode != (mode_t)VNOVAL) &&
5881638Srgrimes	    (vp->v_mount->mnt_flag & MNT_RDONLY))
5891638Srgrimes		return (EROFS);
5901638Srgrimes	if (vap->va_size != VNOVAL) {
5911638Srgrimes 		switch (vp->v_type) {
5921638Srgrimes 		case VDIR:
5931856Sdg 			return (EISDIR);
5941856Sdg 		case VCHR:
5951856Sdg 		case VBLK:
5961638Srgrimes 		case VSOCK:
5971638Srgrimes 		case VFIFO:
5981638Srgrimes			if (vap->va_mtime.tv_sec == VNOVAL &&
5991638Srgrimes			    vap->va_atime.tv_sec == VNOVAL &&
6001638Srgrimes			    vap->va_mode == (u_short)VNOVAL &&
6011638Srgrimes			    vap->va_uid == (uid_t)VNOVAL &&
6021638Srgrimes			    vap->va_gid == (gid_t)VNOVAL)
6031638Srgrimes				return (0);
6041638Srgrimes 			vap->va_size = VNOVAL;
6051638Srgrimes 			break;
6061638Srgrimes 		default:
6071638Srgrimes			/*
6081638Srgrimes			 * Disallow write attempts if the filesystem is
6091638Srgrimes			 * mounted read-only.
6101638Srgrimes			 */
6111638Srgrimes			if (vp->v_mount->mnt_flag & MNT_RDONLY)
6121638Srgrimes				return (EROFS);
6131638Srgrimes 			if (np->n_flag & NMODIFIED) {
6141638Srgrimes 			    if (vap->va_size == 0)
6151638Srgrimes 				error = nfs_vinvalbuf(vp, 0,
6161638Srgrimes 					ap->a_cred, ap->a_p, 1);
6171638Srgrimes 			    else
6181638Srgrimes 				error = nfs_vinvalbuf(vp, V_SAVE,
619 					ap->a_cred, ap->a_p, 1);
620 			    if (error)
621 				return (error);
622 			}
623 			tsize = np->n_size;
624 			np->n_size = np->n_vattr.va_size = vap->va_size;
625 			vnode_pager_setsize(vp, (u_long)np->n_size);
626  		};
627  	} else if ((vap->va_mtime.tv_sec != VNOVAL ||
628		vap->va_atime.tv_sec != VNOVAL) && (np->n_flag & NMODIFIED) &&
629		vp->v_type == VREG &&
630  		(error = nfs_vinvalbuf(vp, V_SAVE, ap->a_cred,
631		 ap->a_p, 1)) == EINTR)
632		return (error);
633	error = nfs_setattrrpc(vp, vap, ap->a_cred, ap->a_p);
634	if (error && vap->va_size != VNOVAL) {
635		np->n_size = np->n_vattr.va_size = tsize;
636		vnode_pager_setsize(vp, (u_long)np->n_size);
637	}
638	return (error);
639}
640
641/*
642 * Do an nfs setattr rpc.
643 */
644static int
645nfs_setattrrpc(vp, vap, cred, procp)
646	register struct vnode *vp;
647	register struct vattr *vap;
648	struct ucred *cred;
649	struct proc *procp;
650{
651	register struct nfsv2_sattr *sp;
652	register caddr_t cp;
653	register long t1, t2;
654	caddr_t bpos, dpos, cp2;
655	u_long *tl;
656	int error = 0, wccflag = NFSV3_WCCRATTR;
657	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
658	int v3 = NFS_ISV3(vp);
659
660	nfsstats.rpccnt[NFSPROC_SETATTR]++;
661	nfsm_reqhead(vp, NFSPROC_SETATTR, NFSX_FH(v3) + NFSX_SATTR(v3));
662	nfsm_fhtom(vp, v3);
663	if (v3) {
664		if (vap->va_mode != (u_short)VNOVAL) {
665			nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED);
666			*tl++ = nfs_true;
667			*tl = txdr_unsigned(vap->va_mode);
668		} else {
669			nfsm_build(tl, u_long *, NFSX_UNSIGNED);
670			*tl = nfs_false;
671		}
672		if (vap->va_uid != (uid_t)VNOVAL) {
673			nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED);
674			*tl++ = nfs_true;
675			*tl = txdr_unsigned(vap->va_uid);
676		} else {
677			nfsm_build(tl, u_long *, NFSX_UNSIGNED);
678			*tl = nfs_false;
679		}
680		if (vap->va_gid != (gid_t)VNOVAL) {
681			nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED);
682			*tl++ = nfs_true;
683			*tl = txdr_unsigned(vap->va_gid);
684		} else {
685			nfsm_build(tl, u_long *, NFSX_UNSIGNED);
686			*tl = nfs_false;
687		}
688		if (vap->va_size != VNOVAL) {
689			nfsm_build(tl, u_long *, 3 * NFSX_UNSIGNED);
690			*tl++ = nfs_true;
691			txdr_hyper(&vap->va_size, tl);
692		} else {
693			nfsm_build(tl, u_long *, NFSX_UNSIGNED);
694			*tl = nfs_false;
695		}
696		if (vap->va_atime.tv_sec != VNOVAL) {
697			if (vap->va_atime.tv_sec != time_second) {
698				nfsm_build(tl, u_long *, 3 * NFSX_UNSIGNED);
699				*tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT);
700				txdr_nfsv3time(&vap->va_atime, tl);
701			} else {
702				nfsm_build(tl, u_long *, NFSX_UNSIGNED);
703				*tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER);
704			}
705		} else {
706			nfsm_build(tl, u_long *, NFSX_UNSIGNED);
707			*tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE);
708		}
709		if (vap->va_mtime.tv_sec != VNOVAL) {
710			if (vap->va_mtime.tv_sec != time_second) {
711				nfsm_build(tl, u_long *, 3 * NFSX_UNSIGNED);
712				*tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT);
713				txdr_nfsv3time(&vap->va_mtime, tl);
714			} else {
715				nfsm_build(tl, u_long *, NFSX_UNSIGNED);
716				*tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER);
717			}
718		} else {
719			nfsm_build(tl, u_long *, NFSX_UNSIGNED);
720			*tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE);
721		}
722		nfsm_build(tl, u_long *, NFSX_UNSIGNED);
723		*tl = nfs_false;
724	} else {
725		nfsm_build(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
726		if (vap->va_mode == (u_short)VNOVAL)
727			sp->sa_mode = VNOVAL;
728		else
729			sp->sa_mode = vtonfsv2_mode(vp->v_type, vap->va_mode);
730		if (vap->va_uid == (uid_t)VNOVAL)
731			sp->sa_uid = VNOVAL;
732		else
733			sp->sa_uid = txdr_unsigned(vap->va_uid);
734		if (vap->va_gid == (gid_t)VNOVAL)
735			sp->sa_gid = VNOVAL;
736		else
737			sp->sa_gid = txdr_unsigned(vap->va_gid);
738		sp->sa_size = txdr_unsigned(vap->va_size);
739		txdr_nfsv2time(&vap->va_atime, &sp->sa_atime);
740		txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime);
741	}
742	nfsm_request(vp, NFSPROC_SETATTR, procp, cred);
743	if (v3) {
744		nfsm_wcc_data(vp, wccflag);
745	} else
746		nfsm_loadattr(vp, (struct vattr *)0);
747	nfsm_reqdone;
748	return (error);
749}
750
751/*
752 * nfs lookup call, one step at a time...
753 * First look in cache
754 * If not found, unlock the directory nfsnode and do the rpc
755 */
756static int
757nfs_lookup(ap)
758	struct vop_lookup_args /* {
759		struct vnodeop_desc *a_desc;
760		struct vnode *a_dvp;
761		struct vnode **a_vpp;
762		struct componentname *a_cnp;
763	} */ *ap;
764{
765	register struct componentname *cnp = ap->a_cnp;
766	register struct vnode *dvp = ap->a_dvp;
767	register struct vnode **vpp = ap->a_vpp;
768	register int flags = cnp->cn_flags;
769	register struct vnode *newvp;
770	register u_long *tl;
771	register caddr_t cp;
772	register long t1, t2;
773	struct nfsmount *nmp;
774	caddr_t bpos, dpos, cp2;
775	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
776	long len;
777	nfsfh_t *fhp;
778	struct nfsnode *np;
779	int lockparent, wantparent, error = 0, attrflag, fhsize;
780	int v3 = NFS_ISV3(dvp);
781	struct proc *p = cnp->cn_proc;
782
783	if ((flags & ISLASTCN) && (dvp->v_mount->mnt_flag & MNT_RDONLY) &&
784	    (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME))
785		return (EROFS);
786	*vpp = NULLVP;
787	if (dvp->v_type != VDIR)
788		return (ENOTDIR);
789	lockparent = flags & LOCKPARENT;
790	wantparent = flags & (LOCKPARENT|WANTPARENT);
791	nmp = VFSTONFS(dvp->v_mount);
792	np = VTONFS(dvp);
793	if ((error = cache_lookup(dvp, vpp, cnp)) && error != ENOENT) {
794		struct vattr vattr;
795		int vpid;
796
797		if (error = VOP_ACCESS(dvp, VEXEC, cnp->cn_cred, p)) {
798			*vpp = NULLVP;
799			return (error);
800		}
801
802		newvp = *vpp;
803		vpid = newvp->v_id;
804		/*
805		 * See the comment starting `Step through' in ufs/ufs_lookup.c
806		 * for an explanation of the locking protocol
807		 */
808		if (dvp == newvp) {
809			VREF(newvp);
810			error = 0;
811		} else if (flags & ISDOTDOT) {
812			VOP_UNLOCK(dvp, 0, p);
813			error = vget(newvp, LK_EXCLUSIVE, p);
814			if (!error && lockparent && (flags & ISLASTCN))
815				error = vn_lock(dvp, LK_EXCLUSIVE, p);
816		} else {
817			error = vget(newvp, LK_EXCLUSIVE, p);
818			if (!lockparent || error || !(flags & ISLASTCN))
819				VOP_UNLOCK(dvp, 0, p);
820		}
821		if (!error) {
822			if (vpid == newvp->v_id) {
823			   if (!VOP_GETATTR(newvp, &vattr, cnp->cn_cred, p)
824			    && vattr.va_ctime.tv_sec == VTONFS(newvp)->n_ctime) {
825				nfsstats.lookupcache_hits++;
826				if (cnp->cn_nameiop != LOOKUP &&
827				    (flags & ISLASTCN))
828					cnp->cn_flags |= SAVENAME;
829				return (0);
830			   }
831			   cache_purge(newvp);
832			}
833			vput(newvp);
834			if (lockparent && dvp != newvp && (flags & ISLASTCN))
835				VOP_UNLOCK(dvp, 0, p);
836		}
837		error = vn_lock(dvp, LK_EXCLUSIVE, p);
838		*vpp = NULLVP;
839		if (error)
840			return (error);
841	}
842	error = 0;
843	newvp = NULLVP;
844	nfsstats.lookupcache_misses++;
845	nfsstats.rpccnt[NFSPROC_LOOKUP]++;
846	len = cnp->cn_namelen;
847	nfsm_reqhead(dvp, NFSPROC_LOOKUP,
848		NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(len));
849	nfsm_fhtom(dvp, v3);
850	nfsm_strtom(cnp->cn_nameptr, len, NFS_MAXNAMLEN);
851	nfsm_request(dvp, NFSPROC_LOOKUP, cnp->cn_proc, cnp->cn_cred);
852	if (error) {
853		nfsm_postop_attr(dvp, attrflag);
854		m_freem(mrep);
855		goto nfsmout;
856	}
857	nfsm_getfh(fhp, fhsize, v3);
858
859	/*
860	 * Handle RENAME case...
861	 */
862	if (cnp->cn_nameiop == RENAME && wantparent && (flags & ISLASTCN)) {
863		if (NFS_CMPFH(np, fhp, fhsize)) {
864			m_freem(mrep);
865			return (EISDIR);
866		}
867		if (error = nfs_nget(dvp->v_mount, fhp, fhsize, &np)) {
868			m_freem(mrep);
869			return (error);
870		}
871		newvp = NFSTOV(np);
872		if (v3) {
873			nfsm_postop_attr(newvp, attrflag);
874			nfsm_postop_attr(dvp, attrflag);
875		} else
876			nfsm_loadattr(newvp, (struct vattr *)0);
877		*vpp = newvp;
878		m_freem(mrep);
879		cnp->cn_flags |= SAVENAME;
880		if (!lockparent)
881			VOP_UNLOCK(dvp, 0, p);
882		return (0);
883	}
884
885	if (flags & ISDOTDOT) {
886		VOP_UNLOCK(dvp, 0, p);
887		error = nfs_nget(dvp->v_mount, fhp, fhsize, &np);
888		if (error) {
889			vn_lock(dvp, LK_EXCLUSIVE + LK_RETRY, p);
890			return (error);
891		}
892		newvp = NFSTOV(np);
893		if (lockparent && (flags & ISLASTCN) &&
894		    (error = vn_lock(dvp, LK_EXCLUSIVE, p))) {
895		    	vput(newvp);
896			return (error);
897		}
898	} else if (NFS_CMPFH(np, fhp, fhsize)) {
899		VREF(dvp);
900		newvp = dvp;
901	} else {
902		if (error = nfs_nget(dvp->v_mount, fhp, fhsize, &np)) {
903			m_freem(mrep);
904			return (error);
905		}
906		if (!lockparent || !(flags & ISLASTCN))
907			VOP_UNLOCK(dvp, 0, p);
908		newvp = NFSTOV(np);
909	}
910	if (v3) {
911		nfsm_postop_attr(newvp, attrflag);
912		nfsm_postop_attr(dvp, attrflag);
913	} else
914		nfsm_loadattr(newvp, (struct vattr *)0);
915	if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN))
916		cnp->cn_flags |= SAVENAME;
917	if ((cnp->cn_flags & MAKEENTRY) &&
918	    (cnp->cn_nameiop != DELETE || !(flags & ISLASTCN))) {
919		np->n_ctime = np->n_vattr.va_ctime.tv_sec;
920		cache_enter(dvp, newvp, cnp);
921	}
922	*vpp = newvp;
923	nfsm_reqdone;
924	if (error) {
925		if (newvp != NULLVP) {
926			vrele(newvp);
927			*vpp = NULLVP;
928		}
929		if ((cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME) &&
930		    (flags & ISLASTCN) && error == ENOENT) {
931			if (!lockparent)
932				VOP_UNLOCK(dvp, 0, p);
933			if (dvp->v_mount->mnt_flag & MNT_RDONLY)
934				error = EROFS;
935			else
936				error = EJUSTRETURN;
937		}
938		if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN))
939			cnp->cn_flags |= SAVENAME;
940	}
941	return (error);
942}
943
944/*
945 * nfs read call.
946 * Just call nfs_bioread() to do the work.
947 */
948static int
949nfs_read(ap)
950	struct vop_read_args /* {
951		struct vnode *a_vp;
952		struct uio *a_uio;
953		int  a_ioflag;
954		struct ucred *a_cred;
955	} */ *ap;
956{
957	register struct vnode *vp = ap->a_vp;
958
959	if (vp->v_type != VREG)
960		return (EPERM);
961	return (nfs_bioread(vp, ap->a_uio, ap->a_ioflag, ap->a_cred, 0));
962}
963
964/*
965 * nfs readlink call
966 */
967static int
968nfs_readlink(ap)
969	struct vop_readlink_args /* {
970		struct vnode *a_vp;
971		struct uio *a_uio;
972		struct ucred *a_cred;
973	} */ *ap;
974{
975	register struct vnode *vp = ap->a_vp;
976
977	if (vp->v_type != VLNK)
978		return (EPERM);
979	return (nfs_bioread(vp, ap->a_uio, 0, ap->a_cred, 0));
980}
981
982/*
983 * Do a readlink rpc.
984 * Called by nfs_doio() from below the buffer cache.
985 */
986int
987nfs_readlinkrpc(vp, uiop, cred)
988	register struct vnode *vp;
989	struct uio *uiop;
990	struct ucred *cred;
991{
992	register u_long *tl;
993	register caddr_t cp;
994	register long t1, t2;
995	caddr_t bpos, dpos, cp2;
996	int error = 0, len, attrflag;
997	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
998	int v3 = NFS_ISV3(vp);
999
1000	nfsstats.rpccnt[NFSPROC_READLINK]++;
1001	nfsm_reqhead(vp, NFSPROC_READLINK, NFSX_FH(v3));
1002	nfsm_fhtom(vp, v3);
1003	nfsm_request(vp, NFSPROC_READLINK, uiop->uio_procp, cred);
1004	if (v3)
1005		nfsm_postop_attr(vp, attrflag);
1006	if (!error) {
1007		nfsm_strsiz(len, NFS_MAXPATHLEN);
1008		nfsm_mtouio(uiop, len);
1009	}
1010	nfsm_reqdone;
1011	return (error);
1012}
1013
1014/*
1015 * nfs read rpc call
1016 * Ditto above
1017 */
1018int
1019nfs_readrpc(vp, uiop, cred)
1020	register struct vnode *vp;
1021	struct uio *uiop;
1022	struct ucred *cred;
1023{
1024	register u_long *tl;
1025	register caddr_t cp;
1026	register long t1, t2;
1027	caddr_t bpos, dpos, cp2;
1028	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
1029	struct nfsmount *nmp;
1030	int error = 0, len, retlen, tsiz, eof, attrflag;
1031	int v3 = NFS_ISV3(vp);
1032
1033#ifndef nolint
1034	eof = 0;
1035#endif
1036	nmp = VFSTONFS(vp->v_mount);
1037	tsiz = uiop->uio_resid;
1038	if (uiop->uio_offset + tsiz > 0xffffffff && !v3)
1039		return (EFBIG);
1040	while (tsiz > 0) {
1041		nfsstats.rpccnt[NFSPROC_READ]++;
1042		len = (tsiz > nmp->nm_rsize) ? nmp->nm_rsize : tsiz;
1043		nfsm_reqhead(vp, NFSPROC_READ, NFSX_FH(v3) + NFSX_UNSIGNED * 3);
1044		nfsm_fhtom(vp, v3);
1045		nfsm_build(tl, u_long *, NFSX_UNSIGNED * 3);
1046		if (v3) {
1047			txdr_hyper(&uiop->uio_offset, tl);
1048			*(tl + 2) = txdr_unsigned(len);
1049		} else {
1050			*tl++ = txdr_unsigned(uiop->uio_offset);
1051			*tl++ = txdr_unsigned(len);
1052			*tl = 0;
1053		}
1054		nfsm_request(vp, NFSPROC_READ, uiop->uio_procp, cred);
1055		if (v3) {
1056			nfsm_postop_attr(vp, attrflag);
1057			if (error) {
1058				m_freem(mrep);
1059				goto nfsmout;
1060			}
1061			nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
1062			eof = fxdr_unsigned(int, *(tl + 1));
1063		} else
1064			nfsm_loadattr(vp, (struct vattr *)0);
1065		nfsm_strsiz(retlen, nmp->nm_rsize);
1066		nfsm_mtouio(uiop, retlen);
1067		m_freem(mrep);
1068		tsiz -= retlen;
1069		if (v3) {
1070			if (eof || retlen == 0)
1071				tsiz = 0;
1072		} else if (retlen < len)
1073			tsiz = 0;
1074	}
1075nfsmout:
1076	return (error);
1077}
1078
1079/*
1080 * nfs write call
1081 */
1082int
1083nfs_writerpc(vp, uiop, cred, iomode, must_commit)
1084	register struct vnode *vp;
1085	register struct uio *uiop;
1086	struct ucred *cred;
1087	int *iomode, *must_commit;
1088{
1089	register u_long *tl;
1090	register caddr_t cp;
1091	register int t1, t2, backup;
1092	caddr_t bpos, dpos, cp2;
1093	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
1094	struct nfsmount *nmp = VFSTONFS(vp->v_mount);
1095	int error = 0, len, tsiz, wccflag = NFSV3_WCCRATTR, rlen, commit;
1096	int v3 = NFS_ISV3(vp), committed = NFSV3WRITE_FILESYNC;
1097
1098#ifndef DIAGNOSTIC
1099	if (uiop->uio_iovcnt != 1)
1100		panic("nfs: writerpc iovcnt > 1");
1101#endif
1102	*must_commit = 0;
1103	tsiz = uiop->uio_resid;
1104	if (uiop->uio_offset + tsiz > 0xffffffff && !v3)
1105		return (EFBIG);
1106	while (tsiz > 0) {
1107		nfsstats.rpccnt[NFSPROC_WRITE]++;
1108		len = (tsiz > nmp->nm_wsize) ? nmp->nm_wsize : tsiz;
1109		nfsm_reqhead(vp, NFSPROC_WRITE,
1110			NFSX_FH(v3) + 5 * NFSX_UNSIGNED + nfsm_rndup(len));
1111		nfsm_fhtom(vp, v3);
1112		if (v3) {
1113			nfsm_build(tl, u_long *, 5 * NFSX_UNSIGNED);
1114			txdr_hyper(&uiop->uio_offset, tl);
1115			tl += 2;
1116			*tl++ = txdr_unsigned(len);
1117			*tl++ = txdr_unsigned(*iomode);
1118		} else {
1119			nfsm_build(tl, u_long *, 4 * NFSX_UNSIGNED);
1120			*++tl = txdr_unsigned(uiop->uio_offset);
1121			tl += 2;
1122		}
1123		*tl = txdr_unsigned(len);
1124		nfsm_uiotom(uiop, len);
1125		nfsm_request(vp, NFSPROC_WRITE, uiop->uio_procp, cred);
1126		if (v3) {
1127			wccflag = NFSV3_WCCCHK;
1128			nfsm_wcc_data(vp, wccflag);
1129			if (!error) {
1130				nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED +
1131					NFSX_V3WRITEVERF);
1132				rlen = fxdr_unsigned(int, *tl++);
1133				if (rlen == 0) {
1134					error = NFSERR_IO;
1135					break;
1136				} else if (rlen < len) {
1137					backup = len - rlen;
1138					uiop->uio_iov->iov_base -= backup;
1139					uiop->uio_iov->iov_len += backup;
1140					uiop->uio_offset -= backup;
1141					uiop->uio_resid += backup;
1142					len = rlen;
1143				}
1144				commit = fxdr_unsigned(int, *tl++);
1145
1146				/*
1147				 * Return the lowest committment level
1148				 * obtained by any of the RPCs.
1149				 */
1150				if (committed == NFSV3WRITE_FILESYNC)
1151					committed = commit;
1152				else if (committed == NFSV3WRITE_DATASYNC &&
1153					commit == NFSV3WRITE_UNSTABLE)
1154					committed = commit;
1155				if ((nmp->nm_flag & NFSMNT_HASWRITEVERF) == 0) {
1156				    bcopy((caddr_t)tl, (caddr_t)nmp->nm_verf,
1157					NFSX_V3WRITEVERF);
1158				    nmp->nm_flag |= NFSMNT_HASWRITEVERF;
1159				} else if (bcmp((caddr_t)tl,
1160				    (caddr_t)nmp->nm_verf, NFSX_V3WRITEVERF)) {
1161				    *must_commit = 1;
1162				    bcopy((caddr_t)tl, (caddr_t)nmp->nm_verf,
1163					NFSX_V3WRITEVERF);
1164				}
1165			}
1166		} else
1167		    nfsm_loadattr(vp, (struct vattr *)0);
1168		if (wccflag)
1169		    VTONFS(vp)->n_mtime = VTONFS(vp)->n_vattr.va_mtime.tv_sec;
1170		m_freem(mrep);
1171		tsiz -= len;
1172	}
1173nfsmout:
1174	if (vp->v_mount->mnt_flag & MNT_ASYNC)
1175		committed = NFSV3WRITE_FILESYNC;
1176	*iomode = committed;
1177	if (error)
1178		uiop->uio_resid = tsiz;
1179	return (error);
1180}
1181
1182/*
1183 * nfs mknod rpc
1184 * For NFS v2 this is a kludge. Use a create rpc but with the IFMT bits of the
1185 * mode set to specify the file type and the size field for rdev.
1186 */
1187static int
1188nfs_mknodrpc(dvp, vpp, cnp, vap)
1189	register struct vnode *dvp;
1190	register struct vnode **vpp;
1191	register struct componentname *cnp;
1192	register struct vattr *vap;
1193{
1194	register struct nfsv2_sattr *sp;
1195	register struct nfsv3_sattr *sp3;
1196	register u_long *tl;
1197	register caddr_t cp;
1198	register long t1, t2;
1199	struct vnode *newvp = (struct vnode *)0;
1200	struct nfsnode *np = (struct nfsnode *)0;
1201	struct vattr vattr;
1202	char *cp2;
1203	caddr_t bpos, dpos;
1204	int error = 0, wccflag = NFSV3_WCCRATTR, gotvp = 0;
1205	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
1206	u_long rdev;
1207	int v3 = NFS_ISV3(dvp);
1208
1209	if (vap->va_type == VCHR || vap->va_type == VBLK)
1210		rdev = txdr_unsigned(vap->va_rdev);
1211	else if (vap->va_type == VFIFO || vap->va_type == VSOCK)
1212		rdev = 0xffffffff;
1213	else {
1214		VOP_ABORTOP(dvp, cnp);
1215		return (EOPNOTSUPP);
1216	}
1217	if (error = VOP_GETATTR(dvp, &vattr, cnp->cn_cred, cnp->cn_proc)) {
1218		VOP_ABORTOP(dvp, cnp);
1219		return (error);
1220	}
1221	nfsstats.rpccnt[NFSPROC_MKNOD]++;
1222	nfsm_reqhead(dvp, NFSPROC_MKNOD, NFSX_FH(v3) + 4 * NFSX_UNSIGNED +
1223		+ nfsm_rndup(cnp->cn_namelen) + NFSX_SATTR(v3));
1224	nfsm_fhtom(dvp, v3);
1225	nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
1226	if (v3) {
1227		nfsm_build(tl, u_long *, NFSX_UNSIGNED + NFSX_V3SRVSATTR);
1228		*tl++ = vtonfsv3_type(vap->va_type);
1229		sp3 = (struct nfsv3_sattr *)tl;
1230		nfsm_v3sattr(sp3, vap, cnp->cn_cred->cr_uid, vattr.va_gid);
1231		if (vap->va_type == VCHR || vap->va_type == VBLK) {
1232			nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED);
1233			*tl++ = txdr_unsigned(major(vap->va_rdev));
1234			*tl = txdr_unsigned(minor(vap->va_rdev));
1235		}
1236	} else {
1237		nfsm_build(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
1238		sp->sa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode);
1239		sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid);
1240		sp->sa_gid = txdr_unsigned(vattr.va_gid);
1241		sp->sa_size = rdev;
1242		txdr_nfsv2time(&vap->va_atime, &sp->sa_atime);
1243		txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime);
1244	}
1245	nfsm_request(dvp, NFSPROC_MKNOD, cnp->cn_proc, cnp->cn_cred);
1246	if (!error) {
1247		nfsm_mtofh(dvp, newvp, v3, gotvp);
1248		if (!gotvp) {
1249			if (newvp) {
1250				vput(newvp);
1251				newvp = (struct vnode *)0;
1252			}
1253			error = nfs_lookitup(dvp, cnp->cn_nameptr,
1254			    cnp->cn_namelen, cnp->cn_cred, cnp->cn_proc, &np);
1255			if (!error)
1256				newvp = NFSTOV(np);
1257		}
1258	}
1259	if (v3)
1260		nfsm_wcc_data(dvp, wccflag);
1261	nfsm_reqdone;
1262	if (error) {
1263		if (newvp)
1264			vput(newvp);
1265	} else {
1266		if (cnp->cn_flags & MAKEENTRY)
1267			cache_enter(dvp, newvp, cnp);
1268		*vpp = newvp;
1269	}
1270	zfree(namei_zone, cnp->cn_pnbuf);
1271	VTONFS(dvp)->n_flag |= NMODIFIED;
1272	if (!wccflag)
1273		VTONFS(dvp)->n_attrstamp = 0;
1274	return (error);
1275}
1276
1277/*
1278 * nfs mknod vop
1279 * just call nfs_mknodrpc() to do the work.
1280 */
1281/* ARGSUSED */
1282static int
1283nfs_mknod(ap)
1284	struct vop_mknod_args /* {
1285		struct vnode *a_dvp;
1286		struct vnode **a_vpp;
1287		struct componentname *a_cnp;
1288		struct vattr *a_vap;
1289	} */ *ap;
1290{
1291	struct vnode *newvp;
1292	int error;
1293
1294	error = nfs_mknodrpc(ap->a_dvp, &newvp, ap->a_cnp, ap->a_vap);
1295	if (!error)
1296		vput(newvp);
1297	return (error);
1298}
1299
1300static u_long create_verf;
1301/*
1302 * nfs file create call
1303 */
1304static int
1305nfs_create(ap)
1306	struct vop_create_args /* {
1307		struct vnode *a_dvp;
1308		struct vnode **a_vpp;
1309		struct componentname *a_cnp;
1310		struct vattr *a_vap;
1311	} */ *ap;
1312{
1313	register struct vnode *dvp = ap->a_dvp;
1314	register struct vattr *vap = ap->a_vap;
1315	register struct componentname *cnp = ap->a_cnp;
1316	register struct nfsv2_sattr *sp;
1317	register struct nfsv3_sattr *sp3;
1318	register u_long *tl;
1319	register caddr_t cp;
1320	register long t1, t2;
1321	struct nfsnode *np = (struct nfsnode *)0;
1322	struct vnode *newvp = (struct vnode *)0;
1323	caddr_t bpos, dpos, cp2;
1324	int error = 0, wccflag = NFSV3_WCCRATTR, gotvp = 0, fmode = 0;
1325	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
1326	struct vattr vattr;
1327	int v3 = NFS_ISV3(dvp);
1328
1329	/*
1330	 * Oops, not for me..
1331	 */
1332	if (vap->va_type == VSOCK)
1333		return (nfs_mknodrpc(dvp, ap->a_vpp, cnp, vap));
1334
1335	if (error = VOP_GETATTR(dvp, &vattr, cnp->cn_cred, cnp->cn_proc)) {
1336		VOP_ABORTOP(dvp, cnp);
1337		return (error);
1338	}
1339	if (vap->va_vaflags & VA_EXCLUSIVE)
1340		fmode |= O_EXCL;
1341again:
1342	nfsstats.rpccnt[NFSPROC_CREATE]++;
1343	nfsm_reqhead(dvp, NFSPROC_CREATE, NFSX_FH(v3) + 2 * NFSX_UNSIGNED +
1344		nfsm_rndup(cnp->cn_namelen) + NFSX_SATTR(v3));
1345	nfsm_fhtom(dvp, v3);
1346	nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
1347	if (v3) {
1348		nfsm_build(tl, u_long *, NFSX_UNSIGNED);
1349		if (fmode & O_EXCL) {
1350		    *tl = txdr_unsigned(NFSV3CREATE_EXCLUSIVE);
1351		    nfsm_build(tl, u_long *, NFSX_V3CREATEVERF);
1352#ifdef INET
1353		    if (!TAILQ_EMPTY(&in_ifaddrhead))
1354			*tl++ = IA_SIN(in_ifaddrhead.tqh_first)->sin_addr.s_addr;
1355		    else
1356#endif
1357			*tl++ = create_verf;
1358		    *tl = ++create_verf;
1359		} else {
1360		    *tl = txdr_unsigned(NFSV3CREATE_UNCHECKED);
1361		    nfsm_build(tl, u_long *, NFSX_V3SRVSATTR);
1362		    sp3 = (struct nfsv3_sattr *)tl;
1363		    nfsm_v3sattr(sp3, vap, cnp->cn_cred->cr_uid, vattr.va_gid);
1364		}
1365	} else {
1366		nfsm_build(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
1367		sp->sa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode);
1368		sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid);
1369		sp->sa_gid = txdr_unsigned(vattr.va_gid);
1370		sp->sa_size = 0;
1371		txdr_nfsv2time(&vap->va_atime, &sp->sa_atime);
1372		txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime);
1373	}
1374	nfsm_request(dvp, NFSPROC_CREATE, cnp->cn_proc, cnp->cn_cred);
1375	if (!error) {
1376		nfsm_mtofh(dvp, newvp, v3, gotvp);
1377		if (!gotvp) {
1378			if (newvp) {
1379				vput(newvp);
1380				newvp = (struct vnode *)0;
1381			}
1382			error = nfs_lookitup(dvp, cnp->cn_nameptr,
1383			    cnp->cn_namelen, cnp->cn_cred, cnp->cn_proc, &np);
1384			if (!error)
1385				newvp = NFSTOV(np);
1386		}
1387	}
1388	if (v3)
1389		nfsm_wcc_data(dvp, wccflag);
1390	nfsm_reqdone;
1391	if (error) {
1392		if (v3 && (fmode & O_EXCL) && error == NFSERR_NOTSUPP) {
1393			fmode &= ~O_EXCL;
1394			goto again;
1395		}
1396		if (newvp)
1397			vput(newvp);
1398	} else if (v3 && (fmode & O_EXCL))
1399		error = nfs_setattrrpc(newvp, vap, cnp->cn_cred, cnp->cn_proc);
1400	if (!error) {
1401		if (cnp->cn_flags & MAKEENTRY)
1402			cache_enter(dvp, newvp, cnp);
1403		*ap->a_vpp = newvp;
1404	}
1405	zfree(namei_zone, cnp->cn_pnbuf);
1406	VTONFS(dvp)->n_flag |= NMODIFIED;
1407	if (!wccflag)
1408		VTONFS(dvp)->n_attrstamp = 0;
1409	return (error);
1410}
1411
1412/*
1413 * nfs file remove call
1414 * To try and make nfs semantics closer to ufs semantics, a file that has
1415 * other processes using the vnode is renamed instead of removed and then
1416 * removed later on the last close.
1417 * - If v_usecount > 1
1418 *	  If a rename is not already in the works
1419 *	     call nfs_sillyrename() to set it up
1420 *     else
1421 *	  do the remove rpc
1422 */
1423static int
1424nfs_remove(ap)
1425	struct vop_remove_args /* {
1426		struct vnodeop_desc *a_desc;
1427		struct vnode * a_dvp;
1428		struct vnode * a_vp;
1429		struct componentname * a_cnp;
1430	} */ *ap;
1431{
1432	register struct vnode *vp = ap->a_vp;
1433	register struct vnode *dvp = ap->a_dvp;
1434	register struct componentname *cnp = ap->a_cnp;
1435	register struct nfsnode *np = VTONFS(vp);
1436	int error = 0;
1437	struct vattr vattr;
1438
1439#ifndef DIAGNOSTIC
1440	if ((cnp->cn_flags & HASBUF) == 0)
1441		panic("nfs_remove: no name");
1442	if (vp->v_usecount < 1)
1443		panic("nfs_remove: bad v_usecount");
1444#endif
1445	if (vp->v_usecount == 1 || (np->n_sillyrename &&
1446	    VOP_GETATTR(vp, &vattr, cnp->cn_cred, cnp->cn_proc) == 0 &&
1447	    vattr.va_nlink > 1)) {
1448		/*
1449		 * Purge the name cache so that the chance of a lookup for
1450		 * the name succeeding while the remove is in progress is
1451		 * minimized. Without node locking it can still happen, such
1452		 * that an I/O op returns ESTALE, but since you get this if
1453		 * another host removes the file..
1454		 */
1455		cache_purge(vp);
1456		/*
1457		 * throw away biocache buffers, mainly to avoid
1458		 * unnecessary delayed writes later.
1459		 */
1460		error = nfs_vinvalbuf(vp, 0, cnp->cn_cred, cnp->cn_proc, 1);
1461		/* Do the rpc */
1462		if (error != EINTR)
1463			error = nfs_removerpc(dvp, cnp->cn_nameptr,
1464				cnp->cn_namelen, cnp->cn_cred, cnp->cn_proc);
1465		/*
1466		 * Kludge City: If the first reply to the remove rpc is lost..
1467		 *   the reply to the retransmitted request will be ENOENT
1468		 *   since the file was in fact removed
1469		 *   Therefore, we cheat and return success.
1470		 */
1471		if (error == ENOENT)
1472			error = 0;
1473	} else if (!np->n_sillyrename)
1474		error = nfs_sillyrename(dvp, vp, cnp);
1475	zfree(namei_zone, cnp->cn_pnbuf);
1476	np->n_attrstamp = 0;
1477	return (error);
1478}
1479
1480/*
1481 * nfs file remove rpc called from nfs_inactive
1482 */
1483int
1484nfs_removeit(sp)
1485	register struct sillyrename *sp;
1486{
1487
1488	return (nfs_removerpc(sp->s_dvp, sp->s_name, sp->s_namlen, sp->s_cred,
1489		(struct proc *)0));
1490}
1491
1492/*
1493 * Nfs remove rpc, called from nfs_remove() and nfs_removeit().
1494 */
1495static int
1496nfs_removerpc(dvp, name, namelen, cred, proc)
1497	register struct vnode *dvp;
1498	char *name;
1499	int namelen;
1500	struct ucred *cred;
1501	struct proc *proc;
1502{
1503	register u_long *tl;
1504	register caddr_t cp;
1505	register long t1, t2;
1506	caddr_t bpos, dpos, cp2;
1507	int error = 0, wccflag = NFSV3_WCCRATTR;
1508	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
1509	int v3 = NFS_ISV3(dvp);
1510
1511	nfsstats.rpccnt[NFSPROC_REMOVE]++;
1512	nfsm_reqhead(dvp, NFSPROC_REMOVE,
1513		NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(namelen));
1514	nfsm_fhtom(dvp, v3);
1515	nfsm_strtom(name, namelen, NFS_MAXNAMLEN);
1516	nfsm_request(dvp, NFSPROC_REMOVE, proc, cred);
1517	if (v3)
1518		nfsm_wcc_data(dvp, wccflag);
1519	nfsm_reqdone;
1520	VTONFS(dvp)->n_flag |= NMODIFIED;
1521	if (!wccflag)
1522		VTONFS(dvp)->n_attrstamp = 0;
1523	return (error);
1524}
1525
1526/*
1527 * nfs file rename call
1528 */
1529static int
1530nfs_rename(ap)
1531	struct vop_rename_args  /* {
1532		struct vnode *a_fdvp;
1533		struct vnode *a_fvp;
1534		struct componentname *a_fcnp;
1535		struct vnode *a_tdvp;
1536		struct vnode *a_tvp;
1537		struct componentname *a_tcnp;
1538	} */ *ap;
1539{
1540	register struct vnode *fvp = ap->a_fvp;
1541	register struct vnode *tvp = ap->a_tvp;
1542	register struct vnode *fdvp = ap->a_fdvp;
1543	register struct vnode *tdvp = ap->a_tdvp;
1544	register struct componentname *tcnp = ap->a_tcnp;
1545	register struct componentname *fcnp = ap->a_fcnp;
1546	int error;
1547
1548#ifndef DIAGNOSTIC
1549	if ((tcnp->cn_flags & HASBUF) == 0 ||
1550	    (fcnp->cn_flags & HASBUF) == 0)
1551		panic("nfs_rename: no name");
1552#endif
1553	/* Check for cross-device rename */
1554	if ((fvp->v_mount != tdvp->v_mount) ||
1555	    (tvp && (fvp->v_mount != tvp->v_mount))) {
1556		error = EXDEV;
1557		goto out;
1558	}
1559
1560	/*
1561	 * If the tvp exists and is in use, sillyrename it before doing the
1562	 * rename of the new file over it.
1563	 * XXX Can't sillyrename a directory.
1564	 */
1565	if (tvp && tvp->v_usecount > 1 && !VTONFS(tvp)->n_sillyrename &&
1566		tvp->v_type != VDIR && !nfs_sillyrename(tdvp, tvp, tcnp)) {
1567		vput(tvp);
1568		tvp = NULL;
1569	}
1570
1571	error = nfs_renamerpc(fdvp, fcnp->cn_nameptr, fcnp->cn_namelen,
1572		tdvp, tcnp->cn_nameptr, tcnp->cn_namelen, tcnp->cn_cred,
1573		tcnp->cn_proc);
1574
1575	if (fvp->v_type == VDIR) {
1576		if (tvp != NULL && tvp->v_type == VDIR)
1577			cache_purge(tdvp);
1578		cache_purge(fdvp);
1579	}
1580out:
1581	if (tdvp == tvp)
1582		vrele(tdvp);
1583	else
1584		vput(tdvp);
1585	if (tvp)
1586		vput(tvp);
1587	vrele(fdvp);
1588	vrele(fvp);
1589	/*
1590	 * Kludge: Map ENOENT => 0 assuming that it is a reply to a retry.
1591	 */
1592	if (error == ENOENT)
1593		error = 0;
1594	return (error);
1595}
1596
1597/*
1598 * nfs file rename rpc called from nfs_remove() above
1599 */
1600static int
1601nfs_renameit(sdvp, scnp, sp)
1602	struct vnode *sdvp;
1603	struct componentname *scnp;
1604	register struct sillyrename *sp;
1605{
1606	return (nfs_renamerpc(sdvp, scnp->cn_nameptr, scnp->cn_namelen,
1607		sdvp, sp->s_name, sp->s_namlen, scnp->cn_cred, scnp->cn_proc));
1608}
1609
1610/*
1611 * Do an nfs rename rpc. Called from nfs_rename() and nfs_renameit().
1612 */
1613static int
1614nfs_renamerpc(fdvp, fnameptr, fnamelen, tdvp, tnameptr, tnamelen, cred, proc)
1615	register struct vnode *fdvp;
1616	char *fnameptr;
1617	int fnamelen;
1618	register struct vnode *tdvp;
1619	char *tnameptr;
1620	int tnamelen;
1621	struct ucred *cred;
1622	struct proc *proc;
1623{
1624	register u_long *tl;
1625	register caddr_t cp;
1626	register long t1, t2;
1627	caddr_t bpos, dpos, cp2;
1628	int error = 0, fwccflag = NFSV3_WCCRATTR, twccflag = NFSV3_WCCRATTR;
1629	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
1630	int v3 = NFS_ISV3(fdvp);
1631
1632	nfsstats.rpccnt[NFSPROC_RENAME]++;
1633	nfsm_reqhead(fdvp, NFSPROC_RENAME,
1634		(NFSX_FH(v3) + NFSX_UNSIGNED)*2 + nfsm_rndup(fnamelen) +
1635		nfsm_rndup(tnamelen));
1636	nfsm_fhtom(fdvp, v3);
1637	nfsm_strtom(fnameptr, fnamelen, NFS_MAXNAMLEN);
1638	nfsm_fhtom(tdvp, v3);
1639	nfsm_strtom(tnameptr, tnamelen, NFS_MAXNAMLEN);
1640	nfsm_request(fdvp, NFSPROC_RENAME, proc, cred);
1641	if (v3) {
1642		nfsm_wcc_data(fdvp, fwccflag);
1643		nfsm_wcc_data(tdvp, twccflag);
1644	}
1645	nfsm_reqdone;
1646	VTONFS(fdvp)->n_flag |= NMODIFIED;
1647	VTONFS(tdvp)->n_flag |= NMODIFIED;
1648	if (!fwccflag)
1649		VTONFS(fdvp)->n_attrstamp = 0;
1650	if (!twccflag)
1651		VTONFS(tdvp)->n_attrstamp = 0;
1652	return (error);
1653}
1654
1655/*
1656 * nfs hard link create call
1657 */
1658static int
1659nfs_link(ap)
1660	struct vop_link_args /* {
1661		struct vnode *a_tdvp;
1662		struct vnode *a_vp;
1663		struct componentname *a_cnp;
1664	} */ *ap;
1665{
1666	register struct vnode *vp = ap->a_vp;
1667	register struct vnode *tdvp = ap->a_tdvp;
1668	register struct componentname *cnp = ap->a_cnp;
1669	register u_long *tl;
1670	register caddr_t cp;
1671	register long t1, t2;
1672	caddr_t bpos, dpos, cp2;
1673	int error = 0, wccflag = NFSV3_WCCRATTR, attrflag = 0;
1674	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
1675	int v3 = NFS_ISV3(vp);
1676
1677	if (vp->v_mount != tdvp->v_mount) {
1678		VOP_ABORTOP(vp, cnp);
1679		return (EXDEV);
1680	}
1681
1682	/*
1683	 * Push all writes to the server, so that the attribute cache
1684	 * doesn't get "out of sync" with the server.
1685	 * XXX There should be a better way!
1686	 */
1687	VOP_FSYNC(vp, cnp->cn_cred, MNT_WAIT, cnp->cn_proc);
1688
1689	nfsstats.rpccnt[NFSPROC_LINK]++;
1690	nfsm_reqhead(vp, NFSPROC_LINK,
1691		NFSX_FH(v3)*2 + NFSX_UNSIGNED + nfsm_rndup(cnp->cn_namelen));
1692	nfsm_fhtom(vp, v3);
1693	nfsm_fhtom(tdvp, v3);
1694	nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
1695	nfsm_request(vp, NFSPROC_LINK, cnp->cn_proc, cnp->cn_cred);
1696	if (v3) {
1697		nfsm_postop_attr(vp, attrflag);
1698		nfsm_wcc_data(tdvp, wccflag);
1699	}
1700	nfsm_reqdone;
1701	zfree(namei_zone, cnp->cn_pnbuf);
1702	VTONFS(tdvp)->n_flag |= NMODIFIED;
1703	if (!attrflag)
1704		VTONFS(vp)->n_attrstamp = 0;
1705	if (!wccflag)
1706		VTONFS(tdvp)->n_attrstamp = 0;
1707	/*
1708	 * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry.
1709	 */
1710	if (error == EEXIST)
1711		error = 0;
1712	return (error);
1713}
1714
1715/*
1716 * nfs symbolic link create call
1717 */
1718static int
1719nfs_symlink(ap)
1720	struct vop_symlink_args /* {
1721		struct vnode *a_dvp;
1722		struct vnode **a_vpp;
1723		struct componentname *a_cnp;
1724		struct vattr *a_vap;
1725		char *a_target;
1726	} */ *ap;
1727{
1728	register struct vnode *dvp = ap->a_dvp;
1729	register struct vattr *vap = ap->a_vap;
1730	register struct componentname *cnp = ap->a_cnp;
1731	register struct nfsv2_sattr *sp;
1732	register struct nfsv3_sattr *sp3;
1733	register u_long *tl;
1734	register caddr_t cp;
1735	register long t1, t2;
1736	caddr_t bpos, dpos, cp2;
1737	int slen, error = 0, wccflag = NFSV3_WCCRATTR, gotvp;
1738	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
1739	struct vnode *newvp = (struct vnode *)0;
1740	int v3 = NFS_ISV3(dvp);
1741
1742	nfsstats.rpccnt[NFSPROC_SYMLINK]++;
1743	slen = strlen(ap->a_target);
1744	nfsm_reqhead(dvp, NFSPROC_SYMLINK, NFSX_FH(v3) + 2*NFSX_UNSIGNED +
1745	    nfsm_rndup(cnp->cn_namelen) + nfsm_rndup(slen) + NFSX_SATTR(v3));
1746	nfsm_fhtom(dvp, v3);
1747	nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
1748	if (v3) {
1749		nfsm_build(sp3, struct nfsv3_sattr *, NFSX_V3SRVSATTR);
1750		nfsm_v3sattr(sp3, vap, cnp->cn_cred->cr_uid,
1751			cnp->cn_cred->cr_gid);
1752	}
1753	nfsm_strtom(ap->a_target, slen, NFS_MAXPATHLEN);
1754	if (!v3) {
1755		nfsm_build(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
1756		sp->sa_mode = vtonfsv2_mode(VLNK, vap->va_mode);
1757		sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid);
1758		sp->sa_gid = txdr_unsigned(cnp->cn_cred->cr_gid);
1759		sp->sa_size = -1;
1760		txdr_nfsv2time(&vap->va_atime, &sp->sa_atime);
1761		txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime);
1762	}
1763	nfsm_request(dvp, NFSPROC_SYMLINK, cnp->cn_proc, cnp->cn_cred);
1764	if (v3) {
1765		if (!error)
1766			nfsm_mtofh(dvp, newvp, v3, gotvp);
1767		nfsm_wcc_data(dvp, wccflag);
1768	}
1769	nfsm_reqdone;
1770	if (newvp)
1771		vput(newvp);
1772	zfree(namei_zone, cnp->cn_pnbuf);
1773	VTONFS(dvp)->n_flag |= NMODIFIED;
1774	if (!wccflag)
1775		VTONFS(dvp)->n_attrstamp = 0;
1776	/*
1777	 * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry.
1778	 */
1779	if (error == EEXIST)
1780		error = 0;
1781	return (error);
1782}
1783
1784/*
1785 * nfs make dir call
1786 */
1787static int
1788nfs_mkdir(ap)
1789	struct vop_mkdir_args /* {
1790		struct vnode *a_dvp;
1791		struct vnode **a_vpp;
1792		struct componentname *a_cnp;
1793		struct vattr *a_vap;
1794	} */ *ap;
1795{
1796	register struct vnode *dvp = ap->a_dvp;
1797	register struct vattr *vap = ap->a_vap;
1798	register struct componentname *cnp = ap->a_cnp;
1799	register struct nfsv2_sattr *sp;
1800	register struct nfsv3_sattr *sp3;
1801	register u_long *tl;
1802	register caddr_t cp;
1803	register long t1, t2;
1804	register int len;
1805	struct nfsnode *np = (struct nfsnode *)0;
1806	struct vnode *newvp = (struct vnode *)0;
1807	caddr_t bpos, dpos, cp2;
1808	int error = 0, wccflag = NFSV3_WCCRATTR;
1809	int gotvp = 0;
1810	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
1811	struct vattr vattr;
1812	int v3 = NFS_ISV3(dvp);
1813
1814	if (error = VOP_GETATTR(dvp, &vattr, cnp->cn_cred, cnp->cn_proc)) {
1815		VOP_ABORTOP(dvp, cnp);
1816		return (error);
1817	}
1818	len = cnp->cn_namelen;
1819	nfsstats.rpccnt[NFSPROC_MKDIR]++;
1820	nfsm_reqhead(dvp, NFSPROC_MKDIR,
1821	  NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(len) + NFSX_SATTR(v3));
1822	nfsm_fhtom(dvp, v3);
1823	nfsm_strtom(cnp->cn_nameptr, len, NFS_MAXNAMLEN);
1824	if (v3) {
1825		nfsm_build(sp3, struct nfsv3_sattr *, NFSX_V3SRVSATTR);
1826		nfsm_v3sattr(sp3, vap, cnp->cn_cred->cr_uid, vattr.va_gid);
1827	} else {
1828		nfsm_build(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
1829		sp->sa_mode = vtonfsv2_mode(VDIR, vap->va_mode);
1830		sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid);
1831		sp->sa_gid = txdr_unsigned(vattr.va_gid);
1832		sp->sa_size = -1;
1833		txdr_nfsv2time(&vap->va_atime, &sp->sa_atime);
1834		txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime);
1835	}
1836	nfsm_request(dvp, NFSPROC_MKDIR, cnp->cn_proc, cnp->cn_cred);
1837	if (!error)
1838		nfsm_mtofh(dvp, newvp, v3, gotvp);
1839	if (v3)
1840		nfsm_wcc_data(dvp, wccflag);
1841	nfsm_reqdone;
1842	VTONFS(dvp)->n_flag |= NMODIFIED;
1843	if (!wccflag)
1844		VTONFS(dvp)->n_attrstamp = 0;
1845	/*
1846	 * Kludge: Map EEXIST => 0 assuming that you have a reply to a retry
1847	 * if we can succeed in looking up the directory.
1848	 */
1849	if (error == EEXIST || (!error && !gotvp)) {
1850		if (newvp) {
1851			vrele(newvp);
1852			newvp = (struct vnode *)0;
1853		}
1854		error = nfs_lookitup(dvp, cnp->cn_nameptr, len, cnp->cn_cred,
1855			cnp->cn_proc, &np);
1856		if (!error) {
1857			newvp = NFSTOV(np);
1858			if (newvp->v_type != VDIR)
1859				error = EEXIST;
1860		}
1861	}
1862	if (error) {
1863		if (newvp)
1864			vrele(newvp);
1865	} else
1866		*ap->a_vpp = newvp;
1867	zfree(namei_zone, cnp->cn_pnbuf);
1868	return (error);
1869}
1870
1871/*
1872 * nfs remove directory call
1873 */
1874static int
1875nfs_rmdir(ap)
1876	struct vop_rmdir_args /* {
1877		struct vnode *a_dvp;
1878		struct vnode *a_vp;
1879		struct componentname *a_cnp;
1880	} */ *ap;
1881{
1882	register struct vnode *vp = ap->a_vp;
1883	register struct vnode *dvp = ap->a_dvp;
1884	register struct componentname *cnp = ap->a_cnp;
1885	register u_long *tl;
1886	register caddr_t cp;
1887	register long t1, t2;
1888	caddr_t bpos, dpos, cp2;
1889	int error = 0, wccflag = NFSV3_WCCRATTR;
1890	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
1891	int v3 = NFS_ISV3(dvp);
1892
1893	nfsstats.rpccnt[NFSPROC_RMDIR]++;
1894	nfsm_reqhead(dvp, NFSPROC_RMDIR,
1895		NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(cnp->cn_namelen));
1896	nfsm_fhtom(dvp, v3);
1897	nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
1898	nfsm_request(dvp, NFSPROC_RMDIR, cnp->cn_proc, cnp->cn_cred);
1899	if (v3)
1900		nfsm_wcc_data(dvp, wccflag);
1901	nfsm_reqdone;
1902	zfree(namei_zone, cnp->cn_pnbuf);
1903	VTONFS(dvp)->n_flag |= NMODIFIED;
1904	if (!wccflag)
1905		VTONFS(dvp)->n_attrstamp = 0;
1906	cache_purge(dvp);
1907	cache_purge(vp);
1908	/*
1909	 * Kludge: Map ENOENT => 0 assuming that you have a reply to a retry.
1910	 */
1911	if (error == ENOENT)
1912		error = 0;
1913	return (error);
1914}
1915
1916/*
1917 * nfs readdir call
1918 */
1919static int
1920nfs_readdir(ap)
1921	struct vop_readdir_args /* {
1922		struct vnode *a_vp;
1923		struct uio *a_uio;
1924		struct ucred *a_cred;
1925	} */ *ap;
1926{
1927	register struct vnode *vp = ap->a_vp;
1928	register struct nfsnode *np = VTONFS(vp);
1929	register struct uio *uio = ap->a_uio;
1930	int tresid, error;
1931	struct vattr vattr;
1932
1933	if (vp->v_type != VDIR)
1934		return (EPERM);
1935	/*
1936	 * First, check for hit on the EOF offset cache
1937	 */
1938	if (np->n_direofoffset > 0 && uio->uio_offset >= np->n_direofoffset &&
1939	    (np->n_flag & NMODIFIED) == 0) {
1940		if (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) {
1941			if (NQNFS_CKCACHABLE(vp, ND_READ)) {
1942				nfsstats.direofcache_hits++;
1943				return (0);
1944			}
1945		} else if (VOP_GETATTR(vp, &vattr, ap->a_cred, uio->uio_procp) == 0 &&
1946			np->n_mtime == vattr.va_mtime.tv_sec) {
1947			nfsstats.direofcache_hits++;
1948			return (0);
1949		}
1950	}
1951
1952	/*
1953	 * Call nfs_bioread() to do the real work.
1954	 */
1955	tresid = uio->uio_resid;
1956	error = nfs_bioread(vp, uio, 0, ap->a_cred, 0);
1957
1958	if (!error && uio->uio_resid == tresid)
1959		nfsstats.direofcache_misses++;
1960	return (error);
1961}
1962
1963/*
1964 * Readdir rpc call.
1965 * Called from below the buffer cache by nfs_doio().
1966 */
1967int
1968nfs_readdirrpc(vp, uiop, cred)
1969	struct vnode *vp;
1970	register struct uio *uiop;
1971	struct ucred *cred;
1972
1973{
1974	register int len, left;
1975	register struct dirent *dp;
1976	register u_long *tl;
1977	register caddr_t cp;
1978	register long t1, t2;
1979	register nfsuint64 *cookiep;
1980	caddr_t bpos, dpos, cp2;
1981	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
1982	nfsuint64 cookie;
1983	struct nfsmount *nmp = VFSTONFS(vp->v_mount);
1984	struct nfsnode *dnp = VTONFS(vp);
1985	u_quad_t fileno;
1986	int error = 0, tlen, more_dirs = 1, blksiz = 0, bigenough = 1;
1987	int attrflag;
1988	int v3 = NFS_ISV3(vp);
1989
1990#ifndef nolint
1991	dp = (struct dirent *)0;
1992#endif
1993#ifndef DIAGNOSTIC
1994	if (uiop->uio_iovcnt != 1 || (uiop->uio_offset & (NFS_DIRBLKSIZ - 1)) ||
1995		(uiop->uio_resid & (NFS_DIRBLKSIZ - 1)))
1996		panic("nfs readdirrpc bad uio");
1997#endif
1998
1999	/*
2000	 * If there is no cookie, assume directory was stale.
2001	 */
2002	cookiep = nfs_getcookie(dnp, uiop->uio_offset, 0);
2003	if (cookiep)
2004		cookie = *cookiep;
2005	else
2006		return (NFSERR_BAD_COOKIE);
2007	/*
2008	 * Loop around doing readdir rpc's of size nm_readdirsize
2009	 * truncated to a multiple of DIRBLKSIZ.
2010	 * The stopping criteria is EOF or buffer full.
2011	 */
2012	while (more_dirs && bigenough) {
2013		nfsstats.rpccnt[NFSPROC_READDIR]++;
2014		nfsm_reqhead(vp, NFSPROC_READDIR, NFSX_FH(v3) +
2015			NFSX_READDIR(v3));
2016		nfsm_fhtom(vp, v3);
2017		if (v3) {
2018			nfsm_build(tl, u_long *, 5 * NFSX_UNSIGNED);
2019			*tl++ = cookie.nfsuquad[0];
2020			*tl++ = cookie.nfsuquad[1];
2021			*tl++ = dnp->n_cookieverf.nfsuquad[0];
2022			*tl++ = dnp->n_cookieverf.nfsuquad[1];
2023		} else {
2024			nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED);
2025			*tl++ = cookie.nfsuquad[0];
2026		}
2027		*tl = txdr_unsigned(nmp->nm_readdirsize);
2028		nfsm_request(vp, NFSPROC_READDIR, uiop->uio_procp, cred);
2029		if (v3) {
2030			nfsm_postop_attr(vp, attrflag);
2031			if (!error) {
2032				nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
2033				dnp->n_cookieverf.nfsuquad[0] = *tl++;
2034				dnp->n_cookieverf.nfsuquad[1] = *tl;
2035			} else {
2036				m_freem(mrep);
2037				goto nfsmout;
2038			}
2039		}
2040		nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
2041		more_dirs = fxdr_unsigned(int, *tl);
2042
2043		/* loop thru the dir entries, doctoring them to 4bsd form */
2044		while (more_dirs && bigenough) {
2045			if (v3) {
2046				nfsm_dissect(tl, u_long *, 3 * NFSX_UNSIGNED);
2047				fxdr_hyper(tl, &fileno);
2048				len = fxdr_unsigned(int, *(tl + 2));
2049			} else {
2050				nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
2051				fileno = fxdr_unsigned(u_quad_t, *tl++);
2052				len = fxdr_unsigned(int, *tl);
2053			}
2054			if (len <= 0 || len > NFS_MAXNAMLEN) {
2055				error = EBADRPC;
2056				m_freem(mrep);
2057				goto nfsmout;
2058			}
2059			tlen = nfsm_rndup(len);
2060			if (tlen == len)
2061				tlen += 4;	/* To ensure null termination */
2062			left = DIRBLKSIZ - blksiz;
2063			if ((tlen + DIRHDSIZ) > left) {
2064				dp->d_reclen += left;
2065				uiop->uio_iov->iov_base += left;
2066				uiop->uio_iov->iov_len -= left;
2067				uiop->uio_offset += left;
2068				uiop->uio_resid -= left;
2069				blksiz = 0;
2070			}
2071			if ((tlen + DIRHDSIZ) > uiop->uio_resid)
2072				bigenough = 0;
2073			if (bigenough) {
2074				dp = (struct dirent *)uiop->uio_iov->iov_base;
2075				dp->d_fileno = (int)fileno;
2076				dp->d_namlen = len;
2077				dp->d_reclen = tlen + DIRHDSIZ;
2078				dp->d_type = DT_UNKNOWN;
2079				blksiz += dp->d_reclen;
2080				if (blksiz == DIRBLKSIZ)
2081					blksiz = 0;
2082				uiop->uio_offset += DIRHDSIZ;
2083				uiop->uio_resid -= DIRHDSIZ;
2084				uiop->uio_iov->iov_base += DIRHDSIZ;
2085				uiop->uio_iov->iov_len -= DIRHDSIZ;
2086				nfsm_mtouio(uiop, len);
2087				cp = uiop->uio_iov->iov_base;
2088				tlen -= len;
2089				*cp = '\0';	/* null terminate */
2090				uiop->uio_iov->iov_base += tlen;
2091				uiop->uio_iov->iov_len -= tlen;
2092				uiop->uio_offset += tlen;
2093				uiop->uio_resid -= tlen;
2094			} else
2095				nfsm_adv(nfsm_rndup(len));
2096			if (v3) {
2097				nfsm_dissect(tl, u_long *, 3 * NFSX_UNSIGNED);
2098			} else {
2099				nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
2100			}
2101			if (bigenough) {
2102				cookie.nfsuquad[0] = *tl++;
2103				if (v3)
2104					cookie.nfsuquad[1] = *tl++;
2105			} else if (v3)
2106				tl += 2;
2107			else
2108				tl++;
2109			more_dirs = fxdr_unsigned(int, *tl);
2110		}
2111		/*
2112		 * If at end of rpc data, get the eof boolean
2113		 */
2114		if (!more_dirs) {
2115			nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
2116			more_dirs = (fxdr_unsigned(int, *tl) == 0);
2117		}
2118		m_freem(mrep);
2119	}
2120	/*
2121	 * Fill last record, iff any, out to a multiple of DIRBLKSIZ
2122	 * by increasing d_reclen for the last record.
2123	 */
2124	if (blksiz > 0) {
2125		left = DIRBLKSIZ - blksiz;
2126		dp->d_reclen += left;
2127		uiop->uio_iov->iov_base += left;
2128		uiop->uio_iov->iov_len -= left;
2129		uiop->uio_offset += left;
2130		uiop->uio_resid -= left;
2131	}
2132
2133	/*
2134	 * We are now either at the end of the directory or have filled the
2135	 * block.
2136	 */
2137	if (bigenough)
2138		dnp->n_direofoffset = uiop->uio_offset;
2139	else {
2140		if (uiop->uio_resid > 0)
2141			printf("EEK! readdirrpc resid > 0\n");
2142		cookiep = nfs_getcookie(dnp, uiop->uio_offset, 1);
2143		*cookiep = cookie;
2144	}
2145nfsmout:
2146	return (error);
2147}
2148
2149/*
2150 * NFS V3 readdir plus RPC. Used in place of nfs_readdirrpc().
2151 */
2152int
2153nfs_readdirplusrpc(vp, uiop, cred)
2154	struct vnode *vp;
2155	register struct uio *uiop;
2156	struct ucred *cred;
2157{
2158	register int len, left;
2159	register struct dirent *dp;
2160	register u_long *tl;
2161	register caddr_t cp;
2162	register long t1, t2;
2163	register struct vnode *newvp;
2164	register nfsuint64 *cookiep;
2165	caddr_t bpos, dpos, cp2, dpossav1, dpossav2;
2166	struct mbuf *mreq, *mrep, *md, *mb, *mb2, *mdsav1, *mdsav2;
2167	struct nameidata nami, *ndp = &nami;
2168	struct componentname *cnp = &ndp->ni_cnd;
2169	nfsuint64 cookie;
2170	struct nfsmount *nmp = VFSTONFS(vp->v_mount);
2171	struct nfsnode *dnp = VTONFS(vp), *np;
2172	nfsfh_t *fhp;
2173	u_quad_t fileno;
2174	int error = 0, tlen, more_dirs = 1, blksiz = 0, doit, bigenough = 1, i;
2175	int attrflag, fhsize;
2176
2177#ifndef nolint
2178	dp = (struct dirent *)0;
2179#endif
2180#ifndef DIAGNOSTIC
2181	if (uiop->uio_iovcnt != 1 || (uiop->uio_offset & (DIRBLKSIZ - 1)) ||
2182		(uiop->uio_resid & (DIRBLKSIZ - 1)))
2183		panic("nfs readdirplusrpc bad uio");
2184#endif
2185	ndp->ni_dvp = vp;
2186	newvp = NULLVP;
2187
2188	/*
2189	 * If there is no cookie, assume directory was stale.
2190	 */
2191	cookiep = nfs_getcookie(dnp, uiop->uio_offset, 0);
2192	if (cookiep)
2193		cookie = *cookiep;
2194	else
2195		return (NFSERR_BAD_COOKIE);
2196	/*
2197	 * Loop around doing readdir rpc's of size nm_readdirsize
2198	 * truncated to a multiple of DIRBLKSIZ.
2199	 * The stopping criteria is EOF or buffer full.
2200	 */
2201	while (more_dirs && bigenough) {
2202		nfsstats.rpccnt[NFSPROC_READDIRPLUS]++;
2203		nfsm_reqhead(vp, NFSPROC_READDIRPLUS,
2204			NFSX_FH(1) + 6 * NFSX_UNSIGNED);
2205		nfsm_fhtom(vp, 1);
2206 		nfsm_build(tl, u_long *, 6 * NFSX_UNSIGNED);
2207		*tl++ = cookie.nfsuquad[0];
2208		*tl++ = cookie.nfsuquad[1];
2209		*tl++ = dnp->n_cookieverf.nfsuquad[0];
2210		*tl++ = dnp->n_cookieverf.nfsuquad[1];
2211		*tl++ = txdr_unsigned(nmp->nm_readdirsize);
2212		*tl = txdr_unsigned(nmp->nm_rsize);
2213		nfsm_request(vp, NFSPROC_READDIRPLUS, uiop->uio_procp, cred);
2214		nfsm_postop_attr(vp, attrflag);
2215		if (error) {
2216			m_freem(mrep);
2217			goto nfsmout;
2218		}
2219		nfsm_dissect(tl, u_long *, 3 * NFSX_UNSIGNED);
2220		dnp->n_cookieverf.nfsuquad[0] = *tl++;
2221		dnp->n_cookieverf.nfsuquad[1] = *tl++;
2222		more_dirs = fxdr_unsigned(int, *tl);
2223
2224		/* loop thru the dir entries, doctoring them to 4bsd form */
2225		while (more_dirs && bigenough) {
2226			nfsm_dissect(tl, u_long *, 3 * NFSX_UNSIGNED);
2227			fxdr_hyper(tl, &fileno);
2228			len = fxdr_unsigned(int, *(tl + 2));
2229			if (len <= 0 || len > NFS_MAXNAMLEN) {
2230				error = EBADRPC;
2231				m_freem(mrep);
2232				goto nfsmout;
2233			}
2234			tlen = nfsm_rndup(len);
2235			if (tlen == len)
2236				tlen += 4;	/* To ensure null termination*/
2237			left = DIRBLKSIZ - blksiz;
2238			if ((tlen + DIRHDSIZ) > left) {
2239				dp->d_reclen += left;
2240				uiop->uio_iov->iov_base += left;
2241				uiop->uio_iov->iov_len -= left;
2242				uiop->uio_offset += left;
2243				uiop->uio_resid -= left;
2244				blksiz = 0;
2245			}
2246			if ((tlen + DIRHDSIZ) > uiop->uio_resid)
2247				bigenough = 0;
2248			if (bigenough) {
2249				dp = (struct dirent *)uiop->uio_iov->iov_base;
2250				dp->d_fileno = (int)fileno;
2251				dp->d_namlen = len;
2252				dp->d_reclen = tlen + DIRHDSIZ;
2253				dp->d_type = DT_UNKNOWN;
2254				blksiz += dp->d_reclen;
2255				if (blksiz == DIRBLKSIZ)
2256					blksiz = 0;
2257				uiop->uio_offset += DIRHDSIZ;
2258				uiop->uio_resid -= DIRHDSIZ;
2259				uiop->uio_iov->iov_base += DIRHDSIZ;
2260				uiop->uio_iov->iov_len -= DIRHDSIZ;
2261				cnp->cn_nameptr = uiop->uio_iov->iov_base;
2262				cnp->cn_namelen = len;
2263				nfsm_mtouio(uiop, len);
2264				cp = uiop->uio_iov->iov_base;
2265				tlen -= len;
2266				*cp = '\0';
2267				uiop->uio_iov->iov_base += tlen;
2268				uiop->uio_iov->iov_len -= tlen;
2269				uiop->uio_offset += tlen;
2270				uiop->uio_resid -= tlen;
2271			} else
2272				nfsm_adv(nfsm_rndup(len));
2273			nfsm_dissect(tl, u_long *, 3 * NFSX_UNSIGNED);
2274			if (bigenough) {
2275				cookie.nfsuquad[0] = *tl++;
2276				cookie.nfsuquad[1] = *tl++;
2277			} else
2278				tl += 2;
2279
2280			/*
2281			 * Since the attributes are before the file handle
2282			 * (sigh), we must skip over the attributes and then
2283			 * come back and get them.
2284			 */
2285			attrflag = fxdr_unsigned(int, *tl);
2286			if (attrflag) {
2287			    dpossav1 = dpos;
2288			    mdsav1 = md;
2289			    nfsm_adv(NFSX_V3FATTR);
2290			    nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
2291			    doit = fxdr_unsigned(int, *tl);
2292			    if (doit) {
2293				nfsm_getfh(fhp, fhsize, 1);
2294				if (NFS_CMPFH(dnp, fhp, fhsize)) {
2295				    VREF(vp);
2296				    newvp = vp;
2297				    np = dnp;
2298				} else {
2299				    if (error = nfs_nget(vp->v_mount, fhp,
2300					fhsize, &np))
2301					doit = 0;
2302				    else
2303					newvp = NFSTOV(np);
2304				}
2305			    }
2306			    if (doit) {
2307				dpossav2 = dpos;
2308				dpos = dpossav1;
2309				mdsav2 = md;
2310				md = mdsav1;
2311				nfsm_loadattr(newvp, (struct vattr *)0);
2312				dpos = dpossav2;
2313				md = mdsav2;
2314				dp->d_type =
2315				    IFTODT(VTTOIF(np->n_vattr.va_type));
2316				ndp->ni_vp = newvp;
2317				cnp->cn_hash = 0;
2318				for (cp = cnp->cn_nameptr, i = 1; i <= len;
2319				    i++, cp++)
2320				    cnp->cn_hash += (unsigned char)*cp * i;
2321			        cache_enter(ndp->ni_dvp, ndp->ni_vp, cnp);
2322			    }
2323			} else {
2324			    /* Just skip over the file handle */
2325			    nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
2326			    i = fxdr_unsigned(int, *tl);
2327			    nfsm_adv(nfsm_rndup(i));
2328			}
2329			if (newvp != NULLVP) {
2330			    vrele(newvp);
2331			    newvp = NULLVP;
2332			}
2333			nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
2334			more_dirs = fxdr_unsigned(int, *tl);
2335		}
2336		/*
2337		 * If at end of rpc data, get the eof boolean
2338		 */
2339		if (!more_dirs) {
2340			nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
2341			more_dirs = (fxdr_unsigned(int, *tl) == 0);
2342		}
2343		m_freem(mrep);
2344	}
2345	/*
2346	 * Fill last record, iff any, out to a multiple of NFS_DIRBLKSIZ
2347	 * by increasing d_reclen for the last record.
2348	 */
2349	if (blksiz > 0) {
2350		left = DIRBLKSIZ - blksiz;
2351		dp->d_reclen += left;
2352		uiop->uio_iov->iov_base += left;
2353		uiop->uio_iov->iov_len -= left;
2354		uiop->uio_offset += left;
2355		uiop->uio_resid -= left;
2356	}
2357
2358	/*
2359	 * We are now either at the end of the directory or have filled the
2360	 * block.
2361	 */
2362	if (bigenough)
2363		dnp->n_direofoffset = uiop->uio_offset;
2364	else {
2365		if (uiop->uio_resid > 0)
2366			printf("EEK! readdirplusrpc resid > 0\n");
2367		cookiep = nfs_getcookie(dnp, uiop->uio_offset, 1);
2368		*cookiep = cookie;
2369	}
2370nfsmout:
2371	if (newvp != NULLVP) {
2372	        if (newvp == vp)
2373			vrele(newvp);
2374		else
2375			vput(newvp);
2376		newvp = NULLVP;
2377	}
2378	return (error);
2379}
2380
2381/*
2382 * Silly rename. To make the NFS filesystem that is stateless look a little
2383 * more like the "ufs" a remove of an active vnode is translated to a rename
2384 * to a funny looking filename that is removed by nfs_inactive on the
2385 * nfsnode. There is the potential for another process on a different client
2386 * to create the same funny name between the nfs_lookitup() fails and the
2387 * nfs_rename() completes, but...
2388 */
2389static int
2390nfs_sillyrename(dvp, vp, cnp)
2391	struct vnode *dvp, *vp;
2392	struct componentname *cnp;
2393{
2394	register struct sillyrename *sp;
2395	struct nfsnode *np;
2396	int error;
2397	short pid;
2398
2399	cache_purge(dvp);
2400	np = VTONFS(vp);
2401#ifndef DIAGNOSTIC
2402	if (vp->v_type == VDIR)
2403		panic("nfs: sillyrename dir");
2404#endif
2405	MALLOC(sp, struct sillyrename *, sizeof (struct sillyrename),
2406		M_NFSREQ, M_WAITOK);
2407	sp->s_cred = crdup(cnp->cn_cred);
2408	sp->s_dvp = dvp;
2409	VREF(dvp);
2410
2411	/* Fudge together a funny name */
2412	pid = cnp->cn_proc->p_pid;
2413	sp->s_namlen = sprintf(sp->s_name, ".nfsA%04x4.4", pid);
2414
2415	/* Try lookitups until we get one that isn't there */
2416	while (nfs_lookitup(dvp, sp->s_name, sp->s_namlen, sp->s_cred,
2417		cnp->cn_proc, (struct nfsnode **)0) == 0) {
2418		sp->s_name[4]++;
2419		if (sp->s_name[4] > 'z') {
2420			error = EINVAL;
2421			goto bad;
2422		}
2423	}
2424	if (error = nfs_renameit(dvp, cnp, sp))
2425		goto bad;
2426	error = nfs_lookitup(dvp, sp->s_name, sp->s_namlen, sp->s_cred,
2427		cnp->cn_proc, &np);
2428	np->n_sillyrename = sp;
2429	return (0);
2430bad:
2431	vrele(sp->s_dvp);
2432	crfree(sp->s_cred);
2433	free((caddr_t)sp, M_NFSREQ);
2434	return (error);
2435}
2436
2437/*
2438 * Look up a file name and optionally either update the file handle or
2439 * allocate an nfsnode, depending on the value of npp.
2440 * npp == NULL	--> just do the lookup
2441 * *npp == NULL --> allocate a new nfsnode and make sure attributes are
2442 *			handled too
2443 * *npp != NULL --> update the file handle in the vnode
2444 */
2445static int
2446nfs_lookitup(dvp, name, len, cred, procp, npp)
2447	register struct vnode *dvp;
2448	char *name;
2449	int len;
2450	struct ucred *cred;
2451	struct proc *procp;
2452	struct nfsnode **npp;
2453{
2454	register u_long *tl;
2455	register caddr_t cp;
2456	register long t1, t2;
2457	struct vnode *newvp = (struct vnode *)0;
2458	struct nfsnode *np, *dnp = VTONFS(dvp);
2459	caddr_t bpos, dpos, cp2;
2460	int error = 0, fhlen, attrflag;
2461	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
2462	nfsfh_t *nfhp;
2463	int v3 = NFS_ISV3(dvp);
2464
2465	nfsstats.rpccnt[NFSPROC_LOOKUP]++;
2466	nfsm_reqhead(dvp, NFSPROC_LOOKUP,
2467		NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(len));
2468	nfsm_fhtom(dvp, v3);
2469	nfsm_strtom(name, len, NFS_MAXNAMLEN);
2470	nfsm_request(dvp, NFSPROC_LOOKUP, procp, cred);
2471	if (npp && !error) {
2472		nfsm_getfh(nfhp, fhlen, v3);
2473		if (*npp) {
2474		    np = *npp;
2475		    if (np->n_fhsize > NFS_SMALLFH && fhlen <= NFS_SMALLFH) {
2476			free((caddr_t)np->n_fhp, M_NFSBIGFH);
2477			np->n_fhp = &np->n_fh;
2478		    } else if (np->n_fhsize <= NFS_SMALLFH && fhlen>NFS_SMALLFH)
2479			np->n_fhp =(nfsfh_t *)malloc(fhlen,M_NFSBIGFH,M_WAITOK);
2480		    bcopy((caddr_t)nfhp, (caddr_t)np->n_fhp, fhlen);
2481		    np->n_fhsize = fhlen;
2482		    newvp = NFSTOV(np);
2483		} else if (NFS_CMPFH(dnp, nfhp, fhlen)) {
2484		    VREF(dvp);
2485		    newvp = dvp;
2486		} else {
2487		    error = nfs_nget(dvp->v_mount, nfhp, fhlen, &np);
2488		    if (error) {
2489			m_freem(mrep);
2490			return (error);
2491		    }
2492		    newvp = NFSTOV(np);
2493		}
2494		if (v3) {
2495			nfsm_postop_attr(newvp, attrflag);
2496			if (!attrflag && *npp == NULL) {
2497				m_freem(mrep);
2498				if (newvp == dvp)
2499					vrele(newvp);
2500				else
2501					vput(newvp);
2502				return (ENOENT);
2503			}
2504		} else
2505			nfsm_loadattr(newvp, (struct vattr *)0);
2506	}
2507	nfsm_reqdone;
2508	if (npp && *npp == NULL) {
2509		if (error) {
2510			if (newvp)
2511				if (newvp == dvp)
2512					vrele(newvp);
2513				else
2514					vput(newvp);
2515		} else
2516			*npp = np;
2517	}
2518	return (error);
2519}
2520
2521/*
2522 * Nfs Version 3 commit rpc
2523 */
2524static int
2525nfs_commit(vp, offset, cnt, cred, procp)
2526	register struct vnode *vp;
2527	u_quad_t offset;
2528	int cnt;
2529	struct ucred *cred;
2530	struct proc *procp;
2531{
2532	register caddr_t cp;
2533	register u_long *tl;
2534	register int t1, t2;
2535	register struct nfsmount *nmp = VFSTONFS(vp->v_mount);
2536	caddr_t bpos, dpos, cp2;
2537	int error = 0, wccflag = NFSV3_WCCRATTR;
2538	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
2539
2540	if ((nmp->nm_flag & NFSMNT_HASWRITEVERF) == 0)
2541		return (0);
2542	nfsstats.rpccnt[NFSPROC_COMMIT]++;
2543	nfsm_reqhead(vp, NFSPROC_COMMIT, NFSX_FH(1));
2544	nfsm_fhtom(vp, 1);
2545	nfsm_build(tl, u_long *, 3 * NFSX_UNSIGNED);
2546	txdr_hyper(&offset, tl);
2547	tl += 2;
2548	*tl = txdr_unsigned(cnt);
2549	nfsm_request(vp, NFSPROC_COMMIT, procp, cred);
2550	nfsm_wcc_data(vp, wccflag);
2551	if (!error) {
2552		nfsm_dissect(tl, u_long *, NFSX_V3WRITEVERF);
2553		if (bcmp((caddr_t)nmp->nm_verf, (caddr_t)tl,
2554			NFSX_V3WRITEVERF)) {
2555			bcopy((caddr_t)tl, (caddr_t)nmp->nm_verf,
2556				NFSX_V3WRITEVERF);
2557			error = NFSERR_STALEWRITEVERF;
2558		}
2559	}
2560	nfsm_reqdone;
2561	return (error);
2562}
2563
2564/*
2565 * Kludge City..
2566 * - make nfs_bmap() essentially a no-op that does no translation
2567 * - do nfs_strategy() by doing I/O with nfs_readrpc/nfs_writerpc
2568 *   (Maybe I could use the process's page mapping, but I was concerned that
2569 *    Kernel Write might not be enabled and also figured copyout() would do
2570 *    a lot more work than bcopy() and also it currently happens in the
2571 *    context of the swapper process (2).
2572 */
2573static int
2574nfs_bmap(ap)
2575	struct vop_bmap_args /* {
2576		struct vnode *a_vp;
2577		daddr_t  a_bn;
2578		struct vnode **a_vpp;
2579		daddr_t *a_bnp;
2580		int *a_runp;
2581		int *a_runb;
2582	} */ *ap;
2583{
2584	register struct vnode *vp = ap->a_vp;
2585
2586	if (ap->a_vpp != NULL)
2587		*ap->a_vpp = vp;
2588	if (ap->a_bnp != NULL)
2589		*ap->a_bnp = ap->a_bn * btodb(vp->v_mount->mnt_stat.f_iosize);
2590	if (ap->a_runp != NULL)
2591		*ap->a_runp = 0;
2592	if (ap->a_runb != NULL)
2593		*ap->a_runb = 0;
2594	return (0);
2595}
2596
2597/*
2598 * Strategy routine.
2599 * For async requests when nfsiod(s) are running, queue the request by
2600 * calling nfs_asyncio(), otherwise just all nfs_doio() to do the
2601 * request.
2602 */
2603static int
2604nfs_strategy(ap)
2605	struct vop_strategy_args *ap;
2606{
2607	register struct buf *bp = ap->a_bp;
2608	struct ucred *cr;
2609	struct proc *p;
2610	int error = 0;
2611
2612	if (bp->b_flags & B_PHYS)
2613		panic("nfs physio");
2614	if (bp->b_flags & B_ASYNC)
2615		p = (struct proc *)0;
2616	else
2617		p = curproc;	/* XXX */
2618	if (bp->b_flags & B_READ)
2619		cr = bp->b_rcred;
2620	else
2621		cr = bp->b_wcred;
2622	/*
2623	 * If the op is asynchronous and an i/o daemon is waiting
2624	 * queue the request, wake it up and wait for completion
2625	 * otherwise just do it ourselves.
2626	 */
2627	if ((bp->b_flags & B_ASYNC) == 0 ||
2628		nfs_asyncio(bp, NOCRED))
2629		error = nfs_doio(bp, cr, p);
2630	return (error);
2631}
2632
2633/*
2634 * Mmap a file
2635 *
2636 * NB Currently unsupported.
2637 */
2638/* ARGSUSED */
2639static int
2640nfs_mmap(ap)
2641	struct vop_mmap_args /* {
2642		struct vnode *a_vp;
2643		int  a_fflags;
2644		struct ucred *a_cred;
2645		struct proc *a_p;
2646	} */ *ap;
2647{
2648
2649	return (EINVAL);
2650}
2651
2652/*
2653 * fsync vnode op. Just call nfs_flush() with commit == 1.
2654 */
2655/* ARGSUSED */
2656static int
2657nfs_fsync(ap)
2658	struct vop_fsync_args /* {
2659		struct vnodeop_desc *a_desc;
2660		struct vnode * a_vp;
2661		struct ucred * a_cred;
2662		int  a_waitfor;
2663		struct proc * a_p;
2664	} */ *ap;
2665{
2666
2667	return (nfs_flush(ap->a_vp, ap->a_cred, ap->a_waitfor, ap->a_p, 1));
2668}
2669
2670/*
2671 * Flush all the blocks associated with a vnode.
2672 * 	Walk through the buffer pool and push any dirty pages
2673 *	associated with the vnode.
2674 */
2675static int
2676nfs_flush(vp, cred, waitfor, p, commit)
2677	register struct vnode *vp;
2678	struct ucred *cred;
2679	int waitfor;
2680	struct proc *p;
2681	int commit;
2682{
2683	register struct nfsnode *np = VTONFS(vp);
2684	register struct buf *bp;
2685	register int i;
2686	struct buf *nbp;
2687	struct nfsmount *nmp = VFSTONFS(vp->v_mount);
2688	int s, error = 0, slptimeo = 0, slpflag = 0, retv, bvecpos;
2689	int passone = 1;
2690	u_quad_t off, endoff, toff;
2691	struct ucred* wcred = NULL;
2692	struct buf **bvec = NULL;
2693#ifndef NFS_COMMITBVECSIZ
2694#define NFS_COMMITBVECSIZ	20
2695#endif
2696	struct buf *bvec_on_stack[NFS_COMMITBVECSIZ];
2697	int bvecsize = 0, bveccount;
2698
2699	if (nmp->nm_flag & NFSMNT_INT)
2700		slpflag = PCATCH;
2701	if (!commit)
2702		passone = 0;
2703	/*
2704	 * A b_flags == (B_DELWRI | B_NEEDCOMMIT) block has been written to the
2705	 * server, but nas not been committed to stable storage on the server
2706	 * yet. On the first pass, the byte range is worked out and the commit
2707	 * rpc is done. On the second pass, nfs_writebp() is called to do the
2708	 * job.
2709	 */
2710again:
2711	off = (u_quad_t)-1;
2712	endoff = 0;
2713	bvecpos = 0;
2714	if (NFS_ISV3(vp) && commit) {
2715		s = splbio();
2716		/*
2717		 * Count up how many buffers waiting for a commit.
2718		 */
2719		bveccount = 0;
2720		for (bp = vp->v_dirtyblkhd.lh_first; bp; bp = nbp) {
2721			nbp = bp->b_vnbufs.le_next;
2722			if ((bp->b_flags & (B_BUSY | B_DELWRI | B_NEEDCOMMIT))
2723			    == (B_DELWRI | B_NEEDCOMMIT))
2724				bveccount++;
2725		}
2726		/*
2727		 * Allocate space to remember the list of bufs to commit.  It is
2728		 * important to use M_NOWAIT here to avoid a race with nfs_write.
2729		 * If we can't get memory (for whatever reason), we will end up
2730		 * committing the buffers one-by-one in the loop below.
2731		 */
2732		if (bveccount > NFS_COMMITBVECSIZ) {
2733			if (bvec != NULL && bvec != bvec_on_stack)
2734				free(bvec, M_TEMP);
2735			bvec = (struct buf **)
2736				malloc(bveccount * sizeof(struct buf *),
2737				       M_TEMP, M_NOWAIT);
2738			if (bvec == NULL) {
2739				bvec = bvec_on_stack;
2740				bvecsize = NFS_COMMITBVECSIZ;
2741			} else
2742				bvecsize = bveccount;
2743		} else {
2744			bvec = bvec_on_stack;
2745			bvecsize = NFS_COMMITBVECSIZ;
2746		}
2747		for (bp = vp->v_dirtyblkhd.lh_first; bp; bp = nbp) {
2748			nbp = bp->b_vnbufs.le_next;
2749			if (bvecpos >= bvecsize)
2750				break;
2751			if ((bp->b_flags & (B_BUSY | B_DELWRI | B_NEEDCOMMIT))
2752				!= (B_DELWRI | B_NEEDCOMMIT))
2753				continue;
2754			bremfree(bp);
2755			/*
2756			 * Work out if all buffers are using the same cred
2757			 * so we can deal with them all with one commit.
2758			 */
2759			if (wcred == NULL)
2760				wcred = bp->b_wcred;
2761			else if (wcred != bp->b_wcred)
2762				wcred = NOCRED;
2763			bp->b_flags |= (B_BUSY | B_WRITEINPROG);
2764			vfs_busy_pages(bp, 1);
2765			/*
2766			 * A list of these buffers is kept so that the
2767			 * second loop knows which buffers have actually
2768			 * been committed. This is necessary, since there
2769			 * may be a race between the commit rpc and new
2770			 * uncommitted writes on the file.
2771			 */
2772			bvec[bvecpos++] = bp;
2773			toff = ((u_quad_t)bp->b_blkno) * DEV_BSIZE +
2774				bp->b_dirtyoff;
2775			if (toff < off)
2776				off = toff;
2777			toff += (u_quad_t)(bp->b_dirtyend - bp->b_dirtyoff);
2778			if (toff > endoff)
2779				endoff = toff;
2780		}
2781		splx(s);
2782	}
2783	if (bvecpos > 0) {
2784		/*
2785		 * Commit data on the server, as required.
2786		 * If all bufs are using the same wcred, then use that with
2787		 * one call for all of them, otherwise commit each one
2788		 * separately.
2789		 */
2790		if (wcred != NOCRED)
2791			retv = nfs_commit(vp, off, (int)(endoff - off),
2792					  wcred, p);
2793		else {
2794			retv = 0;
2795			for (i = 0; i < bvecpos; i++) {
2796				off_t off, size;
2797				bp = bvec[i];
2798				off = ((u_quad_t)bp->b_blkno) * DEV_BSIZE +
2799					bp->b_dirtyoff;
2800				size = (u_quad_t)(bp->b_dirtyend
2801						  - bp->b_dirtyoff);
2802				retv = nfs_commit(vp, off, (int)size,
2803						  bp->b_wcred, p);
2804				if (retv) break;
2805			}
2806		}
2807
2808		if (retv == NFSERR_STALEWRITEVERF)
2809			nfs_clearcommit(vp->v_mount);
2810		/*
2811		 * Now, either mark the blocks I/O done or mark the
2812		 * blocks dirty, depending on whether the commit
2813		 * succeeded.
2814		 */
2815		for (i = 0; i < bvecpos; i++) {
2816			bp = bvec[i];
2817			bp->b_flags &= ~(B_NEEDCOMMIT | B_WRITEINPROG);
2818			if (retv) {
2819			    vfs_unbusy_pages(bp);
2820			    brelse(bp);
2821			} else {
2822			    vp->v_numoutput++;
2823			    bp->b_flags |= B_ASYNC;
2824			    if (bp->b_flags & B_DELWRI) {
2825				--numdirtybuffers;
2826			    	if (needsbuffer) {
2827					vfs_bio_need_satisfy();
2828				}
2829			    }
2830			    s = splbio();	/* XXX check this positionning */
2831			    bp->b_flags &= ~(B_READ|B_DONE|B_ERROR|B_DELWRI);
2832			    bp->b_dirtyoff = bp->b_dirtyend = 0;
2833			    reassignbuf(bp, vp);
2834			    splx(s);
2835			    biodone(bp);
2836			}
2837		}
2838	}
2839
2840	/*
2841	 * Start/do any write(s) that are required.
2842	 */
2843loop:
2844	s = splbio();
2845	for (bp = vp->v_dirtyblkhd.lh_first; bp; bp = nbp) {
2846		nbp = bp->b_vnbufs.le_next;
2847		if (bp->b_flags & B_BUSY) {
2848			if (waitfor != MNT_WAIT || passone)
2849				continue;
2850			bp->b_flags |= B_WANTED;
2851			error = tsleep((caddr_t)bp, slpflag | (PRIBIO + 1),
2852				"nfsfsync", slptimeo);
2853			splx(s);
2854			if (error) {
2855			    if (nfs_sigintr(nmp, (struct nfsreq *)0, p)) {
2856				error = EINTR;
2857				goto done;
2858			    }
2859			    if (slpflag == PCATCH) {
2860				slpflag = 0;
2861				slptimeo = 2 * hz;
2862			    }
2863			}
2864			goto loop;
2865		}
2866		if ((bp->b_flags & B_DELWRI) == 0)
2867			panic("nfs_fsync: not dirty");
2868		if ((passone || !commit) && (bp->b_flags & B_NEEDCOMMIT))
2869			continue;
2870		bremfree(bp);
2871		if (passone || !commit)
2872		    bp->b_flags |= (B_BUSY|B_ASYNC);
2873		else
2874		    bp->b_flags |= (B_BUSY|B_ASYNC|B_WRITEINPROG|B_NEEDCOMMIT);
2875		splx(s);
2876		VOP_BWRITE(bp);
2877		goto loop;
2878	}
2879	splx(s);
2880	if (passone) {
2881		passone = 0;
2882		goto again;
2883	}
2884	if (waitfor == MNT_WAIT) {
2885		while (vp->v_numoutput) {
2886			vp->v_flag |= VBWAIT;
2887			error = tsleep((caddr_t)&vp->v_numoutput,
2888				slpflag | (PRIBIO + 1), "nfsfsync", slptimeo);
2889			if (error) {
2890			    if (nfs_sigintr(nmp, (struct nfsreq *)0, p)) {
2891				error = EINTR;
2892				goto done;
2893			    }
2894			    if (slpflag == PCATCH) {
2895				slpflag = 0;
2896				slptimeo = 2 * hz;
2897			    }
2898			}
2899		}
2900		if (vp->v_dirtyblkhd.lh_first && commit) {
2901			goto loop;
2902		}
2903	}
2904	if (np->n_flag & NWRITEERR) {
2905		error = np->n_error;
2906		np->n_flag &= ~NWRITEERR;
2907	}
2908done:
2909	if (bvec != NULL && bvec != bvec_on_stack)
2910		free(bvec, M_TEMP);
2911	return (error);
2912}
2913
2914/*
2915 * NFS advisory byte-level locks.
2916 * Currently unsupported.
2917 */
2918static int
2919nfs_advlock(ap)
2920	struct vop_advlock_args /* {
2921		struct vnode *a_vp;
2922		caddr_t  a_id;
2923		int  a_op;
2924		struct flock *a_fl;
2925		int  a_flags;
2926	} */ *ap;
2927{
2928	register struct nfsnode *np = VTONFS(ap->a_vp);
2929
2930	/*
2931	 * The following kludge is to allow diskless support to work
2932	 * until a real NFS lockd is implemented. Basically, just pretend
2933	 * that this is a local lock.
2934	 */
2935	return (lf_advlock(ap, &(np->n_lockf), np->n_size));
2936}
2937
2938/*
2939 * Print out the contents of an nfsnode.
2940 */
2941static int
2942nfs_print(ap)
2943	struct vop_print_args /* {
2944		struct vnode *a_vp;
2945	} */ *ap;
2946{
2947	register struct vnode *vp = ap->a_vp;
2948	register struct nfsnode *np = VTONFS(vp);
2949
2950	printf("tag VT_NFS, fileid %ld fsid 0x%lx",
2951		np->n_vattr.va_fileid, np->n_vattr.va_fsid);
2952	if (vp->v_type == VFIFO)
2953		fifo_printinfo(vp);
2954	printf("\n");
2955	return (0);
2956}
2957
2958/*
2959 * Just call nfs_writebp() with the force argument set to 1.
2960 */
2961static int
2962nfs_bwrite(ap)
2963	struct vop_bwrite_args /* {
2964		struct vnode *a_bp;
2965	} */ *ap;
2966{
2967
2968	return (nfs_writebp(ap->a_bp, 1));
2969}
2970
2971/*
2972 * This is a clone of vn_bwrite(), except that B_WRITEINPROG isn't set unless
2973 * the force flag is one and it also handles the B_NEEDCOMMIT flag.
2974 */
2975int
2976nfs_writebp(bp, force)
2977	register struct buf *bp;
2978	int force;
2979{
2980	int s;
2981	register int oldflags = bp->b_flags, retv = 1;
2982	off_t off;
2983
2984	if(!(bp->b_flags & B_BUSY))
2985		panic("bwrite: buffer is not busy???");
2986
2987	if (bp->b_flags & B_INVAL)
2988		bp->b_flags |= B_INVAL | B_NOCACHE;
2989
2990	if (bp->b_flags & B_DELWRI) {
2991		--numdirtybuffers;
2992		if (needsbuffer)
2993			vfs_bio_need_satisfy();
2994	}
2995	s = splbio(); /* XXX check if needed */
2996	bp->b_flags &= ~(B_READ|B_DONE|B_ERROR|B_DELWRI);
2997
2998	if ((oldflags & (B_ASYNC|B_DELWRI)) == (B_ASYNC|B_DELWRI)) {
2999		reassignbuf(bp, bp->b_vp);
3000	}
3001
3002	bp->b_vp->v_numoutput++;
3003	curproc->p_stats->p_ru.ru_oublock++;
3004	splx(s);
3005
3006	/*
3007	 * If B_NEEDCOMMIT is set, a commit rpc may do the trick. If not
3008	 * an actual write will have to be scheduled via. VOP_STRATEGY().
3009	 * If B_WRITEINPROG is already set, then push it with a write anyhow.
3010	 */
3011	vfs_busy_pages(bp, 1);
3012	if ((oldflags & (B_NEEDCOMMIT | B_WRITEINPROG)) == B_NEEDCOMMIT) {
3013		off = ((u_quad_t)bp->b_blkno) * DEV_BSIZE + bp->b_dirtyoff;
3014		bp->b_flags |= B_WRITEINPROG;
3015		retv = nfs_commit(bp->b_vp, off, bp->b_dirtyend-bp->b_dirtyoff,
3016			bp->b_wcred, bp->b_proc);
3017		bp->b_flags &= ~B_WRITEINPROG;
3018		if (!retv) {
3019			bp->b_dirtyoff = bp->b_dirtyend = 0;
3020			bp->b_flags &= ~B_NEEDCOMMIT;
3021			biodone(bp);
3022		} else if (retv == NFSERR_STALEWRITEVERF)
3023			nfs_clearcommit(bp->b_vp->v_mount);
3024	}
3025	if (retv) {
3026		if (force)
3027			bp->b_flags |= B_WRITEINPROG;
3028		VOP_STRATEGY(bp);
3029	}
3030
3031	if( (oldflags & B_ASYNC) == 0) {
3032		int rtval = biowait(bp);
3033
3034		if (oldflags & B_DELWRI) {
3035			s = splbio();
3036			reassignbuf(bp, bp->b_vp);
3037			splx(s);
3038		}
3039
3040		brelse(bp);
3041		return (rtval);
3042	}
3043
3044	return (0);
3045}
3046
3047/*
3048 * nfs special file access vnode op.
3049 * Essentially just get vattr and then imitate iaccess() since the device is
3050 * local to the client.
3051 */
3052static int
3053nfsspec_access(ap)
3054	struct vop_access_args /* {
3055		struct vnode *a_vp;
3056		int  a_mode;
3057		struct ucred *a_cred;
3058		struct proc *a_p;
3059	} */ *ap;
3060{
3061	register struct vattr *vap;
3062	register gid_t *gp;
3063	register struct ucred *cred = ap->a_cred;
3064	struct vnode *vp = ap->a_vp;
3065	mode_t mode = ap->a_mode;
3066	struct vattr vattr;
3067	register int i;
3068	int error;
3069
3070	/*
3071	 * Disallow write attempts on filesystems mounted read-only;
3072	 * unless the file is a socket, fifo, or a block or character
3073	 * device resident on the filesystem.
3074	 */
3075	if ((mode & VWRITE) && (vp->v_mount->mnt_flag & MNT_RDONLY)) {
3076		switch (vp->v_type) {
3077		case VREG: case VDIR: case VLNK:
3078			return (EROFS);
3079		}
3080	}
3081	/*
3082	 * If you're the super-user,
3083	 * you always get access.
3084	 */
3085	if (cred->cr_uid == 0)
3086		return (0);
3087	vap = &vattr;
3088	error = VOP_GETATTR(vp, vap, cred, ap->a_p);
3089	if (error)
3090		return (error);
3091	/*
3092	 * Access check is based on only one of owner, group, public.
3093	 * If not owner, then check group. If not a member of the
3094	 * group, then check public access.
3095	 */
3096	if (cred->cr_uid != vap->va_uid) {
3097		mode >>= 3;
3098		gp = cred->cr_groups;
3099		for (i = 0; i < cred->cr_ngroups; i++, gp++)
3100			if (vap->va_gid == *gp)
3101				goto found;
3102		mode >>= 3;
3103found:
3104		;
3105	}
3106	error = (vap->va_mode & mode) == mode ? 0 : EACCES;
3107	return (error);
3108}
3109
3110/*
3111 * Read wrapper for special devices.
3112 */
3113static int
3114nfsspec_read(ap)
3115	struct vop_read_args /* {
3116		struct vnode *a_vp;
3117		struct uio *a_uio;
3118		int  a_ioflag;
3119		struct ucred *a_cred;
3120	} */ *ap;
3121{
3122	register struct nfsnode *np = VTONFS(ap->a_vp);
3123	struct timeval tv;
3124
3125	/*
3126	 * Set access flag.
3127	 */
3128	np->n_flag |= NACC;
3129	getmicrotime(&tv);
3130	np->n_atim.tv_sec = tv.tv_sec;
3131	np->n_atim.tv_nsec = tv.tv_usec * 1000;
3132	return (VOCALL(spec_vnodeop_p, VOFFSET(vop_read), ap));
3133}
3134
3135/*
3136 * Write wrapper for special devices.
3137 */
3138static int
3139nfsspec_write(ap)
3140	struct vop_write_args /* {
3141		struct vnode *a_vp;
3142		struct uio *a_uio;
3143		int  a_ioflag;
3144		struct ucred *a_cred;
3145	} */ *ap;
3146{
3147	register struct nfsnode *np = VTONFS(ap->a_vp);
3148	struct timeval tv;
3149
3150	/*
3151	 * Set update flag.
3152	 */
3153	np->n_flag |= NUPD;
3154	getmicrotime(&tv);
3155	np->n_mtim.tv_sec = tv.tv_sec;
3156	np->n_mtim.tv_nsec = tv.tv_usec * 1000;
3157	return (VOCALL(spec_vnodeop_p, VOFFSET(vop_write), ap));
3158}
3159
3160/*
3161 * Close wrapper for special devices.
3162 *
3163 * Update the times on the nfsnode then do device close.
3164 */
3165static int
3166nfsspec_close(ap)
3167	struct vop_close_args /* {
3168		struct vnode *a_vp;
3169		int  a_fflag;
3170		struct ucred *a_cred;
3171		struct proc *a_p;
3172	} */ *ap;
3173{
3174	register struct vnode *vp = ap->a_vp;
3175	register struct nfsnode *np = VTONFS(vp);
3176	struct vattr vattr;
3177
3178	if (np->n_flag & (NACC | NUPD)) {
3179		np->n_flag |= NCHG;
3180		if (vp->v_usecount == 1 &&
3181		    (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) {
3182			VATTR_NULL(&vattr);
3183			if (np->n_flag & NACC)
3184				vattr.va_atime = np->n_atim;
3185			if (np->n_flag & NUPD)
3186				vattr.va_mtime = np->n_mtim;
3187			(void)VOP_SETATTR(vp, &vattr, ap->a_cred, ap->a_p);
3188		}
3189	}
3190	return (VOCALL(spec_vnodeop_p, VOFFSET(vop_close), ap));
3191}
3192
3193/*
3194 * Read wrapper for fifos.
3195 */
3196static int
3197nfsfifo_read(ap)
3198	struct vop_read_args /* {
3199		struct vnode *a_vp;
3200		struct uio *a_uio;
3201		int  a_ioflag;
3202		struct ucred *a_cred;
3203	} */ *ap;
3204{
3205	register struct nfsnode *np = VTONFS(ap->a_vp);
3206	struct timeval tv;
3207
3208	/*
3209	 * Set access flag.
3210	 */
3211	np->n_flag |= NACC;
3212	getmicrotime(&tv);
3213	np->n_atim.tv_sec = tv.tv_sec;
3214	np->n_atim.tv_nsec = tv.tv_usec * 1000;
3215	return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_read), ap));
3216}
3217
3218/*
3219 * Write wrapper for fifos.
3220 */
3221static int
3222nfsfifo_write(ap)
3223	struct vop_write_args /* {
3224		struct vnode *a_vp;
3225		struct uio *a_uio;
3226		int  a_ioflag;
3227		struct ucred *a_cred;
3228	} */ *ap;
3229{
3230	register struct nfsnode *np = VTONFS(ap->a_vp);
3231	struct timeval tv;
3232
3233	/*
3234	 * Set update flag.
3235	 */
3236	np->n_flag |= NUPD;
3237	getmicrotime(&tv);
3238	np->n_mtim.tv_sec = tv.tv_sec;
3239	np->n_mtim.tv_nsec = tv.tv_usec * 1000;
3240	return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_write), ap));
3241}
3242
3243/*
3244 * Close wrapper for fifos.
3245 *
3246 * Update the times on the nfsnode then do fifo close.
3247 */
3248static int
3249nfsfifo_close(ap)
3250	struct vop_close_args /* {
3251		struct vnode *a_vp;
3252		int  a_fflag;
3253		struct ucred *a_cred;
3254		struct proc *a_p;
3255	} */ *ap;
3256{
3257	register struct vnode *vp = ap->a_vp;
3258	register struct nfsnode *np = VTONFS(vp);
3259	struct timeval tv;
3260	struct vattr vattr;
3261
3262	if (np->n_flag & (NACC | NUPD)) {
3263		getmicrotime(&tv);
3264		if (np->n_flag & NACC) {
3265			np->n_atim.tv_sec = tv.tv_sec;
3266			np->n_atim.tv_nsec = tv.tv_usec * 1000;
3267		}
3268		if (np->n_flag & NUPD) {
3269			np->n_mtim.tv_sec = tv.tv_sec;
3270			np->n_mtim.tv_nsec = tv.tv_usec * 1000;
3271		}
3272		np->n_flag |= NCHG;
3273		if (vp->v_usecount == 1 &&
3274		    (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) {
3275			VATTR_NULL(&vattr);
3276			if (np->n_flag & NACC)
3277				vattr.va_atime = np->n_atim;
3278			if (np->n_flag & NUPD)
3279				vattr.va_mtime = np->n_mtim;
3280			(void)VOP_SETATTR(vp, &vattr, ap->a_cred, ap->a_p);
3281		}
3282	}
3283	return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_close), ap));
3284}
3285