xref: /csrg-svn/sys/nfs/nfs_vnops.c (revision 56390)
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*56390Smckusick  *	@(#)nfs_vnops.c	7.94 (Berkeley) 10/02/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 */
11056364Smckusick 	{ &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 */
15856364Smckusick 	{ &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];
20456364Smckusick extern u_long nfs_prog, nfs_vers, nfs_true, nfs_false;
20538414Smckusick extern char nfsiobuf[MAXPHYS+NBPG];
20641905Smckusick struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON];
20746988Smckusick int nfs_numasync = 0;
208*56390Smckusick /* Queue head for nfsiod's */
209*56390Smckusick struct buf *nfs_bqueuehead;
210*56390Smckusick struct buf **nfs_bqueuetail = &nfs_bqueuehead;
21154740Smckusick #define	DIRHDSIZ	(sizeof (struct dirent) - (MAXNAMLEN + 1))
21238414Smckusick 
21338414Smckusick /*
21438414Smckusick  * nfs null call from vfs.
21538414Smckusick  */
21652234Sheideman int
21752196Smckusick nfs_null(vp, cred, procp)
21838414Smckusick 	struct vnode *vp;
21938414Smckusick 	struct ucred *cred;
22052196Smckusick 	struct proc *procp;
22138414Smckusick {
22239488Smckusick 	caddr_t bpos, dpos;
22339488Smckusick 	int error = 0;
22439488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb;
22538414Smckusick 
22652196Smckusick 	nfsm_reqhead(vp, NFSPROC_NULL, 0);
22752196Smckusick 	nfsm_request(vp, NFSPROC_NULL, procp, cred);
22838414Smckusick 	nfsm_reqdone;
22938414Smckusick 	return (error);
23038414Smckusick }
23138414Smckusick 
23238414Smckusick /*
23338414Smckusick  * nfs access vnode op.
23456364Smckusick  * For nfs, just return ok. File accesses may fail later.
23556364Smckusick  * For nqnfs, use the access rpc to check accessibility. If file modes are
23656364Smckusick  * changed on the server, accesses might still fail later.
23738414Smckusick  */
23852234Sheideman int
23953806Smckusick nfs_access(ap)
24054668Smckusick 	struct vop_access_args /* {
24154668Smckusick 		struct vnode *a_vp;
24254668Smckusick 		int  a_mode;
24354668Smckusick 		struct ucred *a_cred;
24454668Smckusick 		struct proc *a_p;
24554668Smckusick 	} */ *ap;
24638414Smckusick {
24756364Smckusick 	register struct vnode *vp = ap->a_vp;
24856364Smckusick 	register u_long *tl;
24956364Smckusick 	register caddr_t cp;
25056364Smckusick 	caddr_t bpos, dpos;
25156364Smckusick 	int error = 0;
25256364Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
25338414Smckusick 
25438414Smckusick 	/*
25556364Smckusick 	 * There is no way to check accessibility via. ordinary nfs, so if
25656364Smckusick 	 * access isn't allowed they will get burned later.
25738414Smckusick 	 */
25856364Smckusick 	if (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) {
25956364Smckusick 		nfsstats.rpccnt[NQNFSPROC_ACCESS]++;
26056364Smckusick 		nfsm_reqhead(vp, NQNFSPROC_ACCESS, NFSX_FH + 3 * NFSX_UNSIGNED);
26156364Smckusick 		nfsm_fhtom(vp);
26256364Smckusick 		nfsm_build(tl, u_long *, 3 * NFSX_UNSIGNED);
26356364Smckusick 		if (ap->a_mode & VREAD)
26456364Smckusick 			*tl++ = nfs_true;
26556364Smckusick 		else
26656364Smckusick 			*tl++ = nfs_false;
26756364Smckusick 		if (ap->a_mode & VWRITE)
26856364Smckusick 			*tl++ = nfs_true;
26956364Smckusick 		else
27056364Smckusick 			*tl++ = nfs_false;
27156364Smckusick 		if (ap->a_mode & VEXEC)
27256364Smckusick 			*tl = nfs_true;
27356364Smckusick 		else
27456364Smckusick 			*tl = nfs_false;
27556364Smckusick 		nfsm_request(vp, NQNFSPROC_ACCESS, ap->a_p, ap->a_cred);
27656364Smckusick 		nfsm_reqdone;
27738884Smacklem 		return (error);
27856364Smckusick 	} else
27938414Smckusick 		return (0);
28038414Smckusick }
28138414Smckusick 
28238414Smckusick /*
28338414Smckusick  * nfs open vnode op
28456289Smckusick  * Check to see if the type is ok
28552196Smckusick  * and that deletion is not in progress.
28656289Smckusick  * For paged in text files, you will need to flush the page cache
28756289Smckusick  * if consistency is lost.
28838414Smckusick  */
28939488Smckusick /* ARGSUSED */
29052234Sheideman int
29153806Smckusick nfs_open(ap)
29254668Smckusick 	struct vop_open_args /* {
29354668Smckusick 		struct vnode *a_vp;
29454668Smckusick 		int  a_mode;
29554668Smckusick 		struct ucred *a_cred;
29654668Smckusick 		struct proc *a_p;
29754668Smckusick 	} */ *ap;
29838414Smckusick {
29953806Smckusick 	register struct vnode *vp = ap->a_vp;
30056289Smckusick 	struct nfsnode *np = VTONFS(vp);
30156289Smckusick 	struct nfsmount *nmp = VFSTONFS(vp->v_mount);
30256289Smckusick 	struct vattr vattr;
30356289Smckusick 	int error;
30438414Smckusick 
30553806Smckusick 	if (vp->v_type != VREG && vp->v_type != VDIR && vp->v_type != VLNK)
30638414Smckusick 		return (EACCES);
30756289Smckusick 	if (vp->v_flag & VTEXT) {
30856289Smckusick 	    /*
30956289Smckusick 	     * Get a valid lease. If cached data is stale, flush it.
31056289Smckusick 	     */
31156289Smckusick 	    if (nmp->nm_flag & NFSMNT_NQNFS) {
31256289Smckusick 		if (NQNFS_CKINVALID(vp, np, NQL_READ)) {
31356289Smckusick 		    do {
31456289Smckusick 			error = nqnfs_getlease(vp, NQL_READ, ap->a_cred, ap->a_p);
31556289Smckusick 		    } while (error == NQNFS_EXPIRED);
31656289Smckusick 		    if (error)
31756289Smckusick 			return (error);
31856289Smckusick 		    if (np->n_lrev != np->n_brev) {
31956289Smckusick 			np->n_flag &= ~NMODIFIED;
32056289Smckusick 			vinvalbuf(vp, TRUE, ap->a_cred, ap->a_p);
32156289Smckusick 			(void) vnode_pager_uncache(vp);
32256289Smckusick 			np->n_brev = np->n_lrev;
32356289Smckusick 		    }
32456289Smckusick 		}
32556289Smckusick 	    } else {
32656289Smckusick 		if (np->n_flag & NMODIFIED) {
32756289Smckusick 			np->n_flag &= ~NMODIFIED;
32856289Smckusick 			vinvalbuf(vp, TRUE, ap->a_cred, ap->a_p);
32956289Smckusick 			(void) vnode_pager_uncache(vp);
33056289Smckusick 			np->n_attrstamp = 0;
33156289Smckusick 			np->n_direofoffset = 0;
33256289Smckusick 			if (error = VOP_GETATTR(vp, &vattr, ap->a_cred, ap->a_p))
33356289Smckusick 				return (error);
33456289Smckusick 			np->n_mtime = vattr.va_mtime.ts_sec;
33556289Smckusick 		} else {
33656289Smckusick 			if (error = VOP_GETATTR(vp, &vattr, ap->a_cred, ap->a_p))
33756289Smckusick 				return (error);
33856289Smckusick 			if (np->n_mtime != vattr.va_mtime.ts_sec) {
33956289Smckusick 				np->n_direofoffset = 0;
34056289Smckusick 				vinvalbuf(vp, TRUE, ap->a_cred, ap->a_p);
34156289Smckusick 				(void) vnode_pager_uncache(vp);
34256289Smckusick 				np->n_mtime = vattr.va_mtime.ts_sec;
34356289Smckusick 			}
34456289Smckusick 		}
34556289Smckusick 	    }
34656289Smckusick 	} else if ((nmp->nm_flag & NFSMNT_NQNFS) == 0)
34756289Smckusick 		np->n_attrstamp = 0; /* For Open/Close consistency */
34852196Smckusick 	return (0);
34938414Smckusick }
35038414Smckusick 
35138414Smckusick /*
35238414Smckusick  * nfs close vnode op
35338884Smacklem  * For reg files, invalidate any buffer cache entries.
35438414Smckusick  */
35539488Smckusick /* ARGSUSED */
35652234Sheideman int
35753806Smckusick nfs_close(ap)
35854451Smckusick 	struct vop_close_args /* {
35954451Smckusick 		struct vnodeop_desc *a_desc;
36054451Smckusick 		struct vnode *a_vp;
36154451Smckusick 		int  a_fflag;
36254451Smckusick 		struct ucred *a_cred;
36354451Smckusick 		struct proc *a_p;
36454451Smckusick 	} */ *ap;
36538414Smckusick {
36653806Smckusick 	register struct vnode *vp = ap->a_vp;
36753806Smckusick 	register struct nfsnode *np = VTONFS(vp);
36839341Smckusick 	int error = 0;
36938414Smckusick 
37053806Smckusick 	if (vp->v_type == VREG) {
37153806Smckusick 	    if ((VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) == 0 &&
37253629Smckusick 		(np->n_flag & NMODIFIED)) {
37354451Smckusick 		error = vinvalbuf(vp, TRUE, ap->a_cred, ap->a_p);
37441905Smckusick 		np->n_flag &= ~NMODIFIED;
37541905Smckusick 		np->n_attrstamp = 0;
37653629Smckusick 	    }
37753629Smckusick 	    if (np->n_flag & NWRITEERR) {
37853629Smckusick 		np->n_flag &= ~NWRITEERR;
37953629Smckusick 		error = np->n_error;
38053629Smckusick 	    }
38138884Smacklem 	}
38238414Smckusick 	return (error);
38338414Smckusick }
38438414Smckusick 
38538414Smckusick /*
38638414Smckusick  * nfs getattr call from vfs.
38738414Smckusick  */
38852234Sheideman int
38953805Smckusick nfs_getattr(ap)
39054668Smckusick 	struct vop_getattr_args /* {
39154668Smckusick 		struct vnode *a_vp;
39254668Smckusick 		struct vattr *a_vap;
39354668Smckusick 		struct ucred *a_cred;
39454668Smckusick 		struct proc *a_p;
39554668Smckusick 	} */ *ap;
39638414Smckusick {
39753805Smckusick 	register struct vnode *vp = ap->a_vp;
39853805Smckusick 	register struct nfsnode *np = VTONFS(vp);
39939488Smckusick 	register caddr_t cp;
40039488Smckusick 	caddr_t bpos, dpos;
40139488Smckusick 	int error = 0;
40239488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
40338414Smckusick 
40453805Smckusick 	/*
40553805Smckusick 	 * Update local times for special files.
40653805Smckusick 	 */
40756329Smckusick 	if (np->n_flag & (NACC | NUPD))
40853805Smckusick 		np->n_flag |= NCHG;
40953805Smckusick 	/*
41053805Smckusick 	 * First look in the cache.
41153805Smckusick 	 */
41253805Smckusick 	if (nfs_getattrcache(vp, ap->a_vap) == 0)
41338414Smckusick 		return (0);
41438414Smckusick 	nfsstats.rpccnt[NFSPROC_GETATTR]++;
41553805Smckusick 	nfsm_reqhead(vp, NFSPROC_GETATTR, NFSX_FH);
41653805Smckusick 	nfsm_fhtom(vp);
41753805Smckusick 	nfsm_request(vp, NFSPROC_GETATTR, ap->a_p, ap->a_cred);
41853805Smckusick 	nfsm_loadattr(vp, ap->a_vap);
41938414Smckusick 	nfsm_reqdone;
42038414Smckusick 	return (error);
42138414Smckusick }
42238414Smckusick 
42338414Smckusick /*
42438414Smckusick  * nfs setattr call.
42538414Smckusick  */
42652234Sheideman int
42753806Smckusick nfs_setattr(ap)
42854451Smckusick 	struct vop_setattr_args /* {
42954451Smckusick 		struct vnodeop_desc *a_desc;
43054451Smckusick 		struct vnode *a_vp;
43154451Smckusick 		struct vattr *a_vap;
43254451Smckusick 		struct ucred *a_cred;
43354451Smckusick 		struct proc *a_p;
43454451Smckusick 	} */ *ap;
43538414Smckusick {
43638884Smacklem 	register struct nfsv2_sattr *sp;
43739488Smckusick 	register caddr_t cp;
43839488Smckusick 	register long t1;
43952196Smckusick 	caddr_t bpos, dpos, cp2;
44052196Smckusick 	u_long *tl;
44156289Smckusick 	int error = 0, isnq;
44239488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
44353806Smckusick 	register struct vnode *vp = ap->a_vp;
44453806Smckusick 	register struct nfsnode *np = VTONFS(vp);
44553806Smckusick 	register struct vattr *vap = ap->a_vap;
44652196Smckusick 	u_quad_t frev;
44738414Smckusick 
44838414Smckusick 	nfsstats.rpccnt[NFSPROC_SETATTR]++;
44956289Smckusick 	isnq = (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS);
45056289Smckusick 	nfsm_reqhead(vp, NFSPROC_SETATTR, NFSX_FH+NFSX_SATTR(isnq));
45153806Smckusick 	nfsm_fhtom(vp);
45256289Smckusick 	nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR(isnq));
45356289Smckusick 	if (vap->va_mode == (u_short)-1)
45438884Smacklem 		sp->sa_mode = VNOVAL;
45538414Smckusick 	else
45653806Smckusick 		sp->sa_mode = vtonfs_mode(vp->v_type, vap->va_mode);
45756289Smckusick 	if (vap->va_uid == (uid_t)-1)
45838884Smacklem 		sp->sa_uid = VNOVAL;
45938414Smckusick 	else
46053806Smckusick 		sp->sa_uid = txdr_unsigned(vap->va_uid);
46156289Smckusick 	if (vap->va_gid == (gid_t)-1)
46238884Smacklem 		sp->sa_gid = VNOVAL;
46338414Smckusick 	else
46453806Smckusick 		sp->sa_gid = txdr_unsigned(vap->va_gid);
46556289Smckusick 	if (isnq) {
46656289Smckusick 		txdr_hyper(&vap->va_size, &sp->sa_nqsize);
46756289Smckusick 		txdr_nqtime(&vap->va_atime, &sp->sa_nqatime);
46856289Smckusick 		txdr_nqtime(&vap->va_mtime, &sp->sa_nqmtime);
46956289Smckusick 		sp->sa_nqflags = txdr_unsigned(vap->va_flags);
47056289Smckusick 		sp->sa_nqrdev = VNOVAL;
47156289Smckusick 	} else {
47256289Smckusick 		sp->sa_nfssize = txdr_unsigned(vap->va_size);
47356289Smckusick 		sp->sa_nfsatime.nfs_sec = txdr_unsigned(vap->va_atime.ts_sec);
47456289Smckusick 		sp->sa_nfsatime.nfs_usec = txdr_unsigned(vap->va_flags);
47556289Smckusick 		txdr_nfstime(&vap->va_mtime, &sp->sa_nfsmtime);
47656289Smckusick 	}
47754106Smckusick 	if (vap->va_size != VNOVAL || vap->va_mtime.ts_sec != VNOVAL ||
47854106Smckusick 	    vap->va_atime.ts_sec != VNOVAL) {
47939359Smckusick 		if (np->n_flag & NMODIFIED) {
48053806Smckusick 			if (vap->va_size == 0)
48154451Smckusick 				error =
48254451Smckusick 				    vinvalbuf(vp, FALSE, ap->a_cred, ap->a_p);
48346988Smckusick 			else
48454451Smckusick 				error =
48554451Smckusick 				    vinvalbuf(vp, TRUE, ap->a_cred, ap->a_p);
48654451Smckusick 			np->n_flag &= ~NMODIFIED;
48739359Smckusick 		}
48856289Smckusick 		if (vap->va_size != VNOVAL)
48956289Smckusick 			np->n_size = np->n_vattr.va_size = vap->va_size;
49039359Smckusick 	}
49153806Smckusick 	nfsm_request(vp, NFSPROC_SETATTR, ap->a_p, ap->a_cred);
49253806Smckusick 	nfsm_loadattr(vp, (struct vattr *)0);
49353806Smckusick 	if ((VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) &&
49453806Smckusick 	    NQNFS_CKCACHABLE(vp, NQL_WRITE)) {
49552196Smckusick 		nfsm_dissect(tl, u_long *, 2*NFSX_UNSIGNED);
49652196Smckusick 		fxdr_hyper(tl, &frev);
49754451Smckusick 		if (frev > np->n_brev)
49852196Smckusick 			np->n_brev = frev;
49952196Smckusick 	}
50038414Smckusick 	nfsm_reqdone;
50138414Smckusick 	return (error);
50238414Smckusick }
50338414Smckusick 
50438414Smckusick /*
50538414Smckusick  * nfs lookup call, one step at a time...
50638414Smckusick  * First look in cache
50738414Smckusick  * If not found, unlock the directory nfsnode and do the rpc
50838414Smckusick  */
50952234Sheideman int
51053806Smckusick nfs_lookup(ap)
51154451Smckusick 	struct vop_lookup_args /* {
51254451Smckusick 		struct vnodeop_desc *a_desc;
51354451Smckusick 		struct vnode *a_dvp;
51454451Smckusick 		struct vnode **a_vpp;
51554451Smckusick 		struct componentname *a_cnp;
51654451Smckusick 	} */ *ap;
51738414Smckusick {
51853806Smckusick 	register struct componentname *cnp = ap->a_cnp;
51953806Smckusick 	register struct vnode *dvp = ap->a_dvp;
52054668Smckusick 	register struct vnode **vpp = ap->a_vpp;
52155184Smckusick 	register int flags = cnp->cn_flags;
52238414Smckusick 	register struct vnode *vdp;
52348054Smckusick 	register u_long *tl;
52439488Smckusick 	register caddr_t cp;
52539488Smckusick 	register long t1, t2;
52652196Smckusick 	struct nfsmount *nmp;
52752196Smckusick 	struct nfsnode *tp;
52839488Smckusick 	caddr_t bpos, dpos, cp2;
52952196Smckusick 	time_t reqtime;
53039488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
53138414Smckusick 	struct vnode *newvp;
53238414Smckusick 	long len;
53338414Smckusick 	nfsv2fh_t *fhp;
53438414Smckusick 	struct nfsnode *np;
53552234Sheideman 	int lockparent, wantparent, error = 0;
53652196Smckusick 	int nqlflag, cachable;
53752196Smckusick 	u_quad_t frev;
53838414Smckusick 
53954668Smckusick 	*vpp = NULL;
54053806Smckusick 	if (dvp->v_type != VDIR)
54138414Smckusick 		return (ENOTDIR);
54255184Smckusick 	lockparent = flags & LOCKPARENT;
54355184Smckusick 	wantparent = flags & (LOCKPARENT|WANTPARENT);
54453806Smckusick 	nmp = VFSTONFS(dvp->v_mount);
54553806Smckusick 	np = VTONFS(dvp);
54654668Smckusick 	if ((error = cache_lookup(dvp, vpp, cnp)) && error != ENOENT) {
54738884Smacklem 		struct vattr vattr;
54838884Smacklem 		int vpid;
54938884Smacklem 
55054668Smckusick 		vdp = *vpp;
55138884Smacklem 		vpid = vdp->v_id;
55238414Smckusick 		/*
55338884Smacklem 		 * See the comment starting `Step through' in ufs/ufs_lookup.c
55438884Smacklem 		 * for an explanation of the locking protocol
55538414Smckusick 		 */
55653806Smckusick 		if (dvp == vdp) {
55738425Smckusick 			VREF(vdp);
55839441Smckusick 			error = 0;
55952196Smckusick 		} else
56039441Smckusick 			error = vget(vdp);
56139441Smckusick 		if (!error) {
56240251Smckusick 			if (vpid == vdp->v_id) {
56352196Smckusick 			   if (nmp->nm_flag & NFSMNT_NQNFS) {
56456289Smckusick 				if ((nmp->nm_flag & NFSMNT_NQLOOKLEASE) == 0) {
56556289Smckusick 					nfsstats.lookupcache_hits++;
56656289Smckusick 					if (cnp->cn_nameiop != LOOKUP &&
56756289Smckusick 					    (flags & ISLASTCN))
56856289Smckusick 					    cnp->cn_flags |= SAVENAME;
56956289Smckusick 					return (0);
57056289Smckusick 			        } else if (NQNFS_CKCACHABLE(dvp, NQL_READ)) {
57154451Smckusick 					if (np->n_lrev != np->n_brev ||
57252196Smckusick 					    (np->n_flag & NMODIFIED)) {
57352196Smckusick 						np->n_direofoffset = 0;
57453806Smckusick 						cache_purge(dvp);
57554451Smckusick 						error = vinvalbuf(dvp, FALSE,
57654451Smckusick 						    cnp->cn_cred, cnp->cn_proc);
57752196Smckusick 						np->n_flag &= ~NMODIFIED;
57852196Smckusick 						np->n_brev = np->n_lrev;
57952196Smckusick 					} else {
58052196Smckusick 						nfsstats.lookupcache_hits++;
58153806Smckusick 						if (cnp->cn_nameiop != LOOKUP &&
58255184Smckusick 						    (flags & ISLASTCN))
58353806Smckusick 						    cnp->cn_flags |= SAVENAME;
58452196Smckusick 						return (0);
58552196Smckusick 					}
58652196Smckusick 				}
58753806Smckusick 			   } else if (!VOP_GETATTR(vdp, &vattr, cnp->cn_cred, cnp->cn_proc) &&
58854106Smckusick 			       vattr.va_ctime.ts_sec == VTONFS(vdp)->n_ctime) {
58939441Smckusick 				nfsstats.lookupcache_hits++;
59053806Smckusick 				if (cnp->cn_nameiop != LOOKUP &&
59155184Smckusick 				    (flags & ISLASTCN))
59253806Smckusick 					cnp->cn_flags |= SAVENAME;
59339441Smckusick 				return (0);
59440251Smckusick 			   }
59547289Smckusick 			   cache_purge(vdp);
59639441Smckusick 			}
59752196Smckusick 			vrele(vdp);
59838884Smacklem 		}
59954668Smckusick 		*vpp = NULLVP;
60052196Smckusick 	}
60139341Smckusick 	error = 0;
60238414Smckusick 	nfsstats.lookupcache_misses++;
60338414Smckusick 	nfsstats.rpccnt[NFSPROC_LOOKUP]++;
60453806Smckusick 	len = cnp->cn_namelen;
60553806Smckusick 	nfsm_reqhead(dvp, NFSPROC_LOOKUP, NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len));
60652196Smckusick 
60752196Smckusick 	/*
60852196Smckusick 	 * For nqnfs optionally piggyback a getlease request for the name
60952196Smckusick 	 * being looked up.
61052196Smckusick 	 */
61152196Smckusick 	if (nmp->nm_flag & NFSMNT_NQNFS) {
61256289Smckusick 		nfsm_build(tl, u_long *, NFSX_UNSIGNED);
61352196Smckusick 		if ((nmp->nm_flag & NFSMNT_NQLOOKLEASE) &&
61455184Smckusick 		    ((cnp->cn_flags & MAKEENTRY) &&
61556289Smckusick 		    (cnp->cn_nameiop != DELETE || !(flags & ISLASTCN))))
61652196Smckusick 			*tl = txdr_unsigned(nmp->nm_leaseterm);
61756289Smckusick 		else
61852196Smckusick 			*tl = 0;
61952196Smckusick 	}
62053806Smckusick 	nfsm_fhtom(dvp);
62153806Smckusick 	nfsm_strtom(cnp->cn_nameptr, len, NFS_MAXNAMLEN);
62252196Smckusick 	reqtime = time.tv_sec;
62353806Smckusick 	nfsm_request(dvp, NFSPROC_LOOKUP, cnp->cn_proc, cnp->cn_cred);
62438414Smckusick nfsmout:
62538414Smckusick 	if (error) {
62653806Smckusick 		if ((cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME) &&
62755184Smckusick 		    (flags & ISLASTCN) && error == ENOENT)
62852823Smckusick 			error = EJUSTRETURN;
62955184Smckusick 		if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN))
63053806Smckusick 			cnp->cn_flags |= SAVENAME;
63140483Smckusick 		return (error);
63238414Smckusick 	}
63352196Smckusick 	if (nmp->nm_flag & NFSMNT_NQNFS) {
63452196Smckusick 		nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
63552196Smckusick 		if (*tl) {
63652196Smckusick 			nqlflag = fxdr_unsigned(int, *tl);
63752196Smckusick 			nfsm_dissect(tl, u_long *, 4*NFSX_UNSIGNED);
63852196Smckusick 			cachable = fxdr_unsigned(int, *tl++);
63952196Smckusick 			reqtime += fxdr_unsigned(int, *tl++);
64052196Smckusick 			fxdr_hyper(tl, &frev);
64152196Smckusick 		} else
64252196Smckusick 			nqlflag = 0;
64352196Smckusick 	}
64452196Smckusick 	nfsm_dissect(fhp, nfsv2fh_t *, NFSX_FH);
64538414Smckusick 
64638414Smckusick 	/*
64752196Smckusick 	 * Handle RENAME case...
64838414Smckusick 	 */
64955184Smckusick 	if (cnp->cn_nameiop == RENAME && wantparent && (flags & ISLASTCN)) {
65052196Smckusick 		if (!bcmp(np->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) {
65138414Smckusick 			m_freem(mrep);
65238414Smckusick 			return (EISDIR);
65338414Smckusick 		}
65453806Smckusick 		if (error = nfs_nget(dvp->v_mount, fhp, &np)) {
65538414Smckusick 			m_freem(mrep);
65638414Smckusick 			return (error);
65738414Smckusick 		}
65838414Smckusick 		newvp = NFSTOV(np);
65939459Smckusick 		if (error =
66039459Smckusick 		    nfs_loadattrcache(&newvp, &md, &dpos, (struct vattr *)0)) {
66152196Smckusick 			vrele(newvp);
66238414Smckusick 			m_freem(mrep);
66338414Smckusick 			return (error);
66438414Smckusick 		}
66554668Smckusick 		*vpp = newvp;
66645037Smckusick 		m_freem(mrep);
66753806Smckusick 		cnp->cn_flags |= SAVENAME;
66838414Smckusick 		return (0);
66938414Smckusick 	}
67038414Smckusick 
67152196Smckusick 	if (!bcmp(np->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) {
67253806Smckusick 		VREF(dvp);
67353806Smckusick 		newvp = dvp;
67438414Smckusick 	} else {
67553806Smckusick 		if (error = nfs_nget(dvp->v_mount, fhp, &np)) {
67638414Smckusick 			m_freem(mrep);
67738414Smckusick 			return (error);
67838414Smckusick 		}
67938414Smckusick 		newvp = NFSTOV(np);
68038414Smckusick 	}
68139459Smckusick 	if (error = nfs_loadattrcache(&newvp, &md, &dpos, (struct vattr *)0)) {
68252196Smckusick 		vrele(newvp);
68338414Smckusick 		m_freem(mrep);
68438414Smckusick 		return (error);
68538414Smckusick 	}
68638414Smckusick 	m_freem(mrep);
68754668Smckusick 	*vpp = newvp;
68855184Smckusick 	if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN))
68953806Smckusick 		cnp->cn_flags |= SAVENAME;
69055184Smckusick 	if ((cnp->cn_flags & MAKEENTRY) &&
69155184Smckusick 	    (cnp->cn_nameiop != DELETE || !(flags & ISLASTCN))) {
69252196Smckusick 		if ((nmp->nm_flag & NFSMNT_NQNFS) == 0)
69354106Smckusick 			np->n_ctime = np->n_vattr.va_ctime.ts_sec;
69456289Smckusick 		else if (nqlflag && reqtime > time.tv_sec)
69556289Smckusick 			nqnfs_clientlease(nmp, np, nqlflag, cachable, reqtime,
69656289Smckusick 				frev);
69754668Smckusick 		cache_enter(dvp, *vpp, cnp);
69840251Smckusick 	}
69952196Smckusick 	return (0);
70038414Smckusick }
70138414Smckusick 
70238414Smckusick /*
70341905Smckusick  * nfs read call.
70441905Smckusick  * Just call nfs_bioread() to do the work.
70541905Smckusick  */
70652234Sheideman int
70753806Smckusick nfs_read(ap)
70854668Smckusick 	struct vop_read_args /* {
70954668Smckusick 		struct vnode *a_vp;
71054668Smckusick 		struct uio *a_uio;
71154668Smckusick 		int  a_ioflag;
71254668Smckusick 		struct ucred *a_cred;
71354668Smckusick 	} */ *ap;
71441905Smckusick {
71553806Smckusick 	register struct vnode *vp = ap->a_vp;
71653806Smckusick 
71753806Smckusick 	if (vp->v_type != VREG)
71841905Smckusick 		return (EPERM);
71953806Smckusick 	return (nfs_bioread(vp, ap->a_uio, ap->a_ioflag, ap->a_cred));
72041905Smckusick }
72141905Smckusick 
72241905Smckusick /*
72338414Smckusick  * nfs readlink call
72438414Smckusick  */
72552234Sheideman int
72653806Smckusick nfs_readlink(ap)
72754668Smckusick 	struct vop_readlink_args /* {
72854668Smckusick 		struct vnode *a_vp;
72954668Smckusick 		struct uio *a_uio;
73054668Smckusick 		struct ucred *a_cred;
73154668Smckusick 	} */ *ap;
73241905Smckusick {
73353806Smckusick 	register struct vnode *vp = ap->a_vp;
73453806Smckusick 
73553806Smckusick 	if (vp->v_type != VLNK)
73641905Smckusick 		return (EPERM);
73753806Smckusick 	return (nfs_bioread(vp, ap->a_uio, 0, ap->a_cred));
73841905Smckusick }
73941905Smckusick 
74041905Smckusick /*
74141905Smckusick  * Do a readlink rpc.
74241905Smckusick  * Called by nfs_doio() from below the buffer cache.
74341905Smckusick  */
74452234Sheideman int
74548054Smckusick nfs_readlinkrpc(vp, uiop, cred)
74639488Smckusick 	register struct vnode *vp;
74738414Smckusick 	struct uio *uiop;
74838414Smckusick 	struct ucred *cred;
74938414Smckusick {
75048054Smckusick 	register u_long *tl;
75139488Smckusick 	register caddr_t cp;
75239488Smckusick 	register long t1;
75339488Smckusick 	caddr_t bpos, dpos, cp2;
75439488Smckusick 	int error = 0;
75539488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
75638414Smckusick 	long len;
75738414Smckusick 
75838414Smckusick 	nfsstats.rpccnt[NFSPROC_READLINK]++;
75952196Smckusick 	nfsm_reqhead(vp, NFSPROC_READLINK, NFSX_FH);
76038414Smckusick 	nfsm_fhtom(vp);
76152196Smckusick 	nfsm_request(vp, NFSPROC_READLINK, uiop->uio_procp, cred);
76238414Smckusick 	nfsm_strsiz(len, NFS_MAXPATHLEN);
76338414Smckusick 	nfsm_mtouio(uiop, len);
76438414Smckusick 	nfsm_reqdone;
76538414Smckusick 	return (error);
76638414Smckusick }
76738414Smckusick 
76838414Smckusick /*
76941905Smckusick  * nfs read rpc call
77041905Smckusick  * Ditto above
77138414Smckusick  */
77252234Sheideman int
77348054Smckusick nfs_readrpc(vp, uiop, cred)
77439488Smckusick 	register struct vnode *vp;
77538414Smckusick 	struct uio *uiop;
77638414Smckusick 	struct ucred *cred;
77738414Smckusick {
77848054Smckusick 	register u_long *tl;
77939488Smckusick 	register caddr_t cp;
78039488Smckusick 	register long t1;
78139488Smckusick 	caddr_t bpos, dpos, cp2;
78239488Smckusick 	int error = 0;
78339488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
78438414Smckusick 	struct nfsmount *nmp;
78538414Smckusick 	long len, retlen, tsiz;
78638414Smckusick 
78741398Smckusick 	nmp = VFSTONFS(vp->v_mount);
78838414Smckusick 	tsiz = uiop->uio_resid;
78956289Smckusick 	if (uiop->uio_offset + tsiz > 0xffffffff &&
79056289Smckusick 	    (nmp->nm_flag & NFSMNT_NQNFS) == 0)
79156289Smckusick 		return (EFBIG);
79238414Smckusick 	while (tsiz > 0) {
79338414Smckusick 		nfsstats.rpccnt[NFSPROC_READ]++;
79438414Smckusick 		len = (tsiz > nmp->nm_rsize) ? nmp->nm_rsize : tsiz;
79552196Smckusick 		nfsm_reqhead(vp, NFSPROC_READ, NFSX_FH+NFSX_UNSIGNED*3);
79638414Smckusick 		nfsm_fhtom(vp);
79748054Smckusick 		nfsm_build(tl, u_long *, NFSX_UNSIGNED*3);
79856289Smckusick 		if (nmp->nm_flag & NFSMNT_NQNFS) {
79956289Smckusick 			txdr_hyper(&uiop->uio_offset, tl);
80056289Smckusick 			*(tl + 2) = txdr_unsigned(len);
80156289Smckusick 		} else {
80256289Smckusick 			*tl++ = txdr_unsigned(uiop->uio_offset);
80356289Smckusick 			*tl++ = txdr_unsigned(len);
80456289Smckusick 			*tl = 0;
80556289Smckusick 		}
80652196Smckusick 		nfsm_request(vp, NFSPROC_READ, uiop->uio_procp, cred);
80738414Smckusick 		nfsm_loadattr(vp, (struct vattr *)0);
80838414Smckusick 		nfsm_strsiz(retlen, nmp->nm_rsize);
80938414Smckusick 		nfsm_mtouio(uiop, retlen);
81038414Smckusick 		m_freem(mrep);
81138414Smckusick 		if (retlen < len)
81238414Smckusick 			tsiz = 0;
81338414Smckusick 		else
81438414Smckusick 			tsiz -= len;
81538414Smckusick 	}
81638414Smckusick nfsmout:
81738414Smckusick 	return (error);
81838414Smckusick }
81938414Smckusick 
82038414Smckusick /*
82138414Smckusick  * nfs write call
82238414Smckusick  */
82352234Sheideman int
82456289Smckusick nfs_writerpc(vp, uiop, cred, ioflags)
82539488Smckusick 	register struct vnode *vp;
82638414Smckusick 	struct uio *uiop;
82738414Smckusick 	struct ucred *cred;
82856289Smckusick 	int ioflags;
82938414Smckusick {
83048054Smckusick 	register u_long *tl;
83139488Smckusick 	register caddr_t cp;
83239488Smckusick 	register long t1;
83352196Smckusick 	caddr_t bpos, dpos, cp2;
83439488Smckusick 	int error = 0;
83539488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
83638414Smckusick 	struct nfsmount *nmp;
83752196Smckusick 	struct nfsnode *np = VTONFS(vp);
83852196Smckusick 	u_quad_t frev;
83938414Smckusick 	long len, tsiz;
84038414Smckusick 
84141398Smckusick 	nmp = VFSTONFS(vp->v_mount);
84238414Smckusick 	tsiz = uiop->uio_resid;
84356289Smckusick 	if (uiop->uio_offset + tsiz > 0xffffffff &&
84456289Smckusick 	    (nmp->nm_flag & NFSMNT_NQNFS) == 0)
84556289Smckusick 		return (EFBIG);
84638414Smckusick 	while (tsiz > 0) {
84738414Smckusick 		nfsstats.rpccnt[NFSPROC_WRITE]++;
84838414Smckusick 		len = (tsiz > nmp->nm_wsize) ? nmp->nm_wsize : tsiz;
84952196Smckusick 		nfsm_reqhead(vp, NFSPROC_WRITE,
85052196Smckusick 			NFSX_FH+NFSX_UNSIGNED*4+nfsm_rndup(len));
85138414Smckusick 		nfsm_fhtom(vp);
85256289Smckusick 		nfsm_build(tl, u_long *, NFSX_UNSIGNED * 4);
85356289Smckusick 		if (nmp->nm_flag & NFSMNT_NQNFS) {
85456289Smckusick 			txdr_hyper(&uiop->uio_offset, tl);
85556289Smckusick 			tl += 2;
85656289Smckusick 			if (ioflags & IO_APPEND)
85756289Smckusick 				*tl++ = txdr_unsigned(1);
85856289Smckusick 			else
85956289Smckusick 				*tl++ = 0;
86056289Smckusick 		} else {
86156289Smckusick 			*++tl = txdr_unsigned(uiop->uio_offset);
86256289Smckusick 			tl += 2;
86356289Smckusick 		}
86456289Smckusick 		*tl = txdr_unsigned(len);
86538414Smckusick 		nfsm_uiotom(uiop, len);
86652196Smckusick 		nfsm_request(vp, NFSPROC_WRITE, uiop->uio_procp, cred);
86738414Smckusick 		nfsm_loadattr(vp, (struct vattr *)0);
86852196Smckusick 		if (nmp->nm_flag & NFSMNT_MYWRITE)
86954106Smckusick 			VTONFS(vp)->n_mtime = VTONFS(vp)->n_vattr.va_mtime.ts_sec;
87052196Smckusick 		else if ((nmp->nm_flag & NFSMNT_NQNFS) &&
87152196Smckusick 			 NQNFS_CKCACHABLE(vp, NQL_WRITE)) {
87252196Smckusick 			nfsm_dissect(tl, u_long *, 2*NFSX_UNSIGNED);
87352196Smckusick 			fxdr_hyper(tl, &frev);
87454451Smckusick 			if (frev > np->n_brev)
87552196Smckusick 				np->n_brev = frev;
87652196Smckusick 		}
87738414Smckusick 		m_freem(mrep);
87838414Smckusick 		tsiz -= len;
87938414Smckusick 	}
88038414Smckusick nfsmout:
88152196Smckusick 	if (error)
88252196Smckusick 		uiop->uio_resid = tsiz;
88338414Smckusick 	return (error);
88438414Smckusick }
88538414Smckusick 
88638414Smckusick /*
88739459Smckusick  * nfs mknod call
88842246Smckusick  * This is a kludge. Use a create rpc but with the IFMT bits of the mode
88942246Smckusick  * set to specify the file type and the size field for rdev.
89039459Smckusick  */
89139459Smckusick /* ARGSUSED */
89252234Sheideman int
89353806Smckusick nfs_mknod(ap)
89454668Smckusick 	struct vop_mknod_args /* {
89554668Smckusick 		struct vnode *a_dvp;
89654668Smckusick 		struct vnode **a_vpp;
89754668Smckusick 		struct componentname *a_cnp;
89854668Smckusick 		struct vattr *a_vap;
89954668Smckusick 	} */ *ap;
90039459Smckusick {
90153806Smckusick 	register struct vnode *dvp = ap->a_dvp;
90253806Smckusick 	register struct vattr *vap = ap->a_vap;
90353806Smckusick 	register struct componentname *cnp = ap->a_cnp;
90442246Smckusick 	register struct nfsv2_sattr *sp;
90548054Smckusick 	register u_long *tl;
90642246Smckusick 	register caddr_t cp;
90756289Smckusick 	register long t1, t2;
90856289Smckusick 	struct vnode *newvp;
90956289Smckusick 	char *cp2;
91042246Smckusick 	caddr_t bpos, dpos;
91156289Smckusick 	int error = 0, isnq;
91242246Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
91342246Smckusick 	u_long rdev;
91439459Smckusick 
91556289Smckusick 	isnq = (VFSTONFS(dvp->v_mount)->nm_flag & NFSMNT_NQNFS);
91653806Smckusick 	if (vap->va_type == VCHR || vap->va_type == VBLK)
91753806Smckusick 		rdev = txdr_unsigned(vap->va_rdev);
91842246Smckusick #ifdef FIFO
91953806Smckusick 	else if (vap->va_type == VFIFO)
92042246Smckusick 		rdev = 0xffffffff;
92142246Smckusick #endif /* FIFO */
92242246Smckusick 	else {
92353806Smckusick 		VOP_ABORTOP(dvp, cnp);
92453806Smckusick 		vput(dvp);
92542246Smckusick 		return (EOPNOTSUPP);
92642246Smckusick 	}
92742246Smckusick 	nfsstats.rpccnt[NFSPROC_CREATE]++;
92853806Smckusick 	nfsm_reqhead(dvp, NFSPROC_CREATE,
92956289Smckusick 	  NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen)+NFSX_SATTR(isnq));
93053806Smckusick 	nfsm_fhtom(dvp);
93153806Smckusick 	nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
93256289Smckusick 	nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR(isnq));
93353806Smckusick 	sp->sa_mode = vtonfs_mode(vap->va_type, vap->va_mode);
93453806Smckusick 	sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid);
93553806Smckusick 	sp->sa_gid = txdr_unsigned(cnp->cn_cred->cr_gid);
93656289Smckusick 	if (isnq) {
93756289Smckusick 		sp->sa_nqrdev = rdev;
93856289Smckusick 		sp->sa_nqflags = 0;
93956289Smckusick 		txdr_nqtime(&vap->va_atime, &sp->sa_nqatime);
94056289Smckusick 		txdr_nqtime(&vap->va_mtime, &sp->sa_nqmtime);
94156289Smckusick 	} else {
94256289Smckusick 		sp->sa_nfssize = rdev;
94356289Smckusick 		txdr_nfstime(&vap->va_atime, &sp->sa_nfsatime);
94456289Smckusick 		txdr_nfstime(&vap->va_mtime, &sp->sa_nfsmtime);
94556289Smckusick 	}
94653806Smckusick 	nfsm_request(dvp, NFSPROC_CREATE, cnp->cn_proc, cnp->cn_cred);
94756289Smckusick 	nfsm_mtofh(dvp, newvp);
94842246Smckusick 	nfsm_reqdone;
94956289Smckusick 	if (!error)
95056289Smckusick 		cache_enter(dvp, newvp, cnp);
95153806Smckusick 	FREE(cnp->cn_pnbuf, M_NAMEI);
95253806Smckusick 	VTONFS(dvp)->n_flag |= NMODIFIED;
95353806Smckusick 	vrele(dvp);
95442246Smckusick 	return (error);
95539459Smckusick }
95639459Smckusick 
95739459Smckusick /*
95838414Smckusick  * nfs file create call
95938414Smckusick  */
96052234Sheideman int
96153806Smckusick nfs_create(ap)
96254668Smckusick 	struct vop_create_args /* {
96354668Smckusick 		struct vnode *a_dvp;
96454668Smckusick 		struct vnode **a_vpp;
96554668Smckusick 		struct componentname *a_cnp;
96654668Smckusick 		struct vattr *a_vap;
96754668Smckusick 	} */ *ap;
96838414Smckusick {
96953806Smckusick 	register struct vnode *dvp = ap->a_dvp;
97053806Smckusick 	register struct vattr *vap = ap->a_vap;
97153806Smckusick 	register struct componentname *cnp = ap->a_cnp;
97238884Smacklem 	register struct nfsv2_sattr *sp;
97348054Smckusick 	register u_long *tl;
97439488Smckusick 	register caddr_t cp;
97539488Smckusick 	register long t1, t2;
97639488Smckusick 	caddr_t bpos, dpos, cp2;
97756289Smckusick 	int error = 0, isnq;
97839488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
97938414Smckusick 
98038414Smckusick 	nfsstats.rpccnt[NFSPROC_CREATE]++;
98156289Smckusick 	isnq = (VFSTONFS(dvp->v_mount)->nm_flag & NFSMNT_NQNFS);
98253806Smckusick 	nfsm_reqhead(dvp, NFSPROC_CREATE,
98356289Smckusick 	  NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen)+NFSX_SATTR(isnq));
98453806Smckusick 	nfsm_fhtom(dvp);
98553806Smckusick 	nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
98656289Smckusick 	nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR(isnq));
98753806Smckusick 	sp->sa_mode = vtonfs_mode(vap->va_type, vap->va_mode);
98853806Smckusick 	sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid);
98953806Smckusick 	sp->sa_gid = txdr_unsigned(cnp->cn_cred->cr_gid);
99056289Smckusick 	if (isnq) {
99156289Smckusick 		u_quad_t qval = 0;
99256289Smckusick 
99356289Smckusick 		txdr_hyper(&qval, &sp->sa_nqsize);
99456289Smckusick 		sp->sa_nqflags = 0;
99556289Smckusick 		sp->sa_nqrdev = -1;
99656289Smckusick 		txdr_nqtime(&vap->va_atime, &sp->sa_nqatime);
99756289Smckusick 		txdr_nqtime(&vap->va_mtime, &sp->sa_nqmtime);
99856289Smckusick 	} else {
99956289Smckusick 		sp->sa_nfssize = 0;
100056289Smckusick 		txdr_nfstime(&vap->va_atime, &sp->sa_nfsatime);
100156289Smckusick 		txdr_nfstime(&vap->va_mtime, &sp->sa_nfsmtime);
100256289Smckusick 	}
100353806Smckusick 	nfsm_request(dvp, NFSPROC_CREATE, cnp->cn_proc, cnp->cn_cred);
100453806Smckusick 	nfsm_mtofh(dvp, *ap->a_vpp);
100538414Smckusick 	nfsm_reqdone;
100656289Smckusick 	if (!error)
100756289Smckusick 		cache_enter(dvp, *ap->a_vpp, cnp);
100853806Smckusick 	FREE(cnp->cn_pnbuf, M_NAMEI);
100953806Smckusick 	VTONFS(dvp)->n_flag |= NMODIFIED;
101053806Smckusick 	vrele(dvp);
101138414Smckusick 	return (error);
101238414Smckusick }
101338414Smckusick 
101438414Smckusick /*
101538414Smckusick  * nfs file remove call
101641905Smckusick  * To try and make nfs semantics closer to ufs semantics, a file that has
101741905Smckusick  * other processes using the vnode is renamed instead of removed and then
101839341Smckusick  * removed later on the last close.
101941905Smckusick  * - If v_usecount > 1
102039341Smckusick  *	  If a rename is not already in the works
102139341Smckusick  *	     call nfs_sillyrename() to set it up
102239341Smckusick  *     else
102339341Smckusick  *	  do the remove rpc
102438414Smckusick  */
102552234Sheideman int
102653806Smckusick nfs_remove(ap)
102754451Smckusick 	struct vop_remove_args /* {
102854451Smckusick 		struct vnodeop_desc *a_desc;
102954451Smckusick 		struct vnode * a_dvp;
103054451Smckusick 		struct vnode * a_vp;
103154451Smckusick 		struct componentname * a_cnp;
103254451Smckusick 	} */ *ap;
103338414Smckusick {
103453806Smckusick 	register struct vnode *vp = ap->a_vp;
103553806Smckusick 	register struct vnode *dvp = ap->a_dvp;
103653806Smckusick 	register struct componentname *cnp = ap->a_cnp;
103753806Smckusick 	register struct nfsnode *np = VTONFS(vp);
103848054Smckusick 	register u_long *tl;
103939488Smckusick 	register caddr_t cp;
104052196Smckusick 	register long t2;
104139488Smckusick 	caddr_t bpos, dpos;
104239488Smckusick 	int error = 0;
104339488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
104438414Smckusick 
104553806Smckusick 	if (vp->v_usecount > 1) {
104639341Smckusick 		if (!np->n_sillyrename)
104753806Smckusick 			error = nfs_sillyrename(dvp, vp, cnp);
104839341Smckusick 	} else {
104952196Smckusick 		/*
105052196Smckusick 		 * Purge the name cache so that the chance of a lookup for
105152196Smckusick 		 * the name succeeding while the remove is in progress is
105252196Smckusick 		 * minimized. Without node locking it can still happen, such
105352196Smckusick 		 * that an I/O op returns ESTALE, but since you get this if
105452196Smckusick 		 * another host removes the file..
105552196Smckusick 		 */
105653806Smckusick 		cache_purge(vp);
105752196Smckusick 		/*
105852196Smckusick 		 * Throw away biocache buffers. Mainly to avoid
105952196Smckusick 		 * unnecessary delayed writes.
106052196Smckusick 		 */
106154451Smckusick 		error = vinvalbuf(vp, FALSE, cnp->cn_cred, cnp->cn_proc);
106252196Smckusick 		/* Do the rpc */
106338414Smckusick 		nfsstats.rpccnt[NFSPROC_REMOVE]++;
106453806Smckusick 		nfsm_reqhead(dvp, NFSPROC_REMOVE,
106553806Smckusick 			NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen));
106653806Smckusick 		nfsm_fhtom(dvp);
106753806Smckusick 		nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
106853806Smckusick 		nfsm_request(dvp, NFSPROC_REMOVE, cnp->cn_proc, cnp->cn_cred);
106938414Smckusick 		nfsm_reqdone;
107053806Smckusick 		FREE(cnp->cn_pnbuf, M_NAMEI);
107153806Smckusick 		VTONFS(dvp)->n_flag |= NMODIFIED;
107239751Smckusick 		/*
107339751Smckusick 		 * Kludge City: If the first reply to the remove rpc is lost..
107439751Smckusick 		 *   the reply to the retransmitted request will be ENOENT
107539751Smckusick 		 *   since the file was in fact removed
107639751Smckusick 		 *   Therefore, we cheat and return success.
107739751Smckusick 		 */
107839751Smckusick 		if (error == ENOENT)
107939751Smckusick 			error = 0;
108038414Smckusick 	}
108140042Smckusick 	np->n_attrstamp = 0;
108253806Smckusick 	vrele(dvp);
108353806Smckusick 	vrele(vp);
108438414Smckusick 	return (error);
108538414Smckusick }
108638414Smckusick 
108738414Smckusick /*
108838414Smckusick  * nfs file remove rpc called from nfs_inactive
108938414Smckusick  */
109052234Sheideman int
109154451Smckusick nfs_removeit(sp)
109248364Smckusick 	register struct sillyrename *sp;
109338414Smckusick {
109448054Smckusick 	register u_long *tl;
109539488Smckusick 	register caddr_t cp;
109652196Smckusick 	register long t2;
109739488Smckusick 	caddr_t bpos, dpos;
109839488Smckusick 	int error = 0;
109939488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
110038414Smckusick 
110138414Smckusick 	nfsstats.rpccnt[NFSPROC_REMOVE]++;
110252196Smckusick 	nfsm_reqhead(sp->s_dvp, NFSPROC_REMOVE,
110348364Smckusick 		NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(sp->s_namlen));
110448364Smckusick 	nfsm_fhtom(sp->s_dvp);
110548364Smckusick 	nfsm_strtom(sp->s_name, sp->s_namlen, NFS_MAXNAMLEN);
110654451Smckusick 	nfsm_request(sp->s_dvp, NFSPROC_REMOVE, NULL, sp->s_cred);
110738414Smckusick 	nfsm_reqdone;
110848364Smckusick 	VTONFS(sp->s_dvp)->n_flag |= NMODIFIED;
110938414Smckusick 	return (error);
111038414Smckusick }
111138414Smckusick 
111238414Smckusick /*
111338414Smckusick  * nfs file rename call
111438414Smckusick  */
111552234Sheideman int
111653806Smckusick nfs_rename(ap)
111754668Smckusick 	struct vop_rename_args  /* {
111854668Smckusick 		struct vnode *a_fdvp;
111954668Smckusick 		struct vnode *a_fvp;
112054668Smckusick 		struct componentname *a_fcnp;
112154668Smckusick 		struct vnode *a_tdvp;
112254668Smckusick 		struct vnode *a_tvp;
112354668Smckusick 		struct componentname *a_tcnp;
112454668Smckusick 	} */ *ap;
112538414Smckusick {
112653806Smckusick 	register struct vnode *fvp = ap->a_fvp;
112753806Smckusick 	register struct vnode *tvp = ap->a_tvp;
112853806Smckusick 	register struct vnode *fdvp = ap->a_fdvp;
112953806Smckusick 	register struct vnode *tdvp = ap->a_tdvp;
113053806Smckusick 	register struct componentname *tcnp = ap->a_tcnp;
113153806Smckusick 	register struct componentname *fcnp = ap->a_fcnp;
113248054Smckusick 	register u_long *tl;
113339488Smckusick 	register caddr_t cp;
113452196Smckusick 	register long t2;
113539488Smckusick 	caddr_t bpos, dpos;
113639488Smckusick 	int error = 0;
113739488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
113838414Smckusick 
113953804Spendry 	/* Check for cross-device rename */
114053806Smckusick 	if ((fvp->v_mount != tdvp->v_mount) ||
114153806Smckusick 	    (tvp && (fvp->v_mount != tvp->v_mount))) {
114253804Spendry 		error = EXDEV;
114353804Spendry 		goto out;
114453804Spendry 	}
114553804Spendry 
114653804Spendry 
114738414Smckusick 	nfsstats.rpccnt[NFSPROC_RENAME]++;
114853806Smckusick 	nfsm_reqhead(fdvp, NFSPROC_RENAME,
114953806Smckusick 		(NFSX_FH+NFSX_UNSIGNED)*2+nfsm_rndup(fcnp->cn_namelen)+
115053806Smckusick 		nfsm_rndup(fcnp->cn_namelen)); /* or fcnp->cn_cred?*/
115153806Smckusick 	nfsm_fhtom(fdvp);
115253806Smckusick 	nfsm_strtom(fcnp->cn_nameptr, fcnp->cn_namelen, NFS_MAXNAMLEN);
115353806Smckusick 	nfsm_fhtom(tdvp);
115453806Smckusick 	nfsm_strtom(tcnp->cn_nameptr, tcnp->cn_namelen, NFS_MAXNAMLEN);
115553806Smckusick 	nfsm_request(fdvp, NFSPROC_RENAME, tcnp->cn_proc, tcnp->cn_cred);
115638414Smckusick 	nfsm_reqdone;
115753806Smckusick 	VTONFS(fdvp)->n_flag |= NMODIFIED;
115853806Smckusick 	VTONFS(tdvp)->n_flag |= NMODIFIED;
115953806Smckusick 	if (fvp->v_type == VDIR) {
116053806Smckusick 		if (tvp != NULL && tvp->v_type == VDIR)
116153806Smckusick 			cache_purge(tdvp);
116253806Smckusick 		cache_purge(fdvp);
116338414Smckusick 	}
116453804Spendry out:
116553806Smckusick 	if (tdvp == tvp)
116653806Smckusick 		vrele(tdvp);
116743360Smckusick 	else
116853806Smckusick 		vput(tdvp);
116953806Smckusick 	if (tvp)
117053806Smckusick 		vput(tvp);
117153806Smckusick 	vrele(fdvp);
117253806Smckusick 	vrele(fvp);
117340112Smckusick 	/*
117440112Smckusick 	 * Kludge: Map ENOENT => 0 assuming that it is a reply to a retry.
117540112Smckusick 	 */
117640112Smckusick 	if (error == ENOENT)
117740112Smckusick 		error = 0;
117838414Smckusick 	return (error);
117938414Smckusick }
118038414Smckusick 
118138414Smckusick /*
118241905Smckusick  * nfs file rename rpc called from nfs_remove() above
118338414Smckusick  */
118452234Sheideman int
118552234Sheideman nfs_renameit(sdvp, scnp, sp)
118652234Sheideman 	struct vnode *sdvp;
118752234Sheideman 	struct componentname *scnp;
118848364Smckusick 	register struct sillyrename *sp;
118938414Smckusick {
119048054Smckusick 	register u_long *tl;
119139488Smckusick 	register caddr_t cp;
119252196Smckusick 	register long t2;
119339488Smckusick 	caddr_t bpos, dpos;
119439488Smckusick 	int error = 0;
119539488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
119638414Smckusick 
119738414Smckusick 	nfsstats.rpccnt[NFSPROC_RENAME]++;
119852234Sheideman 	nfsm_reqhead(sdvp, NFSPROC_RENAME,
119952234Sheideman 		(NFSX_FH+NFSX_UNSIGNED)*2+nfsm_rndup(scnp->cn_namelen)+
120052196Smckusick 		nfsm_rndup(sp->s_namlen));
120152234Sheideman 	nfsm_fhtom(sdvp);
120252234Sheideman 	nfsm_strtom(scnp->cn_nameptr, scnp->cn_namelen, NFS_MAXNAMLEN);
120352234Sheideman 	nfsm_fhtom(sdvp);
120448364Smckusick 	nfsm_strtom(sp->s_name, sp->s_namlen, NFS_MAXNAMLEN);
120552234Sheideman 	nfsm_request(sdvp, NFSPROC_RENAME, scnp->cn_proc, scnp->cn_cred);
120638414Smckusick 	nfsm_reqdone;
120752234Sheideman 	FREE(scnp->cn_pnbuf, M_NAMEI);
120852234Sheideman 	VTONFS(sdvp)->n_flag |= NMODIFIED;
120938414Smckusick 	return (error);
121038414Smckusick }
121138414Smckusick 
121238414Smckusick /*
121338414Smckusick  * nfs hard link create call
121438414Smckusick  */
121552234Sheideman int
121653806Smckusick nfs_link(ap)
121754668Smckusick 	struct vop_link_args /* {
121854668Smckusick 		struct vnode *a_vp;
121954668Smckusick 		struct vnode *a_tdvp;
122054668Smckusick 		struct componentname *a_cnp;
122154668Smckusick 	} */ *ap;
122238414Smckusick {
122353806Smckusick 	register struct vnode *vp = ap->a_vp;
122453806Smckusick 	register struct vnode *tdvp = ap->a_tdvp;
122553806Smckusick 	register struct componentname *cnp = ap->a_cnp;
122648054Smckusick 	register u_long *tl;
122739488Smckusick 	register caddr_t cp;
122852196Smckusick 	register long t2;
122939488Smckusick 	caddr_t bpos, dpos;
123039488Smckusick 	int error = 0;
123139488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
123238414Smckusick 
123353806Smckusick 	if (vp->v_mount != tdvp->v_mount) {
123453806Smckusick 		/*VOP_ABORTOP(vp, cnp);*/
123553806Smckusick 		if (tdvp == vp)
123653806Smckusick 			vrele(vp);
123753804Spendry 		else
123853806Smckusick 			vput(vp);
123953804Spendry 		return (EXDEV);
124053804Spendry 	}
124153804Spendry 
124238414Smckusick 	nfsstats.rpccnt[NFSPROC_LINK]++;
124353806Smckusick 	nfsm_reqhead(tdvp, NFSPROC_LINK,
124453806Smckusick 		NFSX_FH*2+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen));
124553806Smckusick 	nfsm_fhtom(tdvp);
124653806Smckusick 	nfsm_fhtom(vp);
124753806Smckusick 	nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
124853806Smckusick 	nfsm_request(tdvp, NFSPROC_LINK, cnp->cn_proc, cnp->cn_cred);
124938414Smckusick 	nfsm_reqdone;
125053806Smckusick 	FREE(cnp->cn_pnbuf, M_NAMEI);
125153806Smckusick 	VTONFS(tdvp)->n_attrstamp = 0;
125253806Smckusick 	VTONFS(vp)->n_flag |= NMODIFIED;
125353806Smckusick 	vrele(vp);
125440112Smckusick 	/*
125540112Smckusick 	 * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry.
125640112Smckusick 	 */
125740112Smckusick 	if (error == EEXIST)
125840112Smckusick 		error = 0;
125938414Smckusick 	return (error);
126038414Smckusick }
126138414Smckusick 
126238414Smckusick /*
126338414Smckusick  * nfs symbolic link create call
126438414Smckusick  */
126552234Sheideman /* start here */
126652234Sheideman int
126753806Smckusick nfs_symlink(ap)
126854668Smckusick 	struct vop_symlink_args /* {
126954668Smckusick 		struct vnode *a_dvp;
127054668Smckusick 		struct vnode **a_vpp;
127154668Smckusick 		struct componentname *a_cnp;
127254668Smckusick 		struct vattr *a_vap;
127354668Smckusick 		char *a_target;
127454668Smckusick 	} */ *ap;
127538414Smckusick {
127653806Smckusick 	register struct vnode *dvp = ap->a_dvp;
127753806Smckusick 	register struct vattr *vap = ap->a_vap;
127853806Smckusick 	register struct componentname *cnp = ap->a_cnp;
127938884Smacklem 	register struct nfsv2_sattr *sp;
128048054Smckusick 	register u_long *tl;
128139488Smckusick 	register caddr_t cp;
128252196Smckusick 	register long t2;
128339488Smckusick 	caddr_t bpos, dpos;
128456289Smckusick 	int slen, error = 0, isnq;
128539488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
128638414Smckusick 
128738414Smckusick 	nfsstats.rpccnt[NFSPROC_SYMLINK]++;
128853600Sheideman 	slen = strlen(ap->a_target);
128956289Smckusick 	isnq = (VFSTONFS(dvp->v_mount)->nm_flag & NFSMNT_NQNFS);
129053806Smckusick 	nfsm_reqhead(dvp, NFSPROC_SYMLINK, NFSX_FH+2*NFSX_UNSIGNED+
129156289Smckusick 	    nfsm_rndup(cnp->cn_namelen)+nfsm_rndup(slen)+NFSX_SATTR(isnq));
129253806Smckusick 	nfsm_fhtom(dvp);
129353806Smckusick 	nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
129453600Sheideman 	nfsm_strtom(ap->a_target, slen, NFS_MAXPATHLEN);
129556289Smckusick 	nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR(isnq));
129653806Smckusick 	sp->sa_mode = vtonfs_mode(VLNK, vap->va_mode);
129753806Smckusick 	sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid);
129853806Smckusick 	sp->sa_gid = txdr_unsigned(cnp->cn_cred->cr_gid);
129956289Smckusick 	if (isnq) {
130056289Smckusick 		quad_t qval = -1;
130156289Smckusick 
130256289Smckusick 		txdr_hyper(&qval, &sp->sa_nqsize);
130356289Smckusick 		sp->sa_nqflags = 0;
130456289Smckusick 		txdr_nqtime(&vap->va_atime, &sp->sa_nqatime);
130556289Smckusick 		txdr_nqtime(&vap->va_mtime, &sp->sa_nqmtime);
130656289Smckusick 	} else {
130756289Smckusick 		sp->sa_nfssize = -1;
130856289Smckusick 		txdr_nfstime(&vap->va_atime, &sp->sa_nfsatime);
130956289Smckusick 		txdr_nfstime(&vap->va_mtime, &sp->sa_nfsmtime);
131056289Smckusick 	}
131153806Smckusick 	nfsm_request(dvp, NFSPROC_SYMLINK, cnp->cn_proc, cnp->cn_cred);
131238414Smckusick 	nfsm_reqdone;
131353806Smckusick 	FREE(cnp->cn_pnbuf, M_NAMEI);
131453806Smckusick 	VTONFS(dvp)->n_flag |= NMODIFIED;
131553806Smckusick 	vrele(dvp);
131640112Smckusick 	/*
131740112Smckusick 	 * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry.
131840112Smckusick 	 */
131940112Smckusick 	if (error == EEXIST)
132040112Smckusick 		error = 0;
132138414Smckusick 	return (error);
132238414Smckusick }
132338414Smckusick 
132438414Smckusick /*
132538414Smckusick  * nfs make dir call
132638414Smckusick  */
132752234Sheideman int
132853806Smckusick nfs_mkdir(ap)
132954668Smckusick 	struct vop_mkdir_args /* {
133054668Smckusick 		struct vnode *a_dvp;
133154668Smckusick 		struct vnode **a_vpp;
133254668Smckusick 		struct componentname *a_cnp;
133354668Smckusick 		struct vattr *a_vap;
133454668Smckusick 	} */ *ap;
133538414Smckusick {
133653806Smckusick 	register struct vnode *dvp = ap->a_dvp;
133753806Smckusick 	register struct vattr *vap = ap->a_vap;
133853806Smckusick 	register struct componentname *cnp = ap->a_cnp;
133954668Smckusick 	register struct vnode **vpp = ap->a_vpp;
134038884Smacklem 	register struct nfsv2_sattr *sp;
134148054Smckusick 	register u_long *tl;
134239488Smckusick 	register caddr_t cp;
134339488Smckusick 	register long t1, t2;
134441905Smckusick 	register int len;
134539488Smckusick 	caddr_t bpos, dpos, cp2;
134656289Smckusick 	int error = 0, firsttry = 1, isnq;
134739488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
134838414Smckusick 
134953806Smckusick 	len = cnp->cn_namelen;
135056289Smckusick 	isnq = (VFSTONFS(dvp->v_mount)->nm_flag & NFSMNT_NQNFS);
135138414Smckusick 	nfsstats.rpccnt[NFSPROC_MKDIR]++;
135253806Smckusick 	nfsm_reqhead(dvp, NFSPROC_MKDIR,
135356289Smckusick 	  NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len)+NFSX_SATTR(isnq));
135453806Smckusick 	nfsm_fhtom(dvp);
135553806Smckusick 	nfsm_strtom(cnp->cn_nameptr, len, NFS_MAXNAMLEN);
135656289Smckusick 	nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR(isnq));
135753806Smckusick 	sp->sa_mode = vtonfs_mode(VDIR, vap->va_mode);
135853806Smckusick 	sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid);
135953806Smckusick 	sp->sa_gid = txdr_unsigned(cnp->cn_cred->cr_gid);
136056289Smckusick 	if (isnq) {
136156289Smckusick 		quad_t qval = -1;
136256289Smckusick 
136356289Smckusick 		txdr_hyper(&qval, &sp->sa_nqsize);
136456289Smckusick 		sp->sa_nqflags = 0;
136556289Smckusick 		txdr_nqtime(&vap->va_atime, &sp->sa_nqatime);
136656289Smckusick 		txdr_nqtime(&vap->va_mtime, &sp->sa_nqmtime);
136756289Smckusick 	} else {
136856289Smckusick 		sp->sa_nfssize = -1;
136956289Smckusick 		txdr_nfstime(&vap->va_atime, &sp->sa_nfsatime);
137056289Smckusick 		txdr_nfstime(&vap->va_mtime, &sp->sa_nfsmtime);
137156289Smckusick 	}
137253806Smckusick 	nfsm_request(dvp, NFSPROC_MKDIR, cnp->cn_proc, cnp->cn_cred);
137354668Smckusick 	nfsm_mtofh(dvp, *vpp);
137438414Smckusick 	nfsm_reqdone;
137553806Smckusick 	VTONFS(dvp)->n_flag |= NMODIFIED;
137640112Smckusick 	/*
137741905Smckusick 	 * Kludge: Map EEXIST => 0 assuming that you have a reply to a retry
137841905Smckusick 	 * if we can succeed in looking up the directory.
137941905Smckusick 	 * "firsttry" is necessary since the macros may "goto nfsmout" which
138041905Smckusick 	 * is above the if on errors. (Ugh)
138140112Smckusick 	 */
138241905Smckusick 	if (error == EEXIST && firsttry) {
138341905Smckusick 		firsttry = 0;
138440112Smckusick 		error = 0;
138541905Smckusick 		nfsstats.rpccnt[NFSPROC_LOOKUP]++;
138654668Smckusick 		*vpp = NULL;
138753806Smckusick 		nfsm_reqhead(dvp, NFSPROC_LOOKUP,
138841905Smckusick 		    NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len));
138953806Smckusick 		nfsm_fhtom(dvp);
139053806Smckusick 		nfsm_strtom(cnp->cn_nameptr, len, NFS_MAXNAMLEN);
139153806Smckusick 		nfsm_request(dvp, NFSPROC_LOOKUP, cnp->cn_proc, cnp->cn_cred);
139254668Smckusick 		nfsm_mtofh(dvp, *vpp);
139354668Smckusick 		if ((*vpp)->v_type != VDIR) {
139454668Smckusick 			vput(*vpp);
139541905Smckusick 			error = EEXIST;
139641905Smckusick 		}
139741905Smckusick 		m_freem(mrep);
139841905Smckusick 	}
139953806Smckusick 	FREE(cnp->cn_pnbuf, M_NAMEI);
140053806Smckusick 	vrele(dvp);
140138414Smckusick 	return (error);
140238414Smckusick }
140338414Smckusick 
140438414Smckusick /*
140538414Smckusick  * nfs remove directory call
140638414Smckusick  */
140752234Sheideman int
140853806Smckusick nfs_rmdir(ap)
140954668Smckusick 	struct vop_rmdir_args /* {
141054668Smckusick 		struct vnode *a_dvp;
141154668Smckusick 		struct vnode *a_vp;
141254668Smckusick 		struct componentname *a_cnp;
141354668Smckusick 	} */ *ap;
141438414Smckusick {
141553806Smckusick 	register struct vnode *vp = ap->a_vp;
141653806Smckusick 	register struct vnode *dvp = ap->a_dvp;
141753806Smckusick 	register struct componentname *cnp = ap->a_cnp;
141848054Smckusick 	register u_long *tl;
141939488Smckusick 	register caddr_t cp;
142052196Smckusick 	register long t2;
142139488Smckusick 	caddr_t bpos, dpos;
142239488Smckusick 	int error = 0;
142339488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
142438414Smckusick 
142553806Smckusick 	if (dvp == vp) {
142653806Smckusick 		vrele(dvp);
142753806Smckusick 		vrele(dvp);
142853806Smckusick 		FREE(cnp->cn_pnbuf, M_NAMEI);
142938414Smckusick 		return (EINVAL);
143038414Smckusick 	}
143138414Smckusick 	nfsstats.rpccnt[NFSPROC_RMDIR]++;
143253806Smckusick 	nfsm_reqhead(dvp, NFSPROC_RMDIR,
143353806Smckusick 		NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen));
143453806Smckusick 	nfsm_fhtom(dvp);
143553806Smckusick 	nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
143653806Smckusick 	nfsm_request(dvp, NFSPROC_RMDIR, cnp->cn_proc, cnp->cn_cred);
143738414Smckusick 	nfsm_reqdone;
143853806Smckusick 	FREE(cnp->cn_pnbuf, M_NAMEI);
143953806Smckusick 	VTONFS(dvp)->n_flag |= NMODIFIED;
144053806Smckusick 	cache_purge(dvp);
144153806Smckusick 	cache_purge(vp);
144253806Smckusick 	vrele(vp);
144353806Smckusick 	vrele(dvp);
144440112Smckusick 	/*
144540112Smckusick 	 * Kludge: Map ENOENT => 0 assuming that you have a reply to a retry.
144640112Smckusick 	 */
144740112Smckusick 	if (error == ENOENT)
144840112Smckusick 		error = 0;
144938414Smckusick 	return (error);
145038414Smckusick }
145138414Smckusick 
145238414Smckusick /*
145338414Smckusick  * nfs readdir call
145438414Smckusick  * Although cookie is defined as opaque, I translate it to/from net byte
145538414Smckusick  * order so that it looks more sensible. This appears consistent with the
145638414Smckusick  * Ultrix implementation of NFS.
145738414Smckusick  */
145852234Sheideman int
145953806Smckusick nfs_readdir(ap)
146054668Smckusick 	struct vop_readdir_args /* {
146154668Smckusick 		struct vnode *a_vp;
146254668Smckusick 		struct uio *a_uio;
146354668Smckusick 		struct ucred *a_cred;
146454668Smckusick 	} */ *ap;
146538414Smckusick {
146653806Smckusick 	register struct vnode *vp = ap->a_vp;
146753806Smckusick 	register struct nfsnode *np = VTONFS(vp);
146853806Smckusick 	register struct uio *uio = ap->a_uio;
146941905Smckusick 	int tresid, error;
147041905Smckusick 	struct vattr vattr;
147141905Smckusick 
147253806Smckusick 	if (vp->v_type != VDIR)
147341905Smckusick 		return (EPERM);
147441905Smckusick 	/*
147541905Smckusick 	 * First, check for hit on the EOF offset cache
147641905Smckusick 	 */
147753806Smckusick 	if (uio->uio_offset != 0 && uio->uio_offset == np->n_direofoffset &&
147852196Smckusick 	    (np->n_flag & NMODIFIED) == 0) {
147953806Smckusick 		if (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) {
148053806Smckusick 			if (NQNFS_CKCACHABLE(vp, NQL_READ)) {
148152196Smckusick 				nfsstats.direofcache_hits++;
148252196Smckusick 				return (0);
148352196Smckusick 			}
148453806Smckusick 		} else if (VOP_GETATTR(vp, &vattr, ap->a_cred, uio->uio_procp) == 0 &&
148554106Smckusick 			np->n_mtime == vattr.va_mtime.ts_sec) {
148652196Smckusick 			nfsstats.direofcache_hits++;
148752196Smckusick 			return (0);
148852196Smckusick 		}
148941905Smckusick 	}
149041905Smckusick 
149141905Smckusick 	/*
149241905Smckusick 	 * Call nfs_bioread() to do the real work.
149341905Smckusick 	 */
149453806Smckusick 	tresid = uio->uio_resid;
149553806Smckusick 	error = nfs_bioread(vp, uio, 0, ap->a_cred);
149641905Smckusick 
149754451Smckusick 	if (!error && uio->uio_resid == tresid)
149841905Smckusick 		nfsstats.direofcache_misses++;
149941905Smckusick 	return (error);
150041905Smckusick }
150141905Smckusick 
150241905Smckusick /*
150341905Smckusick  * Readdir rpc call.
150441905Smckusick  * Called from below the buffer cache by nfs_doio().
150541905Smckusick  */
150652234Sheideman int
150748054Smckusick nfs_readdirrpc(vp, uiop, cred)
150841905Smckusick 	register struct vnode *vp;
150941905Smckusick 	struct uio *uiop;
151041905Smckusick 	struct ucred *cred;
151141905Smckusick {
151238414Smckusick 	register long len;
151354740Smckusick 	register struct dirent *dp;
151448054Smckusick 	register u_long *tl;
151539488Smckusick 	register caddr_t cp;
151639488Smckusick 	register long t1;
151741905Smckusick 	long tlen, lastlen;
151839488Smckusick 	caddr_t bpos, dpos, cp2;
151939488Smckusick 	int error = 0;
152039488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
152138414Smckusick 	struct mbuf *md2;
152238414Smckusick 	caddr_t dpos2;
152338414Smckusick 	int siz;
152440296Smckusick 	int more_dirs = 1;
152556289Smckusick 	u_long off, savoff;
152654740Smckusick 	struct dirent *savdp;
152740296Smckusick 	struct nfsmount *nmp;
152840296Smckusick 	struct nfsnode *np = VTONFS(vp);
152940296Smckusick 	long tresid;
153038414Smckusick 
153141398Smckusick 	nmp = VFSTONFS(vp->v_mount);
153240296Smckusick 	tresid = uiop->uio_resid;
153340296Smckusick 	/*
153440296Smckusick 	 * Loop around doing readdir rpc's of size uio_resid or nm_rsize,
153548054Smckusick 	 * whichever is smaller, truncated to a multiple of NFS_DIRBLKSIZ.
153641905Smckusick 	 * The stopping criteria is EOF or buffer full.
153740296Smckusick 	 */
153848054Smckusick 	while (more_dirs && uiop->uio_resid >= NFS_DIRBLKSIZ) {
153940296Smckusick 		nfsstats.rpccnt[NFSPROC_READDIR]++;
154052196Smckusick 		nfsm_reqhead(vp, NFSPROC_READDIR,
154156289Smckusick 			NFSX_FH + 2 * NFSX_UNSIGNED);
154240296Smckusick 		nfsm_fhtom(vp);
154356289Smckusick 		nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED);
154456289Smckusick 		off = (u_long)uiop->uio_offset;
154556289Smckusick 		*tl++ = txdr_unsigned(off);
154648054Smckusick 		*tl = txdr_unsigned(((uiop->uio_resid > nmp->nm_rsize) ?
154748054Smckusick 			nmp->nm_rsize : uiop->uio_resid) & ~(NFS_DIRBLKSIZ-1));
154852196Smckusick 		nfsm_request(vp, NFSPROC_READDIR, uiop->uio_procp, cred);
154940296Smckusick 		siz = 0;
155052196Smckusick 		nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
155148054Smckusick 		more_dirs = fxdr_unsigned(int, *tl);
155240296Smckusick 
155340296Smckusick 		/* Save the position so that we can do nfsm_mtouio() later */
155440296Smckusick 		dpos2 = dpos;
155540296Smckusick 		md2 = md;
155640296Smckusick 
155740296Smckusick 		/* loop thru the dir entries, doctoring them to 4bsd form */
155842246Smckusick #ifdef lint
155954740Smckusick 		dp = (struct dirent *)0;
156042246Smckusick #endif /* lint */
156140296Smckusick 		while (more_dirs && siz < uiop->uio_resid) {
156240296Smckusick 			savoff = off;		/* Hold onto offset and dp */
156340296Smckusick 			savdp = dp;
156456289Smckusick 			nfsm_dissecton(tl, u_long *, 2 * NFSX_UNSIGNED);
156554740Smckusick 			dp = (struct dirent *)tl;
156654740Smckusick 			dp->d_fileno = fxdr_unsigned(u_long, *tl++);
156748054Smckusick 			len = fxdr_unsigned(int, *tl);
156840296Smckusick 			if (len <= 0 || len > NFS_MAXNAMLEN) {
156940296Smckusick 				error = EBADRPC;
157040296Smckusick 				m_freem(mrep);
157140296Smckusick 				goto nfsmout;
157240296Smckusick 			}
157354986Smckusick 			dp->d_namlen = (u_char)len;
157454986Smckusick 			dp->d_type = DT_UNKNOWN;
157540296Smckusick 			nfsm_adv(len);		/* Point past name */
157640296Smckusick 			tlen = nfsm_rndup(len);
157740296Smckusick 			/*
157840296Smckusick 			 * This should not be necessary, but some servers have
157940296Smckusick 			 * broken XDR such that these bytes are not null filled.
158040296Smckusick 			 */
158140296Smckusick 			if (tlen != len) {
158240296Smckusick 				*dpos = '\0';	/* Null-terminate */
158340296Smckusick 				nfsm_adv(tlen - len);
158440296Smckusick 				len = tlen;
158540296Smckusick 			}
158656289Smckusick 			nfsm_dissecton(tl, u_long *, 2 * NFSX_UNSIGNED);
158754986Smckusick 			off = fxdr_unsigned(u_long, *tl);
158848054Smckusick 			*tl++ = 0;	/* Ensures null termination of name */
158948054Smckusick 			more_dirs = fxdr_unsigned(int, *tl);
159056289Smckusick 			dp->d_reclen = len + 4 * NFSX_UNSIGNED;
159140296Smckusick 			siz += dp->d_reclen;
159240296Smckusick 		}
159340296Smckusick 		/*
159440296Smckusick 		 * If at end of rpc data, get the eof boolean
159540296Smckusick 		 */
159640296Smckusick 		if (!more_dirs) {
159752196Smckusick 			nfsm_dissecton(tl, u_long *, NFSX_UNSIGNED);
159848054Smckusick 			more_dirs = (fxdr_unsigned(int, *tl) == 0);
159938414Smckusick 
160040296Smckusick 			/*
160140296Smckusick 			 * If at EOF, cache directory offset
160240296Smckusick 			 */
160341905Smckusick 			if (!more_dirs)
160440296Smckusick 				np->n_direofoffset = off;
160538414Smckusick 		}
160640296Smckusick 		/*
160740296Smckusick 		 * If there is too much to fit in the data buffer, use savoff and
160840296Smckusick 		 * savdp to trim off the last record.
160940296Smckusick 		 * --> we are not at eof
161040296Smckusick 		 */
161140296Smckusick 		if (siz > uiop->uio_resid) {
161240296Smckusick 			off = savoff;
161340296Smckusick 			siz -= dp->d_reclen;
161440296Smckusick 			dp = savdp;
161540296Smckusick 			more_dirs = 0;	/* Paranoia */
161640113Smckusick 		}
161740296Smckusick 		if (siz > 0) {
161841905Smckusick 			lastlen = dp->d_reclen;
161940296Smckusick 			md = md2;
162040296Smckusick 			dpos = dpos2;
162140296Smckusick 			nfsm_mtouio(uiop, siz);
162256289Smckusick 			uiop->uio_offset = (off_t)off;
162340296Smckusick 		} else
162440296Smckusick 			more_dirs = 0;	/* Ugh, never happens, but in case.. */
162540296Smckusick 		m_freem(mrep);
162638414Smckusick 	}
162741905Smckusick 	/*
162848054Smckusick 	 * Fill last record, iff any, out to a multiple of NFS_DIRBLKSIZ
162941905Smckusick 	 * by increasing d_reclen for the last record.
163041905Smckusick 	 */
163141905Smckusick 	if (uiop->uio_resid < tresid) {
163248054Smckusick 		len = uiop->uio_resid & (NFS_DIRBLKSIZ - 1);
163341905Smckusick 		if (len > 0) {
163454740Smckusick 			dp = (struct dirent *)
163541905Smckusick 				(uiop->uio_iov->iov_base - lastlen);
163641905Smckusick 			dp->d_reclen += len;
163741905Smckusick 			uiop->uio_iov->iov_base += len;
163841905Smckusick 			uiop->uio_iov->iov_len -= len;
163941905Smckusick 			uiop->uio_resid -= len;
164041905Smckusick 		}
164141905Smckusick 	}
164240296Smckusick nfsmout:
164338414Smckusick 	return (error);
164438414Smckusick }
164538414Smckusick 
164652196Smckusick /*
164756289Smckusick  * Nqnfs readdir_and_lookup RPC. Used in place of nfs_readdirrpc().
164852196Smckusick  */
164952234Sheideman int
165052196Smckusick nfs_readdirlookrpc(vp, uiop, cred)
165152196Smckusick 	struct vnode *vp;
165252196Smckusick 	register struct uio *uiop;
165352196Smckusick 	struct ucred *cred;
165452196Smckusick {
165552196Smckusick 	register int len;
165654740Smckusick 	register struct dirent *dp;
165752196Smckusick 	register u_long *tl;
165852196Smckusick 	register caddr_t cp;
165952196Smckusick 	register long t1;
166052196Smckusick 	caddr_t bpos, dpos, cp2;
166152196Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
166252196Smckusick 	struct nameidata nami, *ndp = &nami;
166352317Sheideman 	struct componentname *cnp = &ndp->ni_cnd;
166456289Smckusick 	u_long off, endoff, fileno;
166552196Smckusick 	time_t reqtime, ltime;
166652196Smckusick 	struct nfsmount *nmp;
166752196Smckusick 	struct nfsnode *np, *tp;
166852196Smckusick 	struct vnode *newvp;
166952196Smckusick 	nfsv2fh_t *fhp;
167052196Smckusick 	u_quad_t frev;
167152196Smckusick 	int error = 0, tlen, more_dirs = 1, tresid, doit, bigenough, i;
167252196Smckusick 	int cachable;
167352196Smckusick 
167452196Smckusick 	if (uiop->uio_iovcnt != 1)
167552196Smckusick 		panic("nfs rdirlook");
167652196Smckusick 	nmp = VFSTONFS(vp->v_mount);
167752196Smckusick 	tresid = uiop->uio_resid;
167852196Smckusick 	ndp->ni_dvp = vp;
167952196Smckusick 	newvp = NULLVP;
168052196Smckusick 	/*
168152196Smckusick 	 * Loop around doing readdir rpc's of size uio_resid or nm_rsize,
168252196Smckusick 	 * whichever is smaller, truncated to a multiple of NFS_DIRBLKSIZ.
168352196Smckusick 	 * The stopping criteria is EOF or buffer full.
168452196Smckusick 	 */
168552196Smckusick 	while (more_dirs && uiop->uio_resid >= NFS_DIRBLKSIZ) {
168652196Smckusick 		nfsstats.rpccnt[NQNFSPROC_READDIRLOOK]++;
168752196Smckusick 		nfsm_reqhead(vp, NQNFSPROC_READDIRLOOK,
168856289Smckusick 			NFSX_FH + 3 * NFSX_UNSIGNED);
168952196Smckusick 		nfsm_fhtom(vp);
169056289Smckusick  		nfsm_build(tl, u_long *, 3 * NFSX_UNSIGNED);
169156289Smckusick 		off = (u_long)uiop->uio_offset;
169256289Smckusick 		*tl++ = txdr_unsigned(off);
169352196Smckusick 		*tl++ = txdr_unsigned(((uiop->uio_resid > nmp->nm_rsize) ?
169452196Smckusick 			nmp->nm_rsize : uiop->uio_resid) & ~(NFS_DIRBLKSIZ-1));
169556289Smckusick 		if (nmp->nm_flag & NFSMNT_NQLOOKLEASE)
169656289Smckusick 			*tl = txdr_unsigned(nmp->nm_leaseterm);
169756289Smckusick 		else
169856289Smckusick 			*tl = 0;
169952196Smckusick 		reqtime = time.tv_sec;
170052196Smckusick 		nfsm_request(vp, NQNFSPROC_READDIRLOOK, uiop->uio_procp, cred);
170152196Smckusick 		nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
170252196Smckusick 		more_dirs = fxdr_unsigned(int, *tl);
170352196Smckusick 
170452196Smckusick 		/* loop thru the dir entries, doctoring them to 4bsd form */
170552196Smckusick 		bigenough = 1;
170652196Smckusick 		while (more_dirs && bigenough) {
170752196Smckusick 			doit = 1;
170856289Smckusick 			nfsm_dissect(tl, u_long *, 4 * NFSX_UNSIGNED);
170956289Smckusick 			if (nmp->nm_flag & NFSMNT_NQLOOKLEASE) {
171056289Smckusick 				cachable = fxdr_unsigned(int, *tl++);
171156289Smckusick 				ltime = reqtime + fxdr_unsigned(int, *tl++);
171256289Smckusick 				fxdr_hyper(tl, &frev);
171356289Smckusick 			}
171452196Smckusick 			nfsm_dissect(fhp, nfsv2fh_t *, NFSX_FH);
171552196Smckusick 			if (!bcmp(VTONFS(vp)->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) {
171652196Smckusick 				VREF(vp);
171752196Smckusick 				newvp = vp;
171852196Smckusick 				np = VTONFS(vp);
171952196Smckusick 			} else {
172052196Smckusick 				if (error = nfs_nget(vp->v_mount, fhp, &np))
172152196Smckusick 					doit = 0;
172252196Smckusick 				newvp = NFSTOV(np);
172352196Smckusick 			}
172452196Smckusick 			if (error = nfs_loadattrcache(&newvp, &md, &dpos,
172552196Smckusick 				(struct vattr *)0))
172652196Smckusick 				doit = 0;
172756289Smckusick 			nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
172852196Smckusick 			fileno = fxdr_unsigned(u_long, *tl++);
172952196Smckusick 			len = fxdr_unsigned(int, *tl);
173052196Smckusick 			if (len <= 0 || len > NFS_MAXNAMLEN) {
173152196Smckusick 				error = EBADRPC;
173252196Smckusick 				m_freem(mrep);
173352196Smckusick 				goto nfsmout;
173452196Smckusick 			}
173552196Smckusick 			tlen = (len + 4) & ~0x3;
173652196Smckusick 			if ((tlen + DIRHDSIZ) > uiop->uio_resid)
173752196Smckusick 				bigenough = 0;
173852196Smckusick 			if (bigenough && doit) {
173954740Smckusick 				dp = (struct dirent *)uiop->uio_iov->iov_base;
174054740Smckusick 				dp->d_fileno = fileno;
174152196Smckusick 				dp->d_namlen = len;
174252196Smckusick 				dp->d_reclen = tlen + DIRHDSIZ;
174354986Smckusick 				dp->d_type =
174454986Smckusick 				    IFTODT(VTTOIF(np->n_vattr.va_type));
174552196Smckusick 				uiop->uio_resid -= DIRHDSIZ;
174652196Smckusick 				uiop->uio_iov->iov_base += DIRHDSIZ;
174752196Smckusick 				uiop->uio_iov->iov_len -= DIRHDSIZ;
174852317Sheideman 				cnp->cn_nameptr = uiop->uio_iov->iov_base;
174952317Sheideman 				cnp->cn_namelen = len;
175052196Smckusick 				ndp->ni_vp = newvp;
175152196Smckusick 				nfsm_mtouio(uiop, len);
175252196Smckusick 				cp = uiop->uio_iov->iov_base;
175352196Smckusick 				tlen -= len;
175452196Smckusick 				for (i = 0; i < tlen; i++)
175552196Smckusick 					*cp++ = '\0';
175652196Smckusick 				uiop->uio_iov->iov_base += tlen;
175752196Smckusick 				uiop->uio_iov->iov_len -= tlen;
175852196Smckusick 				uiop->uio_resid -= tlen;
175952317Sheideman 				cnp->cn_hash = 0;
176052317Sheideman 				for (cp = cnp->cn_nameptr, i = 1; i <= len; i++, cp++)
176152317Sheideman 					cnp->cn_hash += (unsigned char)*cp * i;
176256289Smckusick 				if ((nmp->nm_flag & NFSMNT_NQLOOKLEASE) &&
176356289Smckusick 					ltime > time.tv_sec)
176456289Smckusick 					nqnfs_clientlease(nmp, np, NQL_READ,
176556289Smckusick 						cachable, ltime, frev);
176656289Smckusick 				cache_enter(ndp->ni_dvp, ndp->ni_vp, cnp);
176752196Smckusick 			} else {
176852196Smckusick 				nfsm_adv(nfsm_rndup(len));
176952196Smckusick 			}
177052196Smckusick 			if (newvp != NULLVP) {
177152196Smckusick 				vrele(newvp);
177252196Smckusick 				newvp = NULLVP;
177352196Smckusick 			}
177456289Smckusick 			nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
177552196Smckusick 			if (bigenough)
177656289Smckusick 				endoff = off = fxdr_unsigned(u_long, *tl++);
177752196Smckusick 			else
177856289Smckusick 				endoff = fxdr_unsigned(u_long, *tl++);
177952196Smckusick 			more_dirs = fxdr_unsigned(int, *tl);
178052196Smckusick 		}
178152196Smckusick 		/*
178252196Smckusick 		 * If at end of rpc data, get the eof boolean
178352196Smckusick 		 */
178452196Smckusick 		if (!more_dirs) {
178552196Smckusick 			nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
178652196Smckusick 			more_dirs = (fxdr_unsigned(int, *tl) == 0);
178752196Smckusick 
178852196Smckusick 			/*
178952196Smckusick 			 * If at EOF, cache directory offset
179052196Smckusick 			 */
179152196Smckusick 			if (!more_dirs)
179252196Smckusick 				VTONFS(vp)->n_direofoffset = endoff;
179352196Smckusick 		}
179452196Smckusick 		if (uiop->uio_resid < tresid)
179556289Smckusick 			uiop->uio_offset = (off_t)off;
179652196Smckusick 		else
179752196Smckusick 			more_dirs = 0;
179852196Smckusick 		m_freem(mrep);
179952196Smckusick 	}
180052196Smckusick 	/*
180152196Smckusick 	 * Fill last record, iff any, out to a multiple of NFS_DIRBLKSIZ
180252196Smckusick 	 * by increasing d_reclen for the last record.
180352196Smckusick 	 */
180452196Smckusick 	if (uiop->uio_resid < tresid) {
180552196Smckusick 		len = uiop->uio_resid & (NFS_DIRBLKSIZ - 1);
180652196Smckusick 		if (len > 0) {
180752196Smckusick 			dp->d_reclen += len;
180852196Smckusick 			uiop->uio_iov->iov_base += len;
180952196Smckusick 			uiop->uio_iov->iov_len -= len;
181052196Smckusick 			uiop->uio_resid -= len;
181152196Smckusick 		}
181252196Smckusick 	}
181352196Smckusick nfsmout:
181452196Smckusick 	if (newvp != NULLVP)
181552196Smckusick 		vrele(newvp);
181652196Smckusick 	return (error);
181752196Smckusick }
181839488Smckusick static char hextoasc[] = "0123456789abcdef";
181938414Smckusick 
182038414Smckusick /*
182138414Smckusick  * Silly rename. To make the NFS filesystem that is stateless look a little
182238414Smckusick  * more like the "ufs" a remove of an active vnode is translated to a rename
182338414Smckusick  * to a funny looking filename that is removed by nfs_inactive on the
182438414Smckusick  * nfsnode. There is the potential for another process on a different client
182538414Smckusick  * to create the same funny name between the nfs_lookitup() fails and the
182638414Smckusick  * nfs_rename() completes, but...
182738414Smckusick  */
182852234Sheideman int
182952317Sheideman nfs_sillyrename(dvp, vp, cnp)
183052234Sheideman 	struct vnode *dvp, *vp;
183152234Sheideman 	struct componentname *cnp;
183238414Smckusick {
183338414Smckusick 	register struct nfsnode *np;
183438414Smckusick 	register struct sillyrename *sp;
183538414Smckusick 	int error;
183638414Smckusick 	short pid;
183738414Smckusick 
183852234Sheideman 	cache_purge(dvp);
183952234Sheideman 	np = VTONFS(vp);
184051986Smckusick #ifdef SILLYSEPARATE
184138414Smckusick 	MALLOC(sp, struct sillyrename *, sizeof (struct sillyrename),
184248364Smckusick 		M_NFSREQ, M_WAITOK);
184351986Smckusick #else
184451986Smckusick 	sp = &np->n_silly;
184551986Smckusick #endif
184652234Sheideman 	sp->s_cred = crdup(cnp->cn_cred);
184752234Sheideman 	sp->s_dvp = dvp;
184852234Sheideman 	VREF(dvp);
184938414Smckusick 
185038414Smckusick 	/* Fudge together a funny name */
185152234Sheideman 	pid = cnp->cn_proc->p_pid;
185248364Smckusick 	bcopy(".nfsAxxxx4.4", sp->s_name, 13);
185348364Smckusick 	sp->s_namlen = 12;
185448364Smckusick 	sp->s_name[8] = hextoasc[pid & 0xf];
185548364Smckusick 	sp->s_name[7] = hextoasc[(pid >> 4) & 0xf];
185648364Smckusick 	sp->s_name[6] = hextoasc[(pid >> 8) & 0xf];
185748364Smckusick 	sp->s_name[5] = hextoasc[(pid >> 12) & 0xf];
185838414Smckusick 
185938414Smckusick 	/* Try lookitups until we get one that isn't there */
186052234Sheideman 	while (nfs_lookitup(sp, (nfsv2fh_t *)0, cnp->cn_proc) == 0) {
186148364Smckusick 		sp->s_name[4]++;
186248364Smckusick 		if (sp->s_name[4] > 'z') {
186338414Smckusick 			error = EINVAL;
186438414Smckusick 			goto bad;
186538414Smckusick 		}
186638414Smckusick 	}
186752234Sheideman 	if (error = nfs_renameit(dvp, cnp, sp))
186838414Smckusick 		goto bad;
186952234Sheideman 	nfs_lookitup(sp, &np->n_fh, cnp->cn_proc);
187038414Smckusick 	np->n_sillyrename = sp;
187138414Smckusick 	return (0);
187238414Smckusick bad:
187348364Smckusick 	vrele(sp->s_dvp);
187448364Smckusick 	crfree(sp->s_cred);
187551986Smckusick #ifdef SILLYSEPARATE
187648364Smckusick 	free((caddr_t)sp, M_NFSREQ);
187751986Smckusick #endif
187838414Smckusick 	return (error);
187938414Smckusick }
188038414Smckusick 
188138414Smckusick /*
188238414Smckusick  * Look up a file name for silly rename stuff.
188338414Smckusick  * Just like nfs_lookup() except that it doesn't load returned values
188438414Smckusick  * into the nfsnode table.
188538414Smckusick  * If fhp != NULL it copies the returned file handle out
188638414Smckusick  */
188752234Sheideman int
188852196Smckusick nfs_lookitup(sp, fhp, procp)
188948364Smckusick 	register struct sillyrename *sp;
189038414Smckusick 	nfsv2fh_t *fhp;
189152196Smckusick 	struct proc *procp;
189238414Smckusick {
189348364Smckusick 	register struct vnode *vp = sp->s_dvp;
189448054Smckusick 	register u_long *tl;
189539488Smckusick 	register caddr_t cp;
189639488Smckusick 	register long t1, t2;
189739488Smckusick 	caddr_t bpos, dpos, cp2;
189839488Smckusick 	u_long xid;
189956289Smckusick 	int error = 0, isnq;
190039488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
190138414Smckusick 	long len;
190238414Smckusick 
190356289Smckusick 	isnq = (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS);
190438414Smckusick 	nfsstats.rpccnt[NFSPROC_LOOKUP]++;
190548364Smckusick 	len = sp->s_namlen;
190652196Smckusick 	nfsm_reqhead(vp, NFSPROC_LOOKUP, NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len));
190756289Smckusick 	if (isnq) {
190856289Smckusick 		nfsm_build(tl, u_long *, NFSX_UNSIGNED);
190956289Smckusick 		*tl = 0;
191056289Smckusick 	}
191138414Smckusick 	nfsm_fhtom(vp);
191248364Smckusick 	nfsm_strtom(sp->s_name, len, NFS_MAXNAMLEN);
191352196Smckusick 	nfsm_request(vp, NFSPROC_LOOKUP, procp, sp->s_cred);
191438414Smckusick 	if (fhp != NULL) {
191556289Smckusick 		if (isnq)
191656289Smckusick 			nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
191752196Smckusick 		nfsm_dissect(cp, caddr_t, NFSX_FH);
191838414Smckusick 		bcopy(cp, (caddr_t)fhp, NFSX_FH);
191938414Smckusick 	}
192038414Smckusick 	nfsm_reqdone;
192138414Smckusick 	return (error);
192238414Smckusick }
192338414Smckusick 
192438414Smckusick /*
192538414Smckusick  * Kludge City..
192638414Smckusick  * - make nfs_bmap() essentially a no-op that does no translation
192741905Smckusick  * - do nfs_strategy() by faking physical I/O with nfs_readrpc/nfs_writerpc
192838414Smckusick  *   after mapping the physical addresses into Kernel Virtual space in the
192938414Smckusick  *   nfsiobuf area.
193038414Smckusick  *   (Maybe I could use the process's page mapping, but I was concerned that
193138414Smckusick  *    Kernel Write might not be enabled and also figured copyout() would do
193238414Smckusick  *    a lot more work than bcopy() and also it currently happens in the
193338414Smckusick  *    context of the swapper process (2).
193438414Smckusick  */
193552234Sheideman int
193653806Smckusick nfs_bmap(ap)
193754668Smckusick 	struct vop_bmap_args /* {
193854668Smckusick 		struct vnode *a_vp;
193954668Smckusick 		daddr_t  a_bn;
194054668Smckusick 		struct vnode **a_vpp;
194154668Smckusick 		daddr_t *a_bnp;
194254668Smckusick 	} */ *ap;
194338414Smckusick {
194453806Smckusick 	register struct vnode *vp = ap->a_vp;
194553806Smckusick 
194653600Sheideman 	if (ap->a_vpp != NULL)
194753806Smckusick 		*ap->a_vpp = vp;
194853600Sheideman 	if (ap->a_bnp != NULL)
194953806Smckusick 		*ap->a_bnp = ap->a_bn * btodb(vp->v_mount->mnt_stat.f_iosize);
195038414Smckusick 	return (0);
195138414Smckusick }
195238414Smckusick 
195338414Smckusick /*
195438884Smacklem  * Strategy routine for phys. i/o
195538884Smacklem  * If the biod's are running, queue a request
195638884Smacklem  * otherwise just call nfs_doio() to get it done
195738414Smckusick  */
195852234Sheideman int
195953806Smckusick nfs_strategy(ap)
196054668Smckusick 	struct vop_strategy_args /* {
196154668Smckusick 		struct buf *a_bp;
196254668Smckusick 	} */ *ap;
196338414Smckusick {
196453806Smckusick 	register struct buf *bp = ap->a_bp;
196539341Smckusick 	register int i;
196638884Smacklem 	int error = 0;
196739341Smckusick 	int fnd = 0;
196838884Smacklem 
196938884Smacklem 	/*
197041905Smckusick 	 * Set b_proc. It seems a bit silly to do it here, but since bread()
197141905Smckusick 	 * doesn't set it, I will.
197246450Skarels 	 * Set b_proc == NULL for asynchronous ops, since these may still
197341905Smckusick 	 * be hanging about after the process terminates.
197441905Smckusick 	 */
197553806Smckusick 	if ((bp->b_flags & B_PHYS) == 0) {
197653806Smckusick 		if (bp->b_flags & B_ASYNC)
197753806Smckusick 			bp->b_proc = (struct proc *)0;
197846988Smckusick 		else
197953806Smckusick 			bp->b_proc = curproc;
198046988Smckusick 	}
198141905Smckusick 	/*
198246450Skarels 	 * If the op is asynchronous and an i/o daemon is waiting
198338884Smacklem 	 * queue the request, wake it up and wait for completion
198446450Skarels 	 * otherwise just do it ourselves.
198538884Smacklem 	 */
198653806Smckusick 	if ((bp->b_flags & B_ASYNC) == 0 || nfs_numasync == 0)
198753806Smckusick 		return (nfs_doio(bp));
198846988Smckusick 	for (i = 0; i < NFS_MAXASYNCDAEMON; i++) {
198946988Smckusick 		if (nfs_iodwant[i]) {
1990*56390Smckusick 			bp->b_actf = NULL;
1991*56390Smckusick 			bp->b_actb = nfs_bqueuetail;
1992*56390Smckusick 			*nfs_bqueuetail = bp;
1993*56390Smckusick 			nfs_bqueuetail = &bp->b_actf;
199439341Smckusick 			fnd++;
199539341Smckusick 			wakeup((caddr_t)&nfs_iodwant[i]);
199639341Smckusick 			break;
199738884Smacklem 		}
199839341Smckusick 	}
199939341Smckusick 	if (!fnd)
200053806Smckusick 		error = nfs_doio(bp);
200138884Smacklem 	return (error);
200238884Smacklem }
200338884Smacklem 
200438884Smacklem /*
200538884Smacklem  * Fun and games with i/o
200638884Smacklem  * Essentially play ubasetup() and disk interrupt service routine by
200738884Smacklem  * mapping the data buffer into kernel virtual space and doing the
200838884Smacklem  * nfs read or write rpc's from it.
200941905Smckusick  * If the nfsiod's are not running, this is just called from nfs_strategy(),
201041905Smckusick  * otherwise it is called by the nfsiods to do what would normally be
201138884Smacklem  * partially disk interrupt driven.
201238884Smacklem  */
201352234Sheideman int
201438884Smacklem nfs_doio(bp)
201538884Smacklem 	register struct buf *bp;
201638884Smacklem {
201738414Smckusick 	register struct uio *uiop;
201838414Smckusick 	register struct vnode *vp;
201939341Smckusick 	struct nfsnode *np;
202038884Smacklem 	struct ucred *cr;
202141539Smckusick 	int error;
202241539Smckusick 	struct uio uio;
202341539Smckusick 	struct iovec io;
202438414Smckusick 
202538414Smckusick 	vp = bp->b_vp;
202640251Smckusick 	np = VTONFS(vp);
202738414Smckusick 	uiop = &uio;
202838414Smckusick 	uiop->uio_iov = &io;
202938414Smckusick 	uiop->uio_iovcnt = 1;
203038414Smckusick 	uiop->uio_segflg = UIO_SYSSPACE;
203152196Smckusick 	uiop->uio_procp = bp->b_proc;
203239751Smckusick 
203338414Smckusick 	/*
203438884Smacklem 	 * For phys i/o, map the b_addr into kernel virtual space using
203538884Smacklem 	 * the Nfsiomap pte's
203638884Smacklem 	 * Also, add a temporary b_rcred for reading using the process's uid
203738884Smacklem 	 * and a guess at a group
203838414Smckusick 	 */
203938884Smacklem 	if (bp->b_flags & B_PHYS) {
204048054Smckusick 		if (bp->b_flags & B_DIRTY)
204148054Smckusick 			uiop->uio_procp = pageproc;
204248054Smckusick 		cr = crcopy(uiop->uio_procp->p_ucred);
204341539Smckusick 		/* mapping was already done by vmapbuf */
204441539Smckusick 		io.iov_base = bp->b_un.b_addr;
204539751Smckusick 
204638884Smacklem 		/*
204739751Smckusick 		 * And do the i/o rpc
204839751Smckusick 		 */
204939751Smckusick 		io.iov_len = uiop->uio_resid = bp->b_bcount;
205039823Smckusick 		uiop->uio_offset = bp->b_blkno * DEV_BSIZE;
205139751Smckusick 		if (bp->b_flags & B_READ) {
205239751Smckusick 			uiop->uio_rw = UIO_READ;
205339751Smckusick 			nfsstats.read_physios++;
205448054Smckusick 			bp->b_error = error = nfs_readrpc(vp, uiop, cr);
205545717Smckusick 			(void) vnode_pager_uncache(vp);
205639751Smckusick 		} else {
205739751Smckusick 			uiop->uio_rw = UIO_WRITE;
205839751Smckusick 			nfsstats.write_physios++;
205956289Smckusick 			bp->b_error = error = nfs_writerpc(vp, uiop, cr, 0);
206039341Smckusick 		}
206139751Smckusick 
206239751Smckusick 		/*
206339751Smckusick 		 * Finally, release pte's used by physical i/o
206439751Smckusick 		 */
206538884Smacklem 		crfree(cr);
206639751Smckusick 	} else {
206739751Smckusick 		if (bp->b_flags & B_READ) {
206839751Smckusick 			io.iov_len = uiop->uio_resid = bp->b_bcount;
206939751Smckusick 			io.iov_base = bp->b_un.b_addr;
207039751Smckusick 			uiop->uio_rw = UIO_READ;
207141905Smckusick 			switch (vp->v_type) {
207241905Smckusick 			case VREG:
207341905Smckusick 				uiop->uio_offset = bp->b_blkno * DEV_BSIZE;
207441905Smckusick 				nfsstats.read_bios++;
207548054Smckusick 				error = nfs_readrpc(vp, uiop, bp->b_rcred);
207641905Smckusick 				break;
207741905Smckusick 			case VLNK:
207841905Smckusick 				uiop->uio_offset = 0;
207941905Smckusick 				nfsstats.readlink_bios++;
208048054Smckusick 				error = nfs_readlinkrpc(vp, uiop, bp->b_rcred);
208141905Smckusick 				break;
208241905Smckusick 			case VDIR:
208341905Smckusick 				uiop->uio_offset = bp->b_lblkno;
208441905Smckusick 				nfsstats.readdir_bios++;
208556289Smckusick 				if (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS)
208652196Smckusick 				    error = nfs_readdirlookrpc(vp, uiop, bp->b_rcred);
208752196Smckusick 				else
208852196Smckusick 				    error = nfs_readdirrpc(vp, uiop, bp->b_rcred);
208941905Smckusick 				/*
209041905Smckusick 				 * Save offset cookie in b_blkno.
209141905Smckusick 				 */
209241905Smckusick 				bp->b_blkno = uiop->uio_offset;
209341905Smckusick 				break;
209441905Smckusick 			};
209541905Smckusick 			bp->b_error = error;
209639751Smckusick 		} else {
209739751Smckusick 			io.iov_len = uiop->uio_resid = bp->b_dirtyend
209839751Smckusick 				- bp->b_dirtyoff;
209939823Smckusick 			uiop->uio_offset = (bp->b_blkno * DEV_BSIZE)
210039751Smckusick 				+ bp->b_dirtyoff;
210139751Smckusick 			io.iov_base = bp->b_un.b_addr + bp->b_dirtyoff;
210239751Smckusick 			uiop->uio_rw = UIO_WRITE;
210339751Smckusick 			nfsstats.write_bios++;
210441905Smckusick 			bp->b_error = error = nfs_writerpc(vp, uiop,
210556289Smckusick 				bp->b_wcred, 0);
210639751Smckusick 			if (error) {
210739751Smckusick 				np->n_error = error;
210839751Smckusick 				np->n_flag |= NWRITEERR;
210939751Smckusick 			}
211039751Smckusick 			bp->b_dirtyoff = bp->b_dirtyend = 0;
211139751Smckusick 		}
211238884Smacklem 	}
211339751Smckusick 	if (error)
211439751Smckusick 		bp->b_flags |= B_ERROR;
211539751Smckusick 	bp->b_resid = uiop->uio_resid;
211638414Smckusick 	biodone(bp);
211738414Smckusick 	return (error);
211838414Smckusick }
211938884Smacklem 
212038884Smacklem /*
212148054Smckusick  * Mmap a file
212248054Smckusick  *
212348054Smckusick  * NB Currently unsupported.
212448054Smckusick  */
212548054Smckusick /* ARGSUSED */
212652234Sheideman int
212753806Smckusick nfs_mmap(ap)
212854668Smckusick 	struct vop_mmap_args /* {
212954668Smckusick 		struct vnode *a_vp;
213054668Smckusick 		int  a_fflags;
213154668Smckusick 		struct ucred *a_cred;
213254668Smckusick 		struct proc *a_p;
213354668Smckusick 	} */ *ap;
213448054Smckusick {
213548054Smckusick 
213648054Smckusick 	return (EINVAL);
213748054Smckusick }
213848054Smckusick 
213948054Smckusick /*
214038884Smacklem  * Flush all the blocks associated with a vnode.
214138884Smacklem  * 	Walk through the buffer pool and push any dirty pages
214238884Smacklem  *	associated with the vnode.
214338884Smacklem  */
214439488Smckusick /* ARGSUSED */
214552234Sheideman int
214653806Smckusick nfs_fsync(ap)
214754451Smckusick 	struct vop_fsync_args /* {
214854451Smckusick 		struct vnodeop_desc *a_desc;
214954451Smckusick 		struct vnode * a_vp;
215054451Smckusick 		struct ucred * a_cred;
215154451Smckusick 		int  a_waitfor;
215254451Smckusick 		struct proc * a_p;
215354451Smckusick 	} */ *ap;
215438884Smacklem {
215554451Smckusick 	register struct vnode *vp = ap->a_vp;
215654451Smckusick 	register struct nfsnode *np = VTONFS(vp);
215754451Smckusick 	register struct buf *bp;
215854451Smckusick 	struct buf *nbp;
215954451Smckusick 	int s, error = 0;
216038884Smacklem 
216154451Smckusick loop:
216254451Smckusick 	s = splbio();
216354451Smckusick 	for (bp = vp->v_dirtyblkhd; bp; bp = nbp) {
216454451Smckusick 		nbp = bp->b_blockf;
216554451Smckusick 		if ((bp->b_flags & B_BUSY))
216654451Smckusick 			continue;
216754451Smckusick 		if ((bp->b_flags & B_DELWRI) == 0)
216854451Smckusick 			panic("nfs_fsync: not dirty");
216954451Smckusick 		bremfree(bp);
217054451Smckusick 		bp->b_flags |= B_BUSY;
217154451Smckusick 		splx(s);
217254451Smckusick 		error = bawrite(bp);
217354451Smckusick 		goto loop;
217438884Smacklem 	}
217554451Smckusick 	if (ap->a_waitfor == MNT_WAIT) {
217654451Smckusick 		while (vp->v_numoutput) {
217754451Smckusick 			vp->v_flag |= VBWAIT;
217854451Smckusick 			sleep((caddr_t)&vp->v_numoutput, PRIBIO + 1);
217954451Smckusick 		}
218054451Smckusick #ifdef DIAGNOSTIC
218154451Smckusick 		if (vp->v_dirtyblkhd) {
218254451Smckusick 			vprint("nfs_fsync: dirty", vp);
218354451Smckusick 			goto loop;
218454451Smckusick 		}
218554451Smckusick #endif
218654451Smckusick 	}
218754451Smckusick 	splx(s);
218854451Smckusick 	np->n_flag &= ~NMODIFIED;
218953629Smckusick 	if (np->n_flag & NWRITEERR) {
219039751Smckusick 		error = np->n_error;
219153629Smckusick 		np->n_flag &= ~NWRITEERR;
219253629Smckusick 	}
219338884Smacklem 	return (error);
219438884Smacklem }
219539672Smckusick 
219639672Smckusick /*
219746201Smckusick  * NFS advisory byte-level locks.
219846201Smckusick  * Currently unsupported.
219946201Smckusick  */
220052234Sheideman int
220153806Smckusick nfs_advlock(ap)
220254668Smckusick 	struct vop_advlock_args /* {
220354668Smckusick 		struct vnode *a_vp;
220454668Smckusick 		caddr_t  a_id;
220554668Smckusick 		int  a_op;
220654668Smckusick 		struct flock *a_fl;
220754668Smckusick 		int  a_flags;
220854668Smckusick 	} */ *ap;
220946201Smckusick {
221046201Smckusick 
221146201Smckusick 	return (EOPNOTSUPP);
221246201Smckusick }
221346201Smckusick 
221446201Smckusick /*
221539672Smckusick  * Print out the contents of an nfsnode.
221639672Smckusick  */
221752234Sheideman int
221853806Smckusick nfs_print(ap)
221954668Smckusick 	struct vop_print_args /* {
222054668Smckusick 		struct vnode *a_vp;
222154668Smckusick 	} */ *ap;
222239672Smckusick {
222353806Smckusick 	register struct vnode *vp = ap->a_vp;
222453806Smckusick 	register struct nfsnode *np = VTONFS(vp);
222539672Smckusick 
222640294Smckusick 	printf("tag VT_NFS, fileid %d fsid 0x%x",
222740294Smckusick 		np->n_vattr.va_fileid, np->n_vattr.va_fsid);
222840294Smckusick #ifdef FIFO
222953806Smckusick 	if (vp->v_type == VFIFO)
223053806Smckusick 		fifo_printinfo(vp);
223140294Smckusick #endif /* FIFO */
223239914Smckusick 	printf("\n");
223339672Smckusick }
223451573Smckusick 
223551573Smckusick /*
223651573Smckusick  * NFS directory offset lookup.
223751573Smckusick  * Currently unsupported.
223851573Smckusick  */
223952234Sheideman int
224053806Smckusick nfs_blkatoff(ap)
224154668Smckusick 	struct vop_blkatoff_args /* {
224254668Smckusick 		struct vnode *a_vp;
224354668Smckusick 		off_t a_offset;
224454668Smckusick 		char **a_res;
224554668Smckusick 		struct buf **a_bpp;
224654668Smckusick 	} */ *ap;
224751573Smckusick {
224851573Smckusick 
224951573Smckusick 	return (EOPNOTSUPP);
225051573Smckusick }
225151573Smckusick 
225251573Smckusick /*
225351573Smckusick  * NFS flat namespace allocation.
225451573Smckusick  * Currently unsupported.
225551573Smckusick  */
225652234Sheideman int
225753806Smckusick nfs_valloc(ap)
225854668Smckusick 	struct vop_valloc_args /* {
225954668Smckusick 		struct vnode *a_pvp;
226054668Smckusick 		int a_mode;
226154668Smckusick 		struct ucred *a_cred;
226254668Smckusick 		struct vnode **a_vpp;
226354668Smckusick 	} */ *ap;
226451573Smckusick {
226551573Smckusick 
226651573Smckusick 	return (EOPNOTSUPP);
226751573Smckusick }
226851573Smckusick 
226951573Smckusick /*
227051573Smckusick  * NFS flat namespace free.
227151573Smckusick  * Currently unsupported.
227251573Smckusick  */
227353582Sheideman int
227453806Smckusick nfs_vfree(ap)
227554668Smckusick 	struct vop_vfree_args /* {
227654668Smckusick 		struct vnode *a_pvp;
227754668Smckusick 		ino_t a_ino;
227854668Smckusick 		int a_mode;
227954668Smckusick 	} */ *ap;
228051573Smckusick {
228151573Smckusick 
228253582Sheideman 	return (EOPNOTSUPP);
228351573Smckusick }
228451573Smckusick 
228551573Smckusick /*
228651573Smckusick  * NFS file truncation.
228751573Smckusick  */
228852234Sheideman int
228953806Smckusick nfs_truncate(ap)
229054668Smckusick 	struct vop_truncate_args /* {
229154668Smckusick 		struct vnode *a_vp;
229254668Smckusick 		off_t a_length;
229354668Smckusick 		int a_flags;
229454668Smckusick 		struct ucred *a_cred;
229554668Smckusick 		struct proc *a_p;
229654668Smckusick 	} */ *ap;
229751573Smckusick {
229851573Smckusick 
229951573Smckusick 	/* Use nfs_setattr */
230051573Smckusick 	printf("nfs_truncate: need to implement!!");
230151573Smckusick 	return (EOPNOTSUPP);
230251573Smckusick }
230351573Smckusick 
230451573Smckusick /*
230551573Smckusick  * NFS update.
230651573Smckusick  */
230752234Sheideman int
230853806Smckusick nfs_update(ap)
230954668Smckusick 	struct vop_update_args /* {
231054668Smckusick 		struct vnode *a_vp;
231154668Smckusick 		struct timeval *a_ta;
231254668Smckusick 		struct timeval *a_tm;
231354668Smckusick 		int a_waitfor;
231454668Smckusick 	} */ *ap;
231551573Smckusick {
231651573Smckusick 
231751573Smckusick 	/* Use nfs_setattr */
231851573Smckusick 	printf("nfs_update: need to implement!!");
231951573Smckusick 	return (EOPNOTSUPP);
232051573Smckusick }
232153629Smckusick 
232253629Smckusick /*
232356364Smckusick  * nfs special file access vnode op.
232456364Smckusick  * Essentially just get vattr and then imitate iaccess() since the device is
232556364Smckusick  * local to the client.
232656364Smckusick  */
232756364Smckusick int
232856364Smckusick nfsspec_access(ap)
232956364Smckusick 	struct vop_access_args /* {
233056364Smckusick 		struct vnode *a_vp;
233156364Smckusick 		int  a_mode;
233256364Smckusick 		struct ucred *a_cred;
233356364Smckusick 		struct proc *a_p;
233456364Smckusick 	} */ *ap;
233556364Smckusick {
233656364Smckusick 	register struct vattr *vap;
233756364Smckusick 	register gid_t *gp;
233856364Smckusick 	register struct ucred *cred = ap->a_cred;
233956364Smckusick 	mode_t mode = ap->a_mode;
234056364Smckusick 	struct vattr vattr;
234156364Smckusick 	register int i;
234256364Smckusick 	int error;
234356364Smckusick 
234456364Smckusick 	/*
234556364Smckusick 	 * If you're the super-user,
234656364Smckusick 	 * you always get access.
234756364Smckusick 	 */
234856364Smckusick 	if (cred->cr_uid == 0)
234956364Smckusick 		return (0);
235056364Smckusick 	vap = &vattr;
235156364Smckusick 	if (error = VOP_GETATTR(ap->a_vp, vap, cred, ap->a_p))
235256364Smckusick 		return (error);
235356364Smckusick 	/*
235456364Smckusick 	 * Access check is based on only one of owner, group, public.
235556364Smckusick 	 * If not owner, then check group. If not a member of the
235656364Smckusick 	 * group, then check public access.
235756364Smckusick 	 */
235856364Smckusick 	if (cred->cr_uid != vap->va_uid) {
235956364Smckusick 		mode >>= 3;
236056364Smckusick 		gp = cred->cr_groups;
236156364Smckusick 		for (i = 0; i < cred->cr_ngroups; i++, gp++)
236256364Smckusick 			if (vap->va_gid == *gp)
236356364Smckusick 				goto found;
236456364Smckusick 		mode >>= 3;
236556364Smckusick found:
236656364Smckusick 		;
236756364Smckusick 	}
236856364Smckusick 	if ((vap->va_mode & mode) != 0)
236956364Smckusick 		return (0);
237056364Smckusick 	return (EACCES);
237156364Smckusick }
237256364Smckusick 
237356364Smckusick /*
237453629Smckusick  * Read wrapper for special devices.
237553629Smckusick  */
237653629Smckusick int
237753629Smckusick nfsspec_read(ap)
237854668Smckusick 	struct vop_read_args /* {
237954668Smckusick 		struct vnode *a_vp;
238054668Smckusick 		struct uio *a_uio;
238154668Smckusick 		int  a_ioflag;
238254668Smckusick 		struct ucred *a_cred;
238354668Smckusick 	} */ *ap;
238453629Smckusick {
238554032Smckusick 	register struct nfsnode *np = VTONFS(ap->a_vp);
238653629Smckusick 
238753629Smckusick 	/*
238853629Smckusick 	 * Set access flag.
238953629Smckusick 	 */
239054032Smckusick 	np->n_flag |= NACC;
239154032Smckusick 	np->n_atim = time;
239253629Smckusick 	return (VOCALL(spec_vnodeop_p, VOFFSET(vop_read), ap));
239353629Smckusick }
239453629Smckusick 
239553629Smckusick /*
239653629Smckusick  * Write wrapper for special devices.
239753629Smckusick  */
239853629Smckusick int
239953629Smckusick nfsspec_write(ap)
240054668Smckusick 	struct vop_write_args /* {
240154668Smckusick 		struct vnode *a_vp;
240254668Smckusick 		struct uio *a_uio;
240354668Smckusick 		int  a_ioflag;
240454668Smckusick 		struct ucred *a_cred;
240554668Smckusick 	} */ *ap;
240653629Smckusick {
240754032Smckusick 	register struct nfsnode *np = VTONFS(ap->a_vp);
240853629Smckusick 
240953629Smckusick 	/*
241054032Smckusick 	 * Set update flag.
241153629Smckusick 	 */
241254032Smckusick 	np->n_flag |= NUPD;
241354032Smckusick 	np->n_mtim = time;
241453629Smckusick 	return (VOCALL(spec_vnodeop_p, VOFFSET(vop_write), ap));
241553629Smckusick }
241653629Smckusick 
241753629Smckusick /*
241853629Smckusick  * Close wrapper for special devices.
241953629Smckusick  *
242053629Smckusick  * Update the times on the nfsnode then do device close.
242153629Smckusick  */
242253629Smckusick int
242353629Smckusick nfsspec_close(ap)
242454668Smckusick 	struct vop_close_args /* {
242554668Smckusick 		struct vnode *a_vp;
242654668Smckusick 		int  a_fflag;
242754668Smckusick 		struct ucred *a_cred;
242854668Smckusick 		struct proc *a_p;
242954668Smckusick 	} */ *ap;
243053629Smckusick {
243153806Smckusick 	register struct vnode *vp = ap->a_vp;
243253806Smckusick 	register struct nfsnode *np = VTONFS(vp);
243353629Smckusick 	struct vattr vattr;
243453629Smckusick 
243553629Smckusick 	if (np->n_flag & (NACC | NUPD)) {
243653629Smckusick 		np->n_flag |= NCHG;
243753806Smckusick 		if (vp->v_usecount == 1 &&
243853806Smckusick 		    (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) {
243953629Smckusick 			VATTR_NULL(&vattr);
244054106Smckusick 			if (np->n_flag & NACC) {
244154106Smckusick 				vattr.va_atime.ts_sec = np->n_atim.tv_sec;
244254106Smckusick 				vattr.va_atime.ts_nsec =
244354106Smckusick 				    np->n_atim.tv_usec * 1000;
244454106Smckusick 			}
244554106Smckusick 			if (np->n_flag & NUPD) {
244654106Smckusick 				vattr.va_mtime.ts_sec = np->n_mtim.tv_sec;
244754106Smckusick 				vattr.va_mtime.ts_nsec =
244854106Smckusick 				    np->n_mtim.tv_usec * 1000;
244954106Smckusick 			}
245053806Smckusick 			(void)VOP_SETATTR(vp, &vattr, ap->a_cred, ap->a_p);
245153629Smckusick 		}
245253629Smckusick 	}
245353629Smckusick 	return (VOCALL(spec_vnodeop_p, VOFFSET(vop_close), ap));
245453629Smckusick }
245553629Smckusick 
245653629Smckusick #ifdef FIFO
245753629Smckusick /*
245853629Smckusick  * Read wrapper for fifos.
245953629Smckusick  */
246053629Smckusick int
246153629Smckusick nfsfifo_read(ap)
246254668Smckusick 	struct vop_read_args /* {
246354668Smckusick 		struct vnode *a_vp;
246454668Smckusick 		struct uio *a_uio;
246554668Smckusick 		int  a_ioflag;
246654668Smckusick 		struct ucred *a_cred;
246754668Smckusick 	} */ *ap;
246853629Smckusick {
246953629Smckusick 	extern int (**fifo_vnodeop_p)();
247054032Smckusick 	register struct nfsnode *np = VTONFS(ap->a_vp);
247153629Smckusick 
247253629Smckusick 	/*
247353629Smckusick 	 * Set access flag.
247453629Smckusick 	 */
247554032Smckusick 	np->n_flag |= NACC;
247654032Smckusick 	np->n_atim = time;
247753629Smckusick 	return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_read), ap));
247853629Smckusick }
247953629Smckusick 
248053629Smckusick /*
248153629Smckusick  * Write wrapper for fifos.
248253629Smckusick  */
248353629Smckusick int
248453629Smckusick nfsfifo_write(ap)
248554668Smckusick 	struct vop_write_args /* {
248654668Smckusick 		struct vnode *a_vp;
248754668Smckusick 		struct uio *a_uio;
248854668Smckusick 		int  a_ioflag;
248954668Smckusick 		struct ucred *a_cred;
249054668Smckusick 	} */ *ap;
249153629Smckusick {
249253629Smckusick 	extern int (**fifo_vnodeop_p)();
249354032Smckusick 	register struct nfsnode *np = VTONFS(ap->a_vp);
249453629Smckusick 
249553629Smckusick 	/*
249653629Smckusick 	 * Set update flag.
249753629Smckusick 	 */
249854032Smckusick 	np->n_flag |= NUPD;
249954032Smckusick 	np->n_mtim = time;
250053629Smckusick 	return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_write), ap));
250153629Smckusick }
250253629Smckusick 
250353629Smckusick /*
250453629Smckusick  * Close wrapper for fifos.
250553629Smckusick  *
250653629Smckusick  * Update the times on the nfsnode then do fifo close.
250753629Smckusick  */
250853629Smckusick int
250953629Smckusick nfsfifo_close(ap)
251054668Smckusick 	struct vop_close_args /* {
251154668Smckusick 		struct vnode *a_vp;
251254668Smckusick 		int  a_fflag;
251354668Smckusick 		struct ucred *a_cred;
251454668Smckusick 		struct proc *a_p;
251554668Smckusick 	} */ *ap;
251653629Smckusick {
251753806Smckusick 	register struct vnode *vp = ap->a_vp;
251853806Smckusick 	register struct nfsnode *np = VTONFS(vp);
251953629Smckusick 	struct vattr vattr;
252053629Smckusick 	extern int (**fifo_vnodeop_p)();
252153629Smckusick 
252253629Smckusick 	if (np->n_flag & (NACC | NUPD)) {
252353629Smckusick 		if (np->n_flag & NACC)
252453629Smckusick 			np->n_atim = time;
252553629Smckusick 		if (np->n_flag & NUPD)
252653629Smckusick 			np->n_mtim = time;
252753629Smckusick 		np->n_flag |= NCHG;
252853806Smckusick 		if (vp->v_usecount == 1 &&
252953806Smckusick 		    (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) {
253053629Smckusick 			VATTR_NULL(&vattr);
253154106Smckusick 			if (np->n_flag & NACC) {
253254106Smckusick 				vattr.va_atime.ts_sec = np->n_atim.tv_sec;
253354106Smckusick 				vattr.va_atime.ts_nsec =
253454106Smckusick 				    np->n_atim.tv_usec * 1000;
253554106Smckusick 			}
253654106Smckusick 			if (np->n_flag & NUPD) {
253754106Smckusick 				vattr.va_mtime.ts_sec = np->n_mtim.tv_sec;
253854106Smckusick 				vattr.va_mtime.ts_nsec =
253954106Smckusick 				    np->n_mtim.tv_usec * 1000;
254054106Smckusick 			}
254153806Smckusick 			(void)VOP_SETATTR(vp, &vattr, ap->a_cred, ap->a_p);
254253629Smckusick 		}
254353629Smckusick 	}
254453629Smckusick 	return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_close), ap));
254553629Smckusick }
254653629Smckusick #endif /* FIFO */
2547