xref: /csrg-svn/sys/nfs/nfs_vnops.c (revision 68653)
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*68653Smckusick  *	@(#)nfs_vnops.c	8.14 (Berkeley) 03/30/95
1138414Smckusick  */
1238414Smckusick 
13*68653Smckusick 
1438414Smckusick /*
15*68653Smckusick  * 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>
21*68653Smckusick #include <sys/resourcevar.h>
22*68653Smckusick #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>
31*68653Smckusick #include <sys/fcntl.h>
32*68653Smckusick #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>
40*68653Smckusick #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 
48*68653Smckusick #include <net/if.h>
49*68653Smckusick #include <netinet/in.h>
50*68653Smckusick #include <netinet/in_var.h>
51*68653Smckusick 
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 */
104*68653Smckusick 	{ &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();
216*68653Smckusick int nfs_commit();
21756289Smckusick 
21848054Smckusick /*
21952196Smckusick  * Global variables
22048054Smckusick  */
221*68653Smckusick extern u_long nfs_true, nfs_false;
222*68653Smckusick extern struct nfsstats nfsstats;
223*68653Smckusick 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.
249*68653Smckusick  * For nfs version 2, just return ok. File accesses may fail later.
250*68653Smckusick  * For nfs version 3, use the access rpc to check accessibility. If file modes
251*68653Smckusick  * 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;
265*68653Smckusick 	register int t1, t2;
266*68653Smckusick 	caddr_t bpos, dpos, cp2;
267*68653Smckusick 	int error = 0, attrflag;
26856364Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
269*68653Smckusick 	u_long mode, rmode;
270*68653Smckusick 	int v3 = NFS_ISV3(vp);
27138414Smckusick 
27238414Smckusick 	/*
273*68653Smckusick 	 * 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 	 */
280*68653Smckusick 	if (v3) {
281*68653Smckusick 		nfsstats.rpccnt[NFSPROC_ACCESS]++;
282*68653Smckusick 		nfsm_reqhead(vp, NFSPROC_ACCESS, NFSX_FH(v3) + NFSX_UNSIGNED);
283*68653Smckusick 		nfsm_fhtom(vp, v3);
284*68653Smckusick 		nfsm_build(tl, u_long *, NFSX_UNSIGNED);
28556364Smckusick 		if (ap->a_mode & VREAD)
286*68653Smckusick 			mode = NFSV3ACCESS_READ;
28756364Smckusick 		else
288*68653Smckusick 			mode = 0;
289*68653Smckusick 		if (vp->v_type == VDIR) {
290*68653Smckusick 			if (ap->a_mode & VWRITE)
291*68653Smckusick 				mode |= (NFSV3ACCESS_MODIFY | NFSV3ACCESS_EXTEND |
292*68653Smckusick 					 NFSV3ACCESS_DELETE);
293*68653Smckusick 			if (ap->a_mode & VEXEC)
294*68653Smckusick 				mode |= NFSV3ACCESS_LOOKUP;
295*68653Smckusick 		} else {
296*68653Smckusick 			if (ap->a_mode & VWRITE)
297*68653Smckusick 				mode |= (NFSV3ACCESS_MODIFY | NFSV3ACCESS_EXTEND);
298*68653Smckusick 			if (ap->a_mode & VEXEC)
299*68653Smckusick 				mode |= NFSV3ACCESS_EXECUTE;
300*68653Smckusick 		}
301*68653Smckusick 		*tl = txdr_unsigned(mode);
302*68653Smckusick 		nfsm_request(vp, NFSPROC_ACCESS, ap->a_p, ap->a_cred);
303*68653Smckusick 		nfsm_postop_attr(vp, attrflag);
304*68653Smckusick 		if (!error) {
305*68653Smckusick 			nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
306*68653Smckusick 			rmode = fxdr_unsigned(u_long, *tl);
307*68653Smckusick 			/*
308*68653Smckusick 			 * The NFS V3 spec does not clarify whether or not
309*68653Smckusick 			 * the returned access bits can be a superset of
310*68653Smckusick 			 * the ones requested, so...
311*68653Smckusick 			 */
312*68653Smckusick 			if ((rmode & mode) != mode)
313*68653Smckusick 				error = EACCES;
314*68653Smckusick 		}
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)
345*68653Smckusick { printf("open eacces vtyp=%d\n",vp->v_type);
34638414Smckusick 		return (EACCES);
347*68653Smckusick }
348*68653Smckusick 	/*
349*68653Smckusick 	 * Get a valid lease. If cached data is stale, flush it.
350*68653Smckusick 	 */
351*68653Smckusick 	if (nmp->nm_flag & NFSMNT_NQNFS) {
352*68653Smckusick 		if (NQNFS_CKINVALID(vp, np, ND_READ)) {
35356289Smckusick 		    do {
354*68653Smckusick 			error = nqnfs_getlease(vp, ND_READ, ap->a_cred,
355*68653Smckusick 			    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 		}
368*68653Smckusick 	} 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;
375*68653Smckusick 			if (vp->v_type == VDIR)
376*68653Smckusick 				np->n_direofoffset = 0;
377*68653Smckusick 			error = VOP_GETATTR(vp, &vattr, ap->a_cred, ap->a_p);
378*68653Smckusick 			if (error)
37956289Smckusick 				return (error);
38056289Smckusick 			np->n_mtime = vattr.va_mtime.ts_sec;
38156289Smckusick 		} else {
382*68653Smckusick 			error = VOP_GETATTR(vp, &vattr, ap->a_cred, ap->a_p);
383*68653Smckusick 			if (error)
38456289Smckusick 				return (error);
38556289Smckusick 			if (np->n_mtime != vattr.va_mtime.ts_sec) {
386*68653Smckusick 				if (vp->v_type == VDIR)
387*68653Smckusick 					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 		}
395*68653Smckusick 	}
396*68653Smckusick 	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
403*68653Smckusick  * What an NFS client should do upon close after writing is a debatable issue.
404*68653Smckusick  * Most NFS clients push delayed writes to the server upon close, basically for
405*68653Smckusick  * two reasons:
406*68653Smckusick  * 1 - So that any write errors may be reported back to the client process
407*68653Smckusick  *     doing the close system call. By far the two most likely errors are
408*68653Smckusick  *     NFSERR_NOSPC and NFSERR_DQUOT to indicate space allocation failure.
409*68653Smckusick  * 2 - To put a worst case upper bound on cache inconsistency between
410*68653Smckusick  *     multiple clients for the file.
411*68653Smckusick  * There is also a consistency problem for Version 2 of the protocol w.r.t.
412*68653Smckusick  * not being able to tell if other clients are writing a file concurrently,
413*68653Smckusick  * since there is no way of knowing if the changed modify time in the reply
414*68653Smckusick  * is only due to the write for this client.
415*68653Smckusick  * (NFS Version 3 provides weak cache consistency data in the reply that
416*68653Smckusick  *  should be sufficient to detect and handle this case.)
417*68653Smckusick  *
418*68653Smckusick  * The current code does the following:
419*68653Smckusick  * for NFS Version 2 - play it safe and flush/invalidate all dirty buffers
420*68653Smckusick  * for NFS Version 3 - flush dirty buffers to the server but don't invalidate
421*68653Smckusick  *                     or commit them (this satisfies 1 and 2 except for the
422*68653Smckusick  *                     case where the server crashes after this close but
423*68653Smckusick  *                     before the commit RPC, which is felt to be "good
424*68653Smckusick  *                     enough". Changing the last argument to nfs_flush() to
425*68653Smckusick  *                     a 1 would force a commit operation, if it is felt a
426*68653Smckusick  *                     commit is necessary now.
427*68653Smckusick  * for NQNFS         - do nothing now, since 2 is dealt with via leases and
428*68653Smckusick  *                     1 should be dealt with via an fsync() system call for
429*68653Smckusick  *                     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)) {
449*68653Smckusick 		if (NFS_ISV3(vp))
450*68653Smckusick 		    error = nfs_flush(vp, ap->a_cred, MNT_WAIT, ap->a_p, 0);
451*68653Smckusick 		else
452*68653Smckusick 		    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;
478*68653Smckusick 	register u_long *tl;
479*68653Smckusick 	register int t1, t2;
48039488Smckusick 	caddr_t bpos, dpos;
48139488Smckusick 	int error = 0;
48239488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
483*68653Smckusick 	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]++;
496*68653Smckusick 	nfsm_reqhead(vp, NFSPROC_GETATTR, NFSX_FH(v3));
497*68653Smckusick 	nfsm_fhtom(vp, v3);
49853805Smckusick 	nfsm_request(vp, NFSPROC_GETATTR, ap->a_p, ap->a_cred);
499*68653Smckusick 	if (!error)
500*68653Smckusick 		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 {
518*68653Smckusick 	register struct vnode *vp = ap->a_vp;
519*68653Smckusick 	register struct nfsnode *np = VTONFS(vp);
520*68653Smckusick 	register struct vattr *vap = ap->a_vap;
521*68653Smckusick 	int error = 0;
522*68653Smckusick 	u_quad_t tsize;
523*68653Smckusick 
524*68653Smckusick #ifndef nolint
525*68653Smckusick 	tsize = (u_quad_t)0;
526*68653Smckusick #endif
527*68653Smckusick 	if (vap->va_size != VNOVAL) {
528*68653Smckusick  		switch (vp->v_type) {
529*68653Smckusick  		case VDIR:
530*68653Smckusick  			return (EISDIR);
531*68653Smckusick  		case VCHR:
532*68653Smckusick  		case VBLK:
533*68653Smckusick 			if (vap->va_mtime.ts_sec == VNOVAL &&
534*68653Smckusick 			    vap->va_atime.ts_sec == VNOVAL &&
535*68653Smckusick 			    vap->va_mode == (u_short)VNOVAL &&
536*68653Smckusick 			    vap->va_uid == (uid_t)VNOVAL &&
537*68653Smckusick 			    vap->va_gid == (gid_t)VNOVAL)
538*68653Smckusick 				return (0);
539*68653Smckusick  			vap->va_size = VNOVAL;
540*68653Smckusick  			break;
541*68653Smckusick  		default:
542*68653Smckusick  			if (np->n_flag & NMODIFIED) {
543*68653Smckusick  			    if (vap->va_size == 0)
544*68653Smckusick  				error = nfs_vinvalbuf(vp, 0,
545*68653Smckusick  					ap->a_cred, ap->a_p, 1);
546*68653Smckusick  			    else
547*68653Smckusick  				error = nfs_vinvalbuf(vp, V_SAVE,
548*68653Smckusick  					ap->a_cred, ap->a_p, 1);
549*68653Smckusick  			    if (error)
550*68653Smckusick  				return (error);
551*68653Smckusick  			}
552*68653Smckusick  			tsize = np->n_size;
553*68653Smckusick  			np->n_size = np->n_vattr.va_size = vap->va_size;
554*68653Smckusick  			vnode_pager_setsize(vp, (u_long)np->n_size);
555*68653Smckusick   		};
556*68653Smckusick   	} else if ((vap->va_mtime.ts_sec != VNOVAL ||
557*68653Smckusick 		vap->va_atime.ts_sec != VNOVAL) && (np->n_flag & NMODIFIED) &&
558*68653Smckusick 		vp->v_type == VREG &&
559*68653Smckusick   		(error = nfs_vinvalbuf(vp, V_SAVE, ap->a_cred,
560*68653Smckusick 		 ap->a_p, 1)) == EINTR)
561*68653Smckusick 		return (error);
562*68653Smckusick 	error = nfs_setattrrpc(vp, vap, ap->a_cred, ap->a_p);
563*68653Smckusick 	if (error) {
564*68653Smckusick 		np->n_size = np->n_vattr.va_size = tsize;
565*68653Smckusick 		vnode_pager_setsize(vp, (u_long)np->n_size);
566*68653Smckusick 	}
567*68653Smckusick 	return (error);
568*68653Smckusick }
569*68653Smckusick 
570*68653Smckusick /*
571*68653Smckusick  * Do an nfs setattr rpc.
572*68653Smckusick  */
573*68653Smckusick int
574*68653Smckusick nfs_setattrrpc(vp, vap, cred, procp)
575*68653Smckusick 	register struct vnode *vp;
576*68653Smckusick 	register struct vattr *vap;
577*68653Smckusick 	struct ucred *cred;
578*68653Smckusick 	struct proc *procp;
579*68653Smckusick {
58038884Smacklem 	register struct nfsv2_sattr *sp;
58139488Smckusick 	register caddr_t cp;
582*68653Smckusick 	register long t1, t2;
58352196Smckusick 	caddr_t bpos, dpos, cp2;
58452196Smckusick 	u_long *tl;
585*68653Smckusick 	int error = 0, wccflag = NFSV3_WCCRATTR;
58639488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
587*68653Smckusick 	u_quad_t frev;
588*68653Smckusick 	int v3 = NFS_ISV3(vp);
58938414Smckusick 
590*68653Smckusick 	nfsstats.rpccnt[NFSPROC_SETATTR]++;
591*68653Smckusick 	nfsm_reqhead(vp, NFSPROC_SETATTR, NFSX_FH(v3) + NFSX_SATTR(v3));
592*68653Smckusick 	nfsm_fhtom(vp, v3);
593*68653Smckusick 	if (v3) {
594*68653Smckusick 		if (vap->va_mode != (u_short)VNOVAL) {
595*68653Smckusick 			nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED);
596*68653Smckusick 			*tl++ = nfs_true;
597*68653Smckusick 			*tl = txdr_unsigned(vap->va_mode);
598*68653Smckusick 		} else {
599*68653Smckusick 			nfsm_build(tl, u_long *, NFSX_UNSIGNED);
600*68653Smckusick 			*tl = nfs_false;
601*68653Smckusick 		}
602*68653Smckusick 		if (vap->va_uid != (uid_t)VNOVAL) {
603*68653Smckusick 			nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED);
604*68653Smckusick 			*tl++ = nfs_true;
605*68653Smckusick 			*tl = txdr_unsigned(vap->va_uid);
606*68653Smckusick 		} else {
607*68653Smckusick 			nfsm_build(tl, u_long *, NFSX_UNSIGNED);
608*68653Smckusick 			*tl = nfs_false;
609*68653Smckusick 		}
610*68653Smckusick 		if (vap->va_gid != (gid_t)VNOVAL) {
611*68653Smckusick 			nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED);
612*68653Smckusick 			*tl++ = nfs_true;
613*68653Smckusick 			*tl = txdr_unsigned(vap->va_gid);
614*68653Smckusick 		} else {
615*68653Smckusick 			nfsm_build(tl, u_long *, NFSX_UNSIGNED);
616*68653Smckusick 			*tl = nfs_false;
617*68653Smckusick 		}
61857791Smckusick 		if (vap->va_size != VNOVAL) {
619*68653Smckusick 			nfsm_build(tl, u_long *, 3 * NFSX_UNSIGNED);
620*68653Smckusick 			*tl++ = nfs_true;
621*68653Smckusick 			txdr_hyper(&vap->va_size, tl);
622*68653Smckusick 		} else {
623*68653Smckusick 			nfsm_build(tl, u_long *, NFSX_UNSIGNED);
624*68653Smckusick 			*tl = nfs_false;
625*68653Smckusick 		}
626*68653Smckusick 		if (vap->va_atime.ts_sec != VNOVAL) {
627*68653Smckusick 			if (vap->va_atime.ts_sec != time.tv_sec) {
628*68653Smckusick 				nfsm_build(tl, u_long *, 3 * NFSX_UNSIGNED);
629*68653Smckusick 				*tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT);
630*68653Smckusick 				txdr_nfsv3time(&vap->va_atime, tl);
631*68653Smckusick 			} else {
632*68653Smckusick 				nfsm_build(tl, u_long *, NFSX_UNSIGNED);
633*68653Smckusick 				*tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER);
63457791Smckusick 			}
635*68653Smckusick 		} else {
636*68653Smckusick 			nfsm_build(tl, u_long *, NFSX_UNSIGNED);
637*68653Smckusick 			*tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE);
638*68653Smckusick 		}
639*68653Smckusick 		if (vap->va_mtime.ts_sec != VNOVAL) {
640*68653Smckusick 			if (vap->va_mtime.ts_sec != time.tv_sec) {
641*68653Smckusick 				nfsm_build(tl, u_long *, 3 * NFSX_UNSIGNED);
642*68653Smckusick 				*tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT);
643*68653Smckusick 				txdr_nfsv3time(&vap->va_atime, tl);
644*68653Smckusick 			} else {
645*68653Smckusick 				nfsm_build(tl, u_long *, NFSX_UNSIGNED);
646*68653Smckusick 				*tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER);
647*68653Smckusick 			}
648*68653Smckusick 		} else {
649*68653Smckusick 			nfsm_build(tl, u_long *, NFSX_UNSIGNED);
650*68653Smckusick 			*tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE);
651*68653Smckusick 		}
652*68653Smckusick 		nfsm_build(tl, u_long *, NFSX_UNSIGNED);
653*68653Smckusick 		*tl = nfs_false;
65456289Smckusick 	} else {
655*68653Smckusick 		nfsm_build(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
656*68653Smckusick 		if (vap->va_mode == (u_short)VNOVAL)
657*68653Smckusick 			sp->sa_mode = VNOVAL;
658*68653Smckusick 		else
659*68653Smckusick 			sp->sa_mode = vtonfsv2_mode(vp->v_type, vap->va_mode);
660*68653Smckusick 		if (vap->va_uid == (uid_t)VNOVAL)
661*68653Smckusick 			sp->sa_uid = VNOVAL;
662*68653Smckusick 		else
663*68653Smckusick 			sp->sa_uid = txdr_unsigned(vap->va_uid);
664*68653Smckusick 		if (vap->va_gid == (gid_t)VNOVAL)
665*68653Smckusick 			sp->sa_gid = VNOVAL;
666*68653Smckusick 		else
667*68653Smckusick 			sp->sa_gid = txdr_unsigned(vap->va_gid);
668*68653Smckusick 		sp->sa_size = txdr_unsigned(vap->va_size);
669*68653Smckusick 		txdr_nfsv2time(&vap->va_atime, &sp->sa_atime);
670*68653Smckusick 		txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime);
67156289Smckusick 	}
672*68653Smckusick 	nfsm_request(vp, NFSPROC_SETATTR, procp, cred);
673*68653Smckusick 	if (v3) {
674*68653Smckusick 		nfsm_wcc_data(vp, wccflag);
675*68653Smckusick 	} else
676*68653Smckusick 		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*68653Smckusick 	register struct vnode *newvp;
70048054Smckusick 	register u_long *tl;
70139488Smckusick 	register caddr_t cp;
70239488Smckusick 	register long t1, t2;
70352196Smckusick 	struct nfsmount *nmp;
70439488Smckusick 	caddr_t bpos, dpos, cp2;
70539488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
70638414Smckusick 	long len;
707*68653Smckusick 	nfsfh_t *fhp;
70838414Smckusick 	struct nfsnode *np;
709*68653Smckusick 	int lockparent, wantparent, error = 0, attrflag, fhsize;
710*68653Smckusick 	int v3 = NFS_ISV3(dvp);
71138414Smckusick 
712*68653Smckusick 	*vpp = NULLVP;
71353806Smckusick 	if (dvp->v_type != VDIR)
71438414Smckusick 		return (ENOTDIR);
71555184Smckusick 	lockparent = flags & LOCKPARENT;
71655184Smckusick 	wantparent = flags & (LOCKPARENT|WANTPARENT);
71753806Smckusick 	nmp = VFSTONFS(dvp->v_mount);
71853806Smckusick 	np = VTONFS(dvp);
71954668Smckusick 	if ((error = cache_lookup(dvp, vpp, cnp)) && error != ENOENT) {
72038884Smacklem 		struct vattr vattr;
72138884Smacklem 		int vpid;
72238884Smacklem 
723*68653Smckusick 		newvp = *vpp;
724*68653Smckusick 		vpid = newvp->v_id;
72538414Smckusick 		/*
72638884Smacklem 		 * See the comment starting `Step through' in ufs/ufs_lookup.c
72738884Smacklem 		 * for an explanation of the locking protocol
72838414Smckusick 		 */
729*68653Smckusick 		if (dvp == newvp) {
730*68653Smckusick 			VREF(newvp);
73139441Smckusick 			error = 0;
73252196Smckusick 		} else
733*68653Smckusick 			error = vget(newvp, 1);
73439441Smckusick 		if (!error) {
735*68653Smckusick 			if (vpid == newvp->v_id) {
736*68653Smckusick 			   if (!VOP_GETATTR(newvp, &vattr, cnp->cn_cred, cnp->cn_proc)
737*68653Smckusick 			    && vattr.va_ctime.ts_sec == VTONFS(newvp)->n_ctime) {
73839441Smckusick 				nfsstats.lookupcache_hits++;
73953806Smckusick 				if (cnp->cn_nameiop != LOOKUP &&
74055184Smckusick 				    (flags & ISLASTCN))
74153806Smckusick 					cnp->cn_flags |= SAVENAME;
74239441Smckusick 				return (0);
74340251Smckusick 			   }
744*68653Smckusick 			   cache_purge(newvp);
74539441Smckusick 			}
746*68653Smckusick 			vrele(newvp);
74738884Smacklem 		}
74854668Smckusick 		*vpp = NULLVP;
74952196Smckusick 	}
75039341Smckusick 	error = 0;
751*68653Smckusick 	newvp = NULLVP;
75238414Smckusick 	nfsstats.lookupcache_misses++;
75338414Smckusick 	nfsstats.rpccnt[NFSPROC_LOOKUP]++;
75453806Smckusick 	len = cnp->cn_namelen;
755*68653Smckusick 	nfsm_reqhead(dvp, NFSPROC_LOOKUP,
756*68653Smckusick 		NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(len));
757*68653Smckusick 	nfsm_fhtom(dvp, v3);
75853806Smckusick 	nfsm_strtom(cnp->cn_nameptr, len, NFS_MAXNAMLEN);
75953806Smckusick 	nfsm_request(dvp, NFSPROC_LOOKUP, cnp->cn_proc, cnp->cn_cred);
76038414Smckusick 	if (error) {
761*68653Smckusick 		nfsm_postop_attr(dvp, attrflag);
762*68653Smckusick 		m_freem(mrep);
763*68653Smckusick 		goto nfsmout;
76438414Smckusick 	}
765*68653Smckusick 	nfsm_getfh(fhp, fhsize, v3);
76638414Smckusick 
76738414Smckusick 	/*
76852196Smckusick 	 * Handle RENAME case...
76938414Smckusick 	 */
77055184Smckusick 	if (cnp->cn_nameiop == RENAME && wantparent && (flags & ISLASTCN)) {
771*68653Smckusick 		if (NFS_CMPFH(np, fhp, fhsize)) {
77238414Smckusick 			m_freem(mrep);
77338414Smckusick 			return (EISDIR);
77438414Smckusick 		}
775*68653Smckusick 		if (error = nfs_nget(dvp->v_mount, fhp, fhsize, &np)) {
77638414Smckusick 			m_freem(mrep);
77738414Smckusick 			return (error);
77838414Smckusick 		}
77938414Smckusick 		newvp = NFSTOV(np);
780*68653Smckusick 		if (v3) {
781*68653Smckusick 			nfsm_postop_attr(newvp, attrflag);
782*68653Smckusick 			nfsm_postop_attr(dvp, attrflag);
783*68653Smckusick 		} else
784*68653Smckusick 			nfsm_loadattr(newvp, (struct vattr *)0);
78554668Smckusick 		*vpp = newvp;
78645037Smckusick 		m_freem(mrep);
78753806Smckusick 		cnp->cn_flags |= SAVENAME;
78838414Smckusick 		return (0);
78938414Smckusick 	}
79038414Smckusick 
791*68653Smckusick 	if (NFS_CMPFH(np, fhp, fhsize)) {
79253806Smckusick 		VREF(dvp);
79353806Smckusick 		newvp = dvp;
79438414Smckusick 	} else {
795*68653Smckusick 		if (error = nfs_nget(dvp->v_mount, fhp, fhsize, &np)) {
79638414Smckusick 			m_freem(mrep);
79738414Smckusick 			return (error);
79838414Smckusick 		}
79938414Smckusick 		newvp = NFSTOV(np);
80038414Smckusick 	}
801*68653Smckusick 	if (v3) {
802*68653Smckusick 		nfsm_postop_attr(newvp, attrflag);
803*68653Smckusick 		nfsm_postop_attr(dvp, attrflag);
804*68653Smckusick 	} else
805*68653Smckusick 		nfsm_loadattr(newvp, (struct vattr *)0);
80655184Smckusick 	if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN))
80753806Smckusick 		cnp->cn_flags |= SAVENAME;
80855184Smckusick 	if ((cnp->cn_flags & MAKEENTRY) &&
80955184Smckusick 	    (cnp->cn_nameiop != DELETE || !(flags & ISLASTCN))) {
810*68653Smckusick 		np->n_ctime = np->n_vattr.va_ctime.ts_sec;
811*68653Smckusick 		cache_enter(dvp, newvp, cnp);
81240251Smckusick 	}
813*68653Smckusick 	*vpp = newvp;
814*68653Smckusick 	nfsm_reqdone;
815*68653Smckusick 	if (error) {
816*68653Smckusick 		if (newvp != NULLVP)
817*68653Smckusick 			vrele(newvp);
818*68653Smckusick 		if ((cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME) &&
819*68653Smckusick 		    (flags & ISLASTCN) && error == ENOENT)
820*68653Smckusick 			error = EJUSTRETURN;
821*68653Smckusick 		if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN))
822*68653Smckusick 			cnp->cn_flags |= SAVENAME;
823*68653Smckusick 	}
824*68653Smckusick 	return (error);
82538414Smckusick }
82638414Smckusick 
82738414Smckusick /*
82841905Smckusick  * nfs read call.
82941905Smckusick  * Just call nfs_bioread() to do the work.
83041905Smckusick  */
83152234Sheideman int
83253806Smckusick nfs_read(ap)
83354668Smckusick 	struct vop_read_args /* {
83454668Smckusick 		struct vnode *a_vp;
83554668Smckusick 		struct uio *a_uio;
83654668Smckusick 		int  a_ioflag;
83754668Smckusick 		struct ucred *a_cred;
83854668Smckusick 	} */ *ap;
83941905Smckusick {
84053806Smckusick 	register struct vnode *vp = ap->a_vp;
84153806Smckusick 
84253806Smckusick 	if (vp->v_type != VREG)
84341905Smckusick 		return (EPERM);
84453806Smckusick 	return (nfs_bioread(vp, ap->a_uio, ap->a_ioflag, ap->a_cred));
84541905Smckusick }
84641905Smckusick 
84741905Smckusick /*
84838414Smckusick  * nfs readlink call
84938414Smckusick  */
85052234Sheideman int
85153806Smckusick nfs_readlink(ap)
85254668Smckusick 	struct vop_readlink_args /* {
85354668Smckusick 		struct vnode *a_vp;
85454668Smckusick 		struct uio *a_uio;
85554668Smckusick 		struct ucred *a_cred;
85654668Smckusick 	} */ *ap;
85741905Smckusick {
85853806Smckusick 	register struct vnode *vp = ap->a_vp;
85953806Smckusick 
86053806Smckusick 	if (vp->v_type != VLNK)
86141905Smckusick 		return (EPERM);
86253806Smckusick 	return (nfs_bioread(vp, ap->a_uio, 0, ap->a_cred));
86341905Smckusick }
86441905Smckusick 
86541905Smckusick /*
86641905Smckusick  * Do a readlink rpc.
86741905Smckusick  * Called by nfs_doio() from below the buffer cache.
86841905Smckusick  */
86952234Sheideman int
87048054Smckusick nfs_readlinkrpc(vp, uiop, cred)
87139488Smckusick 	register struct vnode *vp;
87238414Smckusick 	struct uio *uiop;
87338414Smckusick 	struct ucred *cred;
87438414Smckusick {
87548054Smckusick 	register u_long *tl;
87639488Smckusick 	register caddr_t cp;
877*68653Smckusick 	register long t1, t2;
87839488Smckusick 	caddr_t bpos, dpos, cp2;
879*68653Smckusick 	int error = 0, len, attrflag;
88039488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
881*68653Smckusick 	int v3 = NFS_ISV3(vp);
88238414Smckusick 
88338414Smckusick 	nfsstats.rpccnt[NFSPROC_READLINK]++;
884*68653Smckusick 	nfsm_reqhead(vp, NFSPROC_READLINK, NFSX_FH(v3));
885*68653Smckusick 	nfsm_fhtom(vp, v3);
88652196Smckusick 	nfsm_request(vp, NFSPROC_READLINK, uiop->uio_procp, cred);
887*68653Smckusick 	if (v3)
888*68653Smckusick 		nfsm_postop_attr(vp, attrflag);
889*68653Smckusick 	if (!error) {
890*68653Smckusick 		nfsm_strsiz(len, NFS_MAXPATHLEN);
891*68653Smckusick 		nfsm_mtouio(uiop, len);
892*68653Smckusick 	}
89338414Smckusick 	nfsm_reqdone;
89438414Smckusick 	return (error);
89538414Smckusick }
89638414Smckusick 
89738414Smckusick /*
89841905Smckusick  * nfs read rpc call
89941905Smckusick  * Ditto above
90038414Smckusick  */
90152234Sheideman int
90248054Smckusick nfs_readrpc(vp, uiop, cred)
90339488Smckusick 	register struct vnode *vp;
90438414Smckusick 	struct uio *uiop;
90538414Smckusick 	struct ucred *cred;
90638414Smckusick {
90748054Smckusick 	register u_long *tl;
90839488Smckusick 	register caddr_t cp;
909*68653Smckusick 	register long t1, t2;
91039488Smckusick 	caddr_t bpos, dpos, cp2;
91139488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
91238414Smckusick 	struct nfsmount *nmp;
913*68653Smckusick 	int error = 0, len, retlen, tsiz, eof, attrflag;
914*68653Smckusick 	int v3 = NFS_ISV3(vp);
91538414Smckusick 
916*68653Smckusick #ifndef nolint
917*68653Smckusick 	eof = 0;
918*68653Smckusick #endif
91941398Smckusick 	nmp = VFSTONFS(vp->v_mount);
92038414Smckusick 	tsiz = uiop->uio_resid;
921*68653Smckusick 	if (uiop->uio_offset + tsiz > 0xffffffff && !v3)
92256289Smckusick 		return (EFBIG);
92338414Smckusick 	while (tsiz > 0) {
92438414Smckusick 		nfsstats.rpccnt[NFSPROC_READ]++;
92538414Smckusick 		len = (tsiz > nmp->nm_rsize) ? nmp->nm_rsize : tsiz;
926*68653Smckusick 		nfsm_reqhead(vp, NFSPROC_READ, NFSX_FH(v3) + NFSX_UNSIGNED * 3);
927*68653Smckusick 		nfsm_fhtom(vp, v3);
928*68653Smckusick 		nfsm_build(tl, u_long *, NFSX_UNSIGNED * 3);
929*68653Smckusick 		if (v3) {
93056289Smckusick 			txdr_hyper(&uiop->uio_offset, tl);
93156289Smckusick 			*(tl + 2) = txdr_unsigned(len);
93256289Smckusick 		} else {
93356289Smckusick 			*tl++ = txdr_unsigned(uiop->uio_offset);
93456289Smckusick 			*tl++ = txdr_unsigned(len);
93556289Smckusick 			*tl = 0;
93656289Smckusick 		}
93752196Smckusick 		nfsm_request(vp, NFSPROC_READ, uiop->uio_procp, cred);
938*68653Smckusick 		if (v3) {
939*68653Smckusick 			nfsm_postop_attr(vp, attrflag);
940*68653Smckusick 			if (error) {
941*68653Smckusick 				m_freem(mrep);
942*68653Smckusick 				goto nfsmout;
943*68653Smckusick 			}
944*68653Smckusick 			nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
945*68653Smckusick 			eof = fxdr_unsigned(int, *(tl + 1));
946*68653Smckusick 		} else
947*68653Smckusick 			nfsm_loadattr(vp, (struct vattr *)0);
94838414Smckusick 		nfsm_strsiz(retlen, nmp->nm_rsize);
94938414Smckusick 		nfsm_mtouio(uiop, retlen);
95038414Smckusick 		m_freem(mrep);
951*68653Smckusick 		tsiz -= retlen;
952*68653Smckusick 		if (v3) {
953*68653Smckusick 			if (eof || retlen == 0)
954*68653Smckusick 				tsiz = 0;
955*68653Smckusick 		} else if (retlen < len)
95638414Smckusick 			tsiz = 0;
95738414Smckusick 	}
95838414Smckusick nfsmout:
95938414Smckusick 	return (error);
96038414Smckusick }
96138414Smckusick 
96238414Smckusick /*
96338414Smckusick  * nfs write call
96438414Smckusick  */
96552234Sheideman int
966*68653Smckusick nfs_writerpc(vp, uiop, cred, iomode, must_commit)
96739488Smckusick 	register struct vnode *vp;
968*68653Smckusick 	register struct uio *uiop;
96938414Smckusick 	struct ucred *cred;
970*68653Smckusick 	int *iomode, *must_commit;
97138414Smckusick {
97248054Smckusick 	register u_long *tl;
97339488Smckusick 	register caddr_t cp;
974*68653Smckusick 	register int t1, t2, backup;
97552196Smckusick 	caddr_t bpos, dpos, cp2;
97639488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
977*68653Smckusick 	struct nfsmount *nmp = VFSTONFS(vp->v_mount);
97852196Smckusick 	struct nfsnode *np = VTONFS(vp);
97952196Smckusick 	u_quad_t frev;
980*68653Smckusick 	int error = 0, len, tsiz, wccflag = NFSV3_WCCRATTR, rlen, commit;
981*68653Smckusick 	int v3 = NFS_ISV3(vp), committed = NFSV3WRITE_FILESYNC;
98238414Smckusick 
983*68653Smckusick #ifndef DIAGNOSTIC
984*68653Smckusick 	if (uiop->uio_iovcnt != 1)
985*68653Smckusick 		panic("nfs: writerpc iovcnt > 1");
986*68653Smckusick #endif
987*68653Smckusick 	*must_commit = 0;
98838414Smckusick 	tsiz = uiop->uio_resid;
989*68653Smckusick 	if (uiop->uio_offset + tsiz > 0xffffffff && !v3)
99056289Smckusick 		return (EFBIG);
99138414Smckusick 	while (tsiz > 0) {
99238414Smckusick 		nfsstats.rpccnt[NFSPROC_WRITE]++;
99338414Smckusick 		len = (tsiz > nmp->nm_wsize) ? nmp->nm_wsize : tsiz;
99452196Smckusick 		nfsm_reqhead(vp, NFSPROC_WRITE,
995*68653Smckusick 			NFSX_FH(v3) + 5 * NFSX_UNSIGNED + nfsm_rndup(len));
996*68653Smckusick 		nfsm_fhtom(vp, v3);
997*68653Smckusick 		if (v3) {
998*68653Smckusick 			nfsm_build(tl, u_long *, 5 * NFSX_UNSIGNED);
99956289Smckusick 			txdr_hyper(&uiop->uio_offset, tl);
100056289Smckusick 			tl += 2;
1001*68653Smckusick 			*tl++ = txdr_unsigned(len);
1002*68653Smckusick 			*tl++ = txdr_unsigned(*iomode);
100356289Smckusick 		} else {
1004*68653Smckusick 			nfsm_build(tl, u_long *, 4 * NFSX_UNSIGNED);
100556289Smckusick 			*++tl = txdr_unsigned(uiop->uio_offset);
100656289Smckusick 			tl += 2;
100756289Smckusick 		}
100856289Smckusick 		*tl = txdr_unsigned(len);
100938414Smckusick 		nfsm_uiotom(uiop, len);
101052196Smckusick 		nfsm_request(vp, NFSPROC_WRITE, uiop->uio_procp, cred);
1011*68653Smckusick 		if (v3) {
1012*68653Smckusick 			wccflag = NFSV3_WCCCHK;
1013*68653Smckusick 			nfsm_wcc_data(vp, wccflag);
1014*68653Smckusick 			if (!error) {
1015*68653Smckusick 				nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED +
1016*68653Smckusick 					NFSX_V3WRITEVERF);
1017*68653Smckusick 				rlen = fxdr_unsigned(int, *tl++);
1018*68653Smckusick 				if (rlen == 0) {
1019*68653Smckusick 					error = NFSERR_IO;
1020*68653Smckusick 					break;
1021*68653Smckusick 				} else if (rlen < len) {
1022*68653Smckusick 					backup = len - rlen;
1023*68653Smckusick 					uiop->uio_iov->iov_base -= backup;
1024*68653Smckusick 					uiop->uio_iov->iov_len += backup;
1025*68653Smckusick 					uiop->uio_offset -= backup;
1026*68653Smckusick 					uiop->uio_resid += backup;
1027*68653Smckusick 					len = rlen;
1028*68653Smckusick 				}
1029*68653Smckusick 				commit = fxdr_unsigned(int, *tl++);
1030*68653Smckusick 
1031*68653Smckusick 				/*
1032*68653Smckusick 				 * Return the lowest committment level
1033*68653Smckusick 				 * obtained by any of the RPCs.
1034*68653Smckusick 				 */
1035*68653Smckusick 				if (committed == NFSV3WRITE_FILESYNC)
1036*68653Smckusick 					committed = commit;
1037*68653Smckusick 				else if (committed == NFSV3WRITE_DATASYNC &&
1038*68653Smckusick 					commit == NFSV3WRITE_UNSTABLE)
1039*68653Smckusick 					committed = commit;
1040*68653Smckusick 				if ((nmp->nm_flag & NFSMNT_HASWRITEVERF) == 0) {
1041*68653Smckusick 				    bcopy((caddr_t)tl, (caddr_t)nmp->nm_verf,
1042*68653Smckusick 					NFSX_V3WRITEVERF);
1043*68653Smckusick 				    nmp->nm_flag |= NFSMNT_HASWRITEVERF;
1044*68653Smckusick 				} else if (bcmp((caddr_t)tl,
1045*68653Smckusick 				    (caddr_t)nmp->nm_verf, NFSX_V3WRITEVERF)) {
1046*68653Smckusick 				    *must_commit = 1;
1047*68653Smckusick 				    bcopy((caddr_t)tl, (caddr_t)nmp->nm_verf,
1048*68653Smckusick 					NFSX_V3WRITEVERF);
1049*68653Smckusick 				}
1050*68653Smckusick 			}
1051*68653Smckusick 		} else
1052*68653Smckusick 		    nfsm_loadattr(vp, (struct vattr *)0);
1053*68653Smckusick 		if (wccflag)
1054*68653Smckusick 		    VTONFS(vp)->n_mtime = VTONFS(vp)->n_vattr.va_mtime.ts_sec;
105538414Smckusick 		m_freem(mrep);
105638414Smckusick 		tsiz -= len;
105738414Smckusick 	}
105838414Smckusick nfsmout:
1059*68653Smckusick 	*iomode = committed;
106052196Smckusick 	if (error)
106152196Smckusick 		uiop->uio_resid = tsiz;
106238414Smckusick 	return (error);
106338414Smckusick }
106438414Smckusick 
106538414Smckusick /*
1066*68653Smckusick  * nfs mknod rpc
1067*68653Smckusick  * For NFS v2 this is a kludge. Use a create rpc but with the IFMT bits of the
1068*68653Smckusick  * mode set to specify the file type and the size field for rdev.
106939459Smckusick  */
107052234Sheideman int
1071*68653Smckusick nfs_mknodrpc(dvp, vpp, cnp, vap)
1072*68653Smckusick 	register struct vnode *dvp;
1073*68653Smckusick 	register struct vnode **vpp;
1074*68653Smckusick 	register struct componentname *cnp;
1075*68653Smckusick 	register struct vattr *vap;
107639459Smckusick {
107742246Smckusick 	register struct nfsv2_sattr *sp;
1078*68653Smckusick 	register struct nfsv3_sattr *sp3;
107948054Smckusick 	register u_long *tl;
108042246Smckusick 	register caddr_t cp;
108156289Smckusick 	register long t1, t2;
1082*68653Smckusick 	struct vnode *newvp = (struct vnode *)0;
1083*68653Smckusick 	struct nfsnode *np;
108459116Smckusick 	struct vattr vattr;
108556289Smckusick 	char *cp2;
108642246Smckusick 	caddr_t bpos, dpos;
1087*68653Smckusick 	int error = 0, wccflag = NFSV3_WCCRATTR, gotvp = 0;
108842246Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
108942246Smckusick 	u_long rdev;
1090*68653Smckusick 	int v3 = NFS_ISV3(dvp);
109139459Smckusick 
109253806Smckusick 	if (vap->va_type == VCHR || vap->va_type == VBLK)
109353806Smckusick 		rdev = txdr_unsigned(vap->va_rdev);
1094*68653Smckusick 	else if (vap->va_type == VFIFO || vap->va_type == VSOCK)
109542246Smckusick 		rdev = 0xffffffff;
109642246Smckusick 	else {
109753806Smckusick 		VOP_ABORTOP(dvp, cnp);
109853806Smckusick 		vput(dvp);
109942246Smckusick 		return (EOPNOTSUPP);
110042246Smckusick 	}
110159116Smckusick 	if (error = VOP_GETATTR(dvp, &vattr, cnp->cn_cred, cnp->cn_proc)) {
110259116Smckusick 		VOP_ABORTOP(dvp, cnp);
110359116Smckusick 		vput(dvp);
110459116Smckusick 		return (error);
110559116Smckusick 	}
1106*68653Smckusick 	nfsstats.rpccnt[NFSPROC_MKNOD]++;
1107*68653Smckusick 	nfsm_reqhead(dvp, NFSPROC_MKNOD, NFSX_FH(v3) + 4 * NFSX_UNSIGNED +
1108*68653Smckusick 		+ nfsm_rndup(cnp->cn_namelen) + NFSX_SATTR(v3));
1109*68653Smckusick 	nfsm_fhtom(dvp, v3);
111053806Smckusick 	nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
1111*68653Smckusick 	if (v3) {
1112*68653Smckusick 		nfsm_build(tl, u_long *, NFSX_UNSIGNED + NFSX_V3SRVSATTR);
1113*68653Smckusick 		*tl++ = vtonfsv3_type(vap->va_type);
1114*68653Smckusick 		sp3 = (struct nfsv3_sattr *)tl;
1115*68653Smckusick 		nfsm_v3sattr(sp3, vap, cnp->cn_cred->cr_uid, vattr.va_gid);
1116*68653Smckusick 		if (vap->va_type == VCHR || vap->va_type == VBLK) {
1117*68653Smckusick 			nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED);
1118*68653Smckusick 			*tl++ = txdr_unsigned(major(vap->va_rdev));
1119*68653Smckusick 			*tl = txdr_unsigned(minor(vap->va_rdev));
1120*68653Smckusick 		}
112156289Smckusick 	} else {
1122*68653Smckusick 		nfsm_build(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
1123*68653Smckusick 		sp->sa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode);
1124*68653Smckusick 		sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid);
1125*68653Smckusick 		sp->sa_gid = txdr_unsigned(vattr.va_gid);
1126*68653Smckusick 		sp->sa_size = rdev;
1127*68653Smckusick 		txdr_nfsv2time(&vap->va_atime, &sp->sa_atime);
1128*68653Smckusick 		txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime);
112956289Smckusick 	}
1130*68653Smckusick 	nfsm_request(dvp, NFSPROC_MKNOD, cnp->cn_proc, cnp->cn_cred);
1131*68653Smckusick 	if (!error) {
1132*68653Smckusick 		nfsm_mtofh(dvp, newvp, v3, gotvp);
1133*68653Smckusick 		if (!gotvp) {
1134*68653Smckusick 			if (newvp) {
1135*68653Smckusick 				vrele(newvp);
1136*68653Smckusick 				newvp = (struct vnode *)0;
1137*68653Smckusick 			}
1138*68653Smckusick 			error = nfs_lookitup(dvp, cnp->cn_nameptr,
1139*68653Smckusick 			    cnp->cn_namelen, cnp->cn_cred, cnp->cn_proc, &np);
1140*68653Smckusick 			if (!error)
1141*68653Smckusick 				newvp = NFSTOV(np);
1142*68653Smckusick 		}
1143*68653Smckusick 	}
1144*68653Smckusick 	if (v3)
1145*68653Smckusick 		nfsm_wcc_data(dvp, wccflag);
114642246Smckusick 	nfsm_reqdone;
1147*68653Smckusick 	if (error) {
1148*68653Smckusick 		if (newvp)
1149*68653Smckusick 			vrele(newvp);
1150*68653Smckusick 	} else {
1151*68653Smckusick 		if (cnp->cn_flags & MAKEENTRY)
1152*68653Smckusick 			cache_enter(dvp, newvp, cnp);
1153*68653Smckusick 		*vpp = newvp;
1154*68653Smckusick 	}
115553806Smckusick 	FREE(cnp->cn_pnbuf, M_NAMEI);
115653806Smckusick 	VTONFS(dvp)->n_flag |= NMODIFIED;
1157*68653Smckusick 	if (!wccflag)
1158*68653Smckusick 		VTONFS(dvp)->n_attrstamp = 0;
115953806Smckusick 	vrele(dvp);
116042246Smckusick 	return (error);
116139459Smckusick }
116239459Smckusick 
116339459Smckusick /*
1164*68653Smckusick  * nfs mknod vop
1165*68653Smckusick  * just call nfs_mknodrpc() to do the work.
1166*68653Smckusick  */
1167*68653Smckusick /* ARGSUSED */
1168*68653Smckusick int
1169*68653Smckusick nfs_mknod(ap)
1170*68653Smckusick 	struct vop_mknod_args /* {
1171*68653Smckusick 		struct vnode *a_dvp;
1172*68653Smckusick 		struct vnode **a_vpp;
1173*68653Smckusick 		struct componentname *a_cnp;
1174*68653Smckusick 		struct vattr *a_vap;
1175*68653Smckusick 	} */ *ap;
1176*68653Smckusick {
1177*68653Smckusick 	struct vnode *newvp;
1178*68653Smckusick 	int error;
1179*68653Smckusick 
1180*68653Smckusick 	error = nfs_mknodrpc(ap->a_dvp, &newvp, ap->a_cnp, ap->a_vap);
1181*68653Smckusick 	if (!error)
1182*68653Smckusick 		vrele(newvp);
1183*68653Smckusick 	return (error);
1184*68653Smckusick }
1185*68653Smckusick 
1186*68653Smckusick static u_long create_verf;
1187*68653Smckusick /*
118838414Smckusick  * nfs file create call
118938414Smckusick  */
119052234Sheideman int
119153806Smckusick nfs_create(ap)
119254668Smckusick 	struct vop_create_args /* {
119354668Smckusick 		struct vnode *a_dvp;
119454668Smckusick 		struct vnode **a_vpp;
119554668Smckusick 		struct componentname *a_cnp;
119654668Smckusick 		struct vattr *a_vap;
119754668Smckusick 	} */ *ap;
119838414Smckusick {
119953806Smckusick 	register struct vnode *dvp = ap->a_dvp;
120053806Smckusick 	register struct vattr *vap = ap->a_vap;
120153806Smckusick 	register struct componentname *cnp = ap->a_cnp;
120238884Smacklem 	register struct nfsv2_sattr *sp;
1203*68653Smckusick 	register struct nfsv3_sattr *sp3;
120448054Smckusick 	register u_long *tl;
120539488Smckusick 	register caddr_t cp;
120639488Smckusick 	register long t1, t2;
1207*68653Smckusick 	struct nfsnode *np = (struct nfsnode *)0;
1208*68653Smckusick 	struct vnode *newvp = (struct vnode *)0;
120939488Smckusick 	caddr_t bpos, dpos, cp2;
1210*68653Smckusick 	int error = 0, wccflag = NFSV3_WCCRATTR, gotvp = 0, fmode = 0;
121139488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
121259116Smckusick 	struct vattr vattr;
1213*68653Smckusick 	int v3 = NFS_ISV3(dvp);
121438414Smckusick 
1215*68653Smckusick 	/*
1216*68653Smckusick 	 * Oops, not for me..
1217*68653Smckusick 	 */
1218*68653Smckusick 	if (vap->va_type == VSOCK)
1219*68653Smckusick 		return (nfs_mknodrpc(dvp, ap->a_vpp, cnp, vap));
1220*68653Smckusick 
122159116Smckusick 	if (error = VOP_GETATTR(dvp, &vattr, cnp->cn_cred, cnp->cn_proc)) {
122259116Smckusick 		VOP_ABORTOP(dvp, cnp);
122359116Smckusick 		vput(dvp);
122459116Smckusick 		return (error);
122559116Smckusick 	}
1226*68653Smckusick 	if (vap->va_vaflags & VA_EXCLUSIVE)
1227*68653Smckusick 		fmode |= O_EXCL;
1228*68653Smckusick again:
122938414Smckusick 	nfsstats.rpccnt[NFSPROC_CREATE]++;
1230*68653Smckusick 	nfsm_reqhead(dvp, NFSPROC_CREATE, NFSX_FH(v3) + 2 * NFSX_UNSIGNED +
1231*68653Smckusick 		nfsm_rndup(cnp->cn_namelen) + NFSX_SATTR(v3));
1232*68653Smckusick 	nfsm_fhtom(dvp, v3);
123353806Smckusick 	nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
1234*68653Smckusick 	if (v3) {
1235*68653Smckusick 		nfsm_build(tl, u_long *, NFSX_UNSIGNED);
1236*68653Smckusick 		if (fmode & O_EXCL) {
1237*68653Smckusick 		    *tl = txdr_unsigned(NFSV3CREATE_EXCLUSIVE);
1238*68653Smckusick 		    nfsm_build(tl, u_long *, NFSX_V3CREATEVERF);
1239*68653Smckusick 		    if (in_ifaddr)
1240*68653Smckusick 			*tl++ = IA_SIN(in_ifaddr)->sin_addr.s_addr;
1241*68653Smckusick 		    else
1242*68653Smckusick 			*tl++ = create_verf;
1243*68653Smckusick 		    *tl = ++create_verf;
1244*68653Smckusick 		} else {
1245*68653Smckusick 		    *tl = txdr_unsigned(NFSV3CREATE_UNCHECKED);
1246*68653Smckusick 		    nfsm_build(tl, u_long *, NFSX_V3SRVSATTR);
1247*68653Smckusick 		    sp3 = (struct nfsv3_sattr *)tl;
1248*68653Smckusick 		    nfsm_v3sattr(sp3, vap, cnp->cn_cred->cr_uid, vattr.va_gid);
1249*68653Smckusick 		}
125056289Smckusick 	} else {
1251*68653Smckusick 		nfsm_build(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
1252*68653Smckusick 		sp->sa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode);
1253*68653Smckusick 		sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid);
1254*68653Smckusick 		sp->sa_gid = txdr_unsigned(vattr.va_gid);
1255*68653Smckusick 		sp->sa_size = 0;
1256*68653Smckusick 		txdr_nfsv2time(&vap->va_atime, &sp->sa_atime);
1257*68653Smckusick 		txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime);
125856289Smckusick 	}
125953806Smckusick 	nfsm_request(dvp, NFSPROC_CREATE, cnp->cn_proc, cnp->cn_cred);
1260*68653Smckusick 	if (!error) {
1261*68653Smckusick 		nfsm_mtofh(dvp, newvp, v3, gotvp);
1262*68653Smckusick 		if (!gotvp) {
1263*68653Smckusick 			if (newvp) {
1264*68653Smckusick 				vrele(newvp);
1265*68653Smckusick 				newvp = (struct vnode *)0;
1266*68653Smckusick 			}
1267*68653Smckusick 			error = nfs_lookitup(dvp, cnp->cn_nameptr,
1268*68653Smckusick 			    cnp->cn_namelen, cnp->cn_cred, cnp->cn_proc, &np);
1269*68653Smckusick 			if (!error)
1270*68653Smckusick 				newvp = NFSTOV(np);
1271*68653Smckusick 		}
1272*68653Smckusick 	}
1273*68653Smckusick 	if (v3)
1274*68653Smckusick 		nfsm_wcc_data(dvp, wccflag);
127538414Smckusick 	nfsm_reqdone;
1276*68653Smckusick 	if (error) {
1277*68653Smckusick 		if (v3 && (fmode & O_EXCL) && error == NFSERR_NOTSUPP) {
1278*68653Smckusick 			fmode &= ~O_EXCL;
1279*68653Smckusick 			goto again;
1280*68653Smckusick 		}
1281*68653Smckusick 		if (newvp)
1282*68653Smckusick 			vrele(newvp);
1283*68653Smckusick 	} else if (v3 && (fmode & O_EXCL))
1284*68653Smckusick 		error = nfs_setattrrpc(newvp, vap, cnp->cn_cred, cnp->cn_proc);
1285*68653Smckusick 	if (!error) {
1286*68653Smckusick 		if (cnp->cn_flags & MAKEENTRY)
1287*68653Smckusick 			cache_enter(dvp, newvp, cnp);
1288*68653Smckusick 		*ap->a_vpp = newvp;
1289*68653Smckusick 	}
129053806Smckusick 	FREE(cnp->cn_pnbuf, M_NAMEI);
129153806Smckusick 	VTONFS(dvp)->n_flag |= NMODIFIED;
1292*68653Smckusick 	if (!wccflag)
1293*68653Smckusick 		VTONFS(dvp)->n_attrstamp = 0;
129453806Smckusick 	vrele(dvp);
129538414Smckusick 	return (error);
129638414Smckusick }
129738414Smckusick 
129838414Smckusick /*
129938414Smckusick  * nfs file remove call
130041905Smckusick  * To try and make nfs semantics closer to ufs semantics, a file that has
130141905Smckusick  * other processes using the vnode is renamed instead of removed and then
130239341Smckusick  * removed later on the last close.
130341905Smckusick  * - If v_usecount > 1
130439341Smckusick  *	  If a rename is not already in the works
130539341Smckusick  *	     call nfs_sillyrename() to set it up
130639341Smckusick  *     else
130739341Smckusick  *	  do the remove rpc
130838414Smckusick  */
130952234Sheideman int
131053806Smckusick nfs_remove(ap)
131154451Smckusick 	struct vop_remove_args /* {
131254451Smckusick 		struct vnodeop_desc *a_desc;
131354451Smckusick 		struct vnode * a_dvp;
131454451Smckusick 		struct vnode * a_vp;
131554451Smckusick 		struct componentname * a_cnp;
131654451Smckusick 	} */ *ap;
131738414Smckusick {
131853806Smckusick 	register struct vnode *vp = ap->a_vp;
131953806Smckusick 	register struct vnode *dvp = ap->a_dvp;
132053806Smckusick 	register struct componentname *cnp = ap->a_cnp;
132153806Smckusick 	register struct nfsnode *np = VTONFS(vp);
132248054Smckusick 	register u_long *tl;
132339488Smckusick 	register caddr_t cp;
132452196Smckusick 	register long t2;
132539488Smckusick 	caddr_t bpos, dpos;
132639488Smckusick 	int error = 0;
132739488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
1328*68653Smckusick 	struct vattr vattr;
1329*68653Smckusick 	int v3 = NFS_ISV3(dvp);
133038414Smckusick 
1331*68653Smckusick #ifndef DIAGNOSTIC
1332*68653Smckusick 	if ((cnp->cn_flags & HASBUF) == 0)
1333*68653Smckusick 		panic("nfs_remove: no name");
1334*68653Smckusick 	if (vp->v_usecount < 1)
1335*68653Smckusick 		panic("nfs_remove: bad v_usecount");
1336*68653Smckusick #endif
1337*68653Smckusick 	if (vp->v_usecount == 1 || (np->n_sillyrename &&
1338*68653Smckusick 	    VOP_GETATTR(vp, &vattr, cnp->cn_cred, cnp->cn_proc) == 0 &&
1339*68653Smckusick 	    vattr.va_nlink > 1)) {
134052196Smckusick 		/*
134152196Smckusick 		 * Purge the name cache so that the chance of a lookup for
134252196Smckusick 		 * the name succeeding while the remove is in progress is
134352196Smckusick 		 * minimized. Without node locking it can still happen, such
134452196Smckusick 		 * that an I/O op returns ESTALE, but since you get this if
134552196Smckusick 		 * another host removes the file..
134652196Smckusick 		 */
134753806Smckusick 		cache_purge(vp);
134852196Smckusick 		/*
1349*68653Smckusick 		 * throw away biocache buffers, mainly to avoid
1350*68653Smckusick 		 * unnecessary delayed writes later.
135152196Smckusick 		 */
135257791Smckusick 		error = nfs_vinvalbuf(vp, 0, cnp->cn_cred, cnp->cn_proc, 1);
135352196Smckusick 		/* Do the rpc */
1354*68653Smckusick 		if (error != EINTR)
1355*68653Smckusick 			error = nfs_removerpc(dvp, cnp->cn_nameptr,
1356*68653Smckusick 				cnp->cn_namelen, cnp->cn_cred, cnp->cn_proc);
135739751Smckusick 		/*
135839751Smckusick 		 * Kludge City: If the first reply to the remove rpc is lost..
135939751Smckusick 		 *   the reply to the retransmitted request will be ENOENT
136039751Smckusick 		 *   since the file was in fact removed
136139751Smckusick 		 *   Therefore, we cheat and return success.
136239751Smckusick 		 */
136339751Smckusick 		if (error == ENOENT)
136439751Smckusick 			error = 0;
1365*68653Smckusick 	} else if (!np->n_sillyrename)
1366*68653Smckusick 		error = nfs_sillyrename(dvp, vp, cnp);
1367*68653Smckusick 	FREE(cnp->cn_pnbuf, M_NAMEI);
136840042Smckusick 	np->n_attrstamp = 0;
136953806Smckusick 	vrele(dvp);
137053806Smckusick 	vrele(vp);
137138414Smckusick 	return (error);
137238414Smckusick }
137338414Smckusick 
137438414Smckusick /*
137538414Smckusick  * nfs file remove rpc called from nfs_inactive
137638414Smckusick  */
137752234Sheideman int
137854451Smckusick nfs_removeit(sp)
137948364Smckusick 	register struct sillyrename *sp;
138038414Smckusick {
1381*68653Smckusick 
1382*68653Smckusick 	return (nfs_removerpc(sp->s_dvp, sp->s_name, sp->s_namlen, sp->s_cred,
1383*68653Smckusick 		(struct proc *)0));
1384*68653Smckusick }
1385*68653Smckusick 
1386*68653Smckusick /*
1387*68653Smckusick  * Nfs remove rpc, called from nfs_remove() and nfs_removeit().
1388*68653Smckusick  */
1389*68653Smckusick int
1390*68653Smckusick nfs_removerpc(dvp, name, namelen, cred, proc)
1391*68653Smckusick 	register struct vnode *dvp;
1392*68653Smckusick 	char *name;
1393*68653Smckusick 	int namelen;
1394*68653Smckusick 	struct ucred *cred;
1395*68653Smckusick 	struct proc *proc;
1396*68653Smckusick {
139748054Smckusick 	register u_long *tl;
139839488Smckusick 	register caddr_t cp;
1399*68653Smckusick 	register long t1, t2;
1400*68653Smckusick 	caddr_t bpos, dpos, cp2;
1401*68653Smckusick 	int error = 0, wccflag = NFSV3_WCCRATTR;
140239488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
1403*68653Smckusick 	int v3 = NFS_ISV3(dvp);
140438414Smckusick 
140538414Smckusick 	nfsstats.rpccnt[NFSPROC_REMOVE]++;
1406*68653Smckusick 	nfsm_reqhead(dvp, NFSPROC_REMOVE,
1407*68653Smckusick 		NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(namelen));
1408*68653Smckusick 	nfsm_fhtom(dvp, v3);
1409*68653Smckusick 	nfsm_strtom(name, namelen, NFS_MAXNAMLEN);
1410*68653Smckusick 	nfsm_request(dvp, NFSPROC_REMOVE, proc, cred);
1411*68653Smckusick 	if (v3)
1412*68653Smckusick 		nfsm_wcc_data(dvp, wccflag);
141338414Smckusick 	nfsm_reqdone;
1414*68653Smckusick 	VTONFS(dvp)->n_flag |= NMODIFIED;
1415*68653Smckusick 	if (!wccflag)
1416*68653Smckusick 		VTONFS(dvp)->n_attrstamp = 0;
141738414Smckusick 	return (error);
141838414Smckusick }
141938414Smckusick 
142038414Smckusick /*
142138414Smckusick  * nfs file rename call
142238414Smckusick  */
142352234Sheideman int
142453806Smckusick nfs_rename(ap)
142554668Smckusick 	struct vop_rename_args  /* {
142654668Smckusick 		struct vnode *a_fdvp;
142754668Smckusick 		struct vnode *a_fvp;
142854668Smckusick 		struct componentname *a_fcnp;
142954668Smckusick 		struct vnode *a_tdvp;
143054668Smckusick 		struct vnode *a_tvp;
143154668Smckusick 		struct componentname *a_tcnp;
143254668Smckusick 	} */ *ap;
143338414Smckusick {
143453806Smckusick 	register struct vnode *fvp = ap->a_fvp;
143553806Smckusick 	register struct vnode *tvp = ap->a_tvp;
143653806Smckusick 	register struct vnode *fdvp = ap->a_fdvp;
143753806Smckusick 	register struct vnode *tdvp = ap->a_tdvp;
143853806Smckusick 	register struct componentname *tcnp = ap->a_tcnp;
143953806Smckusick 	register struct componentname *fcnp = ap->a_fcnp;
1440*68653Smckusick 	int error;
144138414Smckusick 
1442*68653Smckusick #ifndef DIAGNOSTIC
1443*68653Smckusick 	if ((tcnp->cn_flags & HASBUF) == 0 ||
1444*68653Smckusick 	    (fcnp->cn_flags & HASBUF) == 0)
1445*68653Smckusick 		panic("nfs_rename: no name");
1446*68653Smckusick #endif
144753804Spendry 	/* Check for cross-device rename */
144853806Smckusick 	if ((fvp->v_mount != tdvp->v_mount) ||
144953806Smckusick 	    (tvp && (fvp->v_mount != tvp->v_mount))) {
145053804Spendry 		error = EXDEV;
145153804Spendry 		goto out;
145253804Spendry 	}
145353804Spendry 
1454*68653Smckusick 	/*
1455*68653Smckusick 	 * If the tvp exists and is in use, sillyrename it before doing the
1456*68653Smckusick 	 * rename of the new file over it.
1457*68653Smckusick 	 */
1458*68653Smckusick 	if (tvp && tvp->v_usecount > 1 && !VTONFS(tvp)->n_sillyrename &&
1459*68653Smckusick 		!nfs_sillyrename(tdvp, tvp, tcnp)) {
1460*68653Smckusick 		vrele(tvp);
1461*68653Smckusick 		tvp = NULL;
1462*68653Smckusick 	}
146353804Spendry 
1464*68653Smckusick 	error = nfs_renamerpc(fdvp, fcnp->cn_nameptr, fcnp->cn_namelen,
1465*68653Smckusick 		tdvp, tcnp->cn_nameptr, tcnp->cn_namelen, tcnp->cn_cred,
1466*68653Smckusick 		tcnp->cn_proc);
1467*68653Smckusick 
146853806Smckusick 	if (fvp->v_type == VDIR) {
146953806Smckusick 		if (tvp != NULL && tvp->v_type == VDIR)
147053806Smckusick 			cache_purge(tdvp);
147153806Smckusick 		cache_purge(fdvp);
147238414Smckusick 	}
147353804Spendry out:
147453806Smckusick 	if (tdvp == tvp)
147553806Smckusick 		vrele(tdvp);
147643360Smckusick 	else
147753806Smckusick 		vput(tdvp);
147853806Smckusick 	if (tvp)
147953806Smckusick 		vput(tvp);
148053806Smckusick 	vrele(fdvp);
148153806Smckusick 	vrele(fvp);
148240112Smckusick 	/*
148340112Smckusick 	 * Kludge: Map ENOENT => 0 assuming that it is a reply to a retry.
148440112Smckusick 	 */
148540112Smckusick 	if (error == ENOENT)
148640112Smckusick 		error = 0;
148738414Smckusick 	return (error);
148838414Smckusick }
148938414Smckusick 
149038414Smckusick /*
149141905Smckusick  * nfs file rename rpc called from nfs_remove() above
149238414Smckusick  */
149352234Sheideman int
149452234Sheideman nfs_renameit(sdvp, scnp, sp)
149552234Sheideman 	struct vnode *sdvp;
149652234Sheideman 	struct componentname *scnp;
149748364Smckusick 	register struct sillyrename *sp;
149838414Smckusick {
1499*68653Smckusick 	return (nfs_renamerpc(sdvp, scnp->cn_nameptr, scnp->cn_namelen,
1500*68653Smckusick 		sdvp, sp->s_name, sp->s_namlen, scnp->cn_cred, scnp->cn_proc));
1501*68653Smckusick }
1502*68653Smckusick 
1503*68653Smckusick /*
1504*68653Smckusick  * Do an nfs rename rpc. Called from nfs_rename() and nfs_renameit().
1505*68653Smckusick  */
1506*68653Smckusick int
1507*68653Smckusick nfs_renamerpc(fdvp, fnameptr, fnamelen, tdvp, tnameptr, tnamelen, cred, proc)
1508*68653Smckusick 	register struct vnode *fdvp;
1509*68653Smckusick 	char *fnameptr;
1510*68653Smckusick 	int fnamelen;
1511*68653Smckusick 	register struct vnode *tdvp;
1512*68653Smckusick 	char *tnameptr;
1513*68653Smckusick 	int tnamelen;
1514*68653Smckusick 	struct ucred *cred;
1515*68653Smckusick 	struct proc *proc;
1516*68653Smckusick {
151748054Smckusick 	register u_long *tl;
151839488Smckusick 	register caddr_t cp;
1519*68653Smckusick 	register long t1, t2;
1520*68653Smckusick 	caddr_t bpos, dpos, cp2;
1521*68653Smckusick 	int error = 0, fwccflag = NFSV3_WCCRATTR, twccflag = NFSV3_WCCRATTR;
152239488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
1523*68653Smckusick 	int v3 = NFS_ISV3(fdvp);
152438414Smckusick 
152538414Smckusick 	nfsstats.rpccnt[NFSPROC_RENAME]++;
1526*68653Smckusick 	nfsm_reqhead(fdvp, NFSPROC_RENAME,
1527*68653Smckusick 		(NFSX_FH(v3) + NFSX_UNSIGNED)*2 + nfsm_rndup(fnamelen) +
1528*68653Smckusick 		nfsm_rndup(tnamelen));
1529*68653Smckusick 	nfsm_fhtom(fdvp, v3);
1530*68653Smckusick 	nfsm_strtom(fnameptr, fnamelen, NFS_MAXNAMLEN);
1531*68653Smckusick 	nfsm_fhtom(tdvp, v3);
1532*68653Smckusick 	nfsm_strtom(tnameptr, tnamelen, NFS_MAXNAMLEN);
1533*68653Smckusick 	nfsm_request(fdvp, NFSPROC_RENAME, proc, cred);
1534*68653Smckusick 	if (v3) {
1535*68653Smckusick 		nfsm_wcc_data(fdvp, fwccflag);
1536*68653Smckusick 		nfsm_wcc_data(tdvp, twccflag);
1537*68653Smckusick 	}
153838414Smckusick 	nfsm_reqdone;
1539*68653Smckusick 	VTONFS(fdvp)->n_flag |= NMODIFIED;
1540*68653Smckusick 	VTONFS(tdvp)->n_flag |= NMODIFIED;
1541*68653Smckusick 	if (!fwccflag)
1542*68653Smckusick 		VTONFS(fdvp)->n_attrstamp = 0;
1543*68653Smckusick 	if (!twccflag)
1544*68653Smckusick 		VTONFS(tdvp)->n_attrstamp = 0;
154538414Smckusick 	return (error);
154638414Smckusick }
154738414Smckusick 
154838414Smckusick /*
154938414Smckusick  * nfs hard link create call
155038414Smckusick  */
155152234Sheideman int
155253806Smckusick nfs_link(ap)
155354668Smckusick 	struct vop_link_args /* {
155454668Smckusick 		struct vnode *a_vp;
155554668Smckusick 		struct vnode *a_tdvp;
155654668Smckusick 		struct componentname *a_cnp;
155754668Smckusick 	} */ *ap;
155838414Smckusick {
155953806Smckusick 	register struct vnode *vp = ap->a_vp;
156053806Smckusick 	register struct vnode *tdvp = ap->a_tdvp;
156153806Smckusick 	register struct componentname *cnp = ap->a_cnp;
156248054Smckusick 	register u_long *tl;
156339488Smckusick 	register caddr_t cp;
1564*68653Smckusick 	register long t1, t2;
1565*68653Smckusick 	caddr_t bpos, dpos, cp2;
1566*68653Smckusick 	int error = 0, wccflag = NFSV3_WCCRATTR, attrflag = 0;
156739488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
1568*68653Smckusick 	int v3 = NFS_ISV3(vp);
156938414Smckusick 
1570*68653Smckusick 	if (vp->v_mount != tdvp->v_mount) {
1571*68653Smckusick 		/*VOP_ABORTOP(vp, cnp);*/
1572*68653Smckusick 		if (tdvp == vp)
1573*68653Smckusick 			vrele(tdvp);
1574*68653Smckusick 		else
1575*68653Smckusick 			vput(tdvp);
157653804Spendry 		return (EXDEV);
157753804Spendry 	}
157853804Spendry 
157967659Smckusick 	/*
158067659Smckusick 	 * Push all writes to the server, so that the attribute cache
158167659Smckusick 	 * doesn't get "out of sync" with the server.
158267659Smckusick 	 * XXX There should be a better way!
158367659Smckusick 	 */
158468539Smckusick 	VOP_FSYNC(vp, cnp->cn_cred, MNT_WAIT, cnp->cn_proc);
158567659Smckusick 
158638414Smckusick 	nfsstats.rpccnt[NFSPROC_LINK]++;
158768539Smckusick 	nfsm_reqhead(vp, NFSPROC_LINK,
1588*68653Smckusick 		NFSX_FH(v3)*2 + NFSX_UNSIGNED + nfsm_rndup(cnp->cn_namelen));
1589*68653Smckusick 	nfsm_fhtom(vp, v3);
1590*68653Smckusick 	nfsm_fhtom(tdvp, v3);
159153806Smckusick 	nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
159268539Smckusick 	nfsm_request(vp, NFSPROC_LINK, cnp->cn_proc, cnp->cn_cred);
1593*68653Smckusick 	if (v3) {
1594*68653Smckusick 		nfsm_postop_attr(vp, attrflag);
1595*68653Smckusick 		nfsm_wcc_data(tdvp, wccflag);
1596*68653Smckusick 	}
159738414Smckusick 	nfsm_reqdone;
159853806Smckusick 	FREE(cnp->cn_pnbuf, M_NAMEI);
1599*68653Smckusick 	VTONFS(tdvp)->n_flag |= NMODIFIED;
1600*68653Smckusick 	if (!attrflag)
1601*68653Smckusick 		VTONFS(vp)->n_attrstamp = 0;
1602*68653Smckusick 	if (!wccflag)
1603*68653Smckusick 		VTONFS(tdvp)->n_attrstamp = 0;
1604*68653Smckusick 	vrele(tdvp);
160540112Smckusick 	/*
160640112Smckusick 	 * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry.
160740112Smckusick 	 */
160840112Smckusick 	if (error == EEXIST)
160940112Smckusick 		error = 0;
161038414Smckusick 	return (error);
161138414Smckusick }
161238414Smckusick 
161338414Smckusick /*
161438414Smckusick  * nfs symbolic link create call
161538414Smckusick  */
161652234Sheideman int
161753806Smckusick nfs_symlink(ap)
161854668Smckusick 	struct vop_symlink_args /* {
161954668Smckusick 		struct vnode *a_dvp;
162054668Smckusick 		struct vnode **a_vpp;
162154668Smckusick 		struct componentname *a_cnp;
162254668Smckusick 		struct vattr *a_vap;
162354668Smckusick 		char *a_target;
162454668Smckusick 	} */ *ap;
162538414Smckusick {
162653806Smckusick 	register struct vnode *dvp = ap->a_dvp;
162753806Smckusick 	register struct vattr *vap = ap->a_vap;
162853806Smckusick 	register struct componentname *cnp = ap->a_cnp;
162938884Smacklem 	register struct nfsv2_sattr *sp;
1630*68653Smckusick 	register struct nfsv3_sattr *sp3;
163148054Smckusick 	register u_long *tl;
163239488Smckusick 	register caddr_t cp;
1633*68653Smckusick 	register long t1, t2;
1634*68653Smckusick 	caddr_t bpos, dpos, cp2;
1635*68653Smckusick 	int slen, error = 0, wccflag = NFSV3_WCCRATTR, gotvp;
163639488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
1637*68653Smckusick 	struct vnode *newvp = (struct vnode *)0;
1638*68653Smckusick 	int v3 = NFS_ISV3(dvp);
163938414Smckusick 
164038414Smckusick 	nfsstats.rpccnt[NFSPROC_SYMLINK]++;
164153600Sheideman 	slen = strlen(ap->a_target);
1642*68653Smckusick 	nfsm_reqhead(dvp, NFSPROC_SYMLINK, NFSX_FH(v3) + 2*NFSX_UNSIGNED +
1643*68653Smckusick 	    nfsm_rndup(cnp->cn_namelen) + nfsm_rndup(slen) + NFSX_SATTR(v3));
1644*68653Smckusick 	nfsm_fhtom(dvp, v3);
164553806Smckusick 	nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
1646*68653Smckusick 	if (v3) {
1647*68653Smckusick 		nfsm_build(sp3, struct nfsv3_sattr *, NFSX_V3SRVSATTR);
1648*68653Smckusick 		nfsm_v3sattr(sp3, vap, cnp->cn_cred->cr_uid,
1649*68653Smckusick 			cnp->cn_cred->cr_gid);
1650*68653Smckusick 	}
165153600Sheideman 	nfsm_strtom(ap->a_target, slen, NFS_MAXPATHLEN);
1652*68653Smckusick 	if (!v3) {
1653*68653Smckusick 		nfsm_build(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
1654*68653Smckusick 		sp->sa_mode = vtonfsv2_mode(VLNK, vap->va_mode);
1655*68653Smckusick 		sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid);
1656*68653Smckusick 		sp->sa_gid = txdr_unsigned(cnp->cn_cred->cr_gid);
1657*68653Smckusick 		sp->sa_size = -1;
1658*68653Smckusick 		txdr_nfsv2time(&vap->va_atime, &sp->sa_atime);
1659*68653Smckusick 		txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime);
166056289Smckusick 	}
166153806Smckusick 	nfsm_request(dvp, NFSPROC_SYMLINK, cnp->cn_proc, cnp->cn_cred);
1662*68653Smckusick 	if (v3) {
1663*68653Smckusick 		if (!error)
1664*68653Smckusick 			nfsm_mtofh(dvp, newvp, v3, gotvp);
1665*68653Smckusick 		nfsm_wcc_data(dvp, wccflag);
1666*68653Smckusick 	}
166738414Smckusick 	nfsm_reqdone;
1668*68653Smckusick 	if (newvp)
1669*68653Smckusick 		vrele(newvp);
167053806Smckusick 	FREE(cnp->cn_pnbuf, M_NAMEI);
167153806Smckusick 	VTONFS(dvp)->n_flag |= NMODIFIED;
1672*68653Smckusick 	if (!wccflag)
1673*68653Smckusick 		VTONFS(dvp)->n_attrstamp = 0;
167453806Smckusick 	vrele(dvp);
167540112Smckusick 	/*
167640112Smckusick 	 * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry.
167740112Smckusick 	 */
167840112Smckusick 	if (error == EEXIST)
167940112Smckusick 		error = 0;
168038414Smckusick 	return (error);
168138414Smckusick }
168238414Smckusick 
168338414Smckusick /*
168438414Smckusick  * nfs make dir call
168538414Smckusick  */
168652234Sheideman int
168753806Smckusick nfs_mkdir(ap)
168854668Smckusick 	struct vop_mkdir_args /* {
168954668Smckusick 		struct vnode *a_dvp;
169054668Smckusick 		struct vnode **a_vpp;
169154668Smckusick 		struct componentname *a_cnp;
169254668Smckusick 		struct vattr *a_vap;
169354668Smckusick 	} */ *ap;
169438414Smckusick {
169553806Smckusick 	register struct vnode *dvp = ap->a_dvp;
169653806Smckusick 	register struct vattr *vap = ap->a_vap;
169753806Smckusick 	register struct componentname *cnp = ap->a_cnp;
169838884Smacklem 	register struct nfsv2_sattr *sp;
1699*68653Smckusick 	register struct nfsv3_sattr *sp3;
170048054Smckusick 	register u_long *tl;
170139488Smckusick 	register caddr_t cp;
170239488Smckusick 	register long t1, t2;
170341905Smckusick 	register int len;
1704*68653Smckusick 	struct nfsnode *np = (struct nfsnode *)0;
1705*68653Smckusick 	struct vnode *newvp = (struct vnode *)0;
170639488Smckusick 	caddr_t bpos, dpos, cp2;
1707*68653Smckusick 	nfsfh_t *fhp;
1708*68653Smckusick 	int error = 0, wccflag = NFSV3_WCCRATTR, attrflag;
1709*68653Smckusick 	int fhsize, gotvp = 0;
171039488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
171159116Smckusick 	struct vattr vattr;
1712*68653Smckusick 	int v3 = NFS_ISV3(dvp);
171338414Smckusick 
171459116Smckusick 	if (error = VOP_GETATTR(dvp, &vattr, cnp->cn_cred, cnp->cn_proc)) {
171559116Smckusick 		VOP_ABORTOP(dvp, cnp);
171659116Smckusick 		vput(dvp);
171759116Smckusick 		return (error);
171859116Smckusick 	}
171953806Smckusick 	len = cnp->cn_namelen;
172038414Smckusick 	nfsstats.rpccnt[NFSPROC_MKDIR]++;
172153806Smckusick 	nfsm_reqhead(dvp, NFSPROC_MKDIR,
1722*68653Smckusick 	  NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(len) + NFSX_SATTR(v3));
1723*68653Smckusick 	nfsm_fhtom(dvp, v3);
172453806Smckusick 	nfsm_strtom(cnp->cn_nameptr, len, NFS_MAXNAMLEN);
1725*68653Smckusick 	if (v3) {
1726*68653Smckusick 		nfsm_build(sp3, struct nfsv3_sattr *, NFSX_V3SRVSATTR);
1727*68653Smckusick 		nfsm_v3sattr(sp3, vap, cnp->cn_cred->cr_uid, vattr.va_gid);
172856289Smckusick 	} else {
1729*68653Smckusick 		nfsm_build(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
1730*68653Smckusick 		sp->sa_mode = vtonfsv2_mode(VDIR, vap->va_mode);
1731*68653Smckusick 		sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid);
1732*68653Smckusick 		sp->sa_gid = txdr_unsigned(vattr.va_gid);
1733*68653Smckusick 		sp->sa_size = -1;
1734*68653Smckusick 		txdr_nfsv2time(&vap->va_atime, &sp->sa_atime);
1735*68653Smckusick 		txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime);
173656289Smckusick 	}
173753806Smckusick 	nfsm_request(dvp, NFSPROC_MKDIR, cnp->cn_proc, cnp->cn_cred);
1738*68653Smckusick 	if (!error)
1739*68653Smckusick 		nfsm_mtofh(dvp, newvp, v3, gotvp);
1740*68653Smckusick 	if (v3)
1741*68653Smckusick 		nfsm_wcc_data(dvp, wccflag);
174238414Smckusick 	nfsm_reqdone;
174353806Smckusick 	VTONFS(dvp)->n_flag |= NMODIFIED;
1744*68653Smckusick 	if (!wccflag)
1745*68653Smckusick 		VTONFS(dvp)->n_attrstamp = 0;
174640112Smckusick 	/*
174741905Smckusick 	 * Kludge: Map EEXIST => 0 assuming that you have a reply to a retry
174841905Smckusick 	 * if we can succeed in looking up the directory.
174940112Smckusick 	 */
1750*68653Smckusick 	if (error == EEXIST || (!error && !gotvp)) {
1751*68653Smckusick 		if (newvp) {
1752*68653Smckusick 			vrele(newvp);
1753*68653Smckusick 			newvp = (struct vnode *)0;
175441905Smckusick 		}
1755*68653Smckusick 		error = nfs_lookitup(dvp, cnp->cn_nameptr, len, cnp->cn_cred,
1756*68653Smckusick 			cnp->cn_proc, &np);
1757*68653Smckusick 		if (!error) {
1758*68653Smckusick 			newvp = NFSTOV(np);
1759*68653Smckusick 			if (newvp->v_type != VDIR)
1760*68653Smckusick 				error = EEXIST;
1761*68653Smckusick 		}
176241905Smckusick 	}
1763*68653Smckusick 	if (error) {
1764*68653Smckusick 		if (newvp)
1765*68653Smckusick 			vrele(newvp);
1766*68653Smckusick 	} else
1767*68653Smckusick 		*ap->a_vpp = newvp;
176853806Smckusick 	FREE(cnp->cn_pnbuf, M_NAMEI);
176953806Smckusick 	vrele(dvp);
177038414Smckusick 	return (error);
177138414Smckusick }
177238414Smckusick 
177338414Smckusick /*
177438414Smckusick  * nfs remove directory call
177538414Smckusick  */
177652234Sheideman int
177753806Smckusick nfs_rmdir(ap)
177854668Smckusick 	struct vop_rmdir_args /* {
177954668Smckusick 		struct vnode *a_dvp;
178054668Smckusick 		struct vnode *a_vp;
178154668Smckusick 		struct componentname *a_cnp;
178254668Smckusick 	} */ *ap;
178338414Smckusick {
178453806Smckusick 	register struct vnode *vp = ap->a_vp;
178553806Smckusick 	register struct vnode *dvp = ap->a_dvp;
178653806Smckusick 	register struct componentname *cnp = ap->a_cnp;
178748054Smckusick 	register u_long *tl;
178839488Smckusick 	register caddr_t cp;
1789*68653Smckusick 	register long t1, t2;
1790*68653Smckusick 	caddr_t bpos, dpos, cp2;
1791*68653Smckusick 	int error = 0, wccflag = NFSV3_WCCRATTR;
179239488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
1793*68653Smckusick 	int v3 = NFS_ISV3(dvp);
179438414Smckusick 
179553806Smckusick 	if (dvp == vp) {
179653806Smckusick 		vrele(dvp);
179753806Smckusick 		vrele(dvp);
179853806Smckusick 		FREE(cnp->cn_pnbuf, M_NAMEI);
179938414Smckusick 		return (EINVAL);
180038414Smckusick 	}
180138414Smckusick 	nfsstats.rpccnt[NFSPROC_RMDIR]++;
180253806Smckusick 	nfsm_reqhead(dvp, NFSPROC_RMDIR,
1803*68653Smckusick 		NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(cnp->cn_namelen));
1804*68653Smckusick 	nfsm_fhtom(dvp, v3);
180553806Smckusick 	nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
180653806Smckusick 	nfsm_request(dvp, NFSPROC_RMDIR, cnp->cn_proc, cnp->cn_cred);
1807*68653Smckusick 	if (v3)
1808*68653Smckusick 		nfsm_wcc_data(dvp, wccflag);
180938414Smckusick 	nfsm_reqdone;
181053806Smckusick 	FREE(cnp->cn_pnbuf, M_NAMEI);
181153806Smckusick 	VTONFS(dvp)->n_flag |= NMODIFIED;
1812*68653Smckusick 	if (!wccflag)
1813*68653Smckusick 		VTONFS(dvp)->n_attrstamp = 0;
181453806Smckusick 	cache_purge(dvp);
181553806Smckusick 	cache_purge(vp);
181653806Smckusick 	vrele(vp);
181753806Smckusick 	vrele(dvp);
181840112Smckusick 	/*
181940112Smckusick 	 * Kludge: Map ENOENT => 0 assuming that you have a reply to a retry.
182040112Smckusick 	 */
182140112Smckusick 	if (error == ENOENT)
182240112Smckusick 		error = 0;
182338414Smckusick 	return (error);
182438414Smckusick }
182538414Smckusick 
182638414Smckusick /*
182738414Smckusick  * nfs readdir call
182838414Smckusick  */
182952234Sheideman int
183053806Smckusick nfs_readdir(ap)
183154668Smckusick 	struct vop_readdir_args /* {
183254668Smckusick 		struct vnode *a_vp;
183354668Smckusick 		struct uio *a_uio;
183454668Smckusick 		struct ucred *a_cred;
183554668Smckusick 	} */ *ap;
183638414Smckusick {
183753806Smckusick 	register struct vnode *vp = ap->a_vp;
183853806Smckusick 	register struct nfsnode *np = VTONFS(vp);
183953806Smckusick 	register struct uio *uio = ap->a_uio;
184041905Smckusick 	int tresid, error;
184141905Smckusick 	struct vattr vattr;
184241905Smckusick 
184353806Smckusick 	if (vp->v_type != VDIR)
184441905Smckusick 		return (EPERM);
184541905Smckusick 	/*
184641905Smckusick 	 * First, check for hit on the EOF offset cache
184741905Smckusick 	 */
1848*68653Smckusick 	if (np->n_direofoffset > 0 && uio->uio_offset >= np->n_direofoffset &&
184952196Smckusick 	    (np->n_flag & NMODIFIED) == 0) {
185053806Smckusick 		if (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) {
1851*68653Smckusick 			if (NQNFS_CKCACHABLE(vp, ND_READ)) {
185252196Smckusick 				nfsstats.direofcache_hits++;
185352196Smckusick 				return (0);
185452196Smckusick 			}
185553806Smckusick 		} else if (VOP_GETATTR(vp, &vattr, ap->a_cred, uio->uio_procp) == 0 &&
185654106Smckusick 			np->n_mtime == vattr.va_mtime.ts_sec) {
185752196Smckusick 			nfsstats.direofcache_hits++;
185852196Smckusick 			return (0);
185952196Smckusick 		}
186041905Smckusick 	}
186141905Smckusick 
186241905Smckusick 	/*
186341905Smckusick 	 * Call nfs_bioread() to do the real work.
186441905Smckusick 	 */
186553806Smckusick 	tresid = uio->uio_resid;
186653806Smckusick 	error = nfs_bioread(vp, uio, 0, ap->a_cred);
186741905Smckusick 
186854451Smckusick 	if (!error && uio->uio_resid == tresid)
186941905Smckusick 		nfsstats.direofcache_misses++;
187041905Smckusick 	return (error);
187141905Smckusick }
187241905Smckusick 
187341905Smckusick /*
187441905Smckusick  * Readdir rpc call.
187541905Smckusick  * Called from below the buffer cache by nfs_doio().
187641905Smckusick  */
187752234Sheideman int
187848054Smckusick nfs_readdirrpc(vp, uiop, cred)
1879*68653Smckusick 	struct vnode *vp;
1880*68653Smckusick 	register struct uio *uiop;
188141905Smckusick 	struct ucred *cred;
188241905Smckusick {
1883*68653Smckusick 	register int len, left;
188454740Smckusick 	register struct dirent *dp;
188548054Smckusick 	register u_long *tl;
188639488Smckusick 	register caddr_t cp;
1887*68653Smckusick 	register long t1, t2;
1888*68653Smckusick 	register nfsuint64 *cookiep;
188939488Smckusick 	caddr_t bpos, dpos, cp2;
189039488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
1891*68653Smckusick 	nfsuint64 cookie;
1892*68653Smckusick 	struct nfsmount *nmp = VFSTONFS(vp->v_mount);
1893*68653Smckusick 	struct nfsnode *dnp = VTONFS(vp);
1894*68653Smckusick 	nfsfh_t *fhp;
1895*68653Smckusick 	u_quad_t frev, fileno;
1896*68653Smckusick 	int error = 0, tlen, more_dirs = 1, blksiz = 0, bigenough = 1, i;
1897*68653Smckusick 	int cachable, attrflag, fhsize;
1898*68653Smckusick 	int v3 = NFS_ISV3(vp);
189938414Smckusick 
1900*68653Smckusick #ifndef nolint
1901*68653Smckusick 	dp = (struct dirent *)0;
1902*68653Smckusick #endif
1903*68653Smckusick #ifndef DIAGNOSTIC
1904*68653Smckusick 	if (uiop->uio_iovcnt != 1 || (uiop->uio_offset & (NFS_DIRBLKSIZ - 1)) ||
1905*68653Smckusick 		(uiop->uio_resid & (NFS_DIRBLKSIZ - 1)))
1906*68653Smckusick 		panic("nfs readdirrpc bad uio");
1907*68653Smckusick #endif
1908*68653Smckusick 
190940296Smckusick 	/*
1910*68653Smckusick 	 * If there is no cookie, assume end of directory.
1911*68653Smckusick 	 */
1912*68653Smckusick 	cookiep = nfs_getcookie(dnp, uiop->uio_offset, 0);
1913*68653Smckusick 	if (cookiep)
1914*68653Smckusick 		cookie = *cookiep;
1915*68653Smckusick 	else
1916*68653Smckusick 		return (0);
1917*68653Smckusick 	/*
1918*68653Smckusick 	 * Loop around doing readdir rpc's of size nm_readdirsize
1919*68653Smckusick 	 * truncated to a multiple of DIRBLKSIZ.
192041905Smckusick 	 * The stopping criteria is EOF or buffer full.
192140296Smckusick 	 */
1922*68653Smckusick 	while (more_dirs && bigenough) {
192340296Smckusick 		nfsstats.rpccnt[NFSPROC_READDIR]++;
1924*68653Smckusick 		nfsm_reqhead(vp, NFSPROC_READDIR, NFSX_FH(v3) +
1925*68653Smckusick 			NFSX_READDIR(v3));
1926*68653Smckusick 		nfsm_fhtom(vp, v3);
1927*68653Smckusick 		if (v3) {
1928*68653Smckusick 			nfsm_build(tl, u_long *, 5 * NFSX_UNSIGNED);
1929*68653Smckusick 			*tl++ = cookie.nfsuquad[0];
1930*68653Smckusick 			*tl++ = cookie.nfsuquad[1];
1931*68653Smckusick 			*tl++ = dnp->n_cookieverf.nfsuquad[0];
1932*68653Smckusick 			*tl++ = dnp->n_cookieverf.nfsuquad[1];
1933*68653Smckusick 		} else {
1934*68653Smckusick 			nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED);
1935*68653Smckusick 			*tl++ = cookie.nfsuquad[0];
1936*68653Smckusick 		}
1937*68653Smckusick 		*tl = txdr_unsigned(nmp->nm_readdirsize);
193852196Smckusick 		nfsm_request(vp, NFSPROC_READDIR, uiop->uio_procp, cred);
1939*68653Smckusick 		if (v3) {
1940*68653Smckusick 			nfsm_postop_attr(vp, attrflag);
1941*68653Smckusick 			if (!error) {
1942*68653Smckusick 				nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
1943*68653Smckusick 				dnp->n_cookieverf.nfsuquad[0] = *tl++;
1944*68653Smckusick 				dnp->n_cookieverf.nfsuquad[1] = *tl;
1945*68653Smckusick 			} else {
1946*68653Smckusick 				m_freem(mrep);
1947*68653Smckusick 				goto nfsmout;
1948*68653Smckusick 			}
1949*68653Smckusick 		}
195052196Smckusick 		nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
195148054Smckusick 		more_dirs = fxdr_unsigned(int, *tl);
195240296Smckusick 
195340296Smckusick 		/* loop thru the dir entries, doctoring them to 4bsd form */
1954*68653Smckusick 		while (more_dirs && bigenough) {
1955*68653Smckusick 			if (v3) {
1956*68653Smckusick 				nfsm_dissect(tl, u_long *, 3 * NFSX_UNSIGNED);
1957*68653Smckusick 				fxdr_hyper(tl, &fileno);
1958*68653Smckusick 				len = fxdr_unsigned(int, *(tl + 2));
1959*68653Smckusick 			} else {
1960*68653Smckusick 				nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
1961*68653Smckusick 				fileno = fxdr_unsigned(u_quad_t, *tl++);
1962*68653Smckusick 				len = fxdr_unsigned(int, *tl);
1963*68653Smckusick 			}
196440296Smckusick 			if (len <= 0 || len > NFS_MAXNAMLEN) {
196540296Smckusick 				error = EBADRPC;
196640296Smckusick 				m_freem(mrep);
196740296Smckusick 				goto nfsmout;
196840296Smckusick 			}
196940296Smckusick 			tlen = nfsm_rndup(len);
1970*68653Smckusick 			if (tlen == len)
1971*68653Smckusick 				tlen += 4;	/* To ensure null termination */
1972*68653Smckusick 			left = DIRBLKSIZ - blksiz;
1973*68653Smckusick 			if ((tlen + DIRHDSIZ) > left) {
1974*68653Smckusick 				dp->d_reclen += left;
1975*68653Smckusick 				uiop->uio_iov->iov_base += left;
1976*68653Smckusick 				uiop->uio_iov->iov_len -= left;
1977*68653Smckusick 				uiop->uio_offset += left;
1978*68653Smckusick 				uiop->uio_resid -= left;
1979*68653Smckusick 				blksiz = 0;
198040296Smckusick 			}
1981*68653Smckusick 			if ((tlen + DIRHDSIZ) > uiop->uio_resid)
1982*68653Smckusick 				bigenough = 0;
1983*68653Smckusick 			if (bigenough) {
1984*68653Smckusick 				dp = (struct dirent *)uiop->uio_iov->iov_base;
1985*68653Smckusick 				dp->d_fileno = (int)fileno;
1986*68653Smckusick 				dp->d_namlen = len;
1987*68653Smckusick 				dp->d_reclen = tlen + DIRHDSIZ;
1988*68653Smckusick 				dp->d_type = DT_UNKNOWN;
1989*68653Smckusick 				blksiz += dp->d_reclen;
1990*68653Smckusick 				if (blksiz == DIRBLKSIZ)
1991*68653Smckusick 					blksiz = 0;
1992*68653Smckusick 				uiop->uio_offset += DIRHDSIZ;
1993*68653Smckusick 				uiop->uio_resid -= DIRHDSIZ;
1994*68653Smckusick 				uiop->uio_iov->iov_base += DIRHDSIZ;
1995*68653Smckusick 				uiop->uio_iov->iov_len -= DIRHDSIZ;
1996*68653Smckusick 				nfsm_mtouio(uiop, len);
1997*68653Smckusick 				cp = uiop->uio_iov->iov_base;
1998*68653Smckusick 				tlen -= len;
1999*68653Smckusick 				*cp = '\0';	/* null terminate */
2000*68653Smckusick 				uiop->uio_iov->iov_base += tlen;
2001*68653Smckusick 				uiop->uio_iov->iov_len -= tlen;
2002*68653Smckusick 				uiop->uio_offset += tlen;
2003*68653Smckusick 				uiop->uio_resid -= tlen;
2004*68653Smckusick 			} else
2005*68653Smckusick 				nfsm_adv(nfsm_rndup(len));
2006*68653Smckusick 			if (v3) {
2007*68653Smckusick 				nfsm_dissect(tl, u_long *, 3 * NFSX_UNSIGNED);
2008*68653Smckusick 			} else {
2009*68653Smckusick 				nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
2010*68653Smckusick 			}
2011*68653Smckusick 			if (bigenough) {
2012*68653Smckusick 				cookie.nfsuquad[0] = *tl++;
2013*68653Smckusick 				if (v3)
2014*68653Smckusick 					cookie.nfsuquad[1] = *tl++;
2015*68653Smckusick 			} else if (v3)
2016*68653Smckusick 				tl += 2;
2017*68653Smckusick 			else
2018*68653Smckusick 				tl++;
201948054Smckusick 			more_dirs = fxdr_unsigned(int, *tl);
202040296Smckusick 		}
202140296Smckusick 		/*
202240296Smckusick 		 * If at end of rpc data, get the eof boolean
202340296Smckusick 		 */
202440296Smckusick 		if (!more_dirs) {
202563483Smckusick 			nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
202648054Smckusick 			more_dirs = (fxdr_unsigned(int, *tl) == 0);
202738414Smckusick 		}
202840296Smckusick 		m_freem(mrep);
202938414Smckusick 	}
203041905Smckusick 	/*
2031*68653Smckusick 	 * Fill last record, iff any, out to a multiple of DIRBLKSIZ
203241905Smckusick 	 * by increasing d_reclen for the last record.
203341905Smckusick 	 */
2034*68653Smckusick 	if (blksiz > 0) {
2035*68653Smckusick 		left = DIRBLKSIZ - blksiz;
2036*68653Smckusick 		dp->d_reclen += left;
2037*68653Smckusick 		uiop->uio_iov->iov_base += left;
2038*68653Smckusick 		uiop->uio_iov->iov_len -= left;
2039*68653Smckusick 		uiop->uio_offset += left;
2040*68653Smckusick 		uiop->uio_resid -= left;
204141905Smckusick 	}
2042*68653Smckusick 
2043*68653Smckusick 	/*
2044*68653Smckusick 	 * We are now either at the end of the directory or have filled the
2045*68653Smckusick 	 * block.
2046*68653Smckusick 	 */
2047*68653Smckusick 	if (bigenough)
2048*68653Smckusick 		dnp->n_direofoffset = uiop->uio_offset;
2049*68653Smckusick 	else {
2050*68653Smckusick 		if (uiop->uio_resid > 0)
2051*68653Smckusick 			printf("EEK! readdirrpc resid > 0\n");
2052*68653Smckusick 		cookiep = nfs_getcookie(dnp, uiop->uio_offset, 1);
2053*68653Smckusick 		*cookiep = cookie;
2054*68653Smckusick 	}
205540296Smckusick nfsmout:
205638414Smckusick 	return (error);
205738414Smckusick }
205838414Smckusick 
205952196Smckusick /*
2060*68653Smckusick  * NFS V3 readdir plus RPC. Used in place of nfs_readdirrpc().
206152196Smckusick  */
206252234Sheideman int
2063*68653Smckusick nfs_readdirplusrpc(vp, uiop, cred)
206452196Smckusick 	struct vnode *vp;
206552196Smckusick 	register struct uio *uiop;
206652196Smckusick 	struct ucred *cred;
206752196Smckusick {
2068*68653Smckusick 	register int len, left;
206954740Smckusick 	register struct dirent *dp;
207052196Smckusick 	register u_long *tl;
207152196Smckusick 	register caddr_t cp;
2072*68653Smckusick 	register long t1, t2;
2073*68653Smckusick 	register struct vnode *newvp;
2074*68653Smckusick 	register nfsuint64 *cookiep;
2075*68653Smckusick 	caddr_t bpos, dpos, cp2, dpossav1, dpossav2;
2076*68653Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2, *mdsav1, *mdsav2;
207752196Smckusick 	struct nameidata nami, *ndp = &nami;
207852317Sheideman 	struct componentname *cnp = &ndp->ni_cnd;
2079*68653Smckusick 	nfsuint64 cookie;
2080*68653Smckusick 	struct nfsmount *nmp = VFSTONFS(vp->v_mount);
2081*68653Smckusick 	struct nfsnode *dnp = VTONFS(vp), *np;
2082*68653Smckusick 	nfsfh_t *fhp;
2083*68653Smckusick 	u_quad_t frev, fileno;
2084*68653Smckusick 	int error = 0, tlen, more_dirs = 1, blksiz = 0, doit, bigenough = 1, i;
2085*68653Smckusick 	int cachable, attrflag, fhsize;
208652196Smckusick 
2087*68653Smckusick #ifndef nolint
2088*68653Smckusick 	dp = (struct dirent *)0;
2089*68653Smckusick #endif
2090*68653Smckusick #ifndef DIAGNOSTIC
2091*68653Smckusick 	if (uiop->uio_iovcnt != 1 || (uiop->uio_offset & (DIRBLKSIZ - 1)) ||
2092*68653Smckusick 		(uiop->uio_resid & (DIRBLKSIZ - 1)))
2093*68653Smckusick 		panic("nfs readdirplusrpc bad uio");
2094*68653Smckusick #endif
209552196Smckusick 	ndp->ni_dvp = vp;
209652196Smckusick 	newvp = NULLVP;
2097*68653Smckusick 
209852196Smckusick 	/*
2099*68653Smckusick 	 * If there is no cookie, assume end of directory.
2100*68653Smckusick 	 */
2101*68653Smckusick 	cookiep = nfs_getcookie(dnp, uiop->uio_offset, 0);
2102*68653Smckusick 	if (cookiep)
2103*68653Smckusick 		cookie = *cookiep;
2104*68653Smckusick 	else
2105*68653Smckusick 		return (0);
2106*68653Smckusick 	/*
2107*68653Smckusick 	 * Loop around doing readdir rpc's of size nm_readdirsize
2108*68653Smckusick 	 * truncated to a multiple of DIRBLKSIZ.
210952196Smckusick 	 * The stopping criteria is EOF or buffer full.
211052196Smckusick 	 */
2111*68653Smckusick 	while (more_dirs && bigenough) {
2112*68653Smckusick 		nfsstats.rpccnt[NFSPROC_READDIRPLUS]++;
2113*68653Smckusick 		nfsm_reqhead(vp, NFSPROC_READDIRPLUS,
2114*68653Smckusick 			NFSX_FH(1) + 6 * NFSX_UNSIGNED);
2115*68653Smckusick 		nfsm_fhtom(vp, 1);
2116*68653Smckusick  		nfsm_build(tl, u_long *, 6 * NFSX_UNSIGNED);
2117*68653Smckusick 		*tl++ = cookie.nfsuquad[0];
2118*68653Smckusick 		*tl++ = cookie.nfsuquad[1];
2119*68653Smckusick 		*tl++ = dnp->n_cookieverf.nfsuquad[0];
2120*68653Smckusick 		*tl++ = dnp->n_cookieverf.nfsuquad[1];
2121*68653Smckusick 		*tl++ = txdr_unsigned(nmp->nm_readdirsize);
2122*68653Smckusick 		*tl = txdr_unsigned(nmp->nm_rsize);
2123*68653Smckusick 		nfsm_request(vp, NFSPROC_READDIRPLUS, uiop->uio_procp, cred);
2124*68653Smckusick 		nfsm_postop_attr(vp, attrflag);
2125*68653Smckusick 		if (error) {
2126*68653Smckusick 			m_freem(mrep);
2127*68653Smckusick 			goto nfsmout;
2128*68653Smckusick 		}
2129*68653Smckusick 		nfsm_dissect(tl, u_long *, 3 * NFSX_UNSIGNED);
2130*68653Smckusick 		dnp->n_cookieverf.nfsuquad[0] = *tl++;
2131*68653Smckusick 		dnp->n_cookieverf.nfsuquad[1] = *tl++;
213252196Smckusick 		more_dirs = fxdr_unsigned(int, *tl);
213352196Smckusick 
213452196Smckusick 		/* loop thru the dir entries, doctoring them to 4bsd form */
213552196Smckusick 		while (more_dirs && bigenough) {
2136*68653Smckusick 			nfsm_dissect(tl, u_long *, 3 * NFSX_UNSIGNED);
2137*68653Smckusick 			fxdr_hyper(tl, &fileno);
2138*68653Smckusick 			len = fxdr_unsigned(int, *(tl + 2));
213952196Smckusick 			if (len <= 0 || len > NFS_MAXNAMLEN) {
214052196Smckusick 				error = EBADRPC;
214152196Smckusick 				m_freem(mrep);
214252196Smckusick 				goto nfsmout;
214352196Smckusick 			}
2144*68653Smckusick 			tlen = nfsm_rndup(len);
2145*68653Smckusick 			if (tlen == len)
2146*68653Smckusick 				tlen += 4;	/* To ensure null termination*/
2147*68653Smckusick 			left = DIRBLKSIZ - blksiz;
2148*68653Smckusick 			if ((tlen + DIRHDSIZ) > left) {
2149*68653Smckusick 				dp->d_reclen += left;
2150*68653Smckusick 				uiop->uio_iov->iov_base += left;
2151*68653Smckusick 				uiop->uio_iov->iov_len -= left;
2152*68653Smckusick 				uiop->uio_offset += left;
2153*68653Smckusick 				uiop->uio_resid -= left;
2154*68653Smckusick 				blksiz = 0;
2155*68653Smckusick 			}
215652196Smckusick 			if ((tlen + DIRHDSIZ) > uiop->uio_resid)
215752196Smckusick 				bigenough = 0;
2158*68653Smckusick 			if (bigenough) {
215954740Smckusick 				dp = (struct dirent *)uiop->uio_iov->iov_base;
2160*68653Smckusick 				dp->d_fileno = (int)fileno;
216152196Smckusick 				dp->d_namlen = len;
216252196Smckusick 				dp->d_reclen = tlen + DIRHDSIZ;
2163*68653Smckusick 				dp->d_type = DT_UNKNOWN;
2164*68653Smckusick 				blksiz += dp->d_reclen;
2165*68653Smckusick 				if (blksiz == DIRBLKSIZ)
2166*68653Smckusick 					blksiz = 0;
2167*68653Smckusick 				uiop->uio_offset += DIRHDSIZ;
216852196Smckusick 				uiop->uio_resid -= DIRHDSIZ;
216952196Smckusick 				uiop->uio_iov->iov_base += DIRHDSIZ;
217052196Smckusick 				uiop->uio_iov->iov_len -= DIRHDSIZ;
217152317Sheideman 				cnp->cn_nameptr = uiop->uio_iov->iov_base;
217252317Sheideman 				cnp->cn_namelen = len;
217352196Smckusick 				nfsm_mtouio(uiop, len);
217452196Smckusick 				cp = uiop->uio_iov->iov_base;
217552196Smckusick 				tlen -= len;
2176*68653Smckusick 				*cp = '\0';
217752196Smckusick 				uiop->uio_iov->iov_base += tlen;
217852196Smckusick 				uiop->uio_iov->iov_len -= tlen;
2179*68653Smckusick 				uiop->uio_offset += tlen;
218052196Smckusick 				uiop->uio_resid -= tlen;
2181*68653Smckusick 			} else
2182*68653Smckusick 				nfsm_adv(nfsm_rndup(len));
2183*68653Smckusick 			nfsm_dissect(tl, u_long *, 3 * NFSX_UNSIGNED);
2184*68653Smckusick 			if (bigenough) {
2185*68653Smckusick 				cookie.nfsuquad[0] = *tl++;
2186*68653Smckusick 				cookie.nfsuquad[1] = *tl++;
2187*68653Smckusick 			} else
2188*68653Smckusick 				tl += 2;
2189*68653Smckusick 
2190*68653Smckusick 			/*
2191*68653Smckusick 			 * Since the attributes are before the file handle
2192*68653Smckusick 			 * (sigh), we must skip over the attributes and then
2193*68653Smckusick 			 * come back and get them.
2194*68653Smckusick 			 */
2195*68653Smckusick 			attrflag = fxdr_unsigned(int, *tl);
2196*68653Smckusick 			if (attrflag) {
2197*68653Smckusick 			    dpossav1 = dpos;
2198*68653Smckusick 			    mdsav1 = md;
2199*68653Smckusick 			    nfsm_adv(NFSX_V3FATTR);
2200*68653Smckusick 			    nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
2201*68653Smckusick 			    doit = fxdr_unsigned(int, *tl);
2202*68653Smckusick 			    if (doit) {
2203*68653Smckusick 				nfsm_getfh(fhp, fhsize, 1);
2204*68653Smckusick 				if (NFS_CMPFH(dnp, fhp, fhsize)) {
2205*68653Smckusick 				    VREF(vp);
2206*68653Smckusick 				    newvp = vp;
2207*68653Smckusick 				    np = dnp;
2208*68653Smckusick 				} else {
2209*68653Smckusick 				    if (error = nfs_nget(vp->v_mount, fhp,
2210*68653Smckusick 					fhsize, &np))
2211*68653Smckusick 					doit = 0;
2212*68653Smckusick 				    else
2213*68653Smckusick 					newvp = NFSTOV(np);
2214*68653Smckusick 				}
2215*68653Smckusick 			    }
2216*68653Smckusick 			    if (doit) {
2217*68653Smckusick 				dpossav2 = dpos;
2218*68653Smckusick 				dpos = dpossav1;
2219*68653Smckusick 				mdsav2 = md;
2220*68653Smckusick 				md = mdsav1;
2221*68653Smckusick 				nfsm_loadattr(newvp, (struct vattr *)0);
2222*68653Smckusick 				dpos = dpossav2;
2223*68653Smckusick 				md = mdsav2;
2224*68653Smckusick 				dp->d_type =
2225*68653Smckusick 				    IFTODT(VTTOIF(np->n_vattr.va_type));
2226*68653Smckusick 				ndp->ni_vp = newvp;
222752317Sheideman 				cnp->cn_hash = 0;
2228*68653Smckusick 				for (cp = cnp->cn_nameptr, i = 1; i <= len;
2229*68653Smckusick 				    i++, cp++)
2230*68653Smckusick 				    cnp->cn_hash += (unsigned char)*cp * i;
223156927Smckusick 				if (cnp->cn_namelen <= NCHNAMLEN)
223257791Smckusick 				    cache_enter(ndp->ni_dvp, ndp->ni_vp, cnp);
2233*68653Smckusick 			    }
223452196Smckusick 			} else {
2235*68653Smckusick 			    /* Just skip over the file handle */
2236*68653Smckusick 			    nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
2237*68653Smckusick 			    i = fxdr_unsigned(int, *tl);
2238*68653Smckusick 			    nfsm_adv(nfsm_rndup(i));
223952196Smckusick 			}
224052196Smckusick 			if (newvp != NULLVP) {
2241*68653Smckusick 			    vrele(newvp);
2242*68653Smckusick 			    newvp = NULLVP;
224352196Smckusick 			}
2244*68653Smckusick 			nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
224552196Smckusick 			more_dirs = fxdr_unsigned(int, *tl);
224652196Smckusick 		}
224752196Smckusick 		/*
224852196Smckusick 		 * If at end of rpc data, get the eof boolean
224952196Smckusick 		 */
225052196Smckusick 		if (!more_dirs) {
225152196Smckusick 			nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
225252196Smckusick 			more_dirs = (fxdr_unsigned(int, *tl) == 0);
225352196Smckusick 		}
225452196Smckusick 		m_freem(mrep);
225552196Smckusick 	}
225652196Smckusick 	/*
225752196Smckusick 	 * Fill last record, iff any, out to a multiple of NFS_DIRBLKSIZ
225852196Smckusick 	 * by increasing d_reclen for the last record.
225952196Smckusick 	 */
2260*68653Smckusick 	if (blksiz > 0) {
2261*68653Smckusick 		left = DIRBLKSIZ - blksiz;
2262*68653Smckusick 		dp->d_reclen += left;
2263*68653Smckusick 		uiop->uio_iov->iov_base += left;
2264*68653Smckusick 		uiop->uio_iov->iov_len -= left;
2265*68653Smckusick 		uiop->uio_offset += left;
2266*68653Smckusick 		uiop->uio_resid -= left;
226752196Smckusick 	}
2268*68653Smckusick 
2269*68653Smckusick 	/*
2270*68653Smckusick 	 * We are now either at the end of the directory or have filled the
2271*68653Smckusick 	 * block.
2272*68653Smckusick 	 */
2273*68653Smckusick 	if (bigenough)
2274*68653Smckusick 		dnp->n_direofoffset = uiop->uio_offset;
2275*68653Smckusick 	else {
2276*68653Smckusick 		if (uiop->uio_resid > 0)
2277*68653Smckusick 			printf("EEK! readdirplusrpc resid > 0\n");
2278*68653Smckusick 		cookiep = nfs_getcookie(dnp, uiop->uio_offset, 1);
2279*68653Smckusick 		*cookiep = cookie;
2280*68653Smckusick 	}
228152196Smckusick nfsmout:
228252196Smckusick 	if (newvp != NULLVP)
228352196Smckusick 		vrele(newvp);
228452196Smckusick 	return (error);
228552196Smckusick }
228639488Smckusick static char hextoasc[] = "0123456789abcdef";
228738414Smckusick 
228838414Smckusick /*
228938414Smckusick  * Silly rename. To make the NFS filesystem that is stateless look a little
229038414Smckusick  * more like the "ufs" a remove of an active vnode is translated to a rename
229138414Smckusick  * to a funny looking filename that is removed by nfs_inactive on the
229238414Smckusick  * nfsnode. There is the potential for another process on a different client
229338414Smckusick  * to create the same funny name between the nfs_lookitup() fails and the
229438414Smckusick  * nfs_rename() completes, but...
229538414Smckusick  */
229652234Sheideman int
229752317Sheideman nfs_sillyrename(dvp, vp, cnp)
229852234Sheideman 	struct vnode *dvp, *vp;
229952234Sheideman 	struct componentname *cnp;
230038414Smckusick {
230138414Smckusick 	register struct sillyrename *sp;
2302*68653Smckusick 	struct nfsnode *np;
230338414Smckusick 	int error;
230438414Smckusick 	short pid;
230538414Smckusick 
230652234Sheideman 	cache_purge(dvp);
230752234Sheideman 	np = VTONFS(vp);
2308*68653Smckusick #ifndef DIAGNOSTIC
2309*68653Smckusick 	if (vp->v_type == VDIR)
2310*68653Smckusick 		panic("nfs: sillyrename dir");
2311*68653Smckusick #endif
231238414Smckusick 	MALLOC(sp, struct sillyrename *, sizeof (struct sillyrename),
231348364Smckusick 		M_NFSREQ, M_WAITOK);
231452234Sheideman 	sp->s_cred = crdup(cnp->cn_cred);
231552234Sheideman 	sp->s_dvp = dvp;
231652234Sheideman 	VREF(dvp);
231738414Smckusick 
231838414Smckusick 	/* Fudge together a funny name */
231952234Sheideman 	pid = cnp->cn_proc->p_pid;
232048364Smckusick 	bcopy(".nfsAxxxx4.4", sp->s_name, 13);
232148364Smckusick 	sp->s_namlen = 12;
232248364Smckusick 	sp->s_name[8] = hextoasc[pid & 0xf];
232348364Smckusick 	sp->s_name[7] = hextoasc[(pid >> 4) & 0xf];
232448364Smckusick 	sp->s_name[6] = hextoasc[(pid >> 8) & 0xf];
232548364Smckusick 	sp->s_name[5] = hextoasc[(pid >> 12) & 0xf];
232638414Smckusick 
232738414Smckusick 	/* Try lookitups until we get one that isn't there */
2328*68653Smckusick 	while (nfs_lookitup(dvp, sp->s_name, sp->s_namlen, sp->s_cred,
2329*68653Smckusick 		cnp->cn_proc, (struct nfsnode **)0) == 0) {
233048364Smckusick 		sp->s_name[4]++;
233148364Smckusick 		if (sp->s_name[4] > 'z') {
233238414Smckusick 			error = EINVAL;
233338414Smckusick 			goto bad;
233438414Smckusick 		}
233538414Smckusick 	}
233652234Sheideman 	if (error = nfs_renameit(dvp, cnp, sp))
233738414Smckusick 		goto bad;
2338*68653Smckusick 	error = nfs_lookitup(dvp, sp->s_name, sp->s_namlen, sp->s_cred,
2339*68653Smckusick 		cnp->cn_proc, &np);
234038414Smckusick 	np->n_sillyrename = sp;
234138414Smckusick 	return (0);
234238414Smckusick bad:
234348364Smckusick 	vrele(sp->s_dvp);
234448364Smckusick 	crfree(sp->s_cred);
234548364Smckusick 	free((caddr_t)sp, M_NFSREQ);
234638414Smckusick 	return (error);
234738414Smckusick }
234838414Smckusick 
234938414Smckusick /*
2350*68653Smckusick  * Look up a file name and optionally either update the file handle or
2351*68653Smckusick  * allocate an nfsnode, depending on the value of npp.
2352*68653Smckusick  * npp == NULL	--> just do the lookup
2353*68653Smckusick  * *npp == NULL --> allocate a new nfsnode and make sure attributes are
2354*68653Smckusick  *			handled too
2355*68653Smckusick  * *npp != NULL --> update the file handle in the vnode
235638414Smckusick  */
235752234Sheideman int
2358*68653Smckusick nfs_lookitup(dvp, name, len, cred, procp, npp)
2359*68653Smckusick 	register struct vnode *dvp;
2360*68653Smckusick 	char *name;
2361*68653Smckusick 	int len;
2362*68653Smckusick 	struct ucred *cred;
236352196Smckusick 	struct proc *procp;
2364*68653Smckusick 	struct nfsnode **npp;
236538414Smckusick {
236648054Smckusick 	register u_long *tl;
236739488Smckusick 	register caddr_t cp;
236839488Smckusick 	register long t1, t2;
2369*68653Smckusick 	struct vnode *newvp = (struct vnode *)0;
2370*68653Smckusick 	struct nfsnode *np, *dnp = VTONFS(dvp);
237139488Smckusick 	caddr_t bpos, dpos, cp2;
2372*68653Smckusick 	int error = 0, fhlen, attrflag;
237339488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
2374*68653Smckusick 	nfsfh_t *nfhp;
2375*68653Smckusick 	int v3 = NFS_ISV3(dvp);
237638414Smckusick 
237738414Smckusick 	nfsstats.rpccnt[NFSPROC_LOOKUP]++;
2378*68653Smckusick 	nfsm_reqhead(dvp, NFSPROC_LOOKUP,
2379*68653Smckusick 		NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(len));
2380*68653Smckusick 	nfsm_fhtom(dvp, v3);
2381*68653Smckusick 	nfsm_strtom(name, len, NFS_MAXNAMLEN);
2382*68653Smckusick 	nfsm_request(dvp, NFSPROC_LOOKUP, procp, cred);
2383*68653Smckusick 	if (npp && !error) {
2384*68653Smckusick 		nfsm_getfh(nfhp, fhlen, v3);
2385*68653Smckusick 		if (*npp) {
2386*68653Smckusick 		    np = *npp;
2387*68653Smckusick 		    if (np->n_fhsize > NFS_SMALLFH && fhlen <= NFS_SMALLFH) {
2388*68653Smckusick 			free((caddr_t)np->n_fhp, M_NFSBIGFH);
2389*68653Smckusick 			np->n_fhp = &np->n_fh;
2390*68653Smckusick 		    } else if (np->n_fhsize <= NFS_SMALLFH && fhlen>NFS_SMALLFH)
2391*68653Smckusick 			np->n_fhp =(nfsfh_t *)malloc(fhlen,M_NFSBIGFH,M_WAITOK);
2392*68653Smckusick 		    bcopy((caddr_t)nfhp, (caddr_t)np->n_fhp, fhlen);
2393*68653Smckusick 		    np->n_fhsize = fhlen;
2394*68653Smckusick 		    newvp = NFSTOV(np);
2395*68653Smckusick 		} else if (NFS_CMPFH(dnp, nfhp, fhlen)) {
2396*68653Smckusick 		    VREF(dvp);
2397*68653Smckusick 		    newvp = dvp;
2398*68653Smckusick 		} else {
2399*68653Smckusick 		    error = nfs_nget(dvp->v_mount, nfhp, fhlen, &np);
2400*68653Smckusick 		    if (error) {
2401*68653Smckusick 			m_freem(mrep);
2402*68653Smckusick 			return (error);
2403*68653Smckusick 		    }
2404*68653Smckusick 		    newvp = NFSTOV(np);
2405*68653Smckusick 		}
2406*68653Smckusick 		if (v3) {
2407*68653Smckusick 			nfsm_postop_attr(newvp, attrflag);
2408*68653Smckusick 			if (!attrflag && *npp == NULL) {
2409*68653Smckusick 				m_freem(mrep);
2410*68653Smckusick 				vrele(newvp);
2411*68653Smckusick 				return (ENOENT);
2412*68653Smckusick 			}
2413*68653Smckusick 		} else
2414*68653Smckusick 			nfsm_loadattr(newvp, (struct vattr *)0);
241556289Smckusick 	}
2416*68653Smckusick 	nfsm_reqdone;
2417*68653Smckusick 	if (npp && *npp == NULL) {
2418*68653Smckusick 		if (error) {
2419*68653Smckusick 			if (newvp)
2420*68653Smckusick 				vrele(newvp);
2421*68653Smckusick 		} else
2422*68653Smckusick 			*npp = np;
242338414Smckusick 	}
2424*68653Smckusick 	return (error);
2425*68653Smckusick }
2426*68653Smckusick 
2427*68653Smckusick /*
2428*68653Smckusick  * Nfs Version 3 commit rpc
2429*68653Smckusick  */
2430*68653Smckusick int
2431*68653Smckusick nfs_commit(vp, offset, cnt, cred, procp)
2432*68653Smckusick 	register struct vnode *vp;
2433*68653Smckusick 	u_quad_t offset;
2434*68653Smckusick 	int cnt;
2435*68653Smckusick 	struct ucred *cred;
2436*68653Smckusick 	struct proc *procp;
2437*68653Smckusick {
2438*68653Smckusick 	register caddr_t cp;
2439*68653Smckusick 	register u_long *tl;
2440*68653Smckusick 	register int t1, t2;
2441*68653Smckusick 	register struct nfsmount *nmp = VFSTONFS(vp->v_mount);
2442*68653Smckusick 	caddr_t bpos, dpos, cp2;
2443*68653Smckusick 	int error = 0, wccflag = NFSV3_WCCRATTR;
2444*68653Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
2445*68653Smckusick 
2446*68653Smckusick 	if ((nmp->nm_flag & NFSMNT_HASWRITEVERF) == 0)
2447*68653Smckusick 		return (0);
2448*68653Smckusick 	nfsstats.rpccnt[NFSPROC_COMMIT]++;
2449*68653Smckusick 	nfsm_reqhead(vp, NFSPROC_COMMIT, NFSX_FH(1));
2450*68653Smckusick 	nfsm_fhtom(vp, 1);
2451*68653Smckusick 	nfsm_build(tl, u_long *, 3 * NFSX_UNSIGNED);
2452*68653Smckusick 	txdr_hyper(&offset, tl);
2453*68653Smckusick 	tl += 2;
2454*68653Smckusick 	*tl = txdr_unsigned(cnt);
2455*68653Smckusick 	nfsm_request(vp, NFSPROC_COMMIT, procp, cred);
2456*68653Smckusick 	nfsm_wcc_data(vp, wccflag);
2457*68653Smckusick 	if (!error) {
2458*68653Smckusick 		nfsm_dissect(tl, u_long *, NFSX_V3WRITEVERF);
2459*68653Smckusick 		if (bcmp((caddr_t)nmp->nm_verf, (caddr_t)tl,
2460*68653Smckusick 			NFSX_V3WRITEVERF)) {
2461*68653Smckusick 			bcopy((caddr_t)tl, (caddr_t)nmp->nm_verf,
2462*68653Smckusick 				NFSX_V3WRITEVERF);
2463*68653Smckusick 			error = NFSERR_STALEWRITEVERF;
2464*68653Smckusick 		}
2465*68653Smckusick 	}
246638414Smckusick 	nfsm_reqdone;
246738414Smckusick 	return (error);
246838414Smckusick }
246938414Smckusick 
247038414Smckusick /*
247138414Smckusick  * Kludge City..
247238414Smckusick  * - make nfs_bmap() essentially a no-op that does no translation
2473*68653Smckusick  * - do nfs_strategy() by doing I/O with nfs_readrpc/nfs_writerpc
247438414Smckusick  *   (Maybe I could use the process's page mapping, but I was concerned that
247538414Smckusick  *    Kernel Write might not be enabled and also figured copyout() would do
247638414Smckusick  *    a lot more work than bcopy() and also it currently happens in the
247738414Smckusick  *    context of the swapper process (2).
247838414Smckusick  */
247952234Sheideman int
248053806Smckusick nfs_bmap(ap)
248154668Smckusick 	struct vop_bmap_args /* {
248254668Smckusick 		struct vnode *a_vp;
248354668Smckusick 		daddr_t  a_bn;
248454668Smckusick 		struct vnode **a_vpp;
248554668Smckusick 		daddr_t *a_bnp;
248656452Smargo 		int *a_runp;
248754668Smckusick 	} */ *ap;
248838414Smckusick {
248953806Smckusick 	register struct vnode *vp = ap->a_vp;
249053806Smckusick 
249153600Sheideman 	if (ap->a_vpp != NULL)
249253806Smckusick 		*ap->a_vpp = vp;
249353600Sheideman 	if (ap->a_bnp != NULL)
249453806Smckusick 		*ap->a_bnp = ap->a_bn * btodb(vp->v_mount->mnt_stat.f_iosize);
249538414Smckusick 	return (0);
249638414Smckusick }
249738414Smckusick 
249838414Smckusick /*
249957791Smckusick  * Strategy routine.
250057791Smckusick  * For async requests when nfsiod(s) are running, queue the request by
250157791Smckusick  * calling nfs_asyncio(), otherwise just all nfs_doio() to do the
250257791Smckusick  * request.
250338414Smckusick  */
250452234Sheideman int
250553806Smckusick nfs_strategy(ap)
250657791Smckusick 	struct vop_strategy_args *ap;
250738414Smckusick {
250853806Smckusick 	register struct buf *bp = ap->a_bp;
250957791Smckusick 	struct ucred *cr;
251057791Smckusick 	struct proc *p;
251138884Smacklem 	int error = 0;
251238884Smacklem 
251357791Smckusick 	if (bp->b_flags & B_PHYS)
251457791Smckusick 		panic("nfs physio");
251557791Smckusick 	if (bp->b_flags & B_ASYNC)
251657791Smckusick 		p = (struct proc *)0;
251757791Smckusick 	else
251857791Smckusick 		p = curproc;	/* XXX */
251957791Smckusick 	if (bp->b_flags & B_READ)
252057791Smckusick 		cr = bp->b_rcred;
252157791Smckusick 	else
252257791Smckusick 		cr = bp->b_wcred;
252338884Smacklem 	/*
252446450Skarels 	 * If the op is asynchronous and an i/o daemon is waiting
252538884Smacklem 	 * queue the request, wake it up and wait for completion
252646450Skarels 	 * otherwise just do it ourselves.
252738884Smacklem 	 */
252857791Smckusick 	if ((bp->b_flags & B_ASYNC) == 0 ||
252957791Smckusick 		nfs_asyncio(bp, NOCRED))
253057791Smckusick 		error = nfs_doio(bp, cr, p);
253138884Smacklem 	return (error);
253238884Smacklem }
253338884Smacklem 
253438884Smacklem /*
253548054Smckusick  * Mmap a file
253648054Smckusick  *
253748054Smckusick  * NB Currently unsupported.
253848054Smckusick  */
253948054Smckusick /* ARGSUSED */
254052234Sheideman int
254153806Smckusick nfs_mmap(ap)
254254668Smckusick 	struct vop_mmap_args /* {
254354668Smckusick 		struct vnode *a_vp;
254454668Smckusick 		int  a_fflags;
254554668Smckusick 		struct ucred *a_cred;
254654668Smckusick 		struct proc *a_p;
254754668Smckusick 	} */ *ap;
254848054Smckusick {
254948054Smckusick 
255048054Smckusick 	return (EINVAL);
255148054Smckusick }
255248054Smckusick 
255348054Smckusick /*
2554*68653Smckusick  * fsync vnode op. Just call nfs_flush() with commit == 1.
255538884Smacklem  */
255639488Smckusick /* ARGSUSED */
255752234Sheideman int
255853806Smckusick nfs_fsync(ap)
255954451Smckusick 	struct vop_fsync_args /* {
256054451Smckusick 		struct vnodeop_desc *a_desc;
256154451Smckusick 		struct vnode * a_vp;
256254451Smckusick 		struct ucred * a_cred;
256354451Smckusick 		int  a_waitfor;
256454451Smckusick 		struct proc * a_p;
256554451Smckusick 	} */ *ap;
256638884Smacklem {
2567*68653Smckusick 
2568*68653Smckusick 	return (nfs_flush(ap->a_vp, ap->a_cred, ap->a_waitfor, ap->a_p, 1));
2569*68653Smckusick }
2570*68653Smckusick 
2571*68653Smckusick /*
2572*68653Smckusick  * Flush all the blocks associated with a vnode.
2573*68653Smckusick  * 	Walk through the buffer pool and push any dirty pages
2574*68653Smckusick  *	associated with the vnode.
2575*68653Smckusick  */
2576*68653Smckusick int
2577*68653Smckusick nfs_flush(vp, cred, waitfor, p, commit)
2578*68653Smckusick 	register struct vnode *vp;
2579*68653Smckusick 	struct ucred *cred;
2580*68653Smckusick 	int waitfor;
2581*68653Smckusick 	struct proc *p;
2582*68653Smckusick 	int commit;
2583*68653Smckusick {
258454451Smckusick 	register struct nfsnode *np = VTONFS(vp);
258554451Smckusick 	register struct buf *bp;
2586*68653Smckusick 	register int i;
258754451Smckusick 	struct buf *nbp;
2588*68653Smckusick 	struct nfsmount *nmp = VFSTONFS(vp->v_mount);
2589*68653Smckusick 	int s, error = 0, slptimeo = 0, slpflag = 0, retv, bvecpos;
2590*68653Smckusick 	int passone = 1;
2591*68653Smckusick 	u_quad_t off = (u_quad_t)-1, endoff = 0, toff;
2592*68653Smckusick #ifndef NFS_COMMITBVECSIZ
2593*68653Smckusick #define NFS_COMMITBVECSIZ	20
2594*68653Smckusick #endif
2595*68653Smckusick 	struct buf *bvec[NFS_COMMITBVECSIZ];
259638884Smacklem 
259757791Smckusick 	if (nmp->nm_flag & NFSMNT_INT)
259857791Smckusick 		slpflag = PCATCH;
2599*68653Smckusick 	if (!commit)
2600*68653Smckusick 		passone = 0;
2601*68653Smckusick 	/*
2602*68653Smckusick 	 * A b_flags == (B_DELWRI | B_NEEDCOMMIT) block has been written to the
2603*68653Smckusick 	 * server, but nas not been committed to stable storage on the server
2604*68653Smckusick 	 * yet. On the first pass, the byte range is worked out and the commit
2605*68653Smckusick 	 * rpc is done. On the second pass, nfs_writebp() is called to do the
2606*68653Smckusick 	 * job.
2607*68653Smckusick 	 */
2608*68653Smckusick again:
2609*68653Smckusick 	bvecpos = 0;
2610*68653Smckusick 	if (NFS_ISV3(vp) && commit) {
2611*68653Smckusick 		s = splbio();
2612*68653Smckusick 		for (bp = vp->v_dirtyblkhd.lh_first; bp; bp = nbp) {
2613*68653Smckusick 			nbp = bp->b_vnbufs.le_next;
2614*68653Smckusick 			if (bvecpos >= NFS_COMMITBVECSIZ)
2615*68653Smckusick 				break;
2616*68653Smckusick 			if ((bp->b_flags & (B_BUSY | B_DELWRI | B_NEEDCOMMIT))
2617*68653Smckusick 				!= (B_DELWRI | B_NEEDCOMMIT))
2618*68653Smckusick 				continue;
2619*68653Smckusick 			bremfree(bp);
2620*68653Smckusick 			bp->b_flags |= (B_BUSY | B_WRITEINPROG);
2621*68653Smckusick 			/*
2622*68653Smckusick 			 * A list of these buffers is kept so that the
2623*68653Smckusick 			 * second loop knows which buffers have actually
2624*68653Smckusick 			 * been committed. This is necessary, since there
2625*68653Smckusick 			 * may be a race between the commit rpc and new
2626*68653Smckusick 			 * uncommitted writes on the file.
2627*68653Smckusick 			 */
2628*68653Smckusick 			bvec[bvecpos++] = bp;
2629*68653Smckusick 			toff = ((u_quad_t)bp->b_blkno) * DEV_BSIZE +
2630*68653Smckusick 				bp->b_dirtyoff;
2631*68653Smckusick 			if (toff < off)
2632*68653Smckusick 				off = toff;
2633*68653Smckusick 			toff += (u_quad_t)(bp->b_dirtyend - bp->b_dirtyoff);
2634*68653Smckusick 			if (toff > endoff)
2635*68653Smckusick 				endoff = toff;
2636*68653Smckusick 		}
2637*68653Smckusick 		splx(s);
2638*68653Smckusick 	}
2639*68653Smckusick 	if (bvecpos > 0) {
2640*68653Smckusick 		/*
2641*68653Smckusick 		 * Commit data on the server, as required.
2642*68653Smckusick 		 */
2643*68653Smckusick 		retv = nfs_commit(vp, off, (int)(endoff - off), cred, p);
2644*68653Smckusick 		if (retv == NFSERR_STALEWRITEVERF)
2645*68653Smckusick 			nfs_clearcommit(vp->v_mount);
2646*68653Smckusick 		/*
2647*68653Smckusick 		 * Now, either mark the blocks I/O done or mark the
2648*68653Smckusick 		 * blocks dirty, depending on whether the commit
2649*68653Smckusick 		 * succeeded.
2650*68653Smckusick 		 */
2651*68653Smckusick 		for (i = 0; i < bvecpos; i++) {
2652*68653Smckusick 			bp = bvec[i];
2653*68653Smckusick 			bp->b_flags &= ~(B_NEEDCOMMIT | B_WRITEINPROG);
2654*68653Smckusick 			if (retv) {
2655*68653Smckusick 			    brelse(bp);
2656*68653Smckusick 			} else {
2657*68653Smckusick 			    vp->v_numoutput++;
2658*68653Smckusick 			    bp->b_flags |= B_ASYNC;
2659*68653Smckusick 			    bp->b_flags &= ~(B_READ|B_DONE|B_ERROR|B_DELWRI);
2660*68653Smckusick 			    bp->b_dirtyoff = bp->b_dirtyend = 0;
2661*68653Smckusick 			    reassignbuf(bp, vp);
2662*68653Smckusick 			    biodone(bp);
2663*68653Smckusick 			}
2664*68653Smckusick 		}
2665*68653Smckusick 	}
2666*68653Smckusick 
2667*68653Smckusick 	/*
2668*68653Smckusick 	 * Start/do any write(s) that are required.
2669*68653Smckusick 	 */
267054451Smckusick loop:
267154451Smckusick 	s = splbio();
267265252Smckusick 	for (bp = vp->v_dirtyblkhd.lh_first; bp; bp = nbp) {
267365252Smckusick 		nbp = bp->b_vnbufs.le_next;
267457791Smckusick 		if (bp->b_flags & B_BUSY) {
2675*68653Smckusick 			if (waitfor != MNT_WAIT || passone)
267657791Smckusick 				continue;
267757791Smckusick 			bp->b_flags |= B_WANTED;
267857791Smckusick 			error = tsleep((caddr_t)bp, slpflag | (PRIBIO + 1),
267957791Smckusick 				"nfsfsync", slptimeo);
268057791Smckusick 			splx(s);
268157791Smckusick 			if (error) {
2682*68653Smckusick 			    if (nfs_sigintr(nmp, (struct nfsreq *)0, p))
268357791Smckusick 				return (EINTR);
268457791Smckusick 			    if (slpflag == PCATCH) {
268557791Smckusick 				slpflag = 0;
268657791Smckusick 				slptimeo = 2 * hz;
268757791Smckusick 			    }
268857791Smckusick 			}
268957791Smckusick 			goto loop;
269057791Smckusick 		}
269154451Smckusick 		if ((bp->b_flags & B_DELWRI) == 0)
269254451Smckusick 			panic("nfs_fsync: not dirty");
2693*68653Smckusick 		if ((passone || !commit) && (bp->b_flags & B_NEEDCOMMIT))
2694*68653Smckusick 			continue;
269554451Smckusick 		bremfree(bp);
2696*68653Smckusick 		if (passone || !commit)
2697*68653Smckusick 		    bp->b_flags |= (B_BUSY|B_ASYNC);
2698*68653Smckusick 		else
2699*68653Smckusick 		    bp->b_flags |= (B_BUSY|B_ASYNC|B_WRITEINPROG|B_NEEDCOMMIT);
270054451Smckusick 		splx(s);
270157791Smckusick 		VOP_BWRITE(bp);
270254451Smckusick 		goto loop;
270338884Smacklem 	}
270457791Smckusick 	splx(s);
2705*68653Smckusick 	if (passone) {
2706*68653Smckusick 		passone = 0;
2707*68653Smckusick 		goto again;
2708*68653Smckusick 	}
2709*68653Smckusick 	if (waitfor == MNT_WAIT) {
271054451Smckusick 		while (vp->v_numoutput) {
271154451Smckusick 			vp->v_flag |= VBWAIT;
271257791Smckusick 			error = tsleep((caddr_t)&vp->v_numoutput,
271357791Smckusick 				slpflag | (PRIBIO + 1), "nfsfsync", slptimeo);
271457791Smckusick 			if (error) {
2715*68653Smckusick 			    if (nfs_sigintr(nmp, (struct nfsreq *)0, p))
271657791Smckusick 				return (EINTR);
271757791Smckusick 			    if (slpflag == PCATCH) {
271857791Smckusick 				slpflag = 0;
271957791Smckusick 				slptimeo = 2 * hz;
272057791Smckusick 			    }
272157791Smckusick 			}
272254451Smckusick 		}
2723*68653Smckusick 		if (vp->v_dirtyblkhd.lh_first && commit) {
2724*68653Smckusick #ifndef DIAGNOSTIC
272554451Smckusick 			vprint("nfs_fsync: dirty", vp);
272657791Smckusick #endif
272754451Smckusick 			goto loop;
272854451Smckusick 		}
272954451Smckusick 	}
273053629Smckusick 	if (np->n_flag & NWRITEERR) {
273139751Smckusick 		error = np->n_error;
273253629Smckusick 		np->n_flag &= ~NWRITEERR;
273353629Smckusick 	}
273438884Smacklem 	return (error);
273538884Smacklem }
273639672Smckusick 
273739672Smckusick /*
273860400Smckusick  * Return POSIX pathconf information applicable to nfs.
273960400Smckusick  *
2740*68653Smckusick  * The NFS V2 protocol doesn't support this, so just return EINVAL
2741*68653Smckusick  * for V2.
274260400Smckusick  */
274360400Smckusick /* ARGSUSED */
2744*68653Smckusick int
274560400Smckusick nfs_pathconf(ap)
274660400Smckusick 	struct vop_pathconf_args /* {
274760400Smckusick 		struct vnode *a_vp;
274860400Smckusick 		int a_name;
274960400Smckusick 		int *a_retval;
275060400Smckusick 	} */ *ap;
275160400Smckusick {
275260400Smckusick 
275360400Smckusick 	return (EINVAL);
275460400Smckusick }
275560400Smckusick 
275660400Smckusick /*
275746201Smckusick  * NFS advisory byte-level locks.
275846201Smckusick  * Currently unsupported.
275946201Smckusick  */
276052234Sheideman int
276153806Smckusick nfs_advlock(ap)
276254668Smckusick 	struct vop_advlock_args /* {
276354668Smckusick 		struct vnode *a_vp;
276454668Smckusick 		caddr_t  a_id;
276554668Smckusick 		int  a_op;
276654668Smckusick 		struct flock *a_fl;
276754668Smckusick 		int  a_flags;
276854668Smckusick 	} */ *ap;
276946201Smckusick {
277046201Smckusick 
277146201Smckusick 	return (EOPNOTSUPP);
277246201Smckusick }
277346201Smckusick 
277446201Smckusick /*
277539672Smckusick  * Print out the contents of an nfsnode.
277639672Smckusick  */
277752234Sheideman int
277853806Smckusick nfs_print(ap)
277954668Smckusick 	struct vop_print_args /* {
278054668Smckusick 		struct vnode *a_vp;
278154668Smckusick 	} */ *ap;
278239672Smckusick {
278353806Smckusick 	register struct vnode *vp = ap->a_vp;
278453806Smckusick 	register struct nfsnode *np = VTONFS(vp);
278539672Smckusick 
2786*68653Smckusick 	printf("tag VT_NFS, fileid %ld fsid 0x%lx",
278740294Smckusick 		np->n_vattr.va_fileid, np->n_vattr.va_fsid);
278853806Smckusick 	if (vp->v_type == VFIFO)
278953806Smckusick 		fifo_printinfo(vp);
279039914Smckusick 	printf("\n");
2791*68653Smckusick 	return (0);
279239672Smckusick }
279351573Smckusick 
279451573Smckusick /*
279551573Smckusick  * NFS directory offset lookup.
279651573Smckusick  * Currently unsupported.
279751573Smckusick  */
279852234Sheideman int
279953806Smckusick nfs_blkatoff(ap)
280054668Smckusick 	struct vop_blkatoff_args /* {
280154668Smckusick 		struct vnode *a_vp;
280254668Smckusick 		off_t a_offset;
280354668Smckusick 		char **a_res;
280454668Smckusick 		struct buf **a_bpp;
280554668Smckusick 	} */ *ap;
280651573Smckusick {
280751573Smckusick 
280851573Smckusick 	return (EOPNOTSUPP);
280951573Smckusick }
281051573Smckusick 
281151573Smckusick /*
281251573Smckusick  * NFS flat namespace allocation.
281351573Smckusick  * Currently unsupported.
281451573Smckusick  */
281552234Sheideman int
281653806Smckusick nfs_valloc(ap)
281754668Smckusick 	struct vop_valloc_args /* {
281854668Smckusick 		struct vnode *a_pvp;
281954668Smckusick 		int a_mode;
282054668Smckusick 		struct ucred *a_cred;
282154668Smckusick 		struct vnode **a_vpp;
282254668Smckusick 	} */ *ap;
282351573Smckusick {
282451573Smckusick 
282551573Smckusick 	return (EOPNOTSUPP);
282651573Smckusick }
282751573Smckusick 
282851573Smckusick /*
282951573Smckusick  * NFS flat namespace free.
283051573Smckusick  * Currently unsupported.
283151573Smckusick  */
283253582Sheideman int
283353806Smckusick nfs_vfree(ap)
283454668Smckusick 	struct vop_vfree_args /* {
283554668Smckusick 		struct vnode *a_pvp;
283654668Smckusick 		ino_t a_ino;
283754668Smckusick 		int a_mode;
283854668Smckusick 	} */ *ap;
283951573Smckusick {
284051573Smckusick 
284153582Sheideman 	return (EOPNOTSUPP);
284251573Smckusick }
284351573Smckusick 
284451573Smckusick /*
284551573Smckusick  * NFS file truncation.
284651573Smckusick  */
284752234Sheideman int
284853806Smckusick nfs_truncate(ap)
284954668Smckusick 	struct vop_truncate_args /* {
285054668Smckusick 		struct vnode *a_vp;
285154668Smckusick 		off_t a_length;
285254668Smckusick 		int a_flags;
285354668Smckusick 		struct ucred *a_cred;
285454668Smckusick 		struct proc *a_p;
285554668Smckusick 	} */ *ap;
285651573Smckusick {
285751573Smckusick 
285851573Smckusick 	/* Use nfs_setattr */
285951573Smckusick 	printf("nfs_truncate: need to implement!!");
286051573Smckusick 	return (EOPNOTSUPP);
286151573Smckusick }
286251573Smckusick 
286351573Smckusick /*
286451573Smckusick  * NFS update.
286551573Smckusick  */
286652234Sheideman int
286753806Smckusick nfs_update(ap)
286854668Smckusick 	struct vop_update_args /* {
286954668Smckusick 		struct vnode *a_vp;
287054668Smckusick 		struct timeval *a_ta;
287154668Smckusick 		struct timeval *a_tm;
287254668Smckusick 		int a_waitfor;
287354668Smckusick 	} */ *ap;
287451573Smckusick {
287551573Smckusick 
287651573Smckusick 	/* Use nfs_setattr */
287751573Smckusick 	printf("nfs_update: need to implement!!");
287851573Smckusick 	return (EOPNOTSUPP);
287951573Smckusick }
288053629Smckusick 
288153629Smckusick /*
2882*68653Smckusick  * Just call nfs_writebp() with the force argument set to 1.
2883*68653Smckusick  */
2884*68653Smckusick int
2885*68653Smckusick nfs_bwrite(ap)
2886*68653Smckusick 	struct vop_bwrite_args /* {
2887*68653Smckusick 		struct vnode *a_bp;
2888*68653Smckusick 	} */ *ap;
2889*68653Smckusick {
2890*68653Smckusick 
2891*68653Smckusick 	return (nfs_writebp(ap->a_bp, 1));
2892*68653Smckusick }
2893*68653Smckusick 
2894*68653Smckusick /*
2895*68653Smckusick  * This is a clone of vn_bwrite(), except that B_WRITEINPROG isn't set unless
2896*68653Smckusick  * the force flag is one and it also handles the B_NEEDCOMMIT flag.
2897*68653Smckusick  */
2898*68653Smckusick int
2899*68653Smckusick nfs_writebp(bp, force)
2900*68653Smckusick 	register struct buf *bp;
2901*68653Smckusick 	int force;
2902*68653Smckusick {
2903*68653Smckusick 	register int oldflags = bp->b_flags, retv = 1;
2904*68653Smckusick 	register struct proc *p = curproc;	/* XXX */
2905*68653Smckusick 	off_t off;
2906*68653Smckusick 
2907*68653Smckusick 	if(!(bp->b_flags & B_BUSY))
2908*68653Smckusick 		panic("bwrite: buffer is not busy???");
2909*68653Smckusick 
2910*68653Smckusick 	bp->b_flags &= ~(B_READ|B_DONE|B_ERROR|B_DELWRI);
2911*68653Smckusick 
2912*68653Smckusick 	if (oldflags & B_ASYNC) {
2913*68653Smckusick 		if (oldflags & B_DELWRI) {
2914*68653Smckusick 			reassignbuf(bp, bp->b_vp);
2915*68653Smckusick 		} else if (p) {
2916*68653Smckusick 			++p->p_stats->p_ru.ru_oublock;
2917*68653Smckusick 		}
2918*68653Smckusick 	}
2919*68653Smckusick 	bp->b_vp->v_numoutput++;
2920*68653Smckusick 
2921*68653Smckusick 	/*
2922*68653Smckusick 	 * If B_NEEDCOMMIT is set, a commit rpc may do the trick. If not
2923*68653Smckusick 	 * an actual write will have to be scheduled via. VOP_STRATEGY().
2924*68653Smckusick 	 * If B_WRITEINPROG is already set, then push it with a write anyhow.
2925*68653Smckusick 	 */
2926*68653Smckusick 	if (oldflags & (B_NEEDCOMMIT | B_WRITEINPROG) == B_NEEDCOMMIT) {
2927*68653Smckusick 		off = ((u_quad_t)bp->b_blkno) * DEV_BSIZE + bp->b_dirtyoff;
2928*68653Smckusick 		bp->b_flags |= B_WRITEINPROG;
2929*68653Smckusick 		retv = nfs_commit(bp->b_vp, off, bp->b_dirtyend-bp->b_dirtyoff,
2930*68653Smckusick 			bp->b_wcred, bp->b_proc);
2931*68653Smckusick 		bp->b_flags &= ~B_WRITEINPROG;
2932*68653Smckusick 		if (!retv) {
2933*68653Smckusick 			bp->b_dirtyoff = bp->b_dirtyend = 0;
2934*68653Smckusick 			bp->b_flags &= ~B_NEEDCOMMIT;
2935*68653Smckusick 			biodone(bp);
2936*68653Smckusick 		} else if (retv == NFSERR_STALEWRITEVERF)
2937*68653Smckusick 			nfs_clearcommit(bp->b_vp->v_mount);
2938*68653Smckusick 	}
2939*68653Smckusick 	if (retv) {
2940*68653Smckusick 		if (force)
2941*68653Smckusick 			bp->b_flags |= B_WRITEINPROG;
2942*68653Smckusick 		VOP_STRATEGY(bp);
2943*68653Smckusick 	}
2944*68653Smckusick 
2945*68653Smckusick 	if( (oldflags & B_ASYNC) == 0) {
2946*68653Smckusick 		int rtval = biowait(bp);
2947*68653Smckusick 		if (oldflags & B_DELWRI) {
2948*68653Smckusick 			reassignbuf(bp, bp->b_vp);
2949*68653Smckusick 		} else if (p) {
2950*68653Smckusick 			++p->p_stats->p_ru.ru_oublock;
2951*68653Smckusick 		}
2952*68653Smckusick 		brelse(bp);
2953*68653Smckusick 		return (rtval);
2954*68653Smckusick 	}
2955*68653Smckusick 
2956*68653Smckusick 	return (0);
2957*68653Smckusick }
2958*68653Smckusick 
2959*68653Smckusick /*
296056364Smckusick  * nfs special file access vnode op.
296156364Smckusick  * Essentially just get vattr and then imitate iaccess() since the device is
296256364Smckusick  * local to the client.
296356364Smckusick  */
296456364Smckusick int
296556364Smckusick nfsspec_access(ap)
296656364Smckusick 	struct vop_access_args /* {
296756364Smckusick 		struct vnode *a_vp;
296856364Smckusick 		int  a_mode;
296956364Smckusick 		struct ucred *a_cred;
297056364Smckusick 		struct proc *a_p;
297156364Smckusick 	} */ *ap;
297256364Smckusick {
297356364Smckusick 	register struct vattr *vap;
297456364Smckusick 	register gid_t *gp;
297556364Smckusick 	register struct ucred *cred = ap->a_cred;
297656364Smckusick 	mode_t mode = ap->a_mode;
297756364Smckusick 	struct vattr vattr;
297856364Smckusick 	register int i;
297956364Smckusick 	int error;
298056364Smckusick 
298156364Smckusick 	/*
298256364Smckusick 	 * If you're the super-user,
298356364Smckusick 	 * you always get access.
298456364Smckusick 	 */
298556364Smckusick 	if (cred->cr_uid == 0)
298656364Smckusick 		return (0);
298756364Smckusick 	vap = &vattr;
2988*68653Smckusick 	error = VOP_GETATTR(ap->a_vp, vap, cred, ap->a_p);
2989*68653Smckusick 	if (error)
299056364Smckusick 		return (error);
299156364Smckusick 	/*
299256364Smckusick 	 * Access check is based on only one of owner, group, public.
299356364Smckusick 	 * If not owner, then check group. If not a member of the
299456364Smckusick 	 * group, then check public access.
299556364Smckusick 	 */
299656364Smckusick 	if (cred->cr_uid != vap->va_uid) {
299756364Smckusick 		mode >>= 3;
299856364Smckusick 		gp = cred->cr_groups;
299956364Smckusick 		for (i = 0; i < cred->cr_ngroups; i++, gp++)
300056364Smckusick 			if (vap->va_gid == *gp)
300156364Smckusick 				goto found;
300256364Smckusick 		mode >>= 3;
300356364Smckusick found:
300456364Smckusick 		;
300556364Smckusick 	}
3006*68653Smckusick 	error = (vap->va_mode & mode) == mode ? 0 : EACCES;
3007*68653Smckusick 	return (error);
300856364Smckusick }
300956364Smckusick 
301056364Smckusick /*
301153629Smckusick  * Read wrapper for special devices.
301253629Smckusick  */
301353629Smckusick int
301453629Smckusick nfsspec_read(ap)
301554668Smckusick 	struct vop_read_args /* {
301654668Smckusick 		struct vnode *a_vp;
301754668Smckusick 		struct uio *a_uio;
301854668Smckusick 		int  a_ioflag;
301954668Smckusick 		struct ucred *a_cred;
302054668Smckusick 	} */ *ap;
302153629Smckusick {
302254032Smckusick 	register struct nfsnode *np = VTONFS(ap->a_vp);
302353629Smckusick 
302453629Smckusick 	/*
302553629Smckusick 	 * Set access flag.
302653629Smckusick 	 */
302754032Smckusick 	np->n_flag |= NACC;
3028*68653Smckusick 	np->n_atim.ts_sec = time.tv_sec;
3029*68653Smckusick 	np->n_atim.ts_nsec = time.tv_usec * 1000;
303053629Smckusick 	return (VOCALL(spec_vnodeop_p, VOFFSET(vop_read), ap));
303153629Smckusick }
303253629Smckusick 
303353629Smckusick /*
303453629Smckusick  * Write wrapper for special devices.
303553629Smckusick  */
303653629Smckusick int
303753629Smckusick nfsspec_write(ap)
303854668Smckusick 	struct vop_write_args /* {
303954668Smckusick 		struct vnode *a_vp;
304054668Smckusick 		struct uio *a_uio;
304154668Smckusick 		int  a_ioflag;
304254668Smckusick 		struct ucred *a_cred;
304354668Smckusick 	} */ *ap;
304453629Smckusick {
304554032Smckusick 	register struct nfsnode *np = VTONFS(ap->a_vp);
304653629Smckusick 
304753629Smckusick 	/*
304854032Smckusick 	 * Set update flag.
304953629Smckusick 	 */
305054032Smckusick 	np->n_flag |= NUPD;
3051*68653Smckusick 	np->n_mtim.ts_sec = time.tv_sec;
3052*68653Smckusick 	np->n_mtim.ts_nsec = time.tv_usec * 1000;
305353629Smckusick 	return (VOCALL(spec_vnodeop_p, VOFFSET(vop_write), ap));
305453629Smckusick }
305553629Smckusick 
305653629Smckusick /*
305753629Smckusick  * Close wrapper for special devices.
305853629Smckusick  *
305953629Smckusick  * Update the times on the nfsnode then do device close.
306053629Smckusick  */
306153629Smckusick int
306253629Smckusick nfsspec_close(ap)
306354668Smckusick 	struct vop_close_args /* {
306454668Smckusick 		struct vnode *a_vp;
306554668Smckusick 		int  a_fflag;
306654668Smckusick 		struct ucred *a_cred;
306754668Smckusick 		struct proc *a_p;
306854668Smckusick 	} */ *ap;
306953629Smckusick {
307053806Smckusick 	register struct vnode *vp = ap->a_vp;
307153806Smckusick 	register struct nfsnode *np = VTONFS(vp);
307253629Smckusick 	struct vattr vattr;
307353629Smckusick 
307453629Smckusick 	if (np->n_flag & (NACC | NUPD)) {
307553629Smckusick 		np->n_flag |= NCHG;
307653806Smckusick 		if (vp->v_usecount == 1 &&
307753806Smckusick 		    (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) {
307853629Smckusick 			VATTR_NULL(&vattr);
3079*68653Smckusick 			if (np->n_flag & NACC)
3080*68653Smckusick 				vattr.va_atime = np->n_atim;
3081*68653Smckusick 			if (np->n_flag & NUPD)
3082*68653Smckusick 				vattr.va_mtime = np->n_mtim;
308353806Smckusick 			(void)VOP_SETATTR(vp, &vattr, ap->a_cred, ap->a_p);
308453629Smckusick 		}
308553629Smckusick 	}
308653629Smckusick 	return (VOCALL(spec_vnodeop_p, VOFFSET(vop_close), ap));
308753629Smckusick }
308853629Smckusick 
308953629Smckusick /*
309053629Smckusick  * Read wrapper for fifos.
309153629Smckusick  */
309253629Smckusick int
309353629Smckusick nfsfifo_read(ap)
309454668Smckusick 	struct vop_read_args /* {
309554668Smckusick 		struct vnode *a_vp;
309654668Smckusick 		struct uio *a_uio;
309754668Smckusick 		int  a_ioflag;
309854668Smckusick 		struct ucred *a_cred;
309954668Smckusick 	} */ *ap;
310053629Smckusick {
310153629Smckusick 	extern int (**fifo_vnodeop_p)();
310254032Smckusick 	register struct nfsnode *np = VTONFS(ap->a_vp);
310353629Smckusick 
310453629Smckusick 	/*
310553629Smckusick 	 * Set access flag.
310653629Smckusick 	 */
310754032Smckusick 	np->n_flag |= NACC;
3108*68653Smckusick 	np->n_atim.ts_sec = time.tv_sec;
3109*68653Smckusick 	np->n_atim.ts_nsec = time.tv_usec * 1000;
311053629Smckusick 	return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_read), ap));
311153629Smckusick }
311253629Smckusick 
311353629Smckusick /*
311453629Smckusick  * Write wrapper for fifos.
311553629Smckusick  */
311653629Smckusick int
311753629Smckusick nfsfifo_write(ap)
311854668Smckusick 	struct vop_write_args /* {
311954668Smckusick 		struct vnode *a_vp;
312054668Smckusick 		struct uio *a_uio;
312154668Smckusick 		int  a_ioflag;
312254668Smckusick 		struct ucred *a_cred;
312354668Smckusick 	} */ *ap;
312453629Smckusick {
312553629Smckusick 	extern int (**fifo_vnodeop_p)();
312654032Smckusick 	register struct nfsnode *np = VTONFS(ap->a_vp);
312753629Smckusick 
312853629Smckusick 	/*
312953629Smckusick 	 * Set update flag.
313053629Smckusick 	 */
313154032Smckusick 	np->n_flag |= NUPD;
3132*68653Smckusick 	np->n_mtim.ts_sec = time.tv_sec;
3133*68653Smckusick 	np->n_mtim.ts_nsec = time.tv_usec * 1000;
313453629Smckusick 	return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_write), ap));
313553629Smckusick }
313653629Smckusick 
313753629Smckusick /*
313853629Smckusick  * Close wrapper for fifos.
313953629Smckusick  *
314053629Smckusick  * Update the times on the nfsnode then do fifo close.
314153629Smckusick  */
314253629Smckusick int
314353629Smckusick nfsfifo_close(ap)
314454668Smckusick 	struct vop_close_args /* {
314554668Smckusick 		struct vnode *a_vp;
314654668Smckusick 		int  a_fflag;
314754668Smckusick 		struct ucred *a_cred;
314854668Smckusick 		struct proc *a_p;
314954668Smckusick 	} */ *ap;
315053629Smckusick {
315153806Smckusick 	register struct vnode *vp = ap->a_vp;
315253806Smckusick 	register struct nfsnode *np = VTONFS(vp);
315353629Smckusick 	struct vattr vattr;
315453629Smckusick 	extern int (**fifo_vnodeop_p)();
315553629Smckusick 
315653629Smckusick 	if (np->n_flag & (NACC | NUPD)) {
3157*68653Smckusick 		if (np->n_flag & NACC) {
3158*68653Smckusick 			np->n_atim.ts_sec = time.tv_sec;
3159*68653Smckusick 			np->n_atim.ts_nsec = time.tv_usec * 1000;
3160*68653Smckusick 		}
3161*68653Smckusick 		if (np->n_flag & NUPD) {
3162*68653Smckusick 			np->n_mtim.ts_sec = time.tv_sec;
3163*68653Smckusick 			np->n_mtim.ts_nsec = time.tv_usec * 1000;
3164*68653Smckusick 		}
316553629Smckusick 		np->n_flag |= NCHG;
316653806Smckusick 		if (vp->v_usecount == 1 &&
316753806Smckusick 		    (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) {
316853629Smckusick 			VATTR_NULL(&vattr);
3169*68653Smckusick 			if (np->n_flag & NACC)
3170*68653Smckusick 				vattr.va_atime = np->n_atim;
3171*68653Smckusick 			if (np->n_flag & NUPD)
3172*68653Smckusick 				vattr.va_mtime = np->n_mtim;
317353806Smckusick 			(void)VOP_SETATTR(vp, &vattr, ap->a_cred, ap->a_p);
317453629Smckusick 		}
317553629Smckusick 	}
317653629Smckusick 	return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_close), ap));
317753629Smckusick }
3178