xref: /csrg-svn/sys/nfs/nfs_vnops.c (revision 69424)
138414Smckusick /*
263486Sbostic  * Copyright (c) 1989, 1993
363486Sbostic  *	The Regents of the University of California.  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*69424Smckusick  *	@(#)nfs_vnops.c	8.15 (Berkeley) 05/14/95
1138414Smckusick  */
1238414Smckusick 
1368653Smckusick 
1438414Smckusick /*
1568653Smckusick  * vnode op calls for Sun NFS version 2 and 3
1638414Smckusick  */
1738414Smckusick 
1853322Smckusick #include <sys/param.h>
1953322Smckusick #include <sys/kernel.h>
2053322Smckusick #include <sys/systm.h>
2168653Smckusick #include <sys/resourcevar.h>
2268653Smckusick #include <sys/proc.h>
2353322Smckusick #include <sys/mount.h>
2453322Smckusick #include <sys/buf.h>
2553322Smckusick #include <sys/malloc.h>
2653322Smckusick #include <sys/mbuf.h>
2753322Smckusick #include <sys/conf.h>
2853322Smckusick #include <sys/namei.h>
2953322Smckusick #include <sys/vnode.h>
3054740Smckusick #include <sys/dirent.h>
3168653Smckusick #include <sys/fcntl.h>
3268653Smckusick #include <ufs/ufs/dir.h>
3347573Skarels 
3453322Smckusick #include <vm/vm.h>
3538414Smckusick 
3655041Smckusick #include <miscfs/specfs/specdev.h>
3755041Smckusick #include <miscfs/fifofs/fifo.h>
3855041Smckusick 
3953322Smckusick #include <nfs/rpcv2.h>
4068653Smckusick #include <nfs/nfsproto.h>
4153322Smckusick #include <nfs/nfs.h>
4253322Smckusick #include <nfs/nfsnode.h>
4353322Smckusick #include <nfs/nfsmount.h>
4453322Smckusick #include <nfs/xdr_subs.h>
4553322Smckusick #include <nfs/nfsm_subs.h>
4653322Smckusick #include <nfs/nqnfs.h>
4753322Smckusick 
4868653Smckusick #include <net/if.h>
4968653Smckusick #include <netinet/in.h>
5068653Smckusick #include <netinet/in_var.h>
5168653Smckusick 
5238414Smckusick /* Defs */
5338414Smckusick #define	TRUE	1
5438414Smckusick #define	FALSE	0
5538414Smckusick 
5648054Smckusick /*
5748054Smckusick  * Global vfs data structures for nfs
5848054Smckusick  */
5953554Sheideman int (**nfsv2_vnodeop_p)();
6053554Sheideman struct vnodeopv_entry_desc nfsv2_vnodeop_entries[] = {
6153554Sheideman 	{ &vop_default_desc, vn_default_error },
6253806Smckusick 	{ &vop_lookup_desc, nfs_lookup },	/* lookup */
6353806Smckusick 	{ &vop_create_desc, nfs_create },	/* create */
6453554Sheideman 	{ &vop_mknod_desc, nfs_mknod },		/* mknod */
6553554Sheideman 	{ &vop_open_desc, nfs_open },		/* open */
6653554Sheideman 	{ &vop_close_desc, nfs_close },		/* close */
6753806Smckusick 	{ &vop_access_desc, nfs_access },	/* access */
6853806Smckusick 	{ &vop_getattr_desc, nfs_getattr },	/* getattr */
6953806Smckusick 	{ &vop_setattr_desc, nfs_setattr },	/* setattr */
7053554Sheideman 	{ &vop_read_desc, nfs_read },		/* read */
7153554Sheideman 	{ &vop_write_desc, nfs_write },		/* write */
7267651Smckusick 	{ &vop_lease_desc, nfs_lease_check },	/* lease */
7353554Sheideman 	{ &vop_ioctl_desc, nfs_ioctl },		/* ioctl */
7453806Smckusick 	{ &vop_select_desc, nfs_select },	/* select */
7568418Smckusick 	{ &vop_revoke_desc, nfs_revoke },	/* revoke */
7653554Sheideman 	{ &vop_mmap_desc, nfs_mmap },		/* mmap */
7753554Sheideman 	{ &vop_fsync_desc, nfs_fsync },		/* fsync */
7853554Sheideman 	{ &vop_seek_desc, nfs_seek },		/* seek */
7953806Smckusick 	{ &vop_remove_desc, nfs_remove },	/* remove */
8053554Sheideman 	{ &vop_link_desc, nfs_link },		/* link */
8153806Smckusick 	{ &vop_rename_desc, nfs_rename },	/* rename */
8253554Sheideman 	{ &vop_mkdir_desc, nfs_mkdir },		/* mkdir */
8353554Sheideman 	{ &vop_rmdir_desc, nfs_rmdir },		/* rmdir */
8453806Smckusick 	{ &vop_symlink_desc, nfs_symlink },	/* symlink */
8553806Smckusick 	{ &vop_readdir_desc, nfs_readdir },	/* readdir */
8653806Smckusick 	{ &vop_readlink_desc, nfs_readlink },	/* readlink */
8753806Smckusick 	{ &vop_abortop_desc, nfs_abortop },	/* abortop */
8853806Smckusick 	{ &vop_inactive_desc, nfs_inactive },	/* inactive */
8953806Smckusick 	{ &vop_reclaim_desc, nfs_reclaim },	/* reclaim */
9053554Sheideman 	{ &vop_lock_desc, nfs_lock },		/* lock */
9153806Smckusick 	{ &vop_unlock_desc, nfs_unlock },	/* unlock */
9253554Sheideman 	{ &vop_bmap_desc, nfs_bmap },		/* bmap */
9353806Smckusick 	{ &vop_strategy_desc, nfs_strategy },	/* strategy */
9453554Sheideman 	{ &vop_print_desc, nfs_print },		/* print */
9553806Smckusick 	{ &vop_islocked_desc, nfs_islocked },	/* islocked */
9660400Smckusick 	{ &vop_pathconf_desc, nfs_pathconf },	/* pathconf */
9753806Smckusick 	{ &vop_advlock_desc, nfs_advlock },	/* advlock */
9853806Smckusick 	{ &vop_blkatoff_desc, nfs_blkatoff },	/* blkatoff */
9953806Smckusick 	{ &vop_valloc_desc, nfs_valloc },	/* valloc */
10066079Shibler 	{ &vop_reallocblks_desc, nfs_reallocblks },	/* reallocblks */
10153554Sheideman 	{ &vop_vfree_desc, nfs_vfree },		/* vfree */
10253806Smckusick 	{ &vop_truncate_desc, nfs_truncate },	/* truncate */
10353806Smckusick 	{ &vop_update_desc, nfs_update },	/* update */
10468653Smckusick 	{ &vop_bwrite_desc, nfs_bwrite },
10553554Sheideman 	{ (struct vnodeop_desc*)NULL, (int(*)())NULL }
10638414Smckusick };
10753554Sheideman struct vnodeopv_desc nfsv2_vnodeop_opv_desc =
10853554Sheideman 	{ &nfsv2_vnodeop_p, nfsv2_vnodeop_entries };
10938414Smckusick 
11048054Smckusick /*
11148054Smckusick  * Special device vnode ops
11248054Smckusick  */
11353554Sheideman int (**spec_nfsv2nodeop_p)();
11453554Sheideman struct vnodeopv_entry_desc spec_nfsv2nodeop_entries[] = {
11553554Sheideman 	{ &vop_default_desc, vn_default_error },
11653806Smckusick 	{ &vop_lookup_desc, spec_lookup },	/* lookup */
11753806Smckusick 	{ &vop_create_desc, spec_create },	/* create */
11853806Smckusick 	{ &vop_mknod_desc, spec_mknod },	/* mknod */
11953554Sheideman 	{ &vop_open_desc, spec_open },		/* open */
12053806Smckusick 	{ &vop_close_desc, nfsspec_close },	/* close */
12156364Smckusick 	{ &vop_access_desc, nfsspec_access },	/* access */
12253806Smckusick 	{ &vop_getattr_desc, nfs_getattr },	/* getattr */
12353806Smckusick 	{ &vop_setattr_desc, nfs_setattr },	/* setattr */
12453806Smckusick 	{ &vop_read_desc, nfsspec_read },	/* read */
12553806Smckusick 	{ &vop_write_desc, nfsspec_write },	/* write */
12667651Smckusick 	{ &vop_lease_desc, spec_lease_check },	/* lease */
12753806Smckusick 	{ &vop_ioctl_desc, spec_ioctl },	/* ioctl */
12853806Smckusick 	{ &vop_select_desc, spec_select },	/* select */
12968418Smckusick 	{ &vop_revoke_desc, spec_revoke },	/* revoke */
13053554Sheideman 	{ &vop_mmap_desc, spec_mmap },		/* mmap */
13154451Smckusick 	{ &vop_fsync_desc, nfs_fsync },		/* fsync */
13253554Sheideman 	{ &vop_seek_desc, spec_seek },		/* seek */
13353806Smckusick 	{ &vop_remove_desc, spec_remove },	/* remove */
13453554Sheideman 	{ &vop_link_desc, spec_link },		/* link */
13553806Smckusick 	{ &vop_rename_desc, spec_rename },	/* rename */
13653806Smckusick 	{ &vop_mkdir_desc, spec_mkdir },	/* mkdir */
13753806Smckusick 	{ &vop_rmdir_desc, spec_rmdir },	/* rmdir */
13853806Smckusick 	{ &vop_symlink_desc, spec_symlink },	/* symlink */
13953806Smckusick 	{ &vop_readdir_desc, spec_readdir },	/* readdir */
14053806Smckusick 	{ &vop_readlink_desc, spec_readlink },	/* readlink */
14153806Smckusick 	{ &vop_abortop_desc, spec_abortop },	/* abortop */
14253806Smckusick 	{ &vop_inactive_desc, nfs_inactive },	/* inactive */
14353806Smckusick 	{ &vop_reclaim_desc, nfs_reclaim },	/* reclaim */
14453554Sheideman 	{ &vop_lock_desc, nfs_lock },		/* lock */
14553806Smckusick 	{ &vop_unlock_desc, nfs_unlock },	/* unlock */
14653554Sheideman 	{ &vop_bmap_desc, spec_bmap },		/* bmap */
14753806Smckusick 	{ &vop_strategy_desc, spec_strategy },	/* strategy */
14853554Sheideman 	{ &vop_print_desc, nfs_print },		/* print */
14953806Smckusick 	{ &vop_islocked_desc, nfs_islocked },	/* islocked */
15060400Smckusick 	{ &vop_pathconf_desc, spec_pathconf },	/* pathconf */
15153806Smckusick 	{ &vop_advlock_desc, spec_advlock },	/* advlock */
15253806Smckusick 	{ &vop_blkatoff_desc, spec_blkatoff },	/* blkatoff */
15353806Smckusick 	{ &vop_valloc_desc, spec_valloc },	/* valloc */
15466079Shibler 	{ &vop_reallocblks_desc, spec_reallocblks },	/* reallocblks */
15553806Smckusick 	{ &vop_vfree_desc, spec_vfree },	/* vfree */
15653806Smckusick 	{ &vop_truncate_desc, spec_truncate },	/* truncate */
15753806Smckusick 	{ &vop_update_desc, nfs_update },	/* update */
15857809Smckusick 	{ &vop_bwrite_desc, vn_bwrite },
15953554Sheideman 	{ (struct vnodeop_desc*)NULL, (int(*)())NULL }
16038414Smckusick };
16153554Sheideman struct vnodeopv_desc spec_nfsv2nodeop_opv_desc =
16253554Sheideman 	{ &spec_nfsv2nodeop_p, spec_nfsv2nodeop_entries };
16338414Smckusick 
16453554Sheideman int (**fifo_nfsv2nodeop_p)();
16553554Sheideman struct vnodeopv_entry_desc fifo_nfsv2nodeop_entries[] = {
16653554Sheideman 	{ &vop_default_desc, vn_default_error },
16753806Smckusick 	{ &vop_lookup_desc, fifo_lookup },	/* lookup */
16853806Smckusick 	{ &vop_create_desc, fifo_create },	/* create */
16953806Smckusick 	{ &vop_mknod_desc, fifo_mknod },	/* mknod */
17053554Sheideman 	{ &vop_open_desc, fifo_open },		/* open */
17153806Smckusick 	{ &vop_close_desc, nfsfifo_close },	/* close */
17256364Smckusick 	{ &vop_access_desc, nfsspec_access },	/* access */
17353806Smckusick 	{ &vop_getattr_desc, nfs_getattr },	/* getattr */
17453806Smckusick 	{ &vop_setattr_desc, nfs_setattr },	/* setattr */
17553806Smckusick 	{ &vop_read_desc, nfsfifo_read },	/* read */
17653806Smckusick 	{ &vop_write_desc, nfsfifo_write },	/* write */
17767651Smckusick 	{ &vop_lease_desc, fifo_lease_check },	/* lease */
17853806Smckusick 	{ &vop_ioctl_desc, fifo_ioctl },	/* ioctl */
17953806Smckusick 	{ &vop_select_desc, fifo_select },	/* select */
18068418Smckusick 	{ &vop_revoke_desc, fifo_revoke },	/* revoke */
18153554Sheideman 	{ &vop_mmap_desc, fifo_mmap },		/* mmap */
18254451Smckusick 	{ &vop_fsync_desc, nfs_fsync },		/* fsync */
18353554Sheideman 	{ &vop_seek_desc, fifo_seek },		/* seek */
18453806Smckusick 	{ &vop_remove_desc, fifo_remove },	/* remove */
18553554Sheideman 	{ &vop_link_desc, fifo_link },		/* link */
18653806Smckusick 	{ &vop_rename_desc, fifo_rename },	/* rename */
18753806Smckusick 	{ &vop_mkdir_desc, fifo_mkdir },	/* mkdir */
18853806Smckusick 	{ &vop_rmdir_desc, fifo_rmdir },	/* rmdir */
18953806Smckusick 	{ &vop_symlink_desc, fifo_symlink },	/* symlink */
19053806Smckusick 	{ &vop_readdir_desc, fifo_readdir },	/* readdir */
19153806Smckusick 	{ &vop_readlink_desc, fifo_readlink },	/* readlink */
19253806Smckusick 	{ &vop_abortop_desc, fifo_abortop },	/* abortop */
19353806Smckusick 	{ &vop_inactive_desc, nfs_inactive },	/* inactive */
19453806Smckusick 	{ &vop_reclaim_desc, nfs_reclaim },	/* reclaim */
19553554Sheideman 	{ &vop_lock_desc, nfs_lock },		/* lock */
19653806Smckusick 	{ &vop_unlock_desc, nfs_unlock },	/* unlock */
19753554Sheideman 	{ &vop_bmap_desc, fifo_bmap },		/* bmap */
19853806Smckusick 	{ &vop_strategy_desc, fifo_badop },	/* strategy */
19953554Sheideman 	{ &vop_print_desc, nfs_print },		/* print */
20053806Smckusick 	{ &vop_islocked_desc, nfs_islocked },	/* islocked */
20160400Smckusick 	{ &vop_pathconf_desc, fifo_pathconf },	/* pathconf */
20253806Smckusick 	{ &vop_advlock_desc, fifo_advlock },	/* advlock */
20353806Smckusick 	{ &vop_blkatoff_desc, fifo_blkatoff },	/* blkatoff */
20453806Smckusick 	{ &vop_valloc_desc, fifo_valloc },	/* valloc */
20566079Shibler 	{ &vop_reallocblks_desc, fifo_reallocblks },	/* reallocblks */
20653806Smckusick 	{ &vop_vfree_desc, fifo_vfree },	/* vfree */
20753806Smckusick 	{ &vop_truncate_desc, fifo_truncate },	/* truncate */
20853806Smckusick 	{ &vop_update_desc, nfs_update },	/* update */
20957809Smckusick 	{ &vop_bwrite_desc, vn_bwrite },
21053554Sheideman 	{ (struct vnodeop_desc*)NULL, (int(*)())NULL }
21140294Smckusick };
21253554Sheideman struct vnodeopv_desc fifo_nfsv2nodeop_opv_desc =
21353554Sheideman 	{ &fifo_nfsv2nodeop_p, fifo_nfsv2nodeop_entries };
21440294Smckusick 
21556289Smckusick void nqnfs_clientlease();
21668653Smckusick int nfs_commit();
21756289Smckusick 
21848054Smckusick /*
21952196Smckusick  * Global variables
22048054Smckusick  */
22168653Smckusick extern u_long nfs_true, nfs_false;
22268653Smckusick extern struct nfsstats nfsstats;
22368653Smckusick extern nfstype nfsv3_type[9];
22441905Smckusick struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON];
22546988Smckusick int nfs_numasync = 0;
22654740Smckusick #define	DIRHDSIZ	(sizeof (struct dirent) - (MAXNAMLEN + 1))
22738414Smckusick 
22838414Smckusick /*
22938414Smckusick  * nfs null call from vfs.
23038414Smckusick  */
23152234Sheideman int
23252196Smckusick nfs_null(vp, cred, procp)
23338414Smckusick 	struct vnode *vp;
23438414Smckusick 	struct ucred *cred;
23552196Smckusick 	struct proc *procp;
23638414Smckusick {
23739488Smckusick 	caddr_t bpos, dpos;
23839488Smckusick 	int error = 0;
23939488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb;
24038414Smckusick 
24152196Smckusick 	nfsm_reqhead(vp, NFSPROC_NULL, 0);
24252196Smckusick 	nfsm_request(vp, NFSPROC_NULL, procp, cred);
24338414Smckusick 	nfsm_reqdone;
24438414Smckusick 	return (error);
24538414Smckusick }
24638414Smckusick 
24738414Smckusick /*
24838414Smckusick  * nfs access vnode op.
24968653Smckusick  * For nfs version 2, just return ok. File accesses may fail later.
25068653Smckusick  * For nfs version 3, use the access rpc to check accessibility. If file modes
25168653Smckusick  * are changed on the server, accesses might still fail later.
25238414Smckusick  */
25352234Sheideman int
25453806Smckusick nfs_access(ap)
25554668Smckusick 	struct vop_access_args /* {
25654668Smckusick 		struct vnode *a_vp;
25754668Smckusick 		int  a_mode;
25854668Smckusick 		struct ucred *a_cred;
25954668Smckusick 		struct proc *a_p;
26054668Smckusick 	} */ *ap;
26138414Smckusick {
26256364Smckusick 	register struct vnode *vp = ap->a_vp;
26356364Smckusick 	register u_long *tl;
26456364Smckusick 	register caddr_t cp;
26568653Smckusick 	register int t1, t2;
26668653Smckusick 	caddr_t bpos, dpos, cp2;
26768653Smckusick 	int error = 0, attrflag;
26856364Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
26968653Smckusick 	u_long mode, rmode;
27068653Smckusick 	int v3 = NFS_ISV3(vp);
27138414Smckusick 
27238414Smckusick 	/*
27368653Smckusick 	 * For nfs v3, do an access rpc, otherwise you are stuck emulating
27456708Smckusick 	 * ufs_access() locally using the vattr. This may not be correct,
27556708Smckusick 	 * since the server may apply other access criteria such as
27656708Smckusick 	 * client uid-->server uid mapping that we do not know about, but
27756708Smckusick 	 * this is better than just returning anything that is lying about
27856708Smckusick 	 * in the cache.
27938414Smckusick 	 */
28068653Smckusick 	if (v3) {
28168653Smckusick 		nfsstats.rpccnt[NFSPROC_ACCESS]++;
28268653Smckusick 		nfsm_reqhead(vp, NFSPROC_ACCESS, NFSX_FH(v3) + NFSX_UNSIGNED);
28368653Smckusick 		nfsm_fhtom(vp, v3);
28468653Smckusick 		nfsm_build(tl, u_long *, NFSX_UNSIGNED);
28556364Smckusick 		if (ap->a_mode & VREAD)
28668653Smckusick 			mode = NFSV3ACCESS_READ;
28756364Smckusick 		else
28868653Smckusick 			mode = 0;
28968653Smckusick 		if (vp->v_type == VDIR) {
29068653Smckusick 			if (ap->a_mode & VWRITE)
29168653Smckusick 				mode |= (NFSV3ACCESS_MODIFY | NFSV3ACCESS_EXTEND |
29268653Smckusick 					 NFSV3ACCESS_DELETE);
29368653Smckusick 			if (ap->a_mode & VEXEC)
29468653Smckusick 				mode |= NFSV3ACCESS_LOOKUP;
29568653Smckusick 		} else {
29668653Smckusick 			if (ap->a_mode & VWRITE)
29768653Smckusick 				mode |= (NFSV3ACCESS_MODIFY | NFSV3ACCESS_EXTEND);
29868653Smckusick 			if (ap->a_mode & VEXEC)
29968653Smckusick 				mode |= NFSV3ACCESS_EXECUTE;
30068653Smckusick 		}
30168653Smckusick 		*tl = txdr_unsigned(mode);
30268653Smckusick 		nfsm_request(vp, NFSPROC_ACCESS, ap->a_p, ap->a_cred);
30368653Smckusick 		nfsm_postop_attr(vp, attrflag);
30468653Smckusick 		if (!error) {
30568653Smckusick 			nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
30668653Smckusick 			rmode = fxdr_unsigned(u_long, *tl);
30768653Smckusick 			/*
30868653Smckusick 			 * The NFS V3 spec does not clarify whether or not
30968653Smckusick 			 * the returned access bits can be a superset of
31068653Smckusick 			 * the ones requested, so...
31168653Smckusick 			 */
31268653Smckusick 			if ((rmode & mode) != mode)
31368653Smckusick 				error = EACCES;
31468653Smckusick 		}
31556364Smckusick 		nfsm_reqdone;
31638884Smacklem 		return (error);
31756364Smckusick 	} else
31856708Smckusick 		return (nfsspec_access(ap));
31938414Smckusick }
32038414Smckusick 
32138414Smckusick /*
32238414Smckusick  * nfs open vnode op
32356289Smckusick  * Check to see if the type is ok
32452196Smckusick  * and that deletion is not in progress.
32556289Smckusick  * For paged in text files, you will need to flush the page cache
32656289Smckusick  * if consistency is lost.
32738414Smckusick  */
32839488Smckusick /* ARGSUSED */
32952234Sheideman int
33053806Smckusick nfs_open(ap)
33154668Smckusick 	struct vop_open_args /* {
33254668Smckusick 		struct vnode *a_vp;
33354668Smckusick 		int  a_mode;
33454668Smckusick 		struct ucred *a_cred;
33554668Smckusick 		struct proc *a_p;
33654668Smckusick 	} */ *ap;
33738414Smckusick {
33853806Smckusick 	register struct vnode *vp = ap->a_vp;
33956289Smckusick 	struct nfsnode *np = VTONFS(vp);
34056289Smckusick 	struct nfsmount *nmp = VFSTONFS(vp->v_mount);
34156289Smckusick 	struct vattr vattr;
34256289Smckusick 	int error;
34338414Smckusick 
34453806Smckusick 	if (vp->v_type != VREG && vp->v_type != VDIR && vp->v_type != VLNK)
34568653Smckusick { printf("open eacces vtyp=%d\n",vp->v_type);
34638414Smckusick 		return (EACCES);
34768653Smckusick }
34868653Smckusick 	/*
34968653Smckusick 	 * Get a valid lease. If cached data is stale, flush it.
35068653Smckusick 	 */
35168653Smckusick 	if (nmp->nm_flag & NFSMNT_NQNFS) {
35268653Smckusick 		if (NQNFS_CKINVALID(vp, np, ND_READ)) {
35356289Smckusick 		    do {
35468653Smckusick 			error = nqnfs_getlease(vp, ND_READ, ap->a_cred,
35568653Smckusick 			    ap->a_p);
35656289Smckusick 		    } while (error == NQNFS_EXPIRED);
35756289Smckusick 		    if (error)
35856289Smckusick 			return (error);
35959706Smckusick 		    if (np->n_lrev != np->n_brev ||
36059706Smckusick 			(np->n_flag & NQNFSNONCACHE)) {
36157791Smckusick 			if ((error = nfs_vinvalbuf(vp, V_SAVE, ap->a_cred,
36257791Smckusick 				ap->a_p, 1)) == EINTR)
36357791Smckusick 				return (error);
36456289Smckusick 			(void) vnode_pager_uncache(vp);
36556289Smckusick 			np->n_brev = np->n_lrev;
36656289Smckusick 		    }
36756289Smckusick 		}
36868653Smckusick 	} else {
36956289Smckusick 		if (np->n_flag & NMODIFIED) {
37057791Smckusick 			if ((error = nfs_vinvalbuf(vp, V_SAVE, ap->a_cred,
37157791Smckusick 				ap->a_p, 1)) == EINTR)
37257791Smckusick 				return (error);
37356289Smckusick 			(void) vnode_pager_uncache(vp);
37456289Smckusick 			np->n_attrstamp = 0;
37568653Smckusick 			if (vp->v_type == VDIR)
37668653Smckusick 				np->n_direofoffset = 0;
37768653Smckusick 			error = VOP_GETATTR(vp, &vattr, ap->a_cred, ap->a_p);
37868653Smckusick 			if (error)
37956289Smckusick 				return (error);
38056289Smckusick 			np->n_mtime = vattr.va_mtime.ts_sec;
38156289Smckusick 		} else {
38268653Smckusick 			error = VOP_GETATTR(vp, &vattr, ap->a_cred, ap->a_p);
38368653Smckusick 			if (error)
38456289Smckusick 				return (error);
38556289Smckusick 			if (np->n_mtime != vattr.va_mtime.ts_sec) {
38668653Smckusick 				if (vp->v_type == VDIR)
38768653Smckusick 					np->n_direofoffset = 0;
38857791Smckusick 				if ((error = nfs_vinvalbuf(vp, V_SAVE,
38957791Smckusick 					ap->a_cred, ap->a_p, 1)) == EINTR)
39057791Smckusick 					return (error);
39156289Smckusick 				(void) vnode_pager_uncache(vp);
39256289Smckusick 				np->n_mtime = vattr.va_mtime.ts_sec;
39356289Smckusick 			}
39456289Smckusick 		}
39568653Smckusick 	}
39668653Smckusick 	if ((nmp->nm_flag & NFSMNT_NQNFS) == 0)
39756289Smckusick 		np->n_attrstamp = 0; /* For Open/Close consistency */
39852196Smckusick 	return (0);
39938414Smckusick }
40038414Smckusick 
40138414Smckusick /*
40238414Smckusick  * nfs close vnode op
40368653Smckusick  * What an NFS client should do upon close after writing is a debatable issue.
40468653Smckusick  * Most NFS clients push delayed writes to the server upon close, basically for
40568653Smckusick  * two reasons:
40668653Smckusick  * 1 - So that any write errors may be reported back to the client process
40768653Smckusick  *     doing the close system call. By far the two most likely errors are
40868653Smckusick  *     NFSERR_NOSPC and NFSERR_DQUOT to indicate space allocation failure.
40968653Smckusick  * 2 - To put a worst case upper bound on cache inconsistency between
41068653Smckusick  *     multiple clients for the file.
41168653Smckusick  * There is also a consistency problem for Version 2 of the protocol w.r.t.
41268653Smckusick  * not being able to tell if other clients are writing a file concurrently,
41368653Smckusick  * since there is no way of knowing if the changed modify time in the reply
41468653Smckusick  * is only due to the write for this client.
41568653Smckusick  * (NFS Version 3 provides weak cache consistency data in the reply that
41668653Smckusick  *  should be sufficient to detect and handle this case.)
41768653Smckusick  *
41868653Smckusick  * The current code does the following:
41968653Smckusick  * for NFS Version 2 - play it safe and flush/invalidate all dirty buffers
42068653Smckusick  * for NFS Version 3 - flush dirty buffers to the server but don't invalidate
42168653Smckusick  *                     or commit them (this satisfies 1 and 2 except for the
42268653Smckusick  *                     case where the server crashes after this close but
42368653Smckusick  *                     before the commit RPC, which is felt to be "good
42468653Smckusick  *                     enough". Changing the last argument to nfs_flush() to
42568653Smckusick  *                     a 1 would force a commit operation, if it is felt a
42668653Smckusick  *                     commit is necessary now.
42768653Smckusick  * for NQNFS         - do nothing now, since 2 is dealt with via leases and
42868653Smckusick  *                     1 should be dealt with via an fsync() system call for
42968653Smckusick  *                     cases where write errors are important.
43038414Smckusick  */
43139488Smckusick /* ARGSUSED */
43252234Sheideman int
43353806Smckusick nfs_close(ap)
43454451Smckusick 	struct vop_close_args /* {
43554451Smckusick 		struct vnodeop_desc *a_desc;
43654451Smckusick 		struct vnode *a_vp;
43754451Smckusick 		int  a_fflag;
43854451Smckusick 		struct ucred *a_cred;
43954451Smckusick 		struct proc *a_p;
44054451Smckusick 	} */ *ap;
44138414Smckusick {
44253806Smckusick 	register struct vnode *vp = ap->a_vp;
44353806Smckusick 	register struct nfsnode *np = VTONFS(vp);
44439341Smckusick 	int error = 0;
44538414Smckusick 
44653806Smckusick 	if (vp->v_type == VREG) {
44753806Smckusick 	    if ((VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) == 0 &&
44853629Smckusick 		(np->n_flag & NMODIFIED)) {
44968653Smckusick 		if (NFS_ISV3(vp))
45068653Smckusick 		    error = nfs_flush(vp, ap->a_cred, MNT_WAIT, ap->a_p, 0);
45168653Smckusick 		else
45268653Smckusick 		    error = nfs_vinvalbuf(vp, V_SAVE, ap->a_cred, ap->a_p, 1);
45341905Smckusick 		np->n_attrstamp = 0;
45453629Smckusick 	    }
45553629Smckusick 	    if (np->n_flag & NWRITEERR) {
45653629Smckusick 		np->n_flag &= ~NWRITEERR;
45753629Smckusick 		error = np->n_error;
45853629Smckusick 	    }
45938884Smacklem 	}
46038414Smckusick 	return (error);
46138414Smckusick }
46238414Smckusick 
46338414Smckusick /*
46438414Smckusick  * nfs getattr call from vfs.
46538414Smckusick  */
46652234Sheideman int
46753805Smckusick nfs_getattr(ap)
46854668Smckusick 	struct vop_getattr_args /* {
46954668Smckusick 		struct vnode *a_vp;
47054668Smckusick 		struct vattr *a_vap;
47154668Smckusick 		struct ucred *a_cred;
47254668Smckusick 		struct proc *a_p;
47354668Smckusick 	} */ *ap;
47438414Smckusick {
47553805Smckusick 	register struct vnode *vp = ap->a_vp;
47653805Smckusick 	register struct nfsnode *np = VTONFS(vp);
47739488Smckusick 	register caddr_t cp;
47868653Smckusick 	register u_long *tl;
47968653Smckusick 	register int t1, t2;
48039488Smckusick 	caddr_t bpos, dpos;
48139488Smckusick 	int error = 0;
48239488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
48368653Smckusick 	int v3 = NFS_ISV3(vp);
48438414Smckusick 
48553805Smckusick 	/*
48653805Smckusick 	 * Update local times for special files.
48753805Smckusick 	 */
48856329Smckusick 	if (np->n_flag & (NACC | NUPD))
48953805Smckusick 		np->n_flag |= NCHG;
49053805Smckusick 	/*
49153805Smckusick 	 * First look in the cache.
49253805Smckusick 	 */
49353805Smckusick 	if (nfs_getattrcache(vp, ap->a_vap) == 0)
49438414Smckusick 		return (0);
49538414Smckusick 	nfsstats.rpccnt[NFSPROC_GETATTR]++;
49668653Smckusick 	nfsm_reqhead(vp, NFSPROC_GETATTR, NFSX_FH(v3));
49768653Smckusick 	nfsm_fhtom(vp, v3);
49853805Smckusick 	nfsm_request(vp, NFSPROC_GETATTR, ap->a_p, ap->a_cred);
49968653Smckusick 	if (!error)
50068653Smckusick 		nfsm_loadattr(vp, ap->a_vap);
50138414Smckusick 	nfsm_reqdone;
50238414Smckusick 	return (error);
50338414Smckusick }
50438414Smckusick 
50538414Smckusick /*
50638414Smckusick  * nfs setattr call.
50738414Smckusick  */
50852234Sheideman int
50953806Smckusick nfs_setattr(ap)
51054451Smckusick 	struct vop_setattr_args /* {
51154451Smckusick 		struct vnodeop_desc *a_desc;
51254451Smckusick 		struct vnode *a_vp;
51354451Smckusick 		struct vattr *a_vap;
51454451Smckusick 		struct ucred *a_cred;
51554451Smckusick 		struct proc *a_p;
51654451Smckusick 	} */ *ap;
51738414Smckusick {
51868653Smckusick 	register struct vnode *vp = ap->a_vp;
51968653Smckusick 	register struct nfsnode *np = VTONFS(vp);
52068653Smckusick 	register struct vattr *vap = ap->a_vap;
52168653Smckusick 	int error = 0;
52268653Smckusick 	u_quad_t tsize;
52368653Smckusick 
52468653Smckusick #ifndef nolint
52568653Smckusick 	tsize = (u_quad_t)0;
52668653Smckusick #endif
52768653Smckusick 	if (vap->va_size != VNOVAL) {
52868653Smckusick  		switch (vp->v_type) {
52968653Smckusick  		case VDIR:
53068653Smckusick  			return (EISDIR);
53168653Smckusick  		case VCHR:
53268653Smckusick  		case VBLK:
53368653Smckusick 			if (vap->va_mtime.ts_sec == VNOVAL &&
53468653Smckusick 			    vap->va_atime.ts_sec == VNOVAL &&
53568653Smckusick 			    vap->va_mode == (u_short)VNOVAL &&
53668653Smckusick 			    vap->va_uid == (uid_t)VNOVAL &&
53768653Smckusick 			    vap->va_gid == (gid_t)VNOVAL)
53868653Smckusick 				return (0);
53968653Smckusick  			vap->va_size = VNOVAL;
54068653Smckusick  			break;
54168653Smckusick  		default:
54268653Smckusick  			if (np->n_flag & NMODIFIED) {
54368653Smckusick  			    if (vap->va_size == 0)
54468653Smckusick  				error = nfs_vinvalbuf(vp, 0,
54568653Smckusick  					ap->a_cred, ap->a_p, 1);
54668653Smckusick  			    else
54768653Smckusick  				error = nfs_vinvalbuf(vp, V_SAVE,
54868653Smckusick  					ap->a_cred, ap->a_p, 1);
54968653Smckusick  			    if (error)
55068653Smckusick  				return (error);
55168653Smckusick  			}
55268653Smckusick  			tsize = np->n_size;
55368653Smckusick  			np->n_size = np->n_vattr.va_size = vap->va_size;
55468653Smckusick  			vnode_pager_setsize(vp, (u_long)np->n_size);
55568653Smckusick   		};
55668653Smckusick   	} else if ((vap->va_mtime.ts_sec != VNOVAL ||
55768653Smckusick 		vap->va_atime.ts_sec != VNOVAL) && (np->n_flag & NMODIFIED) &&
55868653Smckusick 		vp->v_type == VREG &&
55968653Smckusick   		(error = nfs_vinvalbuf(vp, V_SAVE, ap->a_cred,
56068653Smckusick 		 ap->a_p, 1)) == EINTR)
56168653Smckusick 		return (error);
56268653Smckusick 	error = nfs_setattrrpc(vp, vap, ap->a_cred, ap->a_p);
56368653Smckusick 	if (error) {
56468653Smckusick 		np->n_size = np->n_vattr.va_size = tsize;
56568653Smckusick 		vnode_pager_setsize(vp, (u_long)np->n_size);
56668653Smckusick 	}
56768653Smckusick 	return (error);
56868653Smckusick }
56968653Smckusick 
57068653Smckusick /*
57168653Smckusick  * Do an nfs setattr rpc.
57268653Smckusick  */
57368653Smckusick int
57468653Smckusick nfs_setattrrpc(vp, vap, cred, procp)
57568653Smckusick 	register struct vnode *vp;
57668653Smckusick 	register struct vattr *vap;
57768653Smckusick 	struct ucred *cred;
57868653Smckusick 	struct proc *procp;
57968653Smckusick {
58038884Smacklem 	register struct nfsv2_sattr *sp;
58139488Smckusick 	register caddr_t cp;
58268653Smckusick 	register long t1, t2;
58352196Smckusick 	caddr_t bpos, dpos, cp2;
58452196Smckusick 	u_long *tl;
58568653Smckusick 	int error = 0, wccflag = NFSV3_WCCRATTR;
58639488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
58768653Smckusick 	u_quad_t frev;
58868653Smckusick 	int v3 = NFS_ISV3(vp);
58938414Smckusick 
59068653Smckusick 	nfsstats.rpccnt[NFSPROC_SETATTR]++;
59168653Smckusick 	nfsm_reqhead(vp, NFSPROC_SETATTR, NFSX_FH(v3) + NFSX_SATTR(v3));
59268653Smckusick 	nfsm_fhtom(vp, v3);
59368653Smckusick 	if (v3) {
59468653Smckusick 		if (vap->va_mode != (u_short)VNOVAL) {
59568653Smckusick 			nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED);
59668653Smckusick 			*tl++ = nfs_true;
59768653Smckusick 			*tl = txdr_unsigned(vap->va_mode);
59868653Smckusick 		} else {
59968653Smckusick 			nfsm_build(tl, u_long *, NFSX_UNSIGNED);
60068653Smckusick 			*tl = nfs_false;
60168653Smckusick 		}
60268653Smckusick 		if (vap->va_uid != (uid_t)VNOVAL) {
60368653Smckusick 			nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED);
60468653Smckusick 			*tl++ = nfs_true;
60568653Smckusick 			*tl = txdr_unsigned(vap->va_uid);
60668653Smckusick 		} else {
60768653Smckusick 			nfsm_build(tl, u_long *, NFSX_UNSIGNED);
60868653Smckusick 			*tl = nfs_false;
60968653Smckusick 		}
61068653Smckusick 		if (vap->va_gid != (gid_t)VNOVAL) {
61168653Smckusick 			nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED);
61268653Smckusick 			*tl++ = nfs_true;
61368653Smckusick 			*tl = txdr_unsigned(vap->va_gid);
61468653Smckusick 		} else {
61568653Smckusick 			nfsm_build(tl, u_long *, NFSX_UNSIGNED);
61668653Smckusick 			*tl = nfs_false;
61768653Smckusick 		}
61857791Smckusick 		if (vap->va_size != VNOVAL) {
61968653Smckusick 			nfsm_build(tl, u_long *, 3 * NFSX_UNSIGNED);
62068653Smckusick 			*tl++ = nfs_true;
62168653Smckusick 			txdr_hyper(&vap->va_size, tl);
62268653Smckusick 		} else {
62368653Smckusick 			nfsm_build(tl, u_long *, NFSX_UNSIGNED);
62468653Smckusick 			*tl = nfs_false;
62568653Smckusick 		}
62668653Smckusick 		if (vap->va_atime.ts_sec != VNOVAL) {
62768653Smckusick 			if (vap->va_atime.ts_sec != time.tv_sec) {
62868653Smckusick 				nfsm_build(tl, u_long *, 3 * NFSX_UNSIGNED);
62968653Smckusick 				*tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT);
63068653Smckusick 				txdr_nfsv3time(&vap->va_atime, tl);
63168653Smckusick 			} else {
63268653Smckusick 				nfsm_build(tl, u_long *, NFSX_UNSIGNED);
63368653Smckusick 				*tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER);
63457791Smckusick 			}
63568653Smckusick 		} else {
63668653Smckusick 			nfsm_build(tl, u_long *, NFSX_UNSIGNED);
63768653Smckusick 			*tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE);
63868653Smckusick 		}
63968653Smckusick 		if (vap->va_mtime.ts_sec != VNOVAL) {
64068653Smckusick 			if (vap->va_mtime.ts_sec != time.tv_sec) {
64168653Smckusick 				nfsm_build(tl, u_long *, 3 * NFSX_UNSIGNED);
64268653Smckusick 				*tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT);
64368653Smckusick 				txdr_nfsv3time(&vap->va_atime, tl);
64468653Smckusick 			} else {
64568653Smckusick 				nfsm_build(tl, u_long *, NFSX_UNSIGNED);
64668653Smckusick 				*tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER);
64768653Smckusick 			}
64868653Smckusick 		} else {
64968653Smckusick 			nfsm_build(tl, u_long *, NFSX_UNSIGNED);
65068653Smckusick 			*tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE);
65168653Smckusick 		}
65268653Smckusick 		nfsm_build(tl, u_long *, NFSX_UNSIGNED);
65368653Smckusick 		*tl = nfs_false;
65456289Smckusick 	} else {
65568653Smckusick 		nfsm_build(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
65668653Smckusick 		if (vap->va_mode == (u_short)VNOVAL)
65768653Smckusick 			sp->sa_mode = VNOVAL;
65868653Smckusick 		else
65968653Smckusick 			sp->sa_mode = vtonfsv2_mode(vp->v_type, vap->va_mode);
66068653Smckusick 		if (vap->va_uid == (uid_t)VNOVAL)
66168653Smckusick 			sp->sa_uid = VNOVAL;
66268653Smckusick 		else
66368653Smckusick 			sp->sa_uid = txdr_unsigned(vap->va_uid);
66468653Smckusick 		if (vap->va_gid == (gid_t)VNOVAL)
66568653Smckusick 			sp->sa_gid = VNOVAL;
66668653Smckusick 		else
66768653Smckusick 			sp->sa_gid = txdr_unsigned(vap->va_gid);
66868653Smckusick 		sp->sa_size = txdr_unsigned(vap->va_size);
66968653Smckusick 		txdr_nfsv2time(&vap->va_atime, &sp->sa_atime);
67068653Smckusick 		txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime);
67156289Smckusick 	}
67268653Smckusick 	nfsm_request(vp, NFSPROC_SETATTR, procp, cred);
67368653Smckusick 	if (v3) {
67468653Smckusick 		nfsm_wcc_data(vp, wccflag);
67568653Smckusick 	} else
67668653Smckusick 		nfsm_loadattr(vp, (struct vattr *)0);
67738414Smckusick 	nfsm_reqdone;
67838414Smckusick 	return (error);
67938414Smckusick }
68038414Smckusick 
68138414Smckusick /*
68238414Smckusick  * nfs lookup call, one step at a time...
68338414Smckusick  * First look in cache
68438414Smckusick  * If not found, unlock the directory nfsnode and do the rpc
68538414Smckusick  */
68652234Sheideman int
68753806Smckusick nfs_lookup(ap)
68854451Smckusick 	struct vop_lookup_args /* {
68954451Smckusick 		struct vnodeop_desc *a_desc;
69054451Smckusick 		struct vnode *a_dvp;
69154451Smckusick 		struct vnode **a_vpp;
69254451Smckusick 		struct componentname *a_cnp;
69354451Smckusick 	} */ *ap;
69438414Smckusick {
69553806Smckusick 	register struct componentname *cnp = ap->a_cnp;
69653806Smckusick 	register struct vnode *dvp = ap->a_dvp;
69754668Smckusick 	register struct vnode **vpp = ap->a_vpp;
69855184Smckusick 	register int flags = cnp->cn_flags;
699*69424Smckusick 	register struct proc *p = cnp->cn_proc;
70068653Smckusick 	register struct vnode *newvp;
70148054Smckusick 	register u_long *tl;
70239488Smckusick 	register caddr_t cp;
70339488Smckusick 	register long t1, t2;
70452196Smckusick 	struct nfsmount *nmp;
70539488Smckusick 	caddr_t bpos, dpos, cp2;
70639488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
70738414Smckusick 	long len;
70868653Smckusick 	nfsfh_t *fhp;
70938414Smckusick 	struct nfsnode *np;
71068653Smckusick 	int lockparent, wantparent, error = 0, attrflag, fhsize;
71168653Smckusick 	int v3 = NFS_ISV3(dvp);
71238414Smckusick 
71368653Smckusick 	*vpp = NULLVP;
71453806Smckusick 	if (dvp->v_type != VDIR)
71538414Smckusick 		return (ENOTDIR);
71655184Smckusick 	lockparent = flags & LOCKPARENT;
71755184Smckusick 	wantparent = flags & (LOCKPARENT|WANTPARENT);
71853806Smckusick 	nmp = VFSTONFS(dvp->v_mount);
71953806Smckusick 	np = VTONFS(dvp);
72054668Smckusick 	if ((error = cache_lookup(dvp, vpp, cnp)) && error != ENOENT) {
72138884Smacklem 		struct vattr vattr;
72238884Smacklem 		int vpid;
72338884Smacklem 
72468653Smckusick 		newvp = *vpp;
72568653Smckusick 		vpid = newvp->v_id;
72638414Smckusick 		/*
72738884Smacklem 		 * See the comment starting `Step through' in ufs/ufs_lookup.c
72838884Smacklem 		 * for an explanation of the locking protocol
72938414Smckusick 		 */
73068653Smckusick 		if (dvp == newvp) {
73168653Smckusick 			VREF(newvp);
73239441Smckusick 			error = 0;
73352196Smckusick 		} else
734*69424Smckusick 			error = vget(newvp, LK_EXCLUSIVE, p);
73539441Smckusick 		if (!error) {
73668653Smckusick 			if (vpid == newvp->v_id) {
73768653Smckusick 			   if (!VOP_GETATTR(newvp, &vattr, cnp->cn_cred, cnp->cn_proc)
73868653Smckusick 			    && vattr.va_ctime.ts_sec == VTONFS(newvp)->n_ctime) {
73939441Smckusick 				nfsstats.lookupcache_hits++;
74053806Smckusick 				if (cnp->cn_nameiop != LOOKUP &&
74155184Smckusick 				    (flags & ISLASTCN))
74253806Smckusick 					cnp->cn_flags |= SAVENAME;
74339441Smckusick 				return (0);
74440251Smckusick 			   }
74568653Smckusick 			   cache_purge(newvp);
74639441Smckusick 			}
74768653Smckusick 			vrele(newvp);
74838884Smacklem 		}
74954668Smckusick 		*vpp = NULLVP;
75052196Smckusick 	}
75139341Smckusick 	error = 0;
75268653Smckusick 	newvp = NULLVP;
75338414Smckusick 	nfsstats.lookupcache_misses++;
75438414Smckusick 	nfsstats.rpccnt[NFSPROC_LOOKUP]++;
75553806Smckusick 	len = cnp->cn_namelen;
75668653Smckusick 	nfsm_reqhead(dvp, NFSPROC_LOOKUP,
75768653Smckusick 		NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(len));
75868653Smckusick 	nfsm_fhtom(dvp, v3);
75953806Smckusick 	nfsm_strtom(cnp->cn_nameptr, len, NFS_MAXNAMLEN);
76053806Smckusick 	nfsm_request(dvp, NFSPROC_LOOKUP, cnp->cn_proc, cnp->cn_cred);
76138414Smckusick 	if (error) {
76268653Smckusick 		nfsm_postop_attr(dvp, attrflag);
76368653Smckusick 		m_freem(mrep);
76468653Smckusick 		goto nfsmout;
76538414Smckusick 	}
76668653Smckusick 	nfsm_getfh(fhp, fhsize, v3);
76738414Smckusick 
76838414Smckusick 	/*
76952196Smckusick 	 * Handle RENAME case...
77038414Smckusick 	 */
77155184Smckusick 	if (cnp->cn_nameiop == RENAME && wantparent && (flags & ISLASTCN)) {
77268653Smckusick 		if (NFS_CMPFH(np, fhp, fhsize)) {
77338414Smckusick 			m_freem(mrep);
77438414Smckusick 			return (EISDIR);
77538414Smckusick 		}
77668653Smckusick 		if (error = nfs_nget(dvp->v_mount, fhp, fhsize, &np)) {
77738414Smckusick 			m_freem(mrep);
77838414Smckusick 			return (error);
77938414Smckusick 		}
78038414Smckusick 		newvp = NFSTOV(np);
78168653Smckusick 		if (v3) {
78268653Smckusick 			nfsm_postop_attr(newvp, attrflag);
78368653Smckusick 			nfsm_postop_attr(dvp, attrflag);
78468653Smckusick 		} else
78568653Smckusick 			nfsm_loadattr(newvp, (struct vattr *)0);
78654668Smckusick 		*vpp = newvp;
78745037Smckusick 		m_freem(mrep);
78853806Smckusick 		cnp->cn_flags |= SAVENAME;
78938414Smckusick 		return (0);
79038414Smckusick 	}
79138414Smckusick 
79268653Smckusick 	if (NFS_CMPFH(np, fhp, fhsize)) {
79353806Smckusick 		VREF(dvp);
79453806Smckusick 		newvp = dvp;
79538414Smckusick 	} else {
79668653Smckusick 		if (error = nfs_nget(dvp->v_mount, fhp, fhsize, &np)) {
79738414Smckusick 			m_freem(mrep);
79838414Smckusick 			return (error);
79938414Smckusick 		}
80038414Smckusick 		newvp = NFSTOV(np);
80138414Smckusick 	}
80268653Smckusick 	if (v3) {
80368653Smckusick 		nfsm_postop_attr(newvp, attrflag);
80468653Smckusick 		nfsm_postop_attr(dvp, attrflag);
80568653Smckusick 	} else
80668653Smckusick 		nfsm_loadattr(newvp, (struct vattr *)0);
80755184Smckusick 	if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN))
80853806Smckusick 		cnp->cn_flags |= SAVENAME;
80955184Smckusick 	if ((cnp->cn_flags & MAKEENTRY) &&
81055184Smckusick 	    (cnp->cn_nameiop != DELETE || !(flags & ISLASTCN))) {
81168653Smckusick 		np->n_ctime = np->n_vattr.va_ctime.ts_sec;
81268653Smckusick 		cache_enter(dvp, newvp, cnp);
81340251Smckusick 	}
81468653Smckusick 	*vpp = newvp;
81568653Smckusick 	nfsm_reqdone;
81668653Smckusick 	if (error) {
81768653Smckusick 		if (newvp != NULLVP)
81868653Smckusick 			vrele(newvp);
81968653Smckusick 		if ((cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME) &&
82068653Smckusick 		    (flags & ISLASTCN) && error == ENOENT)
82168653Smckusick 			error = EJUSTRETURN;
82268653Smckusick 		if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN))
82368653Smckusick 			cnp->cn_flags |= SAVENAME;
82468653Smckusick 	}
82568653Smckusick 	return (error);
82638414Smckusick }
82738414Smckusick 
82838414Smckusick /*
82941905Smckusick  * nfs read call.
83041905Smckusick  * Just call nfs_bioread() to do the work.
83141905Smckusick  */
83252234Sheideman int
83353806Smckusick nfs_read(ap)
83454668Smckusick 	struct vop_read_args /* {
83554668Smckusick 		struct vnode *a_vp;
83654668Smckusick 		struct uio *a_uio;
83754668Smckusick 		int  a_ioflag;
83854668Smckusick 		struct ucred *a_cred;
83954668Smckusick 	} */ *ap;
84041905Smckusick {
84153806Smckusick 	register struct vnode *vp = ap->a_vp;
84253806Smckusick 
84353806Smckusick 	if (vp->v_type != VREG)
84441905Smckusick 		return (EPERM);
84553806Smckusick 	return (nfs_bioread(vp, ap->a_uio, ap->a_ioflag, ap->a_cred));
84641905Smckusick }
84741905Smckusick 
84841905Smckusick /*
84938414Smckusick  * nfs readlink call
85038414Smckusick  */
85152234Sheideman int
85253806Smckusick nfs_readlink(ap)
85354668Smckusick 	struct vop_readlink_args /* {
85454668Smckusick 		struct vnode *a_vp;
85554668Smckusick 		struct uio *a_uio;
85654668Smckusick 		struct ucred *a_cred;
85754668Smckusick 	} */ *ap;
85841905Smckusick {
85953806Smckusick 	register struct vnode *vp = ap->a_vp;
86053806Smckusick 
86153806Smckusick 	if (vp->v_type != VLNK)
86241905Smckusick 		return (EPERM);
86353806Smckusick 	return (nfs_bioread(vp, ap->a_uio, 0, ap->a_cred));
86441905Smckusick }
86541905Smckusick 
86641905Smckusick /*
86741905Smckusick  * Do a readlink rpc.
86841905Smckusick  * Called by nfs_doio() from below the buffer cache.
86941905Smckusick  */
87052234Sheideman int
87148054Smckusick nfs_readlinkrpc(vp, uiop, cred)
87239488Smckusick 	register struct vnode *vp;
87338414Smckusick 	struct uio *uiop;
87438414Smckusick 	struct ucred *cred;
87538414Smckusick {
87648054Smckusick 	register u_long *tl;
87739488Smckusick 	register caddr_t cp;
87868653Smckusick 	register long t1, t2;
87939488Smckusick 	caddr_t bpos, dpos, cp2;
88068653Smckusick 	int error = 0, len, attrflag;
88139488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
88268653Smckusick 	int v3 = NFS_ISV3(vp);
88338414Smckusick 
88438414Smckusick 	nfsstats.rpccnt[NFSPROC_READLINK]++;
88568653Smckusick 	nfsm_reqhead(vp, NFSPROC_READLINK, NFSX_FH(v3));
88668653Smckusick 	nfsm_fhtom(vp, v3);
88752196Smckusick 	nfsm_request(vp, NFSPROC_READLINK, uiop->uio_procp, cred);
88868653Smckusick 	if (v3)
88968653Smckusick 		nfsm_postop_attr(vp, attrflag);
89068653Smckusick 	if (!error) {
89168653Smckusick 		nfsm_strsiz(len, NFS_MAXPATHLEN);
89268653Smckusick 		nfsm_mtouio(uiop, len);
89368653Smckusick 	}
89438414Smckusick 	nfsm_reqdone;
89538414Smckusick 	return (error);
89638414Smckusick }
89738414Smckusick 
89838414Smckusick /*
89941905Smckusick  * nfs read rpc call
90041905Smckusick  * Ditto above
90138414Smckusick  */
90252234Sheideman int
90348054Smckusick nfs_readrpc(vp, uiop, cred)
90439488Smckusick 	register struct vnode *vp;
90538414Smckusick 	struct uio *uiop;
90638414Smckusick 	struct ucred *cred;
90738414Smckusick {
90848054Smckusick 	register u_long *tl;
90939488Smckusick 	register caddr_t cp;
91068653Smckusick 	register long t1, t2;
91139488Smckusick 	caddr_t bpos, dpos, cp2;
91239488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
91338414Smckusick 	struct nfsmount *nmp;
91468653Smckusick 	int error = 0, len, retlen, tsiz, eof, attrflag;
91568653Smckusick 	int v3 = NFS_ISV3(vp);
91638414Smckusick 
91768653Smckusick #ifndef nolint
91868653Smckusick 	eof = 0;
91968653Smckusick #endif
92041398Smckusick 	nmp = VFSTONFS(vp->v_mount);
92138414Smckusick 	tsiz = uiop->uio_resid;
92268653Smckusick 	if (uiop->uio_offset + tsiz > 0xffffffff && !v3)
92356289Smckusick 		return (EFBIG);
92438414Smckusick 	while (tsiz > 0) {
92538414Smckusick 		nfsstats.rpccnt[NFSPROC_READ]++;
92638414Smckusick 		len = (tsiz > nmp->nm_rsize) ? nmp->nm_rsize : tsiz;
92768653Smckusick 		nfsm_reqhead(vp, NFSPROC_READ, NFSX_FH(v3) + NFSX_UNSIGNED * 3);
92868653Smckusick 		nfsm_fhtom(vp, v3);
92968653Smckusick 		nfsm_build(tl, u_long *, NFSX_UNSIGNED * 3);
93068653Smckusick 		if (v3) {
93156289Smckusick 			txdr_hyper(&uiop->uio_offset, tl);
93256289Smckusick 			*(tl + 2) = txdr_unsigned(len);
93356289Smckusick 		} else {
93456289Smckusick 			*tl++ = txdr_unsigned(uiop->uio_offset);
93556289Smckusick 			*tl++ = txdr_unsigned(len);
93656289Smckusick 			*tl = 0;
93756289Smckusick 		}
93852196Smckusick 		nfsm_request(vp, NFSPROC_READ, uiop->uio_procp, cred);
93968653Smckusick 		if (v3) {
94068653Smckusick 			nfsm_postop_attr(vp, attrflag);
94168653Smckusick 			if (error) {
94268653Smckusick 				m_freem(mrep);
94368653Smckusick 				goto nfsmout;
94468653Smckusick 			}
94568653Smckusick 			nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
94668653Smckusick 			eof = fxdr_unsigned(int, *(tl + 1));
94768653Smckusick 		} else
94868653Smckusick 			nfsm_loadattr(vp, (struct vattr *)0);
94938414Smckusick 		nfsm_strsiz(retlen, nmp->nm_rsize);
95038414Smckusick 		nfsm_mtouio(uiop, retlen);
95138414Smckusick 		m_freem(mrep);
95268653Smckusick 		tsiz -= retlen;
95368653Smckusick 		if (v3) {
95468653Smckusick 			if (eof || retlen == 0)
95568653Smckusick 				tsiz = 0;
95668653Smckusick 		} else if (retlen < len)
95738414Smckusick 			tsiz = 0;
95838414Smckusick 	}
95938414Smckusick nfsmout:
96038414Smckusick 	return (error);
96138414Smckusick }
96238414Smckusick 
96338414Smckusick /*
96438414Smckusick  * nfs write call
96538414Smckusick  */
96652234Sheideman int
96768653Smckusick nfs_writerpc(vp, uiop, cred, iomode, must_commit)
96839488Smckusick 	register struct vnode *vp;
96968653Smckusick 	register struct uio *uiop;
97038414Smckusick 	struct ucred *cred;
97168653Smckusick 	int *iomode, *must_commit;
97238414Smckusick {
97348054Smckusick 	register u_long *tl;
97439488Smckusick 	register caddr_t cp;
97568653Smckusick 	register int t1, t2, backup;
97652196Smckusick 	caddr_t bpos, dpos, cp2;
97739488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
97868653Smckusick 	struct nfsmount *nmp = VFSTONFS(vp->v_mount);
97952196Smckusick 	struct nfsnode *np = VTONFS(vp);
98052196Smckusick 	u_quad_t frev;
98168653Smckusick 	int error = 0, len, tsiz, wccflag = NFSV3_WCCRATTR, rlen, commit;
98268653Smckusick 	int v3 = NFS_ISV3(vp), committed = NFSV3WRITE_FILESYNC;
98338414Smckusick 
98468653Smckusick #ifndef DIAGNOSTIC
98568653Smckusick 	if (uiop->uio_iovcnt != 1)
98668653Smckusick 		panic("nfs: writerpc iovcnt > 1");
98768653Smckusick #endif
98868653Smckusick 	*must_commit = 0;
98938414Smckusick 	tsiz = uiop->uio_resid;
99068653Smckusick 	if (uiop->uio_offset + tsiz > 0xffffffff && !v3)
99156289Smckusick 		return (EFBIG);
99238414Smckusick 	while (tsiz > 0) {
99338414Smckusick 		nfsstats.rpccnt[NFSPROC_WRITE]++;
99438414Smckusick 		len = (tsiz > nmp->nm_wsize) ? nmp->nm_wsize : tsiz;
99552196Smckusick 		nfsm_reqhead(vp, NFSPROC_WRITE,
99668653Smckusick 			NFSX_FH(v3) + 5 * NFSX_UNSIGNED + nfsm_rndup(len));
99768653Smckusick 		nfsm_fhtom(vp, v3);
99868653Smckusick 		if (v3) {
99968653Smckusick 			nfsm_build(tl, u_long *, 5 * NFSX_UNSIGNED);
100056289Smckusick 			txdr_hyper(&uiop->uio_offset, tl);
100156289Smckusick 			tl += 2;
100268653Smckusick 			*tl++ = txdr_unsigned(len);
100368653Smckusick 			*tl++ = txdr_unsigned(*iomode);
100456289Smckusick 		} else {
100568653Smckusick 			nfsm_build(tl, u_long *, 4 * NFSX_UNSIGNED);
100656289Smckusick 			*++tl = txdr_unsigned(uiop->uio_offset);
100756289Smckusick 			tl += 2;
100856289Smckusick 		}
100956289Smckusick 		*tl = txdr_unsigned(len);
101038414Smckusick 		nfsm_uiotom(uiop, len);
101152196Smckusick 		nfsm_request(vp, NFSPROC_WRITE, uiop->uio_procp, cred);
101268653Smckusick 		if (v3) {
101368653Smckusick 			wccflag = NFSV3_WCCCHK;
101468653Smckusick 			nfsm_wcc_data(vp, wccflag);
101568653Smckusick 			if (!error) {
101668653Smckusick 				nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED +
101768653Smckusick 					NFSX_V3WRITEVERF);
101868653Smckusick 				rlen = fxdr_unsigned(int, *tl++);
101968653Smckusick 				if (rlen == 0) {
102068653Smckusick 					error = NFSERR_IO;
102168653Smckusick 					break;
102268653Smckusick 				} else if (rlen < len) {
102368653Smckusick 					backup = len - rlen;
102468653Smckusick 					uiop->uio_iov->iov_base -= backup;
102568653Smckusick 					uiop->uio_iov->iov_len += backup;
102668653Smckusick 					uiop->uio_offset -= backup;
102768653Smckusick 					uiop->uio_resid += backup;
102868653Smckusick 					len = rlen;
102968653Smckusick 				}
103068653Smckusick 				commit = fxdr_unsigned(int, *tl++);
103168653Smckusick 
103268653Smckusick 				/*
103368653Smckusick 				 * Return the lowest committment level
103468653Smckusick 				 * obtained by any of the RPCs.
103568653Smckusick 				 */
103668653Smckusick 				if (committed == NFSV3WRITE_FILESYNC)
103768653Smckusick 					committed = commit;
103868653Smckusick 				else if (committed == NFSV3WRITE_DATASYNC &&
103968653Smckusick 					commit == NFSV3WRITE_UNSTABLE)
104068653Smckusick 					committed = commit;
104168653Smckusick 				if ((nmp->nm_flag & NFSMNT_HASWRITEVERF) == 0) {
104268653Smckusick 				    bcopy((caddr_t)tl, (caddr_t)nmp->nm_verf,
104368653Smckusick 					NFSX_V3WRITEVERF);
104468653Smckusick 				    nmp->nm_flag |= NFSMNT_HASWRITEVERF;
104568653Smckusick 				} else if (bcmp((caddr_t)tl,
104668653Smckusick 				    (caddr_t)nmp->nm_verf, NFSX_V3WRITEVERF)) {
104768653Smckusick 				    *must_commit = 1;
104868653Smckusick 				    bcopy((caddr_t)tl, (caddr_t)nmp->nm_verf,
104968653Smckusick 					NFSX_V3WRITEVERF);
105068653Smckusick 				}
105168653Smckusick 			}
105268653Smckusick 		} else
105368653Smckusick 		    nfsm_loadattr(vp, (struct vattr *)0);
105468653Smckusick 		if (wccflag)
105568653Smckusick 		    VTONFS(vp)->n_mtime = VTONFS(vp)->n_vattr.va_mtime.ts_sec;
105638414Smckusick 		m_freem(mrep);
105738414Smckusick 		tsiz -= len;
105838414Smckusick 	}
105938414Smckusick nfsmout:
106068653Smckusick 	*iomode = committed;
106152196Smckusick 	if (error)
106252196Smckusick 		uiop->uio_resid = tsiz;
106338414Smckusick 	return (error);
106438414Smckusick }
106538414Smckusick 
106638414Smckusick /*
106768653Smckusick  * nfs mknod rpc
106868653Smckusick  * For NFS v2 this is a kludge. Use a create rpc but with the IFMT bits of the
106968653Smckusick  * mode set to specify the file type and the size field for rdev.
107039459Smckusick  */
107152234Sheideman int
107268653Smckusick nfs_mknodrpc(dvp, vpp, cnp, vap)
107368653Smckusick 	register struct vnode *dvp;
107468653Smckusick 	register struct vnode **vpp;
107568653Smckusick 	register struct componentname *cnp;
107668653Smckusick 	register struct vattr *vap;
107739459Smckusick {
107842246Smckusick 	register struct nfsv2_sattr *sp;
107968653Smckusick 	register struct nfsv3_sattr *sp3;
108048054Smckusick 	register u_long *tl;
108142246Smckusick 	register caddr_t cp;
108256289Smckusick 	register long t1, t2;
108368653Smckusick 	struct vnode *newvp = (struct vnode *)0;
108468653Smckusick 	struct nfsnode *np;
108559116Smckusick 	struct vattr vattr;
108656289Smckusick 	char *cp2;
108742246Smckusick 	caddr_t bpos, dpos;
108868653Smckusick 	int error = 0, wccflag = NFSV3_WCCRATTR, gotvp = 0;
108942246Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
109042246Smckusick 	u_long rdev;
109168653Smckusick 	int v3 = NFS_ISV3(dvp);
109239459Smckusick 
109353806Smckusick 	if (vap->va_type == VCHR || vap->va_type == VBLK)
109453806Smckusick 		rdev = txdr_unsigned(vap->va_rdev);
109568653Smckusick 	else if (vap->va_type == VFIFO || vap->va_type == VSOCK)
109642246Smckusick 		rdev = 0xffffffff;
109742246Smckusick 	else {
109853806Smckusick 		VOP_ABORTOP(dvp, cnp);
109953806Smckusick 		vput(dvp);
110042246Smckusick 		return (EOPNOTSUPP);
110142246Smckusick 	}
110259116Smckusick 	if (error = VOP_GETATTR(dvp, &vattr, cnp->cn_cred, cnp->cn_proc)) {
110359116Smckusick 		VOP_ABORTOP(dvp, cnp);
110459116Smckusick 		vput(dvp);
110559116Smckusick 		return (error);
110659116Smckusick 	}
110768653Smckusick 	nfsstats.rpccnt[NFSPROC_MKNOD]++;
110868653Smckusick 	nfsm_reqhead(dvp, NFSPROC_MKNOD, NFSX_FH(v3) + 4 * NFSX_UNSIGNED +
110968653Smckusick 		+ nfsm_rndup(cnp->cn_namelen) + NFSX_SATTR(v3));
111068653Smckusick 	nfsm_fhtom(dvp, v3);
111153806Smckusick 	nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
111268653Smckusick 	if (v3) {
111368653Smckusick 		nfsm_build(tl, u_long *, NFSX_UNSIGNED + NFSX_V3SRVSATTR);
111468653Smckusick 		*tl++ = vtonfsv3_type(vap->va_type);
111568653Smckusick 		sp3 = (struct nfsv3_sattr *)tl;
111668653Smckusick 		nfsm_v3sattr(sp3, vap, cnp->cn_cred->cr_uid, vattr.va_gid);
111768653Smckusick 		if (vap->va_type == VCHR || vap->va_type == VBLK) {
111868653Smckusick 			nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED);
111968653Smckusick 			*tl++ = txdr_unsigned(major(vap->va_rdev));
112068653Smckusick 			*tl = txdr_unsigned(minor(vap->va_rdev));
112168653Smckusick 		}
112256289Smckusick 	} else {
112368653Smckusick 		nfsm_build(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
112468653Smckusick 		sp->sa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode);
112568653Smckusick 		sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid);
112668653Smckusick 		sp->sa_gid = txdr_unsigned(vattr.va_gid);
112768653Smckusick 		sp->sa_size = rdev;
112868653Smckusick 		txdr_nfsv2time(&vap->va_atime, &sp->sa_atime);
112968653Smckusick 		txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime);
113056289Smckusick 	}
113168653Smckusick 	nfsm_request(dvp, NFSPROC_MKNOD, cnp->cn_proc, cnp->cn_cred);
113268653Smckusick 	if (!error) {
113368653Smckusick 		nfsm_mtofh(dvp, newvp, v3, gotvp);
113468653Smckusick 		if (!gotvp) {
113568653Smckusick 			if (newvp) {
113668653Smckusick 				vrele(newvp);
113768653Smckusick 				newvp = (struct vnode *)0;
113868653Smckusick 			}
113968653Smckusick 			error = nfs_lookitup(dvp, cnp->cn_nameptr,
114068653Smckusick 			    cnp->cn_namelen, cnp->cn_cred, cnp->cn_proc, &np);
114168653Smckusick 			if (!error)
114268653Smckusick 				newvp = NFSTOV(np);
114368653Smckusick 		}
114468653Smckusick 	}
114568653Smckusick 	if (v3)
114668653Smckusick 		nfsm_wcc_data(dvp, wccflag);
114742246Smckusick 	nfsm_reqdone;
114868653Smckusick 	if (error) {
114968653Smckusick 		if (newvp)
115068653Smckusick 			vrele(newvp);
115168653Smckusick 	} else {
115268653Smckusick 		if (cnp->cn_flags & MAKEENTRY)
115368653Smckusick 			cache_enter(dvp, newvp, cnp);
115468653Smckusick 		*vpp = newvp;
115568653Smckusick 	}
115653806Smckusick 	FREE(cnp->cn_pnbuf, M_NAMEI);
115753806Smckusick 	VTONFS(dvp)->n_flag |= NMODIFIED;
115868653Smckusick 	if (!wccflag)
115968653Smckusick 		VTONFS(dvp)->n_attrstamp = 0;
116053806Smckusick 	vrele(dvp);
116142246Smckusick 	return (error);
116239459Smckusick }
116339459Smckusick 
116439459Smckusick /*
116568653Smckusick  * nfs mknod vop
116668653Smckusick  * just call nfs_mknodrpc() to do the work.
116768653Smckusick  */
116868653Smckusick /* ARGSUSED */
116968653Smckusick int
117068653Smckusick nfs_mknod(ap)
117168653Smckusick 	struct vop_mknod_args /* {
117268653Smckusick 		struct vnode *a_dvp;
117368653Smckusick 		struct vnode **a_vpp;
117468653Smckusick 		struct componentname *a_cnp;
117568653Smckusick 		struct vattr *a_vap;
117668653Smckusick 	} */ *ap;
117768653Smckusick {
117868653Smckusick 	struct vnode *newvp;
117968653Smckusick 	int error;
118068653Smckusick 
118168653Smckusick 	error = nfs_mknodrpc(ap->a_dvp, &newvp, ap->a_cnp, ap->a_vap);
118268653Smckusick 	if (!error)
118368653Smckusick 		vrele(newvp);
118468653Smckusick 	return (error);
118568653Smckusick }
118668653Smckusick 
118768653Smckusick static u_long create_verf;
118868653Smckusick /*
118938414Smckusick  * nfs file create call
119038414Smckusick  */
119152234Sheideman int
119253806Smckusick nfs_create(ap)
119354668Smckusick 	struct vop_create_args /* {
119454668Smckusick 		struct vnode *a_dvp;
119554668Smckusick 		struct vnode **a_vpp;
119654668Smckusick 		struct componentname *a_cnp;
119754668Smckusick 		struct vattr *a_vap;
119854668Smckusick 	} */ *ap;
119938414Smckusick {
120053806Smckusick 	register struct vnode *dvp = ap->a_dvp;
120153806Smckusick 	register struct vattr *vap = ap->a_vap;
120253806Smckusick 	register struct componentname *cnp = ap->a_cnp;
120338884Smacklem 	register struct nfsv2_sattr *sp;
120468653Smckusick 	register struct nfsv3_sattr *sp3;
120548054Smckusick 	register u_long *tl;
120639488Smckusick 	register caddr_t cp;
120739488Smckusick 	register long t1, t2;
120868653Smckusick 	struct nfsnode *np = (struct nfsnode *)0;
120968653Smckusick 	struct vnode *newvp = (struct vnode *)0;
121039488Smckusick 	caddr_t bpos, dpos, cp2;
121168653Smckusick 	int error = 0, wccflag = NFSV3_WCCRATTR, gotvp = 0, fmode = 0;
121239488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
121359116Smckusick 	struct vattr vattr;
121468653Smckusick 	int v3 = NFS_ISV3(dvp);
121538414Smckusick 
121668653Smckusick 	/*
121768653Smckusick 	 * Oops, not for me..
121868653Smckusick 	 */
121968653Smckusick 	if (vap->va_type == VSOCK)
122068653Smckusick 		return (nfs_mknodrpc(dvp, ap->a_vpp, cnp, vap));
122168653Smckusick 
122259116Smckusick 	if (error = VOP_GETATTR(dvp, &vattr, cnp->cn_cred, cnp->cn_proc)) {
122359116Smckusick 		VOP_ABORTOP(dvp, cnp);
122459116Smckusick 		vput(dvp);
122559116Smckusick 		return (error);
122659116Smckusick 	}
122768653Smckusick 	if (vap->va_vaflags & VA_EXCLUSIVE)
122868653Smckusick 		fmode |= O_EXCL;
122968653Smckusick again:
123038414Smckusick 	nfsstats.rpccnt[NFSPROC_CREATE]++;
123168653Smckusick 	nfsm_reqhead(dvp, NFSPROC_CREATE, NFSX_FH(v3) + 2 * NFSX_UNSIGNED +
123268653Smckusick 		nfsm_rndup(cnp->cn_namelen) + NFSX_SATTR(v3));
123368653Smckusick 	nfsm_fhtom(dvp, v3);
123453806Smckusick 	nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
123568653Smckusick 	if (v3) {
123668653Smckusick 		nfsm_build(tl, u_long *, NFSX_UNSIGNED);
123768653Smckusick 		if (fmode & O_EXCL) {
123868653Smckusick 		    *tl = txdr_unsigned(NFSV3CREATE_EXCLUSIVE);
123968653Smckusick 		    nfsm_build(tl, u_long *, NFSX_V3CREATEVERF);
124068653Smckusick 		    if (in_ifaddr)
124168653Smckusick 			*tl++ = IA_SIN(in_ifaddr)->sin_addr.s_addr;
124268653Smckusick 		    else
124368653Smckusick 			*tl++ = create_verf;
124468653Smckusick 		    *tl = ++create_verf;
124568653Smckusick 		} else {
124668653Smckusick 		    *tl = txdr_unsigned(NFSV3CREATE_UNCHECKED);
124768653Smckusick 		    nfsm_build(tl, u_long *, NFSX_V3SRVSATTR);
124868653Smckusick 		    sp3 = (struct nfsv3_sattr *)tl;
124968653Smckusick 		    nfsm_v3sattr(sp3, vap, cnp->cn_cred->cr_uid, vattr.va_gid);
125068653Smckusick 		}
125156289Smckusick 	} else {
125268653Smckusick 		nfsm_build(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
125368653Smckusick 		sp->sa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode);
125468653Smckusick 		sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid);
125568653Smckusick 		sp->sa_gid = txdr_unsigned(vattr.va_gid);
125668653Smckusick 		sp->sa_size = 0;
125768653Smckusick 		txdr_nfsv2time(&vap->va_atime, &sp->sa_atime);
125868653Smckusick 		txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime);
125956289Smckusick 	}
126053806Smckusick 	nfsm_request(dvp, NFSPROC_CREATE, cnp->cn_proc, cnp->cn_cred);
126168653Smckusick 	if (!error) {
126268653Smckusick 		nfsm_mtofh(dvp, newvp, v3, gotvp);
126368653Smckusick 		if (!gotvp) {
126468653Smckusick 			if (newvp) {
126568653Smckusick 				vrele(newvp);
126668653Smckusick 				newvp = (struct vnode *)0;
126768653Smckusick 			}
126868653Smckusick 			error = nfs_lookitup(dvp, cnp->cn_nameptr,
126968653Smckusick 			    cnp->cn_namelen, cnp->cn_cred, cnp->cn_proc, &np);
127068653Smckusick 			if (!error)
127168653Smckusick 				newvp = NFSTOV(np);
127268653Smckusick 		}
127368653Smckusick 	}
127468653Smckusick 	if (v3)
127568653Smckusick 		nfsm_wcc_data(dvp, wccflag);
127638414Smckusick 	nfsm_reqdone;
127768653Smckusick 	if (error) {
127868653Smckusick 		if (v3 && (fmode & O_EXCL) && error == NFSERR_NOTSUPP) {
127968653Smckusick 			fmode &= ~O_EXCL;
128068653Smckusick 			goto again;
128168653Smckusick 		}
128268653Smckusick 		if (newvp)
128368653Smckusick 			vrele(newvp);
128468653Smckusick 	} else if (v3 && (fmode & O_EXCL))
128568653Smckusick 		error = nfs_setattrrpc(newvp, vap, cnp->cn_cred, cnp->cn_proc);
128668653Smckusick 	if (!error) {
128768653Smckusick 		if (cnp->cn_flags & MAKEENTRY)
128868653Smckusick 			cache_enter(dvp, newvp, cnp);
128968653Smckusick 		*ap->a_vpp = newvp;
129068653Smckusick 	}
129153806Smckusick 	FREE(cnp->cn_pnbuf, M_NAMEI);
129253806Smckusick 	VTONFS(dvp)->n_flag |= NMODIFIED;
129368653Smckusick 	if (!wccflag)
129468653Smckusick 		VTONFS(dvp)->n_attrstamp = 0;
129553806Smckusick 	vrele(dvp);
129638414Smckusick 	return (error);
129738414Smckusick }
129838414Smckusick 
129938414Smckusick /*
130038414Smckusick  * nfs file remove call
130141905Smckusick  * To try and make nfs semantics closer to ufs semantics, a file that has
130241905Smckusick  * other processes using the vnode is renamed instead of removed and then
130339341Smckusick  * removed later on the last close.
130441905Smckusick  * - If v_usecount > 1
130539341Smckusick  *	  If a rename is not already in the works
130639341Smckusick  *	     call nfs_sillyrename() to set it up
130739341Smckusick  *     else
130839341Smckusick  *	  do the remove rpc
130938414Smckusick  */
131052234Sheideman int
131153806Smckusick nfs_remove(ap)
131254451Smckusick 	struct vop_remove_args /* {
131354451Smckusick 		struct vnodeop_desc *a_desc;
131454451Smckusick 		struct vnode * a_dvp;
131554451Smckusick 		struct vnode * a_vp;
131654451Smckusick 		struct componentname * a_cnp;
131754451Smckusick 	} */ *ap;
131838414Smckusick {
131953806Smckusick 	register struct vnode *vp = ap->a_vp;
132053806Smckusick 	register struct vnode *dvp = ap->a_dvp;
132153806Smckusick 	register struct componentname *cnp = ap->a_cnp;
132253806Smckusick 	register struct nfsnode *np = VTONFS(vp);
132348054Smckusick 	register u_long *tl;
132439488Smckusick 	register caddr_t cp;
132552196Smckusick 	register long t2;
132639488Smckusick 	caddr_t bpos, dpos;
132739488Smckusick 	int error = 0;
132839488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
132968653Smckusick 	struct vattr vattr;
133068653Smckusick 	int v3 = NFS_ISV3(dvp);
133138414Smckusick 
133268653Smckusick #ifndef DIAGNOSTIC
133368653Smckusick 	if ((cnp->cn_flags & HASBUF) == 0)
133468653Smckusick 		panic("nfs_remove: no name");
133568653Smckusick 	if (vp->v_usecount < 1)
133668653Smckusick 		panic("nfs_remove: bad v_usecount");
133768653Smckusick #endif
133868653Smckusick 	if (vp->v_usecount == 1 || (np->n_sillyrename &&
133968653Smckusick 	    VOP_GETATTR(vp, &vattr, cnp->cn_cred, cnp->cn_proc) == 0 &&
134068653Smckusick 	    vattr.va_nlink > 1)) {
134152196Smckusick 		/*
134252196Smckusick 		 * Purge the name cache so that the chance of a lookup for
134352196Smckusick 		 * the name succeeding while the remove is in progress is
134452196Smckusick 		 * minimized. Without node locking it can still happen, such
134552196Smckusick 		 * that an I/O op returns ESTALE, but since you get this if
134652196Smckusick 		 * another host removes the file..
134752196Smckusick 		 */
134853806Smckusick 		cache_purge(vp);
134952196Smckusick 		/*
135068653Smckusick 		 * throw away biocache buffers, mainly to avoid
135168653Smckusick 		 * unnecessary delayed writes later.
135252196Smckusick 		 */
135357791Smckusick 		error = nfs_vinvalbuf(vp, 0, cnp->cn_cred, cnp->cn_proc, 1);
135452196Smckusick 		/* Do the rpc */
135568653Smckusick 		if (error != EINTR)
135668653Smckusick 			error = nfs_removerpc(dvp, cnp->cn_nameptr,
135768653Smckusick 				cnp->cn_namelen, cnp->cn_cred, cnp->cn_proc);
135839751Smckusick 		/*
135939751Smckusick 		 * Kludge City: If the first reply to the remove rpc is lost..
136039751Smckusick 		 *   the reply to the retransmitted request will be ENOENT
136139751Smckusick 		 *   since the file was in fact removed
136239751Smckusick 		 *   Therefore, we cheat and return success.
136339751Smckusick 		 */
136439751Smckusick 		if (error == ENOENT)
136539751Smckusick 			error = 0;
136668653Smckusick 	} else if (!np->n_sillyrename)
136768653Smckusick 		error = nfs_sillyrename(dvp, vp, cnp);
136868653Smckusick 	FREE(cnp->cn_pnbuf, M_NAMEI);
136940042Smckusick 	np->n_attrstamp = 0;
137053806Smckusick 	vrele(dvp);
137153806Smckusick 	vrele(vp);
137238414Smckusick 	return (error);
137338414Smckusick }
137438414Smckusick 
137538414Smckusick /*
137638414Smckusick  * nfs file remove rpc called from nfs_inactive
137738414Smckusick  */
137852234Sheideman int
137954451Smckusick nfs_removeit(sp)
138048364Smckusick 	register struct sillyrename *sp;
138138414Smckusick {
138268653Smckusick 
138368653Smckusick 	return (nfs_removerpc(sp->s_dvp, sp->s_name, sp->s_namlen, sp->s_cred,
138468653Smckusick 		(struct proc *)0));
138568653Smckusick }
138668653Smckusick 
138768653Smckusick /*
138868653Smckusick  * Nfs remove rpc, called from nfs_remove() and nfs_removeit().
138968653Smckusick  */
139068653Smckusick int
139168653Smckusick nfs_removerpc(dvp, name, namelen, cred, proc)
139268653Smckusick 	register struct vnode *dvp;
139368653Smckusick 	char *name;
139468653Smckusick 	int namelen;
139568653Smckusick 	struct ucred *cred;
139668653Smckusick 	struct proc *proc;
139768653Smckusick {
139848054Smckusick 	register u_long *tl;
139939488Smckusick 	register caddr_t cp;
140068653Smckusick 	register long t1, t2;
140168653Smckusick 	caddr_t bpos, dpos, cp2;
140268653Smckusick 	int error = 0, wccflag = NFSV3_WCCRATTR;
140339488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
140468653Smckusick 	int v3 = NFS_ISV3(dvp);
140538414Smckusick 
140638414Smckusick 	nfsstats.rpccnt[NFSPROC_REMOVE]++;
140768653Smckusick 	nfsm_reqhead(dvp, NFSPROC_REMOVE,
140868653Smckusick 		NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(namelen));
140968653Smckusick 	nfsm_fhtom(dvp, v3);
141068653Smckusick 	nfsm_strtom(name, namelen, NFS_MAXNAMLEN);
141168653Smckusick 	nfsm_request(dvp, NFSPROC_REMOVE, proc, cred);
141268653Smckusick 	if (v3)
141368653Smckusick 		nfsm_wcc_data(dvp, wccflag);
141438414Smckusick 	nfsm_reqdone;
141568653Smckusick 	VTONFS(dvp)->n_flag |= NMODIFIED;
141668653Smckusick 	if (!wccflag)
141768653Smckusick 		VTONFS(dvp)->n_attrstamp = 0;
141838414Smckusick 	return (error);
141938414Smckusick }
142038414Smckusick 
142138414Smckusick /*
142238414Smckusick  * nfs file rename call
142338414Smckusick  */
142452234Sheideman int
142553806Smckusick nfs_rename(ap)
142654668Smckusick 	struct vop_rename_args  /* {
142754668Smckusick 		struct vnode *a_fdvp;
142854668Smckusick 		struct vnode *a_fvp;
142954668Smckusick 		struct componentname *a_fcnp;
143054668Smckusick 		struct vnode *a_tdvp;
143154668Smckusick 		struct vnode *a_tvp;
143254668Smckusick 		struct componentname *a_tcnp;
143354668Smckusick 	} */ *ap;
143438414Smckusick {
143553806Smckusick 	register struct vnode *fvp = ap->a_fvp;
143653806Smckusick 	register struct vnode *tvp = ap->a_tvp;
143753806Smckusick 	register struct vnode *fdvp = ap->a_fdvp;
143853806Smckusick 	register struct vnode *tdvp = ap->a_tdvp;
143953806Smckusick 	register struct componentname *tcnp = ap->a_tcnp;
144053806Smckusick 	register struct componentname *fcnp = ap->a_fcnp;
144168653Smckusick 	int error;
144238414Smckusick 
144368653Smckusick #ifndef DIAGNOSTIC
144468653Smckusick 	if ((tcnp->cn_flags & HASBUF) == 0 ||
144568653Smckusick 	    (fcnp->cn_flags & HASBUF) == 0)
144668653Smckusick 		panic("nfs_rename: no name");
144768653Smckusick #endif
144853804Spendry 	/* Check for cross-device rename */
144953806Smckusick 	if ((fvp->v_mount != tdvp->v_mount) ||
145053806Smckusick 	    (tvp && (fvp->v_mount != tvp->v_mount))) {
145153804Spendry 		error = EXDEV;
145253804Spendry 		goto out;
145353804Spendry 	}
145453804Spendry 
145568653Smckusick 	/*
145668653Smckusick 	 * If the tvp exists and is in use, sillyrename it before doing the
145768653Smckusick 	 * rename of the new file over it.
145868653Smckusick 	 */
145968653Smckusick 	if (tvp && tvp->v_usecount > 1 && !VTONFS(tvp)->n_sillyrename &&
146068653Smckusick 		!nfs_sillyrename(tdvp, tvp, tcnp)) {
146168653Smckusick 		vrele(tvp);
146268653Smckusick 		tvp = NULL;
146368653Smckusick 	}
146453804Spendry 
146568653Smckusick 	error = nfs_renamerpc(fdvp, fcnp->cn_nameptr, fcnp->cn_namelen,
146668653Smckusick 		tdvp, tcnp->cn_nameptr, tcnp->cn_namelen, tcnp->cn_cred,
146768653Smckusick 		tcnp->cn_proc);
146868653Smckusick 
146953806Smckusick 	if (fvp->v_type == VDIR) {
147053806Smckusick 		if (tvp != NULL && tvp->v_type == VDIR)
147153806Smckusick 			cache_purge(tdvp);
147253806Smckusick 		cache_purge(fdvp);
147338414Smckusick 	}
147453804Spendry out:
147553806Smckusick 	if (tdvp == tvp)
147653806Smckusick 		vrele(tdvp);
147743360Smckusick 	else
147853806Smckusick 		vput(tdvp);
147953806Smckusick 	if (tvp)
148053806Smckusick 		vput(tvp);
148153806Smckusick 	vrele(fdvp);
148253806Smckusick 	vrele(fvp);
148340112Smckusick 	/*
148440112Smckusick 	 * Kludge: Map ENOENT => 0 assuming that it is a reply to a retry.
148540112Smckusick 	 */
148640112Smckusick 	if (error == ENOENT)
148740112Smckusick 		error = 0;
148838414Smckusick 	return (error);
148938414Smckusick }
149038414Smckusick 
149138414Smckusick /*
149241905Smckusick  * nfs file rename rpc called from nfs_remove() above
149338414Smckusick  */
149452234Sheideman int
149552234Sheideman nfs_renameit(sdvp, scnp, sp)
149652234Sheideman 	struct vnode *sdvp;
149752234Sheideman 	struct componentname *scnp;
149848364Smckusick 	register struct sillyrename *sp;
149938414Smckusick {
150068653Smckusick 	return (nfs_renamerpc(sdvp, scnp->cn_nameptr, scnp->cn_namelen,
150168653Smckusick 		sdvp, sp->s_name, sp->s_namlen, scnp->cn_cred, scnp->cn_proc));
150268653Smckusick }
150368653Smckusick 
150468653Smckusick /*
150568653Smckusick  * Do an nfs rename rpc. Called from nfs_rename() and nfs_renameit().
150668653Smckusick  */
150768653Smckusick int
150868653Smckusick nfs_renamerpc(fdvp, fnameptr, fnamelen, tdvp, tnameptr, tnamelen, cred, proc)
150968653Smckusick 	register struct vnode *fdvp;
151068653Smckusick 	char *fnameptr;
151168653Smckusick 	int fnamelen;
151268653Smckusick 	register struct vnode *tdvp;
151368653Smckusick 	char *tnameptr;
151468653Smckusick 	int tnamelen;
151568653Smckusick 	struct ucred *cred;
151668653Smckusick 	struct proc *proc;
151768653Smckusick {
151848054Smckusick 	register u_long *tl;
151939488Smckusick 	register caddr_t cp;
152068653Smckusick 	register long t1, t2;
152168653Smckusick 	caddr_t bpos, dpos, cp2;
152268653Smckusick 	int error = 0, fwccflag = NFSV3_WCCRATTR, twccflag = NFSV3_WCCRATTR;
152339488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
152468653Smckusick 	int v3 = NFS_ISV3(fdvp);
152538414Smckusick 
152638414Smckusick 	nfsstats.rpccnt[NFSPROC_RENAME]++;
152768653Smckusick 	nfsm_reqhead(fdvp, NFSPROC_RENAME,
152868653Smckusick 		(NFSX_FH(v3) + NFSX_UNSIGNED)*2 + nfsm_rndup(fnamelen) +
152968653Smckusick 		nfsm_rndup(tnamelen));
153068653Smckusick 	nfsm_fhtom(fdvp, v3);
153168653Smckusick 	nfsm_strtom(fnameptr, fnamelen, NFS_MAXNAMLEN);
153268653Smckusick 	nfsm_fhtom(tdvp, v3);
153368653Smckusick 	nfsm_strtom(tnameptr, tnamelen, NFS_MAXNAMLEN);
153468653Smckusick 	nfsm_request(fdvp, NFSPROC_RENAME, proc, cred);
153568653Smckusick 	if (v3) {
153668653Smckusick 		nfsm_wcc_data(fdvp, fwccflag);
153768653Smckusick 		nfsm_wcc_data(tdvp, twccflag);
153868653Smckusick 	}
153938414Smckusick 	nfsm_reqdone;
154068653Smckusick 	VTONFS(fdvp)->n_flag |= NMODIFIED;
154168653Smckusick 	VTONFS(tdvp)->n_flag |= NMODIFIED;
154268653Smckusick 	if (!fwccflag)
154368653Smckusick 		VTONFS(fdvp)->n_attrstamp = 0;
154468653Smckusick 	if (!twccflag)
154568653Smckusick 		VTONFS(tdvp)->n_attrstamp = 0;
154638414Smckusick 	return (error);
154738414Smckusick }
154838414Smckusick 
154938414Smckusick /*
155038414Smckusick  * nfs hard link create call
155138414Smckusick  */
155252234Sheideman int
155353806Smckusick nfs_link(ap)
155454668Smckusick 	struct vop_link_args /* {
155554668Smckusick 		struct vnode *a_vp;
155654668Smckusick 		struct vnode *a_tdvp;
155754668Smckusick 		struct componentname *a_cnp;
155854668Smckusick 	} */ *ap;
155938414Smckusick {
156053806Smckusick 	register struct vnode *vp = ap->a_vp;
156153806Smckusick 	register struct vnode *tdvp = ap->a_tdvp;
156253806Smckusick 	register struct componentname *cnp = ap->a_cnp;
156348054Smckusick 	register u_long *tl;
156439488Smckusick 	register caddr_t cp;
156568653Smckusick 	register long t1, t2;
156668653Smckusick 	caddr_t bpos, dpos, cp2;
156768653Smckusick 	int error = 0, wccflag = NFSV3_WCCRATTR, attrflag = 0;
156839488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
156968653Smckusick 	int v3 = NFS_ISV3(vp);
157038414Smckusick 
157168653Smckusick 	if (vp->v_mount != tdvp->v_mount) {
157268653Smckusick 		/*VOP_ABORTOP(vp, cnp);*/
157368653Smckusick 		if (tdvp == vp)
157468653Smckusick 			vrele(tdvp);
157568653Smckusick 		else
157668653Smckusick 			vput(tdvp);
157753804Spendry 		return (EXDEV);
157853804Spendry 	}
157953804Spendry 
158067659Smckusick 	/*
158167659Smckusick 	 * Push all writes to the server, so that the attribute cache
158267659Smckusick 	 * doesn't get "out of sync" with the server.
158367659Smckusick 	 * XXX There should be a better way!
158467659Smckusick 	 */
158568539Smckusick 	VOP_FSYNC(vp, cnp->cn_cred, MNT_WAIT, cnp->cn_proc);
158667659Smckusick 
158738414Smckusick 	nfsstats.rpccnt[NFSPROC_LINK]++;
158868539Smckusick 	nfsm_reqhead(vp, NFSPROC_LINK,
158968653Smckusick 		NFSX_FH(v3)*2 + NFSX_UNSIGNED + nfsm_rndup(cnp->cn_namelen));
159068653Smckusick 	nfsm_fhtom(vp, v3);
159168653Smckusick 	nfsm_fhtom(tdvp, v3);
159253806Smckusick 	nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
159368539Smckusick 	nfsm_request(vp, NFSPROC_LINK, cnp->cn_proc, cnp->cn_cred);
159468653Smckusick 	if (v3) {
159568653Smckusick 		nfsm_postop_attr(vp, attrflag);
159668653Smckusick 		nfsm_wcc_data(tdvp, wccflag);
159768653Smckusick 	}
159838414Smckusick 	nfsm_reqdone;
159953806Smckusick 	FREE(cnp->cn_pnbuf, M_NAMEI);
160068653Smckusick 	VTONFS(tdvp)->n_flag |= NMODIFIED;
160168653Smckusick 	if (!attrflag)
160268653Smckusick 		VTONFS(vp)->n_attrstamp = 0;
160368653Smckusick 	if (!wccflag)
160468653Smckusick 		VTONFS(tdvp)->n_attrstamp = 0;
160568653Smckusick 	vrele(tdvp);
160640112Smckusick 	/*
160740112Smckusick 	 * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry.
160840112Smckusick 	 */
160940112Smckusick 	if (error == EEXIST)
161040112Smckusick 		error = 0;
161138414Smckusick 	return (error);
161238414Smckusick }
161338414Smckusick 
161438414Smckusick /*
161538414Smckusick  * nfs symbolic link create call
161638414Smckusick  */
161752234Sheideman int
161853806Smckusick nfs_symlink(ap)
161954668Smckusick 	struct vop_symlink_args /* {
162054668Smckusick 		struct vnode *a_dvp;
162154668Smckusick 		struct vnode **a_vpp;
162254668Smckusick 		struct componentname *a_cnp;
162354668Smckusick 		struct vattr *a_vap;
162454668Smckusick 		char *a_target;
162554668Smckusick 	} */ *ap;
162638414Smckusick {
162753806Smckusick 	register struct vnode *dvp = ap->a_dvp;
162853806Smckusick 	register struct vattr *vap = ap->a_vap;
162953806Smckusick 	register struct componentname *cnp = ap->a_cnp;
163038884Smacklem 	register struct nfsv2_sattr *sp;
163168653Smckusick 	register struct nfsv3_sattr *sp3;
163248054Smckusick 	register u_long *tl;
163339488Smckusick 	register caddr_t cp;
163468653Smckusick 	register long t1, t2;
163568653Smckusick 	caddr_t bpos, dpos, cp2;
163668653Smckusick 	int slen, error = 0, wccflag = NFSV3_WCCRATTR, gotvp;
163739488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
163868653Smckusick 	struct vnode *newvp = (struct vnode *)0;
163968653Smckusick 	int v3 = NFS_ISV3(dvp);
164038414Smckusick 
164138414Smckusick 	nfsstats.rpccnt[NFSPROC_SYMLINK]++;
164253600Sheideman 	slen = strlen(ap->a_target);
164368653Smckusick 	nfsm_reqhead(dvp, NFSPROC_SYMLINK, NFSX_FH(v3) + 2*NFSX_UNSIGNED +
164468653Smckusick 	    nfsm_rndup(cnp->cn_namelen) + nfsm_rndup(slen) + NFSX_SATTR(v3));
164568653Smckusick 	nfsm_fhtom(dvp, v3);
164653806Smckusick 	nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
164768653Smckusick 	if (v3) {
164868653Smckusick 		nfsm_build(sp3, struct nfsv3_sattr *, NFSX_V3SRVSATTR);
164968653Smckusick 		nfsm_v3sattr(sp3, vap, cnp->cn_cred->cr_uid,
165068653Smckusick 			cnp->cn_cred->cr_gid);
165168653Smckusick 	}
165253600Sheideman 	nfsm_strtom(ap->a_target, slen, NFS_MAXPATHLEN);
165368653Smckusick 	if (!v3) {
165468653Smckusick 		nfsm_build(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
165568653Smckusick 		sp->sa_mode = vtonfsv2_mode(VLNK, vap->va_mode);
165668653Smckusick 		sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid);
165768653Smckusick 		sp->sa_gid = txdr_unsigned(cnp->cn_cred->cr_gid);
165868653Smckusick 		sp->sa_size = -1;
165968653Smckusick 		txdr_nfsv2time(&vap->va_atime, &sp->sa_atime);
166068653Smckusick 		txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime);
166156289Smckusick 	}
166253806Smckusick 	nfsm_request(dvp, NFSPROC_SYMLINK, cnp->cn_proc, cnp->cn_cred);
166368653Smckusick 	if (v3) {
166468653Smckusick 		if (!error)
166568653Smckusick 			nfsm_mtofh(dvp, newvp, v3, gotvp);
166668653Smckusick 		nfsm_wcc_data(dvp, wccflag);
166768653Smckusick 	}
166838414Smckusick 	nfsm_reqdone;
166968653Smckusick 	if (newvp)
167068653Smckusick 		vrele(newvp);
167153806Smckusick 	FREE(cnp->cn_pnbuf, M_NAMEI);
167253806Smckusick 	VTONFS(dvp)->n_flag |= NMODIFIED;
167368653Smckusick 	if (!wccflag)
167468653Smckusick 		VTONFS(dvp)->n_attrstamp = 0;
167553806Smckusick 	vrele(dvp);
167640112Smckusick 	/*
167740112Smckusick 	 * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry.
167840112Smckusick 	 */
167940112Smckusick 	if (error == EEXIST)
168040112Smckusick 		error = 0;
168138414Smckusick 	return (error);
168238414Smckusick }
168338414Smckusick 
168438414Smckusick /*
168538414Smckusick  * nfs make dir call
168638414Smckusick  */
168752234Sheideman int
168853806Smckusick nfs_mkdir(ap)
168954668Smckusick 	struct vop_mkdir_args /* {
169054668Smckusick 		struct vnode *a_dvp;
169154668Smckusick 		struct vnode **a_vpp;
169254668Smckusick 		struct componentname *a_cnp;
169354668Smckusick 		struct vattr *a_vap;
169454668Smckusick 	} */ *ap;
169538414Smckusick {
169653806Smckusick 	register struct vnode *dvp = ap->a_dvp;
169753806Smckusick 	register struct vattr *vap = ap->a_vap;
169853806Smckusick 	register struct componentname *cnp = ap->a_cnp;
169938884Smacklem 	register struct nfsv2_sattr *sp;
170068653Smckusick 	register struct nfsv3_sattr *sp3;
170148054Smckusick 	register u_long *tl;
170239488Smckusick 	register caddr_t cp;
170339488Smckusick 	register long t1, t2;
170441905Smckusick 	register int len;
170568653Smckusick 	struct nfsnode *np = (struct nfsnode *)0;
170668653Smckusick 	struct vnode *newvp = (struct vnode *)0;
170739488Smckusick 	caddr_t bpos, dpos, cp2;
170868653Smckusick 	nfsfh_t *fhp;
170968653Smckusick 	int error = 0, wccflag = NFSV3_WCCRATTR, attrflag;
171068653Smckusick 	int fhsize, gotvp = 0;
171139488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
171259116Smckusick 	struct vattr vattr;
171368653Smckusick 	int v3 = NFS_ISV3(dvp);
171438414Smckusick 
171559116Smckusick 	if (error = VOP_GETATTR(dvp, &vattr, cnp->cn_cred, cnp->cn_proc)) {
171659116Smckusick 		VOP_ABORTOP(dvp, cnp);
171759116Smckusick 		vput(dvp);
171859116Smckusick 		return (error);
171959116Smckusick 	}
172053806Smckusick 	len = cnp->cn_namelen;
172138414Smckusick 	nfsstats.rpccnt[NFSPROC_MKDIR]++;
172253806Smckusick 	nfsm_reqhead(dvp, NFSPROC_MKDIR,
172368653Smckusick 	  NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(len) + NFSX_SATTR(v3));
172468653Smckusick 	nfsm_fhtom(dvp, v3);
172553806Smckusick 	nfsm_strtom(cnp->cn_nameptr, len, NFS_MAXNAMLEN);
172668653Smckusick 	if (v3) {
172768653Smckusick 		nfsm_build(sp3, struct nfsv3_sattr *, NFSX_V3SRVSATTR);
172868653Smckusick 		nfsm_v3sattr(sp3, vap, cnp->cn_cred->cr_uid, vattr.va_gid);
172956289Smckusick 	} else {
173068653Smckusick 		nfsm_build(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
173168653Smckusick 		sp->sa_mode = vtonfsv2_mode(VDIR, vap->va_mode);
173268653Smckusick 		sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid);
173368653Smckusick 		sp->sa_gid = txdr_unsigned(vattr.va_gid);
173468653Smckusick 		sp->sa_size = -1;
173568653Smckusick 		txdr_nfsv2time(&vap->va_atime, &sp->sa_atime);
173668653Smckusick 		txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime);
173756289Smckusick 	}
173853806Smckusick 	nfsm_request(dvp, NFSPROC_MKDIR, cnp->cn_proc, cnp->cn_cred);
173968653Smckusick 	if (!error)
174068653Smckusick 		nfsm_mtofh(dvp, newvp, v3, gotvp);
174168653Smckusick 	if (v3)
174268653Smckusick 		nfsm_wcc_data(dvp, wccflag);
174338414Smckusick 	nfsm_reqdone;
174453806Smckusick 	VTONFS(dvp)->n_flag |= NMODIFIED;
174568653Smckusick 	if (!wccflag)
174668653Smckusick 		VTONFS(dvp)->n_attrstamp = 0;
174740112Smckusick 	/*
174841905Smckusick 	 * Kludge: Map EEXIST => 0 assuming that you have a reply to a retry
174941905Smckusick 	 * if we can succeed in looking up the directory.
175040112Smckusick 	 */
175168653Smckusick 	if (error == EEXIST || (!error && !gotvp)) {
175268653Smckusick 		if (newvp) {
175368653Smckusick 			vrele(newvp);
175468653Smckusick 			newvp = (struct vnode *)0;
175541905Smckusick 		}
175668653Smckusick 		error = nfs_lookitup(dvp, cnp->cn_nameptr, len, cnp->cn_cred,
175768653Smckusick 			cnp->cn_proc, &np);
175868653Smckusick 		if (!error) {
175968653Smckusick 			newvp = NFSTOV(np);
176068653Smckusick 			if (newvp->v_type != VDIR)
176168653Smckusick 				error = EEXIST;
176268653Smckusick 		}
176341905Smckusick 	}
176468653Smckusick 	if (error) {
176568653Smckusick 		if (newvp)
176668653Smckusick 			vrele(newvp);
176768653Smckusick 	} else
176868653Smckusick 		*ap->a_vpp = newvp;
176953806Smckusick 	FREE(cnp->cn_pnbuf, M_NAMEI);
177053806Smckusick 	vrele(dvp);
177138414Smckusick 	return (error);
177238414Smckusick }
177338414Smckusick 
177438414Smckusick /*
177538414Smckusick  * nfs remove directory call
177638414Smckusick  */
177752234Sheideman int
177853806Smckusick nfs_rmdir(ap)
177954668Smckusick 	struct vop_rmdir_args /* {
178054668Smckusick 		struct vnode *a_dvp;
178154668Smckusick 		struct vnode *a_vp;
178254668Smckusick 		struct componentname *a_cnp;
178354668Smckusick 	} */ *ap;
178438414Smckusick {
178553806Smckusick 	register struct vnode *vp = ap->a_vp;
178653806Smckusick 	register struct vnode *dvp = ap->a_dvp;
178753806Smckusick 	register struct componentname *cnp = ap->a_cnp;
178848054Smckusick 	register u_long *tl;
178939488Smckusick 	register caddr_t cp;
179068653Smckusick 	register long t1, t2;
179168653Smckusick 	caddr_t bpos, dpos, cp2;
179268653Smckusick 	int error = 0, wccflag = NFSV3_WCCRATTR;
179339488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
179468653Smckusick 	int v3 = NFS_ISV3(dvp);
179538414Smckusick 
179653806Smckusick 	if (dvp == vp) {
179753806Smckusick 		vrele(dvp);
179853806Smckusick 		vrele(dvp);
179953806Smckusick 		FREE(cnp->cn_pnbuf, M_NAMEI);
180038414Smckusick 		return (EINVAL);
180138414Smckusick 	}
180238414Smckusick 	nfsstats.rpccnt[NFSPROC_RMDIR]++;
180353806Smckusick 	nfsm_reqhead(dvp, NFSPROC_RMDIR,
180468653Smckusick 		NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(cnp->cn_namelen));
180568653Smckusick 	nfsm_fhtom(dvp, v3);
180653806Smckusick 	nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
180753806Smckusick 	nfsm_request(dvp, NFSPROC_RMDIR, cnp->cn_proc, cnp->cn_cred);
180868653Smckusick 	if (v3)
180968653Smckusick 		nfsm_wcc_data(dvp, wccflag);
181038414Smckusick 	nfsm_reqdone;
181153806Smckusick 	FREE(cnp->cn_pnbuf, M_NAMEI);
181253806Smckusick 	VTONFS(dvp)->n_flag |= NMODIFIED;
181368653Smckusick 	if (!wccflag)
181468653Smckusick 		VTONFS(dvp)->n_attrstamp = 0;
181553806Smckusick 	cache_purge(dvp);
181653806Smckusick 	cache_purge(vp);
181753806Smckusick 	vrele(vp);
181853806Smckusick 	vrele(dvp);
181940112Smckusick 	/*
182040112Smckusick 	 * Kludge: Map ENOENT => 0 assuming that you have a reply to a retry.
182140112Smckusick 	 */
182240112Smckusick 	if (error == ENOENT)
182340112Smckusick 		error = 0;
182438414Smckusick 	return (error);
182538414Smckusick }
182638414Smckusick 
182738414Smckusick /*
182838414Smckusick  * nfs readdir call
182938414Smckusick  */
183052234Sheideman int
183153806Smckusick nfs_readdir(ap)
183254668Smckusick 	struct vop_readdir_args /* {
183354668Smckusick 		struct vnode *a_vp;
183454668Smckusick 		struct uio *a_uio;
183554668Smckusick 		struct ucred *a_cred;
183654668Smckusick 	} */ *ap;
183738414Smckusick {
183853806Smckusick 	register struct vnode *vp = ap->a_vp;
183953806Smckusick 	register struct nfsnode *np = VTONFS(vp);
184053806Smckusick 	register struct uio *uio = ap->a_uio;
184141905Smckusick 	int tresid, error;
184241905Smckusick 	struct vattr vattr;
184341905Smckusick 
184453806Smckusick 	if (vp->v_type != VDIR)
184541905Smckusick 		return (EPERM);
184641905Smckusick 	/*
184741905Smckusick 	 * First, check for hit on the EOF offset cache
184841905Smckusick 	 */
184968653Smckusick 	if (np->n_direofoffset > 0 && uio->uio_offset >= np->n_direofoffset &&
185052196Smckusick 	    (np->n_flag & NMODIFIED) == 0) {
185153806Smckusick 		if (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) {
185268653Smckusick 			if (NQNFS_CKCACHABLE(vp, ND_READ)) {
185352196Smckusick 				nfsstats.direofcache_hits++;
185452196Smckusick 				return (0);
185552196Smckusick 			}
185653806Smckusick 		} else if (VOP_GETATTR(vp, &vattr, ap->a_cred, uio->uio_procp) == 0 &&
185754106Smckusick 			np->n_mtime == vattr.va_mtime.ts_sec) {
185852196Smckusick 			nfsstats.direofcache_hits++;
185952196Smckusick 			return (0);
186052196Smckusick 		}
186141905Smckusick 	}
186241905Smckusick 
186341905Smckusick 	/*
186441905Smckusick 	 * Call nfs_bioread() to do the real work.
186541905Smckusick 	 */
186653806Smckusick 	tresid = uio->uio_resid;
186753806Smckusick 	error = nfs_bioread(vp, uio, 0, ap->a_cred);
186841905Smckusick 
186954451Smckusick 	if (!error && uio->uio_resid == tresid)
187041905Smckusick 		nfsstats.direofcache_misses++;
187141905Smckusick 	return (error);
187241905Smckusick }
187341905Smckusick 
187441905Smckusick /*
187541905Smckusick  * Readdir rpc call.
187641905Smckusick  * Called from below the buffer cache by nfs_doio().
187741905Smckusick  */
187852234Sheideman int
187948054Smckusick nfs_readdirrpc(vp, uiop, cred)
188068653Smckusick 	struct vnode *vp;
188168653Smckusick 	register struct uio *uiop;
188241905Smckusick 	struct ucred *cred;
188341905Smckusick {
188468653Smckusick 	register int len, left;
188554740Smckusick 	register struct dirent *dp;
188648054Smckusick 	register u_long *tl;
188739488Smckusick 	register caddr_t cp;
188868653Smckusick 	register long t1, t2;
188968653Smckusick 	register nfsuint64 *cookiep;
189039488Smckusick 	caddr_t bpos, dpos, cp2;
189139488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
189268653Smckusick 	nfsuint64 cookie;
189368653Smckusick 	struct nfsmount *nmp = VFSTONFS(vp->v_mount);
189468653Smckusick 	struct nfsnode *dnp = VTONFS(vp);
189568653Smckusick 	nfsfh_t *fhp;
189668653Smckusick 	u_quad_t frev, fileno;
189768653Smckusick 	int error = 0, tlen, more_dirs = 1, blksiz = 0, bigenough = 1, i;
189868653Smckusick 	int cachable, attrflag, fhsize;
189968653Smckusick 	int v3 = NFS_ISV3(vp);
190038414Smckusick 
190168653Smckusick #ifndef nolint
190268653Smckusick 	dp = (struct dirent *)0;
190368653Smckusick #endif
190468653Smckusick #ifndef DIAGNOSTIC
190568653Smckusick 	if (uiop->uio_iovcnt != 1 || (uiop->uio_offset & (NFS_DIRBLKSIZ - 1)) ||
190668653Smckusick 		(uiop->uio_resid & (NFS_DIRBLKSIZ - 1)))
190768653Smckusick 		panic("nfs readdirrpc bad uio");
190868653Smckusick #endif
190968653Smckusick 
191040296Smckusick 	/*
191168653Smckusick 	 * If there is no cookie, assume end of directory.
191268653Smckusick 	 */
191368653Smckusick 	cookiep = nfs_getcookie(dnp, uiop->uio_offset, 0);
191468653Smckusick 	if (cookiep)
191568653Smckusick 		cookie = *cookiep;
191668653Smckusick 	else
191768653Smckusick 		return (0);
191868653Smckusick 	/*
191968653Smckusick 	 * Loop around doing readdir rpc's of size nm_readdirsize
192068653Smckusick 	 * truncated to a multiple of DIRBLKSIZ.
192141905Smckusick 	 * The stopping criteria is EOF or buffer full.
192240296Smckusick 	 */
192368653Smckusick 	while (more_dirs && bigenough) {
192440296Smckusick 		nfsstats.rpccnt[NFSPROC_READDIR]++;
192568653Smckusick 		nfsm_reqhead(vp, NFSPROC_READDIR, NFSX_FH(v3) +
192668653Smckusick 			NFSX_READDIR(v3));
192768653Smckusick 		nfsm_fhtom(vp, v3);
192868653Smckusick 		if (v3) {
192968653Smckusick 			nfsm_build(tl, u_long *, 5 * NFSX_UNSIGNED);
193068653Smckusick 			*tl++ = cookie.nfsuquad[0];
193168653Smckusick 			*tl++ = cookie.nfsuquad[1];
193268653Smckusick 			*tl++ = dnp->n_cookieverf.nfsuquad[0];
193368653Smckusick 			*tl++ = dnp->n_cookieverf.nfsuquad[1];
193468653Smckusick 		} else {
193568653Smckusick 			nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED);
193668653Smckusick 			*tl++ = cookie.nfsuquad[0];
193768653Smckusick 		}
193868653Smckusick 		*tl = txdr_unsigned(nmp->nm_readdirsize);
193952196Smckusick 		nfsm_request(vp, NFSPROC_READDIR, uiop->uio_procp, cred);
194068653Smckusick 		if (v3) {
194168653Smckusick 			nfsm_postop_attr(vp, attrflag);
194268653Smckusick 			if (!error) {
194368653Smckusick 				nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
194468653Smckusick 				dnp->n_cookieverf.nfsuquad[0] = *tl++;
194568653Smckusick 				dnp->n_cookieverf.nfsuquad[1] = *tl;
194668653Smckusick 			} else {
194768653Smckusick 				m_freem(mrep);
194868653Smckusick 				goto nfsmout;
194968653Smckusick 			}
195068653Smckusick 		}
195152196Smckusick 		nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
195248054Smckusick 		more_dirs = fxdr_unsigned(int, *tl);
195340296Smckusick 
195440296Smckusick 		/* loop thru the dir entries, doctoring them to 4bsd form */
195568653Smckusick 		while (more_dirs && bigenough) {
195668653Smckusick 			if (v3) {
195768653Smckusick 				nfsm_dissect(tl, u_long *, 3 * NFSX_UNSIGNED);
195868653Smckusick 				fxdr_hyper(tl, &fileno);
195968653Smckusick 				len = fxdr_unsigned(int, *(tl + 2));
196068653Smckusick 			} else {
196168653Smckusick 				nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
196268653Smckusick 				fileno = fxdr_unsigned(u_quad_t, *tl++);
196368653Smckusick 				len = fxdr_unsigned(int, *tl);
196468653Smckusick 			}
196540296Smckusick 			if (len <= 0 || len > NFS_MAXNAMLEN) {
196640296Smckusick 				error = EBADRPC;
196740296Smckusick 				m_freem(mrep);
196840296Smckusick 				goto nfsmout;
196940296Smckusick 			}
197040296Smckusick 			tlen = nfsm_rndup(len);
197168653Smckusick 			if (tlen == len)
197268653Smckusick 				tlen += 4;	/* To ensure null termination */
197368653Smckusick 			left = DIRBLKSIZ - blksiz;
197468653Smckusick 			if ((tlen + DIRHDSIZ) > left) {
197568653Smckusick 				dp->d_reclen += left;
197668653Smckusick 				uiop->uio_iov->iov_base += left;
197768653Smckusick 				uiop->uio_iov->iov_len -= left;
197868653Smckusick 				uiop->uio_offset += left;
197968653Smckusick 				uiop->uio_resid -= left;
198068653Smckusick 				blksiz = 0;
198140296Smckusick 			}
198268653Smckusick 			if ((tlen + DIRHDSIZ) > uiop->uio_resid)
198368653Smckusick 				bigenough = 0;
198468653Smckusick 			if (bigenough) {
198568653Smckusick 				dp = (struct dirent *)uiop->uio_iov->iov_base;
198668653Smckusick 				dp->d_fileno = (int)fileno;
198768653Smckusick 				dp->d_namlen = len;
198868653Smckusick 				dp->d_reclen = tlen + DIRHDSIZ;
198968653Smckusick 				dp->d_type = DT_UNKNOWN;
199068653Smckusick 				blksiz += dp->d_reclen;
199168653Smckusick 				if (blksiz == DIRBLKSIZ)
199268653Smckusick 					blksiz = 0;
199368653Smckusick 				uiop->uio_offset += DIRHDSIZ;
199468653Smckusick 				uiop->uio_resid -= DIRHDSIZ;
199568653Smckusick 				uiop->uio_iov->iov_base += DIRHDSIZ;
199668653Smckusick 				uiop->uio_iov->iov_len -= DIRHDSIZ;
199768653Smckusick 				nfsm_mtouio(uiop, len);
199868653Smckusick 				cp = uiop->uio_iov->iov_base;
199968653Smckusick 				tlen -= len;
200068653Smckusick 				*cp = '\0';	/* null terminate */
200168653Smckusick 				uiop->uio_iov->iov_base += tlen;
200268653Smckusick 				uiop->uio_iov->iov_len -= tlen;
200368653Smckusick 				uiop->uio_offset += tlen;
200468653Smckusick 				uiop->uio_resid -= tlen;
200568653Smckusick 			} else
200668653Smckusick 				nfsm_adv(nfsm_rndup(len));
200768653Smckusick 			if (v3) {
200868653Smckusick 				nfsm_dissect(tl, u_long *, 3 * NFSX_UNSIGNED);
200968653Smckusick 			} else {
201068653Smckusick 				nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
201168653Smckusick 			}
201268653Smckusick 			if (bigenough) {
201368653Smckusick 				cookie.nfsuquad[0] = *tl++;
201468653Smckusick 				if (v3)
201568653Smckusick 					cookie.nfsuquad[1] = *tl++;
201668653Smckusick 			} else if (v3)
201768653Smckusick 				tl += 2;
201868653Smckusick 			else
201968653Smckusick 				tl++;
202048054Smckusick 			more_dirs = fxdr_unsigned(int, *tl);
202140296Smckusick 		}
202240296Smckusick 		/*
202340296Smckusick 		 * If at end of rpc data, get the eof boolean
202440296Smckusick 		 */
202540296Smckusick 		if (!more_dirs) {
202663483Smckusick 			nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
202748054Smckusick 			more_dirs = (fxdr_unsigned(int, *tl) == 0);
202838414Smckusick 		}
202940296Smckusick 		m_freem(mrep);
203038414Smckusick 	}
203141905Smckusick 	/*
203268653Smckusick 	 * Fill last record, iff any, out to a multiple of DIRBLKSIZ
203341905Smckusick 	 * by increasing d_reclen for the last record.
203441905Smckusick 	 */
203568653Smckusick 	if (blksiz > 0) {
203668653Smckusick 		left = DIRBLKSIZ - blksiz;
203768653Smckusick 		dp->d_reclen += left;
203868653Smckusick 		uiop->uio_iov->iov_base += left;
203968653Smckusick 		uiop->uio_iov->iov_len -= left;
204068653Smckusick 		uiop->uio_offset += left;
204168653Smckusick 		uiop->uio_resid -= left;
204241905Smckusick 	}
204368653Smckusick 
204468653Smckusick 	/*
204568653Smckusick 	 * We are now either at the end of the directory or have filled the
204668653Smckusick 	 * block.
204768653Smckusick 	 */
204868653Smckusick 	if (bigenough)
204968653Smckusick 		dnp->n_direofoffset = uiop->uio_offset;
205068653Smckusick 	else {
205168653Smckusick 		if (uiop->uio_resid > 0)
205268653Smckusick 			printf("EEK! readdirrpc resid > 0\n");
205368653Smckusick 		cookiep = nfs_getcookie(dnp, uiop->uio_offset, 1);
205468653Smckusick 		*cookiep = cookie;
205568653Smckusick 	}
205640296Smckusick nfsmout:
205738414Smckusick 	return (error);
205838414Smckusick }
205938414Smckusick 
206052196Smckusick /*
206168653Smckusick  * NFS V3 readdir plus RPC. Used in place of nfs_readdirrpc().
206252196Smckusick  */
206352234Sheideman int
206468653Smckusick nfs_readdirplusrpc(vp, uiop, cred)
206552196Smckusick 	struct vnode *vp;
206652196Smckusick 	register struct uio *uiop;
206752196Smckusick 	struct ucred *cred;
206852196Smckusick {
206968653Smckusick 	register int len, left;
207054740Smckusick 	register struct dirent *dp;
207152196Smckusick 	register u_long *tl;
207252196Smckusick 	register caddr_t cp;
207368653Smckusick 	register long t1, t2;
207468653Smckusick 	register struct vnode *newvp;
207568653Smckusick 	register nfsuint64 *cookiep;
207668653Smckusick 	caddr_t bpos, dpos, cp2, dpossav1, dpossav2;
207768653Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2, *mdsav1, *mdsav2;
207852196Smckusick 	struct nameidata nami, *ndp = &nami;
207952317Sheideman 	struct componentname *cnp = &ndp->ni_cnd;
208068653Smckusick 	nfsuint64 cookie;
208168653Smckusick 	struct nfsmount *nmp = VFSTONFS(vp->v_mount);
208268653Smckusick 	struct nfsnode *dnp = VTONFS(vp), *np;
208368653Smckusick 	nfsfh_t *fhp;
208468653Smckusick 	u_quad_t frev, fileno;
208568653Smckusick 	int error = 0, tlen, more_dirs = 1, blksiz = 0, doit, bigenough = 1, i;
208668653Smckusick 	int cachable, attrflag, fhsize;
208752196Smckusick 
208868653Smckusick #ifndef nolint
208968653Smckusick 	dp = (struct dirent *)0;
209068653Smckusick #endif
209168653Smckusick #ifndef DIAGNOSTIC
209268653Smckusick 	if (uiop->uio_iovcnt != 1 || (uiop->uio_offset & (DIRBLKSIZ - 1)) ||
209368653Smckusick 		(uiop->uio_resid & (DIRBLKSIZ - 1)))
209468653Smckusick 		panic("nfs readdirplusrpc bad uio");
209568653Smckusick #endif
209652196Smckusick 	ndp->ni_dvp = vp;
209752196Smckusick 	newvp = NULLVP;
209868653Smckusick 
209952196Smckusick 	/*
210068653Smckusick 	 * If there is no cookie, assume end of directory.
210168653Smckusick 	 */
210268653Smckusick 	cookiep = nfs_getcookie(dnp, uiop->uio_offset, 0);
210368653Smckusick 	if (cookiep)
210468653Smckusick 		cookie = *cookiep;
210568653Smckusick 	else
210668653Smckusick 		return (0);
210768653Smckusick 	/*
210868653Smckusick 	 * Loop around doing readdir rpc's of size nm_readdirsize
210968653Smckusick 	 * truncated to a multiple of DIRBLKSIZ.
211052196Smckusick 	 * The stopping criteria is EOF or buffer full.
211152196Smckusick 	 */
211268653Smckusick 	while (more_dirs && bigenough) {
211368653Smckusick 		nfsstats.rpccnt[NFSPROC_READDIRPLUS]++;
211468653Smckusick 		nfsm_reqhead(vp, NFSPROC_READDIRPLUS,
211568653Smckusick 			NFSX_FH(1) + 6 * NFSX_UNSIGNED);
211668653Smckusick 		nfsm_fhtom(vp, 1);
211768653Smckusick  		nfsm_build(tl, u_long *, 6 * NFSX_UNSIGNED);
211868653Smckusick 		*tl++ = cookie.nfsuquad[0];
211968653Smckusick 		*tl++ = cookie.nfsuquad[1];
212068653Smckusick 		*tl++ = dnp->n_cookieverf.nfsuquad[0];
212168653Smckusick 		*tl++ = dnp->n_cookieverf.nfsuquad[1];
212268653Smckusick 		*tl++ = txdr_unsigned(nmp->nm_readdirsize);
212368653Smckusick 		*tl = txdr_unsigned(nmp->nm_rsize);
212468653Smckusick 		nfsm_request(vp, NFSPROC_READDIRPLUS, uiop->uio_procp, cred);
212568653Smckusick 		nfsm_postop_attr(vp, attrflag);
212668653Smckusick 		if (error) {
212768653Smckusick 			m_freem(mrep);
212868653Smckusick 			goto nfsmout;
212968653Smckusick 		}
213068653Smckusick 		nfsm_dissect(tl, u_long *, 3 * NFSX_UNSIGNED);
213168653Smckusick 		dnp->n_cookieverf.nfsuquad[0] = *tl++;
213268653Smckusick 		dnp->n_cookieverf.nfsuquad[1] = *tl++;
213352196Smckusick 		more_dirs = fxdr_unsigned(int, *tl);
213452196Smckusick 
213552196Smckusick 		/* loop thru the dir entries, doctoring them to 4bsd form */
213652196Smckusick 		while (more_dirs && bigenough) {
213768653Smckusick 			nfsm_dissect(tl, u_long *, 3 * NFSX_UNSIGNED);
213868653Smckusick 			fxdr_hyper(tl, &fileno);
213968653Smckusick 			len = fxdr_unsigned(int, *(tl + 2));
214052196Smckusick 			if (len <= 0 || len > NFS_MAXNAMLEN) {
214152196Smckusick 				error = EBADRPC;
214252196Smckusick 				m_freem(mrep);
214352196Smckusick 				goto nfsmout;
214452196Smckusick 			}
214568653Smckusick 			tlen = nfsm_rndup(len);
214668653Smckusick 			if (tlen == len)
214768653Smckusick 				tlen += 4;	/* To ensure null termination*/
214868653Smckusick 			left = DIRBLKSIZ - blksiz;
214968653Smckusick 			if ((tlen + DIRHDSIZ) > left) {
215068653Smckusick 				dp->d_reclen += left;
215168653Smckusick 				uiop->uio_iov->iov_base += left;
215268653Smckusick 				uiop->uio_iov->iov_len -= left;
215368653Smckusick 				uiop->uio_offset += left;
215468653Smckusick 				uiop->uio_resid -= left;
215568653Smckusick 				blksiz = 0;
215668653Smckusick 			}
215752196Smckusick 			if ((tlen + DIRHDSIZ) > uiop->uio_resid)
215852196Smckusick 				bigenough = 0;
215968653Smckusick 			if (bigenough) {
216054740Smckusick 				dp = (struct dirent *)uiop->uio_iov->iov_base;
216168653Smckusick 				dp->d_fileno = (int)fileno;
216252196Smckusick 				dp->d_namlen = len;
216352196Smckusick 				dp->d_reclen = tlen + DIRHDSIZ;
216468653Smckusick 				dp->d_type = DT_UNKNOWN;
216568653Smckusick 				blksiz += dp->d_reclen;
216668653Smckusick 				if (blksiz == DIRBLKSIZ)
216768653Smckusick 					blksiz = 0;
216868653Smckusick 				uiop->uio_offset += DIRHDSIZ;
216952196Smckusick 				uiop->uio_resid -= DIRHDSIZ;
217052196Smckusick 				uiop->uio_iov->iov_base += DIRHDSIZ;
217152196Smckusick 				uiop->uio_iov->iov_len -= DIRHDSIZ;
217252317Sheideman 				cnp->cn_nameptr = uiop->uio_iov->iov_base;
217352317Sheideman 				cnp->cn_namelen = len;
217452196Smckusick 				nfsm_mtouio(uiop, len);
217552196Smckusick 				cp = uiop->uio_iov->iov_base;
217652196Smckusick 				tlen -= len;
217768653Smckusick 				*cp = '\0';
217852196Smckusick 				uiop->uio_iov->iov_base += tlen;
217952196Smckusick 				uiop->uio_iov->iov_len -= tlen;
218068653Smckusick 				uiop->uio_offset += tlen;
218152196Smckusick 				uiop->uio_resid -= tlen;
218268653Smckusick 			} else
218368653Smckusick 				nfsm_adv(nfsm_rndup(len));
218468653Smckusick 			nfsm_dissect(tl, u_long *, 3 * NFSX_UNSIGNED);
218568653Smckusick 			if (bigenough) {
218668653Smckusick 				cookie.nfsuquad[0] = *tl++;
218768653Smckusick 				cookie.nfsuquad[1] = *tl++;
218868653Smckusick 			} else
218968653Smckusick 				tl += 2;
219068653Smckusick 
219168653Smckusick 			/*
219268653Smckusick 			 * Since the attributes are before the file handle
219368653Smckusick 			 * (sigh), we must skip over the attributes and then
219468653Smckusick 			 * come back and get them.
219568653Smckusick 			 */
219668653Smckusick 			attrflag = fxdr_unsigned(int, *tl);
219768653Smckusick 			if (attrflag) {
219868653Smckusick 			    dpossav1 = dpos;
219968653Smckusick 			    mdsav1 = md;
220068653Smckusick 			    nfsm_adv(NFSX_V3FATTR);
220168653Smckusick 			    nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
220268653Smckusick 			    doit = fxdr_unsigned(int, *tl);
220368653Smckusick 			    if (doit) {
220468653Smckusick 				nfsm_getfh(fhp, fhsize, 1);
220568653Smckusick 				if (NFS_CMPFH(dnp, fhp, fhsize)) {
220668653Smckusick 				    VREF(vp);
220768653Smckusick 				    newvp = vp;
220868653Smckusick 				    np = dnp;
220968653Smckusick 				} else {
221068653Smckusick 				    if (error = nfs_nget(vp->v_mount, fhp,
221168653Smckusick 					fhsize, &np))
221268653Smckusick 					doit = 0;
221368653Smckusick 				    else
221468653Smckusick 					newvp = NFSTOV(np);
221568653Smckusick 				}
221668653Smckusick 			    }
221768653Smckusick 			    if (doit) {
221868653Smckusick 				dpossav2 = dpos;
221968653Smckusick 				dpos = dpossav1;
222068653Smckusick 				mdsav2 = md;
222168653Smckusick 				md = mdsav1;
222268653Smckusick 				nfsm_loadattr(newvp, (struct vattr *)0);
222368653Smckusick 				dpos = dpossav2;
222468653Smckusick 				md = mdsav2;
222568653Smckusick 				dp->d_type =
222668653Smckusick 				    IFTODT(VTTOIF(np->n_vattr.va_type));
222768653Smckusick 				ndp->ni_vp = newvp;
222852317Sheideman 				cnp->cn_hash = 0;
222968653Smckusick 				for (cp = cnp->cn_nameptr, i = 1; i <= len;
223068653Smckusick 				    i++, cp++)
223168653Smckusick 				    cnp->cn_hash += (unsigned char)*cp * i;
223256927Smckusick 				if (cnp->cn_namelen <= NCHNAMLEN)
223357791Smckusick 				    cache_enter(ndp->ni_dvp, ndp->ni_vp, cnp);
223468653Smckusick 			    }
223552196Smckusick 			} else {
223668653Smckusick 			    /* Just skip over the file handle */
223768653Smckusick 			    nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
223868653Smckusick 			    i = fxdr_unsigned(int, *tl);
223968653Smckusick 			    nfsm_adv(nfsm_rndup(i));
224052196Smckusick 			}
224152196Smckusick 			if (newvp != NULLVP) {
224268653Smckusick 			    vrele(newvp);
224368653Smckusick 			    newvp = NULLVP;
224452196Smckusick 			}
224568653Smckusick 			nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
224652196Smckusick 			more_dirs = fxdr_unsigned(int, *tl);
224752196Smckusick 		}
224852196Smckusick 		/*
224952196Smckusick 		 * If at end of rpc data, get the eof boolean
225052196Smckusick 		 */
225152196Smckusick 		if (!more_dirs) {
225252196Smckusick 			nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
225352196Smckusick 			more_dirs = (fxdr_unsigned(int, *tl) == 0);
225452196Smckusick 		}
225552196Smckusick 		m_freem(mrep);
225652196Smckusick 	}
225752196Smckusick 	/*
225852196Smckusick 	 * Fill last record, iff any, out to a multiple of NFS_DIRBLKSIZ
225952196Smckusick 	 * by increasing d_reclen for the last record.
226052196Smckusick 	 */
226168653Smckusick 	if (blksiz > 0) {
226268653Smckusick 		left = DIRBLKSIZ - blksiz;
226368653Smckusick 		dp->d_reclen += left;
226468653Smckusick 		uiop->uio_iov->iov_base += left;
226568653Smckusick 		uiop->uio_iov->iov_len -= left;
226668653Smckusick 		uiop->uio_offset += left;
226768653Smckusick 		uiop->uio_resid -= left;
226852196Smckusick 	}
226968653Smckusick 
227068653Smckusick 	/*
227168653Smckusick 	 * We are now either at the end of the directory or have filled the
227268653Smckusick 	 * block.
227368653Smckusick 	 */
227468653Smckusick 	if (bigenough)
227568653Smckusick 		dnp->n_direofoffset = uiop->uio_offset;
227668653Smckusick 	else {
227768653Smckusick 		if (uiop->uio_resid > 0)
227868653Smckusick 			printf("EEK! readdirplusrpc resid > 0\n");
227968653Smckusick 		cookiep = nfs_getcookie(dnp, uiop->uio_offset, 1);
228068653Smckusick 		*cookiep = cookie;
228168653Smckusick 	}
228252196Smckusick nfsmout:
228352196Smckusick 	if (newvp != NULLVP)
228452196Smckusick 		vrele(newvp);
228552196Smckusick 	return (error);
228652196Smckusick }
228739488Smckusick static char hextoasc[] = "0123456789abcdef";
228838414Smckusick 
228938414Smckusick /*
229038414Smckusick  * Silly rename. To make the NFS filesystem that is stateless look a little
229138414Smckusick  * more like the "ufs" a remove of an active vnode is translated to a rename
229238414Smckusick  * to a funny looking filename that is removed by nfs_inactive on the
229338414Smckusick  * nfsnode. There is the potential for another process on a different client
229438414Smckusick  * to create the same funny name between the nfs_lookitup() fails and the
229538414Smckusick  * nfs_rename() completes, but...
229638414Smckusick  */
229752234Sheideman int
229852317Sheideman nfs_sillyrename(dvp, vp, cnp)
229952234Sheideman 	struct vnode *dvp, *vp;
230052234Sheideman 	struct componentname *cnp;
230138414Smckusick {
230238414Smckusick 	register struct sillyrename *sp;
230368653Smckusick 	struct nfsnode *np;
230438414Smckusick 	int error;
230538414Smckusick 	short pid;
230638414Smckusick 
230752234Sheideman 	cache_purge(dvp);
230852234Sheideman 	np = VTONFS(vp);
230968653Smckusick #ifndef DIAGNOSTIC
231068653Smckusick 	if (vp->v_type == VDIR)
231168653Smckusick 		panic("nfs: sillyrename dir");
231268653Smckusick #endif
231338414Smckusick 	MALLOC(sp, struct sillyrename *, sizeof (struct sillyrename),
231448364Smckusick 		M_NFSREQ, M_WAITOK);
231552234Sheideman 	sp->s_cred = crdup(cnp->cn_cred);
231652234Sheideman 	sp->s_dvp = dvp;
231752234Sheideman 	VREF(dvp);
231838414Smckusick 
231938414Smckusick 	/* Fudge together a funny name */
232052234Sheideman 	pid = cnp->cn_proc->p_pid;
232148364Smckusick 	bcopy(".nfsAxxxx4.4", sp->s_name, 13);
232248364Smckusick 	sp->s_namlen = 12;
232348364Smckusick 	sp->s_name[8] = hextoasc[pid & 0xf];
232448364Smckusick 	sp->s_name[7] = hextoasc[(pid >> 4) & 0xf];
232548364Smckusick 	sp->s_name[6] = hextoasc[(pid >> 8) & 0xf];
232648364Smckusick 	sp->s_name[5] = hextoasc[(pid >> 12) & 0xf];
232738414Smckusick 
232838414Smckusick 	/* Try lookitups until we get one that isn't there */
232968653Smckusick 	while (nfs_lookitup(dvp, sp->s_name, sp->s_namlen, sp->s_cred,
233068653Smckusick 		cnp->cn_proc, (struct nfsnode **)0) == 0) {
233148364Smckusick 		sp->s_name[4]++;
233248364Smckusick 		if (sp->s_name[4] > 'z') {
233338414Smckusick 			error = EINVAL;
233438414Smckusick 			goto bad;
233538414Smckusick 		}
233638414Smckusick 	}
233752234Sheideman 	if (error = nfs_renameit(dvp, cnp, sp))
233838414Smckusick 		goto bad;
233968653Smckusick 	error = nfs_lookitup(dvp, sp->s_name, sp->s_namlen, sp->s_cred,
234068653Smckusick 		cnp->cn_proc, &np);
234138414Smckusick 	np->n_sillyrename = sp;
234238414Smckusick 	return (0);
234338414Smckusick bad:
234448364Smckusick 	vrele(sp->s_dvp);
234548364Smckusick 	crfree(sp->s_cred);
234648364Smckusick 	free((caddr_t)sp, M_NFSREQ);
234738414Smckusick 	return (error);
234838414Smckusick }
234938414Smckusick 
235038414Smckusick /*
235168653Smckusick  * Look up a file name and optionally either update the file handle or
235268653Smckusick  * allocate an nfsnode, depending on the value of npp.
235368653Smckusick  * npp == NULL	--> just do the lookup
235468653Smckusick  * *npp == NULL --> allocate a new nfsnode and make sure attributes are
235568653Smckusick  *			handled too
235668653Smckusick  * *npp != NULL --> update the file handle in the vnode
235738414Smckusick  */
235852234Sheideman int
235968653Smckusick nfs_lookitup(dvp, name, len, cred, procp, npp)
236068653Smckusick 	register struct vnode *dvp;
236168653Smckusick 	char *name;
236268653Smckusick 	int len;
236368653Smckusick 	struct ucred *cred;
236452196Smckusick 	struct proc *procp;
236568653Smckusick 	struct nfsnode **npp;
236638414Smckusick {
236748054Smckusick 	register u_long *tl;
236839488Smckusick 	register caddr_t cp;
236939488Smckusick 	register long t1, t2;
237068653Smckusick 	struct vnode *newvp = (struct vnode *)0;
237168653Smckusick 	struct nfsnode *np, *dnp = VTONFS(dvp);
237239488Smckusick 	caddr_t bpos, dpos, cp2;
237368653Smckusick 	int error = 0, fhlen, attrflag;
237439488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
237568653Smckusick 	nfsfh_t *nfhp;
237668653Smckusick 	int v3 = NFS_ISV3(dvp);
237738414Smckusick 
237838414Smckusick 	nfsstats.rpccnt[NFSPROC_LOOKUP]++;
237968653Smckusick 	nfsm_reqhead(dvp, NFSPROC_LOOKUP,
238068653Smckusick 		NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(len));
238168653Smckusick 	nfsm_fhtom(dvp, v3);
238268653Smckusick 	nfsm_strtom(name, len, NFS_MAXNAMLEN);
238368653Smckusick 	nfsm_request(dvp, NFSPROC_LOOKUP, procp, cred);
238468653Smckusick 	if (npp && !error) {
238568653Smckusick 		nfsm_getfh(nfhp, fhlen, v3);
238668653Smckusick 		if (*npp) {
238768653Smckusick 		    np = *npp;
238868653Smckusick 		    if (np->n_fhsize > NFS_SMALLFH && fhlen <= NFS_SMALLFH) {
238968653Smckusick 			free((caddr_t)np->n_fhp, M_NFSBIGFH);
239068653Smckusick 			np->n_fhp = &np->n_fh;
239168653Smckusick 		    } else if (np->n_fhsize <= NFS_SMALLFH && fhlen>NFS_SMALLFH)
239268653Smckusick 			np->n_fhp =(nfsfh_t *)malloc(fhlen,M_NFSBIGFH,M_WAITOK);
239368653Smckusick 		    bcopy((caddr_t)nfhp, (caddr_t)np->n_fhp, fhlen);
239468653Smckusick 		    np->n_fhsize = fhlen;
239568653Smckusick 		    newvp = NFSTOV(np);
239668653Smckusick 		} else if (NFS_CMPFH(dnp, nfhp, fhlen)) {
239768653Smckusick 		    VREF(dvp);
239868653Smckusick 		    newvp = dvp;
239968653Smckusick 		} else {
240068653Smckusick 		    error = nfs_nget(dvp->v_mount, nfhp, fhlen, &np);
240168653Smckusick 		    if (error) {
240268653Smckusick 			m_freem(mrep);
240368653Smckusick 			return (error);
240468653Smckusick 		    }
240568653Smckusick 		    newvp = NFSTOV(np);
240668653Smckusick 		}
240768653Smckusick 		if (v3) {
240868653Smckusick 			nfsm_postop_attr(newvp, attrflag);
240968653Smckusick 			if (!attrflag && *npp == NULL) {
241068653Smckusick 				m_freem(mrep);
241168653Smckusick 				vrele(newvp);
241268653Smckusick 				return (ENOENT);
241368653Smckusick 			}
241468653Smckusick 		} else
241568653Smckusick 			nfsm_loadattr(newvp, (struct vattr *)0);
241656289Smckusick 	}
241768653Smckusick 	nfsm_reqdone;
241868653Smckusick 	if (npp && *npp == NULL) {
241968653Smckusick 		if (error) {
242068653Smckusick 			if (newvp)
242168653Smckusick 				vrele(newvp);
242268653Smckusick 		} else
242368653Smckusick 			*npp = np;
242438414Smckusick 	}
242568653Smckusick 	return (error);
242668653Smckusick }
242768653Smckusick 
242868653Smckusick /*
242968653Smckusick  * Nfs Version 3 commit rpc
243068653Smckusick  */
243168653Smckusick int
243268653Smckusick nfs_commit(vp, offset, cnt, cred, procp)
243368653Smckusick 	register struct vnode *vp;
243468653Smckusick 	u_quad_t offset;
243568653Smckusick 	int cnt;
243668653Smckusick 	struct ucred *cred;
243768653Smckusick 	struct proc *procp;
243868653Smckusick {
243968653Smckusick 	register caddr_t cp;
244068653Smckusick 	register u_long *tl;
244168653Smckusick 	register int t1, t2;
244268653Smckusick 	register struct nfsmount *nmp = VFSTONFS(vp->v_mount);
244368653Smckusick 	caddr_t bpos, dpos, cp2;
244468653Smckusick 	int error = 0, wccflag = NFSV3_WCCRATTR;
244568653Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
244668653Smckusick 
244768653Smckusick 	if ((nmp->nm_flag & NFSMNT_HASWRITEVERF) == 0)
244868653Smckusick 		return (0);
244968653Smckusick 	nfsstats.rpccnt[NFSPROC_COMMIT]++;
245068653Smckusick 	nfsm_reqhead(vp, NFSPROC_COMMIT, NFSX_FH(1));
245168653Smckusick 	nfsm_fhtom(vp, 1);
245268653Smckusick 	nfsm_build(tl, u_long *, 3 * NFSX_UNSIGNED);
245368653Smckusick 	txdr_hyper(&offset, tl);
245468653Smckusick 	tl += 2;
245568653Smckusick 	*tl = txdr_unsigned(cnt);
245668653Smckusick 	nfsm_request(vp, NFSPROC_COMMIT, procp, cred);
245768653Smckusick 	nfsm_wcc_data(vp, wccflag);
245868653Smckusick 	if (!error) {
245968653Smckusick 		nfsm_dissect(tl, u_long *, NFSX_V3WRITEVERF);
246068653Smckusick 		if (bcmp((caddr_t)nmp->nm_verf, (caddr_t)tl,
246168653Smckusick 			NFSX_V3WRITEVERF)) {
246268653Smckusick 			bcopy((caddr_t)tl, (caddr_t)nmp->nm_verf,
246368653Smckusick 				NFSX_V3WRITEVERF);
246468653Smckusick 			error = NFSERR_STALEWRITEVERF;
246568653Smckusick 		}
246668653Smckusick 	}
246738414Smckusick 	nfsm_reqdone;
246838414Smckusick 	return (error);
246938414Smckusick }
247038414Smckusick 
247138414Smckusick /*
247238414Smckusick  * Kludge City..
247338414Smckusick  * - make nfs_bmap() essentially a no-op that does no translation
247468653Smckusick  * - do nfs_strategy() by doing I/O with nfs_readrpc/nfs_writerpc
247538414Smckusick  *   (Maybe I could use the process's page mapping, but I was concerned that
247638414Smckusick  *    Kernel Write might not be enabled and also figured copyout() would do
247738414Smckusick  *    a lot more work than bcopy() and also it currently happens in the
247838414Smckusick  *    context of the swapper process (2).
247938414Smckusick  */
248052234Sheideman int
248153806Smckusick nfs_bmap(ap)
248254668Smckusick 	struct vop_bmap_args /* {
248354668Smckusick 		struct vnode *a_vp;
248454668Smckusick 		daddr_t  a_bn;
248554668Smckusick 		struct vnode **a_vpp;
248654668Smckusick 		daddr_t *a_bnp;
248756452Smargo 		int *a_runp;
248854668Smckusick 	} */ *ap;
248938414Smckusick {
249053806Smckusick 	register struct vnode *vp = ap->a_vp;
249153806Smckusick 
249253600Sheideman 	if (ap->a_vpp != NULL)
249353806Smckusick 		*ap->a_vpp = vp;
249453600Sheideman 	if (ap->a_bnp != NULL)
249553806Smckusick 		*ap->a_bnp = ap->a_bn * btodb(vp->v_mount->mnt_stat.f_iosize);
249638414Smckusick 	return (0);
249738414Smckusick }
249838414Smckusick 
249938414Smckusick /*
250057791Smckusick  * Strategy routine.
250157791Smckusick  * For async requests when nfsiod(s) are running, queue the request by
250257791Smckusick  * calling nfs_asyncio(), otherwise just all nfs_doio() to do the
250357791Smckusick  * request.
250438414Smckusick  */
250552234Sheideman int
250653806Smckusick nfs_strategy(ap)
250757791Smckusick 	struct vop_strategy_args *ap;
250838414Smckusick {
250953806Smckusick 	register struct buf *bp = ap->a_bp;
251057791Smckusick 	struct ucred *cr;
251157791Smckusick 	struct proc *p;
251238884Smacklem 	int error = 0;
251338884Smacklem 
251457791Smckusick 	if (bp->b_flags & B_PHYS)
251557791Smckusick 		panic("nfs physio");
251657791Smckusick 	if (bp->b_flags & B_ASYNC)
251757791Smckusick 		p = (struct proc *)0;
251857791Smckusick 	else
251957791Smckusick 		p = curproc;	/* XXX */
252057791Smckusick 	if (bp->b_flags & B_READ)
252157791Smckusick 		cr = bp->b_rcred;
252257791Smckusick 	else
252357791Smckusick 		cr = bp->b_wcred;
252438884Smacklem 	/*
252546450Skarels 	 * If the op is asynchronous and an i/o daemon is waiting
252638884Smacklem 	 * queue the request, wake it up and wait for completion
252746450Skarels 	 * otherwise just do it ourselves.
252838884Smacklem 	 */
252957791Smckusick 	if ((bp->b_flags & B_ASYNC) == 0 ||
253057791Smckusick 		nfs_asyncio(bp, NOCRED))
253157791Smckusick 		error = nfs_doio(bp, cr, p);
253238884Smacklem 	return (error);
253338884Smacklem }
253438884Smacklem 
253538884Smacklem /*
253648054Smckusick  * Mmap a file
253748054Smckusick  *
253848054Smckusick  * NB Currently unsupported.
253948054Smckusick  */
254048054Smckusick /* ARGSUSED */
254152234Sheideman int
254253806Smckusick nfs_mmap(ap)
254354668Smckusick 	struct vop_mmap_args /* {
254454668Smckusick 		struct vnode *a_vp;
254554668Smckusick 		int  a_fflags;
254654668Smckusick 		struct ucred *a_cred;
254754668Smckusick 		struct proc *a_p;
254854668Smckusick 	} */ *ap;
254948054Smckusick {
255048054Smckusick 
255148054Smckusick 	return (EINVAL);
255248054Smckusick }
255348054Smckusick 
255448054Smckusick /*
255568653Smckusick  * fsync vnode op. Just call nfs_flush() with commit == 1.
255638884Smacklem  */
255739488Smckusick /* ARGSUSED */
255852234Sheideman int
255953806Smckusick nfs_fsync(ap)
256054451Smckusick 	struct vop_fsync_args /* {
256154451Smckusick 		struct vnodeop_desc *a_desc;
256254451Smckusick 		struct vnode * a_vp;
256354451Smckusick 		struct ucred * a_cred;
256454451Smckusick 		int  a_waitfor;
256554451Smckusick 		struct proc * a_p;
256654451Smckusick 	} */ *ap;
256738884Smacklem {
256868653Smckusick 
256968653Smckusick 	return (nfs_flush(ap->a_vp, ap->a_cred, ap->a_waitfor, ap->a_p, 1));
257068653Smckusick }
257168653Smckusick 
257268653Smckusick /*
257368653Smckusick  * Flush all the blocks associated with a vnode.
257468653Smckusick  * 	Walk through the buffer pool and push any dirty pages
257568653Smckusick  *	associated with the vnode.
257668653Smckusick  */
257768653Smckusick int
257868653Smckusick nfs_flush(vp, cred, waitfor, p, commit)
257968653Smckusick 	register struct vnode *vp;
258068653Smckusick 	struct ucred *cred;
258168653Smckusick 	int waitfor;
258268653Smckusick 	struct proc *p;
258368653Smckusick 	int commit;
258468653Smckusick {
258554451Smckusick 	register struct nfsnode *np = VTONFS(vp);
258654451Smckusick 	register struct buf *bp;
258768653Smckusick 	register int i;
258854451Smckusick 	struct buf *nbp;
258968653Smckusick 	struct nfsmount *nmp = VFSTONFS(vp->v_mount);
259068653Smckusick 	int s, error = 0, slptimeo = 0, slpflag = 0, retv, bvecpos;
259168653Smckusick 	int passone = 1;
259268653Smckusick 	u_quad_t off = (u_quad_t)-1, endoff = 0, toff;
259368653Smckusick #ifndef NFS_COMMITBVECSIZ
259468653Smckusick #define NFS_COMMITBVECSIZ	20
259568653Smckusick #endif
259668653Smckusick 	struct buf *bvec[NFS_COMMITBVECSIZ];
259738884Smacklem 
259857791Smckusick 	if (nmp->nm_flag & NFSMNT_INT)
259957791Smckusick 		slpflag = PCATCH;
260068653Smckusick 	if (!commit)
260168653Smckusick 		passone = 0;
260268653Smckusick 	/*
260368653Smckusick 	 * A b_flags == (B_DELWRI | B_NEEDCOMMIT) block has been written to the
260468653Smckusick 	 * server, but nas not been committed to stable storage on the server
260568653Smckusick 	 * yet. On the first pass, the byte range is worked out and the commit
260668653Smckusick 	 * rpc is done. On the second pass, nfs_writebp() is called to do the
260768653Smckusick 	 * job.
260868653Smckusick 	 */
260968653Smckusick again:
261068653Smckusick 	bvecpos = 0;
261168653Smckusick 	if (NFS_ISV3(vp) && commit) {
261268653Smckusick 		s = splbio();
261368653Smckusick 		for (bp = vp->v_dirtyblkhd.lh_first; bp; bp = nbp) {
261468653Smckusick 			nbp = bp->b_vnbufs.le_next;
261568653Smckusick 			if (bvecpos >= NFS_COMMITBVECSIZ)
261668653Smckusick 				break;
261768653Smckusick 			if ((bp->b_flags & (B_BUSY | B_DELWRI | B_NEEDCOMMIT))
261868653Smckusick 				!= (B_DELWRI | B_NEEDCOMMIT))
261968653Smckusick 				continue;
262068653Smckusick 			bremfree(bp);
262168653Smckusick 			bp->b_flags |= (B_BUSY | B_WRITEINPROG);
262268653Smckusick 			/*
262368653Smckusick 			 * A list of these buffers is kept so that the
262468653Smckusick 			 * second loop knows which buffers have actually
262568653Smckusick 			 * been committed. This is necessary, since there
262668653Smckusick 			 * may be a race between the commit rpc and new
262768653Smckusick 			 * uncommitted writes on the file.
262868653Smckusick 			 */
262968653Smckusick 			bvec[bvecpos++] = bp;
263068653Smckusick 			toff = ((u_quad_t)bp->b_blkno) * DEV_BSIZE +
263168653Smckusick 				bp->b_dirtyoff;
263268653Smckusick 			if (toff < off)
263368653Smckusick 				off = toff;
263468653Smckusick 			toff += (u_quad_t)(bp->b_dirtyend - bp->b_dirtyoff);
263568653Smckusick 			if (toff > endoff)
263668653Smckusick 				endoff = toff;
263768653Smckusick 		}
263868653Smckusick 		splx(s);
263968653Smckusick 	}
264068653Smckusick 	if (bvecpos > 0) {
264168653Smckusick 		/*
264268653Smckusick 		 * Commit data on the server, as required.
264368653Smckusick 		 */
264468653Smckusick 		retv = nfs_commit(vp, off, (int)(endoff - off), cred, p);
264568653Smckusick 		if (retv == NFSERR_STALEWRITEVERF)
264668653Smckusick 			nfs_clearcommit(vp->v_mount);
264768653Smckusick 		/*
264868653Smckusick 		 * Now, either mark the blocks I/O done or mark the
264968653Smckusick 		 * blocks dirty, depending on whether the commit
265068653Smckusick 		 * succeeded.
265168653Smckusick 		 */
265268653Smckusick 		for (i = 0; i < bvecpos; i++) {
265368653Smckusick 			bp = bvec[i];
265468653Smckusick 			bp->b_flags &= ~(B_NEEDCOMMIT | B_WRITEINPROG);
265568653Smckusick 			if (retv) {
265668653Smckusick 			    brelse(bp);
265768653Smckusick 			} else {
265868653Smckusick 			    vp->v_numoutput++;
265968653Smckusick 			    bp->b_flags |= B_ASYNC;
266068653Smckusick 			    bp->b_flags &= ~(B_READ|B_DONE|B_ERROR|B_DELWRI);
266168653Smckusick 			    bp->b_dirtyoff = bp->b_dirtyend = 0;
266268653Smckusick 			    reassignbuf(bp, vp);
266368653Smckusick 			    biodone(bp);
266468653Smckusick 			}
266568653Smckusick 		}
266668653Smckusick 	}
266768653Smckusick 
266868653Smckusick 	/*
266968653Smckusick 	 * Start/do any write(s) that are required.
267068653Smckusick 	 */
267154451Smckusick loop:
267254451Smckusick 	s = splbio();
267365252Smckusick 	for (bp = vp->v_dirtyblkhd.lh_first; bp; bp = nbp) {
267465252Smckusick 		nbp = bp->b_vnbufs.le_next;
267557791Smckusick 		if (bp->b_flags & B_BUSY) {
267668653Smckusick 			if (waitfor != MNT_WAIT || passone)
267757791Smckusick 				continue;
267857791Smckusick 			bp->b_flags |= B_WANTED;
267957791Smckusick 			error = tsleep((caddr_t)bp, slpflag | (PRIBIO + 1),
268057791Smckusick 				"nfsfsync", slptimeo);
268157791Smckusick 			splx(s);
268257791Smckusick 			if (error) {
268368653Smckusick 			    if (nfs_sigintr(nmp, (struct nfsreq *)0, p))
268457791Smckusick 				return (EINTR);
268557791Smckusick 			    if (slpflag == PCATCH) {
268657791Smckusick 				slpflag = 0;
268757791Smckusick 				slptimeo = 2 * hz;
268857791Smckusick 			    }
268957791Smckusick 			}
269057791Smckusick 			goto loop;
269157791Smckusick 		}
269254451Smckusick 		if ((bp->b_flags & B_DELWRI) == 0)
269354451Smckusick 			panic("nfs_fsync: not dirty");
269468653Smckusick 		if ((passone || !commit) && (bp->b_flags & B_NEEDCOMMIT))
269568653Smckusick 			continue;
269654451Smckusick 		bremfree(bp);
269768653Smckusick 		if (passone || !commit)
269868653Smckusick 		    bp->b_flags |= (B_BUSY|B_ASYNC);
269968653Smckusick 		else
270068653Smckusick 		    bp->b_flags |= (B_BUSY|B_ASYNC|B_WRITEINPROG|B_NEEDCOMMIT);
270154451Smckusick 		splx(s);
270257791Smckusick 		VOP_BWRITE(bp);
270354451Smckusick 		goto loop;
270438884Smacklem 	}
270557791Smckusick 	splx(s);
270668653Smckusick 	if (passone) {
270768653Smckusick 		passone = 0;
270868653Smckusick 		goto again;
270968653Smckusick 	}
271068653Smckusick 	if (waitfor == MNT_WAIT) {
271154451Smckusick 		while (vp->v_numoutput) {
271254451Smckusick 			vp->v_flag |= VBWAIT;
271357791Smckusick 			error = tsleep((caddr_t)&vp->v_numoutput,
271457791Smckusick 				slpflag | (PRIBIO + 1), "nfsfsync", slptimeo);
271557791Smckusick 			if (error) {
271668653Smckusick 			    if (nfs_sigintr(nmp, (struct nfsreq *)0, p))
271757791Smckusick 				return (EINTR);
271857791Smckusick 			    if (slpflag == PCATCH) {
271957791Smckusick 				slpflag = 0;
272057791Smckusick 				slptimeo = 2 * hz;
272157791Smckusick 			    }
272257791Smckusick 			}
272354451Smckusick 		}
272468653Smckusick 		if (vp->v_dirtyblkhd.lh_first && commit) {
272568653Smckusick #ifndef DIAGNOSTIC
272654451Smckusick 			vprint("nfs_fsync: dirty", vp);
272757791Smckusick #endif
272854451Smckusick 			goto loop;
272954451Smckusick 		}
273054451Smckusick 	}
273153629Smckusick 	if (np->n_flag & NWRITEERR) {
273239751Smckusick 		error = np->n_error;
273353629Smckusick 		np->n_flag &= ~NWRITEERR;
273453629Smckusick 	}
273538884Smacklem 	return (error);
273638884Smacklem }
273739672Smckusick 
273839672Smckusick /*
273960400Smckusick  * Return POSIX pathconf information applicable to nfs.
274060400Smckusick  *
274168653Smckusick  * The NFS V2 protocol doesn't support this, so just return EINVAL
274268653Smckusick  * for V2.
274360400Smckusick  */
274460400Smckusick /* ARGSUSED */
274568653Smckusick int
274660400Smckusick nfs_pathconf(ap)
274760400Smckusick 	struct vop_pathconf_args /* {
274860400Smckusick 		struct vnode *a_vp;
274960400Smckusick 		int a_name;
275060400Smckusick 		int *a_retval;
275160400Smckusick 	} */ *ap;
275260400Smckusick {
275360400Smckusick 
275460400Smckusick 	return (EINVAL);
275560400Smckusick }
275660400Smckusick 
275760400Smckusick /*
275846201Smckusick  * NFS advisory byte-level locks.
275946201Smckusick  * Currently unsupported.
276046201Smckusick  */
276152234Sheideman int
276253806Smckusick nfs_advlock(ap)
276354668Smckusick 	struct vop_advlock_args /* {
276454668Smckusick 		struct vnode *a_vp;
276554668Smckusick 		caddr_t  a_id;
276654668Smckusick 		int  a_op;
276754668Smckusick 		struct flock *a_fl;
276854668Smckusick 		int  a_flags;
276954668Smckusick 	} */ *ap;
277046201Smckusick {
277146201Smckusick 
277246201Smckusick 	return (EOPNOTSUPP);
277346201Smckusick }
277446201Smckusick 
277546201Smckusick /*
277639672Smckusick  * Print out the contents of an nfsnode.
277739672Smckusick  */
277852234Sheideman int
277953806Smckusick nfs_print(ap)
278054668Smckusick 	struct vop_print_args /* {
278154668Smckusick 		struct vnode *a_vp;
278254668Smckusick 	} */ *ap;
278339672Smckusick {
278453806Smckusick 	register struct vnode *vp = ap->a_vp;
278553806Smckusick 	register struct nfsnode *np = VTONFS(vp);
278639672Smckusick 
278768653Smckusick 	printf("tag VT_NFS, fileid %ld fsid 0x%lx",
278840294Smckusick 		np->n_vattr.va_fileid, np->n_vattr.va_fsid);
278953806Smckusick 	if (vp->v_type == VFIFO)
279053806Smckusick 		fifo_printinfo(vp);
279139914Smckusick 	printf("\n");
279268653Smckusick 	return (0);
279339672Smckusick }
279451573Smckusick 
279551573Smckusick /*
279651573Smckusick  * NFS directory offset lookup.
279751573Smckusick  * Currently unsupported.
279851573Smckusick  */
279952234Sheideman int
280053806Smckusick nfs_blkatoff(ap)
280154668Smckusick 	struct vop_blkatoff_args /* {
280254668Smckusick 		struct vnode *a_vp;
280354668Smckusick 		off_t a_offset;
280454668Smckusick 		char **a_res;
280554668Smckusick 		struct buf **a_bpp;
280654668Smckusick 	} */ *ap;
280751573Smckusick {
280851573Smckusick 
280951573Smckusick 	return (EOPNOTSUPP);
281051573Smckusick }
281151573Smckusick 
281251573Smckusick /*
281351573Smckusick  * NFS flat namespace allocation.
281451573Smckusick  * Currently unsupported.
281551573Smckusick  */
281652234Sheideman int
281753806Smckusick nfs_valloc(ap)
281854668Smckusick 	struct vop_valloc_args /* {
281954668Smckusick 		struct vnode *a_pvp;
282054668Smckusick 		int a_mode;
282154668Smckusick 		struct ucred *a_cred;
282254668Smckusick 		struct vnode **a_vpp;
282354668Smckusick 	} */ *ap;
282451573Smckusick {
282551573Smckusick 
282651573Smckusick 	return (EOPNOTSUPP);
282751573Smckusick }
282851573Smckusick 
282951573Smckusick /*
283051573Smckusick  * NFS flat namespace free.
283151573Smckusick  * Currently unsupported.
283251573Smckusick  */
283353582Sheideman int
283453806Smckusick nfs_vfree(ap)
283554668Smckusick 	struct vop_vfree_args /* {
283654668Smckusick 		struct vnode *a_pvp;
283754668Smckusick 		ino_t a_ino;
283854668Smckusick 		int a_mode;
283954668Smckusick 	} */ *ap;
284051573Smckusick {
284151573Smckusick 
284253582Sheideman 	return (EOPNOTSUPP);
284351573Smckusick }
284451573Smckusick 
284551573Smckusick /*
284651573Smckusick  * NFS file truncation.
284751573Smckusick  */
284852234Sheideman int
284953806Smckusick nfs_truncate(ap)
285054668Smckusick 	struct vop_truncate_args /* {
285154668Smckusick 		struct vnode *a_vp;
285254668Smckusick 		off_t a_length;
285354668Smckusick 		int a_flags;
285454668Smckusick 		struct ucred *a_cred;
285554668Smckusick 		struct proc *a_p;
285654668Smckusick 	} */ *ap;
285751573Smckusick {
285851573Smckusick 
285951573Smckusick 	/* Use nfs_setattr */
286051573Smckusick 	printf("nfs_truncate: need to implement!!");
286151573Smckusick 	return (EOPNOTSUPP);
286251573Smckusick }
286351573Smckusick 
286451573Smckusick /*
286551573Smckusick  * NFS update.
286651573Smckusick  */
286752234Sheideman int
286853806Smckusick nfs_update(ap)
286954668Smckusick 	struct vop_update_args /* {
287054668Smckusick 		struct vnode *a_vp;
287154668Smckusick 		struct timeval *a_ta;
287254668Smckusick 		struct timeval *a_tm;
287354668Smckusick 		int a_waitfor;
287454668Smckusick 	} */ *ap;
287551573Smckusick {
287651573Smckusick 
287751573Smckusick 	/* Use nfs_setattr */
287851573Smckusick 	printf("nfs_update: need to implement!!");
287951573Smckusick 	return (EOPNOTSUPP);
288051573Smckusick }
288153629Smckusick 
288253629Smckusick /*
288368653Smckusick  * Just call nfs_writebp() with the force argument set to 1.
288468653Smckusick  */
288568653Smckusick int
288668653Smckusick nfs_bwrite(ap)
288768653Smckusick 	struct vop_bwrite_args /* {
288868653Smckusick 		struct vnode *a_bp;
288968653Smckusick 	} */ *ap;
289068653Smckusick {
289168653Smckusick 
289268653Smckusick 	return (nfs_writebp(ap->a_bp, 1));
289368653Smckusick }
289468653Smckusick 
289568653Smckusick /*
289668653Smckusick  * This is a clone of vn_bwrite(), except that B_WRITEINPROG isn't set unless
289768653Smckusick  * the force flag is one and it also handles the B_NEEDCOMMIT flag.
289868653Smckusick  */
289968653Smckusick int
290068653Smckusick nfs_writebp(bp, force)
290168653Smckusick 	register struct buf *bp;
290268653Smckusick 	int force;
290368653Smckusick {
290468653Smckusick 	register int oldflags = bp->b_flags, retv = 1;
290568653Smckusick 	register struct proc *p = curproc;	/* XXX */
290668653Smckusick 	off_t off;
290768653Smckusick 
290868653Smckusick 	if(!(bp->b_flags & B_BUSY))
290968653Smckusick 		panic("bwrite: buffer is not busy???");
291068653Smckusick 
291168653Smckusick 	bp->b_flags &= ~(B_READ|B_DONE|B_ERROR|B_DELWRI);
291268653Smckusick 
291368653Smckusick 	if (oldflags & B_ASYNC) {
291468653Smckusick 		if (oldflags & B_DELWRI) {
291568653Smckusick 			reassignbuf(bp, bp->b_vp);
291668653Smckusick 		} else if (p) {
291768653Smckusick 			++p->p_stats->p_ru.ru_oublock;
291868653Smckusick 		}
291968653Smckusick 	}
292068653Smckusick 	bp->b_vp->v_numoutput++;
292168653Smckusick 
292268653Smckusick 	/*
292368653Smckusick 	 * If B_NEEDCOMMIT is set, a commit rpc may do the trick. If not
292468653Smckusick 	 * an actual write will have to be scheduled via. VOP_STRATEGY().
292568653Smckusick 	 * If B_WRITEINPROG is already set, then push it with a write anyhow.
292668653Smckusick 	 */
292768653Smckusick 	if (oldflags & (B_NEEDCOMMIT | B_WRITEINPROG) == B_NEEDCOMMIT) {
292868653Smckusick 		off = ((u_quad_t)bp->b_blkno) * DEV_BSIZE + bp->b_dirtyoff;
292968653Smckusick 		bp->b_flags |= B_WRITEINPROG;
293068653Smckusick 		retv = nfs_commit(bp->b_vp, off, bp->b_dirtyend-bp->b_dirtyoff,
293168653Smckusick 			bp->b_wcred, bp->b_proc);
293268653Smckusick 		bp->b_flags &= ~B_WRITEINPROG;
293368653Smckusick 		if (!retv) {
293468653Smckusick 			bp->b_dirtyoff = bp->b_dirtyend = 0;
293568653Smckusick 			bp->b_flags &= ~B_NEEDCOMMIT;
293668653Smckusick 			biodone(bp);
293768653Smckusick 		} else if (retv == NFSERR_STALEWRITEVERF)
293868653Smckusick 			nfs_clearcommit(bp->b_vp->v_mount);
293968653Smckusick 	}
294068653Smckusick 	if (retv) {
294168653Smckusick 		if (force)
294268653Smckusick 			bp->b_flags |= B_WRITEINPROG;
294368653Smckusick 		VOP_STRATEGY(bp);
294468653Smckusick 	}
294568653Smckusick 
294668653Smckusick 	if( (oldflags & B_ASYNC) == 0) {
294768653Smckusick 		int rtval = biowait(bp);
294868653Smckusick 		if (oldflags & B_DELWRI) {
294968653Smckusick 			reassignbuf(bp, bp->b_vp);
295068653Smckusick 		} else if (p) {
295168653Smckusick 			++p->p_stats->p_ru.ru_oublock;
295268653Smckusick 		}
295368653Smckusick 		brelse(bp);
295468653Smckusick 		return (rtval);
295568653Smckusick 	}
295668653Smckusick 
295768653Smckusick 	return (0);
295868653Smckusick }
295968653Smckusick 
296068653Smckusick /*
296156364Smckusick  * nfs special file access vnode op.
296256364Smckusick  * Essentially just get vattr and then imitate iaccess() since the device is
296356364Smckusick  * local to the client.
296456364Smckusick  */
296556364Smckusick int
296656364Smckusick nfsspec_access(ap)
296756364Smckusick 	struct vop_access_args /* {
296856364Smckusick 		struct vnode *a_vp;
296956364Smckusick 		int  a_mode;
297056364Smckusick 		struct ucred *a_cred;
297156364Smckusick 		struct proc *a_p;
297256364Smckusick 	} */ *ap;
297356364Smckusick {
297456364Smckusick 	register struct vattr *vap;
297556364Smckusick 	register gid_t *gp;
297656364Smckusick 	register struct ucred *cred = ap->a_cred;
297756364Smckusick 	mode_t mode = ap->a_mode;
297856364Smckusick 	struct vattr vattr;
297956364Smckusick 	register int i;
298056364Smckusick 	int error;
298156364Smckusick 
298256364Smckusick 	/*
298356364Smckusick 	 * If you're the super-user,
298456364Smckusick 	 * you always get access.
298556364Smckusick 	 */
298656364Smckusick 	if (cred->cr_uid == 0)
298756364Smckusick 		return (0);
298856364Smckusick 	vap = &vattr;
298968653Smckusick 	error = VOP_GETATTR(ap->a_vp, vap, cred, ap->a_p);
299068653Smckusick 	if (error)
299156364Smckusick 		return (error);
299256364Smckusick 	/*
299356364Smckusick 	 * Access check is based on only one of owner, group, public.
299456364Smckusick 	 * If not owner, then check group. If not a member of the
299556364Smckusick 	 * group, then check public access.
299656364Smckusick 	 */
299756364Smckusick 	if (cred->cr_uid != vap->va_uid) {
299856364Smckusick 		mode >>= 3;
299956364Smckusick 		gp = cred->cr_groups;
300056364Smckusick 		for (i = 0; i < cred->cr_ngroups; i++, gp++)
300156364Smckusick 			if (vap->va_gid == *gp)
300256364Smckusick 				goto found;
300356364Smckusick 		mode >>= 3;
300456364Smckusick found:
300556364Smckusick 		;
300656364Smckusick 	}
300768653Smckusick 	error = (vap->va_mode & mode) == mode ? 0 : EACCES;
300868653Smckusick 	return (error);
300956364Smckusick }
301056364Smckusick 
301156364Smckusick /*
301253629Smckusick  * Read wrapper for special devices.
301353629Smckusick  */
301453629Smckusick int
301553629Smckusick nfsspec_read(ap)
301654668Smckusick 	struct vop_read_args /* {
301754668Smckusick 		struct vnode *a_vp;
301854668Smckusick 		struct uio *a_uio;
301954668Smckusick 		int  a_ioflag;
302054668Smckusick 		struct ucred *a_cred;
302154668Smckusick 	} */ *ap;
302253629Smckusick {
302354032Smckusick 	register struct nfsnode *np = VTONFS(ap->a_vp);
302453629Smckusick 
302553629Smckusick 	/*
302653629Smckusick 	 * Set access flag.
302753629Smckusick 	 */
302854032Smckusick 	np->n_flag |= NACC;
302968653Smckusick 	np->n_atim.ts_sec = time.tv_sec;
303068653Smckusick 	np->n_atim.ts_nsec = time.tv_usec * 1000;
303153629Smckusick 	return (VOCALL(spec_vnodeop_p, VOFFSET(vop_read), ap));
303253629Smckusick }
303353629Smckusick 
303453629Smckusick /*
303553629Smckusick  * Write wrapper for special devices.
303653629Smckusick  */
303753629Smckusick int
303853629Smckusick nfsspec_write(ap)
303954668Smckusick 	struct vop_write_args /* {
304054668Smckusick 		struct vnode *a_vp;
304154668Smckusick 		struct uio *a_uio;
304254668Smckusick 		int  a_ioflag;
304354668Smckusick 		struct ucred *a_cred;
304454668Smckusick 	} */ *ap;
304553629Smckusick {
304654032Smckusick 	register struct nfsnode *np = VTONFS(ap->a_vp);
304753629Smckusick 
304853629Smckusick 	/*
304954032Smckusick 	 * Set update flag.
305053629Smckusick 	 */
305154032Smckusick 	np->n_flag |= NUPD;
305268653Smckusick 	np->n_mtim.ts_sec = time.tv_sec;
305368653Smckusick 	np->n_mtim.ts_nsec = time.tv_usec * 1000;
305453629Smckusick 	return (VOCALL(spec_vnodeop_p, VOFFSET(vop_write), ap));
305553629Smckusick }
305653629Smckusick 
305753629Smckusick /*
305853629Smckusick  * Close wrapper for special devices.
305953629Smckusick  *
306053629Smckusick  * Update the times on the nfsnode then do device close.
306153629Smckusick  */
306253629Smckusick int
306353629Smckusick nfsspec_close(ap)
306454668Smckusick 	struct vop_close_args /* {
306554668Smckusick 		struct vnode *a_vp;
306654668Smckusick 		int  a_fflag;
306754668Smckusick 		struct ucred *a_cred;
306854668Smckusick 		struct proc *a_p;
306954668Smckusick 	} */ *ap;
307053629Smckusick {
307153806Smckusick 	register struct vnode *vp = ap->a_vp;
307253806Smckusick 	register struct nfsnode *np = VTONFS(vp);
307353629Smckusick 	struct vattr vattr;
307453629Smckusick 
307553629Smckusick 	if (np->n_flag & (NACC | NUPD)) {
307653629Smckusick 		np->n_flag |= NCHG;
307753806Smckusick 		if (vp->v_usecount == 1 &&
307853806Smckusick 		    (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) {
307953629Smckusick 			VATTR_NULL(&vattr);
308068653Smckusick 			if (np->n_flag & NACC)
308168653Smckusick 				vattr.va_atime = np->n_atim;
308268653Smckusick 			if (np->n_flag & NUPD)
308368653Smckusick 				vattr.va_mtime = np->n_mtim;
308453806Smckusick 			(void)VOP_SETATTR(vp, &vattr, ap->a_cred, ap->a_p);
308553629Smckusick 		}
308653629Smckusick 	}
308753629Smckusick 	return (VOCALL(spec_vnodeop_p, VOFFSET(vop_close), ap));
308853629Smckusick }
308953629Smckusick 
309053629Smckusick /*
309153629Smckusick  * Read wrapper for fifos.
309253629Smckusick  */
309353629Smckusick int
309453629Smckusick nfsfifo_read(ap)
309554668Smckusick 	struct vop_read_args /* {
309654668Smckusick 		struct vnode *a_vp;
309754668Smckusick 		struct uio *a_uio;
309854668Smckusick 		int  a_ioflag;
309954668Smckusick 		struct ucred *a_cred;
310054668Smckusick 	} */ *ap;
310153629Smckusick {
310253629Smckusick 	extern int (**fifo_vnodeop_p)();
310354032Smckusick 	register struct nfsnode *np = VTONFS(ap->a_vp);
310453629Smckusick 
310553629Smckusick 	/*
310653629Smckusick 	 * Set access flag.
310753629Smckusick 	 */
310854032Smckusick 	np->n_flag |= NACC;
310968653Smckusick 	np->n_atim.ts_sec = time.tv_sec;
311068653Smckusick 	np->n_atim.ts_nsec = time.tv_usec * 1000;
311153629Smckusick 	return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_read), ap));
311253629Smckusick }
311353629Smckusick 
311453629Smckusick /*
311553629Smckusick  * Write wrapper for fifos.
311653629Smckusick  */
311753629Smckusick int
311853629Smckusick nfsfifo_write(ap)
311954668Smckusick 	struct vop_write_args /* {
312054668Smckusick 		struct vnode *a_vp;
312154668Smckusick 		struct uio *a_uio;
312254668Smckusick 		int  a_ioflag;
312354668Smckusick 		struct ucred *a_cred;
312454668Smckusick 	} */ *ap;
312553629Smckusick {
312653629Smckusick 	extern int (**fifo_vnodeop_p)();
312754032Smckusick 	register struct nfsnode *np = VTONFS(ap->a_vp);
312853629Smckusick 
312953629Smckusick 	/*
313053629Smckusick 	 * Set update flag.
313153629Smckusick 	 */
313254032Smckusick 	np->n_flag |= NUPD;
313368653Smckusick 	np->n_mtim.ts_sec = time.tv_sec;
313468653Smckusick 	np->n_mtim.ts_nsec = time.tv_usec * 1000;
313553629Smckusick 	return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_write), ap));
313653629Smckusick }
313753629Smckusick 
313853629Smckusick /*
313953629Smckusick  * Close wrapper for fifos.
314053629Smckusick  *
314153629Smckusick  * Update the times on the nfsnode then do fifo close.
314253629Smckusick  */
314353629Smckusick int
314453629Smckusick nfsfifo_close(ap)
314554668Smckusick 	struct vop_close_args /* {
314654668Smckusick 		struct vnode *a_vp;
314754668Smckusick 		int  a_fflag;
314854668Smckusick 		struct ucred *a_cred;
314954668Smckusick 		struct proc *a_p;
315054668Smckusick 	} */ *ap;
315153629Smckusick {
315253806Smckusick 	register struct vnode *vp = ap->a_vp;
315353806Smckusick 	register struct nfsnode *np = VTONFS(vp);
315453629Smckusick 	struct vattr vattr;
315553629Smckusick 	extern int (**fifo_vnodeop_p)();
315653629Smckusick 
315753629Smckusick 	if (np->n_flag & (NACC | NUPD)) {
315868653Smckusick 		if (np->n_flag & NACC) {
315968653Smckusick 			np->n_atim.ts_sec = time.tv_sec;
316068653Smckusick 			np->n_atim.ts_nsec = time.tv_usec * 1000;
316168653Smckusick 		}
316268653Smckusick 		if (np->n_flag & NUPD) {
316368653Smckusick 			np->n_mtim.ts_sec = time.tv_sec;
316468653Smckusick 			np->n_mtim.ts_nsec = time.tv_usec * 1000;
316568653Smckusick 		}
316653629Smckusick 		np->n_flag |= NCHG;
316753806Smckusick 		if (vp->v_usecount == 1 &&
316853806Smckusick 		    (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) {
316953629Smckusick 			VATTR_NULL(&vattr);
317068653Smckusick 			if (np->n_flag & NACC)
317168653Smckusick 				vattr.va_atime = np->n_atim;
317268653Smckusick 			if (np->n_flag & NUPD)
317368653Smckusick 				vattr.va_mtime = np->n_mtim;
317453806Smckusick 			(void)VOP_SETATTR(vp, &vattr, ap->a_cred, ap->a_p);
317553629Smckusick 		}
317653629Smckusick 	}
317753629Smckusick 	return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_close), ap));
317853629Smckusick }
3179