xref: /csrg-svn/sys/nfs/nfs_vnops.c (revision 56364)
138414Smckusick /*
238414Smckusick  * Copyright (c) 1989 The Regents of the University of California.
338414Smckusick  * All rights reserved.
438414Smckusick  *
538414Smckusick  * This code is derived from software contributed to Berkeley by
638414Smckusick  * Rick Macklem at The University of Guelph.
738414Smckusick  *
844514Sbostic  * %sccs.include.redist.c%
938414Smckusick  *
10*56364Smckusick  *	@(#)nfs_vnops.c	7.93 (Berkeley) 09/30/92
1138414Smckusick  */
1238414Smckusick 
1338414Smckusick /*
1438414Smckusick  * vnode op calls for sun nfs version 2
1538414Smckusick  */
1638414Smckusick 
1753322Smckusick #include <sys/param.h>
1853322Smckusick #include <sys/proc.h>
1953322Smckusick #include <sys/kernel.h>
2053322Smckusick #include <sys/systm.h>
2153322Smckusick #include <sys/mount.h>
2253322Smckusick #include <sys/buf.h>
2353322Smckusick #include <sys/malloc.h>
2453322Smckusick #include <sys/mbuf.h>
2553322Smckusick #include <sys/conf.h>
2653322Smckusick #include <sys/namei.h>
2753322Smckusick #include <sys/vnode.h>
2853322Smckusick #include <sys/map.h>
2954740Smckusick #include <sys/dirent.h>
3047573Skarels 
3153322Smckusick #include <vm/vm.h>
3238414Smckusick 
3355041Smckusick #include <miscfs/specfs/specdev.h>
3455041Smckusick #include <miscfs/fifofs/fifo.h>
3555041Smckusick 
3653322Smckusick #include <nfs/rpcv2.h>
3753322Smckusick #include <nfs/nfsv2.h>
3853322Smckusick #include <nfs/nfs.h>
3953322Smckusick #include <nfs/nfsnode.h>
4053322Smckusick #include <nfs/nfsmount.h>
4153322Smckusick #include <nfs/xdr_subs.h>
4253322Smckusick #include <nfs/nfsm_subs.h>
4353322Smckusick #include <nfs/nqnfs.h>
4453322Smckusick 
4538414Smckusick /* Defs */
4638414Smckusick #define	TRUE	1
4738414Smckusick #define	FALSE	0
4838414Smckusick 
4948054Smckusick /*
5048054Smckusick  * Global vfs data structures for nfs
5148054Smckusick  */
5253554Sheideman int (**nfsv2_vnodeop_p)();
5353554Sheideman struct vnodeopv_entry_desc nfsv2_vnodeop_entries[] = {
5453554Sheideman 	{ &vop_default_desc, vn_default_error },
5553806Smckusick 	{ &vop_lookup_desc, nfs_lookup },	/* lookup */
5653806Smckusick 	{ &vop_create_desc, nfs_create },	/* create */
5753554Sheideman 	{ &vop_mknod_desc, nfs_mknod },		/* mknod */
5853554Sheideman 	{ &vop_open_desc, nfs_open },		/* open */
5953554Sheideman 	{ &vop_close_desc, nfs_close },		/* close */
6053806Smckusick 	{ &vop_access_desc, nfs_access },	/* access */
6153806Smckusick 	{ &vop_getattr_desc, nfs_getattr },	/* getattr */
6253806Smckusick 	{ &vop_setattr_desc, nfs_setattr },	/* setattr */
6353554Sheideman 	{ &vop_read_desc, nfs_read },		/* read */
6453554Sheideman 	{ &vop_write_desc, nfs_write },		/* write */
6553554Sheideman 	{ &vop_ioctl_desc, nfs_ioctl },		/* ioctl */
6653806Smckusick 	{ &vop_select_desc, nfs_select },	/* select */
6753554Sheideman 	{ &vop_mmap_desc, nfs_mmap },		/* mmap */
6853554Sheideman 	{ &vop_fsync_desc, nfs_fsync },		/* fsync */
6953554Sheideman 	{ &vop_seek_desc, nfs_seek },		/* seek */
7053806Smckusick 	{ &vop_remove_desc, nfs_remove },	/* remove */
7153554Sheideman 	{ &vop_link_desc, nfs_link },		/* link */
7253806Smckusick 	{ &vop_rename_desc, nfs_rename },	/* rename */
7353554Sheideman 	{ &vop_mkdir_desc, nfs_mkdir },		/* mkdir */
7453554Sheideman 	{ &vop_rmdir_desc, nfs_rmdir },		/* rmdir */
7553806Smckusick 	{ &vop_symlink_desc, nfs_symlink },	/* symlink */
7653806Smckusick 	{ &vop_readdir_desc, nfs_readdir },	/* readdir */
7753806Smckusick 	{ &vop_readlink_desc, nfs_readlink },	/* readlink */
7853806Smckusick 	{ &vop_abortop_desc, nfs_abortop },	/* abortop */
7953806Smckusick 	{ &vop_inactive_desc, nfs_inactive },	/* inactive */
8053806Smckusick 	{ &vop_reclaim_desc, nfs_reclaim },	/* reclaim */
8153554Sheideman 	{ &vop_lock_desc, nfs_lock },		/* lock */
8253806Smckusick 	{ &vop_unlock_desc, nfs_unlock },	/* unlock */
8353554Sheideman 	{ &vop_bmap_desc, nfs_bmap },		/* bmap */
8453806Smckusick 	{ &vop_strategy_desc, nfs_strategy },	/* strategy */
8553554Sheideman 	{ &vop_print_desc, nfs_print },		/* print */
8653806Smckusick 	{ &vop_islocked_desc, nfs_islocked },	/* islocked */
8753806Smckusick 	{ &vop_advlock_desc, nfs_advlock },	/* advlock */
8853806Smckusick 	{ &vop_blkatoff_desc, nfs_blkatoff },	/* blkatoff */
8953806Smckusick 	{ &vop_valloc_desc, nfs_valloc },	/* valloc */
9053554Sheideman 	{ &vop_vfree_desc, nfs_vfree },		/* vfree */
9153806Smckusick 	{ &vop_truncate_desc, nfs_truncate },	/* truncate */
9253806Smckusick 	{ &vop_update_desc, nfs_update },	/* update */
9353582Sheideman 	{ &vop_bwrite_desc, vn_bwrite },
9453554Sheideman 	{ (struct vnodeop_desc*)NULL, (int(*)())NULL }
9538414Smckusick };
9653554Sheideman struct vnodeopv_desc nfsv2_vnodeop_opv_desc =
9753554Sheideman 	{ &nfsv2_vnodeop_p, nfsv2_vnodeop_entries };
9838414Smckusick 
9948054Smckusick /*
10048054Smckusick  * Special device vnode ops
10148054Smckusick  */
10253554Sheideman int (**spec_nfsv2nodeop_p)();
10353554Sheideman struct vnodeopv_entry_desc spec_nfsv2nodeop_entries[] = {
10453554Sheideman 	{ &vop_default_desc, vn_default_error },
10553806Smckusick 	{ &vop_lookup_desc, spec_lookup },	/* lookup */
10653806Smckusick 	{ &vop_create_desc, spec_create },	/* create */
10753806Smckusick 	{ &vop_mknod_desc, spec_mknod },	/* mknod */
10853554Sheideman 	{ &vop_open_desc, spec_open },		/* open */
10953806Smckusick 	{ &vop_close_desc, nfsspec_close },	/* close */
110*56364Smckusick 	{ &vop_access_desc, nfsspec_access },	/* access */
11153806Smckusick 	{ &vop_getattr_desc, nfs_getattr },	/* getattr */
11253806Smckusick 	{ &vop_setattr_desc, nfs_setattr },	/* setattr */
11353806Smckusick 	{ &vop_read_desc, nfsspec_read },	/* read */
11453806Smckusick 	{ &vop_write_desc, nfsspec_write },	/* write */
11553806Smckusick 	{ &vop_ioctl_desc, spec_ioctl },	/* ioctl */
11653806Smckusick 	{ &vop_select_desc, spec_select },	/* select */
11753554Sheideman 	{ &vop_mmap_desc, spec_mmap },		/* mmap */
11854451Smckusick 	{ &vop_fsync_desc, nfs_fsync },		/* fsync */
11953554Sheideman 	{ &vop_seek_desc, spec_seek },		/* seek */
12053806Smckusick 	{ &vop_remove_desc, spec_remove },	/* remove */
12153554Sheideman 	{ &vop_link_desc, spec_link },		/* link */
12253806Smckusick 	{ &vop_rename_desc, spec_rename },	/* rename */
12353806Smckusick 	{ &vop_mkdir_desc, spec_mkdir },	/* mkdir */
12453806Smckusick 	{ &vop_rmdir_desc, spec_rmdir },	/* rmdir */
12553806Smckusick 	{ &vop_symlink_desc, spec_symlink },	/* symlink */
12653806Smckusick 	{ &vop_readdir_desc, spec_readdir },	/* readdir */
12753806Smckusick 	{ &vop_readlink_desc, spec_readlink },	/* readlink */
12853806Smckusick 	{ &vop_abortop_desc, spec_abortop },	/* abortop */
12953806Smckusick 	{ &vop_inactive_desc, nfs_inactive },	/* inactive */
13053806Smckusick 	{ &vop_reclaim_desc, nfs_reclaim },	/* reclaim */
13153554Sheideman 	{ &vop_lock_desc, nfs_lock },		/* lock */
13253806Smckusick 	{ &vop_unlock_desc, nfs_unlock },	/* unlock */
13353554Sheideman 	{ &vop_bmap_desc, spec_bmap },		/* bmap */
13453806Smckusick 	{ &vop_strategy_desc, spec_strategy },	/* strategy */
13553554Sheideman 	{ &vop_print_desc, nfs_print },		/* print */
13653806Smckusick 	{ &vop_islocked_desc, nfs_islocked },	/* islocked */
13753806Smckusick 	{ &vop_advlock_desc, spec_advlock },	/* advlock */
13853806Smckusick 	{ &vop_blkatoff_desc, spec_blkatoff },	/* blkatoff */
13953806Smckusick 	{ &vop_valloc_desc, spec_valloc },	/* valloc */
14053806Smckusick 	{ &vop_vfree_desc, spec_vfree },	/* vfree */
14153806Smckusick 	{ &vop_truncate_desc, spec_truncate },	/* truncate */
14253806Smckusick 	{ &vop_update_desc, nfs_update },	/* update */
14353582Sheideman 	{ &vop_bwrite_desc, vn_bwrite },
14453554Sheideman 	{ (struct vnodeop_desc*)NULL, (int(*)())NULL }
14538414Smckusick };
14653554Sheideman struct vnodeopv_desc spec_nfsv2nodeop_opv_desc =
14753554Sheideman 	{ &spec_nfsv2nodeop_p, spec_nfsv2nodeop_entries };
14838414Smckusick 
14940294Smckusick #ifdef FIFO
15053554Sheideman int (**fifo_nfsv2nodeop_p)();
15153554Sheideman struct vnodeopv_entry_desc fifo_nfsv2nodeop_entries[] = {
15253554Sheideman 	{ &vop_default_desc, vn_default_error },
15353806Smckusick 	{ &vop_lookup_desc, fifo_lookup },	/* lookup */
15453806Smckusick 	{ &vop_create_desc, fifo_create },	/* create */
15553806Smckusick 	{ &vop_mknod_desc, fifo_mknod },	/* mknod */
15653554Sheideman 	{ &vop_open_desc, fifo_open },		/* open */
15753806Smckusick 	{ &vop_close_desc, nfsfifo_close },	/* close */
158*56364Smckusick 	{ &vop_access_desc, nfsspec_access },	/* access */
15953806Smckusick 	{ &vop_getattr_desc, nfs_getattr },	/* getattr */
16053806Smckusick 	{ &vop_setattr_desc, nfs_setattr },	/* setattr */
16153806Smckusick 	{ &vop_read_desc, nfsfifo_read },	/* read */
16253806Smckusick 	{ &vop_write_desc, nfsfifo_write },	/* write */
16353806Smckusick 	{ &vop_ioctl_desc, fifo_ioctl },	/* ioctl */
16453806Smckusick 	{ &vop_select_desc, fifo_select },	/* select */
16553554Sheideman 	{ &vop_mmap_desc, fifo_mmap },		/* mmap */
16654451Smckusick 	{ &vop_fsync_desc, nfs_fsync },		/* fsync */
16753554Sheideman 	{ &vop_seek_desc, fifo_seek },		/* seek */
16853806Smckusick 	{ &vop_remove_desc, fifo_remove },	/* remove */
16953554Sheideman 	{ &vop_link_desc, fifo_link },		/* link */
17053806Smckusick 	{ &vop_rename_desc, fifo_rename },	/* rename */
17153806Smckusick 	{ &vop_mkdir_desc, fifo_mkdir },	/* mkdir */
17253806Smckusick 	{ &vop_rmdir_desc, fifo_rmdir },	/* rmdir */
17353806Smckusick 	{ &vop_symlink_desc, fifo_symlink },	/* symlink */
17453806Smckusick 	{ &vop_readdir_desc, fifo_readdir },	/* readdir */
17553806Smckusick 	{ &vop_readlink_desc, fifo_readlink },	/* readlink */
17653806Smckusick 	{ &vop_abortop_desc, fifo_abortop },	/* abortop */
17753806Smckusick 	{ &vop_inactive_desc, nfs_inactive },	/* inactive */
17853806Smckusick 	{ &vop_reclaim_desc, nfs_reclaim },	/* reclaim */
17953554Sheideman 	{ &vop_lock_desc, nfs_lock },		/* lock */
18053806Smckusick 	{ &vop_unlock_desc, nfs_unlock },	/* unlock */
18153554Sheideman 	{ &vop_bmap_desc, fifo_bmap },		/* bmap */
18253806Smckusick 	{ &vop_strategy_desc, fifo_badop },	/* strategy */
18353554Sheideman 	{ &vop_print_desc, nfs_print },		/* print */
18453806Smckusick 	{ &vop_islocked_desc, nfs_islocked },	/* islocked */
18553806Smckusick 	{ &vop_advlock_desc, fifo_advlock },	/* advlock */
18653806Smckusick 	{ &vop_blkatoff_desc, fifo_blkatoff },	/* blkatoff */
18753806Smckusick 	{ &vop_valloc_desc, fifo_valloc },	/* valloc */
18853806Smckusick 	{ &vop_vfree_desc, fifo_vfree },	/* vfree */
18953806Smckusick 	{ &vop_truncate_desc, fifo_truncate },	/* truncate */
19053806Smckusick 	{ &vop_update_desc, nfs_update },	/* update */
19153582Sheideman 	{ &vop_bwrite_desc, vn_bwrite },
19253554Sheideman 	{ (struct vnodeop_desc*)NULL, (int(*)())NULL }
19340294Smckusick };
19453554Sheideman struct vnodeopv_desc fifo_nfsv2nodeop_opv_desc =
19553554Sheideman 	{ &fifo_nfsv2nodeop_p, fifo_nfsv2nodeop_entries };
19640294Smckusick #endif /* FIFO */
19740294Smckusick 
19856289Smckusick void nqnfs_clientlease();
19956289Smckusick 
20048054Smckusick /*
20152196Smckusick  * Global variables
20248054Smckusick  */
20338414Smckusick extern u_long nfs_procids[NFS_NPROCS];
204*56364Smckusick extern u_long nfs_prog, nfs_vers, nfs_true, nfs_false;
20538414Smckusick extern char nfsiobuf[MAXPHYS+NBPG];
20638884Smacklem struct buf nfs_bqueue;		/* Queue head for nfsiod's */
20741905Smckusick struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON];
20846988Smckusick int nfs_numasync = 0;
20954740Smckusick #define	DIRHDSIZ	(sizeof (struct dirent) - (MAXNAMLEN + 1))
21038414Smckusick 
21138414Smckusick /*
21238414Smckusick  * nfs null call from vfs.
21338414Smckusick  */
21452234Sheideman int
21552196Smckusick nfs_null(vp, cred, procp)
21638414Smckusick 	struct vnode *vp;
21738414Smckusick 	struct ucred *cred;
21852196Smckusick 	struct proc *procp;
21938414Smckusick {
22039488Smckusick 	caddr_t bpos, dpos;
22139488Smckusick 	int error = 0;
22239488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb;
22338414Smckusick 
22452196Smckusick 	nfsm_reqhead(vp, NFSPROC_NULL, 0);
22552196Smckusick 	nfsm_request(vp, NFSPROC_NULL, procp, cred);
22638414Smckusick 	nfsm_reqdone;
22738414Smckusick 	return (error);
22838414Smckusick }
22938414Smckusick 
23038414Smckusick /*
23138414Smckusick  * nfs access vnode op.
232*56364Smckusick  * For nfs, just return ok. File accesses may fail later.
233*56364Smckusick  * For nqnfs, use the access rpc to check accessibility. If file modes are
234*56364Smckusick  * changed on the server, accesses might still fail later.
23538414Smckusick  */
23652234Sheideman int
23753806Smckusick nfs_access(ap)
23854668Smckusick 	struct vop_access_args /* {
23954668Smckusick 		struct vnode *a_vp;
24054668Smckusick 		int  a_mode;
24154668Smckusick 		struct ucred *a_cred;
24254668Smckusick 		struct proc *a_p;
24354668Smckusick 	} */ *ap;
24438414Smckusick {
245*56364Smckusick 	register struct vnode *vp = ap->a_vp;
246*56364Smckusick 	register u_long *tl;
247*56364Smckusick 	register caddr_t cp;
248*56364Smckusick 	caddr_t bpos, dpos;
249*56364Smckusick 	int error = 0;
250*56364Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
25138414Smckusick 
25238414Smckusick 	/*
253*56364Smckusick 	 * There is no way to check accessibility via. ordinary nfs, so if
254*56364Smckusick 	 * access isn't allowed they will get burned later.
25538414Smckusick 	 */
256*56364Smckusick 	if (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) {
257*56364Smckusick 		nfsstats.rpccnt[NQNFSPROC_ACCESS]++;
258*56364Smckusick 		nfsm_reqhead(vp, NQNFSPROC_ACCESS, NFSX_FH + 3 * NFSX_UNSIGNED);
259*56364Smckusick 		nfsm_fhtom(vp);
260*56364Smckusick 		nfsm_build(tl, u_long *, 3 * NFSX_UNSIGNED);
261*56364Smckusick 		if (ap->a_mode & VREAD)
262*56364Smckusick 			*tl++ = nfs_true;
263*56364Smckusick 		else
264*56364Smckusick 			*tl++ = nfs_false;
265*56364Smckusick 		if (ap->a_mode & VWRITE)
266*56364Smckusick 			*tl++ = nfs_true;
267*56364Smckusick 		else
268*56364Smckusick 			*tl++ = nfs_false;
269*56364Smckusick 		if (ap->a_mode & VEXEC)
270*56364Smckusick 			*tl = nfs_true;
271*56364Smckusick 		else
272*56364Smckusick 			*tl = nfs_false;
273*56364Smckusick 		nfsm_request(vp, NQNFSPROC_ACCESS, ap->a_p, ap->a_cred);
274*56364Smckusick 		nfsm_reqdone;
27538884Smacklem 		return (error);
276*56364Smckusick 	} else
27738414Smckusick 		return (0);
27838414Smckusick }
27938414Smckusick 
28038414Smckusick /*
28138414Smckusick  * nfs open vnode op
28256289Smckusick  * Check to see if the type is ok
28352196Smckusick  * and that deletion is not in progress.
28456289Smckusick  * For paged in text files, you will need to flush the page cache
28556289Smckusick  * if consistency is lost.
28638414Smckusick  */
28739488Smckusick /* ARGSUSED */
28852234Sheideman int
28953806Smckusick nfs_open(ap)
29054668Smckusick 	struct vop_open_args /* {
29154668Smckusick 		struct vnode *a_vp;
29254668Smckusick 		int  a_mode;
29354668Smckusick 		struct ucred *a_cred;
29454668Smckusick 		struct proc *a_p;
29554668Smckusick 	} */ *ap;
29638414Smckusick {
29753806Smckusick 	register struct vnode *vp = ap->a_vp;
29856289Smckusick 	struct nfsnode *np = VTONFS(vp);
29956289Smckusick 	struct nfsmount *nmp = VFSTONFS(vp->v_mount);
30056289Smckusick 	struct vattr vattr;
30156289Smckusick 	int error;
30238414Smckusick 
30353806Smckusick 	if (vp->v_type != VREG && vp->v_type != VDIR && vp->v_type != VLNK)
30438414Smckusick 		return (EACCES);
30556289Smckusick 	if (vp->v_flag & VTEXT) {
30656289Smckusick 	    /*
30756289Smckusick 	     * Get a valid lease. If cached data is stale, flush it.
30856289Smckusick 	     */
30956289Smckusick 	    if (nmp->nm_flag & NFSMNT_NQNFS) {
31056289Smckusick 		if (NQNFS_CKINVALID(vp, np, NQL_READ)) {
31156289Smckusick 		    do {
31256289Smckusick 			error = nqnfs_getlease(vp, NQL_READ, ap->a_cred, ap->a_p);
31356289Smckusick 		    } while (error == NQNFS_EXPIRED);
31456289Smckusick 		    if (error)
31556289Smckusick 			return (error);
31656289Smckusick 		    if (np->n_lrev != np->n_brev) {
31756289Smckusick 			np->n_flag &= ~NMODIFIED;
31856289Smckusick 			vinvalbuf(vp, TRUE, ap->a_cred, ap->a_p);
31956289Smckusick 			(void) vnode_pager_uncache(vp);
32056289Smckusick 			np->n_brev = np->n_lrev;
32156289Smckusick 		    }
32256289Smckusick 		}
32356289Smckusick 	    } else {
32456289Smckusick 		if (np->n_flag & NMODIFIED) {
32556289Smckusick 			np->n_flag &= ~NMODIFIED;
32656289Smckusick 			vinvalbuf(vp, TRUE, ap->a_cred, ap->a_p);
32756289Smckusick 			(void) vnode_pager_uncache(vp);
32856289Smckusick 			np->n_attrstamp = 0;
32956289Smckusick 			np->n_direofoffset = 0;
33056289Smckusick 			if (error = VOP_GETATTR(vp, &vattr, ap->a_cred, ap->a_p))
33156289Smckusick 				return (error);
33256289Smckusick 			np->n_mtime = vattr.va_mtime.ts_sec;
33356289Smckusick 		} else {
33456289Smckusick 			if (error = VOP_GETATTR(vp, &vattr, ap->a_cred, ap->a_p))
33556289Smckusick 				return (error);
33656289Smckusick 			if (np->n_mtime != vattr.va_mtime.ts_sec) {
33756289Smckusick 				np->n_direofoffset = 0;
33856289Smckusick 				vinvalbuf(vp, TRUE, ap->a_cred, ap->a_p);
33956289Smckusick 				(void) vnode_pager_uncache(vp);
34056289Smckusick 				np->n_mtime = vattr.va_mtime.ts_sec;
34156289Smckusick 			}
34256289Smckusick 		}
34356289Smckusick 	    }
34456289Smckusick 	} else if ((nmp->nm_flag & NFSMNT_NQNFS) == 0)
34556289Smckusick 		np->n_attrstamp = 0; /* For Open/Close consistency */
34652196Smckusick 	return (0);
34738414Smckusick }
34838414Smckusick 
34938414Smckusick /*
35038414Smckusick  * nfs close vnode op
35138884Smacklem  * For reg files, invalidate any buffer cache entries.
35238414Smckusick  */
35339488Smckusick /* ARGSUSED */
35452234Sheideman int
35553806Smckusick nfs_close(ap)
35654451Smckusick 	struct vop_close_args /* {
35754451Smckusick 		struct vnodeop_desc *a_desc;
35854451Smckusick 		struct vnode *a_vp;
35954451Smckusick 		int  a_fflag;
36054451Smckusick 		struct ucred *a_cred;
36154451Smckusick 		struct proc *a_p;
36254451Smckusick 	} */ *ap;
36338414Smckusick {
36453806Smckusick 	register struct vnode *vp = ap->a_vp;
36553806Smckusick 	register struct nfsnode *np = VTONFS(vp);
36639341Smckusick 	int error = 0;
36738414Smckusick 
36853806Smckusick 	if (vp->v_type == VREG) {
36953806Smckusick 	    if ((VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) == 0 &&
37053629Smckusick 		(np->n_flag & NMODIFIED)) {
37154451Smckusick 		error = vinvalbuf(vp, TRUE, ap->a_cred, ap->a_p);
37241905Smckusick 		np->n_flag &= ~NMODIFIED;
37341905Smckusick 		np->n_attrstamp = 0;
37453629Smckusick 	    }
37553629Smckusick 	    if (np->n_flag & NWRITEERR) {
37653629Smckusick 		np->n_flag &= ~NWRITEERR;
37753629Smckusick 		error = np->n_error;
37853629Smckusick 	    }
37938884Smacklem 	}
38038414Smckusick 	return (error);
38138414Smckusick }
38238414Smckusick 
38338414Smckusick /*
38438414Smckusick  * nfs getattr call from vfs.
38538414Smckusick  */
38652234Sheideman int
38753805Smckusick nfs_getattr(ap)
38854668Smckusick 	struct vop_getattr_args /* {
38954668Smckusick 		struct vnode *a_vp;
39054668Smckusick 		struct vattr *a_vap;
39154668Smckusick 		struct ucred *a_cred;
39254668Smckusick 		struct proc *a_p;
39354668Smckusick 	} */ *ap;
39438414Smckusick {
39553805Smckusick 	register struct vnode *vp = ap->a_vp;
39653805Smckusick 	register struct nfsnode *np = VTONFS(vp);
39739488Smckusick 	register caddr_t cp;
39839488Smckusick 	caddr_t bpos, dpos;
39939488Smckusick 	int error = 0;
40039488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
40138414Smckusick 
40253805Smckusick 	/*
40353805Smckusick 	 * Update local times for special files.
40453805Smckusick 	 */
40556329Smckusick 	if (np->n_flag & (NACC | NUPD))
40653805Smckusick 		np->n_flag |= NCHG;
40753805Smckusick 	/*
40853805Smckusick 	 * First look in the cache.
40953805Smckusick 	 */
41053805Smckusick 	if (nfs_getattrcache(vp, ap->a_vap) == 0)
41138414Smckusick 		return (0);
41238414Smckusick 	nfsstats.rpccnt[NFSPROC_GETATTR]++;
41353805Smckusick 	nfsm_reqhead(vp, NFSPROC_GETATTR, NFSX_FH);
41453805Smckusick 	nfsm_fhtom(vp);
41553805Smckusick 	nfsm_request(vp, NFSPROC_GETATTR, ap->a_p, ap->a_cred);
41653805Smckusick 	nfsm_loadattr(vp, ap->a_vap);
41738414Smckusick 	nfsm_reqdone;
41838414Smckusick 	return (error);
41938414Smckusick }
42038414Smckusick 
42138414Smckusick /*
42238414Smckusick  * nfs setattr call.
42338414Smckusick  */
42452234Sheideman int
42553806Smckusick nfs_setattr(ap)
42654451Smckusick 	struct vop_setattr_args /* {
42754451Smckusick 		struct vnodeop_desc *a_desc;
42854451Smckusick 		struct vnode *a_vp;
42954451Smckusick 		struct vattr *a_vap;
43054451Smckusick 		struct ucred *a_cred;
43154451Smckusick 		struct proc *a_p;
43254451Smckusick 	} */ *ap;
43338414Smckusick {
43438884Smacklem 	register struct nfsv2_sattr *sp;
43539488Smckusick 	register caddr_t cp;
43639488Smckusick 	register long t1;
43752196Smckusick 	caddr_t bpos, dpos, cp2;
43852196Smckusick 	u_long *tl;
43956289Smckusick 	int error = 0, isnq;
44039488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
44153806Smckusick 	register struct vnode *vp = ap->a_vp;
44253806Smckusick 	register struct nfsnode *np = VTONFS(vp);
44353806Smckusick 	register struct vattr *vap = ap->a_vap;
44452196Smckusick 	u_quad_t frev;
44538414Smckusick 
44638414Smckusick 	nfsstats.rpccnt[NFSPROC_SETATTR]++;
44756289Smckusick 	isnq = (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS);
44856289Smckusick 	nfsm_reqhead(vp, NFSPROC_SETATTR, NFSX_FH+NFSX_SATTR(isnq));
44953806Smckusick 	nfsm_fhtom(vp);
45056289Smckusick 	nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR(isnq));
45156289Smckusick 	if (vap->va_mode == (u_short)-1)
45238884Smacklem 		sp->sa_mode = VNOVAL;
45338414Smckusick 	else
45453806Smckusick 		sp->sa_mode = vtonfs_mode(vp->v_type, vap->va_mode);
45556289Smckusick 	if (vap->va_uid == (uid_t)-1)
45638884Smacklem 		sp->sa_uid = VNOVAL;
45738414Smckusick 	else
45853806Smckusick 		sp->sa_uid = txdr_unsigned(vap->va_uid);
45956289Smckusick 	if (vap->va_gid == (gid_t)-1)
46038884Smacklem 		sp->sa_gid = VNOVAL;
46138414Smckusick 	else
46253806Smckusick 		sp->sa_gid = txdr_unsigned(vap->va_gid);
46356289Smckusick 	if (isnq) {
46456289Smckusick 		txdr_hyper(&vap->va_size, &sp->sa_nqsize);
46556289Smckusick 		txdr_nqtime(&vap->va_atime, &sp->sa_nqatime);
46656289Smckusick 		txdr_nqtime(&vap->va_mtime, &sp->sa_nqmtime);
46756289Smckusick 		sp->sa_nqflags = txdr_unsigned(vap->va_flags);
46856289Smckusick 		sp->sa_nqrdev = VNOVAL;
46956289Smckusick 	} else {
47056289Smckusick 		sp->sa_nfssize = txdr_unsigned(vap->va_size);
47156289Smckusick 		sp->sa_nfsatime.nfs_sec = txdr_unsigned(vap->va_atime.ts_sec);
47256289Smckusick 		sp->sa_nfsatime.nfs_usec = txdr_unsigned(vap->va_flags);
47356289Smckusick 		txdr_nfstime(&vap->va_mtime, &sp->sa_nfsmtime);
47456289Smckusick 	}
47554106Smckusick 	if (vap->va_size != VNOVAL || vap->va_mtime.ts_sec != VNOVAL ||
47654106Smckusick 	    vap->va_atime.ts_sec != VNOVAL) {
47739359Smckusick 		if (np->n_flag & NMODIFIED) {
47853806Smckusick 			if (vap->va_size == 0)
47954451Smckusick 				error =
48054451Smckusick 				    vinvalbuf(vp, FALSE, ap->a_cred, ap->a_p);
48146988Smckusick 			else
48254451Smckusick 				error =
48354451Smckusick 				    vinvalbuf(vp, TRUE, ap->a_cred, ap->a_p);
48454451Smckusick 			np->n_flag &= ~NMODIFIED;
48539359Smckusick 		}
48656289Smckusick 		if (vap->va_size != VNOVAL)
48756289Smckusick 			np->n_size = np->n_vattr.va_size = vap->va_size;
48839359Smckusick 	}
48953806Smckusick 	nfsm_request(vp, NFSPROC_SETATTR, ap->a_p, ap->a_cred);
49053806Smckusick 	nfsm_loadattr(vp, (struct vattr *)0);
49153806Smckusick 	if ((VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) &&
49253806Smckusick 	    NQNFS_CKCACHABLE(vp, NQL_WRITE)) {
49352196Smckusick 		nfsm_dissect(tl, u_long *, 2*NFSX_UNSIGNED);
49452196Smckusick 		fxdr_hyper(tl, &frev);
49554451Smckusick 		if (frev > np->n_brev)
49652196Smckusick 			np->n_brev = frev;
49752196Smckusick 	}
49838414Smckusick 	nfsm_reqdone;
49938414Smckusick 	return (error);
50038414Smckusick }
50138414Smckusick 
50238414Smckusick /*
50338414Smckusick  * nfs lookup call, one step at a time...
50438414Smckusick  * First look in cache
50538414Smckusick  * If not found, unlock the directory nfsnode and do the rpc
50638414Smckusick  */
50752234Sheideman int
50853806Smckusick nfs_lookup(ap)
50954451Smckusick 	struct vop_lookup_args /* {
51054451Smckusick 		struct vnodeop_desc *a_desc;
51154451Smckusick 		struct vnode *a_dvp;
51254451Smckusick 		struct vnode **a_vpp;
51354451Smckusick 		struct componentname *a_cnp;
51454451Smckusick 	} */ *ap;
51538414Smckusick {
51653806Smckusick 	register struct componentname *cnp = ap->a_cnp;
51753806Smckusick 	register struct vnode *dvp = ap->a_dvp;
51854668Smckusick 	register struct vnode **vpp = ap->a_vpp;
51955184Smckusick 	register int flags = cnp->cn_flags;
52038414Smckusick 	register struct vnode *vdp;
52148054Smckusick 	register u_long *tl;
52239488Smckusick 	register caddr_t cp;
52339488Smckusick 	register long t1, t2;
52452196Smckusick 	struct nfsmount *nmp;
52552196Smckusick 	struct nfsnode *tp;
52639488Smckusick 	caddr_t bpos, dpos, cp2;
52752196Smckusick 	time_t reqtime;
52839488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
52938414Smckusick 	struct vnode *newvp;
53038414Smckusick 	long len;
53138414Smckusick 	nfsv2fh_t *fhp;
53238414Smckusick 	struct nfsnode *np;
53352234Sheideman 	int lockparent, wantparent, error = 0;
53452196Smckusick 	int nqlflag, cachable;
53552196Smckusick 	u_quad_t frev;
53638414Smckusick 
53754668Smckusick 	*vpp = NULL;
53853806Smckusick 	if (dvp->v_type != VDIR)
53938414Smckusick 		return (ENOTDIR);
54055184Smckusick 	lockparent = flags & LOCKPARENT;
54155184Smckusick 	wantparent = flags & (LOCKPARENT|WANTPARENT);
54253806Smckusick 	nmp = VFSTONFS(dvp->v_mount);
54353806Smckusick 	np = VTONFS(dvp);
54454668Smckusick 	if ((error = cache_lookup(dvp, vpp, cnp)) && error != ENOENT) {
54538884Smacklem 		struct vattr vattr;
54638884Smacklem 		int vpid;
54738884Smacklem 
54854668Smckusick 		vdp = *vpp;
54938884Smacklem 		vpid = vdp->v_id;
55038414Smckusick 		/*
55138884Smacklem 		 * See the comment starting `Step through' in ufs/ufs_lookup.c
55238884Smacklem 		 * for an explanation of the locking protocol
55338414Smckusick 		 */
55453806Smckusick 		if (dvp == vdp) {
55538425Smckusick 			VREF(vdp);
55639441Smckusick 			error = 0;
55752196Smckusick 		} else
55839441Smckusick 			error = vget(vdp);
55939441Smckusick 		if (!error) {
56040251Smckusick 			if (vpid == vdp->v_id) {
56152196Smckusick 			   if (nmp->nm_flag & NFSMNT_NQNFS) {
56256289Smckusick 				if ((nmp->nm_flag & NFSMNT_NQLOOKLEASE) == 0) {
56356289Smckusick 					nfsstats.lookupcache_hits++;
56456289Smckusick 					if (cnp->cn_nameiop != LOOKUP &&
56556289Smckusick 					    (flags & ISLASTCN))
56656289Smckusick 					    cnp->cn_flags |= SAVENAME;
56756289Smckusick 					return (0);
56856289Smckusick 			        } else if (NQNFS_CKCACHABLE(dvp, NQL_READ)) {
56954451Smckusick 					if (np->n_lrev != np->n_brev ||
57052196Smckusick 					    (np->n_flag & NMODIFIED)) {
57152196Smckusick 						np->n_direofoffset = 0;
57253806Smckusick 						cache_purge(dvp);
57354451Smckusick 						error = vinvalbuf(dvp, FALSE,
57454451Smckusick 						    cnp->cn_cred, cnp->cn_proc);
57552196Smckusick 						np->n_flag &= ~NMODIFIED;
57652196Smckusick 						np->n_brev = np->n_lrev;
57752196Smckusick 					} else {
57852196Smckusick 						nfsstats.lookupcache_hits++;
57953806Smckusick 						if (cnp->cn_nameiop != LOOKUP &&
58055184Smckusick 						    (flags & ISLASTCN))
58153806Smckusick 						    cnp->cn_flags |= SAVENAME;
58252196Smckusick 						return (0);
58352196Smckusick 					}
58452196Smckusick 				}
58553806Smckusick 			   } else if (!VOP_GETATTR(vdp, &vattr, cnp->cn_cred, cnp->cn_proc) &&
58654106Smckusick 			       vattr.va_ctime.ts_sec == VTONFS(vdp)->n_ctime) {
58739441Smckusick 				nfsstats.lookupcache_hits++;
58853806Smckusick 				if (cnp->cn_nameiop != LOOKUP &&
58955184Smckusick 				    (flags & ISLASTCN))
59053806Smckusick 					cnp->cn_flags |= SAVENAME;
59139441Smckusick 				return (0);
59240251Smckusick 			   }
59347289Smckusick 			   cache_purge(vdp);
59439441Smckusick 			}
59552196Smckusick 			vrele(vdp);
59638884Smacklem 		}
59754668Smckusick 		*vpp = NULLVP;
59852196Smckusick 	}
59939341Smckusick 	error = 0;
60038414Smckusick 	nfsstats.lookupcache_misses++;
60138414Smckusick 	nfsstats.rpccnt[NFSPROC_LOOKUP]++;
60253806Smckusick 	len = cnp->cn_namelen;
60353806Smckusick 	nfsm_reqhead(dvp, NFSPROC_LOOKUP, NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len));
60452196Smckusick 
60552196Smckusick 	/*
60652196Smckusick 	 * For nqnfs optionally piggyback a getlease request for the name
60752196Smckusick 	 * being looked up.
60852196Smckusick 	 */
60952196Smckusick 	if (nmp->nm_flag & NFSMNT_NQNFS) {
61056289Smckusick 		nfsm_build(tl, u_long *, NFSX_UNSIGNED);
61152196Smckusick 		if ((nmp->nm_flag & NFSMNT_NQLOOKLEASE) &&
61255184Smckusick 		    ((cnp->cn_flags & MAKEENTRY) &&
61356289Smckusick 		    (cnp->cn_nameiop != DELETE || !(flags & ISLASTCN))))
61452196Smckusick 			*tl = txdr_unsigned(nmp->nm_leaseterm);
61556289Smckusick 		else
61652196Smckusick 			*tl = 0;
61752196Smckusick 	}
61853806Smckusick 	nfsm_fhtom(dvp);
61953806Smckusick 	nfsm_strtom(cnp->cn_nameptr, len, NFS_MAXNAMLEN);
62052196Smckusick 	reqtime = time.tv_sec;
62153806Smckusick 	nfsm_request(dvp, NFSPROC_LOOKUP, cnp->cn_proc, cnp->cn_cred);
62238414Smckusick nfsmout:
62338414Smckusick 	if (error) {
62453806Smckusick 		if ((cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME) &&
62555184Smckusick 		    (flags & ISLASTCN) && error == ENOENT)
62652823Smckusick 			error = EJUSTRETURN;
62755184Smckusick 		if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN))
62853806Smckusick 			cnp->cn_flags |= SAVENAME;
62940483Smckusick 		return (error);
63038414Smckusick 	}
63152196Smckusick 	if (nmp->nm_flag & NFSMNT_NQNFS) {
63252196Smckusick 		nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
63352196Smckusick 		if (*tl) {
63452196Smckusick 			nqlflag = fxdr_unsigned(int, *tl);
63552196Smckusick 			nfsm_dissect(tl, u_long *, 4*NFSX_UNSIGNED);
63652196Smckusick 			cachable = fxdr_unsigned(int, *tl++);
63752196Smckusick 			reqtime += fxdr_unsigned(int, *tl++);
63852196Smckusick 			fxdr_hyper(tl, &frev);
63952196Smckusick 		} else
64052196Smckusick 			nqlflag = 0;
64152196Smckusick 	}
64252196Smckusick 	nfsm_dissect(fhp, nfsv2fh_t *, NFSX_FH);
64338414Smckusick 
64438414Smckusick 	/*
64552196Smckusick 	 * Handle RENAME case...
64638414Smckusick 	 */
64755184Smckusick 	if (cnp->cn_nameiop == RENAME && wantparent && (flags & ISLASTCN)) {
64852196Smckusick 		if (!bcmp(np->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) {
64938414Smckusick 			m_freem(mrep);
65038414Smckusick 			return (EISDIR);
65138414Smckusick 		}
65253806Smckusick 		if (error = nfs_nget(dvp->v_mount, fhp, &np)) {
65338414Smckusick 			m_freem(mrep);
65438414Smckusick 			return (error);
65538414Smckusick 		}
65638414Smckusick 		newvp = NFSTOV(np);
65739459Smckusick 		if (error =
65839459Smckusick 		    nfs_loadattrcache(&newvp, &md, &dpos, (struct vattr *)0)) {
65952196Smckusick 			vrele(newvp);
66038414Smckusick 			m_freem(mrep);
66138414Smckusick 			return (error);
66238414Smckusick 		}
66354668Smckusick 		*vpp = newvp;
66445037Smckusick 		m_freem(mrep);
66553806Smckusick 		cnp->cn_flags |= SAVENAME;
66638414Smckusick 		return (0);
66738414Smckusick 	}
66838414Smckusick 
66952196Smckusick 	if (!bcmp(np->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) {
67053806Smckusick 		VREF(dvp);
67153806Smckusick 		newvp = dvp;
67238414Smckusick 	} else {
67353806Smckusick 		if (error = nfs_nget(dvp->v_mount, fhp, &np)) {
67438414Smckusick 			m_freem(mrep);
67538414Smckusick 			return (error);
67638414Smckusick 		}
67738414Smckusick 		newvp = NFSTOV(np);
67838414Smckusick 	}
67939459Smckusick 	if (error = nfs_loadattrcache(&newvp, &md, &dpos, (struct vattr *)0)) {
68052196Smckusick 		vrele(newvp);
68138414Smckusick 		m_freem(mrep);
68238414Smckusick 		return (error);
68338414Smckusick 	}
68438414Smckusick 	m_freem(mrep);
68554668Smckusick 	*vpp = newvp;
68655184Smckusick 	if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN))
68753806Smckusick 		cnp->cn_flags |= SAVENAME;
68855184Smckusick 	if ((cnp->cn_flags & MAKEENTRY) &&
68955184Smckusick 	    (cnp->cn_nameiop != DELETE || !(flags & ISLASTCN))) {
69052196Smckusick 		if ((nmp->nm_flag & NFSMNT_NQNFS) == 0)
69154106Smckusick 			np->n_ctime = np->n_vattr.va_ctime.ts_sec;
69256289Smckusick 		else if (nqlflag && reqtime > time.tv_sec)
69356289Smckusick 			nqnfs_clientlease(nmp, np, nqlflag, cachable, reqtime,
69456289Smckusick 				frev);
69554668Smckusick 		cache_enter(dvp, *vpp, cnp);
69640251Smckusick 	}
69752196Smckusick 	return (0);
69838414Smckusick }
69938414Smckusick 
70038414Smckusick /*
70141905Smckusick  * nfs read call.
70241905Smckusick  * Just call nfs_bioread() to do the work.
70341905Smckusick  */
70452234Sheideman int
70553806Smckusick nfs_read(ap)
70654668Smckusick 	struct vop_read_args /* {
70754668Smckusick 		struct vnode *a_vp;
70854668Smckusick 		struct uio *a_uio;
70954668Smckusick 		int  a_ioflag;
71054668Smckusick 		struct ucred *a_cred;
71154668Smckusick 	} */ *ap;
71241905Smckusick {
71353806Smckusick 	register struct vnode *vp = ap->a_vp;
71453806Smckusick 
71553806Smckusick 	if (vp->v_type != VREG)
71641905Smckusick 		return (EPERM);
71753806Smckusick 	return (nfs_bioread(vp, ap->a_uio, ap->a_ioflag, ap->a_cred));
71841905Smckusick }
71941905Smckusick 
72041905Smckusick /*
72138414Smckusick  * nfs readlink call
72238414Smckusick  */
72352234Sheideman int
72453806Smckusick nfs_readlink(ap)
72554668Smckusick 	struct vop_readlink_args /* {
72654668Smckusick 		struct vnode *a_vp;
72754668Smckusick 		struct uio *a_uio;
72854668Smckusick 		struct ucred *a_cred;
72954668Smckusick 	} */ *ap;
73041905Smckusick {
73153806Smckusick 	register struct vnode *vp = ap->a_vp;
73253806Smckusick 
73353806Smckusick 	if (vp->v_type != VLNK)
73441905Smckusick 		return (EPERM);
73553806Smckusick 	return (nfs_bioread(vp, ap->a_uio, 0, ap->a_cred));
73641905Smckusick }
73741905Smckusick 
73841905Smckusick /*
73941905Smckusick  * Do a readlink rpc.
74041905Smckusick  * Called by nfs_doio() from below the buffer cache.
74141905Smckusick  */
74252234Sheideman int
74348054Smckusick nfs_readlinkrpc(vp, uiop, cred)
74439488Smckusick 	register struct vnode *vp;
74538414Smckusick 	struct uio *uiop;
74638414Smckusick 	struct ucred *cred;
74738414Smckusick {
74848054Smckusick 	register u_long *tl;
74939488Smckusick 	register caddr_t cp;
75039488Smckusick 	register long t1;
75139488Smckusick 	caddr_t bpos, dpos, cp2;
75239488Smckusick 	int error = 0;
75339488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
75438414Smckusick 	long len;
75538414Smckusick 
75638414Smckusick 	nfsstats.rpccnt[NFSPROC_READLINK]++;
75752196Smckusick 	nfsm_reqhead(vp, NFSPROC_READLINK, NFSX_FH);
75838414Smckusick 	nfsm_fhtom(vp);
75952196Smckusick 	nfsm_request(vp, NFSPROC_READLINK, uiop->uio_procp, cred);
76038414Smckusick 	nfsm_strsiz(len, NFS_MAXPATHLEN);
76138414Smckusick 	nfsm_mtouio(uiop, len);
76238414Smckusick 	nfsm_reqdone;
76338414Smckusick 	return (error);
76438414Smckusick }
76538414Smckusick 
76638414Smckusick /*
76741905Smckusick  * nfs read rpc call
76841905Smckusick  * Ditto above
76938414Smckusick  */
77052234Sheideman int
77148054Smckusick nfs_readrpc(vp, uiop, cred)
77239488Smckusick 	register struct vnode *vp;
77338414Smckusick 	struct uio *uiop;
77438414Smckusick 	struct ucred *cred;
77538414Smckusick {
77648054Smckusick 	register u_long *tl;
77739488Smckusick 	register caddr_t cp;
77839488Smckusick 	register long t1;
77939488Smckusick 	caddr_t bpos, dpos, cp2;
78039488Smckusick 	int error = 0;
78139488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
78238414Smckusick 	struct nfsmount *nmp;
78338414Smckusick 	long len, retlen, tsiz;
78438414Smckusick 
78541398Smckusick 	nmp = VFSTONFS(vp->v_mount);
78638414Smckusick 	tsiz = uiop->uio_resid;
78756289Smckusick 	if (uiop->uio_offset + tsiz > 0xffffffff &&
78856289Smckusick 	    (nmp->nm_flag & NFSMNT_NQNFS) == 0)
78956289Smckusick 		return (EFBIG);
79038414Smckusick 	while (tsiz > 0) {
79138414Smckusick 		nfsstats.rpccnt[NFSPROC_READ]++;
79238414Smckusick 		len = (tsiz > nmp->nm_rsize) ? nmp->nm_rsize : tsiz;
79352196Smckusick 		nfsm_reqhead(vp, NFSPROC_READ, NFSX_FH+NFSX_UNSIGNED*3);
79438414Smckusick 		nfsm_fhtom(vp);
79548054Smckusick 		nfsm_build(tl, u_long *, NFSX_UNSIGNED*3);
79656289Smckusick 		if (nmp->nm_flag & NFSMNT_NQNFS) {
79756289Smckusick 			txdr_hyper(&uiop->uio_offset, tl);
79856289Smckusick 			*(tl + 2) = txdr_unsigned(len);
79956289Smckusick 		} else {
80056289Smckusick 			*tl++ = txdr_unsigned(uiop->uio_offset);
80156289Smckusick 			*tl++ = txdr_unsigned(len);
80256289Smckusick 			*tl = 0;
80356289Smckusick 		}
80452196Smckusick 		nfsm_request(vp, NFSPROC_READ, uiop->uio_procp, cred);
80538414Smckusick 		nfsm_loadattr(vp, (struct vattr *)0);
80638414Smckusick 		nfsm_strsiz(retlen, nmp->nm_rsize);
80738414Smckusick 		nfsm_mtouio(uiop, retlen);
80838414Smckusick 		m_freem(mrep);
80938414Smckusick 		if (retlen < len)
81038414Smckusick 			tsiz = 0;
81138414Smckusick 		else
81238414Smckusick 			tsiz -= len;
81338414Smckusick 	}
81438414Smckusick nfsmout:
81538414Smckusick 	return (error);
81638414Smckusick }
81738414Smckusick 
81838414Smckusick /*
81938414Smckusick  * nfs write call
82038414Smckusick  */
82152234Sheideman int
82256289Smckusick nfs_writerpc(vp, uiop, cred, ioflags)
82339488Smckusick 	register struct vnode *vp;
82438414Smckusick 	struct uio *uiop;
82538414Smckusick 	struct ucred *cred;
82656289Smckusick 	int ioflags;
82738414Smckusick {
82848054Smckusick 	register u_long *tl;
82939488Smckusick 	register caddr_t cp;
83039488Smckusick 	register long t1;
83152196Smckusick 	caddr_t bpos, dpos, cp2;
83239488Smckusick 	int error = 0;
83339488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
83438414Smckusick 	struct nfsmount *nmp;
83552196Smckusick 	struct nfsnode *np = VTONFS(vp);
83652196Smckusick 	u_quad_t frev;
83738414Smckusick 	long len, tsiz;
83838414Smckusick 
83941398Smckusick 	nmp = VFSTONFS(vp->v_mount);
84038414Smckusick 	tsiz = uiop->uio_resid;
84156289Smckusick 	if (uiop->uio_offset + tsiz > 0xffffffff &&
84256289Smckusick 	    (nmp->nm_flag & NFSMNT_NQNFS) == 0)
84356289Smckusick 		return (EFBIG);
84438414Smckusick 	while (tsiz > 0) {
84538414Smckusick 		nfsstats.rpccnt[NFSPROC_WRITE]++;
84638414Smckusick 		len = (tsiz > nmp->nm_wsize) ? nmp->nm_wsize : tsiz;
84752196Smckusick 		nfsm_reqhead(vp, NFSPROC_WRITE,
84852196Smckusick 			NFSX_FH+NFSX_UNSIGNED*4+nfsm_rndup(len));
84938414Smckusick 		nfsm_fhtom(vp);
85056289Smckusick 		nfsm_build(tl, u_long *, NFSX_UNSIGNED * 4);
85156289Smckusick 		if (nmp->nm_flag & NFSMNT_NQNFS) {
85256289Smckusick 			txdr_hyper(&uiop->uio_offset, tl);
85356289Smckusick 			tl += 2;
85456289Smckusick 			if (ioflags & IO_APPEND)
85556289Smckusick 				*tl++ = txdr_unsigned(1);
85656289Smckusick 			else
85756289Smckusick 				*tl++ = 0;
85856289Smckusick 		} else {
85956289Smckusick 			*++tl = txdr_unsigned(uiop->uio_offset);
86056289Smckusick 			tl += 2;
86156289Smckusick 		}
86256289Smckusick 		*tl = txdr_unsigned(len);
86338414Smckusick 		nfsm_uiotom(uiop, len);
86452196Smckusick 		nfsm_request(vp, NFSPROC_WRITE, uiop->uio_procp, cred);
86538414Smckusick 		nfsm_loadattr(vp, (struct vattr *)0);
86652196Smckusick 		if (nmp->nm_flag & NFSMNT_MYWRITE)
86754106Smckusick 			VTONFS(vp)->n_mtime = VTONFS(vp)->n_vattr.va_mtime.ts_sec;
86852196Smckusick 		else if ((nmp->nm_flag & NFSMNT_NQNFS) &&
86952196Smckusick 			 NQNFS_CKCACHABLE(vp, NQL_WRITE)) {
87052196Smckusick 			nfsm_dissect(tl, u_long *, 2*NFSX_UNSIGNED);
87152196Smckusick 			fxdr_hyper(tl, &frev);
87254451Smckusick 			if (frev > np->n_brev)
87352196Smckusick 				np->n_brev = frev;
87452196Smckusick 		}
87538414Smckusick 		m_freem(mrep);
87638414Smckusick 		tsiz -= len;
87738414Smckusick 	}
87838414Smckusick nfsmout:
87952196Smckusick 	if (error)
88052196Smckusick 		uiop->uio_resid = tsiz;
88138414Smckusick 	return (error);
88238414Smckusick }
88338414Smckusick 
88438414Smckusick /*
88539459Smckusick  * nfs mknod call
88642246Smckusick  * This is a kludge. Use a create rpc but with the IFMT bits of the mode
88742246Smckusick  * set to specify the file type and the size field for rdev.
88839459Smckusick  */
88939459Smckusick /* ARGSUSED */
89052234Sheideman int
89153806Smckusick nfs_mknod(ap)
89254668Smckusick 	struct vop_mknod_args /* {
89354668Smckusick 		struct vnode *a_dvp;
89454668Smckusick 		struct vnode **a_vpp;
89554668Smckusick 		struct componentname *a_cnp;
89654668Smckusick 		struct vattr *a_vap;
89754668Smckusick 	} */ *ap;
89839459Smckusick {
89953806Smckusick 	register struct vnode *dvp = ap->a_dvp;
90053806Smckusick 	register struct vattr *vap = ap->a_vap;
90153806Smckusick 	register struct componentname *cnp = ap->a_cnp;
90242246Smckusick 	register struct nfsv2_sattr *sp;
90348054Smckusick 	register u_long *tl;
90442246Smckusick 	register caddr_t cp;
90556289Smckusick 	register long t1, t2;
90656289Smckusick 	struct vnode *newvp;
90756289Smckusick 	char *cp2;
90842246Smckusick 	caddr_t bpos, dpos;
90956289Smckusick 	int error = 0, isnq;
91042246Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
91142246Smckusick 	u_long rdev;
91239459Smckusick 
91356289Smckusick 	isnq = (VFSTONFS(dvp->v_mount)->nm_flag & NFSMNT_NQNFS);
91453806Smckusick 	if (vap->va_type == VCHR || vap->va_type == VBLK)
91553806Smckusick 		rdev = txdr_unsigned(vap->va_rdev);
91642246Smckusick #ifdef FIFO
91753806Smckusick 	else if (vap->va_type == VFIFO)
91842246Smckusick 		rdev = 0xffffffff;
91942246Smckusick #endif /* FIFO */
92042246Smckusick 	else {
92153806Smckusick 		VOP_ABORTOP(dvp, cnp);
92253806Smckusick 		vput(dvp);
92342246Smckusick 		return (EOPNOTSUPP);
92442246Smckusick 	}
92542246Smckusick 	nfsstats.rpccnt[NFSPROC_CREATE]++;
92653806Smckusick 	nfsm_reqhead(dvp, NFSPROC_CREATE,
92756289Smckusick 	  NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen)+NFSX_SATTR(isnq));
92853806Smckusick 	nfsm_fhtom(dvp);
92953806Smckusick 	nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
93056289Smckusick 	nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR(isnq));
93153806Smckusick 	sp->sa_mode = vtonfs_mode(vap->va_type, vap->va_mode);
93253806Smckusick 	sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid);
93353806Smckusick 	sp->sa_gid = txdr_unsigned(cnp->cn_cred->cr_gid);
93456289Smckusick 	if (isnq) {
93556289Smckusick 		sp->sa_nqrdev = rdev;
93656289Smckusick 		sp->sa_nqflags = 0;
93756289Smckusick 		txdr_nqtime(&vap->va_atime, &sp->sa_nqatime);
93856289Smckusick 		txdr_nqtime(&vap->va_mtime, &sp->sa_nqmtime);
93956289Smckusick 	} else {
94056289Smckusick 		sp->sa_nfssize = rdev;
94156289Smckusick 		txdr_nfstime(&vap->va_atime, &sp->sa_nfsatime);
94256289Smckusick 		txdr_nfstime(&vap->va_mtime, &sp->sa_nfsmtime);
94356289Smckusick 	}
94453806Smckusick 	nfsm_request(dvp, NFSPROC_CREATE, cnp->cn_proc, cnp->cn_cred);
94556289Smckusick 	nfsm_mtofh(dvp, newvp);
94642246Smckusick 	nfsm_reqdone;
94756289Smckusick 	if (!error)
94856289Smckusick 		cache_enter(dvp, newvp, cnp);
94953806Smckusick 	FREE(cnp->cn_pnbuf, M_NAMEI);
95053806Smckusick 	VTONFS(dvp)->n_flag |= NMODIFIED;
95153806Smckusick 	vrele(dvp);
95242246Smckusick 	return (error);
95339459Smckusick }
95439459Smckusick 
95539459Smckusick /*
95638414Smckusick  * nfs file create call
95738414Smckusick  */
95852234Sheideman int
95953806Smckusick nfs_create(ap)
96054668Smckusick 	struct vop_create_args /* {
96154668Smckusick 		struct vnode *a_dvp;
96254668Smckusick 		struct vnode **a_vpp;
96354668Smckusick 		struct componentname *a_cnp;
96454668Smckusick 		struct vattr *a_vap;
96554668Smckusick 	} */ *ap;
96638414Smckusick {
96753806Smckusick 	register struct vnode *dvp = ap->a_dvp;
96853806Smckusick 	register struct vattr *vap = ap->a_vap;
96953806Smckusick 	register struct componentname *cnp = ap->a_cnp;
97038884Smacklem 	register struct nfsv2_sattr *sp;
97148054Smckusick 	register u_long *tl;
97239488Smckusick 	register caddr_t cp;
97339488Smckusick 	register long t1, t2;
97439488Smckusick 	caddr_t bpos, dpos, cp2;
97556289Smckusick 	int error = 0, isnq;
97639488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
97738414Smckusick 
97838414Smckusick 	nfsstats.rpccnt[NFSPROC_CREATE]++;
97956289Smckusick 	isnq = (VFSTONFS(dvp->v_mount)->nm_flag & NFSMNT_NQNFS);
98053806Smckusick 	nfsm_reqhead(dvp, NFSPROC_CREATE,
98156289Smckusick 	  NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen)+NFSX_SATTR(isnq));
98253806Smckusick 	nfsm_fhtom(dvp);
98353806Smckusick 	nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
98456289Smckusick 	nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR(isnq));
98553806Smckusick 	sp->sa_mode = vtonfs_mode(vap->va_type, vap->va_mode);
98653806Smckusick 	sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid);
98753806Smckusick 	sp->sa_gid = txdr_unsigned(cnp->cn_cred->cr_gid);
98856289Smckusick 	if (isnq) {
98956289Smckusick 		u_quad_t qval = 0;
99056289Smckusick 
99156289Smckusick 		txdr_hyper(&qval, &sp->sa_nqsize);
99256289Smckusick 		sp->sa_nqflags = 0;
99356289Smckusick 		sp->sa_nqrdev = -1;
99456289Smckusick 		txdr_nqtime(&vap->va_atime, &sp->sa_nqatime);
99556289Smckusick 		txdr_nqtime(&vap->va_mtime, &sp->sa_nqmtime);
99656289Smckusick 	} else {
99756289Smckusick 		sp->sa_nfssize = 0;
99856289Smckusick 		txdr_nfstime(&vap->va_atime, &sp->sa_nfsatime);
99956289Smckusick 		txdr_nfstime(&vap->va_mtime, &sp->sa_nfsmtime);
100056289Smckusick 	}
100153806Smckusick 	nfsm_request(dvp, NFSPROC_CREATE, cnp->cn_proc, cnp->cn_cred);
100253806Smckusick 	nfsm_mtofh(dvp, *ap->a_vpp);
100338414Smckusick 	nfsm_reqdone;
100456289Smckusick 	if (!error)
100556289Smckusick 		cache_enter(dvp, *ap->a_vpp, cnp);
100653806Smckusick 	FREE(cnp->cn_pnbuf, M_NAMEI);
100753806Smckusick 	VTONFS(dvp)->n_flag |= NMODIFIED;
100853806Smckusick 	vrele(dvp);
100938414Smckusick 	return (error);
101038414Smckusick }
101138414Smckusick 
101238414Smckusick /*
101338414Smckusick  * nfs file remove call
101441905Smckusick  * To try and make nfs semantics closer to ufs semantics, a file that has
101541905Smckusick  * other processes using the vnode is renamed instead of removed and then
101639341Smckusick  * removed later on the last close.
101741905Smckusick  * - If v_usecount > 1
101839341Smckusick  *	  If a rename is not already in the works
101939341Smckusick  *	     call nfs_sillyrename() to set it up
102039341Smckusick  *     else
102139341Smckusick  *	  do the remove rpc
102238414Smckusick  */
102352234Sheideman int
102453806Smckusick nfs_remove(ap)
102554451Smckusick 	struct vop_remove_args /* {
102654451Smckusick 		struct vnodeop_desc *a_desc;
102754451Smckusick 		struct vnode * a_dvp;
102854451Smckusick 		struct vnode * a_vp;
102954451Smckusick 		struct componentname * a_cnp;
103054451Smckusick 	} */ *ap;
103138414Smckusick {
103253806Smckusick 	register struct vnode *vp = ap->a_vp;
103353806Smckusick 	register struct vnode *dvp = ap->a_dvp;
103453806Smckusick 	register struct componentname *cnp = ap->a_cnp;
103553806Smckusick 	register struct nfsnode *np = VTONFS(vp);
103648054Smckusick 	register u_long *tl;
103739488Smckusick 	register caddr_t cp;
103852196Smckusick 	register long t2;
103939488Smckusick 	caddr_t bpos, dpos;
104039488Smckusick 	int error = 0;
104139488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
104238414Smckusick 
104353806Smckusick 	if (vp->v_usecount > 1) {
104439341Smckusick 		if (!np->n_sillyrename)
104553806Smckusick 			error = nfs_sillyrename(dvp, vp, cnp);
104639341Smckusick 	} else {
104752196Smckusick 		/*
104852196Smckusick 		 * Purge the name cache so that the chance of a lookup for
104952196Smckusick 		 * the name succeeding while the remove is in progress is
105052196Smckusick 		 * minimized. Without node locking it can still happen, such
105152196Smckusick 		 * that an I/O op returns ESTALE, but since you get this if
105252196Smckusick 		 * another host removes the file..
105352196Smckusick 		 */
105453806Smckusick 		cache_purge(vp);
105552196Smckusick 		/*
105652196Smckusick 		 * Throw away biocache buffers. Mainly to avoid
105752196Smckusick 		 * unnecessary delayed writes.
105852196Smckusick 		 */
105954451Smckusick 		error = vinvalbuf(vp, FALSE, cnp->cn_cred, cnp->cn_proc);
106052196Smckusick 		/* Do the rpc */
106138414Smckusick 		nfsstats.rpccnt[NFSPROC_REMOVE]++;
106253806Smckusick 		nfsm_reqhead(dvp, NFSPROC_REMOVE,
106353806Smckusick 			NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen));
106453806Smckusick 		nfsm_fhtom(dvp);
106553806Smckusick 		nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
106653806Smckusick 		nfsm_request(dvp, NFSPROC_REMOVE, cnp->cn_proc, cnp->cn_cred);
106738414Smckusick 		nfsm_reqdone;
106853806Smckusick 		FREE(cnp->cn_pnbuf, M_NAMEI);
106953806Smckusick 		VTONFS(dvp)->n_flag |= NMODIFIED;
107039751Smckusick 		/*
107139751Smckusick 		 * Kludge City: If the first reply to the remove rpc is lost..
107239751Smckusick 		 *   the reply to the retransmitted request will be ENOENT
107339751Smckusick 		 *   since the file was in fact removed
107439751Smckusick 		 *   Therefore, we cheat and return success.
107539751Smckusick 		 */
107639751Smckusick 		if (error == ENOENT)
107739751Smckusick 			error = 0;
107838414Smckusick 	}
107940042Smckusick 	np->n_attrstamp = 0;
108053806Smckusick 	vrele(dvp);
108153806Smckusick 	vrele(vp);
108238414Smckusick 	return (error);
108338414Smckusick }
108438414Smckusick 
108538414Smckusick /*
108638414Smckusick  * nfs file remove rpc called from nfs_inactive
108738414Smckusick  */
108852234Sheideman int
108954451Smckusick nfs_removeit(sp)
109048364Smckusick 	register struct sillyrename *sp;
109138414Smckusick {
109248054Smckusick 	register u_long *tl;
109339488Smckusick 	register caddr_t cp;
109452196Smckusick 	register long t2;
109539488Smckusick 	caddr_t bpos, dpos;
109639488Smckusick 	int error = 0;
109739488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
109838414Smckusick 
109938414Smckusick 	nfsstats.rpccnt[NFSPROC_REMOVE]++;
110052196Smckusick 	nfsm_reqhead(sp->s_dvp, NFSPROC_REMOVE,
110148364Smckusick 		NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(sp->s_namlen));
110248364Smckusick 	nfsm_fhtom(sp->s_dvp);
110348364Smckusick 	nfsm_strtom(sp->s_name, sp->s_namlen, NFS_MAXNAMLEN);
110454451Smckusick 	nfsm_request(sp->s_dvp, NFSPROC_REMOVE, NULL, sp->s_cred);
110538414Smckusick 	nfsm_reqdone;
110648364Smckusick 	VTONFS(sp->s_dvp)->n_flag |= NMODIFIED;
110738414Smckusick 	return (error);
110838414Smckusick }
110938414Smckusick 
111038414Smckusick /*
111138414Smckusick  * nfs file rename call
111238414Smckusick  */
111352234Sheideman int
111453806Smckusick nfs_rename(ap)
111554668Smckusick 	struct vop_rename_args  /* {
111654668Smckusick 		struct vnode *a_fdvp;
111754668Smckusick 		struct vnode *a_fvp;
111854668Smckusick 		struct componentname *a_fcnp;
111954668Smckusick 		struct vnode *a_tdvp;
112054668Smckusick 		struct vnode *a_tvp;
112154668Smckusick 		struct componentname *a_tcnp;
112254668Smckusick 	} */ *ap;
112338414Smckusick {
112453806Smckusick 	register struct vnode *fvp = ap->a_fvp;
112553806Smckusick 	register struct vnode *tvp = ap->a_tvp;
112653806Smckusick 	register struct vnode *fdvp = ap->a_fdvp;
112753806Smckusick 	register struct vnode *tdvp = ap->a_tdvp;
112853806Smckusick 	register struct componentname *tcnp = ap->a_tcnp;
112953806Smckusick 	register struct componentname *fcnp = ap->a_fcnp;
113048054Smckusick 	register u_long *tl;
113139488Smckusick 	register caddr_t cp;
113252196Smckusick 	register long t2;
113339488Smckusick 	caddr_t bpos, dpos;
113439488Smckusick 	int error = 0;
113539488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
113638414Smckusick 
113753804Spendry 	/* Check for cross-device rename */
113853806Smckusick 	if ((fvp->v_mount != tdvp->v_mount) ||
113953806Smckusick 	    (tvp && (fvp->v_mount != tvp->v_mount))) {
114053804Spendry 		error = EXDEV;
114153804Spendry 		goto out;
114253804Spendry 	}
114353804Spendry 
114453804Spendry 
114538414Smckusick 	nfsstats.rpccnt[NFSPROC_RENAME]++;
114653806Smckusick 	nfsm_reqhead(fdvp, NFSPROC_RENAME,
114753806Smckusick 		(NFSX_FH+NFSX_UNSIGNED)*2+nfsm_rndup(fcnp->cn_namelen)+
114853806Smckusick 		nfsm_rndup(fcnp->cn_namelen)); /* or fcnp->cn_cred?*/
114953806Smckusick 	nfsm_fhtom(fdvp);
115053806Smckusick 	nfsm_strtom(fcnp->cn_nameptr, fcnp->cn_namelen, NFS_MAXNAMLEN);
115153806Smckusick 	nfsm_fhtom(tdvp);
115253806Smckusick 	nfsm_strtom(tcnp->cn_nameptr, tcnp->cn_namelen, NFS_MAXNAMLEN);
115353806Smckusick 	nfsm_request(fdvp, NFSPROC_RENAME, tcnp->cn_proc, tcnp->cn_cred);
115438414Smckusick 	nfsm_reqdone;
115553806Smckusick 	VTONFS(fdvp)->n_flag |= NMODIFIED;
115653806Smckusick 	VTONFS(tdvp)->n_flag |= NMODIFIED;
115753806Smckusick 	if (fvp->v_type == VDIR) {
115853806Smckusick 		if (tvp != NULL && tvp->v_type == VDIR)
115953806Smckusick 			cache_purge(tdvp);
116053806Smckusick 		cache_purge(fdvp);
116138414Smckusick 	}
116253804Spendry out:
116353806Smckusick 	if (tdvp == tvp)
116453806Smckusick 		vrele(tdvp);
116543360Smckusick 	else
116653806Smckusick 		vput(tdvp);
116753806Smckusick 	if (tvp)
116853806Smckusick 		vput(tvp);
116953806Smckusick 	vrele(fdvp);
117053806Smckusick 	vrele(fvp);
117140112Smckusick 	/*
117240112Smckusick 	 * Kludge: Map ENOENT => 0 assuming that it is a reply to a retry.
117340112Smckusick 	 */
117440112Smckusick 	if (error == ENOENT)
117540112Smckusick 		error = 0;
117638414Smckusick 	return (error);
117738414Smckusick }
117838414Smckusick 
117938414Smckusick /*
118041905Smckusick  * nfs file rename rpc called from nfs_remove() above
118138414Smckusick  */
118252234Sheideman int
118352234Sheideman nfs_renameit(sdvp, scnp, sp)
118452234Sheideman 	struct vnode *sdvp;
118552234Sheideman 	struct componentname *scnp;
118648364Smckusick 	register struct sillyrename *sp;
118738414Smckusick {
118848054Smckusick 	register u_long *tl;
118939488Smckusick 	register caddr_t cp;
119052196Smckusick 	register long t2;
119139488Smckusick 	caddr_t bpos, dpos;
119239488Smckusick 	int error = 0;
119339488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
119438414Smckusick 
119538414Smckusick 	nfsstats.rpccnt[NFSPROC_RENAME]++;
119652234Sheideman 	nfsm_reqhead(sdvp, NFSPROC_RENAME,
119752234Sheideman 		(NFSX_FH+NFSX_UNSIGNED)*2+nfsm_rndup(scnp->cn_namelen)+
119852196Smckusick 		nfsm_rndup(sp->s_namlen));
119952234Sheideman 	nfsm_fhtom(sdvp);
120052234Sheideman 	nfsm_strtom(scnp->cn_nameptr, scnp->cn_namelen, NFS_MAXNAMLEN);
120152234Sheideman 	nfsm_fhtom(sdvp);
120248364Smckusick 	nfsm_strtom(sp->s_name, sp->s_namlen, NFS_MAXNAMLEN);
120352234Sheideman 	nfsm_request(sdvp, NFSPROC_RENAME, scnp->cn_proc, scnp->cn_cred);
120438414Smckusick 	nfsm_reqdone;
120552234Sheideman 	FREE(scnp->cn_pnbuf, M_NAMEI);
120652234Sheideman 	VTONFS(sdvp)->n_flag |= NMODIFIED;
120738414Smckusick 	return (error);
120838414Smckusick }
120938414Smckusick 
121038414Smckusick /*
121138414Smckusick  * nfs hard link create call
121238414Smckusick  */
121352234Sheideman int
121453806Smckusick nfs_link(ap)
121554668Smckusick 	struct vop_link_args /* {
121654668Smckusick 		struct vnode *a_vp;
121754668Smckusick 		struct vnode *a_tdvp;
121854668Smckusick 		struct componentname *a_cnp;
121954668Smckusick 	} */ *ap;
122038414Smckusick {
122153806Smckusick 	register struct vnode *vp = ap->a_vp;
122253806Smckusick 	register struct vnode *tdvp = ap->a_tdvp;
122353806Smckusick 	register struct componentname *cnp = ap->a_cnp;
122448054Smckusick 	register u_long *tl;
122539488Smckusick 	register caddr_t cp;
122652196Smckusick 	register long t2;
122739488Smckusick 	caddr_t bpos, dpos;
122839488Smckusick 	int error = 0;
122939488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
123038414Smckusick 
123153806Smckusick 	if (vp->v_mount != tdvp->v_mount) {
123253806Smckusick 		/*VOP_ABORTOP(vp, cnp);*/
123353806Smckusick 		if (tdvp == vp)
123453806Smckusick 			vrele(vp);
123553804Spendry 		else
123653806Smckusick 			vput(vp);
123753804Spendry 		return (EXDEV);
123853804Spendry 	}
123953804Spendry 
124038414Smckusick 	nfsstats.rpccnt[NFSPROC_LINK]++;
124153806Smckusick 	nfsm_reqhead(tdvp, NFSPROC_LINK,
124253806Smckusick 		NFSX_FH*2+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen));
124353806Smckusick 	nfsm_fhtom(tdvp);
124453806Smckusick 	nfsm_fhtom(vp);
124553806Smckusick 	nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
124653806Smckusick 	nfsm_request(tdvp, NFSPROC_LINK, cnp->cn_proc, cnp->cn_cred);
124738414Smckusick 	nfsm_reqdone;
124853806Smckusick 	FREE(cnp->cn_pnbuf, M_NAMEI);
124953806Smckusick 	VTONFS(tdvp)->n_attrstamp = 0;
125053806Smckusick 	VTONFS(vp)->n_flag |= NMODIFIED;
125153806Smckusick 	vrele(vp);
125240112Smckusick 	/*
125340112Smckusick 	 * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry.
125440112Smckusick 	 */
125540112Smckusick 	if (error == EEXIST)
125640112Smckusick 		error = 0;
125738414Smckusick 	return (error);
125838414Smckusick }
125938414Smckusick 
126038414Smckusick /*
126138414Smckusick  * nfs symbolic link create call
126238414Smckusick  */
126352234Sheideman /* start here */
126452234Sheideman int
126553806Smckusick nfs_symlink(ap)
126654668Smckusick 	struct vop_symlink_args /* {
126754668Smckusick 		struct vnode *a_dvp;
126854668Smckusick 		struct vnode **a_vpp;
126954668Smckusick 		struct componentname *a_cnp;
127054668Smckusick 		struct vattr *a_vap;
127154668Smckusick 		char *a_target;
127254668Smckusick 	} */ *ap;
127338414Smckusick {
127453806Smckusick 	register struct vnode *dvp = ap->a_dvp;
127553806Smckusick 	register struct vattr *vap = ap->a_vap;
127653806Smckusick 	register struct componentname *cnp = ap->a_cnp;
127738884Smacklem 	register struct nfsv2_sattr *sp;
127848054Smckusick 	register u_long *tl;
127939488Smckusick 	register caddr_t cp;
128052196Smckusick 	register long t2;
128139488Smckusick 	caddr_t bpos, dpos;
128256289Smckusick 	int slen, error = 0, isnq;
128339488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
128438414Smckusick 
128538414Smckusick 	nfsstats.rpccnt[NFSPROC_SYMLINK]++;
128653600Sheideman 	slen = strlen(ap->a_target);
128756289Smckusick 	isnq = (VFSTONFS(dvp->v_mount)->nm_flag & NFSMNT_NQNFS);
128853806Smckusick 	nfsm_reqhead(dvp, NFSPROC_SYMLINK, NFSX_FH+2*NFSX_UNSIGNED+
128956289Smckusick 	    nfsm_rndup(cnp->cn_namelen)+nfsm_rndup(slen)+NFSX_SATTR(isnq));
129053806Smckusick 	nfsm_fhtom(dvp);
129153806Smckusick 	nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
129253600Sheideman 	nfsm_strtom(ap->a_target, slen, NFS_MAXPATHLEN);
129356289Smckusick 	nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR(isnq));
129453806Smckusick 	sp->sa_mode = vtonfs_mode(VLNK, vap->va_mode);
129553806Smckusick 	sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid);
129653806Smckusick 	sp->sa_gid = txdr_unsigned(cnp->cn_cred->cr_gid);
129756289Smckusick 	if (isnq) {
129856289Smckusick 		quad_t qval = -1;
129956289Smckusick 
130056289Smckusick 		txdr_hyper(&qval, &sp->sa_nqsize);
130156289Smckusick 		sp->sa_nqflags = 0;
130256289Smckusick 		txdr_nqtime(&vap->va_atime, &sp->sa_nqatime);
130356289Smckusick 		txdr_nqtime(&vap->va_mtime, &sp->sa_nqmtime);
130456289Smckusick 	} else {
130556289Smckusick 		sp->sa_nfssize = -1;
130656289Smckusick 		txdr_nfstime(&vap->va_atime, &sp->sa_nfsatime);
130756289Smckusick 		txdr_nfstime(&vap->va_mtime, &sp->sa_nfsmtime);
130856289Smckusick 	}
130953806Smckusick 	nfsm_request(dvp, NFSPROC_SYMLINK, cnp->cn_proc, cnp->cn_cred);
131038414Smckusick 	nfsm_reqdone;
131153806Smckusick 	FREE(cnp->cn_pnbuf, M_NAMEI);
131253806Smckusick 	VTONFS(dvp)->n_flag |= NMODIFIED;
131353806Smckusick 	vrele(dvp);
131440112Smckusick 	/*
131540112Smckusick 	 * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry.
131640112Smckusick 	 */
131740112Smckusick 	if (error == EEXIST)
131840112Smckusick 		error = 0;
131938414Smckusick 	return (error);
132038414Smckusick }
132138414Smckusick 
132238414Smckusick /*
132338414Smckusick  * nfs make dir call
132438414Smckusick  */
132552234Sheideman int
132653806Smckusick nfs_mkdir(ap)
132754668Smckusick 	struct vop_mkdir_args /* {
132854668Smckusick 		struct vnode *a_dvp;
132954668Smckusick 		struct vnode **a_vpp;
133054668Smckusick 		struct componentname *a_cnp;
133154668Smckusick 		struct vattr *a_vap;
133254668Smckusick 	} */ *ap;
133338414Smckusick {
133453806Smckusick 	register struct vnode *dvp = ap->a_dvp;
133553806Smckusick 	register struct vattr *vap = ap->a_vap;
133653806Smckusick 	register struct componentname *cnp = ap->a_cnp;
133754668Smckusick 	register struct vnode **vpp = ap->a_vpp;
133838884Smacklem 	register struct nfsv2_sattr *sp;
133948054Smckusick 	register u_long *tl;
134039488Smckusick 	register caddr_t cp;
134139488Smckusick 	register long t1, t2;
134241905Smckusick 	register int len;
134339488Smckusick 	caddr_t bpos, dpos, cp2;
134456289Smckusick 	int error = 0, firsttry = 1, isnq;
134539488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
134638414Smckusick 
134753806Smckusick 	len = cnp->cn_namelen;
134856289Smckusick 	isnq = (VFSTONFS(dvp->v_mount)->nm_flag & NFSMNT_NQNFS);
134938414Smckusick 	nfsstats.rpccnt[NFSPROC_MKDIR]++;
135053806Smckusick 	nfsm_reqhead(dvp, NFSPROC_MKDIR,
135156289Smckusick 	  NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len)+NFSX_SATTR(isnq));
135253806Smckusick 	nfsm_fhtom(dvp);
135353806Smckusick 	nfsm_strtom(cnp->cn_nameptr, len, NFS_MAXNAMLEN);
135456289Smckusick 	nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR(isnq));
135553806Smckusick 	sp->sa_mode = vtonfs_mode(VDIR, vap->va_mode);
135653806Smckusick 	sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid);
135753806Smckusick 	sp->sa_gid = txdr_unsigned(cnp->cn_cred->cr_gid);
135856289Smckusick 	if (isnq) {
135956289Smckusick 		quad_t qval = -1;
136056289Smckusick 
136156289Smckusick 		txdr_hyper(&qval, &sp->sa_nqsize);
136256289Smckusick 		sp->sa_nqflags = 0;
136356289Smckusick 		txdr_nqtime(&vap->va_atime, &sp->sa_nqatime);
136456289Smckusick 		txdr_nqtime(&vap->va_mtime, &sp->sa_nqmtime);
136556289Smckusick 	} else {
136656289Smckusick 		sp->sa_nfssize = -1;
136756289Smckusick 		txdr_nfstime(&vap->va_atime, &sp->sa_nfsatime);
136856289Smckusick 		txdr_nfstime(&vap->va_mtime, &sp->sa_nfsmtime);
136956289Smckusick 	}
137053806Smckusick 	nfsm_request(dvp, NFSPROC_MKDIR, cnp->cn_proc, cnp->cn_cred);
137154668Smckusick 	nfsm_mtofh(dvp, *vpp);
137238414Smckusick 	nfsm_reqdone;
137353806Smckusick 	VTONFS(dvp)->n_flag |= NMODIFIED;
137440112Smckusick 	/*
137541905Smckusick 	 * Kludge: Map EEXIST => 0 assuming that you have a reply to a retry
137641905Smckusick 	 * if we can succeed in looking up the directory.
137741905Smckusick 	 * "firsttry" is necessary since the macros may "goto nfsmout" which
137841905Smckusick 	 * is above the if on errors. (Ugh)
137940112Smckusick 	 */
138041905Smckusick 	if (error == EEXIST && firsttry) {
138141905Smckusick 		firsttry = 0;
138240112Smckusick 		error = 0;
138341905Smckusick 		nfsstats.rpccnt[NFSPROC_LOOKUP]++;
138454668Smckusick 		*vpp = NULL;
138553806Smckusick 		nfsm_reqhead(dvp, NFSPROC_LOOKUP,
138641905Smckusick 		    NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len));
138753806Smckusick 		nfsm_fhtom(dvp);
138853806Smckusick 		nfsm_strtom(cnp->cn_nameptr, len, NFS_MAXNAMLEN);
138953806Smckusick 		nfsm_request(dvp, NFSPROC_LOOKUP, cnp->cn_proc, cnp->cn_cred);
139054668Smckusick 		nfsm_mtofh(dvp, *vpp);
139154668Smckusick 		if ((*vpp)->v_type != VDIR) {
139254668Smckusick 			vput(*vpp);
139341905Smckusick 			error = EEXIST;
139441905Smckusick 		}
139541905Smckusick 		m_freem(mrep);
139641905Smckusick 	}
139753806Smckusick 	FREE(cnp->cn_pnbuf, M_NAMEI);
139853806Smckusick 	vrele(dvp);
139938414Smckusick 	return (error);
140038414Smckusick }
140138414Smckusick 
140238414Smckusick /*
140338414Smckusick  * nfs remove directory call
140438414Smckusick  */
140552234Sheideman int
140653806Smckusick nfs_rmdir(ap)
140754668Smckusick 	struct vop_rmdir_args /* {
140854668Smckusick 		struct vnode *a_dvp;
140954668Smckusick 		struct vnode *a_vp;
141054668Smckusick 		struct componentname *a_cnp;
141154668Smckusick 	} */ *ap;
141238414Smckusick {
141353806Smckusick 	register struct vnode *vp = ap->a_vp;
141453806Smckusick 	register struct vnode *dvp = ap->a_dvp;
141553806Smckusick 	register struct componentname *cnp = ap->a_cnp;
141648054Smckusick 	register u_long *tl;
141739488Smckusick 	register caddr_t cp;
141852196Smckusick 	register long t2;
141939488Smckusick 	caddr_t bpos, dpos;
142039488Smckusick 	int error = 0;
142139488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
142238414Smckusick 
142353806Smckusick 	if (dvp == vp) {
142453806Smckusick 		vrele(dvp);
142553806Smckusick 		vrele(dvp);
142653806Smckusick 		FREE(cnp->cn_pnbuf, M_NAMEI);
142738414Smckusick 		return (EINVAL);
142838414Smckusick 	}
142938414Smckusick 	nfsstats.rpccnt[NFSPROC_RMDIR]++;
143053806Smckusick 	nfsm_reqhead(dvp, NFSPROC_RMDIR,
143153806Smckusick 		NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen));
143253806Smckusick 	nfsm_fhtom(dvp);
143353806Smckusick 	nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
143453806Smckusick 	nfsm_request(dvp, NFSPROC_RMDIR, cnp->cn_proc, cnp->cn_cred);
143538414Smckusick 	nfsm_reqdone;
143653806Smckusick 	FREE(cnp->cn_pnbuf, M_NAMEI);
143753806Smckusick 	VTONFS(dvp)->n_flag |= NMODIFIED;
143853806Smckusick 	cache_purge(dvp);
143953806Smckusick 	cache_purge(vp);
144053806Smckusick 	vrele(vp);
144153806Smckusick 	vrele(dvp);
144240112Smckusick 	/*
144340112Smckusick 	 * Kludge: Map ENOENT => 0 assuming that you have a reply to a retry.
144440112Smckusick 	 */
144540112Smckusick 	if (error == ENOENT)
144640112Smckusick 		error = 0;
144738414Smckusick 	return (error);
144838414Smckusick }
144938414Smckusick 
145038414Smckusick /*
145138414Smckusick  * nfs readdir call
145238414Smckusick  * Although cookie is defined as opaque, I translate it to/from net byte
145338414Smckusick  * order so that it looks more sensible. This appears consistent with the
145438414Smckusick  * Ultrix implementation of NFS.
145538414Smckusick  */
145652234Sheideman int
145753806Smckusick nfs_readdir(ap)
145854668Smckusick 	struct vop_readdir_args /* {
145954668Smckusick 		struct vnode *a_vp;
146054668Smckusick 		struct uio *a_uio;
146154668Smckusick 		struct ucred *a_cred;
146254668Smckusick 	} */ *ap;
146338414Smckusick {
146453806Smckusick 	register struct vnode *vp = ap->a_vp;
146553806Smckusick 	register struct nfsnode *np = VTONFS(vp);
146653806Smckusick 	register struct uio *uio = ap->a_uio;
146741905Smckusick 	int tresid, error;
146841905Smckusick 	struct vattr vattr;
146941905Smckusick 
147053806Smckusick 	if (vp->v_type != VDIR)
147141905Smckusick 		return (EPERM);
147241905Smckusick 	/*
147341905Smckusick 	 * First, check for hit on the EOF offset cache
147441905Smckusick 	 */
147553806Smckusick 	if (uio->uio_offset != 0 && uio->uio_offset == np->n_direofoffset &&
147652196Smckusick 	    (np->n_flag & NMODIFIED) == 0) {
147753806Smckusick 		if (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) {
147853806Smckusick 			if (NQNFS_CKCACHABLE(vp, NQL_READ)) {
147952196Smckusick 				nfsstats.direofcache_hits++;
148052196Smckusick 				return (0);
148152196Smckusick 			}
148253806Smckusick 		} else if (VOP_GETATTR(vp, &vattr, ap->a_cred, uio->uio_procp) == 0 &&
148354106Smckusick 			np->n_mtime == vattr.va_mtime.ts_sec) {
148452196Smckusick 			nfsstats.direofcache_hits++;
148552196Smckusick 			return (0);
148652196Smckusick 		}
148741905Smckusick 	}
148841905Smckusick 
148941905Smckusick 	/*
149041905Smckusick 	 * Call nfs_bioread() to do the real work.
149141905Smckusick 	 */
149253806Smckusick 	tresid = uio->uio_resid;
149353806Smckusick 	error = nfs_bioread(vp, uio, 0, ap->a_cred);
149441905Smckusick 
149554451Smckusick 	if (!error && uio->uio_resid == tresid)
149641905Smckusick 		nfsstats.direofcache_misses++;
149741905Smckusick 	return (error);
149841905Smckusick }
149941905Smckusick 
150041905Smckusick /*
150141905Smckusick  * Readdir rpc call.
150241905Smckusick  * Called from below the buffer cache by nfs_doio().
150341905Smckusick  */
150452234Sheideman int
150548054Smckusick nfs_readdirrpc(vp, uiop, cred)
150641905Smckusick 	register struct vnode *vp;
150741905Smckusick 	struct uio *uiop;
150841905Smckusick 	struct ucred *cred;
150941905Smckusick {
151038414Smckusick 	register long len;
151154740Smckusick 	register struct dirent *dp;
151248054Smckusick 	register u_long *tl;
151339488Smckusick 	register caddr_t cp;
151439488Smckusick 	register long t1;
151541905Smckusick 	long tlen, lastlen;
151639488Smckusick 	caddr_t bpos, dpos, cp2;
151739488Smckusick 	int error = 0;
151839488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
151938414Smckusick 	struct mbuf *md2;
152038414Smckusick 	caddr_t dpos2;
152138414Smckusick 	int siz;
152240296Smckusick 	int more_dirs = 1;
152356289Smckusick 	u_long off, savoff;
152454740Smckusick 	struct dirent *savdp;
152540296Smckusick 	struct nfsmount *nmp;
152640296Smckusick 	struct nfsnode *np = VTONFS(vp);
152740296Smckusick 	long tresid;
152838414Smckusick 
152941398Smckusick 	nmp = VFSTONFS(vp->v_mount);
153040296Smckusick 	tresid = uiop->uio_resid;
153140296Smckusick 	/*
153240296Smckusick 	 * Loop around doing readdir rpc's of size uio_resid or nm_rsize,
153348054Smckusick 	 * whichever is smaller, truncated to a multiple of NFS_DIRBLKSIZ.
153441905Smckusick 	 * The stopping criteria is EOF or buffer full.
153540296Smckusick 	 */
153648054Smckusick 	while (more_dirs && uiop->uio_resid >= NFS_DIRBLKSIZ) {
153740296Smckusick 		nfsstats.rpccnt[NFSPROC_READDIR]++;
153852196Smckusick 		nfsm_reqhead(vp, NFSPROC_READDIR,
153956289Smckusick 			NFSX_FH + 2 * NFSX_UNSIGNED);
154040296Smckusick 		nfsm_fhtom(vp);
154156289Smckusick 		nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED);
154256289Smckusick 		off = (u_long)uiop->uio_offset;
154356289Smckusick 		*tl++ = txdr_unsigned(off);
154448054Smckusick 		*tl = txdr_unsigned(((uiop->uio_resid > nmp->nm_rsize) ?
154548054Smckusick 			nmp->nm_rsize : uiop->uio_resid) & ~(NFS_DIRBLKSIZ-1));
154652196Smckusick 		nfsm_request(vp, NFSPROC_READDIR, uiop->uio_procp, cred);
154740296Smckusick 		siz = 0;
154852196Smckusick 		nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
154948054Smckusick 		more_dirs = fxdr_unsigned(int, *tl);
155040296Smckusick 
155140296Smckusick 		/* Save the position so that we can do nfsm_mtouio() later */
155240296Smckusick 		dpos2 = dpos;
155340296Smckusick 		md2 = md;
155440296Smckusick 
155540296Smckusick 		/* loop thru the dir entries, doctoring them to 4bsd form */
155642246Smckusick #ifdef lint
155754740Smckusick 		dp = (struct dirent *)0;
155842246Smckusick #endif /* lint */
155940296Smckusick 		while (more_dirs && siz < uiop->uio_resid) {
156040296Smckusick 			savoff = off;		/* Hold onto offset and dp */
156140296Smckusick 			savdp = dp;
156256289Smckusick 			nfsm_dissecton(tl, u_long *, 2 * NFSX_UNSIGNED);
156354740Smckusick 			dp = (struct dirent *)tl;
156454740Smckusick 			dp->d_fileno = fxdr_unsigned(u_long, *tl++);
156548054Smckusick 			len = fxdr_unsigned(int, *tl);
156640296Smckusick 			if (len <= 0 || len > NFS_MAXNAMLEN) {
156740296Smckusick 				error = EBADRPC;
156840296Smckusick 				m_freem(mrep);
156940296Smckusick 				goto nfsmout;
157040296Smckusick 			}
157154986Smckusick 			dp->d_namlen = (u_char)len;
157254986Smckusick 			dp->d_type = DT_UNKNOWN;
157340296Smckusick 			nfsm_adv(len);		/* Point past name */
157440296Smckusick 			tlen = nfsm_rndup(len);
157540296Smckusick 			/*
157640296Smckusick 			 * This should not be necessary, but some servers have
157740296Smckusick 			 * broken XDR such that these bytes are not null filled.
157840296Smckusick 			 */
157940296Smckusick 			if (tlen != len) {
158040296Smckusick 				*dpos = '\0';	/* Null-terminate */
158140296Smckusick 				nfsm_adv(tlen - len);
158240296Smckusick 				len = tlen;
158340296Smckusick 			}
158456289Smckusick 			nfsm_dissecton(tl, u_long *, 2 * NFSX_UNSIGNED);
158554986Smckusick 			off = fxdr_unsigned(u_long, *tl);
158648054Smckusick 			*tl++ = 0;	/* Ensures null termination of name */
158748054Smckusick 			more_dirs = fxdr_unsigned(int, *tl);
158856289Smckusick 			dp->d_reclen = len + 4 * NFSX_UNSIGNED;
158940296Smckusick 			siz += dp->d_reclen;
159040296Smckusick 		}
159140296Smckusick 		/*
159240296Smckusick 		 * If at end of rpc data, get the eof boolean
159340296Smckusick 		 */
159440296Smckusick 		if (!more_dirs) {
159552196Smckusick 			nfsm_dissecton(tl, u_long *, NFSX_UNSIGNED);
159648054Smckusick 			more_dirs = (fxdr_unsigned(int, *tl) == 0);
159738414Smckusick 
159840296Smckusick 			/*
159940296Smckusick 			 * If at EOF, cache directory offset
160040296Smckusick 			 */
160141905Smckusick 			if (!more_dirs)
160240296Smckusick 				np->n_direofoffset = off;
160338414Smckusick 		}
160440296Smckusick 		/*
160540296Smckusick 		 * If there is too much to fit in the data buffer, use savoff and
160640296Smckusick 		 * savdp to trim off the last record.
160740296Smckusick 		 * --> we are not at eof
160840296Smckusick 		 */
160940296Smckusick 		if (siz > uiop->uio_resid) {
161040296Smckusick 			off = savoff;
161140296Smckusick 			siz -= dp->d_reclen;
161240296Smckusick 			dp = savdp;
161340296Smckusick 			more_dirs = 0;	/* Paranoia */
161440113Smckusick 		}
161540296Smckusick 		if (siz > 0) {
161641905Smckusick 			lastlen = dp->d_reclen;
161740296Smckusick 			md = md2;
161840296Smckusick 			dpos = dpos2;
161940296Smckusick 			nfsm_mtouio(uiop, siz);
162056289Smckusick 			uiop->uio_offset = (off_t)off;
162140296Smckusick 		} else
162240296Smckusick 			more_dirs = 0;	/* Ugh, never happens, but in case.. */
162340296Smckusick 		m_freem(mrep);
162438414Smckusick 	}
162541905Smckusick 	/*
162648054Smckusick 	 * Fill last record, iff any, out to a multiple of NFS_DIRBLKSIZ
162741905Smckusick 	 * by increasing d_reclen for the last record.
162841905Smckusick 	 */
162941905Smckusick 	if (uiop->uio_resid < tresid) {
163048054Smckusick 		len = uiop->uio_resid & (NFS_DIRBLKSIZ - 1);
163141905Smckusick 		if (len > 0) {
163254740Smckusick 			dp = (struct dirent *)
163341905Smckusick 				(uiop->uio_iov->iov_base - lastlen);
163441905Smckusick 			dp->d_reclen += len;
163541905Smckusick 			uiop->uio_iov->iov_base += len;
163641905Smckusick 			uiop->uio_iov->iov_len -= len;
163741905Smckusick 			uiop->uio_resid -= len;
163841905Smckusick 		}
163941905Smckusick 	}
164040296Smckusick nfsmout:
164138414Smckusick 	return (error);
164238414Smckusick }
164338414Smckusick 
164452196Smckusick /*
164556289Smckusick  * Nqnfs readdir_and_lookup RPC. Used in place of nfs_readdirrpc().
164652196Smckusick  */
164752234Sheideman int
164852196Smckusick nfs_readdirlookrpc(vp, uiop, cred)
164952196Smckusick 	struct vnode *vp;
165052196Smckusick 	register struct uio *uiop;
165152196Smckusick 	struct ucred *cred;
165252196Smckusick {
165352196Smckusick 	register int len;
165454740Smckusick 	register struct dirent *dp;
165552196Smckusick 	register u_long *tl;
165652196Smckusick 	register caddr_t cp;
165752196Smckusick 	register long t1;
165852196Smckusick 	caddr_t bpos, dpos, cp2;
165952196Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
166052196Smckusick 	struct nameidata nami, *ndp = &nami;
166152317Sheideman 	struct componentname *cnp = &ndp->ni_cnd;
166256289Smckusick 	u_long off, endoff, fileno;
166352196Smckusick 	time_t reqtime, ltime;
166452196Smckusick 	struct nfsmount *nmp;
166552196Smckusick 	struct nfsnode *np, *tp;
166652196Smckusick 	struct vnode *newvp;
166752196Smckusick 	nfsv2fh_t *fhp;
166852196Smckusick 	u_quad_t frev;
166952196Smckusick 	int error = 0, tlen, more_dirs = 1, tresid, doit, bigenough, i;
167052196Smckusick 	int cachable;
167152196Smckusick 
167252196Smckusick 	if (uiop->uio_iovcnt != 1)
167352196Smckusick 		panic("nfs rdirlook");
167452196Smckusick 	nmp = VFSTONFS(vp->v_mount);
167552196Smckusick 	tresid = uiop->uio_resid;
167652196Smckusick 	ndp->ni_dvp = vp;
167752196Smckusick 	newvp = NULLVP;
167852196Smckusick 	/*
167952196Smckusick 	 * Loop around doing readdir rpc's of size uio_resid or nm_rsize,
168052196Smckusick 	 * whichever is smaller, truncated to a multiple of NFS_DIRBLKSIZ.
168152196Smckusick 	 * The stopping criteria is EOF or buffer full.
168252196Smckusick 	 */
168352196Smckusick 	while (more_dirs && uiop->uio_resid >= NFS_DIRBLKSIZ) {
168452196Smckusick 		nfsstats.rpccnt[NQNFSPROC_READDIRLOOK]++;
168552196Smckusick 		nfsm_reqhead(vp, NQNFSPROC_READDIRLOOK,
168656289Smckusick 			NFSX_FH + 3 * NFSX_UNSIGNED);
168752196Smckusick 		nfsm_fhtom(vp);
168856289Smckusick  		nfsm_build(tl, u_long *, 3 * NFSX_UNSIGNED);
168956289Smckusick 		off = (u_long)uiop->uio_offset;
169056289Smckusick 		*tl++ = txdr_unsigned(off);
169152196Smckusick 		*tl++ = txdr_unsigned(((uiop->uio_resid > nmp->nm_rsize) ?
169252196Smckusick 			nmp->nm_rsize : uiop->uio_resid) & ~(NFS_DIRBLKSIZ-1));
169356289Smckusick 		if (nmp->nm_flag & NFSMNT_NQLOOKLEASE)
169456289Smckusick 			*tl = txdr_unsigned(nmp->nm_leaseterm);
169556289Smckusick 		else
169656289Smckusick 			*tl = 0;
169752196Smckusick 		reqtime = time.tv_sec;
169852196Smckusick 		nfsm_request(vp, NQNFSPROC_READDIRLOOK, uiop->uio_procp, cred);
169952196Smckusick 		nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
170052196Smckusick 		more_dirs = fxdr_unsigned(int, *tl);
170152196Smckusick 
170252196Smckusick 		/* loop thru the dir entries, doctoring them to 4bsd form */
170352196Smckusick 		bigenough = 1;
170452196Smckusick 		while (more_dirs && bigenough) {
170552196Smckusick 			doit = 1;
170656289Smckusick 			nfsm_dissect(tl, u_long *, 4 * NFSX_UNSIGNED);
170756289Smckusick 			if (nmp->nm_flag & NFSMNT_NQLOOKLEASE) {
170856289Smckusick 				cachable = fxdr_unsigned(int, *tl++);
170956289Smckusick 				ltime = reqtime + fxdr_unsigned(int, *tl++);
171056289Smckusick 				fxdr_hyper(tl, &frev);
171156289Smckusick 			}
171252196Smckusick 			nfsm_dissect(fhp, nfsv2fh_t *, NFSX_FH);
171352196Smckusick 			if (!bcmp(VTONFS(vp)->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) {
171452196Smckusick 				VREF(vp);
171552196Smckusick 				newvp = vp;
171652196Smckusick 				np = VTONFS(vp);
171752196Smckusick 			} else {
171852196Smckusick 				if (error = nfs_nget(vp->v_mount, fhp, &np))
171952196Smckusick 					doit = 0;
172052196Smckusick 				newvp = NFSTOV(np);
172152196Smckusick 			}
172252196Smckusick 			if (error = nfs_loadattrcache(&newvp, &md, &dpos,
172352196Smckusick 				(struct vattr *)0))
172452196Smckusick 				doit = 0;
172556289Smckusick 			nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
172652196Smckusick 			fileno = fxdr_unsigned(u_long, *tl++);
172752196Smckusick 			len = fxdr_unsigned(int, *tl);
172852196Smckusick 			if (len <= 0 || len > NFS_MAXNAMLEN) {
172952196Smckusick 				error = EBADRPC;
173052196Smckusick 				m_freem(mrep);
173152196Smckusick 				goto nfsmout;
173252196Smckusick 			}
173352196Smckusick 			tlen = (len + 4) & ~0x3;
173452196Smckusick 			if ((tlen + DIRHDSIZ) > uiop->uio_resid)
173552196Smckusick 				bigenough = 0;
173652196Smckusick 			if (bigenough && doit) {
173754740Smckusick 				dp = (struct dirent *)uiop->uio_iov->iov_base;
173854740Smckusick 				dp->d_fileno = fileno;
173952196Smckusick 				dp->d_namlen = len;
174052196Smckusick 				dp->d_reclen = tlen + DIRHDSIZ;
174154986Smckusick 				dp->d_type =
174254986Smckusick 				    IFTODT(VTTOIF(np->n_vattr.va_type));
174352196Smckusick 				uiop->uio_resid -= DIRHDSIZ;
174452196Smckusick 				uiop->uio_iov->iov_base += DIRHDSIZ;
174552196Smckusick 				uiop->uio_iov->iov_len -= DIRHDSIZ;
174652317Sheideman 				cnp->cn_nameptr = uiop->uio_iov->iov_base;
174752317Sheideman 				cnp->cn_namelen = len;
174852196Smckusick 				ndp->ni_vp = newvp;
174952196Smckusick 				nfsm_mtouio(uiop, len);
175052196Smckusick 				cp = uiop->uio_iov->iov_base;
175152196Smckusick 				tlen -= len;
175252196Smckusick 				for (i = 0; i < tlen; i++)
175352196Smckusick 					*cp++ = '\0';
175452196Smckusick 				uiop->uio_iov->iov_base += tlen;
175552196Smckusick 				uiop->uio_iov->iov_len -= tlen;
175652196Smckusick 				uiop->uio_resid -= tlen;
175752317Sheideman 				cnp->cn_hash = 0;
175852317Sheideman 				for (cp = cnp->cn_nameptr, i = 1; i <= len; i++, cp++)
175952317Sheideman 					cnp->cn_hash += (unsigned char)*cp * i;
176056289Smckusick 				if ((nmp->nm_flag & NFSMNT_NQLOOKLEASE) &&
176156289Smckusick 					ltime > time.tv_sec)
176256289Smckusick 					nqnfs_clientlease(nmp, np, NQL_READ,
176356289Smckusick 						cachable, ltime, frev);
176456289Smckusick 				cache_enter(ndp->ni_dvp, ndp->ni_vp, cnp);
176552196Smckusick 			} else {
176652196Smckusick 				nfsm_adv(nfsm_rndup(len));
176752196Smckusick 			}
176852196Smckusick 			if (newvp != NULLVP) {
176952196Smckusick 				vrele(newvp);
177052196Smckusick 				newvp = NULLVP;
177152196Smckusick 			}
177256289Smckusick 			nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
177352196Smckusick 			if (bigenough)
177456289Smckusick 				endoff = off = fxdr_unsigned(u_long, *tl++);
177552196Smckusick 			else
177656289Smckusick 				endoff = fxdr_unsigned(u_long, *tl++);
177752196Smckusick 			more_dirs = fxdr_unsigned(int, *tl);
177852196Smckusick 		}
177952196Smckusick 		/*
178052196Smckusick 		 * If at end of rpc data, get the eof boolean
178152196Smckusick 		 */
178252196Smckusick 		if (!more_dirs) {
178352196Smckusick 			nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
178452196Smckusick 			more_dirs = (fxdr_unsigned(int, *tl) == 0);
178552196Smckusick 
178652196Smckusick 			/*
178752196Smckusick 			 * If at EOF, cache directory offset
178852196Smckusick 			 */
178952196Smckusick 			if (!more_dirs)
179052196Smckusick 				VTONFS(vp)->n_direofoffset = endoff;
179152196Smckusick 		}
179252196Smckusick 		if (uiop->uio_resid < tresid)
179356289Smckusick 			uiop->uio_offset = (off_t)off;
179452196Smckusick 		else
179552196Smckusick 			more_dirs = 0;
179652196Smckusick 		m_freem(mrep);
179752196Smckusick 	}
179852196Smckusick 	/*
179952196Smckusick 	 * Fill last record, iff any, out to a multiple of NFS_DIRBLKSIZ
180052196Smckusick 	 * by increasing d_reclen for the last record.
180152196Smckusick 	 */
180252196Smckusick 	if (uiop->uio_resid < tresid) {
180352196Smckusick 		len = uiop->uio_resid & (NFS_DIRBLKSIZ - 1);
180452196Smckusick 		if (len > 0) {
180552196Smckusick 			dp->d_reclen += len;
180652196Smckusick 			uiop->uio_iov->iov_base += len;
180752196Smckusick 			uiop->uio_iov->iov_len -= len;
180852196Smckusick 			uiop->uio_resid -= len;
180952196Smckusick 		}
181052196Smckusick 	}
181152196Smckusick nfsmout:
181252196Smckusick 	if (newvp != NULLVP)
181352196Smckusick 		vrele(newvp);
181452196Smckusick 	return (error);
181552196Smckusick }
181639488Smckusick static char hextoasc[] = "0123456789abcdef";
181738414Smckusick 
181838414Smckusick /*
181938414Smckusick  * Silly rename. To make the NFS filesystem that is stateless look a little
182038414Smckusick  * more like the "ufs" a remove of an active vnode is translated to a rename
182138414Smckusick  * to a funny looking filename that is removed by nfs_inactive on the
182238414Smckusick  * nfsnode. There is the potential for another process on a different client
182338414Smckusick  * to create the same funny name between the nfs_lookitup() fails and the
182438414Smckusick  * nfs_rename() completes, but...
182538414Smckusick  */
182652234Sheideman int
182752317Sheideman nfs_sillyrename(dvp, vp, cnp)
182852234Sheideman 	struct vnode *dvp, *vp;
182952234Sheideman 	struct componentname *cnp;
183038414Smckusick {
183138414Smckusick 	register struct nfsnode *np;
183238414Smckusick 	register struct sillyrename *sp;
183338414Smckusick 	int error;
183438414Smckusick 	short pid;
183538414Smckusick 
183652234Sheideman 	cache_purge(dvp);
183752234Sheideman 	np = VTONFS(vp);
183851986Smckusick #ifdef SILLYSEPARATE
183938414Smckusick 	MALLOC(sp, struct sillyrename *, sizeof (struct sillyrename),
184048364Smckusick 		M_NFSREQ, M_WAITOK);
184151986Smckusick #else
184251986Smckusick 	sp = &np->n_silly;
184351986Smckusick #endif
184452234Sheideman 	sp->s_cred = crdup(cnp->cn_cred);
184552234Sheideman 	sp->s_dvp = dvp;
184652234Sheideman 	VREF(dvp);
184738414Smckusick 
184838414Smckusick 	/* Fudge together a funny name */
184952234Sheideman 	pid = cnp->cn_proc->p_pid;
185048364Smckusick 	bcopy(".nfsAxxxx4.4", sp->s_name, 13);
185148364Smckusick 	sp->s_namlen = 12;
185248364Smckusick 	sp->s_name[8] = hextoasc[pid & 0xf];
185348364Smckusick 	sp->s_name[7] = hextoasc[(pid >> 4) & 0xf];
185448364Smckusick 	sp->s_name[6] = hextoasc[(pid >> 8) & 0xf];
185548364Smckusick 	sp->s_name[5] = hextoasc[(pid >> 12) & 0xf];
185638414Smckusick 
185738414Smckusick 	/* Try lookitups until we get one that isn't there */
185852234Sheideman 	while (nfs_lookitup(sp, (nfsv2fh_t *)0, cnp->cn_proc) == 0) {
185948364Smckusick 		sp->s_name[4]++;
186048364Smckusick 		if (sp->s_name[4] > 'z') {
186138414Smckusick 			error = EINVAL;
186238414Smckusick 			goto bad;
186338414Smckusick 		}
186438414Smckusick 	}
186552234Sheideman 	if (error = nfs_renameit(dvp, cnp, sp))
186638414Smckusick 		goto bad;
186752234Sheideman 	nfs_lookitup(sp, &np->n_fh, cnp->cn_proc);
186838414Smckusick 	np->n_sillyrename = sp;
186938414Smckusick 	return (0);
187038414Smckusick bad:
187148364Smckusick 	vrele(sp->s_dvp);
187248364Smckusick 	crfree(sp->s_cred);
187351986Smckusick #ifdef SILLYSEPARATE
187448364Smckusick 	free((caddr_t)sp, M_NFSREQ);
187551986Smckusick #endif
187638414Smckusick 	return (error);
187738414Smckusick }
187838414Smckusick 
187938414Smckusick /*
188038414Smckusick  * Look up a file name for silly rename stuff.
188138414Smckusick  * Just like nfs_lookup() except that it doesn't load returned values
188238414Smckusick  * into the nfsnode table.
188338414Smckusick  * If fhp != NULL it copies the returned file handle out
188438414Smckusick  */
188552234Sheideman int
188652196Smckusick nfs_lookitup(sp, fhp, procp)
188748364Smckusick 	register struct sillyrename *sp;
188838414Smckusick 	nfsv2fh_t *fhp;
188952196Smckusick 	struct proc *procp;
189038414Smckusick {
189148364Smckusick 	register struct vnode *vp = sp->s_dvp;
189248054Smckusick 	register u_long *tl;
189339488Smckusick 	register caddr_t cp;
189439488Smckusick 	register long t1, t2;
189539488Smckusick 	caddr_t bpos, dpos, cp2;
189639488Smckusick 	u_long xid;
189756289Smckusick 	int error = 0, isnq;
189839488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
189938414Smckusick 	long len;
190038414Smckusick 
190156289Smckusick 	isnq = (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS);
190238414Smckusick 	nfsstats.rpccnt[NFSPROC_LOOKUP]++;
190348364Smckusick 	len = sp->s_namlen;
190452196Smckusick 	nfsm_reqhead(vp, NFSPROC_LOOKUP, NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len));
190556289Smckusick 	if (isnq) {
190656289Smckusick 		nfsm_build(tl, u_long *, NFSX_UNSIGNED);
190756289Smckusick 		*tl = 0;
190856289Smckusick 	}
190938414Smckusick 	nfsm_fhtom(vp);
191048364Smckusick 	nfsm_strtom(sp->s_name, len, NFS_MAXNAMLEN);
191152196Smckusick 	nfsm_request(vp, NFSPROC_LOOKUP, procp, sp->s_cred);
191238414Smckusick 	if (fhp != NULL) {
191356289Smckusick 		if (isnq)
191456289Smckusick 			nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
191552196Smckusick 		nfsm_dissect(cp, caddr_t, NFSX_FH);
191638414Smckusick 		bcopy(cp, (caddr_t)fhp, NFSX_FH);
191738414Smckusick 	}
191838414Smckusick 	nfsm_reqdone;
191938414Smckusick 	return (error);
192038414Smckusick }
192138414Smckusick 
192238414Smckusick /*
192338414Smckusick  * Kludge City..
192438414Smckusick  * - make nfs_bmap() essentially a no-op that does no translation
192541905Smckusick  * - do nfs_strategy() by faking physical I/O with nfs_readrpc/nfs_writerpc
192638414Smckusick  *   after mapping the physical addresses into Kernel Virtual space in the
192738414Smckusick  *   nfsiobuf area.
192838414Smckusick  *   (Maybe I could use the process's page mapping, but I was concerned that
192938414Smckusick  *    Kernel Write might not be enabled and also figured copyout() would do
193038414Smckusick  *    a lot more work than bcopy() and also it currently happens in the
193138414Smckusick  *    context of the swapper process (2).
193238414Smckusick  */
193352234Sheideman int
193453806Smckusick nfs_bmap(ap)
193554668Smckusick 	struct vop_bmap_args /* {
193654668Smckusick 		struct vnode *a_vp;
193754668Smckusick 		daddr_t  a_bn;
193854668Smckusick 		struct vnode **a_vpp;
193954668Smckusick 		daddr_t *a_bnp;
194054668Smckusick 	} */ *ap;
194138414Smckusick {
194253806Smckusick 	register struct vnode *vp = ap->a_vp;
194353806Smckusick 
194453600Sheideman 	if (ap->a_vpp != NULL)
194553806Smckusick 		*ap->a_vpp = vp;
194653600Sheideman 	if (ap->a_bnp != NULL)
194753806Smckusick 		*ap->a_bnp = ap->a_bn * btodb(vp->v_mount->mnt_stat.f_iosize);
194838414Smckusick 	return (0);
194938414Smckusick }
195038414Smckusick 
195138414Smckusick /*
195238884Smacklem  * Strategy routine for phys. i/o
195338884Smacklem  * If the biod's are running, queue a request
195438884Smacklem  * otherwise just call nfs_doio() to get it done
195538414Smckusick  */
195652234Sheideman int
195753806Smckusick nfs_strategy(ap)
195854668Smckusick 	struct vop_strategy_args /* {
195954668Smckusick 		struct buf *a_bp;
196054668Smckusick 	} */ *ap;
196138414Smckusick {
196253806Smckusick 	register struct buf *bp = ap->a_bp;
196338884Smacklem 	register struct buf *dp;
196439341Smckusick 	register int i;
196538884Smacklem 	int error = 0;
196639341Smckusick 	int fnd = 0;
196738884Smacklem 
196838884Smacklem 	/*
196941905Smckusick 	 * Set b_proc. It seems a bit silly to do it here, but since bread()
197041905Smckusick 	 * doesn't set it, I will.
197146450Skarels 	 * Set b_proc == NULL for asynchronous ops, since these may still
197241905Smckusick 	 * be hanging about after the process terminates.
197341905Smckusick 	 */
197453806Smckusick 	if ((bp->b_flags & B_PHYS) == 0) {
197553806Smckusick 		if (bp->b_flags & B_ASYNC)
197653806Smckusick 			bp->b_proc = (struct proc *)0;
197746988Smckusick 		else
197853806Smckusick 			bp->b_proc = curproc;
197946988Smckusick 	}
198041905Smckusick 	/*
198146450Skarels 	 * If the op is asynchronous and an i/o daemon is waiting
198238884Smacklem 	 * queue the request, wake it up and wait for completion
198346450Skarels 	 * otherwise just do it ourselves.
198438884Smacklem 	 */
198553806Smckusick 	if ((bp->b_flags & B_ASYNC) == 0 || nfs_numasync == 0)
198653806Smckusick 		return (nfs_doio(bp));
198746988Smckusick 	for (i = 0; i < NFS_MAXASYNCDAEMON; i++) {
198846988Smckusick 		if (nfs_iodwant[i]) {
198939341Smckusick 			dp = &nfs_bqueue;
199039341Smckusick 			if (dp->b_actf == NULL) {
199153806Smckusick 				dp->b_actl = bp;
199253806Smckusick 				bp->b_actf = dp;
199339341Smckusick 			} else {
199453806Smckusick 				dp->b_actf->b_actl = bp;
199553806Smckusick 				bp->b_actf = dp->b_actf;
199639341Smckusick 			}
199753806Smckusick 			dp->b_actf = bp;
199853806Smckusick 			bp->b_actl = dp;
199939341Smckusick 			fnd++;
200039341Smckusick 			wakeup((caddr_t)&nfs_iodwant[i]);
200139341Smckusick 			break;
200238884Smacklem 		}
200339341Smckusick 	}
200439341Smckusick 	if (!fnd)
200553806Smckusick 		error = nfs_doio(bp);
200638884Smacklem 	return (error);
200738884Smacklem }
200838884Smacklem 
200938884Smacklem /*
201038884Smacklem  * Fun and games with i/o
201138884Smacklem  * Essentially play ubasetup() and disk interrupt service routine by
201238884Smacklem  * mapping the data buffer into kernel virtual space and doing the
201338884Smacklem  * nfs read or write rpc's from it.
201441905Smckusick  * If the nfsiod's are not running, this is just called from nfs_strategy(),
201541905Smckusick  * otherwise it is called by the nfsiods to do what would normally be
201638884Smacklem  * partially disk interrupt driven.
201738884Smacklem  */
201852234Sheideman int
201938884Smacklem nfs_doio(bp)
202038884Smacklem 	register struct buf *bp;
202138884Smacklem {
202238414Smckusick 	register struct uio *uiop;
202338414Smckusick 	register struct vnode *vp;
202439341Smckusick 	struct nfsnode *np;
202538884Smacklem 	struct ucred *cr;
202641539Smckusick 	int error;
202741539Smckusick 	struct uio uio;
202841539Smckusick 	struct iovec io;
202938414Smckusick 
203038414Smckusick 	vp = bp->b_vp;
203140251Smckusick 	np = VTONFS(vp);
203238414Smckusick 	uiop = &uio;
203338414Smckusick 	uiop->uio_iov = &io;
203438414Smckusick 	uiop->uio_iovcnt = 1;
203538414Smckusick 	uiop->uio_segflg = UIO_SYSSPACE;
203652196Smckusick 	uiop->uio_procp = bp->b_proc;
203739751Smckusick 
203838414Smckusick 	/*
203938884Smacklem 	 * For phys i/o, map the b_addr into kernel virtual space using
204038884Smacklem 	 * the Nfsiomap pte's
204138884Smacklem 	 * Also, add a temporary b_rcred for reading using the process's uid
204238884Smacklem 	 * and a guess at a group
204338414Smckusick 	 */
204438884Smacklem 	if (bp->b_flags & B_PHYS) {
204548054Smckusick 		if (bp->b_flags & B_DIRTY)
204648054Smckusick 			uiop->uio_procp = pageproc;
204748054Smckusick 		cr = crcopy(uiop->uio_procp->p_ucred);
204841539Smckusick 		/* mapping was already done by vmapbuf */
204941539Smckusick 		io.iov_base = bp->b_un.b_addr;
205039751Smckusick 
205138884Smacklem 		/*
205239751Smckusick 		 * And do the i/o rpc
205339751Smckusick 		 */
205439751Smckusick 		io.iov_len = uiop->uio_resid = bp->b_bcount;
205539823Smckusick 		uiop->uio_offset = bp->b_blkno * DEV_BSIZE;
205639751Smckusick 		if (bp->b_flags & B_READ) {
205739751Smckusick 			uiop->uio_rw = UIO_READ;
205839751Smckusick 			nfsstats.read_physios++;
205948054Smckusick 			bp->b_error = error = nfs_readrpc(vp, uiop, cr);
206045717Smckusick 			(void) vnode_pager_uncache(vp);
206139751Smckusick 		} else {
206239751Smckusick 			uiop->uio_rw = UIO_WRITE;
206339751Smckusick 			nfsstats.write_physios++;
206456289Smckusick 			bp->b_error = error = nfs_writerpc(vp, uiop, cr, 0);
206539341Smckusick 		}
206639751Smckusick 
206739751Smckusick 		/*
206839751Smckusick 		 * Finally, release pte's used by physical i/o
206939751Smckusick 		 */
207038884Smacklem 		crfree(cr);
207139751Smckusick 	} else {
207239751Smckusick 		if (bp->b_flags & B_READ) {
207339751Smckusick 			io.iov_len = uiop->uio_resid = bp->b_bcount;
207439751Smckusick 			io.iov_base = bp->b_un.b_addr;
207539751Smckusick 			uiop->uio_rw = UIO_READ;
207641905Smckusick 			switch (vp->v_type) {
207741905Smckusick 			case VREG:
207841905Smckusick 				uiop->uio_offset = bp->b_blkno * DEV_BSIZE;
207941905Smckusick 				nfsstats.read_bios++;
208048054Smckusick 				error = nfs_readrpc(vp, uiop, bp->b_rcred);
208141905Smckusick 				break;
208241905Smckusick 			case VLNK:
208341905Smckusick 				uiop->uio_offset = 0;
208441905Smckusick 				nfsstats.readlink_bios++;
208548054Smckusick 				error = nfs_readlinkrpc(vp, uiop, bp->b_rcred);
208641905Smckusick 				break;
208741905Smckusick 			case VDIR:
208841905Smckusick 				uiop->uio_offset = bp->b_lblkno;
208941905Smckusick 				nfsstats.readdir_bios++;
209056289Smckusick 				if (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS)
209152196Smckusick 				    error = nfs_readdirlookrpc(vp, uiop, bp->b_rcred);
209252196Smckusick 				else
209352196Smckusick 				    error = nfs_readdirrpc(vp, uiop, bp->b_rcred);
209441905Smckusick 				/*
209541905Smckusick 				 * Save offset cookie in b_blkno.
209641905Smckusick 				 */
209741905Smckusick 				bp->b_blkno = uiop->uio_offset;
209841905Smckusick 				break;
209941905Smckusick 			};
210041905Smckusick 			bp->b_error = error;
210139751Smckusick 		} else {
210239751Smckusick 			io.iov_len = uiop->uio_resid = bp->b_dirtyend
210339751Smckusick 				- bp->b_dirtyoff;
210439823Smckusick 			uiop->uio_offset = (bp->b_blkno * DEV_BSIZE)
210539751Smckusick 				+ bp->b_dirtyoff;
210639751Smckusick 			io.iov_base = bp->b_un.b_addr + bp->b_dirtyoff;
210739751Smckusick 			uiop->uio_rw = UIO_WRITE;
210839751Smckusick 			nfsstats.write_bios++;
210941905Smckusick 			bp->b_error = error = nfs_writerpc(vp, uiop,
211056289Smckusick 				bp->b_wcred, 0);
211139751Smckusick 			if (error) {
211239751Smckusick 				np->n_error = error;
211339751Smckusick 				np->n_flag |= NWRITEERR;
211439751Smckusick 			}
211539751Smckusick 			bp->b_dirtyoff = bp->b_dirtyend = 0;
211639751Smckusick 		}
211738884Smacklem 	}
211839751Smckusick 	if (error)
211939751Smckusick 		bp->b_flags |= B_ERROR;
212039751Smckusick 	bp->b_resid = uiop->uio_resid;
212138414Smckusick 	biodone(bp);
212238414Smckusick 	return (error);
212338414Smckusick }
212438884Smacklem 
212538884Smacklem /*
212648054Smckusick  * Mmap a file
212748054Smckusick  *
212848054Smckusick  * NB Currently unsupported.
212948054Smckusick  */
213048054Smckusick /* ARGSUSED */
213152234Sheideman int
213253806Smckusick nfs_mmap(ap)
213354668Smckusick 	struct vop_mmap_args /* {
213454668Smckusick 		struct vnode *a_vp;
213554668Smckusick 		int  a_fflags;
213654668Smckusick 		struct ucred *a_cred;
213754668Smckusick 		struct proc *a_p;
213854668Smckusick 	} */ *ap;
213948054Smckusick {
214048054Smckusick 
214148054Smckusick 	return (EINVAL);
214248054Smckusick }
214348054Smckusick 
214448054Smckusick /*
214538884Smacklem  * Flush all the blocks associated with a vnode.
214638884Smacklem  * 	Walk through the buffer pool and push any dirty pages
214738884Smacklem  *	associated with the vnode.
214838884Smacklem  */
214939488Smckusick /* ARGSUSED */
215052234Sheideman int
215153806Smckusick nfs_fsync(ap)
215254451Smckusick 	struct vop_fsync_args /* {
215354451Smckusick 		struct vnodeop_desc *a_desc;
215454451Smckusick 		struct vnode * a_vp;
215554451Smckusick 		struct ucred * a_cred;
215654451Smckusick 		int  a_waitfor;
215754451Smckusick 		struct proc * a_p;
215854451Smckusick 	} */ *ap;
215938884Smacklem {
216054451Smckusick 	register struct vnode *vp = ap->a_vp;
216154451Smckusick 	register struct nfsnode *np = VTONFS(vp);
216254451Smckusick 	register struct buf *bp;
216354451Smckusick 	struct buf *nbp;
216454451Smckusick 	int s, error = 0;
216538884Smacklem 
216654451Smckusick loop:
216754451Smckusick 	s = splbio();
216854451Smckusick 	for (bp = vp->v_dirtyblkhd; bp; bp = nbp) {
216954451Smckusick 		nbp = bp->b_blockf;
217054451Smckusick 		if ((bp->b_flags & B_BUSY))
217154451Smckusick 			continue;
217254451Smckusick 		if ((bp->b_flags & B_DELWRI) == 0)
217354451Smckusick 			panic("nfs_fsync: not dirty");
217454451Smckusick 		bremfree(bp);
217554451Smckusick 		bp->b_flags |= B_BUSY;
217654451Smckusick 		splx(s);
217754451Smckusick 		error = bawrite(bp);
217854451Smckusick 		goto loop;
217938884Smacklem 	}
218054451Smckusick 	if (ap->a_waitfor == MNT_WAIT) {
218154451Smckusick 		while (vp->v_numoutput) {
218254451Smckusick 			vp->v_flag |= VBWAIT;
218354451Smckusick 			sleep((caddr_t)&vp->v_numoutput, PRIBIO + 1);
218454451Smckusick 		}
218554451Smckusick #ifdef DIAGNOSTIC
218654451Smckusick 		if (vp->v_dirtyblkhd) {
218754451Smckusick 			vprint("nfs_fsync: dirty", vp);
218854451Smckusick 			goto loop;
218954451Smckusick 		}
219054451Smckusick #endif
219154451Smckusick 	}
219254451Smckusick 	splx(s);
219354451Smckusick 	np->n_flag &= ~NMODIFIED;
219453629Smckusick 	if (np->n_flag & NWRITEERR) {
219539751Smckusick 		error = np->n_error;
219653629Smckusick 		np->n_flag &= ~NWRITEERR;
219753629Smckusick 	}
219838884Smacklem 	return (error);
219938884Smacklem }
220039672Smckusick 
220139672Smckusick /*
220246201Smckusick  * NFS advisory byte-level locks.
220346201Smckusick  * Currently unsupported.
220446201Smckusick  */
220552234Sheideman int
220653806Smckusick nfs_advlock(ap)
220754668Smckusick 	struct vop_advlock_args /* {
220854668Smckusick 		struct vnode *a_vp;
220954668Smckusick 		caddr_t  a_id;
221054668Smckusick 		int  a_op;
221154668Smckusick 		struct flock *a_fl;
221254668Smckusick 		int  a_flags;
221354668Smckusick 	} */ *ap;
221446201Smckusick {
221546201Smckusick 
221646201Smckusick 	return (EOPNOTSUPP);
221746201Smckusick }
221846201Smckusick 
221946201Smckusick /*
222039672Smckusick  * Print out the contents of an nfsnode.
222139672Smckusick  */
222252234Sheideman int
222353806Smckusick nfs_print(ap)
222454668Smckusick 	struct vop_print_args /* {
222554668Smckusick 		struct vnode *a_vp;
222654668Smckusick 	} */ *ap;
222739672Smckusick {
222853806Smckusick 	register struct vnode *vp = ap->a_vp;
222953806Smckusick 	register struct nfsnode *np = VTONFS(vp);
223039672Smckusick 
223140294Smckusick 	printf("tag VT_NFS, fileid %d fsid 0x%x",
223240294Smckusick 		np->n_vattr.va_fileid, np->n_vattr.va_fsid);
223340294Smckusick #ifdef FIFO
223453806Smckusick 	if (vp->v_type == VFIFO)
223553806Smckusick 		fifo_printinfo(vp);
223640294Smckusick #endif /* FIFO */
223739914Smckusick 	printf("\n");
223839672Smckusick }
223951573Smckusick 
224051573Smckusick /*
224151573Smckusick  * NFS directory offset lookup.
224251573Smckusick  * Currently unsupported.
224351573Smckusick  */
224452234Sheideman int
224553806Smckusick nfs_blkatoff(ap)
224654668Smckusick 	struct vop_blkatoff_args /* {
224754668Smckusick 		struct vnode *a_vp;
224854668Smckusick 		off_t a_offset;
224954668Smckusick 		char **a_res;
225054668Smckusick 		struct buf **a_bpp;
225154668Smckusick 	} */ *ap;
225251573Smckusick {
225351573Smckusick 
225451573Smckusick 	return (EOPNOTSUPP);
225551573Smckusick }
225651573Smckusick 
225751573Smckusick /*
225851573Smckusick  * NFS flat namespace allocation.
225951573Smckusick  * Currently unsupported.
226051573Smckusick  */
226152234Sheideman int
226253806Smckusick nfs_valloc(ap)
226354668Smckusick 	struct vop_valloc_args /* {
226454668Smckusick 		struct vnode *a_pvp;
226554668Smckusick 		int a_mode;
226654668Smckusick 		struct ucred *a_cred;
226754668Smckusick 		struct vnode **a_vpp;
226854668Smckusick 	} */ *ap;
226951573Smckusick {
227051573Smckusick 
227151573Smckusick 	return (EOPNOTSUPP);
227251573Smckusick }
227351573Smckusick 
227451573Smckusick /*
227551573Smckusick  * NFS flat namespace free.
227651573Smckusick  * Currently unsupported.
227751573Smckusick  */
227853582Sheideman int
227953806Smckusick nfs_vfree(ap)
228054668Smckusick 	struct vop_vfree_args /* {
228154668Smckusick 		struct vnode *a_pvp;
228254668Smckusick 		ino_t a_ino;
228354668Smckusick 		int a_mode;
228454668Smckusick 	} */ *ap;
228551573Smckusick {
228651573Smckusick 
228753582Sheideman 	return (EOPNOTSUPP);
228851573Smckusick }
228951573Smckusick 
229051573Smckusick /*
229151573Smckusick  * NFS file truncation.
229251573Smckusick  */
229352234Sheideman int
229453806Smckusick nfs_truncate(ap)
229554668Smckusick 	struct vop_truncate_args /* {
229654668Smckusick 		struct vnode *a_vp;
229754668Smckusick 		off_t a_length;
229854668Smckusick 		int a_flags;
229954668Smckusick 		struct ucred *a_cred;
230054668Smckusick 		struct proc *a_p;
230154668Smckusick 	} */ *ap;
230251573Smckusick {
230351573Smckusick 
230451573Smckusick 	/* Use nfs_setattr */
230551573Smckusick 	printf("nfs_truncate: need to implement!!");
230651573Smckusick 	return (EOPNOTSUPP);
230751573Smckusick }
230851573Smckusick 
230951573Smckusick /*
231051573Smckusick  * NFS update.
231151573Smckusick  */
231252234Sheideman int
231353806Smckusick nfs_update(ap)
231454668Smckusick 	struct vop_update_args /* {
231554668Smckusick 		struct vnode *a_vp;
231654668Smckusick 		struct timeval *a_ta;
231754668Smckusick 		struct timeval *a_tm;
231854668Smckusick 		int a_waitfor;
231954668Smckusick 	} */ *ap;
232051573Smckusick {
232151573Smckusick 
232251573Smckusick 	/* Use nfs_setattr */
232351573Smckusick 	printf("nfs_update: need to implement!!");
232451573Smckusick 	return (EOPNOTSUPP);
232551573Smckusick }
232653629Smckusick 
232753629Smckusick /*
2328*56364Smckusick  * nfs special file access vnode op.
2329*56364Smckusick  * Essentially just get vattr and then imitate iaccess() since the device is
2330*56364Smckusick  * local to the client.
2331*56364Smckusick  */
2332*56364Smckusick int
2333*56364Smckusick nfsspec_access(ap)
2334*56364Smckusick 	struct vop_access_args /* {
2335*56364Smckusick 		struct vnode *a_vp;
2336*56364Smckusick 		int  a_mode;
2337*56364Smckusick 		struct ucred *a_cred;
2338*56364Smckusick 		struct proc *a_p;
2339*56364Smckusick 	} */ *ap;
2340*56364Smckusick {
2341*56364Smckusick 	register struct vattr *vap;
2342*56364Smckusick 	register gid_t *gp;
2343*56364Smckusick 	register struct ucred *cred = ap->a_cred;
2344*56364Smckusick 	mode_t mode = ap->a_mode;
2345*56364Smckusick 	struct vattr vattr;
2346*56364Smckusick 	register int i;
2347*56364Smckusick 	int error;
2348*56364Smckusick 
2349*56364Smckusick 	/*
2350*56364Smckusick 	 * If you're the super-user,
2351*56364Smckusick 	 * you always get access.
2352*56364Smckusick 	 */
2353*56364Smckusick 	if (cred->cr_uid == 0)
2354*56364Smckusick 		return (0);
2355*56364Smckusick 	vap = &vattr;
2356*56364Smckusick 	if (error = VOP_GETATTR(ap->a_vp, vap, cred, ap->a_p))
2357*56364Smckusick 		return (error);
2358*56364Smckusick 	/*
2359*56364Smckusick 	 * Access check is based on only one of owner, group, public.
2360*56364Smckusick 	 * If not owner, then check group. If not a member of the
2361*56364Smckusick 	 * group, then check public access.
2362*56364Smckusick 	 */
2363*56364Smckusick 	if (cred->cr_uid != vap->va_uid) {
2364*56364Smckusick 		mode >>= 3;
2365*56364Smckusick 		gp = cred->cr_groups;
2366*56364Smckusick 		for (i = 0; i < cred->cr_ngroups; i++, gp++)
2367*56364Smckusick 			if (vap->va_gid == *gp)
2368*56364Smckusick 				goto found;
2369*56364Smckusick 		mode >>= 3;
2370*56364Smckusick found:
2371*56364Smckusick 		;
2372*56364Smckusick 	}
2373*56364Smckusick 	if ((vap->va_mode & mode) != 0)
2374*56364Smckusick 		return (0);
2375*56364Smckusick 	return (EACCES);
2376*56364Smckusick }
2377*56364Smckusick 
2378*56364Smckusick /*
237953629Smckusick  * Read wrapper for special devices.
238053629Smckusick  */
238153629Smckusick int
238253629Smckusick nfsspec_read(ap)
238354668Smckusick 	struct vop_read_args /* {
238454668Smckusick 		struct vnode *a_vp;
238554668Smckusick 		struct uio *a_uio;
238654668Smckusick 		int  a_ioflag;
238754668Smckusick 		struct ucred *a_cred;
238854668Smckusick 	} */ *ap;
238953629Smckusick {
239054032Smckusick 	register struct nfsnode *np = VTONFS(ap->a_vp);
239153629Smckusick 
239253629Smckusick 	/*
239353629Smckusick 	 * Set access flag.
239453629Smckusick 	 */
239554032Smckusick 	np->n_flag |= NACC;
239654032Smckusick 	np->n_atim = time;
239753629Smckusick 	return (VOCALL(spec_vnodeop_p, VOFFSET(vop_read), ap));
239853629Smckusick }
239953629Smckusick 
240053629Smckusick /*
240153629Smckusick  * Write wrapper for special devices.
240253629Smckusick  */
240353629Smckusick int
240453629Smckusick nfsspec_write(ap)
240554668Smckusick 	struct vop_write_args /* {
240654668Smckusick 		struct vnode *a_vp;
240754668Smckusick 		struct uio *a_uio;
240854668Smckusick 		int  a_ioflag;
240954668Smckusick 		struct ucred *a_cred;
241054668Smckusick 	} */ *ap;
241153629Smckusick {
241254032Smckusick 	register struct nfsnode *np = VTONFS(ap->a_vp);
241353629Smckusick 
241453629Smckusick 	/*
241554032Smckusick 	 * Set update flag.
241653629Smckusick 	 */
241754032Smckusick 	np->n_flag |= NUPD;
241854032Smckusick 	np->n_mtim = time;
241953629Smckusick 	return (VOCALL(spec_vnodeop_p, VOFFSET(vop_write), ap));
242053629Smckusick }
242153629Smckusick 
242253629Smckusick /*
242353629Smckusick  * Close wrapper for special devices.
242453629Smckusick  *
242553629Smckusick  * Update the times on the nfsnode then do device close.
242653629Smckusick  */
242753629Smckusick int
242853629Smckusick nfsspec_close(ap)
242954668Smckusick 	struct vop_close_args /* {
243054668Smckusick 		struct vnode *a_vp;
243154668Smckusick 		int  a_fflag;
243254668Smckusick 		struct ucred *a_cred;
243354668Smckusick 		struct proc *a_p;
243454668Smckusick 	} */ *ap;
243553629Smckusick {
243653806Smckusick 	register struct vnode *vp = ap->a_vp;
243753806Smckusick 	register struct nfsnode *np = VTONFS(vp);
243853629Smckusick 	struct vattr vattr;
243953629Smckusick 
244053629Smckusick 	if (np->n_flag & (NACC | NUPD)) {
244153629Smckusick 		np->n_flag |= NCHG;
244253806Smckusick 		if (vp->v_usecount == 1 &&
244353806Smckusick 		    (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) {
244453629Smckusick 			VATTR_NULL(&vattr);
244554106Smckusick 			if (np->n_flag & NACC) {
244654106Smckusick 				vattr.va_atime.ts_sec = np->n_atim.tv_sec;
244754106Smckusick 				vattr.va_atime.ts_nsec =
244854106Smckusick 				    np->n_atim.tv_usec * 1000;
244954106Smckusick 			}
245054106Smckusick 			if (np->n_flag & NUPD) {
245154106Smckusick 				vattr.va_mtime.ts_sec = np->n_mtim.tv_sec;
245254106Smckusick 				vattr.va_mtime.ts_nsec =
245354106Smckusick 				    np->n_mtim.tv_usec * 1000;
245454106Smckusick 			}
245553806Smckusick 			(void)VOP_SETATTR(vp, &vattr, ap->a_cred, ap->a_p);
245653629Smckusick 		}
245753629Smckusick 	}
245853629Smckusick 	return (VOCALL(spec_vnodeop_p, VOFFSET(vop_close), ap));
245953629Smckusick }
246053629Smckusick 
246153629Smckusick #ifdef FIFO
246253629Smckusick /*
246353629Smckusick  * Read wrapper for fifos.
246453629Smckusick  */
246553629Smckusick int
246653629Smckusick nfsfifo_read(ap)
246754668Smckusick 	struct vop_read_args /* {
246854668Smckusick 		struct vnode *a_vp;
246954668Smckusick 		struct uio *a_uio;
247054668Smckusick 		int  a_ioflag;
247154668Smckusick 		struct ucred *a_cred;
247254668Smckusick 	} */ *ap;
247353629Smckusick {
247453629Smckusick 	extern int (**fifo_vnodeop_p)();
247554032Smckusick 	register struct nfsnode *np = VTONFS(ap->a_vp);
247653629Smckusick 
247753629Smckusick 	/*
247853629Smckusick 	 * Set access flag.
247953629Smckusick 	 */
248054032Smckusick 	np->n_flag |= NACC;
248154032Smckusick 	np->n_atim = time;
248253629Smckusick 	return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_read), ap));
248353629Smckusick }
248453629Smckusick 
248553629Smckusick /*
248653629Smckusick  * Write wrapper for fifos.
248753629Smckusick  */
248853629Smckusick int
248953629Smckusick nfsfifo_write(ap)
249054668Smckusick 	struct vop_write_args /* {
249154668Smckusick 		struct vnode *a_vp;
249254668Smckusick 		struct uio *a_uio;
249354668Smckusick 		int  a_ioflag;
249454668Smckusick 		struct ucred *a_cred;
249554668Smckusick 	} */ *ap;
249653629Smckusick {
249753629Smckusick 	extern int (**fifo_vnodeop_p)();
249854032Smckusick 	register struct nfsnode *np = VTONFS(ap->a_vp);
249953629Smckusick 
250053629Smckusick 	/*
250153629Smckusick 	 * Set update flag.
250253629Smckusick 	 */
250354032Smckusick 	np->n_flag |= NUPD;
250454032Smckusick 	np->n_mtim = time;
250553629Smckusick 	return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_write), ap));
250653629Smckusick }
250753629Smckusick 
250853629Smckusick /*
250953629Smckusick  * Close wrapper for fifos.
251053629Smckusick  *
251153629Smckusick  * Update the times on the nfsnode then do fifo close.
251253629Smckusick  */
251353629Smckusick int
251453629Smckusick nfsfifo_close(ap)
251554668Smckusick 	struct vop_close_args /* {
251654668Smckusick 		struct vnode *a_vp;
251754668Smckusick 		int  a_fflag;
251854668Smckusick 		struct ucred *a_cred;
251954668Smckusick 		struct proc *a_p;
252054668Smckusick 	} */ *ap;
252153629Smckusick {
252253806Smckusick 	register struct vnode *vp = ap->a_vp;
252353806Smckusick 	register struct nfsnode *np = VTONFS(vp);
252453629Smckusick 	struct vattr vattr;
252553629Smckusick 	extern int (**fifo_vnodeop_p)();
252653629Smckusick 
252753629Smckusick 	if (np->n_flag & (NACC | NUPD)) {
252853629Smckusick 		if (np->n_flag & NACC)
252953629Smckusick 			np->n_atim = time;
253053629Smckusick 		if (np->n_flag & NUPD)
253153629Smckusick 			np->n_mtim = time;
253253629Smckusick 		np->n_flag |= NCHG;
253353806Smckusick 		if (vp->v_usecount == 1 &&
253453806Smckusick 		    (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) {
253553629Smckusick 			VATTR_NULL(&vattr);
253654106Smckusick 			if (np->n_flag & NACC) {
253754106Smckusick 				vattr.va_atime.ts_sec = np->n_atim.tv_sec;
253854106Smckusick 				vattr.va_atime.ts_nsec =
253954106Smckusick 				    np->n_atim.tv_usec * 1000;
254054106Smckusick 			}
254154106Smckusick 			if (np->n_flag & NUPD) {
254254106Smckusick 				vattr.va_mtime.ts_sec = np->n_mtim.tv_sec;
254354106Smckusick 				vattr.va_mtime.ts_nsec =
254454106Smckusick 				    np->n_mtim.tv_usec * 1000;
254554106Smckusick 			}
254653806Smckusick 			(void)VOP_SETATTR(vp, &vattr, ap->a_cred, ap->a_p);
254753629Smckusick 		}
254853629Smckusick 	}
254953629Smckusick 	return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_close), ap));
255053629Smckusick }
255153629Smckusick #endif /* FIFO */
2552