xref: /csrg-svn/sys/nfs/nfs_vnops.c (revision 56468)
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*56468Smckusick  *	@(#)nfs_vnops.c	7.96 (Berkeley) 10/08/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;
20856390Smckusick /* Queue head for nfsiod's */
209*56468Smckusick struct queue_entry nfs_bufq;
21054740Smckusick #define	DIRHDSIZ	(sizeof (struct dirent) - (MAXNAMLEN + 1))
21138414Smckusick 
21238414Smckusick /*
21338414Smckusick  * nfs null call from vfs.
21438414Smckusick  */
21552234Sheideman int
21652196Smckusick nfs_null(vp, cred, procp)
21738414Smckusick 	struct vnode *vp;
21838414Smckusick 	struct ucred *cred;
21952196Smckusick 	struct proc *procp;
22038414Smckusick {
22139488Smckusick 	caddr_t bpos, dpos;
22239488Smckusick 	int error = 0;
22339488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb;
22438414Smckusick 
22552196Smckusick 	nfsm_reqhead(vp, NFSPROC_NULL, 0);
22652196Smckusick 	nfsm_request(vp, NFSPROC_NULL, procp, cred);
22738414Smckusick 	nfsm_reqdone;
22838414Smckusick 	return (error);
22938414Smckusick }
23038414Smckusick 
23138414Smckusick /*
23238414Smckusick  * nfs access vnode op.
23356364Smckusick  * For nfs, just return ok. File accesses may fail later.
23456364Smckusick  * For nqnfs, use the access rpc to check accessibility. If file modes are
23556364Smckusick  * changed on the server, accesses might still fail later.
23638414Smckusick  */
23752234Sheideman int
23853806Smckusick nfs_access(ap)
23954668Smckusick 	struct vop_access_args /* {
24054668Smckusick 		struct vnode *a_vp;
24154668Smckusick 		int  a_mode;
24254668Smckusick 		struct ucred *a_cred;
24354668Smckusick 		struct proc *a_p;
24454668Smckusick 	} */ *ap;
24538414Smckusick {
24656364Smckusick 	register struct vnode *vp = ap->a_vp;
24756364Smckusick 	register u_long *tl;
24856364Smckusick 	register caddr_t cp;
24956364Smckusick 	caddr_t bpos, dpos;
25056364Smckusick 	int error = 0;
25156364Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
25238414Smckusick 
25338414Smckusick 	/*
25456364Smckusick 	 * There is no way to check accessibility via. ordinary nfs, so if
25556364Smckusick 	 * access isn't allowed they will get burned later.
25638414Smckusick 	 */
25756364Smckusick 	if (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) {
25856364Smckusick 		nfsstats.rpccnt[NQNFSPROC_ACCESS]++;
25956364Smckusick 		nfsm_reqhead(vp, NQNFSPROC_ACCESS, NFSX_FH + 3 * NFSX_UNSIGNED);
26056364Smckusick 		nfsm_fhtom(vp);
26156364Smckusick 		nfsm_build(tl, u_long *, 3 * NFSX_UNSIGNED);
26256364Smckusick 		if (ap->a_mode & VREAD)
26356364Smckusick 			*tl++ = nfs_true;
26456364Smckusick 		else
26556364Smckusick 			*tl++ = nfs_false;
26656364Smckusick 		if (ap->a_mode & VWRITE)
26756364Smckusick 			*tl++ = nfs_true;
26856364Smckusick 		else
26956364Smckusick 			*tl++ = nfs_false;
27056364Smckusick 		if (ap->a_mode & VEXEC)
27156364Smckusick 			*tl = nfs_true;
27256364Smckusick 		else
27356364Smckusick 			*tl = nfs_false;
27456364Smckusick 		nfsm_request(vp, NQNFSPROC_ACCESS, ap->a_p, ap->a_cred);
27556364Smckusick 		nfsm_reqdone;
27638884Smacklem 		return (error);
27756364Smckusick 	} else
27838414Smckusick 		return (0);
27938414Smckusick }
28038414Smckusick 
28138414Smckusick /*
28238414Smckusick  * nfs open vnode op
28356289Smckusick  * Check to see if the type is ok
28452196Smckusick  * and that deletion is not in progress.
28556289Smckusick  * For paged in text files, you will need to flush the page cache
28656289Smckusick  * if consistency is lost.
28738414Smckusick  */
28839488Smckusick /* ARGSUSED */
28952234Sheideman int
29053806Smckusick nfs_open(ap)
29154668Smckusick 	struct vop_open_args /* {
29254668Smckusick 		struct vnode *a_vp;
29354668Smckusick 		int  a_mode;
29454668Smckusick 		struct ucred *a_cred;
29554668Smckusick 		struct proc *a_p;
29654668Smckusick 	} */ *ap;
29738414Smckusick {
29853806Smckusick 	register struct vnode *vp = ap->a_vp;
29956289Smckusick 	struct nfsnode *np = VTONFS(vp);
30056289Smckusick 	struct nfsmount *nmp = VFSTONFS(vp->v_mount);
30156289Smckusick 	struct vattr vattr;
30256289Smckusick 	int error;
30338414Smckusick 
30453806Smckusick 	if (vp->v_type != VREG && vp->v_type != VDIR && vp->v_type != VLNK)
30538414Smckusick 		return (EACCES);
30656289Smckusick 	if (vp->v_flag & VTEXT) {
30756289Smckusick 	    /*
30856289Smckusick 	     * Get a valid lease. If cached data is stale, flush it.
30956289Smckusick 	     */
31056289Smckusick 	    if (nmp->nm_flag & NFSMNT_NQNFS) {
31156289Smckusick 		if (NQNFS_CKINVALID(vp, np, NQL_READ)) {
31256289Smckusick 		    do {
31356289Smckusick 			error = nqnfs_getlease(vp, NQL_READ, ap->a_cred, ap->a_p);
31456289Smckusick 		    } while (error == NQNFS_EXPIRED);
31556289Smckusick 		    if (error)
31656289Smckusick 			return (error);
31756289Smckusick 		    if (np->n_lrev != np->n_brev) {
31856289Smckusick 			np->n_flag &= ~NMODIFIED;
31956289Smckusick 			vinvalbuf(vp, TRUE, ap->a_cred, ap->a_p);
32056289Smckusick 			(void) vnode_pager_uncache(vp);
32156289Smckusick 			np->n_brev = np->n_lrev;
32256289Smckusick 		    }
32356289Smckusick 		}
32456289Smckusick 	    } else {
32556289Smckusick 		if (np->n_flag & NMODIFIED) {
32656289Smckusick 			np->n_flag &= ~NMODIFIED;
32756289Smckusick 			vinvalbuf(vp, TRUE, ap->a_cred, ap->a_p);
32856289Smckusick 			(void) vnode_pager_uncache(vp);
32956289Smckusick 			np->n_attrstamp = 0;
33056289Smckusick 			np->n_direofoffset = 0;
33156289Smckusick 			if (error = VOP_GETATTR(vp, &vattr, ap->a_cred, ap->a_p))
33256289Smckusick 				return (error);
33356289Smckusick 			np->n_mtime = vattr.va_mtime.ts_sec;
33456289Smckusick 		} else {
33556289Smckusick 			if (error = VOP_GETATTR(vp, &vattr, ap->a_cred, ap->a_p))
33656289Smckusick 				return (error);
33756289Smckusick 			if (np->n_mtime != vattr.va_mtime.ts_sec) {
33856289Smckusick 				np->n_direofoffset = 0;
33956289Smckusick 				vinvalbuf(vp, TRUE, ap->a_cred, ap->a_p);
34056289Smckusick 				(void) vnode_pager_uncache(vp);
34156289Smckusick 				np->n_mtime = vattr.va_mtime.ts_sec;
34256289Smckusick 			}
34356289Smckusick 		}
34456289Smckusick 	    }
34556289Smckusick 	} else if ((nmp->nm_flag & NFSMNT_NQNFS) == 0)
34656289Smckusick 		np->n_attrstamp = 0; /* For Open/Close consistency */
34752196Smckusick 	return (0);
34838414Smckusick }
34938414Smckusick 
35038414Smckusick /*
35138414Smckusick  * nfs close vnode op
35238884Smacklem  * For reg files, invalidate any buffer cache entries.
35338414Smckusick  */
35439488Smckusick /* ARGSUSED */
35552234Sheideman int
35653806Smckusick nfs_close(ap)
35754451Smckusick 	struct vop_close_args /* {
35854451Smckusick 		struct vnodeop_desc *a_desc;
35954451Smckusick 		struct vnode *a_vp;
36054451Smckusick 		int  a_fflag;
36154451Smckusick 		struct ucred *a_cred;
36254451Smckusick 		struct proc *a_p;
36354451Smckusick 	} */ *ap;
36438414Smckusick {
36553806Smckusick 	register struct vnode *vp = ap->a_vp;
36653806Smckusick 	register struct nfsnode *np = VTONFS(vp);
36739341Smckusick 	int error = 0;
36838414Smckusick 
36953806Smckusick 	if (vp->v_type == VREG) {
37053806Smckusick 	    if ((VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) == 0 &&
37153629Smckusick 		(np->n_flag & NMODIFIED)) {
37254451Smckusick 		error = vinvalbuf(vp, TRUE, ap->a_cred, ap->a_p);
37341905Smckusick 		np->n_flag &= ~NMODIFIED;
37441905Smckusick 		np->n_attrstamp = 0;
37553629Smckusick 	    }
37653629Smckusick 	    if (np->n_flag & NWRITEERR) {
37753629Smckusick 		np->n_flag &= ~NWRITEERR;
37853629Smckusick 		error = np->n_error;
37953629Smckusick 	    }
38038884Smacklem 	}
38138414Smckusick 	return (error);
38238414Smckusick }
38338414Smckusick 
38438414Smckusick /*
38538414Smckusick  * nfs getattr call from vfs.
38638414Smckusick  */
38752234Sheideman int
38853805Smckusick nfs_getattr(ap)
38954668Smckusick 	struct vop_getattr_args /* {
39054668Smckusick 		struct vnode *a_vp;
39154668Smckusick 		struct vattr *a_vap;
39254668Smckusick 		struct ucred *a_cred;
39354668Smckusick 		struct proc *a_p;
39454668Smckusick 	} */ *ap;
39538414Smckusick {
39653805Smckusick 	register struct vnode *vp = ap->a_vp;
39753805Smckusick 	register struct nfsnode *np = VTONFS(vp);
39839488Smckusick 	register caddr_t cp;
39939488Smckusick 	caddr_t bpos, dpos;
40039488Smckusick 	int error = 0;
40139488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
40238414Smckusick 
40353805Smckusick 	/*
40453805Smckusick 	 * Update local times for special files.
40553805Smckusick 	 */
40656329Smckusick 	if (np->n_flag & (NACC | NUPD))
40753805Smckusick 		np->n_flag |= NCHG;
40853805Smckusick 	/*
40953805Smckusick 	 * First look in the cache.
41053805Smckusick 	 */
41153805Smckusick 	if (nfs_getattrcache(vp, ap->a_vap) == 0)
41238414Smckusick 		return (0);
41338414Smckusick 	nfsstats.rpccnt[NFSPROC_GETATTR]++;
41453805Smckusick 	nfsm_reqhead(vp, NFSPROC_GETATTR, NFSX_FH);
41553805Smckusick 	nfsm_fhtom(vp);
41653805Smckusick 	nfsm_request(vp, NFSPROC_GETATTR, ap->a_p, ap->a_cred);
41753805Smckusick 	nfsm_loadattr(vp, ap->a_vap);
41838414Smckusick 	nfsm_reqdone;
41938414Smckusick 	return (error);
42038414Smckusick }
42138414Smckusick 
42238414Smckusick /*
42338414Smckusick  * nfs setattr call.
42438414Smckusick  */
42552234Sheideman int
42653806Smckusick nfs_setattr(ap)
42754451Smckusick 	struct vop_setattr_args /* {
42854451Smckusick 		struct vnodeop_desc *a_desc;
42954451Smckusick 		struct vnode *a_vp;
43054451Smckusick 		struct vattr *a_vap;
43154451Smckusick 		struct ucred *a_cred;
43254451Smckusick 		struct proc *a_p;
43354451Smckusick 	} */ *ap;
43438414Smckusick {
43538884Smacklem 	register struct nfsv2_sattr *sp;
43639488Smckusick 	register caddr_t cp;
43739488Smckusick 	register long t1;
43852196Smckusick 	caddr_t bpos, dpos, cp2;
43952196Smckusick 	u_long *tl;
44056289Smckusick 	int error = 0, isnq;
44139488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
44253806Smckusick 	register struct vnode *vp = ap->a_vp;
44353806Smckusick 	register struct nfsnode *np = VTONFS(vp);
44453806Smckusick 	register struct vattr *vap = ap->a_vap;
44552196Smckusick 	u_quad_t frev;
44638414Smckusick 
44738414Smckusick 	nfsstats.rpccnt[NFSPROC_SETATTR]++;
44856289Smckusick 	isnq = (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS);
44956289Smckusick 	nfsm_reqhead(vp, NFSPROC_SETATTR, NFSX_FH+NFSX_SATTR(isnq));
45053806Smckusick 	nfsm_fhtom(vp);
45156289Smckusick 	nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR(isnq));
45256289Smckusick 	if (vap->va_mode == (u_short)-1)
45338884Smacklem 		sp->sa_mode = VNOVAL;
45438414Smckusick 	else
45553806Smckusick 		sp->sa_mode = vtonfs_mode(vp->v_type, vap->va_mode);
45656289Smckusick 	if (vap->va_uid == (uid_t)-1)
45738884Smacklem 		sp->sa_uid = VNOVAL;
45838414Smckusick 	else
45953806Smckusick 		sp->sa_uid = txdr_unsigned(vap->va_uid);
46056289Smckusick 	if (vap->va_gid == (gid_t)-1)
46138884Smacklem 		sp->sa_gid = VNOVAL;
46238414Smckusick 	else
46353806Smckusick 		sp->sa_gid = txdr_unsigned(vap->va_gid);
46456289Smckusick 	if (isnq) {
46556289Smckusick 		txdr_hyper(&vap->va_size, &sp->sa_nqsize);
46656289Smckusick 		txdr_nqtime(&vap->va_atime, &sp->sa_nqatime);
46756289Smckusick 		txdr_nqtime(&vap->va_mtime, &sp->sa_nqmtime);
46856289Smckusick 		sp->sa_nqflags = txdr_unsigned(vap->va_flags);
46956289Smckusick 		sp->sa_nqrdev = VNOVAL;
47056289Smckusick 	} else {
47156289Smckusick 		sp->sa_nfssize = txdr_unsigned(vap->va_size);
47256289Smckusick 		sp->sa_nfsatime.nfs_sec = txdr_unsigned(vap->va_atime.ts_sec);
47356289Smckusick 		sp->sa_nfsatime.nfs_usec = txdr_unsigned(vap->va_flags);
47456289Smckusick 		txdr_nfstime(&vap->va_mtime, &sp->sa_nfsmtime);
47556289Smckusick 	}
47654106Smckusick 	if (vap->va_size != VNOVAL || vap->va_mtime.ts_sec != VNOVAL ||
47754106Smckusick 	    vap->va_atime.ts_sec != VNOVAL) {
47839359Smckusick 		if (np->n_flag & NMODIFIED) {
47953806Smckusick 			if (vap->va_size == 0)
48054451Smckusick 				error =
48154451Smckusick 				    vinvalbuf(vp, FALSE, ap->a_cred, ap->a_p);
48246988Smckusick 			else
48354451Smckusick 				error =
48454451Smckusick 				    vinvalbuf(vp, TRUE, ap->a_cred, ap->a_p);
48554451Smckusick 			np->n_flag &= ~NMODIFIED;
48639359Smckusick 		}
48756289Smckusick 		if (vap->va_size != VNOVAL)
48856289Smckusick 			np->n_size = np->n_vattr.va_size = vap->va_size;
48939359Smckusick 	}
49053806Smckusick 	nfsm_request(vp, NFSPROC_SETATTR, ap->a_p, ap->a_cred);
49153806Smckusick 	nfsm_loadattr(vp, (struct vattr *)0);
49253806Smckusick 	if ((VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) &&
49353806Smckusick 	    NQNFS_CKCACHABLE(vp, NQL_WRITE)) {
49452196Smckusick 		nfsm_dissect(tl, u_long *, 2*NFSX_UNSIGNED);
49552196Smckusick 		fxdr_hyper(tl, &frev);
49654451Smckusick 		if (frev > np->n_brev)
49752196Smckusick 			np->n_brev = frev;
49852196Smckusick 	}
49938414Smckusick 	nfsm_reqdone;
50038414Smckusick 	return (error);
50138414Smckusick }
50238414Smckusick 
50338414Smckusick /*
50438414Smckusick  * nfs lookup call, one step at a time...
50538414Smckusick  * First look in cache
50638414Smckusick  * If not found, unlock the directory nfsnode and do the rpc
50738414Smckusick  */
50852234Sheideman int
50953806Smckusick nfs_lookup(ap)
51054451Smckusick 	struct vop_lookup_args /* {
51154451Smckusick 		struct vnodeop_desc *a_desc;
51254451Smckusick 		struct vnode *a_dvp;
51354451Smckusick 		struct vnode **a_vpp;
51454451Smckusick 		struct componentname *a_cnp;
51554451Smckusick 	} */ *ap;
51638414Smckusick {
51753806Smckusick 	register struct componentname *cnp = ap->a_cnp;
51853806Smckusick 	register struct vnode *dvp = ap->a_dvp;
51954668Smckusick 	register struct vnode **vpp = ap->a_vpp;
52055184Smckusick 	register int flags = cnp->cn_flags;
52138414Smckusick 	register struct vnode *vdp;
52248054Smckusick 	register u_long *tl;
52339488Smckusick 	register caddr_t cp;
52439488Smckusick 	register long t1, t2;
52552196Smckusick 	struct nfsmount *nmp;
52652196Smckusick 	struct nfsnode *tp;
52739488Smckusick 	caddr_t bpos, dpos, cp2;
52852196Smckusick 	time_t reqtime;
52939488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
53038414Smckusick 	struct vnode *newvp;
53138414Smckusick 	long len;
53238414Smckusick 	nfsv2fh_t *fhp;
53338414Smckusick 	struct nfsnode *np;
53452234Sheideman 	int lockparent, wantparent, error = 0;
53552196Smckusick 	int nqlflag, cachable;
53652196Smckusick 	u_quad_t frev;
53738414Smckusick 
53854668Smckusick 	*vpp = NULL;
53953806Smckusick 	if (dvp->v_type != VDIR)
54038414Smckusick 		return (ENOTDIR);
54155184Smckusick 	lockparent = flags & LOCKPARENT;
54255184Smckusick 	wantparent = flags & (LOCKPARENT|WANTPARENT);
54353806Smckusick 	nmp = VFSTONFS(dvp->v_mount);
54453806Smckusick 	np = VTONFS(dvp);
54554668Smckusick 	if ((error = cache_lookup(dvp, vpp, cnp)) && error != ENOENT) {
54638884Smacklem 		struct vattr vattr;
54738884Smacklem 		int vpid;
54838884Smacklem 
54954668Smckusick 		vdp = *vpp;
55038884Smacklem 		vpid = vdp->v_id;
55138414Smckusick 		/*
55238884Smacklem 		 * See the comment starting `Step through' in ufs/ufs_lookup.c
55338884Smacklem 		 * for an explanation of the locking protocol
55438414Smckusick 		 */
55553806Smckusick 		if (dvp == vdp) {
55638425Smckusick 			VREF(vdp);
55739441Smckusick 			error = 0;
55852196Smckusick 		} else
55939441Smckusick 			error = vget(vdp);
56039441Smckusick 		if (!error) {
56140251Smckusick 			if (vpid == vdp->v_id) {
56252196Smckusick 			   if (nmp->nm_flag & NFSMNT_NQNFS) {
56356289Smckusick 				if ((nmp->nm_flag & NFSMNT_NQLOOKLEASE) == 0) {
56456289Smckusick 					nfsstats.lookupcache_hits++;
56556289Smckusick 					if (cnp->cn_nameiop != LOOKUP &&
56656289Smckusick 					    (flags & ISLASTCN))
56756289Smckusick 					    cnp->cn_flags |= SAVENAME;
56856289Smckusick 					return (0);
56956289Smckusick 			        } else if (NQNFS_CKCACHABLE(dvp, NQL_READ)) {
57054451Smckusick 					if (np->n_lrev != np->n_brev ||
57152196Smckusick 					    (np->n_flag & NMODIFIED)) {
57252196Smckusick 						np->n_direofoffset = 0;
57353806Smckusick 						cache_purge(dvp);
57454451Smckusick 						error = vinvalbuf(dvp, FALSE,
57554451Smckusick 						    cnp->cn_cred, cnp->cn_proc);
57652196Smckusick 						np->n_flag &= ~NMODIFIED;
57752196Smckusick 						np->n_brev = np->n_lrev;
57852196Smckusick 					} else {
57952196Smckusick 						nfsstats.lookupcache_hits++;
58053806Smckusick 						if (cnp->cn_nameiop != LOOKUP &&
58155184Smckusick 						    (flags & ISLASTCN))
58253806Smckusick 						    cnp->cn_flags |= SAVENAME;
58352196Smckusick 						return (0);
58452196Smckusick 					}
58552196Smckusick 				}
58653806Smckusick 			   } else if (!VOP_GETATTR(vdp, &vattr, cnp->cn_cred, cnp->cn_proc) &&
58754106Smckusick 			       vattr.va_ctime.ts_sec == VTONFS(vdp)->n_ctime) {
58839441Smckusick 				nfsstats.lookupcache_hits++;
58953806Smckusick 				if (cnp->cn_nameiop != LOOKUP &&
59055184Smckusick 				    (flags & ISLASTCN))
59153806Smckusick 					cnp->cn_flags |= SAVENAME;
59239441Smckusick 				return (0);
59340251Smckusick 			   }
59447289Smckusick 			   cache_purge(vdp);
59539441Smckusick 			}
59652196Smckusick 			vrele(vdp);
59738884Smacklem 		}
59854668Smckusick 		*vpp = NULLVP;
59952196Smckusick 	}
60039341Smckusick 	error = 0;
60138414Smckusick 	nfsstats.lookupcache_misses++;
60238414Smckusick 	nfsstats.rpccnt[NFSPROC_LOOKUP]++;
60353806Smckusick 	len = cnp->cn_namelen;
60453806Smckusick 	nfsm_reqhead(dvp, NFSPROC_LOOKUP, NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len));
60552196Smckusick 
60652196Smckusick 	/*
60752196Smckusick 	 * For nqnfs optionally piggyback a getlease request for the name
60852196Smckusick 	 * being looked up.
60952196Smckusick 	 */
61052196Smckusick 	if (nmp->nm_flag & NFSMNT_NQNFS) {
61156289Smckusick 		nfsm_build(tl, u_long *, NFSX_UNSIGNED);
61252196Smckusick 		if ((nmp->nm_flag & NFSMNT_NQLOOKLEASE) &&
61355184Smckusick 		    ((cnp->cn_flags & MAKEENTRY) &&
61456289Smckusick 		    (cnp->cn_nameiop != DELETE || !(flags & ISLASTCN))))
61552196Smckusick 			*tl = txdr_unsigned(nmp->nm_leaseterm);
61656289Smckusick 		else
61752196Smckusick 			*tl = 0;
61852196Smckusick 	}
61953806Smckusick 	nfsm_fhtom(dvp);
62053806Smckusick 	nfsm_strtom(cnp->cn_nameptr, len, NFS_MAXNAMLEN);
62152196Smckusick 	reqtime = time.tv_sec;
62253806Smckusick 	nfsm_request(dvp, NFSPROC_LOOKUP, cnp->cn_proc, cnp->cn_cred);
62338414Smckusick nfsmout:
62438414Smckusick 	if (error) {
62553806Smckusick 		if ((cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME) &&
62655184Smckusick 		    (flags & ISLASTCN) && error == ENOENT)
62752823Smckusick 			error = EJUSTRETURN;
62855184Smckusick 		if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN))
62953806Smckusick 			cnp->cn_flags |= SAVENAME;
63040483Smckusick 		return (error);
63138414Smckusick 	}
63252196Smckusick 	if (nmp->nm_flag & NFSMNT_NQNFS) {
63352196Smckusick 		nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
63452196Smckusick 		if (*tl) {
63552196Smckusick 			nqlflag = fxdr_unsigned(int, *tl);
63652196Smckusick 			nfsm_dissect(tl, u_long *, 4*NFSX_UNSIGNED);
63752196Smckusick 			cachable = fxdr_unsigned(int, *tl++);
63852196Smckusick 			reqtime += fxdr_unsigned(int, *tl++);
63952196Smckusick 			fxdr_hyper(tl, &frev);
64052196Smckusick 		} else
64152196Smckusick 			nqlflag = 0;
64252196Smckusick 	}
64352196Smckusick 	nfsm_dissect(fhp, nfsv2fh_t *, NFSX_FH);
64438414Smckusick 
64538414Smckusick 	/*
64652196Smckusick 	 * Handle RENAME case...
64738414Smckusick 	 */
64855184Smckusick 	if (cnp->cn_nameiop == RENAME && wantparent && (flags & ISLASTCN)) {
64952196Smckusick 		if (!bcmp(np->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) {
65038414Smckusick 			m_freem(mrep);
65138414Smckusick 			return (EISDIR);
65238414Smckusick 		}
65353806Smckusick 		if (error = nfs_nget(dvp->v_mount, fhp, &np)) {
65438414Smckusick 			m_freem(mrep);
65538414Smckusick 			return (error);
65638414Smckusick 		}
65738414Smckusick 		newvp = NFSTOV(np);
65839459Smckusick 		if (error =
65939459Smckusick 		    nfs_loadattrcache(&newvp, &md, &dpos, (struct vattr *)0)) {
66052196Smckusick 			vrele(newvp);
66138414Smckusick 			m_freem(mrep);
66238414Smckusick 			return (error);
66338414Smckusick 		}
66454668Smckusick 		*vpp = newvp;
66545037Smckusick 		m_freem(mrep);
66653806Smckusick 		cnp->cn_flags |= SAVENAME;
66738414Smckusick 		return (0);
66838414Smckusick 	}
66938414Smckusick 
67052196Smckusick 	if (!bcmp(np->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) {
67153806Smckusick 		VREF(dvp);
67253806Smckusick 		newvp = dvp;
67338414Smckusick 	} else {
67453806Smckusick 		if (error = nfs_nget(dvp->v_mount, fhp, &np)) {
67538414Smckusick 			m_freem(mrep);
67638414Smckusick 			return (error);
67738414Smckusick 		}
67838414Smckusick 		newvp = NFSTOV(np);
67938414Smckusick 	}
68039459Smckusick 	if (error = nfs_loadattrcache(&newvp, &md, &dpos, (struct vattr *)0)) {
68152196Smckusick 		vrele(newvp);
68238414Smckusick 		m_freem(mrep);
68338414Smckusick 		return (error);
68438414Smckusick 	}
68538414Smckusick 	m_freem(mrep);
68654668Smckusick 	*vpp = newvp;
68755184Smckusick 	if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN))
68853806Smckusick 		cnp->cn_flags |= SAVENAME;
68955184Smckusick 	if ((cnp->cn_flags & MAKEENTRY) &&
69055184Smckusick 	    (cnp->cn_nameiop != DELETE || !(flags & ISLASTCN))) {
69152196Smckusick 		if ((nmp->nm_flag & NFSMNT_NQNFS) == 0)
69254106Smckusick 			np->n_ctime = np->n_vattr.va_ctime.ts_sec;
69356289Smckusick 		else if (nqlflag && reqtime > time.tv_sec)
69456289Smckusick 			nqnfs_clientlease(nmp, np, nqlflag, cachable, reqtime,
69556289Smckusick 				frev);
69654668Smckusick 		cache_enter(dvp, *vpp, cnp);
69740251Smckusick 	}
69852196Smckusick 	return (0);
69938414Smckusick }
70038414Smckusick 
70138414Smckusick /*
70241905Smckusick  * nfs read call.
70341905Smckusick  * Just call nfs_bioread() to do the work.
70441905Smckusick  */
70552234Sheideman int
70653806Smckusick nfs_read(ap)
70754668Smckusick 	struct vop_read_args /* {
70854668Smckusick 		struct vnode *a_vp;
70954668Smckusick 		struct uio *a_uio;
71054668Smckusick 		int  a_ioflag;
71154668Smckusick 		struct ucred *a_cred;
71254668Smckusick 	} */ *ap;
71341905Smckusick {
71453806Smckusick 	register struct vnode *vp = ap->a_vp;
71553806Smckusick 
71653806Smckusick 	if (vp->v_type != VREG)
71741905Smckusick 		return (EPERM);
71853806Smckusick 	return (nfs_bioread(vp, ap->a_uio, ap->a_ioflag, ap->a_cred));
71941905Smckusick }
72041905Smckusick 
72141905Smckusick /*
72238414Smckusick  * nfs readlink call
72338414Smckusick  */
72452234Sheideman int
72553806Smckusick nfs_readlink(ap)
72654668Smckusick 	struct vop_readlink_args /* {
72754668Smckusick 		struct vnode *a_vp;
72854668Smckusick 		struct uio *a_uio;
72954668Smckusick 		struct ucred *a_cred;
73054668Smckusick 	} */ *ap;
73141905Smckusick {
73253806Smckusick 	register struct vnode *vp = ap->a_vp;
73353806Smckusick 
73453806Smckusick 	if (vp->v_type != VLNK)
73541905Smckusick 		return (EPERM);
73653806Smckusick 	return (nfs_bioread(vp, ap->a_uio, 0, ap->a_cred));
73741905Smckusick }
73841905Smckusick 
73941905Smckusick /*
74041905Smckusick  * Do a readlink rpc.
74141905Smckusick  * Called by nfs_doio() from below the buffer cache.
74241905Smckusick  */
74352234Sheideman int
74448054Smckusick nfs_readlinkrpc(vp, uiop, cred)
74539488Smckusick 	register struct vnode *vp;
74638414Smckusick 	struct uio *uiop;
74738414Smckusick 	struct ucred *cred;
74838414Smckusick {
74948054Smckusick 	register u_long *tl;
75039488Smckusick 	register caddr_t cp;
75139488Smckusick 	register long t1;
75239488Smckusick 	caddr_t bpos, dpos, cp2;
75339488Smckusick 	int error = 0;
75439488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
75538414Smckusick 	long len;
75638414Smckusick 
75738414Smckusick 	nfsstats.rpccnt[NFSPROC_READLINK]++;
75852196Smckusick 	nfsm_reqhead(vp, NFSPROC_READLINK, NFSX_FH);
75938414Smckusick 	nfsm_fhtom(vp);
76052196Smckusick 	nfsm_request(vp, NFSPROC_READLINK, uiop->uio_procp, cred);
76138414Smckusick 	nfsm_strsiz(len, NFS_MAXPATHLEN);
76238414Smckusick 	nfsm_mtouio(uiop, len);
76338414Smckusick 	nfsm_reqdone;
76438414Smckusick 	return (error);
76538414Smckusick }
76638414Smckusick 
76738414Smckusick /*
76841905Smckusick  * nfs read rpc call
76941905Smckusick  * Ditto above
77038414Smckusick  */
77152234Sheideman int
77248054Smckusick nfs_readrpc(vp, uiop, cred)
77339488Smckusick 	register struct vnode *vp;
77438414Smckusick 	struct uio *uiop;
77538414Smckusick 	struct ucred *cred;
77638414Smckusick {
77748054Smckusick 	register u_long *tl;
77839488Smckusick 	register caddr_t cp;
77939488Smckusick 	register long t1;
78039488Smckusick 	caddr_t bpos, dpos, cp2;
78139488Smckusick 	int error = 0;
78239488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
78338414Smckusick 	struct nfsmount *nmp;
78438414Smckusick 	long len, retlen, tsiz;
78538414Smckusick 
78641398Smckusick 	nmp = VFSTONFS(vp->v_mount);
78738414Smckusick 	tsiz = uiop->uio_resid;
78856289Smckusick 	if (uiop->uio_offset + tsiz > 0xffffffff &&
78956289Smckusick 	    (nmp->nm_flag & NFSMNT_NQNFS) == 0)
79056289Smckusick 		return (EFBIG);
79138414Smckusick 	while (tsiz > 0) {
79238414Smckusick 		nfsstats.rpccnt[NFSPROC_READ]++;
79338414Smckusick 		len = (tsiz > nmp->nm_rsize) ? nmp->nm_rsize : tsiz;
79452196Smckusick 		nfsm_reqhead(vp, NFSPROC_READ, NFSX_FH+NFSX_UNSIGNED*3);
79538414Smckusick 		nfsm_fhtom(vp);
79648054Smckusick 		nfsm_build(tl, u_long *, NFSX_UNSIGNED*3);
79756289Smckusick 		if (nmp->nm_flag & NFSMNT_NQNFS) {
79856289Smckusick 			txdr_hyper(&uiop->uio_offset, tl);
79956289Smckusick 			*(tl + 2) = txdr_unsigned(len);
80056289Smckusick 		} else {
80156289Smckusick 			*tl++ = txdr_unsigned(uiop->uio_offset);
80256289Smckusick 			*tl++ = txdr_unsigned(len);
80356289Smckusick 			*tl = 0;
80456289Smckusick 		}
80552196Smckusick 		nfsm_request(vp, NFSPROC_READ, uiop->uio_procp, cred);
80638414Smckusick 		nfsm_loadattr(vp, (struct vattr *)0);
80738414Smckusick 		nfsm_strsiz(retlen, nmp->nm_rsize);
80838414Smckusick 		nfsm_mtouio(uiop, retlen);
80938414Smckusick 		m_freem(mrep);
81038414Smckusick 		if (retlen < len)
81138414Smckusick 			tsiz = 0;
81238414Smckusick 		else
81338414Smckusick 			tsiz -= len;
81438414Smckusick 	}
81538414Smckusick nfsmout:
81638414Smckusick 	return (error);
81738414Smckusick }
81838414Smckusick 
81938414Smckusick /*
82038414Smckusick  * nfs write call
82138414Smckusick  */
82252234Sheideman int
82356289Smckusick nfs_writerpc(vp, uiop, cred, ioflags)
82439488Smckusick 	register struct vnode *vp;
82538414Smckusick 	struct uio *uiop;
82638414Smckusick 	struct ucred *cred;
82756289Smckusick 	int ioflags;
82838414Smckusick {
82948054Smckusick 	register u_long *tl;
83039488Smckusick 	register caddr_t cp;
83139488Smckusick 	register long t1;
83252196Smckusick 	caddr_t bpos, dpos, cp2;
83339488Smckusick 	int error = 0;
83439488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
83538414Smckusick 	struct nfsmount *nmp;
83652196Smckusick 	struct nfsnode *np = VTONFS(vp);
83752196Smckusick 	u_quad_t frev;
83838414Smckusick 	long len, tsiz;
83938414Smckusick 
84041398Smckusick 	nmp = VFSTONFS(vp->v_mount);
84138414Smckusick 	tsiz = uiop->uio_resid;
84256289Smckusick 	if (uiop->uio_offset + tsiz > 0xffffffff &&
84356289Smckusick 	    (nmp->nm_flag & NFSMNT_NQNFS) == 0)
84456289Smckusick 		return (EFBIG);
84538414Smckusick 	while (tsiz > 0) {
84638414Smckusick 		nfsstats.rpccnt[NFSPROC_WRITE]++;
84738414Smckusick 		len = (tsiz > nmp->nm_wsize) ? nmp->nm_wsize : tsiz;
84852196Smckusick 		nfsm_reqhead(vp, NFSPROC_WRITE,
84952196Smckusick 			NFSX_FH+NFSX_UNSIGNED*4+nfsm_rndup(len));
85038414Smckusick 		nfsm_fhtom(vp);
85156289Smckusick 		nfsm_build(tl, u_long *, NFSX_UNSIGNED * 4);
85256289Smckusick 		if (nmp->nm_flag & NFSMNT_NQNFS) {
85356289Smckusick 			txdr_hyper(&uiop->uio_offset, tl);
85456289Smckusick 			tl += 2;
85556289Smckusick 			if (ioflags & IO_APPEND)
85656289Smckusick 				*tl++ = txdr_unsigned(1);
85756289Smckusick 			else
85856289Smckusick 				*tl++ = 0;
85956289Smckusick 		} else {
86056289Smckusick 			*++tl = txdr_unsigned(uiop->uio_offset);
86156289Smckusick 			tl += 2;
86256289Smckusick 		}
86356289Smckusick 		*tl = txdr_unsigned(len);
86438414Smckusick 		nfsm_uiotom(uiop, len);
86552196Smckusick 		nfsm_request(vp, NFSPROC_WRITE, uiop->uio_procp, cred);
86638414Smckusick 		nfsm_loadattr(vp, (struct vattr *)0);
86752196Smckusick 		if (nmp->nm_flag & NFSMNT_MYWRITE)
86854106Smckusick 			VTONFS(vp)->n_mtime = VTONFS(vp)->n_vattr.va_mtime.ts_sec;
86952196Smckusick 		else if ((nmp->nm_flag & NFSMNT_NQNFS) &&
87052196Smckusick 			 NQNFS_CKCACHABLE(vp, NQL_WRITE)) {
87152196Smckusick 			nfsm_dissect(tl, u_long *, 2*NFSX_UNSIGNED);
87252196Smckusick 			fxdr_hyper(tl, &frev);
87354451Smckusick 			if (frev > np->n_brev)
87452196Smckusick 				np->n_brev = frev;
87552196Smckusick 		}
87638414Smckusick 		m_freem(mrep);
87738414Smckusick 		tsiz -= len;
87838414Smckusick 	}
87938414Smckusick nfsmout:
88052196Smckusick 	if (error)
88152196Smckusick 		uiop->uio_resid = tsiz;
88238414Smckusick 	return (error);
88338414Smckusick }
88438414Smckusick 
88538414Smckusick /*
88639459Smckusick  * nfs mknod call
88742246Smckusick  * This is a kludge. Use a create rpc but with the IFMT bits of the mode
88842246Smckusick  * set to specify the file type and the size field for rdev.
88939459Smckusick  */
89039459Smckusick /* ARGSUSED */
89152234Sheideman int
89253806Smckusick nfs_mknod(ap)
89354668Smckusick 	struct vop_mknod_args /* {
89454668Smckusick 		struct vnode *a_dvp;
89554668Smckusick 		struct vnode **a_vpp;
89654668Smckusick 		struct componentname *a_cnp;
89754668Smckusick 		struct vattr *a_vap;
89854668Smckusick 	} */ *ap;
89939459Smckusick {
90053806Smckusick 	register struct vnode *dvp = ap->a_dvp;
90153806Smckusick 	register struct vattr *vap = ap->a_vap;
90253806Smckusick 	register struct componentname *cnp = ap->a_cnp;
90342246Smckusick 	register struct nfsv2_sattr *sp;
90448054Smckusick 	register u_long *tl;
90542246Smckusick 	register caddr_t cp;
90656289Smckusick 	register long t1, t2;
90756289Smckusick 	struct vnode *newvp;
90856289Smckusick 	char *cp2;
90942246Smckusick 	caddr_t bpos, dpos;
91056289Smckusick 	int error = 0, isnq;
91142246Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
91242246Smckusick 	u_long rdev;
91339459Smckusick 
91456289Smckusick 	isnq = (VFSTONFS(dvp->v_mount)->nm_flag & NFSMNT_NQNFS);
91553806Smckusick 	if (vap->va_type == VCHR || vap->va_type == VBLK)
91653806Smckusick 		rdev = txdr_unsigned(vap->va_rdev);
91742246Smckusick #ifdef FIFO
91853806Smckusick 	else if (vap->va_type == VFIFO)
91942246Smckusick 		rdev = 0xffffffff;
92042246Smckusick #endif /* FIFO */
92142246Smckusick 	else {
92253806Smckusick 		VOP_ABORTOP(dvp, cnp);
92353806Smckusick 		vput(dvp);
92442246Smckusick 		return (EOPNOTSUPP);
92542246Smckusick 	}
92642246Smckusick 	nfsstats.rpccnt[NFSPROC_CREATE]++;
92753806Smckusick 	nfsm_reqhead(dvp, NFSPROC_CREATE,
92856289Smckusick 	  NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen)+NFSX_SATTR(isnq));
92953806Smckusick 	nfsm_fhtom(dvp);
93053806Smckusick 	nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
93156289Smckusick 	nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR(isnq));
93253806Smckusick 	sp->sa_mode = vtonfs_mode(vap->va_type, vap->va_mode);
93353806Smckusick 	sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid);
93453806Smckusick 	sp->sa_gid = txdr_unsigned(cnp->cn_cred->cr_gid);
93556289Smckusick 	if (isnq) {
93656289Smckusick 		sp->sa_nqrdev = rdev;
93756289Smckusick 		sp->sa_nqflags = 0;
93856289Smckusick 		txdr_nqtime(&vap->va_atime, &sp->sa_nqatime);
93956289Smckusick 		txdr_nqtime(&vap->va_mtime, &sp->sa_nqmtime);
94056289Smckusick 	} else {
94156289Smckusick 		sp->sa_nfssize = rdev;
94256289Smckusick 		txdr_nfstime(&vap->va_atime, &sp->sa_nfsatime);
94356289Smckusick 		txdr_nfstime(&vap->va_mtime, &sp->sa_nfsmtime);
94456289Smckusick 	}
94553806Smckusick 	nfsm_request(dvp, NFSPROC_CREATE, cnp->cn_proc, cnp->cn_cred);
94656289Smckusick 	nfsm_mtofh(dvp, newvp);
94742246Smckusick 	nfsm_reqdone;
94856289Smckusick 	if (!error)
94956289Smckusick 		cache_enter(dvp, newvp, cnp);
95053806Smckusick 	FREE(cnp->cn_pnbuf, M_NAMEI);
95153806Smckusick 	VTONFS(dvp)->n_flag |= NMODIFIED;
95253806Smckusick 	vrele(dvp);
95342246Smckusick 	return (error);
95439459Smckusick }
95539459Smckusick 
95639459Smckusick /*
95738414Smckusick  * nfs file create call
95838414Smckusick  */
95952234Sheideman int
96053806Smckusick nfs_create(ap)
96154668Smckusick 	struct vop_create_args /* {
96254668Smckusick 		struct vnode *a_dvp;
96354668Smckusick 		struct vnode **a_vpp;
96454668Smckusick 		struct componentname *a_cnp;
96554668Smckusick 		struct vattr *a_vap;
96654668Smckusick 	} */ *ap;
96738414Smckusick {
96853806Smckusick 	register struct vnode *dvp = ap->a_dvp;
96953806Smckusick 	register struct vattr *vap = ap->a_vap;
97053806Smckusick 	register struct componentname *cnp = ap->a_cnp;
97138884Smacklem 	register struct nfsv2_sattr *sp;
97248054Smckusick 	register u_long *tl;
97339488Smckusick 	register caddr_t cp;
97439488Smckusick 	register long t1, t2;
97539488Smckusick 	caddr_t bpos, dpos, cp2;
97656289Smckusick 	int error = 0, isnq;
97739488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
97838414Smckusick 
97938414Smckusick 	nfsstats.rpccnt[NFSPROC_CREATE]++;
98056289Smckusick 	isnq = (VFSTONFS(dvp->v_mount)->nm_flag & NFSMNT_NQNFS);
98153806Smckusick 	nfsm_reqhead(dvp, NFSPROC_CREATE,
98256289Smckusick 	  NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen)+NFSX_SATTR(isnq));
98353806Smckusick 	nfsm_fhtom(dvp);
98453806Smckusick 	nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
98556289Smckusick 	nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR(isnq));
98653806Smckusick 	sp->sa_mode = vtonfs_mode(vap->va_type, vap->va_mode);
98753806Smckusick 	sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid);
98853806Smckusick 	sp->sa_gid = txdr_unsigned(cnp->cn_cred->cr_gid);
98956289Smckusick 	if (isnq) {
99056289Smckusick 		u_quad_t qval = 0;
99156289Smckusick 
99256289Smckusick 		txdr_hyper(&qval, &sp->sa_nqsize);
99356289Smckusick 		sp->sa_nqflags = 0;
99456289Smckusick 		sp->sa_nqrdev = -1;
99556289Smckusick 		txdr_nqtime(&vap->va_atime, &sp->sa_nqatime);
99656289Smckusick 		txdr_nqtime(&vap->va_mtime, &sp->sa_nqmtime);
99756289Smckusick 	} else {
99856289Smckusick 		sp->sa_nfssize = 0;
99956289Smckusick 		txdr_nfstime(&vap->va_atime, &sp->sa_nfsatime);
100056289Smckusick 		txdr_nfstime(&vap->va_mtime, &sp->sa_nfsmtime);
100156289Smckusick 	}
100253806Smckusick 	nfsm_request(dvp, NFSPROC_CREATE, cnp->cn_proc, cnp->cn_cred);
100353806Smckusick 	nfsm_mtofh(dvp, *ap->a_vpp);
100438414Smckusick 	nfsm_reqdone;
100556289Smckusick 	if (!error)
100656289Smckusick 		cache_enter(dvp, *ap->a_vpp, cnp);
100753806Smckusick 	FREE(cnp->cn_pnbuf, M_NAMEI);
100853806Smckusick 	VTONFS(dvp)->n_flag |= NMODIFIED;
100953806Smckusick 	vrele(dvp);
101038414Smckusick 	return (error);
101138414Smckusick }
101238414Smckusick 
101338414Smckusick /*
101438414Smckusick  * nfs file remove call
101541905Smckusick  * To try and make nfs semantics closer to ufs semantics, a file that has
101641905Smckusick  * other processes using the vnode is renamed instead of removed and then
101739341Smckusick  * removed later on the last close.
101841905Smckusick  * - If v_usecount > 1
101939341Smckusick  *	  If a rename is not already in the works
102039341Smckusick  *	     call nfs_sillyrename() to set it up
102139341Smckusick  *     else
102239341Smckusick  *	  do the remove rpc
102338414Smckusick  */
102452234Sheideman int
102553806Smckusick nfs_remove(ap)
102654451Smckusick 	struct vop_remove_args /* {
102754451Smckusick 		struct vnodeop_desc *a_desc;
102854451Smckusick 		struct vnode * a_dvp;
102954451Smckusick 		struct vnode * a_vp;
103054451Smckusick 		struct componentname * a_cnp;
103154451Smckusick 	} */ *ap;
103238414Smckusick {
103353806Smckusick 	register struct vnode *vp = ap->a_vp;
103453806Smckusick 	register struct vnode *dvp = ap->a_dvp;
103553806Smckusick 	register struct componentname *cnp = ap->a_cnp;
103653806Smckusick 	register struct nfsnode *np = VTONFS(vp);
103748054Smckusick 	register u_long *tl;
103839488Smckusick 	register caddr_t cp;
103952196Smckusick 	register long t2;
104039488Smckusick 	caddr_t bpos, dpos;
104139488Smckusick 	int error = 0;
104239488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
104338414Smckusick 
104453806Smckusick 	if (vp->v_usecount > 1) {
104539341Smckusick 		if (!np->n_sillyrename)
104653806Smckusick 			error = nfs_sillyrename(dvp, vp, cnp);
104739341Smckusick 	} else {
104852196Smckusick 		/*
104952196Smckusick 		 * Purge the name cache so that the chance of a lookup for
105052196Smckusick 		 * the name succeeding while the remove is in progress is
105152196Smckusick 		 * minimized. Without node locking it can still happen, such
105252196Smckusick 		 * that an I/O op returns ESTALE, but since you get this if
105352196Smckusick 		 * another host removes the file..
105452196Smckusick 		 */
105553806Smckusick 		cache_purge(vp);
105652196Smckusick 		/*
105752196Smckusick 		 * Throw away biocache buffers. Mainly to avoid
105852196Smckusick 		 * unnecessary delayed writes.
105952196Smckusick 		 */
106054451Smckusick 		error = vinvalbuf(vp, FALSE, cnp->cn_cred, cnp->cn_proc);
106152196Smckusick 		/* Do the rpc */
106238414Smckusick 		nfsstats.rpccnt[NFSPROC_REMOVE]++;
106353806Smckusick 		nfsm_reqhead(dvp, NFSPROC_REMOVE,
106453806Smckusick 			NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen));
106553806Smckusick 		nfsm_fhtom(dvp);
106653806Smckusick 		nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
106753806Smckusick 		nfsm_request(dvp, NFSPROC_REMOVE, cnp->cn_proc, cnp->cn_cred);
106838414Smckusick 		nfsm_reqdone;
106953806Smckusick 		FREE(cnp->cn_pnbuf, M_NAMEI);
107053806Smckusick 		VTONFS(dvp)->n_flag |= NMODIFIED;
107139751Smckusick 		/*
107239751Smckusick 		 * Kludge City: If the first reply to the remove rpc is lost..
107339751Smckusick 		 *   the reply to the retransmitted request will be ENOENT
107439751Smckusick 		 *   since the file was in fact removed
107539751Smckusick 		 *   Therefore, we cheat and return success.
107639751Smckusick 		 */
107739751Smckusick 		if (error == ENOENT)
107839751Smckusick 			error = 0;
107938414Smckusick 	}
108040042Smckusick 	np->n_attrstamp = 0;
108153806Smckusick 	vrele(dvp);
108253806Smckusick 	vrele(vp);
108338414Smckusick 	return (error);
108438414Smckusick }
108538414Smckusick 
108638414Smckusick /*
108738414Smckusick  * nfs file remove rpc called from nfs_inactive
108838414Smckusick  */
108952234Sheideman int
109054451Smckusick nfs_removeit(sp)
109148364Smckusick 	register struct sillyrename *sp;
109238414Smckusick {
109348054Smckusick 	register u_long *tl;
109439488Smckusick 	register caddr_t cp;
109552196Smckusick 	register long t2;
109639488Smckusick 	caddr_t bpos, dpos;
109739488Smckusick 	int error = 0;
109839488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
109938414Smckusick 
110038414Smckusick 	nfsstats.rpccnt[NFSPROC_REMOVE]++;
110152196Smckusick 	nfsm_reqhead(sp->s_dvp, NFSPROC_REMOVE,
110248364Smckusick 		NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(sp->s_namlen));
110348364Smckusick 	nfsm_fhtom(sp->s_dvp);
110448364Smckusick 	nfsm_strtom(sp->s_name, sp->s_namlen, NFS_MAXNAMLEN);
110554451Smckusick 	nfsm_request(sp->s_dvp, NFSPROC_REMOVE, NULL, sp->s_cred);
110638414Smckusick 	nfsm_reqdone;
110748364Smckusick 	VTONFS(sp->s_dvp)->n_flag |= NMODIFIED;
110838414Smckusick 	return (error);
110938414Smckusick }
111038414Smckusick 
111138414Smckusick /*
111238414Smckusick  * nfs file rename call
111338414Smckusick  */
111452234Sheideman int
111553806Smckusick nfs_rename(ap)
111654668Smckusick 	struct vop_rename_args  /* {
111754668Smckusick 		struct vnode *a_fdvp;
111854668Smckusick 		struct vnode *a_fvp;
111954668Smckusick 		struct componentname *a_fcnp;
112054668Smckusick 		struct vnode *a_tdvp;
112154668Smckusick 		struct vnode *a_tvp;
112254668Smckusick 		struct componentname *a_tcnp;
112354668Smckusick 	} */ *ap;
112438414Smckusick {
112553806Smckusick 	register struct vnode *fvp = ap->a_fvp;
112653806Smckusick 	register struct vnode *tvp = ap->a_tvp;
112753806Smckusick 	register struct vnode *fdvp = ap->a_fdvp;
112853806Smckusick 	register struct vnode *tdvp = ap->a_tdvp;
112953806Smckusick 	register struct componentname *tcnp = ap->a_tcnp;
113053806Smckusick 	register struct componentname *fcnp = ap->a_fcnp;
113148054Smckusick 	register u_long *tl;
113239488Smckusick 	register caddr_t cp;
113352196Smckusick 	register long t2;
113439488Smckusick 	caddr_t bpos, dpos;
113539488Smckusick 	int error = 0;
113639488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
113738414Smckusick 
113853804Spendry 	/* Check for cross-device rename */
113953806Smckusick 	if ((fvp->v_mount != tdvp->v_mount) ||
114053806Smckusick 	    (tvp && (fvp->v_mount != tvp->v_mount))) {
114153804Spendry 		error = EXDEV;
114253804Spendry 		goto out;
114353804Spendry 	}
114453804Spendry 
114553804Spendry 
114638414Smckusick 	nfsstats.rpccnt[NFSPROC_RENAME]++;
114753806Smckusick 	nfsm_reqhead(fdvp, NFSPROC_RENAME,
114853806Smckusick 		(NFSX_FH+NFSX_UNSIGNED)*2+nfsm_rndup(fcnp->cn_namelen)+
114953806Smckusick 		nfsm_rndup(fcnp->cn_namelen)); /* or fcnp->cn_cred?*/
115053806Smckusick 	nfsm_fhtom(fdvp);
115153806Smckusick 	nfsm_strtom(fcnp->cn_nameptr, fcnp->cn_namelen, NFS_MAXNAMLEN);
115253806Smckusick 	nfsm_fhtom(tdvp);
115353806Smckusick 	nfsm_strtom(tcnp->cn_nameptr, tcnp->cn_namelen, NFS_MAXNAMLEN);
115453806Smckusick 	nfsm_request(fdvp, NFSPROC_RENAME, tcnp->cn_proc, tcnp->cn_cred);
115538414Smckusick 	nfsm_reqdone;
115653806Smckusick 	VTONFS(fdvp)->n_flag |= NMODIFIED;
115753806Smckusick 	VTONFS(tdvp)->n_flag |= NMODIFIED;
115853806Smckusick 	if (fvp->v_type == VDIR) {
115953806Smckusick 		if (tvp != NULL && tvp->v_type == VDIR)
116053806Smckusick 			cache_purge(tdvp);
116153806Smckusick 		cache_purge(fdvp);
116238414Smckusick 	}
116353804Spendry out:
116453806Smckusick 	if (tdvp == tvp)
116553806Smckusick 		vrele(tdvp);
116643360Smckusick 	else
116753806Smckusick 		vput(tdvp);
116853806Smckusick 	if (tvp)
116953806Smckusick 		vput(tvp);
117053806Smckusick 	vrele(fdvp);
117153806Smckusick 	vrele(fvp);
117240112Smckusick 	/*
117340112Smckusick 	 * Kludge: Map ENOENT => 0 assuming that it is a reply to a retry.
117440112Smckusick 	 */
117540112Smckusick 	if (error == ENOENT)
117640112Smckusick 		error = 0;
117738414Smckusick 	return (error);
117838414Smckusick }
117938414Smckusick 
118038414Smckusick /*
118141905Smckusick  * nfs file rename rpc called from nfs_remove() above
118238414Smckusick  */
118352234Sheideman int
118452234Sheideman nfs_renameit(sdvp, scnp, sp)
118552234Sheideman 	struct vnode *sdvp;
118652234Sheideman 	struct componentname *scnp;
118748364Smckusick 	register struct sillyrename *sp;
118838414Smckusick {
118948054Smckusick 	register u_long *tl;
119039488Smckusick 	register caddr_t cp;
119152196Smckusick 	register long t2;
119239488Smckusick 	caddr_t bpos, dpos;
119339488Smckusick 	int error = 0;
119439488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
119538414Smckusick 
119638414Smckusick 	nfsstats.rpccnt[NFSPROC_RENAME]++;
119752234Sheideman 	nfsm_reqhead(sdvp, NFSPROC_RENAME,
119852234Sheideman 		(NFSX_FH+NFSX_UNSIGNED)*2+nfsm_rndup(scnp->cn_namelen)+
119952196Smckusick 		nfsm_rndup(sp->s_namlen));
120052234Sheideman 	nfsm_fhtom(sdvp);
120152234Sheideman 	nfsm_strtom(scnp->cn_nameptr, scnp->cn_namelen, NFS_MAXNAMLEN);
120252234Sheideman 	nfsm_fhtom(sdvp);
120348364Smckusick 	nfsm_strtom(sp->s_name, sp->s_namlen, NFS_MAXNAMLEN);
120452234Sheideman 	nfsm_request(sdvp, NFSPROC_RENAME, scnp->cn_proc, scnp->cn_cred);
120538414Smckusick 	nfsm_reqdone;
120652234Sheideman 	FREE(scnp->cn_pnbuf, M_NAMEI);
120752234Sheideman 	VTONFS(sdvp)->n_flag |= NMODIFIED;
120838414Smckusick 	return (error);
120938414Smckusick }
121038414Smckusick 
121138414Smckusick /*
121238414Smckusick  * nfs hard link create call
121338414Smckusick  */
121452234Sheideman int
121553806Smckusick nfs_link(ap)
121654668Smckusick 	struct vop_link_args /* {
121754668Smckusick 		struct vnode *a_vp;
121854668Smckusick 		struct vnode *a_tdvp;
121954668Smckusick 		struct componentname *a_cnp;
122054668Smckusick 	} */ *ap;
122138414Smckusick {
122253806Smckusick 	register struct vnode *vp = ap->a_vp;
122353806Smckusick 	register struct vnode *tdvp = ap->a_tdvp;
122453806Smckusick 	register struct componentname *cnp = ap->a_cnp;
122548054Smckusick 	register u_long *tl;
122639488Smckusick 	register caddr_t cp;
122752196Smckusick 	register long t2;
122839488Smckusick 	caddr_t bpos, dpos;
122939488Smckusick 	int error = 0;
123039488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
123138414Smckusick 
123253806Smckusick 	if (vp->v_mount != tdvp->v_mount) {
123353806Smckusick 		/*VOP_ABORTOP(vp, cnp);*/
123453806Smckusick 		if (tdvp == vp)
123553806Smckusick 			vrele(vp);
123653804Spendry 		else
123753806Smckusick 			vput(vp);
123853804Spendry 		return (EXDEV);
123953804Spendry 	}
124053804Spendry 
124138414Smckusick 	nfsstats.rpccnt[NFSPROC_LINK]++;
124253806Smckusick 	nfsm_reqhead(tdvp, NFSPROC_LINK,
124353806Smckusick 		NFSX_FH*2+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen));
124453806Smckusick 	nfsm_fhtom(tdvp);
124553806Smckusick 	nfsm_fhtom(vp);
124653806Smckusick 	nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
124753806Smckusick 	nfsm_request(tdvp, NFSPROC_LINK, cnp->cn_proc, cnp->cn_cred);
124838414Smckusick 	nfsm_reqdone;
124953806Smckusick 	FREE(cnp->cn_pnbuf, M_NAMEI);
125053806Smckusick 	VTONFS(tdvp)->n_attrstamp = 0;
125153806Smckusick 	VTONFS(vp)->n_flag |= NMODIFIED;
125253806Smckusick 	vrele(vp);
125340112Smckusick 	/*
125440112Smckusick 	 * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry.
125540112Smckusick 	 */
125640112Smckusick 	if (error == EEXIST)
125740112Smckusick 		error = 0;
125838414Smckusick 	return (error);
125938414Smckusick }
126038414Smckusick 
126138414Smckusick /*
126238414Smckusick  * nfs symbolic link create call
126338414Smckusick  */
126452234Sheideman /* start here */
126552234Sheideman int
126653806Smckusick nfs_symlink(ap)
126754668Smckusick 	struct vop_symlink_args /* {
126854668Smckusick 		struct vnode *a_dvp;
126954668Smckusick 		struct vnode **a_vpp;
127054668Smckusick 		struct componentname *a_cnp;
127154668Smckusick 		struct vattr *a_vap;
127254668Smckusick 		char *a_target;
127354668Smckusick 	} */ *ap;
127438414Smckusick {
127553806Smckusick 	register struct vnode *dvp = ap->a_dvp;
127653806Smckusick 	register struct vattr *vap = ap->a_vap;
127753806Smckusick 	register struct componentname *cnp = ap->a_cnp;
127838884Smacklem 	register struct nfsv2_sattr *sp;
127948054Smckusick 	register u_long *tl;
128039488Smckusick 	register caddr_t cp;
128152196Smckusick 	register long t2;
128239488Smckusick 	caddr_t bpos, dpos;
128356289Smckusick 	int slen, error = 0, isnq;
128439488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
128538414Smckusick 
128638414Smckusick 	nfsstats.rpccnt[NFSPROC_SYMLINK]++;
128753600Sheideman 	slen = strlen(ap->a_target);
128856289Smckusick 	isnq = (VFSTONFS(dvp->v_mount)->nm_flag & NFSMNT_NQNFS);
128953806Smckusick 	nfsm_reqhead(dvp, NFSPROC_SYMLINK, NFSX_FH+2*NFSX_UNSIGNED+
129056289Smckusick 	    nfsm_rndup(cnp->cn_namelen)+nfsm_rndup(slen)+NFSX_SATTR(isnq));
129153806Smckusick 	nfsm_fhtom(dvp);
129253806Smckusick 	nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
129353600Sheideman 	nfsm_strtom(ap->a_target, slen, NFS_MAXPATHLEN);
129456289Smckusick 	nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR(isnq));
129553806Smckusick 	sp->sa_mode = vtonfs_mode(VLNK, vap->va_mode);
129653806Smckusick 	sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid);
129753806Smckusick 	sp->sa_gid = txdr_unsigned(cnp->cn_cred->cr_gid);
129856289Smckusick 	if (isnq) {
129956289Smckusick 		quad_t qval = -1;
130056289Smckusick 
130156289Smckusick 		txdr_hyper(&qval, &sp->sa_nqsize);
130256289Smckusick 		sp->sa_nqflags = 0;
130356289Smckusick 		txdr_nqtime(&vap->va_atime, &sp->sa_nqatime);
130456289Smckusick 		txdr_nqtime(&vap->va_mtime, &sp->sa_nqmtime);
130556289Smckusick 	} else {
130656289Smckusick 		sp->sa_nfssize = -1;
130756289Smckusick 		txdr_nfstime(&vap->va_atime, &sp->sa_nfsatime);
130856289Smckusick 		txdr_nfstime(&vap->va_mtime, &sp->sa_nfsmtime);
130956289Smckusick 	}
131053806Smckusick 	nfsm_request(dvp, NFSPROC_SYMLINK, cnp->cn_proc, cnp->cn_cred);
131138414Smckusick 	nfsm_reqdone;
131253806Smckusick 	FREE(cnp->cn_pnbuf, M_NAMEI);
131353806Smckusick 	VTONFS(dvp)->n_flag |= NMODIFIED;
131453806Smckusick 	vrele(dvp);
131540112Smckusick 	/*
131640112Smckusick 	 * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry.
131740112Smckusick 	 */
131840112Smckusick 	if (error == EEXIST)
131940112Smckusick 		error = 0;
132038414Smckusick 	return (error);
132138414Smckusick }
132238414Smckusick 
132338414Smckusick /*
132438414Smckusick  * nfs make dir call
132538414Smckusick  */
132652234Sheideman int
132753806Smckusick nfs_mkdir(ap)
132854668Smckusick 	struct vop_mkdir_args /* {
132954668Smckusick 		struct vnode *a_dvp;
133054668Smckusick 		struct vnode **a_vpp;
133154668Smckusick 		struct componentname *a_cnp;
133254668Smckusick 		struct vattr *a_vap;
133354668Smckusick 	} */ *ap;
133438414Smckusick {
133553806Smckusick 	register struct vnode *dvp = ap->a_dvp;
133653806Smckusick 	register struct vattr *vap = ap->a_vap;
133753806Smckusick 	register struct componentname *cnp = ap->a_cnp;
133854668Smckusick 	register struct vnode **vpp = ap->a_vpp;
133938884Smacklem 	register struct nfsv2_sattr *sp;
134048054Smckusick 	register u_long *tl;
134139488Smckusick 	register caddr_t cp;
134239488Smckusick 	register long t1, t2;
134341905Smckusick 	register int len;
134439488Smckusick 	caddr_t bpos, dpos, cp2;
134556289Smckusick 	int error = 0, firsttry = 1, isnq;
134639488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
134738414Smckusick 
134853806Smckusick 	len = cnp->cn_namelen;
134956289Smckusick 	isnq = (VFSTONFS(dvp->v_mount)->nm_flag & NFSMNT_NQNFS);
135038414Smckusick 	nfsstats.rpccnt[NFSPROC_MKDIR]++;
135153806Smckusick 	nfsm_reqhead(dvp, NFSPROC_MKDIR,
135256289Smckusick 	  NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len)+NFSX_SATTR(isnq));
135353806Smckusick 	nfsm_fhtom(dvp);
135453806Smckusick 	nfsm_strtom(cnp->cn_nameptr, len, NFS_MAXNAMLEN);
135556289Smckusick 	nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR(isnq));
135653806Smckusick 	sp->sa_mode = vtonfs_mode(VDIR, vap->va_mode);
135753806Smckusick 	sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid);
135853806Smckusick 	sp->sa_gid = txdr_unsigned(cnp->cn_cred->cr_gid);
135956289Smckusick 	if (isnq) {
136056289Smckusick 		quad_t qval = -1;
136156289Smckusick 
136256289Smckusick 		txdr_hyper(&qval, &sp->sa_nqsize);
136356289Smckusick 		sp->sa_nqflags = 0;
136456289Smckusick 		txdr_nqtime(&vap->va_atime, &sp->sa_nqatime);
136556289Smckusick 		txdr_nqtime(&vap->va_mtime, &sp->sa_nqmtime);
136656289Smckusick 	} else {
136756289Smckusick 		sp->sa_nfssize = -1;
136856289Smckusick 		txdr_nfstime(&vap->va_atime, &sp->sa_nfsatime);
136956289Smckusick 		txdr_nfstime(&vap->va_mtime, &sp->sa_nfsmtime);
137056289Smckusick 	}
137153806Smckusick 	nfsm_request(dvp, NFSPROC_MKDIR, cnp->cn_proc, cnp->cn_cred);
137254668Smckusick 	nfsm_mtofh(dvp, *vpp);
137338414Smckusick 	nfsm_reqdone;
137453806Smckusick 	VTONFS(dvp)->n_flag |= NMODIFIED;
137540112Smckusick 	/*
137641905Smckusick 	 * Kludge: Map EEXIST => 0 assuming that you have a reply to a retry
137741905Smckusick 	 * if we can succeed in looking up the directory.
137841905Smckusick 	 * "firsttry" is necessary since the macros may "goto nfsmout" which
137941905Smckusick 	 * is above the if on errors. (Ugh)
138040112Smckusick 	 */
138141905Smckusick 	if (error == EEXIST && firsttry) {
138241905Smckusick 		firsttry = 0;
138340112Smckusick 		error = 0;
138441905Smckusick 		nfsstats.rpccnt[NFSPROC_LOOKUP]++;
138554668Smckusick 		*vpp = NULL;
138653806Smckusick 		nfsm_reqhead(dvp, NFSPROC_LOOKUP,
138741905Smckusick 		    NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len));
138853806Smckusick 		nfsm_fhtom(dvp);
138953806Smckusick 		nfsm_strtom(cnp->cn_nameptr, len, NFS_MAXNAMLEN);
139053806Smckusick 		nfsm_request(dvp, NFSPROC_LOOKUP, cnp->cn_proc, cnp->cn_cred);
139154668Smckusick 		nfsm_mtofh(dvp, *vpp);
139254668Smckusick 		if ((*vpp)->v_type != VDIR) {
139354668Smckusick 			vput(*vpp);
139441905Smckusick 			error = EEXIST;
139541905Smckusick 		}
139641905Smckusick 		m_freem(mrep);
139741905Smckusick 	}
139853806Smckusick 	FREE(cnp->cn_pnbuf, M_NAMEI);
139953806Smckusick 	vrele(dvp);
140038414Smckusick 	return (error);
140138414Smckusick }
140238414Smckusick 
140338414Smckusick /*
140438414Smckusick  * nfs remove directory call
140538414Smckusick  */
140652234Sheideman int
140753806Smckusick nfs_rmdir(ap)
140854668Smckusick 	struct vop_rmdir_args /* {
140954668Smckusick 		struct vnode *a_dvp;
141054668Smckusick 		struct vnode *a_vp;
141154668Smckusick 		struct componentname *a_cnp;
141254668Smckusick 	} */ *ap;
141338414Smckusick {
141453806Smckusick 	register struct vnode *vp = ap->a_vp;
141553806Smckusick 	register struct vnode *dvp = ap->a_dvp;
141653806Smckusick 	register struct componentname *cnp = ap->a_cnp;
141748054Smckusick 	register u_long *tl;
141839488Smckusick 	register caddr_t cp;
141952196Smckusick 	register long t2;
142039488Smckusick 	caddr_t bpos, dpos;
142139488Smckusick 	int error = 0;
142239488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
142338414Smckusick 
142453806Smckusick 	if (dvp == vp) {
142553806Smckusick 		vrele(dvp);
142653806Smckusick 		vrele(dvp);
142753806Smckusick 		FREE(cnp->cn_pnbuf, M_NAMEI);
142838414Smckusick 		return (EINVAL);
142938414Smckusick 	}
143038414Smckusick 	nfsstats.rpccnt[NFSPROC_RMDIR]++;
143153806Smckusick 	nfsm_reqhead(dvp, NFSPROC_RMDIR,
143253806Smckusick 		NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen));
143353806Smckusick 	nfsm_fhtom(dvp);
143453806Smckusick 	nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
143553806Smckusick 	nfsm_request(dvp, NFSPROC_RMDIR, cnp->cn_proc, cnp->cn_cred);
143638414Smckusick 	nfsm_reqdone;
143753806Smckusick 	FREE(cnp->cn_pnbuf, M_NAMEI);
143853806Smckusick 	VTONFS(dvp)->n_flag |= NMODIFIED;
143953806Smckusick 	cache_purge(dvp);
144053806Smckusick 	cache_purge(vp);
144153806Smckusick 	vrele(vp);
144253806Smckusick 	vrele(dvp);
144340112Smckusick 	/*
144440112Smckusick 	 * Kludge: Map ENOENT => 0 assuming that you have a reply to a retry.
144540112Smckusick 	 */
144640112Smckusick 	if (error == ENOENT)
144740112Smckusick 		error = 0;
144838414Smckusick 	return (error);
144938414Smckusick }
145038414Smckusick 
145138414Smckusick /*
145238414Smckusick  * nfs readdir call
145338414Smckusick  * Although cookie is defined as opaque, I translate it to/from net byte
145438414Smckusick  * order so that it looks more sensible. This appears consistent with the
145538414Smckusick  * Ultrix implementation of NFS.
145638414Smckusick  */
145752234Sheideman int
145853806Smckusick nfs_readdir(ap)
145954668Smckusick 	struct vop_readdir_args /* {
146054668Smckusick 		struct vnode *a_vp;
146154668Smckusick 		struct uio *a_uio;
146254668Smckusick 		struct ucred *a_cred;
146354668Smckusick 	} */ *ap;
146438414Smckusick {
146553806Smckusick 	register struct vnode *vp = ap->a_vp;
146653806Smckusick 	register struct nfsnode *np = VTONFS(vp);
146753806Smckusick 	register struct uio *uio = ap->a_uio;
146841905Smckusick 	int tresid, error;
146941905Smckusick 	struct vattr vattr;
147041905Smckusick 
147153806Smckusick 	if (vp->v_type != VDIR)
147241905Smckusick 		return (EPERM);
147341905Smckusick 	/*
147441905Smckusick 	 * First, check for hit on the EOF offset cache
147541905Smckusick 	 */
147653806Smckusick 	if (uio->uio_offset != 0 && uio->uio_offset == np->n_direofoffset &&
147752196Smckusick 	    (np->n_flag & NMODIFIED) == 0) {
147853806Smckusick 		if (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) {
147953806Smckusick 			if (NQNFS_CKCACHABLE(vp, NQL_READ)) {
148052196Smckusick 				nfsstats.direofcache_hits++;
148152196Smckusick 				return (0);
148252196Smckusick 			}
148353806Smckusick 		} else if (VOP_GETATTR(vp, &vattr, ap->a_cred, uio->uio_procp) == 0 &&
148454106Smckusick 			np->n_mtime == vattr.va_mtime.ts_sec) {
148552196Smckusick 			nfsstats.direofcache_hits++;
148652196Smckusick 			return (0);
148752196Smckusick 		}
148841905Smckusick 	}
148941905Smckusick 
149041905Smckusick 	/*
149141905Smckusick 	 * Call nfs_bioread() to do the real work.
149241905Smckusick 	 */
149353806Smckusick 	tresid = uio->uio_resid;
149453806Smckusick 	error = nfs_bioread(vp, uio, 0, ap->a_cred);
149541905Smckusick 
149654451Smckusick 	if (!error && uio->uio_resid == tresid)
149741905Smckusick 		nfsstats.direofcache_misses++;
149841905Smckusick 	return (error);
149941905Smckusick }
150041905Smckusick 
150141905Smckusick /*
150241905Smckusick  * Readdir rpc call.
150341905Smckusick  * Called from below the buffer cache by nfs_doio().
150441905Smckusick  */
150552234Sheideman int
150648054Smckusick nfs_readdirrpc(vp, uiop, cred)
150741905Smckusick 	register struct vnode *vp;
150841905Smckusick 	struct uio *uiop;
150941905Smckusick 	struct ucred *cred;
151041905Smckusick {
151138414Smckusick 	register long len;
151254740Smckusick 	register struct dirent *dp;
151348054Smckusick 	register u_long *tl;
151439488Smckusick 	register caddr_t cp;
151539488Smckusick 	register long t1;
151641905Smckusick 	long tlen, lastlen;
151739488Smckusick 	caddr_t bpos, dpos, cp2;
151839488Smckusick 	int error = 0;
151939488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
152038414Smckusick 	struct mbuf *md2;
152138414Smckusick 	caddr_t dpos2;
152238414Smckusick 	int siz;
152340296Smckusick 	int more_dirs = 1;
152456289Smckusick 	u_long off, savoff;
152554740Smckusick 	struct dirent *savdp;
152640296Smckusick 	struct nfsmount *nmp;
152740296Smckusick 	struct nfsnode *np = VTONFS(vp);
152840296Smckusick 	long tresid;
152938414Smckusick 
153041398Smckusick 	nmp = VFSTONFS(vp->v_mount);
153140296Smckusick 	tresid = uiop->uio_resid;
153240296Smckusick 	/*
153340296Smckusick 	 * Loop around doing readdir rpc's of size uio_resid or nm_rsize,
153448054Smckusick 	 * whichever is smaller, truncated to a multiple of NFS_DIRBLKSIZ.
153541905Smckusick 	 * The stopping criteria is EOF or buffer full.
153640296Smckusick 	 */
153748054Smckusick 	while (more_dirs && uiop->uio_resid >= NFS_DIRBLKSIZ) {
153840296Smckusick 		nfsstats.rpccnt[NFSPROC_READDIR]++;
153952196Smckusick 		nfsm_reqhead(vp, NFSPROC_READDIR,
154056289Smckusick 			NFSX_FH + 2 * NFSX_UNSIGNED);
154140296Smckusick 		nfsm_fhtom(vp);
154256289Smckusick 		nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED);
154356289Smckusick 		off = (u_long)uiop->uio_offset;
154456289Smckusick 		*tl++ = txdr_unsigned(off);
154548054Smckusick 		*tl = txdr_unsigned(((uiop->uio_resid > nmp->nm_rsize) ?
154648054Smckusick 			nmp->nm_rsize : uiop->uio_resid) & ~(NFS_DIRBLKSIZ-1));
154752196Smckusick 		nfsm_request(vp, NFSPROC_READDIR, uiop->uio_procp, cred);
154840296Smckusick 		siz = 0;
154952196Smckusick 		nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
155048054Smckusick 		more_dirs = fxdr_unsigned(int, *tl);
155140296Smckusick 
155240296Smckusick 		/* Save the position so that we can do nfsm_mtouio() later */
155340296Smckusick 		dpos2 = dpos;
155440296Smckusick 		md2 = md;
155540296Smckusick 
155640296Smckusick 		/* loop thru the dir entries, doctoring them to 4bsd form */
155742246Smckusick #ifdef lint
155854740Smckusick 		dp = (struct dirent *)0;
155942246Smckusick #endif /* lint */
156040296Smckusick 		while (more_dirs && siz < uiop->uio_resid) {
156140296Smckusick 			savoff = off;		/* Hold onto offset and dp */
156240296Smckusick 			savdp = dp;
156356289Smckusick 			nfsm_dissecton(tl, u_long *, 2 * NFSX_UNSIGNED);
156454740Smckusick 			dp = (struct dirent *)tl;
156554740Smckusick 			dp->d_fileno = fxdr_unsigned(u_long, *tl++);
156648054Smckusick 			len = fxdr_unsigned(int, *tl);
156740296Smckusick 			if (len <= 0 || len > NFS_MAXNAMLEN) {
156840296Smckusick 				error = EBADRPC;
156940296Smckusick 				m_freem(mrep);
157040296Smckusick 				goto nfsmout;
157140296Smckusick 			}
157254986Smckusick 			dp->d_namlen = (u_char)len;
157354986Smckusick 			dp->d_type = DT_UNKNOWN;
157440296Smckusick 			nfsm_adv(len);		/* Point past name */
157540296Smckusick 			tlen = nfsm_rndup(len);
157640296Smckusick 			/*
157740296Smckusick 			 * This should not be necessary, but some servers have
157840296Smckusick 			 * broken XDR such that these bytes are not null filled.
157940296Smckusick 			 */
158040296Smckusick 			if (tlen != len) {
158140296Smckusick 				*dpos = '\0';	/* Null-terminate */
158240296Smckusick 				nfsm_adv(tlen - len);
158340296Smckusick 				len = tlen;
158440296Smckusick 			}
158556289Smckusick 			nfsm_dissecton(tl, u_long *, 2 * NFSX_UNSIGNED);
158654986Smckusick 			off = fxdr_unsigned(u_long, *tl);
158748054Smckusick 			*tl++ = 0;	/* Ensures null termination of name */
158848054Smckusick 			more_dirs = fxdr_unsigned(int, *tl);
158956289Smckusick 			dp->d_reclen = len + 4 * NFSX_UNSIGNED;
159040296Smckusick 			siz += dp->d_reclen;
159140296Smckusick 		}
159240296Smckusick 		/*
159340296Smckusick 		 * If at end of rpc data, get the eof boolean
159440296Smckusick 		 */
159540296Smckusick 		if (!more_dirs) {
159652196Smckusick 			nfsm_dissecton(tl, u_long *, NFSX_UNSIGNED);
159748054Smckusick 			more_dirs = (fxdr_unsigned(int, *tl) == 0);
159838414Smckusick 
159940296Smckusick 			/*
160040296Smckusick 			 * If at EOF, cache directory offset
160140296Smckusick 			 */
160241905Smckusick 			if (!more_dirs)
160340296Smckusick 				np->n_direofoffset = off;
160438414Smckusick 		}
160540296Smckusick 		/*
160640296Smckusick 		 * If there is too much to fit in the data buffer, use savoff and
160740296Smckusick 		 * savdp to trim off the last record.
160840296Smckusick 		 * --> we are not at eof
160940296Smckusick 		 */
161040296Smckusick 		if (siz > uiop->uio_resid) {
161140296Smckusick 			off = savoff;
161240296Smckusick 			siz -= dp->d_reclen;
161340296Smckusick 			dp = savdp;
161440296Smckusick 			more_dirs = 0;	/* Paranoia */
161540113Smckusick 		}
161640296Smckusick 		if (siz > 0) {
161741905Smckusick 			lastlen = dp->d_reclen;
161840296Smckusick 			md = md2;
161940296Smckusick 			dpos = dpos2;
162040296Smckusick 			nfsm_mtouio(uiop, siz);
162156289Smckusick 			uiop->uio_offset = (off_t)off;
162240296Smckusick 		} else
162340296Smckusick 			more_dirs = 0;	/* Ugh, never happens, but in case.. */
162440296Smckusick 		m_freem(mrep);
162538414Smckusick 	}
162641905Smckusick 	/*
162748054Smckusick 	 * Fill last record, iff any, out to a multiple of NFS_DIRBLKSIZ
162841905Smckusick 	 * by increasing d_reclen for the last record.
162941905Smckusick 	 */
163041905Smckusick 	if (uiop->uio_resid < tresid) {
163148054Smckusick 		len = uiop->uio_resid & (NFS_DIRBLKSIZ - 1);
163241905Smckusick 		if (len > 0) {
163354740Smckusick 			dp = (struct dirent *)
163441905Smckusick 				(uiop->uio_iov->iov_base - lastlen);
163541905Smckusick 			dp->d_reclen += len;
163641905Smckusick 			uiop->uio_iov->iov_base += len;
163741905Smckusick 			uiop->uio_iov->iov_len -= len;
163841905Smckusick 			uiop->uio_resid -= len;
163941905Smckusick 		}
164041905Smckusick 	}
164140296Smckusick nfsmout:
164238414Smckusick 	return (error);
164338414Smckusick }
164438414Smckusick 
164552196Smckusick /*
164656289Smckusick  * Nqnfs readdir_and_lookup RPC. Used in place of nfs_readdirrpc().
164752196Smckusick  */
164852234Sheideman int
164952196Smckusick nfs_readdirlookrpc(vp, uiop, cred)
165052196Smckusick 	struct vnode *vp;
165152196Smckusick 	register struct uio *uiop;
165252196Smckusick 	struct ucred *cred;
165352196Smckusick {
165452196Smckusick 	register int len;
165554740Smckusick 	register struct dirent *dp;
165652196Smckusick 	register u_long *tl;
165752196Smckusick 	register caddr_t cp;
165852196Smckusick 	register long t1;
165952196Smckusick 	caddr_t bpos, dpos, cp2;
166052196Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
166152196Smckusick 	struct nameidata nami, *ndp = &nami;
166252317Sheideman 	struct componentname *cnp = &ndp->ni_cnd;
166356289Smckusick 	u_long off, endoff, fileno;
166452196Smckusick 	time_t reqtime, ltime;
166552196Smckusick 	struct nfsmount *nmp;
166652196Smckusick 	struct nfsnode *np, *tp;
166752196Smckusick 	struct vnode *newvp;
166852196Smckusick 	nfsv2fh_t *fhp;
166952196Smckusick 	u_quad_t frev;
167052196Smckusick 	int error = 0, tlen, more_dirs = 1, tresid, doit, bigenough, i;
167152196Smckusick 	int cachable;
167252196Smckusick 
167352196Smckusick 	if (uiop->uio_iovcnt != 1)
167452196Smckusick 		panic("nfs rdirlook");
167552196Smckusick 	nmp = VFSTONFS(vp->v_mount);
167652196Smckusick 	tresid = uiop->uio_resid;
167752196Smckusick 	ndp->ni_dvp = vp;
167852196Smckusick 	newvp = NULLVP;
167952196Smckusick 	/*
168052196Smckusick 	 * Loop around doing readdir rpc's of size uio_resid or nm_rsize,
168152196Smckusick 	 * whichever is smaller, truncated to a multiple of NFS_DIRBLKSIZ.
168252196Smckusick 	 * The stopping criteria is EOF or buffer full.
168352196Smckusick 	 */
168452196Smckusick 	while (more_dirs && uiop->uio_resid >= NFS_DIRBLKSIZ) {
168552196Smckusick 		nfsstats.rpccnt[NQNFSPROC_READDIRLOOK]++;
168652196Smckusick 		nfsm_reqhead(vp, NQNFSPROC_READDIRLOOK,
168756289Smckusick 			NFSX_FH + 3 * NFSX_UNSIGNED);
168852196Smckusick 		nfsm_fhtom(vp);
168956289Smckusick  		nfsm_build(tl, u_long *, 3 * NFSX_UNSIGNED);
169056289Smckusick 		off = (u_long)uiop->uio_offset;
169156289Smckusick 		*tl++ = txdr_unsigned(off);
169252196Smckusick 		*tl++ = txdr_unsigned(((uiop->uio_resid > nmp->nm_rsize) ?
169352196Smckusick 			nmp->nm_rsize : uiop->uio_resid) & ~(NFS_DIRBLKSIZ-1));
169456289Smckusick 		if (nmp->nm_flag & NFSMNT_NQLOOKLEASE)
169556289Smckusick 			*tl = txdr_unsigned(nmp->nm_leaseterm);
169656289Smckusick 		else
169756289Smckusick 			*tl = 0;
169852196Smckusick 		reqtime = time.tv_sec;
169952196Smckusick 		nfsm_request(vp, NQNFSPROC_READDIRLOOK, uiop->uio_procp, cred);
170052196Smckusick 		nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
170152196Smckusick 		more_dirs = fxdr_unsigned(int, *tl);
170252196Smckusick 
170352196Smckusick 		/* loop thru the dir entries, doctoring them to 4bsd form */
170452196Smckusick 		bigenough = 1;
170552196Smckusick 		while (more_dirs && bigenough) {
170652196Smckusick 			doit = 1;
170756289Smckusick 			nfsm_dissect(tl, u_long *, 4 * NFSX_UNSIGNED);
170856289Smckusick 			if (nmp->nm_flag & NFSMNT_NQLOOKLEASE) {
170956289Smckusick 				cachable = fxdr_unsigned(int, *tl++);
171056289Smckusick 				ltime = reqtime + fxdr_unsigned(int, *tl++);
171156289Smckusick 				fxdr_hyper(tl, &frev);
171256289Smckusick 			}
171352196Smckusick 			nfsm_dissect(fhp, nfsv2fh_t *, NFSX_FH);
171452196Smckusick 			if (!bcmp(VTONFS(vp)->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) {
171552196Smckusick 				VREF(vp);
171652196Smckusick 				newvp = vp;
171752196Smckusick 				np = VTONFS(vp);
171852196Smckusick 			} else {
171952196Smckusick 				if (error = nfs_nget(vp->v_mount, fhp, &np))
172052196Smckusick 					doit = 0;
172152196Smckusick 				newvp = NFSTOV(np);
172252196Smckusick 			}
172352196Smckusick 			if (error = nfs_loadattrcache(&newvp, &md, &dpos,
172452196Smckusick 				(struct vattr *)0))
172552196Smckusick 				doit = 0;
172656289Smckusick 			nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
172752196Smckusick 			fileno = fxdr_unsigned(u_long, *tl++);
172852196Smckusick 			len = fxdr_unsigned(int, *tl);
172952196Smckusick 			if (len <= 0 || len > NFS_MAXNAMLEN) {
173052196Smckusick 				error = EBADRPC;
173152196Smckusick 				m_freem(mrep);
173252196Smckusick 				goto nfsmout;
173352196Smckusick 			}
173452196Smckusick 			tlen = (len + 4) & ~0x3;
173552196Smckusick 			if ((tlen + DIRHDSIZ) > uiop->uio_resid)
173652196Smckusick 				bigenough = 0;
173752196Smckusick 			if (bigenough && doit) {
173854740Smckusick 				dp = (struct dirent *)uiop->uio_iov->iov_base;
173954740Smckusick 				dp->d_fileno = fileno;
174052196Smckusick 				dp->d_namlen = len;
174152196Smckusick 				dp->d_reclen = tlen + DIRHDSIZ;
174254986Smckusick 				dp->d_type =
174354986Smckusick 				    IFTODT(VTTOIF(np->n_vattr.va_type));
174452196Smckusick 				uiop->uio_resid -= DIRHDSIZ;
174552196Smckusick 				uiop->uio_iov->iov_base += DIRHDSIZ;
174652196Smckusick 				uiop->uio_iov->iov_len -= DIRHDSIZ;
174752317Sheideman 				cnp->cn_nameptr = uiop->uio_iov->iov_base;
174852317Sheideman 				cnp->cn_namelen = len;
174952196Smckusick 				ndp->ni_vp = newvp;
175052196Smckusick 				nfsm_mtouio(uiop, len);
175152196Smckusick 				cp = uiop->uio_iov->iov_base;
175252196Smckusick 				tlen -= len;
175352196Smckusick 				for (i = 0; i < tlen; i++)
175452196Smckusick 					*cp++ = '\0';
175552196Smckusick 				uiop->uio_iov->iov_base += tlen;
175652196Smckusick 				uiop->uio_iov->iov_len -= tlen;
175752196Smckusick 				uiop->uio_resid -= tlen;
175852317Sheideman 				cnp->cn_hash = 0;
175952317Sheideman 				for (cp = cnp->cn_nameptr, i = 1; i <= len; i++, cp++)
176052317Sheideman 					cnp->cn_hash += (unsigned char)*cp * i;
176156289Smckusick 				if ((nmp->nm_flag & NFSMNT_NQLOOKLEASE) &&
176256289Smckusick 					ltime > time.tv_sec)
176356289Smckusick 					nqnfs_clientlease(nmp, np, NQL_READ,
176456289Smckusick 						cachable, ltime, frev);
176556289Smckusick 				cache_enter(ndp->ni_dvp, ndp->ni_vp, cnp);
176652196Smckusick 			} else {
176752196Smckusick 				nfsm_adv(nfsm_rndup(len));
176852196Smckusick 			}
176952196Smckusick 			if (newvp != NULLVP) {
177052196Smckusick 				vrele(newvp);
177152196Smckusick 				newvp = NULLVP;
177252196Smckusick 			}
177356289Smckusick 			nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
177452196Smckusick 			if (bigenough)
177556289Smckusick 				endoff = off = fxdr_unsigned(u_long, *tl++);
177652196Smckusick 			else
177756289Smckusick 				endoff = fxdr_unsigned(u_long, *tl++);
177852196Smckusick 			more_dirs = fxdr_unsigned(int, *tl);
177952196Smckusick 		}
178052196Smckusick 		/*
178152196Smckusick 		 * If at end of rpc data, get the eof boolean
178252196Smckusick 		 */
178352196Smckusick 		if (!more_dirs) {
178452196Smckusick 			nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
178552196Smckusick 			more_dirs = (fxdr_unsigned(int, *tl) == 0);
178652196Smckusick 
178752196Smckusick 			/*
178852196Smckusick 			 * If at EOF, cache directory offset
178952196Smckusick 			 */
179052196Smckusick 			if (!more_dirs)
179152196Smckusick 				VTONFS(vp)->n_direofoffset = endoff;
179252196Smckusick 		}
179352196Smckusick 		if (uiop->uio_resid < tresid)
179456289Smckusick 			uiop->uio_offset = (off_t)off;
179552196Smckusick 		else
179652196Smckusick 			more_dirs = 0;
179752196Smckusick 		m_freem(mrep);
179852196Smckusick 	}
179952196Smckusick 	/*
180052196Smckusick 	 * Fill last record, iff any, out to a multiple of NFS_DIRBLKSIZ
180152196Smckusick 	 * by increasing d_reclen for the last record.
180252196Smckusick 	 */
180352196Smckusick 	if (uiop->uio_resid < tresid) {
180452196Smckusick 		len = uiop->uio_resid & (NFS_DIRBLKSIZ - 1);
180552196Smckusick 		if (len > 0) {
180652196Smckusick 			dp->d_reclen += len;
180752196Smckusick 			uiop->uio_iov->iov_base += len;
180852196Smckusick 			uiop->uio_iov->iov_len -= len;
180952196Smckusick 			uiop->uio_resid -= len;
181052196Smckusick 		}
181152196Smckusick 	}
181252196Smckusick nfsmout:
181352196Smckusick 	if (newvp != NULLVP)
181452196Smckusick 		vrele(newvp);
181552196Smckusick 	return (error);
181652196Smckusick }
181739488Smckusick static char hextoasc[] = "0123456789abcdef";
181838414Smckusick 
181938414Smckusick /*
182038414Smckusick  * Silly rename. To make the NFS filesystem that is stateless look a little
182138414Smckusick  * more like the "ufs" a remove of an active vnode is translated to a rename
182238414Smckusick  * to a funny looking filename that is removed by nfs_inactive on the
182338414Smckusick  * nfsnode. There is the potential for another process on a different client
182438414Smckusick  * to create the same funny name between the nfs_lookitup() fails and the
182538414Smckusick  * nfs_rename() completes, but...
182638414Smckusick  */
182752234Sheideman int
182852317Sheideman nfs_sillyrename(dvp, vp, cnp)
182952234Sheideman 	struct vnode *dvp, *vp;
183052234Sheideman 	struct componentname *cnp;
183138414Smckusick {
183238414Smckusick 	register struct nfsnode *np;
183338414Smckusick 	register struct sillyrename *sp;
183438414Smckusick 	int error;
183538414Smckusick 	short pid;
183638414Smckusick 
183752234Sheideman 	cache_purge(dvp);
183852234Sheideman 	np = VTONFS(vp);
183951986Smckusick #ifdef SILLYSEPARATE
184038414Smckusick 	MALLOC(sp, struct sillyrename *, sizeof (struct sillyrename),
184148364Smckusick 		M_NFSREQ, M_WAITOK);
184251986Smckusick #else
184351986Smckusick 	sp = &np->n_silly;
184451986Smckusick #endif
184552234Sheideman 	sp->s_cred = crdup(cnp->cn_cred);
184652234Sheideman 	sp->s_dvp = dvp;
184752234Sheideman 	VREF(dvp);
184838414Smckusick 
184938414Smckusick 	/* Fudge together a funny name */
185052234Sheideman 	pid = cnp->cn_proc->p_pid;
185148364Smckusick 	bcopy(".nfsAxxxx4.4", sp->s_name, 13);
185248364Smckusick 	sp->s_namlen = 12;
185348364Smckusick 	sp->s_name[8] = hextoasc[pid & 0xf];
185448364Smckusick 	sp->s_name[7] = hextoasc[(pid >> 4) & 0xf];
185548364Smckusick 	sp->s_name[6] = hextoasc[(pid >> 8) & 0xf];
185648364Smckusick 	sp->s_name[5] = hextoasc[(pid >> 12) & 0xf];
185738414Smckusick 
185838414Smckusick 	/* Try lookitups until we get one that isn't there */
185952234Sheideman 	while (nfs_lookitup(sp, (nfsv2fh_t *)0, cnp->cn_proc) == 0) {
186048364Smckusick 		sp->s_name[4]++;
186148364Smckusick 		if (sp->s_name[4] > 'z') {
186238414Smckusick 			error = EINVAL;
186338414Smckusick 			goto bad;
186438414Smckusick 		}
186538414Smckusick 	}
186652234Sheideman 	if (error = nfs_renameit(dvp, cnp, sp))
186738414Smckusick 		goto bad;
186852234Sheideman 	nfs_lookitup(sp, &np->n_fh, cnp->cn_proc);
186938414Smckusick 	np->n_sillyrename = sp;
187038414Smckusick 	return (0);
187138414Smckusick bad:
187248364Smckusick 	vrele(sp->s_dvp);
187348364Smckusick 	crfree(sp->s_cred);
187451986Smckusick #ifdef SILLYSEPARATE
187548364Smckusick 	free((caddr_t)sp, M_NFSREQ);
187651986Smckusick #endif
187738414Smckusick 	return (error);
187838414Smckusick }
187938414Smckusick 
188038414Smckusick /*
188138414Smckusick  * Look up a file name for silly rename stuff.
188238414Smckusick  * Just like nfs_lookup() except that it doesn't load returned values
188338414Smckusick  * into the nfsnode table.
188438414Smckusick  * If fhp != NULL it copies the returned file handle out
188538414Smckusick  */
188652234Sheideman int
188752196Smckusick nfs_lookitup(sp, fhp, procp)
188848364Smckusick 	register struct sillyrename *sp;
188938414Smckusick 	nfsv2fh_t *fhp;
189052196Smckusick 	struct proc *procp;
189138414Smckusick {
189248364Smckusick 	register struct vnode *vp = sp->s_dvp;
189348054Smckusick 	register u_long *tl;
189439488Smckusick 	register caddr_t cp;
189539488Smckusick 	register long t1, t2;
189639488Smckusick 	caddr_t bpos, dpos, cp2;
189739488Smckusick 	u_long xid;
189856289Smckusick 	int error = 0, isnq;
189939488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
190038414Smckusick 	long len;
190138414Smckusick 
190256289Smckusick 	isnq = (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS);
190338414Smckusick 	nfsstats.rpccnt[NFSPROC_LOOKUP]++;
190448364Smckusick 	len = sp->s_namlen;
190552196Smckusick 	nfsm_reqhead(vp, NFSPROC_LOOKUP, NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len));
190656289Smckusick 	if (isnq) {
190756289Smckusick 		nfsm_build(tl, u_long *, NFSX_UNSIGNED);
190856289Smckusick 		*tl = 0;
190956289Smckusick 	}
191038414Smckusick 	nfsm_fhtom(vp);
191148364Smckusick 	nfsm_strtom(sp->s_name, len, NFS_MAXNAMLEN);
191252196Smckusick 	nfsm_request(vp, NFSPROC_LOOKUP, procp, sp->s_cred);
191338414Smckusick 	if (fhp != NULL) {
191456289Smckusick 		if (isnq)
191556289Smckusick 			nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
191652196Smckusick 		nfsm_dissect(cp, caddr_t, NFSX_FH);
191738414Smckusick 		bcopy(cp, (caddr_t)fhp, NFSX_FH);
191838414Smckusick 	}
191938414Smckusick 	nfsm_reqdone;
192038414Smckusick 	return (error);
192138414Smckusick }
192238414Smckusick 
192338414Smckusick /*
192438414Smckusick  * Kludge City..
192538414Smckusick  * - make nfs_bmap() essentially a no-op that does no translation
192641905Smckusick  * - do nfs_strategy() by faking physical I/O with nfs_readrpc/nfs_writerpc
192738414Smckusick  *   after mapping the physical addresses into Kernel Virtual space in the
192838414Smckusick  *   nfsiobuf area.
192938414Smckusick  *   (Maybe I could use the process's page mapping, but I was concerned that
193038414Smckusick  *    Kernel Write might not be enabled and also figured copyout() would do
193138414Smckusick  *    a lot more work than bcopy() and also it currently happens in the
193238414Smckusick  *    context of the swapper process (2).
193338414Smckusick  */
193452234Sheideman int
193553806Smckusick nfs_bmap(ap)
193654668Smckusick 	struct vop_bmap_args /* {
193754668Smckusick 		struct vnode *a_vp;
193854668Smckusick 		daddr_t  a_bn;
193954668Smckusick 		struct vnode **a_vpp;
194054668Smckusick 		daddr_t *a_bnp;
194156452Smargo 		int *a_runp;
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*56468Smckusick 			queue_enter_tail(&nfs_bufq, bp, struct buf *, b_freelist);
199139341Smckusick 			fnd++;
199239341Smckusick 			wakeup((caddr_t)&nfs_iodwant[i]);
199339341Smckusick 			break;
199438884Smacklem 		}
199539341Smckusick 	}
199639341Smckusick 	if (!fnd)
199753806Smckusick 		error = nfs_doio(bp);
199838884Smacklem 	return (error);
199938884Smacklem }
200038884Smacklem 
200138884Smacklem /*
200238884Smacklem  * Fun and games with i/o
200338884Smacklem  * Essentially play ubasetup() and disk interrupt service routine by
200438884Smacklem  * mapping the data buffer into kernel virtual space and doing the
200538884Smacklem  * nfs read or write rpc's from it.
200641905Smckusick  * If the nfsiod's are not running, this is just called from nfs_strategy(),
200741905Smckusick  * otherwise it is called by the nfsiods to do what would normally be
200838884Smacklem  * partially disk interrupt driven.
200938884Smacklem  */
201052234Sheideman int
201138884Smacklem nfs_doio(bp)
201238884Smacklem 	register struct buf *bp;
201338884Smacklem {
201438414Smckusick 	register struct uio *uiop;
201538414Smckusick 	register struct vnode *vp;
201639341Smckusick 	struct nfsnode *np;
201738884Smacklem 	struct ucred *cr;
201841539Smckusick 	int error;
201941539Smckusick 	struct uio uio;
202041539Smckusick 	struct iovec io;
202138414Smckusick 
202238414Smckusick 	vp = bp->b_vp;
202340251Smckusick 	np = VTONFS(vp);
202438414Smckusick 	uiop = &uio;
202538414Smckusick 	uiop->uio_iov = &io;
202638414Smckusick 	uiop->uio_iovcnt = 1;
202738414Smckusick 	uiop->uio_segflg = UIO_SYSSPACE;
202852196Smckusick 	uiop->uio_procp = bp->b_proc;
202939751Smckusick 
203038414Smckusick 	/*
203138884Smacklem 	 * For phys i/o, map the b_addr into kernel virtual space using
203238884Smacklem 	 * the Nfsiomap pte's
203338884Smacklem 	 * Also, add a temporary b_rcred for reading using the process's uid
203438884Smacklem 	 * and a guess at a group
203538414Smckusick 	 */
203638884Smacklem 	if (bp->b_flags & B_PHYS) {
203748054Smckusick 		if (bp->b_flags & B_DIRTY)
203848054Smckusick 			uiop->uio_procp = pageproc;
203948054Smckusick 		cr = crcopy(uiop->uio_procp->p_ucred);
204041539Smckusick 		/* mapping was already done by vmapbuf */
204141539Smckusick 		io.iov_base = bp->b_un.b_addr;
204239751Smckusick 
204338884Smacklem 		/*
204439751Smckusick 		 * And do the i/o rpc
204539751Smckusick 		 */
204639751Smckusick 		io.iov_len = uiop->uio_resid = bp->b_bcount;
204739823Smckusick 		uiop->uio_offset = bp->b_blkno * DEV_BSIZE;
204839751Smckusick 		if (bp->b_flags & B_READ) {
204939751Smckusick 			uiop->uio_rw = UIO_READ;
205039751Smckusick 			nfsstats.read_physios++;
205148054Smckusick 			bp->b_error = error = nfs_readrpc(vp, uiop, cr);
205245717Smckusick 			(void) vnode_pager_uncache(vp);
205339751Smckusick 		} else {
205439751Smckusick 			uiop->uio_rw = UIO_WRITE;
205539751Smckusick 			nfsstats.write_physios++;
205656289Smckusick 			bp->b_error = error = nfs_writerpc(vp, uiop, cr, 0);
205739341Smckusick 		}
205839751Smckusick 
205939751Smckusick 		/*
206039751Smckusick 		 * Finally, release pte's used by physical i/o
206139751Smckusick 		 */
206238884Smacklem 		crfree(cr);
206339751Smckusick 	} else {
206439751Smckusick 		if (bp->b_flags & B_READ) {
206539751Smckusick 			io.iov_len = uiop->uio_resid = bp->b_bcount;
206639751Smckusick 			io.iov_base = bp->b_un.b_addr;
206739751Smckusick 			uiop->uio_rw = UIO_READ;
206841905Smckusick 			switch (vp->v_type) {
206941905Smckusick 			case VREG:
207041905Smckusick 				uiop->uio_offset = bp->b_blkno * DEV_BSIZE;
207141905Smckusick 				nfsstats.read_bios++;
207248054Smckusick 				error = nfs_readrpc(vp, uiop, bp->b_rcred);
207341905Smckusick 				break;
207441905Smckusick 			case VLNK:
207541905Smckusick 				uiop->uio_offset = 0;
207641905Smckusick 				nfsstats.readlink_bios++;
207748054Smckusick 				error = nfs_readlinkrpc(vp, uiop, bp->b_rcred);
207841905Smckusick 				break;
207941905Smckusick 			case VDIR:
208041905Smckusick 				uiop->uio_offset = bp->b_lblkno;
208141905Smckusick 				nfsstats.readdir_bios++;
208256289Smckusick 				if (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS)
208352196Smckusick 				    error = nfs_readdirlookrpc(vp, uiop, bp->b_rcred);
208452196Smckusick 				else
208552196Smckusick 				    error = nfs_readdirrpc(vp, uiop, bp->b_rcred);
208641905Smckusick 				/*
208741905Smckusick 				 * Save offset cookie in b_blkno.
208841905Smckusick 				 */
208941905Smckusick 				bp->b_blkno = uiop->uio_offset;
209041905Smckusick 				break;
209141905Smckusick 			};
209241905Smckusick 			bp->b_error = error;
209339751Smckusick 		} else {
209439751Smckusick 			io.iov_len = uiop->uio_resid = bp->b_dirtyend
209539751Smckusick 				- bp->b_dirtyoff;
209639823Smckusick 			uiop->uio_offset = (bp->b_blkno * DEV_BSIZE)
209739751Smckusick 				+ bp->b_dirtyoff;
209839751Smckusick 			io.iov_base = bp->b_un.b_addr + bp->b_dirtyoff;
209939751Smckusick 			uiop->uio_rw = UIO_WRITE;
210039751Smckusick 			nfsstats.write_bios++;
210141905Smckusick 			bp->b_error = error = nfs_writerpc(vp, uiop,
210256289Smckusick 				bp->b_wcred, 0);
210339751Smckusick 			if (error) {
210439751Smckusick 				np->n_error = error;
210539751Smckusick 				np->n_flag |= NWRITEERR;
210639751Smckusick 			}
210739751Smckusick 			bp->b_dirtyoff = bp->b_dirtyend = 0;
210839751Smckusick 		}
210938884Smacklem 	}
211039751Smckusick 	if (error)
211139751Smckusick 		bp->b_flags |= B_ERROR;
211239751Smckusick 	bp->b_resid = uiop->uio_resid;
211338414Smckusick 	biodone(bp);
211438414Smckusick 	return (error);
211538414Smckusick }
211638884Smacklem 
211738884Smacklem /*
211848054Smckusick  * Mmap a file
211948054Smckusick  *
212048054Smckusick  * NB Currently unsupported.
212148054Smckusick  */
212248054Smckusick /* ARGSUSED */
212352234Sheideman int
212453806Smckusick nfs_mmap(ap)
212554668Smckusick 	struct vop_mmap_args /* {
212654668Smckusick 		struct vnode *a_vp;
212754668Smckusick 		int  a_fflags;
212854668Smckusick 		struct ucred *a_cred;
212954668Smckusick 		struct proc *a_p;
213054668Smckusick 	} */ *ap;
213148054Smckusick {
213248054Smckusick 
213348054Smckusick 	return (EINVAL);
213448054Smckusick }
213548054Smckusick 
213648054Smckusick /*
213738884Smacklem  * Flush all the blocks associated with a vnode.
213838884Smacklem  * 	Walk through the buffer pool and push any dirty pages
213938884Smacklem  *	associated with the vnode.
214038884Smacklem  */
214139488Smckusick /* ARGSUSED */
214252234Sheideman int
214353806Smckusick nfs_fsync(ap)
214454451Smckusick 	struct vop_fsync_args /* {
214554451Smckusick 		struct vnodeop_desc *a_desc;
214654451Smckusick 		struct vnode * a_vp;
214754451Smckusick 		struct ucred * a_cred;
214854451Smckusick 		int  a_waitfor;
214954451Smckusick 		struct proc * a_p;
215054451Smckusick 	} */ *ap;
215138884Smacklem {
215254451Smckusick 	register struct vnode *vp = ap->a_vp;
215354451Smckusick 	register struct nfsnode *np = VTONFS(vp);
215454451Smckusick 	register struct buf *bp;
215554451Smckusick 	struct buf *nbp;
215654451Smckusick 	int s, error = 0;
215738884Smacklem 
215854451Smckusick loop:
215954451Smckusick 	s = splbio();
2160*56468Smckusick 	for (bp = vp->v_dirtyblkhd.le_next; bp; bp = nbp) {
2161*56468Smckusick 		nbp = bp->b_vnbufs.qe_next;
216254451Smckusick 		if ((bp->b_flags & B_BUSY))
216354451Smckusick 			continue;
216454451Smckusick 		if ((bp->b_flags & B_DELWRI) == 0)
216554451Smckusick 			panic("nfs_fsync: not dirty");
216654451Smckusick 		bremfree(bp);
216754451Smckusick 		bp->b_flags |= B_BUSY;
216854451Smckusick 		splx(s);
216954451Smckusick 		error = bawrite(bp);
217054451Smckusick 		goto loop;
217138884Smacklem 	}
217254451Smckusick 	if (ap->a_waitfor == MNT_WAIT) {
217354451Smckusick 		while (vp->v_numoutput) {
217454451Smckusick 			vp->v_flag |= VBWAIT;
217554451Smckusick 			sleep((caddr_t)&vp->v_numoutput, PRIBIO + 1);
217654451Smckusick 		}
217754451Smckusick #ifdef DIAGNOSTIC
2178*56468Smckusick 		if (vp->v_dirtyblkhd.le_next) {
217954451Smckusick 			vprint("nfs_fsync: dirty", vp);
218054451Smckusick 			goto loop;
218154451Smckusick 		}
218254451Smckusick #endif
218354451Smckusick 	}
218454451Smckusick 	splx(s);
218554451Smckusick 	np->n_flag &= ~NMODIFIED;
218653629Smckusick 	if (np->n_flag & NWRITEERR) {
218739751Smckusick 		error = np->n_error;
218853629Smckusick 		np->n_flag &= ~NWRITEERR;
218953629Smckusick 	}
219038884Smacklem 	return (error);
219138884Smacklem }
219239672Smckusick 
219339672Smckusick /*
219446201Smckusick  * NFS advisory byte-level locks.
219546201Smckusick  * Currently unsupported.
219646201Smckusick  */
219752234Sheideman int
219853806Smckusick nfs_advlock(ap)
219954668Smckusick 	struct vop_advlock_args /* {
220054668Smckusick 		struct vnode *a_vp;
220154668Smckusick 		caddr_t  a_id;
220254668Smckusick 		int  a_op;
220354668Smckusick 		struct flock *a_fl;
220454668Smckusick 		int  a_flags;
220554668Smckusick 	} */ *ap;
220646201Smckusick {
220746201Smckusick 
220846201Smckusick 	return (EOPNOTSUPP);
220946201Smckusick }
221046201Smckusick 
221146201Smckusick /*
221239672Smckusick  * Print out the contents of an nfsnode.
221339672Smckusick  */
221452234Sheideman int
221553806Smckusick nfs_print(ap)
221654668Smckusick 	struct vop_print_args /* {
221754668Smckusick 		struct vnode *a_vp;
221854668Smckusick 	} */ *ap;
221939672Smckusick {
222053806Smckusick 	register struct vnode *vp = ap->a_vp;
222153806Smckusick 	register struct nfsnode *np = VTONFS(vp);
222239672Smckusick 
222340294Smckusick 	printf("tag VT_NFS, fileid %d fsid 0x%x",
222440294Smckusick 		np->n_vattr.va_fileid, np->n_vattr.va_fsid);
222540294Smckusick #ifdef FIFO
222653806Smckusick 	if (vp->v_type == VFIFO)
222753806Smckusick 		fifo_printinfo(vp);
222840294Smckusick #endif /* FIFO */
222939914Smckusick 	printf("\n");
223039672Smckusick }
223151573Smckusick 
223251573Smckusick /*
223351573Smckusick  * NFS directory offset lookup.
223451573Smckusick  * Currently unsupported.
223551573Smckusick  */
223652234Sheideman int
223753806Smckusick nfs_blkatoff(ap)
223854668Smckusick 	struct vop_blkatoff_args /* {
223954668Smckusick 		struct vnode *a_vp;
224054668Smckusick 		off_t a_offset;
224154668Smckusick 		char **a_res;
224254668Smckusick 		struct buf **a_bpp;
224354668Smckusick 	} */ *ap;
224451573Smckusick {
224551573Smckusick 
224651573Smckusick 	return (EOPNOTSUPP);
224751573Smckusick }
224851573Smckusick 
224951573Smckusick /*
225051573Smckusick  * NFS flat namespace allocation.
225151573Smckusick  * Currently unsupported.
225251573Smckusick  */
225352234Sheideman int
225453806Smckusick nfs_valloc(ap)
225554668Smckusick 	struct vop_valloc_args /* {
225654668Smckusick 		struct vnode *a_pvp;
225754668Smckusick 		int a_mode;
225854668Smckusick 		struct ucred *a_cred;
225954668Smckusick 		struct vnode **a_vpp;
226054668Smckusick 	} */ *ap;
226151573Smckusick {
226251573Smckusick 
226351573Smckusick 	return (EOPNOTSUPP);
226451573Smckusick }
226551573Smckusick 
226651573Smckusick /*
226751573Smckusick  * NFS flat namespace free.
226851573Smckusick  * Currently unsupported.
226951573Smckusick  */
227053582Sheideman int
227153806Smckusick nfs_vfree(ap)
227254668Smckusick 	struct vop_vfree_args /* {
227354668Smckusick 		struct vnode *a_pvp;
227454668Smckusick 		ino_t a_ino;
227554668Smckusick 		int a_mode;
227654668Smckusick 	} */ *ap;
227751573Smckusick {
227851573Smckusick 
227953582Sheideman 	return (EOPNOTSUPP);
228051573Smckusick }
228151573Smckusick 
228251573Smckusick /*
228351573Smckusick  * NFS file truncation.
228451573Smckusick  */
228552234Sheideman int
228653806Smckusick nfs_truncate(ap)
228754668Smckusick 	struct vop_truncate_args /* {
228854668Smckusick 		struct vnode *a_vp;
228954668Smckusick 		off_t a_length;
229054668Smckusick 		int a_flags;
229154668Smckusick 		struct ucred *a_cred;
229254668Smckusick 		struct proc *a_p;
229354668Smckusick 	} */ *ap;
229451573Smckusick {
229551573Smckusick 
229651573Smckusick 	/* Use nfs_setattr */
229751573Smckusick 	printf("nfs_truncate: need to implement!!");
229851573Smckusick 	return (EOPNOTSUPP);
229951573Smckusick }
230051573Smckusick 
230151573Smckusick /*
230251573Smckusick  * NFS update.
230351573Smckusick  */
230452234Sheideman int
230553806Smckusick nfs_update(ap)
230654668Smckusick 	struct vop_update_args /* {
230754668Smckusick 		struct vnode *a_vp;
230854668Smckusick 		struct timeval *a_ta;
230954668Smckusick 		struct timeval *a_tm;
231054668Smckusick 		int a_waitfor;
231154668Smckusick 	} */ *ap;
231251573Smckusick {
231351573Smckusick 
231451573Smckusick 	/* Use nfs_setattr */
231551573Smckusick 	printf("nfs_update: need to implement!!");
231651573Smckusick 	return (EOPNOTSUPP);
231751573Smckusick }
231853629Smckusick 
231953629Smckusick /*
232056364Smckusick  * nfs special file access vnode op.
232156364Smckusick  * Essentially just get vattr and then imitate iaccess() since the device is
232256364Smckusick  * local to the client.
232356364Smckusick  */
232456364Smckusick int
232556364Smckusick nfsspec_access(ap)
232656364Smckusick 	struct vop_access_args /* {
232756364Smckusick 		struct vnode *a_vp;
232856364Smckusick 		int  a_mode;
232956364Smckusick 		struct ucred *a_cred;
233056364Smckusick 		struct proc *a_p;
233156364Smckusick 	} */ *ap;
233256364Smckusick {
233356364Smckusick 	register struct vattr *vap;
233456364Smckusick 	register gid_t *gp;
233556364Smckusick 	register struct ucred *cred = ap->a_cred;
233656364Smckusick 	mode_t mode = ap->a_mode;
233756364Smckusick 	struct vattr vattr;
233856364Smckusick 	register int i;
233956364Smckusick 	int error;
234056364Smckusick 
234156364Smckusick 	/*
234256364Smckusick 	 * If you're the super-user,
234356364Smckusick 	 * you always get access.
234456364Smckusick 	 */
234556364Smckusick 	if (cred->cr_uid == 0)
234656364Smckusick 		return (0);
234756364Smckusick 	vap = &vattr;
234856364Smckusick 	if (error = VOP_GETATTR(ap->a_vp, vap, cred, ap->a_p))
234956364Smckusick 		return (error);
235056364Smckusick 	/*
235156364Smckusick 	 * Access check is based on only one of owner, group, public.
235256364Smckusick 	 * If not owner, then check group. If not a member of the
235356364Smckusick 	 * group, then check public access.
235456364Smckusick 	 */
235556364Smckusick 	if (cred->cr_uid != vap->va_uid) {
235656364Smckusick 		mode >>= 3;
235756364Smckusick 		gp = cred->cr_groups;
235856364Smckusick 		for (i = 0; i < cred->cr_ngroups; i++, gp++)
235956364Smckusick 			if (vap->va_gid == *gp)
236056364Smckusick 				goto found;
236156364Smckusick 		mode >>= 3;
236256364Smckusick found:
236356364Smckusick 		;
236456364Smckusick 	}
236556364Smckusick 	if ((vap->va_mode & mode) != 0)
236656364Smckusick 		return (0);
236756364Smckusick 	return (EACCES);
236856364Smckusick }
236956364Smckusick 
237056364Smckusick /*
237153629Smckusick  * Read wrapper for special devices.
237253629Smckusick  */
237353629Smckusick int
237453629Smckusick nfsspec_read(ap)
237554668Smckusick 	struct vop_read_args /* {
237654668Smckusick 		struct vnode *a_vp;
237754668Smckusick 		struct uio *a_uio;
237854668Smckusick 		int  a_ioflag;
237954668Smckusick 		struct ucred *a_cred;
238054668Smckusick 	} */ *ap;
238153629Smckusick {
238254032Smckusick 	register struct nfsnode *np = VTONFS(ap->a_vp);
238353629Smckusick 
238453629Smckusick 	/*
238553629Smckusick 	 * Set access flag.
238653629Smckusick 	 */
238754032Smckusick 	np->n_flag |= NACC;
238854032Smckusick 	np->n_atim = time;
238953629Smckusick 	return (VOCALL(spec_vnodeop_p, VOFFSET(vop_read), ap));
239053629Smckusick }
239153629Smckusick 
239253629Smckusick /*
239353629Smckusick  * Write wrapper for special devices.
239453629Smckusick  */
239553629Smckusick int
239653629Smckusick nfsspec_write(ap)
239754668Smckusick 	struct vop_write_args /* {
239854668Smckusick 		struct vnode *a_vp;
239954668Smckusick 		struct uio *a_uio;
240054668Smckusick 		int  a_ioflag;
240154668Smckusick 		struct ucred *a_cred;
240254668Smckusick 	} */ *ap;
240353629Smckusick {
240454032Smckusick 	register struct nfsnode *np = VTONFS(ap->a_vp);
240553629Smckusick 
240653629Smckusick 	/*
240754032Smckusick 	 * Set update flag.
240853629Smckusick 	 */
240954032Smckusick 	np->n_flag |= NUPD;
241054032Smckusick 	np->n_mtim = time;
241153629Smckusick 	return (VOCALL(spec_vnodeop_p, VOFFSET(vop_write), ap));
241253629Smckusick }
241353629Smckusick 
241453629Smckusick /*
241553629Smckusick  * Close wrapper for special devices.
241653629Smckusick  *
241753629Smckusick  * Update the times on the nfsnode then do device close.
241853629Smckusick  */
241953629Smckusick int
242053629Smckusick nfsspec_close(ap)
242154668Smckusick 	struct vop_close_args /* {
242254668Smckusick 		struct vnode *a_vp;
242354668Smckusick 		int  a_fflag;
242454668Smckusick 		struct ucred *a_cred;
242554668Smckusick 		struct proc *a_p;
242654668Smckusick 	} */ *ap;
242753629Smckusick {
242853806Smckusick 	register struct vnode *vp = ap->a_vp;
242953806Smckusick 	register struct nfsnode *np = VTONFS(vp);
243053629Smckusick 	struct vattr vattr;
243153629Smckusick 
243253629Smckusick 	if (np->n_flag & (NACC | NUPD)) {
243353629Smckusick 		np->n_flag |= NCHG;
243453806Smckusick 		if (vp->v_usecount == 1 &&
243553806Smckusick 		    (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) {
243653629Smckusick 			VATTR_NULL(&vattr);
243754106Smckusick 			if (np->n_flag & NACC) {
243854106Smckusick 				vattr.va_atime.ts_sec = np->n_atim.tv_sec;
243954106Smckusick 				vattr.va_atime.ts_nsec =
244054106Smckusick 				    np->n_atim.tv_usec * 1000;
244154106Smckusick 			}
244254106Smckusick 			if (np->n_flag & NUPD) {
244354106Smckusick 				vattr.va_mtime.ts_sec = np->n_mtim.tv_sec;
244454106Smckusick 				vattr.va_mtime.ts_nsec =
244554106Smckusick 				    np->n_mtim.tv_usec * 1000;
244654106Smckusick 			}
244753806Smckusick 			(void)VOP_SETATTR(vp, &vattr, ap->a_cred, ap->a_p);
244853629Smckusick 		}
244953629Smckusick 	}
245053629Smckusick 	return (VOCALL(spec_vnodeop_p, VOFFSET(vop_close), ap));
245153629Smckusick }
245253629Smckusick 
245353629Smckusick #ifdef FIFO
245453629Smckusick /*
245553629Smckusick  * Read wrapper for fifos.
245653629Smckusick  */
245753629Smckusick int
245853629Smckusick nfsfifo_read(ap)
245954668Smckusick 	struct vop_read_args /* {
246054668Smckusick 		struct vnode *a_vp;
246154668Smckusick 		struct uio *a_uio;
246254668Smckusick 		int  a_ioflag;
246354668Smckusick 		struct ucred *a_cred;
246454668Smckusick 	} */ *ap;
246553629Smckusick {
246653629Smckusick 	extern int (**fifo_vnodeop_p)();
246754032Smckusick 	register struct nfsnode *np = VTONFS(ap->a_vp);
246853629Smckusick 
246953629Smckusick 	/*
247053629Smckusick 	 * Set access flag.
247153629Smckusick 	 */
247254032Smckusick 	np->n_flag |= NACC;
247354032Smckusick 	np->n_atim = time;
247453629Smckusick 	return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_read), ap));
247553629Smckusick }
247653629Smckusick 
247753629Smckusick /*
247853629Smckusick  * Write wrapper for fifos.
247953629Smckusick  */
248053629Smckusick int
248153629Smckusick nfsfifo_write(ap)
248254668Smckusick 	struct vop_write_args /* {
248354668Smckusick 		struct vnode *a_vp;
248454668Smckusick 		struct uio *a_uio;
248554668Smckusick 		int  a_ioflag;
248654668Smckusick 		struct ucred *a_cred;
248754668Smckusick 	} */ *ap;
248853629Smckusick {
248953629Smckusick 	extern int (**fifo_vnodeop_p)();
249054032Smckusick 	register struct nfsnode *np = VTONFS(ap->a_vp);
249153629Smckusick 
249253629Smckusick 	/*
249353629Smckusick 	 * Set update flag.
249453629Smckusick 	 */
249554032Smckusick 	np->n_flag |= NUPD;
249654032Smckusick 	np->n_mtim = time;
249753629Smckusick 	return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_write), ap));
249853629Smckusick }
249953629Smckusick 
250053629Smckusick /*
250153629Smckusick  * Close wrapper for fifos.
250253629Smckusick  *
250353629Smckusick  * Update the times on the nfsnode then do fifo close.
250453629Smckusick  */
250553629Smckusick int
250653629Smckusick nfsfifo_close(ap)
250754668Smckusick 	struct vop_close_args /* {
250854668Smckusick 		struct vnode *a_vp;
250954668Smckusick 		int  a_fflag;
251054668Smckusick 		struct ucred *a_cred;
251154668Smckusick 		struct proc *a_p;
251254668Smckusick 	} */ *ap;
251353629Smckusick {
251453806Smckusick 	register struct vnode *vp = ap->a_vp;
251553806Smckusick 	register struct nfsnode *np = VTONFS(vp);
251653629Smckusick 	struct vattr vattr;
251753629Smckusick 	extern int (**fifo_vnodeop_p)();
251853629Smckusick 
251953629Smckusick 	if (np->n_flag & (NACC | NUPD)) {
252053629Smckusick 		if (np->n_flag & NACC)
252153629Smckusick 			np->n_atim = time;
252253629Smckusick 		if (np->n_flag & NUPD)
252353629Smckusick 			np->n_mtim = time;
252453629Smckusick 		np->n_flag |= NCHG;
252553806Smckusick 		if (vp->v_usecount == 1 &&
252653806Smckusick 		    (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) {
252753629Smckusick 			VATTR_NULL(&vattr);
252854106Smckusick 			if (np->n_flag & NACC) {
252954106Smckusick 				vattr.va_atime.ts_sec = np->n_atim.tv_sec;
253054106Smckusick 				vattr.va_atime.ts_nsec =
253154106Smckusick 				    np->n_atim.tv_usec * 1000;
253254106Smckusick 			}
253354106Smckusick 			if (np->n_flag & NUPD) {
253454106Smckusick 				vattr.va_mtime.ts_sec = np->n_mtim.tv_sec;
253554106Smckusick 				vattr.va_mtime.ts_nsec =
253654106Smckusick 				    np->n_mtim.tv_usec * 1000;
253754106Smckusick 			}
253853806Smckusick 			(void)VOP_SETATTR(vp, &vattr, ap->a_cred, ap->a_p);
253953629Smckusick 		}
254053629Smckusick 	}
254153629Smckusick 	return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_close), ap));
254253629Smckusick }
254353629Smckusick #endif /* FIFO */
2544