xref: /csrg-svn/sys/nfs/nfs_vnops.c (revision 57791)
138414Smckusick /*
238414Smckusick  * Copyright (c) 1989 The Regents of the University of California.
338414Smckusick  * All rights reserved.
438414Smckusick  *
538414Smckusick  * This code is derived from software contributed to Berkeley by
638414Smckusick  * Rick Macklem at The University of Guelph.
738414Smckusick  *
844514Sbostic  * %sccs.include.redist.c%
938414Smckusick  *
10*57791Smckusick  *	@(#)nfs_vnops.c	7.102 (Berkeley) 02/02/93
1138414Smckusick  */
1238414Smckusick 
1338414Smckusick /*
1438414Smckusick  * vnode op calls for sun nfs version 2
1538414Smckusick  */
1638414Smckusick 
1753322Smckusick #include <sys/param.h>
1853322Smckusick #include <sys/proc.h>
1953322Smckusick #include <sys/kernel.h>
2053322Smckusick #include <sys/systm.h>
2153322Smckusick #include <sys/mount.h>
2253322Smckusick #include <sys/buf.h>
2353322Smckusick #include <sys/malloc.h>
2453322Smckusick #include <sys/mbuf.h>
2553322Smckusick #include <sys/conf.h>
2653322Smckusick #include <sys/namei.h>
2753322Smckusick #include <sys/vnode.h>
2853322Smckusick #include <sys/map.h>
2954740Smckusick #include <sys/dirent.h>
3047573Skarels 
3153322Smckusick #include <vm/vm.h>
3238414Smckusick 
3355041Smckusick #include <miscfs/specfs/specdev.h>
3455041Smckusick #include <miscfs/fifofs/fifo.h>
3555041Smckusick 
3653322Smckusick #include <nfs/rpcv2.h>
3753322Smckusick #include <nfs/nfsv2.h>
3853322Smckusick #include <nfs/nfs.h>
3953322Smckusick #include <nfs/nfsnode.h>
4053322Smckusick #include <nfs/nfsmount.h>
4153322Smckusick #include <nfs/xdr_subs.h>
4253322Smckusick #include <nfs/nfsm_subs.h>
4353322Smckusick #include <nfs/nqnfs.h>
4453322Smckusick 
4538414Smckusick /* Defs */
4638414Smckusick #define	TRUE	1
4738414Smckusick #define	FALSE	0
4838414Smckusick 
4948054Smckusick /*
5048054Smckusick  * Global vfs data structures for nfs
5148054Smckusick  */
5253554Sheideman int (**nfsv2_vnodeop_p)();
5353554Sheideman struct vnodeopv_entry_desc nfsv2_vnodeop_entries[] = {
5453554Sheideman 	{ &vop_default_desc, vn_default_error },
5553806Smckusick 	{ &vop_lookup_desc, nfs_lookup },	/* lookup */
5653806Smckusick 	{ &vop_create_desc, nfs_create },	/* create */
5753554Sheideman 	{ &vop_mknod_desc, nfs_mknod },		/* mknod */
5853554Sheideman 	{ &vop_open_desc, nfs_open },		/* open */
5953554Sheideman 	{ &vop_close_desc, nfs_close },		/* close */
6053806Smckusick 	{ &vop_access_desc, nfs_access },	/* access */
6153806Smckusick 	{ &vop_getattr_desc, nfs_getattr },	/* getattr */
6253806Smckusick 	{ &vop_setattr_desc, nfs_setattr },	/* setattr */
6353554Sheideman 	{ &vop_read_desc, nfs_read },		/* read */
6453554Sheideman 	{ &vop_write_desc, nfs_write },		/* write */
6553554Sheideman 	{ &vop_ioctl_desc, nfs_ioctl },		/* ioctl */
6653806Smckusick 	{ &vop_select_desc, nfs_select },	/* select */
6753554Sheideman 	{ &vop_mmap_desc, nfs_mmap },		/* mmap */
6853554Sheideman 	{ &vop_fsync_desc, nfs_fsync },		/* fsync */
6953554Sheideman 	{ &vop_seek_desc, nfs_seek },		/* seek */
7053806Smckusick 	{ &vop_remove_desc, nfs_remove },	/* remove */
7153554Sheideman 	{ &vop_link_desc, nfs_link },		/* link */
7253806Smckusick 	{ &vop_rename_desc, nfs_rename },	/* rename */
7353554Sheideman 	{ &vop_mkdir_desc, nfs_mkdir },		/* mkdir */
7453554Sheideman 	{ &vop_rmdir_desc, nfs_rmdir },		/* rmdir */
7553806Smckusick 	{ &vop_symlink_desc, nfs_symlink },	/* symlink */
7653806Smckusick 	{ &vop_readdir_desc, nfs_readdir },	/* readdir */
7753806Smckusick 	{ &vop_readlink_desc, nfs_readlink },	/* readlink */
7853806Smckusick 	{ &vop_abortop_desc, nfs_abortop },	/* abortop */
7953806Smckusick 	{ &vop_inactive_desc, nfs_inactive },	/* inactive */
8053806Smckusick 	{ &vop_reclaim_desc, nfs_reclaim },	/* reclaim */
8153554Sheideman 	{ &vop_lock_desc, nfs_lock },		/* lock */
8253806Smckusick 	{ &vop_unlock_desc, nfs_unlock },	/* unlock */
8353554Sheideman 	{ &vop_bmap_desc, nfs_bmap },		/* bmap */
8453806Smckusick 	{ &vop_strategy_desc, nfs_strategy },	/* strategy */
8553554Sheideman 	{ &vop_print_desc, nfs_print },		/* print */
8653806Smckusick 	{ &vop_islocked_desc, nfs_islocked },	/* islocked */
8753806Smckusick 	{ &vop_advlock_desc, nfs_advlock },	/* advlock */
8853806Smckusick 	{ &vop_blkatoff_desc, nfs_blkatoff },	/* blkatoff */
8953806Smckusick 	{ &vop_valloc_desc, nfs_valloc },	/* valloc */
9053554Sheideman 	{ &vop_vfree_desc, nfs_vfree },		/* vfree */
9153806Smckusick 	{ &vop_truncate_desc, nfs_truncate },	/* truncate */
9253806Smckusick 	{ &vop_update_desc, nfs_update },	/* update */
93*57791Smckusick 	{ &vop_bwrite_desc, nfs_bwrite },
9453554Sheideman 	{ (struct vnodeop_desc*)NULL, (int(*)())NULL }
9538414Smckusick };
9653554Sheideman struct vnodeopv_desc nfsv2_vnodeop_opv_desc =
9753554Sheideman 	{ &nfsv2_vnodeop_p, nfsv2_vnodeop_entries };
9838414Smckusick 
9948054Smckusick /*
10048054Smckusick  * Special device vnode ops
10148054Smckusick  */
10253554Sheideman int (**spec_nfsv2nodeop_p)();
10353554Sheideman struct vnodeopv_entry_desc spec_nfsv2nodeop_entries[] = {
10453554Sheideman 	{ &vop_default_desc, vn_default_error },
10553806Smckusick 	{ &vop_lookup_desc, spec_lookup },	/* lookup */
10653806Smckusick 	{ &vop_create_desc, spec_create },	/* create */
10753806Smckusick 	{ &vop_mknod_desc, spec_mknod },	/* mknod */
10853554Sheideman 	{ &vop_open_desc, spec_open },		/* open */
10953806Smckusick 	{ &vop_close_desc, nfsspec_close },	/* close */
11056364Smckusick 	{ &vop_access_desc, nfsspec_access },	/* access */
11153806Smckusick 	{ &vop_getattr_desc, nfs_getattr },	/* getattr */
11253806Smckusick 	{ &vop_setattr_desc, nfs_setattr },	/* setattr */
11353806Smckusick 	{ &vop_read_desc, nfsspec_read },	/* read */
11453806Smckusick 	{ &vop_write_desc, nfsspec_write },	/* write */
11553806Smckusick 	{ &vop_ioctl_desc, spec_ioctl },	/* ioctl */
11653806Smckusick 	{ &vop_select_desc, spec_select },	/* select */
11753554Sheideman 	{ &vop_mmap_desc, spec_mmap },		/* mmap */
11854451Smckusick 	{ &vop_fsync_desc, nfs_fsync },		/* fsync */
11953554Sheideman 	{ &vop_seek_desc, spec_seek },		/* seek */
12053806Smckusick 	{ &vop_remove_desc, spec_remove },	/* remove */
12153554Sheideman 	{ &vop_link_desc, spec_link },		/* link */
12253806Smckusick 	{ &vop_rename_desc, spec_rename },	/* rename */
12353806Smckusick 	{ &vop_mkdir_desc, spec_mkdir },	/* mkdir */
12453806Smckusick 	{ &vop_rmdir_desc, spec_rmdir },	/* rmdir */
12553806Smckusick 	{ &vop_symlink_desc, spec_symlink },	/* symlink */
12653806Smckusick 	{ &vop_readdir_desc, spec_readdir },	/* readdir */
12753806Smckusick 	{ &vop_readlink_desc, spec_readlink },	/* readlink */
12853806Smckusick 	{ &vop_abortop_desc, spec_abortop },	/* abortop */
12953806Smckusick 	{ &vop_inactive_desc, nfs_inactive },	/* inactive */
13053806Smckusick 	{ &vop_reclaim_desc, nfs_reclaim },	/* reclaim */
13153554Sheideman 	{ &vop_lock_desc, nfs_lock },		/* lock */
13253806Smckusick 	{ &vop_unlock_desc, nfs_unlock },	/* unlock */
13353554Sheideman 	{ &vop_bmap_desc, spec_bmap },		/* bmap */
13453806Smckusick 	{ &vop_strategy_desc, spec_strategy },	/* strategy */
13553554Sheideman 	{ &vop_print_desc, nfs_print },		/* print */
13653806Smckusick 	{ &vop_islocked_desc, nfs_islocked },	/* islocked */
13753806Smckusick 	{ &vop_advlock_desc, spec_advlock },	/* advlock */
13853806Smckusick 	{ &vop_blkatoff_desc, spec_blkatoff },	/* blkatoff */
13953806Smckusick 	{ &vop_valloc_desc, spec_valloc },	/* valloc */
14053806Smckusick 	{ &vop_vfree_desc, spec_vfree },	/* vfree */
14153806Smckusick 	{ &vop_truncate_desc, spec_truncate },	/* truncate */
14253806Smckusick 	{ &vop_update_desc, nfs_update },	/* update */
143*57791Smckusick 	{ &vop_bwrite_desc, nfs_bwrite },
14453554Sheideman 	{ (struct vnodeop_desc*)NULL, (int(*)())NULL }
14538414Smckusick };
14653554Sheideman struct vnodeopv_desc spec_nfsv2nodeop_opv_desc =
14753554Sheideman 	{ &spec_nfsv2nodeop_p, spec_nfsv2nodeop_entries };
14838414Smckusick 
14940294Smckusick #ifdef FIFO
15053554Sheideman int (**fifo_nfsv2nodeop_p)();
15153554Sheideman struct vnodeopv_entry_desc fifo_nfsv2nodeop_entries[] = {
15253554Sheideman 	{ &vop_default_desc, vn_default_error },
15353806Smckusick 	{ &vop_lookup_desc, fifo_lookup },	/* lookup */
15453806Smckusick 	{ &vop_create_desc, fifo_create },	/* create */
15553806Smckusick 	{ &vop_mknod_desc, fifo_mknod },	/* mknod */
15653554Sheideman 	{ &vop_open_desc, fifo_open },		/* open */
15753806Smckusick 	{ &vop_close_desc, nfsfifo_close },	/* close */
15856364Smckusick 	{ &vop_access_desc, nfsspec_access },	/* access */
15953806Smckusick 	{ &vop_getattr_desc, nfs_getattr },	/* getattr */
16053806Smckusick 	{ &vop_setattr_desc, nfs_setattr },	/* setattr */
16153806Smckusick 	{ &vop_read_desc, nfsfifo_read },	/* read */
16253806Smckusick 	{ &vop_write_desc, nfsfifo_write },	/* write */
16353806Smckusick 	{ &vop_ioctl_desc, fifo_ioctl },	/* ioctl */
16453806Smckusick 	{ &vop_select_desc, fifo_select },	/* select */
16553554Sheideman 	{ &vop_mmap_desc, fifo_mmap },		/* mmap */
16654451Smckusick 	{ &vop_fsync_desc, nfs_fsync },		/* fsync */
16753554Sheideman 	{ &vop_seek_desc, fifo_seek },		/* seek */
16853806Smckusick 	{ &vop_remove_desc, fifo_remove },	/* remove */
16953554Sheideman 	{ &vop_link_desc, fifo_link },		/* link */
17053806Smckusick 	{ &vop_rename_desc, fifo_rename },	/* rename */
17153806Smckusick 	{ &vop_mkdir_desc, fifo_mkdir },	/* mkdir */
17253806Smckusick 	{ &vop_rmdir_desc, fifo_rmdir },	/* rmdir */
17353806Smckusick 	{ &vop_symlink_desc, fifo_symlink },	/* symlink */
17453806Smckusick 	{ &vop_readdir_desc, fifo_readdir },	/* readdir */
17553806Smckusick 	{ &vop_readlink_desc, fifo_readlink },	/* readlink */
17653806Smckusick 	{ &vop_abortop_desc, fifo_abortop },	/* abortop */
17753806Smckusick 	{ &vop_inactive_desc, nfs_inactive },	/* inactive */
17853806Smckusick 	{ &vop_reclaim_desc, nfs_reclaim },	/* reclaim */
17953554Sheideman 	{ &vop_lock_desc, nfs_lock },		/* lock */
18053806Smckusick 	{ &vop_unlock_desc, nfs_unlock },	/* unlock */
18153554Sheideman 	{ &vop_bmap_desc, fifo_bmap },		/* bmap */
18253806Smckusick 	{ &vop_strategy_desc, fifo_badop },	/* strategy */
18353554Sheideman 	{ &vop_print_desc, nfs_print },		/* print */
18453806Smckusick 	{ &vop_islocked_desc, nfs_islocked },	/* islocked */
18553806Smckusick 	{ &vop_advlock_desc, fifo_advlock },	/* advlock */
18653806Smckusick 	{ &vop_blkatoff_desc, fifo_blkatoff },	/* blkatoff */
18753806Smckusick 	{ &vop_valloc_desc, fifo_valloc },	/* valloc */
18853806Smckusick 	{ &vop_vfree_desc, fifo_vfree },	/* vfree */
18953806Smckusick 	{ &vop_truncate_desc, fifo_truncate },	/* truncate */
19053806Smckusick 	{ &vop_update_desc, nfs_update },	/* update */
191*57791Smckusick 	{ &vop_bwrite_desc, nfs_bwrite },
19253554Sheideman 	{ (struct vnodeop_desc*)NULL, (int(*)())NULL }
19340294Smckusick };
19453554Sheideman struct vnodeopv_desc fifo_nfsv2nodeop_opv_desc =
19553554Sheideman 	{ &fifo_nfsv2nodeop_p, fifo_nfsv2nodeop_entries };
19640294Smckusick #endif /* FIFO */
19740294Smckusick 
19856289Smckusick void nqnfs_clientlease();
19956289Smckusick 
20048054Smckusick /*
20152196Smckusick  * Global variables
20248054Smckusick  */
20338414Smckusick extern u_long nfs_procids[NFS_NPROCS];
20456364Smckusick extern u_long nfs_prog, nfs_vers, nfs_true, nfs_false;
20538414Smckusick extern char nfsiobuf[MAXPHYS+NBPG];
20641905Smckusick struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON];
20746988Smckusick int nfs_numasync = 0;
20856390Smckusick /* Queue head for nfsiod's */
20956468Smckusick struct queue_entry nfs_bufq;
21054740Smckusick #define	DIRHDSIZ	(sizeof (struct dirent) - (MAXNAMLEN + 1))
21138414Smckusick 
21238414Smckusick /*
21338414Smckusick  * nfs null call from vfs.
21438414Smckusick  */
21552234Sheideman int
21652196Smckusick nfs_null(vp, cred, procp)
21738414Smckusick 	struct vnode *vp;
21838414Smckusick 	struct ucred *cred;
21952196Smckusick 	struct proc *procp;
22038414Smckusick {
22139488Smckusick 	caddr_t bpos, dpos;
22239488Smckusick 	int error = 0;
22339488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb;
22438414Smckusick 
22552196Smckusick 	nfsm_reqhead(vp, NFSPROC_NULL, 0);
22652196Smckusick 	nfsm_request(vp, NFSPROC_NULL, procp, cred);
22738414Smckusick 	nfsm_reqdone;
22838414Smckusick 	return (error);
22938414Smckusick }
23038414Smckusick 
23138414Smckusick /*
23238414Smckusick  * nfs access vnode op.
23356364Smckusick  * For nfs, just return ok. File accesses may fail later.
23456364Smckusick  * For nqnfs, use the access rpc to check accessibility. If file modes are
23556364Smckusick  * changed on the server, accesses might still fail later.
23638414Smckusick  */
23752234Sheideman int
23853806Smckusick nfs_access(ap)
23954668Smckusick 	struct vop_access_args /* {
24054668Smckusick 		struct vnode *a_vp;
24154668Smckusick 		int  a_mode;
24254668Smckusick 		struct ucred *a_cred;
24354668Smckusick 		struct proc *a_p;
24454668Smckusick 	} */ *ap;
24538414Smckusick {
24656364Smckusick 	register struct vnode *vp = ap->a_vp;
24756364Smckusick 	register u_long *tl;
24856364Smckusick 	register caddr_t cp;
24956364Smckusick 	caddr_t bpos, dpos;
25056364Smckusick 	int error = 0;
25156364Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
25238414Smckusick 
25338414Smckusick 	/*
25456708Smckusick 	 * For nqnfs, do an access rpc, otherwise you are stuck emulating
25556708Smckusick 	 * ufs_access() locally using the vattr. This may not be correct,
25656708Smckusick 	 * since the server may apply other access criteria such as
25756708Smckusick 	 * client uid-->server uid mapping that we do not know about, but
25856708Smckusick 	 * this is better than just returning anything that is lying about
25956708Smckusick 	 * in the cache.
26038414Smckusick 	 */
26156364Smckusick 	if (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) {
26256364Smckusick 		nfsstats.rpccnt[NQNFSPROC_ACCESS]++;
26356364Smckusick 		nfsm_reqhead(vp, NQNFSPROC_ACCESS, NFSX_FH + 3 * NFSX_UNSIGNED);
26456364Smckusick 		nfsm_fhtom(vp);
26556364Smckusick 		nfsm_build(tl, u_long *, 3 * NFSX_UNSIGNED);
26656364Smckusick 		if (ap->a_mode & VREAD)
26756364Smckusick 			*tl++ = nfs_true;
26856364Smckusick 		else
26956364Smckusick 			*tl++ = nfs_false;
27056364Smckusick 		if (ap->a_mode & VWRITE)
27156364Smckusick 			*tl++ = nfs_true;
27256364Smckusick 		else
27356364Smckusick 			*tl++ = nfs_false;
27456364Smckusick 		if (ap->a_mode & VEXEC)
27556364Smckusick 			*tl = nfs_true;
27656364Smckusick 		else
27756364Smckusick 			*tl = nfs_false;
27856364Smckusick 		nfsm_request(vp, NQNFSPROC_ACCESS, ap->a_p, ap->a_cred);
27956364Smckusick 		nfsm_reqdone;
28038884Smacklem 		return (error);
28156364Smckusick 	} else
28256708Smckusick 		return (nfsspec_access(ap));
28338414Smckusick }
28438414Smckusick 
28538414Smckusick /*
28638414Smckusick  * nfs open vnode op
28756289Smckusick  * Check to see if the type is ok
28852196Smckusick  * and that deletion is not in progress.
28956289Smckusick  * For paged in text files, you will need to flush the page cache
29056289Smckusick  * if consistency is lost.
29138414Smckusick  */
29239488Smckusick /* ARGSUSED */
29352234Sheideman int
29453806Smckusick nfs_open(ap)
29554668Smckusick 	struct vop_open_args /* {
29654668Smckusick 		struct vnode *a_vp;
29754668Smckusick 		int  a_mode;
29854668Smckusick 		struct ucred *a_cred;
29954668Smckusick 		struct proc *a_p;
30054668Smckusick 	} */ *ap;
30138414Smckusick {
30253806Smckusick 	register struct vnode *vp = ap->a_vp;
30356289Smckusick 	struct nfsnode *np = VTONFS(vp);
30456289Smckusick 	struct nfsmount *nmp = VFSTONFS(vp->v_mount);
30556289Smckusick 	struct vattr vattr;
30656289Smckusick 	int error;
30738414Smckusick 
30853806Smckusick 	if (vp->v_type != VREG && vp->v_type != VDIR && vp->v_type != VLNK)
30938414Smckusick 		return (EACCES);
31056289Smckusick 	if (vp->v_flag & VTEXT) {
31156289Smckusick 	    /*
31256289Smckusick 	     * Get a valid lease. If cached data is stale, flush it.
31356289Smckusick 	     */
31456289Smckusick 	    if (nmp->nm_flag & NFSMNT_NQNFS) {
31556289Smckusick 		if (NQNFS_CKINVALID(vp, np, NQL_READ)) {
31656289Smckusick 		    do {
31756289Smckusick 			error = nqnfs_getlease(vp, NQL_READ, ap->a_cred, ap->a_p);
31856289Smckusick 		    } while (error == NQNFS_EXPIRED);
31956289Smckusick 		    if (error)
32056289Smckusick 			return (error);
32156289Smckusick 		    if (np->n_lrev != np->n_brev) {
322*57791Smckusick 			if ((error = nfs_vinvalbuf(vp, V_SAVE, ap->a_cred,
323*57791Smckusick 				ap->a_p, 1)) == EINTR)
324*57791Smckusick 				return (error);
32556289Smckusick 			(void) vnode_pager_uncache(vp);
32656289Smckusick 			np->n_brev = np->n_lrev;
32756289Smckusick 		    }
32856289Smckusick 		}
32956289Smckusick 	    } else {
33056289Smckusick 		if (np->n_flag & NMODIFIED) {
331*57791Smckusick 			if ((error = nfs_vinvalbuf(vp, V_SAVE, ap->a_cred,
332*57791Smckusick 				ap->a_p, 1)) == EINTR)
333*57791Smckusick 				return (error);
33456289Smckusick 			(void) vnode_pager_uncache(vp);
33556289Smckusick 			np->n_attrstamp = 0;
33656289Smckusick 			np->n_direofoffset = 0;
33756289Smckusick 			if (error = VOP_GETATTR(vp, &vattr, ap->a_cred, ap->a_p))
33856289Smckusick 				return (error);
33956289Smckusick 			np->n_mtime = vattr.va_mtime.ts_sec;
34056289Smckusick 		} else {
34156289Smckusick 			if (error = VOP_GETATTR(vp, &vattr, ap->a_cred, ap->a_p))
34256289Smckusick 				return (error);
34356289Smckusick 			if (np->n_mtime != vattr.va_mtime.ts_sec) {
34456289Smckusick 				np->n_direofoffset = 0;
345*57791Smckusick 				if ((error = nfs_vinvalbuf(vp, V_SAVE,
346*57791Smckusick 					ap->a_cred, ap->a_p, 1)) == EINTR)
347*57791Smckusick 					return (error);
34856289Smckusick 				(void) vnode_pager_uncache(vp);
34956289Smckusick 				np->n_mtime = vattr.va_mtime.ts_sec;
35056289Smckusick 			}
35156289Smckusick 		}
35256289Smckusick 	    }
35356289Smckusick 	} else if ((nmp->nm_flag & NFSMNT_NQNFS) == 0)
35456289Smckusick 		np->n_attrstamp = 0; /* For Open/Close consistency */
35552196Smckusick 	return (0);
35638414Smckusick }
35738414Smckusick 
35838414Smckusick /*
35938414Smckusick  * nfs close vnode op
36038884Smacklem  * For reg files, invalidate any buffer cache entries.
36138414Smckusick  */
36239488Smckusick /* ARGSUSED */
36352234Sheideman int
36453806Smckusick nfs_close(ap)
36554451Smckusick 	struct vop_close_args /* {
36654451Smckusick 		struct vnodeop_desc *a_desc;
36754451Smckusick 		struct vnode *a_vp;
36854451Smckusick 		int  a_fflag;
36954451Smckusick 		struct ucred *a_cred;
37054451Smckusick 		struct proc *a_p;
37154451Smckusick 	} */ *ap;
37238414Smckusick {
37353806Smckusick 	register struct vnode *vp = ap->a_vp;
37453806Smckusick 	register struct nfsnode *np = VTONFS(vp);
37539341Smckusick 	int error = 0;
37638414Smckusick 
37753806Smckusick 	if (vp->v_type == VREG) {
37853806Smckusick 	    if ((VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) == 0 &&
37953629Smckusick 		(np->n_flag & NMODIFIED)) {
380*57791Smckusick 		error = nfs_vinvalbuf(vp, V_SAVE, ap->a_cred, ap->a_p, 1);
38141905Smckusick 		np->n_attrstamp = 0;
38253629Smckusick 	    }
38353629Smckusick 	    if (np->n_flag & NWRITEERR) {
38453629Smckusick 		np->n_flag &= ~NWRITEERR;
38553629Smckusick 		error = np->n_error;
38653629Smckusick 	    }
38738884Smacklem 	}
38838414Smckusick 	return (error);
38938414Smckusick }
39038414Smckusick 
39138414Smckusick /*
39238414Smckusick  * nfs getattr call from vfs.
39338414Smckusick  */
39452234Sheideman int
39553805Smckusick nfs_getattr(ap)
39654668Smckusick 	struct vop_getattr_args /* {
39754668Smckusick 		struct vnode *a_vp;
39854668Smckusick 		struct vattr *a_vap;
39954668Smckusick 		struct ucred *a_cred;
40054668Smckusick 		struct proc *a_p;
40154668Smckusick 	} */ *ap;
40238414Smckusick {
40353805Smckusick 	register struct vnode *vp = ap->a_vp;
40453805Smckusick 	register struct nfsnode *np = VTONFS(vp);
40539488Smckusick 	register caddr_t cp;
40639488Smckusick 	caddr_t bpos, dpos;
40739488Smckusick 	int error = 0;
40839488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
40938414Smckusick 
41053805Smckusick 	/*
41153805Smckusick 	 * Update local times for special files.
41253805Smckusick 	 */
41356329Smckusick 	if (np->n_flag & (NACC | NUPD))
41453805Smckusick 		np->n_flag |= NCHG;
41553805Smckusick 	/*
41653805Smckusick 	 * First look in the cache.
41753805Smckusick 	 */
41853805Smckusick 	if (nfs_getattrcache(vp, ap->a_vap) == 0)
41938414Smckusick 		return (0);
42038414Smckusick 	nfsstats.rpccnt[NFSPROC_GETATTR]++;
42153805Smckusick 	nfsm_reqhead(vp, NFSPROC_GETATTR, NFSX_FH);
42253805Smckusick 	nfsm_fhtom(vp);
42353805Smckusick 	nfsm_request(vp, NFSPROC_GETATTR, ap->a_p, ap->a_cred);
42453805Smckusick 	nfsm_loadattr(vp, ap->a_vap);
42538414Smckusick 	nfsm_reqdone;
42638414Smckusick 	return (error);
42738414Smckusick }
42838414Smckusick 
42938414Smckusick /*
43038414Smckusick  * nfs setattr call.
43138414Smckusick  */
43252234Sheideman int
43353806Smckusick nfs_setattr(ap)
43454451Smckusick 	struct vop_setattr_args /* {
43554451Smckusick 		struct vnodeop_desc *a_desc;
43654451Smckusick 		struct vnode *a_vp;
43754451Smckusick 		struct vattr *a_vap;
43854451Smckusick 		struct ucred *a_cred;
43954451Smckusick 		struct proc *a_p;
44054451Smckusick 	} */ *ap;
44138414Smckusick {
44238884Smacklem 	register struct nfsv2_sattr *sp;
44339488Smckusick 	register caddr_t cp;
44439488Smckusick 	register long t1;
44552196Smckusick 	caddr_t bpos, dpos, cp2;
44652196Smckusick 	u_long *tl;
44756289Smckusick 	int error = 0, isnq;
44839488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
44953806Smckusick 	register struct vnode *vp = ap->a_vp;
45053806Smckusick 	register struct nfsnode *np = VTONFS(vp);
45153806Smckusick 	register struct vattr *vap = ap->a_vap;
45252196Smckusick 	u_quad_t frev;
45338414Smckusick 
454*57791Smckusick 	if (vap->va_size != VNOVAL || vap->va_mtime.ts_sec != VNOVAL ||
455*57791Smckusick 		vap->va_atime.ts_sec != VNOVAL) {
456*57791Smckusick 		if (vap->va_size != VNOVAL) {
457*57791Smckusick 			if (np->n_flag & NMODIFIED) {
458*57791Smckusick 			    if (vap->va_size == 0)
459*57791Smckusick 				error = nfs_vinvalbuf(vp, 0, ap->a_cred,
460*57791Smckusick 					ap->a_p, 1);
461*57791Smckusick 			    else
462*57791Smckusick 				error = nfs_vinvalbuf(vp, V_SAVE, ap->a_cred,
463*57791Smckusick 					ap->a_p, 1);
464*57791Smckusick 			    if (error)
465*57791Smckusick 				return (error);
466*57791Smckusick 			}
467*57791Smckusick 			np->n_size = np->n_vattr.va_size = vap->va_size;
468*57791Smckusick 			vnode_pager_setsize(vp, (u_long)np->n_size);
469*57791Smckusick 		} else if ((np->n_flag & NMODIFIED) &&
470*57791Smckusick 			(error = nfs_vinvalbuf(vp, V_SAVE, ap->a_cred,
471*57791Smckusick 			 ap->a_p, 1)) == EINTR)
472*57791Smckusick 			return (error);
473*57791Smckusick 	}
47438414Smckusick 	nfsstats.rpccnt[NFSPROC_SETATTR]++;
47556289Smckusick 	isnq = (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS);
47656289Smckusick 	nfsm_reqhead(vp, NFSPROC_SETATTR, NFSX_FH+NFSX_SATTR(isnq));
47753806Smckusick 	nfsm_fhtom(vp);
47856289Smckusick 	nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR(isnq));
47956289Smckusick 	if (vap->va_mode == (u_short)-1)
48038884Smacklem 		sp->sa_mode = VNOVAL;
48138414Smckusick 	else
48253806Smckusick 		sp->sa_mode = vtonfs_mode(vp->v_type, vap->va_mode);
48356289Smckusick 	if (vap->va_uid == (uid_t)-1)
48438884Smacklem 		sp->sa_uid = VNOVAL;
48538414Smckusick 	else
48653806Smckusick 		sp->sa_uid = txdr_unsigned(vap->va_uid);
48756289Smckusick 	if (vap->va_gid == (gid_t)-1)
48838884Smacklem 		sp->sa_gid = VNOVAL;
48938414Smckusick 	else
49053806Smckusick 		sp->sa_gid = txdr_unsigned(vap->va_gid);
49156289Smckusick 	if (isnq) {
49256289Smckusick 		txdr_hyper(&vap->va_size, &sp->sa_nqsize);
49356289Smckusick 		txdr_nqtime(&vap->va_atime, &sp->sa_nqatime);
49456289Smckusick 		txdr_nqtime(&vap->va_mtime, &sp->sa_nqmtime);
49556289Smckusick 		sp->sa_nqflags = txdr_unsigned(vap->va_flags);
49656289Smckusick 		sp->sa_nqrdev = VNOVAL;
49756289Smckusick 	} else {
49856289Smckusick 		sp->sa_nfssize = txdr_unsigned(vap->va_size);
49956289Smckusick 		sp->sa_nfsatime.nfs_sec = txdr_unsigned(vap->va_atime.ts_sec);
50056289Smckusick 		sp->sa_nfsatime.nfs_usec = txdr_unsigned(vap->va_flags);
50156289Smckusick 		txdr_nfstime(&vap->va_mtime, &sp->sa_nfsmtime);
50256289Smckusick 	}
50353806Smckusick 	nfsm_request(vp, NFSPROC_SETATTR, ap->a_p, ap->a_cred);
50453806Smckusick 	nfsm_loadattr(vp, (struct vattr *)0);
50553806Smckusick 	if ((VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) &&
50653806Smckusick 	    NQNFS_CKCACHABLE(vp, NQL_WRITE)) {
50752196Smckusick 		nfsm_dissect(tl, u_long *, 2*NFSX_UNSIGNED);
50852196Smckusick 		fxdr_hyper(tl, &frev);
50954451Smckusick 		if (frev > np->n_brev)
51052196Smckusick 			np->n_brev = frev;
51152196Smckusick 	}
51238414Smckusick 	nfsm_reqdone;
51338414Smckusick 	return (error);
51438414Smckusick }
51538414Smckusick 
51638414Smckusick /*
51738414Smckusick  * nfs lookup call, one step at a time...
51838414Smckusick  * First look in cache
51938414Smckusick  * If not found, unlock the directory nfsnode and do the rpc
52038414Smckusick  */
52152234Sheideman int
52253806Smckusick nfs_lookup(ap)
52354451Smckusick 	struct vop_lookup_args /* {
52454451Smckusick 		struct vnodeop_desc *a_desc;
52554451Smckusick 		struct vnode *a_dvp;
52654451Smckusick 		struct vnode **a_vpp;
52754451Smckusick 		struct componentname *a_cnp;
52854451Smckusick 	} */ *ap;
52938414Smckusick {
53053806Smckusick 	register struct componentname *cnp = ap->a_cnp;
53153806Smckusick 	register struct vnode *dvp = ap->a_dvp;
53254668Smckusick 	register struct vnode **vpp = ap->a_vpp;
53355184Smckusick 	register int flags = cnp->cn_flags;
53438414Smckusick 	register struct vnode *vdp;
53548054Smckusick 	register u_long *tl;
53639488Smckusick 	register caddr_t cp;
53739488Smckusick 	register long t1, t2;
53852196Smckusick 	struct nfsmount *nmp;
53952196Smckusick 	struct nfsnode *tp;
54039488Smckusick 	caddr_t bpos, dpos, cp2;
54152196Smckusick 	time_t reqtime;
54239488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
54338414Smckusick 	struct vnode *newvp;
54438414Smckusick 	long len;
54538414Smckusick 	nfsv2fh_t *fhp;
54638414Smckusick 	struct nfsnode *np;
54752234Sheideman 	int lockparent, wantparent, error = 0;
54852196Smckusick 	int nqlflag, cachable;
54952196Smckusick 	u_quad_t frev;
55038414Smckusick 
55154668Smckusick 	*vpp = NULL;
55253806Smckusick 	if (dvp->v_type != VDIR)
55338414Smckusick 		return (ENOTDIR);
55455184Smckusick 	lockparent = flags & LOCKPARENT;
55555184Smckusick 	wantparent = flags & (LOCKPARENT|WANTPARENT);
55653806Smckusick 	nmp = VFSTONFS(dvp->v_mount);
55753806Smckusick 	np = VTONFS(dvp);
55854668Smckusick 	if ((error = cache_lookup(dvp, vpp, cnp)) && error != ENOENT) {
55938884Smacklem 		struct vattr vattr;
56038884Smacklem 		int vpid;
56138884Smacklem 
56254668Smckusick 		vdp = *vpp;
56338884Smacklem 		vpid = vdp->v_id;
56438414Smckusick 		/*
56538884Smacklem 		 * See the comment starting `Step through' in ufs/ufs_lookup.c
56638884Smacklem 		 * for an explanation of the locking protocol
56738414Smckusick 		 */
56853806Smckusick 		if (dvp == vdp) {
56938425Smckusick 			VREF(vdp);
57039441Smckusick 			error = 0;
57152196Smckusick 		} else
57239441Smckusick 			error = vget(vdp);
57339441Smckusick 		if (!error) {
57440251Smckusick 			if (vpid == vdp->v_id) {
57552196Smckusick 			   if (nmp->nm_flag & NFSMNT_NQNFS) {
57656289Smckusick 				if ((nmp->nm_flag & NFSMNT_NQLOOKLEASE) == 0) {
57756289Smckusick 					nfsstats.lookupcache_hits++;
57856289Smckusick 					if (cnp->cn_nameiop != LOOKUP &&
57956289Smckusick 					    (flags & ISLASTCN))
58056289Smckusick 					    cnp->cn_flags |= SAVENAME;
58156289Smckusick 					return (0);
58256289Smckusick 			        } else if (NQNFS_CKCACHABLE(dvp, NQL_READ)) {
58354451Smckusick 					if (np->n_lrev != np->n_brev ||
58452196Smckusick 					    (np->n_flag & NMODIFIED)) {
58552196Smckusick 						np->n_direofoffset = 0;
58653806Smckusick 						cache_purge(dvp);
587*57791Smckusick 						error = nfs_vinvalbuf(dvp, 0,
58856660Smckusick 						    cnp->cn_cred, cnp->cn_proc,
589*57791Smckusick 						    1);
590*57791Smckusick 						if (error == EINTR)
591*57791Smckusick 							return (error);
59252196Smckusick 						np->n_brev = np->n_lrev;
59352196Smckusick 					} else {
59452196Smckusick 						nfsstats.lookupcache_hits++;
59553806Smckusick 						if (cnp->cn_nameiop != LOOKUP &&
59655184Smckusick 						    (flags & ISLASTCN))
59753806Smckusick 						    cnp->cn_flags |= SAVENAME;
59852196Smckusick 						return (0);
59952196Smckusick 					}
60052196Smckusick 				}
60153806Smckusick 			   } else if (!VOP_GETATTR(vdp, &vattr, cnp->cn_cred, cnp->cn_proc) &&
60254106Smckusick 			       vattr.va_ctime.ts_sec == VTONFS(vdp)->n_ctime) {
60339441Smckusick 				nfsstats.lookupcache_hits++;
60453806Smckusick 				if (cnp->cn_nameiop != LOOKUP &&
60555184Smckusick 				    (flags & ISLASTCN))
60653806Smckusick 					cnp->cn_flags |= SAVENAME;
60739441Smckusick 				return (0);
60840251Smckusick 			   }
60947289Smckusick 			   cache_purge(vdp);
61039441Smckusick 			}
61152196Smckusick 			vrele(vdp);
61238884Smacklem 		}
61354668Smckusick 		*vpp = NULLVP;
61452196Smckusick 	}
61539341Smckusick 	error = 0;
61638414Smckusick 	nfsstats.lookupcache_misses++;
61738414Smckusick 	nfsstats.rpccnt[NFSPROC_LOOKUP]++;
61853806Smckusick 	len = cnp->cn_namelen;
61953806Smckusick 	nfsm_reqhead(dvp, NFSPROC_LOOKUP, NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len));
62052196Smckusick 
62152196Smckusick 	/*
62252196Smckusick 	 * For nqnfs optionally piggyback a getlease request for the name
62352196Smckusick 	 * being looked up.
62452196Smckusick 	 */
62552196Smckusick 	if (nmp->nm_flag & NFSMNT_NQNFS) {
62656289Smckusick 		nfsm_build(tl, u_long *, NFSX_UNSIGNED);
62752196Smckusick 		if ((nmp->nm_flag & NFSMNT_NQLOOKLEASE) &&
62855184Smckusick 		    ((cnp->cn_flags & MAKEENTRY) &&
62956289Smckusick 		    (cnp->cn_nameiop != DELETE || !(flags & ISLASTCN))))
63052196Smckusick 			*tl = txdr_unsigned(nmp->nm_leaseterm);
63156289Smckusick 		else
63252196Smckusick 			*tl = 0;
63352196Smckusick 	}
63453806Smckusick 	nfsm_fhtom(dvp);
63553806Smckusick 	nfsm_strtom(cnp->cn_nameptr, len, NFS_MAXNAMLEN);
63652196Smckusick 	reqtime = time.tv_sec;
63753806Smckusick 	nfsm_request(dvp, NFSPROC_LOOKUP, cnp->cn_proc, cnp->cn_cred);
63838414Smckusick nfsmout:
63938414Smckusick 	if (error) {
64053806Smckusick 		if ((cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME) &&
64155184Smckusick 		    (flags & ISLASTCN) && error == ENOENT)
64252823Smckusick 			error = EJUSTRETURN;
64355184Smckusick 		if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN))
64453806Smckusick 			cnp->cn_flags |= SAVENAME;
64540483Smckusick 		return (error);
64638414Smckusick 	}
64752196Smckusick 	if (nmp->nm_flag & NFSMNT_NQNFS) {
64852196Smckusick 		nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
64952196Smckusick 		if (*tl) {
65052196Smckusick 			nqlflag = fxdr_unsigned(int, *tl);
65152196Smckusick 			nfsm_dissect(tl, u_long *, 4*NFSX_UNSIGNED);
65252196Smckusick 			cachable = fxdr_unsigned(int, *tl++);
65352196Smckusick 			reqtime += fxdr_unsigned(int, *tl++);
65452196Smckusick 			fxdr_hyper(tl, &frev);
65552196Smckusick 		} else
65652196Smckusick 			nqlflag = 0;
65752196Smckusick 	}
65852196Smckusick 	nfsm_dissect(fhp, nfsv2fh_t *, NFSX_FH);
65938414Smckusick 
66038414Smckusick 	/*
66152196Smckusick 	 * Handle RENAME case...
66238414Smckusick 	 */
66355184Smckusick 	if (cnp->cn_nameiop == RENAME && wantparent && (flags & ISLASTCN)) {
66452196Smckusick 		if (!bcmp(np->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) {
66538414Smckusick 			m_freem(mrep);
66638414Smckusick 			return (EISDIR);
66738414Smckusick 		}
66853806Smckusick 		if (error = nfs_nget(dvp->v_mount, fhp, &np)) {
66938414Smckusick 			m_freem(mrep);
67038414Smckusick 			return (error);
67138414Smckusick 		}
67238414Smckusick 		newvp = NFSTOV(np);
67339459Smckusick 		if (error =
67439459Smckusick 		    nfs_loadattrcache(&newvp, &md, &dpos, (struct vattr *)0)) {
67552196Smckusick 			vrele(newvp);
67638414Smckusick 			m_freem(mrep);
67738414Smckusick 			return (error);
67838414Smckusick 		}
67954668Smckusick 		*vpp = newvp;
68045037Smckusick 		m_freem(mrep);
68153806Smckusick 		cnp->cn_flags |= SAVENAME;
68238414Smckusick 		return (0);
68338414Smckusick 	}
68438414Smckusick 
68552196Smckusick 	if (!bcmp(np->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) {
68653806Smckusick 		VREF(dvp);
68753806Smckusick 		newvp = dvp;
68838414Smckusick 	} else {
68953806Smckusick 		if (error = nfs_nget(dvp->v_mount, fhp, &np)) {
69038414Smckusick 			m_freem(mrep);
69138414Smckusick 			return (error);
69238414Smckusick 		}
69338414Smckusick 		newvp = NFSTOV(np);
69438414Smckusick 	}
69539459Smckusick 	if (error = nfs_loadattrcache(&newvp, &md, &dpos, (struct vattr *)0)) {
69652196Smckusick 		vrele(newvp);
69738414Smckusick 		m_freem(mrep);
69838414Smckusick 		return (error);
69938414Smckusick 	}
70038414Smckusick 	m_freem(mrep);
70154668Smckusick 	*vpp = newvp;
70255184Smckusick 	if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN))
70353806Smckusick 		cnp->cn_flags |= SAVENAME;
70455184Smckusick 	if ((cnp->cn_flags & MAKEENTRY) &&
70555184Smckusick 	    (cnp->cn_nameiop != DELETE || !(flags & ISLASTCN))) {
70652196Smckusick 		if ((nmp->nm_flag & NFSMNT_NQNFS) == 0)
70754106Smckusick 			np->n_ctime = np->n_vattr.va_ctime.ts_sec;
70856289Smckusick 		else if (nqlflag && reqtime > time.tv_sec)
70956289Smckusick 			nqnfs_clientlease(nmp, np, nqlflag, cachable, reqtime,
71056289Smckusick 				frev);
71154668Smckusick 		cache_enter(dvp, *vpp, cnp);
71240251Smckusick 	}
71352196Smckusick 	return (0);
71438414Smckusick }
71538414Smckusick 
71638414Smckusick /*
71741905Smckusick  * nfs read call.
71841905Smckusick  * Just call nfs_bioread() to do the work.
71941905Smckusick  */
72052234Sheideman int
72153806Smckusick nfs_read(ap)
72254668Smckusick 	struct vop_read_args /* {
72354668Smckusick 		struct vnode *a_vp;
72454668Smckusick 		struct uio *a_uio;
72554668Smckusick 		int  a_ioflag;
72654668Smckusick 		struct ucred *a_cred;
72754668Smckusick 	} */ *ap;
72841905Smckusick {
72953806Smckusick 	register struct vnode *vp = ap->a_vp;
73053806Smckusick 
73153806Smckusick 	if (vp->v_type != VREG)
73241905Smckusick 		return (EPERM);
73353806Smckusick 	return (nfs_bioread(vp, ap->a_uio, ap->a_ioflag, ap->a_cred));
73441905Smckusick }
73541905Smckusick 
73641905Smckusick /*
73738414Smckusick  * nfs readlink call
73838414Smckusick  */
73952234Sheideman int
74053806Smckusick nfs_readlink(ap)
74154668Smckusick 	struct vop_readlink_args /* {
74254668Smckusick 		struct vnode *a_vp;
74354668Smckusick 		struct uio *a_uio;
74454668Smckusick 		struct ucred *a_cred;
74554668Smckusick 	} */ *ap;
74641905Smckusick {
74753806Smckusick 	register struct vnode *vp = ap->a_vp;
74853806Smckusick 
74953806Smckusick 	if (vp->v_type != VLNK)
75041905Smckusick 		return (EPERM);
75153806Smckusick 	return (nfs_bioread(vp, ap->a_uio, 0, ap->a_cred));
75241905Smckusick }
75341905Smckusick 
75441905Smckusick /*
75541905Smckusick  * Do a readlink rpc.
75641905Smckusick  * Called by nfs_doio() from below the buffer cache.
75741905Smckusick  */
75852234Sheideman int
75948054Smckusick nfs_readlinkrpc(vp, uiop, cred)
76039488Smckusick 	register struct vnode *vp;
76138414Smckusick 	struct uio *uiop;
76238414Smckusick 	struct ucred *cred;
76338414Smckusick {
76448054Smckusick 	register u_long *tl;
76539488Smckusick 	register caddr_t cp;
76639488Smckusick 	register long t1;
76739488Smckusick 	caddr_t bpos, dpos, cp2;
76839488Smckusick 	int error = 0;
76939488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
77038414Smckusick 	long len;
77138414Smckusick 
77238414Smckusick 	nfsstats.rpccnt[NFSPROC_READLINK]++;
77352196Smckusick 	nfsm_reqhead(vp, NFSPROC_READLINK, NFSX_FH);
77438414Smckusick 	nfsm_fhtom(vp);
77552196Smckusick 	nfsm_request(vp, NFSPROC_READLINK, uiop->uio_procp, cred);
77638414Smckusick 	nfsm_strsiz(len, NFS_MAXPATHLEN);
77738414Smckusick 	nfsm_mtouio(uiop, len);
77838414Smckusick 	nfsm_reqdone;
77938414Smckusick 	return (error);
78038414Smckusick }
78138414Smckusick 
78238414Smckusick /*
78341905Smckusick  * nfs read rpc call
78441905Smckusick  * Ditto above
78538414Smckusick  */
78652234Sheideman int
78748054Smckusick nfs_readrpc(vp, uiop, cred)
78839488Smckusick 	register struct vnode *vp;
78938414Smckusick 	struct uio *uiop;
79038414Smckusick 	struct ucred *cred;
79138414Smckusick {
79248054Smckusick 	register u_long *tl;
79339488Smckusick 	register caddr_t cp;
79439488Smckusick 	register long t1;
79539488Smckusick 	caddr_t bpos, dpos, cp2;
79639488Smckusick 	int error = 0;
79739488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
79838414Smckusick 	struct nfsmount *nmp;
79938414Smckusick 	long len, retlen, tsiz;
80038414Smckusick 
80141398Smckusick 	nmp = VFSTONFS(vp->v_mount);
80238414Smckusick 	tsiz = uiop->uio_resid;
80356289Smckusick 	if (uiop->uio_offset + tsiz > 0xffffffff &&
80456289Smckusick 	    (nmp->nm_flag & NFSMNT_NQNFS) == 0)
80556289Smckusick 		return (EFBIG);
80638414Smckusick 	while (tsiz > 0) {
80738414Smckusick 		nfsstats.rpccnt[NFSPROC_READ]++;
80838414Smckusick 		len = (tsiz > nmp->nm_rsize) ? nmp->nm_rsize : tsiz;
80952196Smckusick 		nfsm_reqhead(vp, NFSPROC_READ, NFSX_FH+NFSX_UNSIGNED*3);
81038414Smckusick 		nfsm_fhtom(vp);
81148054Smckusick 		nfsm_build(tl, u_long *, NFSX_UNSIGNED*3);
81256289Smckusick 		if (nmp->nm_flag & NFSMNT_NQNFS) {
81356289Smckusick 			txdr_hyper(&uiop->uio_offset, tl);
81456289Smckusick 			*(tl + 2) = txdr_unsigned(len);
81556289Smckusick 		} else {
81656289Smckusick 			*tl++ = txdr_unsigned(uiop->uio_offset);
81756289Smckusick 			*tl++ = txdr_unsigned(len);
81856289Smckusick 			*tl = 0;
81956289Smckusick 		}
82052196Smckusick 		nfsm_request(vp, NFSPROC_READ, uiop->uio_procp, cred);
82138414Smckusick 		nfsm_loadattr(vp, (struct vattr *)0);
82238414Smckusick 		nfsm_strsiz(retlen, nmp->nm_rsize);
82338414Smckusick 		nfsm_mtouio(uiop, retlen);
82438414Smckusick 		m_freem(mrep);
82538414Smckusick 		if (retlen < len)
82638414Smckusick 			tsiz = 0;
82738414Smckusick 		else
82838414Smckusick 			tsiz -= len;
82938414Smckusick 	}
83038414Smckusick nfsmout:
83138414Smckusick 	return (error);
83238414Smckusick }
83338414Smckusick 
83438414Smckusick /*
83538414Smckusick  * nfs write call
83638414Smckusick  */
83752234Sheideman int
83856289Smckusick nfs_writerpc(vp, uiop, cred, ioflags)
83939488Smckusick 	register struct vnode *vp;
84038414Smckusick 	struct uio *uiop;
84138414Smckusick 	struct ucred *cred;
84256289Smckusick 	int ioflags;
84338414Smckusick {
84448054Smckusick 	register u_long *tl;
84539488Smckusick 	register caddr_t cp;
84639488Smckusick 	register long t1;
84752196Smckusick 	caddr_t bpos, dpos, cp2;
84839488Smckusick 	int error = 0;
84939488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
85038414Smckusick 	struct nfsmount *nmp;
85152196Smckusick 	struct nfsnode *np = VTONFS(vp);
85252196Smckusick 	u_quad_t frev;
85338414Smckusick 	long len, tsiz;
85438414Smckusick 
85541398Smckusick 	nmp = VFSTONFS(vp->v_mount);
85638414Smckusick 	tsiz = uiop->uio_resid;
85756289Smckusick 	if (uiop->uio_offset + tsiz > 0xffffffff &&
85856289Smckusick 	    (nmp->nm_flag & NFSMNT_NQNFS) == 0)
85956289Smckusick 		return (EFBIG);
86038414Smckusick 	while (tsiz > 0) {
86138414Smckusick 		nfsstats.rpccnt[NFSPROC_WRITE]++;
86238414Smckusick 		len = (tsiz > nmp->nm_wsize) ? nmp->nm_wsize : tsiz;
86352196Smckusick 		nfsm_reqhead(vp, NFSPROC_WRITE,
86452196Smckusick 			NFSX_FH+NFSX_UNSIGNED*4+nfsm_rndup(len));
86538414Smckusick 		nfsm_fhtom(vp);
86656289Smckusick 		nfsm_build(tl, u_long *, NFSX_UNSIGNED * 4);
86756289Smckusick 		if (nmp->nm_flag & NFSMNT_NQNFS) {
86856289Smckusick 			txdr_hyper(&uiop->uio_offset, tl);
86956289Smckusick 			tl += 2;
87056289Smckusick 			if (ioflags & IO_APPEND)
87156289Smckusick 				*tl++ = txdr_unsigned(1);
87256289Smckusick 			else
87356289Smckusick 				*tl++ = 0;
87456289Smckusick 		} else {
87556289Smckusick 			*++tl = txdr_unsigned(uiop->uio_offset);
87656289Smckusick 			tl += 2;
87756289Smckusick 		}
87856289Smckusick 		*tl = txdr_unsigned(len);
87938414Smckusick 		nfsm_uiotom(uiop, len);
88052196Smckusick 		nfsm_request(vp, NFSPROC_WRITE, uiop->uio_procp, cred);
88138414Smckusick 		nfsm_loadattr(vp, (struct vattr *)0);
88252196Smckusick 		if (nmp->nm_flag & NFSMNT_MYWRITE)
88354106Smckusick 			VTONFS(vp)->n_mtime = VTONFS(vp)->n_vattr.va_mtime.ts_sec;
88452196Smckusick 		else if ((nmp->nm_flag & NFSMNT_NQNFS) &&
88552196Smckusick 			 NQNFS_CKCACHABLE(vp, NQL_WRITE)) {
88652196Smckusick 			nfsm_dissect(tl, u_long *, 2*NFSX_UNSIGNED);
88752196Smckusick 			fxdr_hyper(tl, &frev);
88854451Smckusick 			if (frev > np->n_brev)
88952196Smckusick 				np->n_brev = frev;
89052196Smckusick 		}
89138414Smckusick 		m_freem(mrep);
89238414Smckusick 		tsiz -= len;
89338414Smckusick 	}
89438414Smckusick nfsmout:
89552196Smckusick 	if (error)
89652196Smckusick 		uiop->uio_resid = tsiz;
89738414Smckusick 	return (error);
89838414Smckusick }
89938414Smckusick 
90038414Smckusick /*
90139459Smckusick  * nfs mknod call
90242246Smckusick  * This is a kludge. Use a create rpc but with the IFMT bits of the mode
90342246Smckusick  * set to specify the file type and the size field for rdev.
90439459Smckusick  */
90539459Smckusick /* ARGSUSED */
90652234Sheideman int
90753806Smckusick nfs_mknod(ap)
90854668Smckusick 	struct vop_mknod_args /* {
90954668Smckusick 		struct vnode *a_dvp;
91054668Smckusick 		struct vnode **a_vpp;
91154668Smckusick 		struct componentname *a_cnp;
91254668Smckusick 		struct vattr *a_vap;
91354668Smckusick 	} */ *ap;
91439459Smckusick {
91553806Smckusick 	register struct vnode *dvp = ap->a_dvp;
91653806Smckusick 	register struct vattr *vap = ap->a_vap;
91753806Smckusick 	register struct componentname *cnp = ap->a_cnp;
91842246Smckusick 	register struct nfsv2_sattr *sp;
91948054Smckusick 	register u_long *tl;
92042246Smckusick 	register caddr_t cp;
92156289Smckusick 	register long t1, t2;
92256289Smckusick 	struct vnode *newvp;
92356289Smckusick 	char *cp2;
92442246Smckusick 	caddr_t bpos, dpos;
92556289Smckusick 	int error = 0, isnq;
92642246Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
92742246Smckusick 	u_long rdev;
92839459Smckusick 
92956289Smckusick 	isnq = (VFSTONFS(dvp->v_mount)->nm_flag & NFSMNT_NQNFS);
93053806Smckusick 	if (vap->va_type == VCHR || vap->va_type == VBLK)
93153806Smckusick 		rdev = txdr_unsigned(vap->va_rdev);
93242246Smckusick #ifdef FIFO
93353806Smckusick 	else if (vap->va_type == VFIFO)
93442246Smckusick 		rdev = 0xffffffff;
93542246Smckusick #endif /* FIFO */
93642246Smckusick 	else {
93753806Smckusick 		VOP_ABORTOP(dvp, cnp);
93853806Smckusick 		vput(dvp);
93942246Smckusick 		return (EOPNOTSUPP);
94042246Smckusick 	}
94142246Smckusick 	nfsstats.rpccnt[NFSPROC_CREATE]++;
94253806Smckusick 	nfsm_reqhead(dvp, NFSPROC_CREATE,
94356289Smckusick 	  NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen)+NFSX_SATTR(isnq));
94453806Smckusick 	nfsm_fhtom(dvp);
94553806Smckusick 	nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
94656289Smckusick 	nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR(isnq));
94753806Smckusick 	sp->sa_mode = vtonfs_mode(vap->va_type, vap->va_mode);
94853806Smckusick 	sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid);
94953806Smckusick 	sp->sa_gid = txdr_unsigned(cnp->cn_cred->cr_gid);
95056289Smckusick 	if (isnq) {
95156289Smckusick 		sp->sa_nqrdev = rdev;
95256289Smckusick 		sp->sa_nqflags = 0;
95356289Smckusick 		txdr_nqtime(&vap->va_atime, &sp->sa_nqatime);
95456289Smckusick 		txdr_nqtime(&vap->va_mtime, &sp->sa_nqmtime);
95556289Smckusick 	} else {
95656289Smckusick 		sp->sa_nfssize = rdev;
95756289Smckusick 		txdr_nfstime(&vap->va_atime, &sp->sa_nfsatime);
95856289Smckusick 		txdr_nfstime(&vap->va_mtime, &sp->sa_nfsmtime);
95956289Smckusick 	}
96053806Smckusick 	nfsm_request(dvp, NFSPROC_CREATE, cnp->cn_proc, cnp->cn_cred);
96156289Smckusick 	nfsm_mtofh(dvp, newvp);
96242246Smckusick 	nfsm_reqdone;
96356927Smckusick 	if (!error && (cnp->cn_flags & MAKEENTRY))
96456289Smckusick 		cache_enter(dvp, newvp, cnp);
96553806Smckusick 	FREE(cnp->cn_pnbuf, M_NAMEI);
96653806Smckusick 	VTONFS(dvp)->n_flag |= NMODIFIED;
96753806Smckusick 	vrele(dvp);
96842246Smckusick 	return (error);
96939459Smckusick }
97039459Smckusick 
97139459Smckusick /*
97238414Smckusick  * nfs file create call
97338414Smckusick  */
97452234Sheideman int
97553806Smckusick nfs_create(ap)
97654668Smckusick 	struct vop_create_args /* {
97754668Smckusick 		struct vnode *a_dvp;
97854668Smckusick 		struct vnode **a_vpp;
97954668Smckusick 		struct componentname *a_cnp;
98054668Smckusick 		struct vattr *a_vap;
98154668Smckusick 	} */ *ap;
98238414Smckusick {
98353806Smckusick 	register struct vnode *dvp = ap->a_dvp;
98453806Smckusick 	register struct vattr *vap = ap->a_vap;
98553806Smckusick 	register struct componentname *cnp = ap->a_cnp;
98638884Smacklem 	register struct nfsv2_sattr *sp;
98748054Smckusick 	register u_long *tl;
98839488Smckusick 	register caddr_t cp;
98939488Smckusick 	register long t1, t2;
99039488Smckusick 	caddr_t bpos, dpos, cp2;
99156289Smckusick 	int error = 0, isnq;
99239488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
99338414Smckusick 
99438414Smckusick 	nfsstats.rpccnt[NFSPROC_CREATE]++;
99556289Smckusick 	isnq = (VFSTONFS(dvp->v_mount)->nm_flag & NFSMNT_NQNFS);
99653806Smckusick 	nfsm_reqhead(dvp, NFSPROC_CREATE,
99756289Smckusick 	  NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen)+NFSX_SATTR(isnq));
99853806Smckusick 	nfsm_fhtom(dvp);
99953806Smckusick 	nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
100056289Smckusick 	nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR(isnq));
100153806Smckusick 	sp->sa_mode = vtonfs_mode(vap->va_type, vap->va_mode);
100253806Smckusick 	sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid);
100353806Smckusick 	sp->sa_gid = txdr_unsigned(cnp->cn_cred->cr_gid);
100456289Smckusick 	if (isnq) {
100556289Smckusick 		u_quad_t qval = 0;
100656289Smckusick 
100756289Smckusick 		txdr_hyper(&qval, &sp->sa_nqsize);
100856289Smckusick 		sp->sa_nqflags = 0;
100956289Smckusick 		sp->sa_nqrdev = -1;
101056289Smckusick 		txdr_nqtime(&vap->va_atime, &sp->sa_nqatime);
101156289Smckusick 		txdr_nqtime(&vap->va_mtime, &sp->sa_nqmtime);
101256289Smckusick 	} else {
101356289Smckusick 		sp->sa_nfssize = 0;
101456289Smckusick 		txdr_nfstime(&vap->va_atime, &sp->sa_nfsatime);
101556289Smckusick 		txdr_nfstime(&vap->va_mtime, &sp->sa_nfsmtime);
101656289Smckusick 	}
101753806Smckusick 	nfsm_request(dvp, NFSPROC_CREATE, cnp->cn_proc, cnp->cn_cred);
101853806Smckusick 	nfsm_mtofh(dvp, *ap->a_vpp);
101938414Smckusick 	nfsm_reqdone;
102056927Smckusick 	if (!error && (cnp->cn_flags & MAKEENTRY))
102156289Smckusick 		cache_enter(dvp, *ap->a_vpp, cnp);
102253806Smckusick 	FREE(cnp->cn_pnbuf, M_NAMEI);
102353806Smckusick 	VTONFS(dvp)->n_flag |= NMODIFIED;
102453806Smckusick 	vrele(dvp);
102538414Smckusick 	return (error);
102638414Smckusick }
102738414Smckusick 
102838414Smckusick /*
102938414Smckusick  * nfs file remove call
103041905Smckusick  * To try and make nfs semantics closer to ufs semantics, a file that has
103141905Smckusick  * other processes using the vnode is renamed instead of removed and then
103239341Smckusick  * removed later on the last close.
103341905Smckusick  * - If v_usecount > 1
103439341Smckusick  *	  If a rename is not already in the works
103539341Smckusick  *	     call nfs_sillyrename() to set it up
103639341Smckusick  *     else
103739341Smckusick  *	  do the remove rpc
103838414Smckusick  */
103952234Sheideman int
104053806Smckusick nfs_remove(ap)
104154451Smckusick 	struct vop_remove_args /* {
104254451Smckusick 		struct vnodeop_desc *a_desc;
104354451Smckusick 		struct vnode * a_dvp;
104454451Smckusick 		struct vnode * a_vp;
104554451Smckusick 		struct componentname * a_cnp;
104654451Smckusick 	} */ *ap;
104738414Smckusick {
104853806Smckusick 	register struct vnode *vp = ap->a_vp;
104953806Smckusick 	register struct vnode *dvp = ap->a_dvp;
105053806Smckusick 	register struct componentname *cnp = ap->a_cnp;
105153806Smckusick 	register struct nfsnode *np = VTONFS(vp);
105248054Smckusick 	register u_long *tl;
105339488Smckusick 	register caddr_t cp;
105452196Smckusick 	register long t2;
105539488Smckusick 	caddr_t bpos, dpos;
105639488Smckusick 	int error = 0;
105739488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
105838414Smckusick 
105953806Smckusick 	if (vp->v_usecount > 1) {
106039341Smckusick 		if (!np->n_sillyrename)
106153806Smckusick 			error = nfs_sillyrename(dvp, vp, cnp);
106239341Smckusick 	} else {
106352196Smckusick 		/*
106452196Smckusick 		 * Purge the name cache so that the chance of a lookup for
106552196Smckusick 		 * the name succeeding while the remove is in progress is
106652196Smckusick 		 * minimized. Without node locking it can still happen, such
106752196Smckusick 		 * that an I/O op returns ESTALE, but since you get this if
106852196Smckusick 		 * another host removes the file..
106952196Smckusick 		 */
107053806Smckusick 		cache_purge(vp);
107152196Smckusick 		/*
107252196Smckusick 		 * Throw away biocache buffers. Mainly to avoid
107352196Smckusick 		 * unnecessary delayed writes.
107452196Smckusick 		 */
1075*57791Smckusick 		error = nfs_vinvalbuf(vp, 0, cnp->cn_cred, cnp->cn_proc, 1);
1076*57791Smckusick 		if (error == EINTR)
1077*57791Smckusick 			return (error);
107852196Smckusick 		/* Do the rpc */
107938414Smckusick 		nfsstats.rpccnt[NFSPROC_REMOVE]++;
108053806Smckusick 		nfsm_reqhead(dvp, NFSPROC_REMOVE,
108153806Smckusick 			NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen));
108253806Smckusick 		nfsm_fhtom(dvp);
108353806Smckusick 		nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
108453806Smckusick 		nfsm_request(dvp, NFSPROC_REMOVE, cnp->cn_proc, cnp->cn_cred);
108538414Smckusick 		nfsm_reqdone;
108653806Smckusick 		FREE(cnp->cn_pnbuf, M_NAMEI);
108753806Smckusick 		VTONFS(dvp)->n_flag |= NMODIFIED;
108839751Smckusick 		/*
108939751Smckusick 		 * Kludge City: If the first reply to the remove rpc is lost..
109039751Smckusick 		 *   the reply to the retransmitted request will be ENOENT
109139751Smckusick 		 *   since the file was in fact removed
109239751Smckusick 		 *   Therefore, we cheat and return success.
109339751Smckusick 		 */
109439751Smckusick 		if (error == ENOENT)
109539751Smckusick 			error = 0;
109638414Smckusick 	}
109740042Smckusick 	np->n_attrstamp = 0;
109853806Smckusick 	vrele(dvp);
109953806Smckusick 	vrele(vp);
110038414Smckusick 	return (error);
110138414Smckusick }
110238414Smckusick 
110338414Smckusick /*
110438414Smckusick  * nfs file remove rpc called from nfs_inactive
110538414Smckusick  */
110652234Sheideman int
110754451Smckusick nfs_removeit(sp)
110848364Smckusick 	register struct sillyrename *sp;
110938414Smckusick {
111048054Smckusick 	register u_long *tl;
111139488Smckusick 	register caddr_t cp;
111252196Smckusick 	register long t2;
111339488Smckusick 	caddr_t bpos, dpos;
111439488Smckusick 	int error = 0;
111539488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
111638414Smckusick 
111738414Smckusick 	nfsstats.rpccnt[NFSPROC_REMOVE]++;
111852196Smckusick 	nfsm_reqhead(sp->s_dvp, NFSPROC_REMOVE,
111948364Smckusick 		NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(sp->s_namlen));
112048364Smckusick 	nfsm_fhtom(sp->s_dvp);
112148364Smckusick 	nfsm_strtom(sp->s_name, sp->s_namlen, NFS_MAXNAMLEN);
112254451Smckusick 	nfsm_request(sp->s_dvp, NFSPROC_REMOVE, NULL, sp->s_cred);
112338414Smckusick 	nfsm_reqdone;
112448364Smckusick 	VTONFS(sp->s_dvp)->n_flag |= NMODIFIED;
112538414Smckusick 	return (error);
112638414Smckusick }
112738414Smckusick 
112838414Smckusick /*
112938414Smckusick  * nfs file rename call
113038414Smckusick  */
113152234Sheideman int
113253806Smckusick nfs_rename(ap)
113354668Smckusick 	struct vop_rename_args  /* {
113454668Smckusick 		struct vnode *a_fdvp;
113554668Smckusick 		struct vnode *a_fvp;
113654668Smckusick 		struct componentname *a_fcnp;
113754668Smckusick 		struct vnode *a_tdvp;
113854668Smckusick 		struct vnode *a_tvp;
113954668Smckusick 		struct componentname *a_tcnp;
114054668Smckusick 	} */ *ap;
114138414Smckusick {
114253806Smckusick 	register struct vnode *fvp = ap->a_fvp;
114353806Smckusick 	register struct vnode *tvp = ap->a_tvp;
114453806Smckusick 	register struct vnode *fdvp = ap->a_fdvp;
114553806Smckusick 	register struct vnode *tdvp = ap->a_tdvp;
114653806Smckusick 	register struct componentname *tcnp = ap->a_tcnp;
114753806Smckusick 	register struct componentname *fcnp = ap->a_fcnp;
114848054Smckusick 	register u_long *tl;
114939488Smckusick 	register caddr_t cp;
115052196Smckusick 	register long t2;
115139488Smckusick 	caddr_t bpos, dpos;
115239488Smckusick 	int error = 0;
115339488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
115438414Smckusick 
115553804Spendry 	/* Check for cross-device rename */
115653806Smckusick 	if ((fvp->v_mount != tdvp->v_mount) ||
115753806Smckusick 	    (tvp && (fvp->v_mount != tvp->v_mount))) {
115853804Spendry 		error = EXDEV;
115953804Spendry 		goto out;
116053804Spendry 	}
116153804Spendry 
116253804Spendry 
116338414Smckusick 	nfsstats.rpccnt[NFSPROC_RENAME]++;
116453806Smckusick 	nfsm_reqhead(fdvp, NFSPROC_RENAME,
116553806Smckusick 		(NFSX_FH+NFSX_UNSIGNED)*2+nfsm_rndup(fcnp->cn_namelen)+
116653806Smckusick 		nfsm_rndup(fcnp->cn_namelen)); /* or fcnp->cn_cred?*/
116753806Smckusick 	nfsm_fhtom(fdvp);
116853806Smckusick 	nfsm_strtom(fcnp->cn_nameptr, fcnp->cn_namelen, NFS_MAXNAMLEN);
116953806Smckusick 	nfsm_fhtom(tdvp);
117053806Smckusick 	nfsm_strtom(tcnp->cn_nameptr, tcnp->cn_namelen, NFS_MAXNAMLEN);
117153806Smckusick 	nfsm_request(fdvp, NFSPROC_RENAME, tcnp->cn_proc, tcnp->cn_cred);
117238414Smckusick 	nfsm_reqdone;
117353806Smckusick 	VTONFS(fdvp)->n_flag |= NMODIFIED;
117453806Smckusick 	VTONFS(tdvp)->n_flag |= NMODIFIED;
117553806Smckusick 	if (fvp->v_type == VDIR) {
117653806Smckusick 		if (tvp != NULL && tvp->v_type == VDIR)
117753806Smckusick 			cache_purge(tdvp);
117853806Smckusick 		cache_purge(fdvp);
117938414Smckusick 	}
118053804Spendry out:
118153806Smckusick 	if (tdvp == tvp)
118253806Smckusick 		vrele(tdvp);
118343360Smckusick 	else
118453806Smckusick 		vput(tdvp);
118553806Smckusick 	if (tvp)
118653806Smckusick 		vput(tvp);
118753806Smckusick 	vrele(fdvp);
118853806Smckusick 	vrele(fvp);
118940112Smckusick 	/*
119040112Smckusick 	 * Kludge: Map ENOENT => 0 assuming that it is a reply to a retry.
119140112Smckusick 	 */
119240112Smckusick 	if (error == ENOENT)
119340112Smckusick 		error = 0;
119438414Smckusick 	return (error);
119538414Smckusick }
119638414Smckusick 
119738414Smckusick /*
119841905Smckusick  * nfs file rename rpc called from nfs_remove() above
119938414Smckusick  */
120052234Sheideman int
120152234Sheideman nfs_renameit(sdvp, scnp, sp)
120252234Sheideman 	struct vnode *sdvp;
120352234Sheideman 	struct componentname *scnp;
120448364Smckusick 	register struct sillyrename *sp;
120538414Smckusick {
120648054Smckusick 	register u_long *tl;
120739488Smckusick 	register caddr_t cp;
120852196Smckusick 	register long t2;
120939488Smckusick 	caddr_t bpos, dpos;
121039488Smckusick 	int error = 0;
121139488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
121238414Smckusick 
121338414Smckusick 	nfsstats.rpccnt[NFSPROC_RENAME]++;
121452234Sheideman 	nfsm_reqhead(sdvp, NFSPROC_RENAME,
121552234Sheideman 		(NFSX_FH+NFSX_UNSIGNED)*2+nfsm_rndup(scnp->cn_namelen)+
121652196Smckusick 		nfsm_rndup(sp->s_namlen));
121752234Sheideman 	nfsm_fhtom(sdvp);
121852234Sheideman 	nfsm_strtom(scnp->cn_nameptr, scnp->cn_namelen, NFS_MAXNAMLEN);
121952234Sheideman 	nfsm_fhtom(sdvp);
122048364Smckusick 	nfsm_strtom(sp->s_name, sp->s_namlen, NFS_MAXNAMLEN);
122152234Sheideman 	nfsm_request(sdvp, NFSPROC_RENAME, scnp->cn_proc, scnp->cn_cred);
122238414Smckusick 	nfsm_reqdone;
122352234Sheideman 	FREE(scnp->cn_pnbuf, M_NAMEI);
122452234Sheideman 	VTONFS(sdvp)->n_flag |= NMODIFIED;
122538414Smckusick 	return (error);
122638414Smckusick }
122738414Smckusick 
122838414Smckusick /*
122938414Smckusick  * nfs hard link create call
123038414Smckusick  */
123152234Sheideman int
123253806Smckusick nfs_link(ap)
123354668Smckusick 	struct vop_link_args /* {
123454668Smckusick 		struct vnode *a_vp;
123554668Smckusick 		struct vnode *a_tdvp;
123654668Smckusick 		struct componentname *a_cnp;
123754668Smckusick 	} */ *ap;
123838414Smckusick {
123953806Smckusick 	register struct vnode *vp = ap->a_vp;
124053806Smckusick 	register struct vnode *tdvp = ap->a_tdvp;
124153806Smckusick 	register struct componentname *cnp = ap->a_cnp;
124248054Smckusick 	register u_long *tl;
124339488Smckusick 	register caddr_t cp;
124452196Smckusick 	register long t2;
124539488Smckusick 	caddr_t bpos, dpos;
124639488Smckusick 	int error = 0;
124739488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
124838414Smckusick 
124953806Smckusick 	if (vp->v_mount != tdvp->v_mount) {
125053806Smckusick 		/*VOP_ABORTOP(vp, cnp);*/
125153806Smckusick 		if (tdvp == vp)
125253806Smckusick 			vrele(vp);
125353804Spendry 		else
125453806Smckusick 			vput(vp);
125553804Spendry 		return (EXDEV);
125653804Spendry 	}
125753804Spendry 
125838414Smckusick 	nfsstats.rpccnt[NFSPROC_LINK]++;
125953806Smckusick 	nfsm_reqhead(tdvp, NFSPROC_LINK,
126053806Smckusick 		NFSX_FH*2+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen));
126153806Smckusick 	nfsm_fhtom(tdvp);
126253806Smckusick 	nfsm_fhtom(vp);
126353806Smckusick 	nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
126453806Smckusick 	nfsm_request(tdvp, NFSPROC_LINK, cnp->cn_proc, cnp->cn_cred);
126538414Smckusick 	nfsm_reqdone;
126653806Smckusick 	FREE(cnp->cn_pnbuf, M_NAMEI);
126753806Smckusick 	VTONFS(tdvp)->n_attrstamp = 0;
126853806Smckusick 	VTONFS(vp)->n_flag |= NMODIFIED;
126953806Smckusick 	vrele(vp);
127040112Smckusick 	/*
127140112Smckusick 	 * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry.
127240112Smckusick 	 */
127340112Smckusick 	if (error == EEXIST)
127440112Smckusick 		error = 0;
127538414Smckusick 	return (error);
127638414Smckusick }
127738414Smckusick 
127838414Smckusick /*
127938414Smckusick  * nfs symbolic link create call
128038414Smckusick  */
128152234Sheideman /* start here */
128252234Sheideman int
128353806Smckusick nfs_symlink(ap)
128454668Smckusick 	struct vop_symlink_args /* {
128554668Smckusick 		struct vnode *a_dvp;
128654668Smckusick 		struct vnode **a_vpp;
128754668Smckusick 		struct componentname *a_cnp;
128854668Smckusick 		struct vattr *a_vap;
128954668Smckusick 		char *a_target;
129054668Smckusick 	} */ *ap;
129138414Smckusick {
129253806Smckusick 	register struct vnode *dvp = ap->a_dvp;
129353806Smckusick 	register struct vattr *vap = ap->a_vap;
129453806Smckusick 	register struct componentname *cnp = ap->a_cnp;
129538884Smacklem 	register struct nfsv2_sattr *sp;
129648054Smckusick 	register u_long *tl;
129739488Smckusick 	register caddr_t cp;
129852196Smckusick 	register long t2;
129939488Smckusick 	caddr_t bpos, dpos;
130056289Smckusick 	int slen, error = 0, isnq;
130139488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
130238414Smckusick 
130338414Smckusick 	nfsstats.rpccnt[NFSPROC_SYMLINK]++;
130453600Sheideman 	slen = strlen(ap->a_target);
130556289Smckusick 	isnq = (VFSTONFS(dvp->v_mount)->nm_flag & NFSMNT_NQNFS);
130653806Smckusick 	nfsm_reqhead(dvp, NFSPROC_SYMLINK, NFSX_FH+2*NFSX_UNSIGNED+
130756289Smckusick 	    nfsm_rndup(cnp->cn_namelen)+nfsm_rndup(slen)+NFSX_SATTR(isnq));
130853806Smckusick 	nfsm_fhtom(dvp);
130953806Smckusick 	nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
131053600Sheideman 	nfsm_strtom(ap->a_target, slen, NFS_MAXPATHLEN);
131156289Smckusick 	nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR(isnq));
131253806Smckusick 	sp->sa_mode = vtonfs_mode(VLNK, vap->va_mode);
131353806Smckusick 	sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid);
131453806Smckusick 	sp->sa_gid = txdr_unsigned(cnp->cn_cred->cr_gid);
131556289Smckusick 	if (isnq) {
131656289Smckusick 		quad_t qval = -1;
131756289Smckusick 
131856289Smckusick 		txdr_hyper(&qval, &sp->sa_nqsize);
131956289Smckusick 		sp->sa_nqflags = 0;
132056289Smckusick 		txdr_nqtime(&vap->va_atime, &sp->sa_nqatime);
132156289Smckusick 		txdr_nqtime(&vap->va_mtime, &sp->sa_nqmtime);
132256289Smckusick 	} else {
132356289Smckusick 		sp->sa_nfssize = -1;
132456289Smckusick 		txdr_nfstime(&vap->va_atime, &sp->sa_nfsatime);
132556289Smckusick 		txdr_nfstime(&vap->va_mtime, &sp->sa_nfsmtime);
132656289Smckusick 	}
132753806Smckusick 	nfsm_request(dvp, NFSPROC_SYMLINK, cnp->cn_proc, cnp->cn_cred);
132838414Smckusick 	nfsm_reqdone;
132953806Smckusick 	FREE(cnp->cn_pnbuf, M_NAMEI);
133053806Smckusick 	VTONFS(dvp)->n_flag |= NMODIFIED;
133153806Smckusick 	vrele(dvp);
133240112Smckusick 	/*
133340112Smckusick 	 * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry.
133440112Smckusick 	 */
133540112Smckusick 	if (error == EEXIST)
133640112Smckusick 		error = 0;
133738414Smckusick 	return (error);
133838414Smckusick }
133938414Smckusick 
134038414Smckusick /*
134138414Smckusick  * nfs make dir call
134238414Smckusick  */
134352234Sheideman int
134453806Smckusick nfs_mkdir(ap)
134554668Smckusick 	struct vop_mkdir_args /* {
134654668Smckusick 		struct vnode *a_dvp;
134754668Smckusick 		struct vnode **a_vpp;
134854668Smckusick 		struct componentname *a_cnp;
134954668Smckusick 		struct vattr *a_vap;
135054668Smckusick 	} */ *ap;
135138414Smckusick {
135253806Smckusick 	register struct vnode *dvp = ap->a_dvp;
135353806Smckusick 	register struct vattr *vap = ap->a_vap;
135453806Smckusick 	register struct componentname *cnp = ap->a_cnp;
135554668Smckusick 	register struct vnode **vpp = ap->a_vpp;
135638884Smacklem 	register struct nfsv2_sattr *sp;
135748054Smckusick 	register u_long *tl;
135839488Smckusick 	register caddr_t cp;
135939488Smckusick 	register long t1, t2;
136041905Smckusick 	register int len;
136139488Smckusick 	caddr_t bpos, dpos, cp2;
136256289Smckusick 	int error = 0, firsttry = 1, isnq;
136339488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
136438414Smckusick 
136553806Smckusick 	len = cnp->cn_namelen;
136656289Smckusick 	isnq = (VFSTONFS(dvp->v_mount)->nm_flag & NFSMNT_NQNFS);
136738414Smckusick 	nfsstats.rpccnt[NFSPROC_MKDIR]++;
136853806Smckusick 	nfsm_reqhead(dvp, NFSPROC_MKDIR,
136956289Smckusick 	  NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len)+NFSX_SATTR(isnq));
137053806Smckusick 	nfsm_fhtom(dvp);
137153806Smckusick 	nfsm_strtom(cnp->cn_nameptr, len, NFS_MAXNAMLEN);
137256289Smckusick 	nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR(isnq));
137353806Smckusick 	sp->sa_mode = vtonfs_mode(VDIR, vap->va_mode);
137453806Smckusick 	sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid);
137553806Smckusick 	sp->sa_gid = txdr_unsigned(cnp->cn_cred->cr_gid);
137656289Smckusick 	if (isnq) {
137756289Smckusick 		quad_t qval = -1;
137856289Smckusick 
137956289Smckusick 		txdr_hyper(&qval, &sp->sa_nqsize);
138056289Smckusick 		sp->sa_nqflags = 0;
138156289Smckusick 		txdr_nqtime(&vap->va_atime, &sp->sa_nqatime);
138256289Smckusick 		txdr_nqtime(&vap->va_mtime, &sp->sa_nqmtime);
138356289Smckusick 	} else {
138456289Smckusick 		sp->sa_nfssize = -1;
138556289Smckusick 		txdr_nfstime(&vap->va_atime, &sp->sa_nfsatime);
138656289Smckusick 		txdr_nfstime(&vap->va_mtime, &sp->sa_nfsmtime);
138756289Smckusick 	}
138853806Smckusick 	nfsm_request(dvp, NFSPROC_MKDIR, cnp->cn_proc, cnp->cn_cred);
138954668Smckusick 	nfsm_mtofh(dvp, *vpp);
139038414Smckusick 	nfsm_reqdone;
139153806Smckusick 	VTONFS(dvp)->n_flag |= NMODIFIED;
139240112Smckusick 	/*
139341905Smckusick 	 * Kludge: Map EEXIST => 0 assuming that you have a reply to a retry
139441905Smckusick 	 * if we can succeed in looking up the directory.
139541905Smckusick 	 * "firsttry" is necessary since the macros may "goto nfsmout" which
139641905Smckusick 	 * is above the if on errors. (Ugh)
139740112Smckusick 	 */
139841905Smckusick 	if (error == EEXIST && firsttry) {
139941905Smckusick 		firsttry = 0;
140040112Smckusick 		error = 0;
140141905Smckusick 		nfsstats.rpccnt[NFSPROC_LOOKUP]++;
140254668Smckusick 		*vpp = NULL;
140353806Smckusick 		nfsm_reqhead(dvp, NFSPROC_LOOKUP,
140441905Smckusick 		    NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len));
140553806Smckusick 		nfsm_fhtom(dvp);
140653806Smckusick 		nfsm_strtom(cnp->cn_nameptr, len, NFS_MAXNAMLEN);
140753806Smckusick 		nfsm_request(dvp, NFSPROC_LOOKUP, cnp->cn_proc, cnp->cn_cred);
140854668Smckusick 		nfsm_mtofh(dvp, *vpp);
140954668Smckusick 		if ((*vpp)->v_type != VDIR) {
141054668Smckusick 			vput(*vpp);
141141905Smckusick 			error = EEXIST;
141241905Smckusick 		}
141341905Smckusick 		m_freem(mrep);
141441905Smckusick 	}
141553806Smckusick 	FREE(cnp->cn_pnbuf, M_NAMEI);
141653806Smckusick 	vrele(dvp);
141738414Smckusick 	return (error);
141838414Smckusick }
141938414Smckusick 
142038414Smckusick /*
142138414Smckusick  * nfs remove directory call
142238414Smckusick  */
142352234Sheideman int
142453806Smckusick nfs_rmdir(ap)
142554668Smckusick 	struct vop_rmdir_args /* {
142654668Smckusick 		struct vnode *a_dvp;
142754668Smckusick 		struct vnode *a_vp;
142854668Smckusick 		struct componentname *a_cnp;
142954668Smckusick 	} */ *ap;
143038414Smckusick {
143153806Smckusick 	register struct vnode *vp = ap->a_vp;
143253806Smckusick 	register struct vnode *dvp = ap->a_dvp;
143353806Smckusick 	register struct componentname *cnp = ap->a_cnp;
143448054Smckusick 	register u_long *tl;
143539488Smckusick 	register caddr_t cp;
143652196Smckusick 	register long t2;
143739488Smckusick 	caddr_t bpos, dpos;
143839488Smckusick 	int error = 0;
143939488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
144038414Smckusick 
144153806Smckusick 	if (dvp == vp) {
144253806Smckusick 		vrele(dvp);
144353806Smckusick 		vrele(dvp);
144453806Smckusick 		FREE(cnp->cn_pnbuf, M_NAMEI);
144538414Smckusick 		return (EINVAL);
144638414Smckusick 	}
144738414Smckusick 	nfsstats.rpccnt[NFSPROC_RMDIR]++;
144853806Smckusick 	nfsm_reqhead(dvp, NFSPROC_RMDIR,
144953806Smckusick 		NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen));
145053806Smckusick 	nfsm_fhtom(dvp);
145153806Smckusick 	nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
145253806Smckusick 	nfsm_request(dvp, NFSPROC_RMDIR, cnp->cn_proc, cnp->cn_cred);
145338414Smckusick 	nfsm_reqdone;
145453806Smckusick 	FREE(cnp->cn_pnbuf, M_NAMEI);
145553806Smckusick 	VTONFS(dvp)->n_flag |= NMODIFIED;
145653806Smckusick 	cache_purge(dvp);
145753806Smckusick 	cache_purge(vp);
145853806Smckusick 	vrele(vp);
145953806Smckusick 	vrele(dvp);
146040112Smckusick 	/*
146140112Smckusick 	 * Kludge: Map ENOENT => 0 assuming that you have a reply to a retry.
146240112Smckusick 	 */
146340112Smckusick 	if (error == ENOENT)
146440112Smckusick 		error = 0;
146538414Smckusick 	return (error);
146638414Smckusick }
146738414Smckusick 
146838414Smckusick /*
146938414Smckusick  * nfs readdir call
147038414Smckusick  * Although cookie is defined as opaque, I translate it to/from net byte
147138414Smckusick  * order so that it looks more sensible. This appears consistent with the
147238414Smckusick  * Ultrix implementation of NFS.
147338414Smckusick  */
147452234Sheideman int
147553806Smckusick nfs_readdir(ap)
147654668Smckusick 	struct vop_readdir_args /* {
147754668Smckusick 		struct vnode *a_vp;
147854668Smckusick 		struct uio *a_uio;
147954668Smckusick 		struct ucred *a_cred;
148054668Smckusick 	} */ *ap;
148138414Smckusick {
148253806Smckusick 	register struct vnode *vp = ap->a_vp;
148353806Smckusick 	register struct nfsnode *np = VTONFS(vp);
148453806Smckusick 	register struct uio *uio = ap->a_uio;
148541905Smckusick 	int tresid, error;
148641905Smckusick 	struct vattr vattr;
148741905Smckusick 
148853806Smckusick 	if (vp->v_type != VDIR)
148941905Smckusick 		return (EPERM);
149041905Smckusick 	/*
149141905Smckusick 	 * First, check for hit on the EOF offset cache
149241905Smckusick 	 */
149353806Smckusick 	if (uio->uio_offset != 0 && uio->uio_offset == np->n_direofoffset &&
149452196Smckusick 	    (np->n_flag & NMODIFIED) == 0) {
149553806Smckusick 		if (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) {
149653806Smckusick 			if (NQNFS_CKCACHABLE(vp, NQL_READ)) {
149752196Smckusick 				nfsstats.direofcache_hits++;
149852196Smckusick 				return (0);
149952196Smckusick 			}
150053806Smckusick 		} else if (VOP_GETATTR(vp, &vattr, ap->a_cred, uio->uio_procp) == 0 &&
150154106Smckusick 			np->n_mtime == vattr.va_mtime.ts_sec) {
150252196Smckusick 			nfsstats.direofcache_hits++;
150352196Smckusick 			return (0);
150452196Smckusick 		}
150541905Smckusick 	}
150641905Smckusick 
150741905Smckusick 	/*
150841905Smckusick 	 * Call nfs_bioread() to do the real work.
150941905Smckusick 	 */
151053806Smckusick 	tresid = uio->uio_resid;
151153806Smckusick 	error = nfs_bioread(vp, uio, 0, ap->a_cred);
151241905Smckusick 
151354451Smckusick 	if (!error && uio->uio_resid == tresid)
151441905Smckusick 		nfsstats.direofcache_misses++;
151541905Smckusick 	return (error);
151641905Smckusick }
151741905Smckusick 
151841905Smckusick /*
151941905Smckusick  * Readdir rpc call.
152041905Smckusick  * Called from below the buffer cache by nfs_doio().
152141905Smckusick  */
152252234Sheideman int
152348054Smckusick nfs_readdirrpc(vp, uiop, cred)
152441905Smckusick 	register struct vnode *vp;
152541905Smckusick 	struct uio *uiop;
152641905Smckusick 	struct ucred *cred;
152741905Smckusick {
152838414Smckusick 	register long len;
152954740Smckusick 	register struct dirent *dp;
153048054Smckusick 	register u_long *tl;
153139488Smckusick 	register caddr_t cp;
153239488Smckusick 	register long t1;
153341905Smckusick 	long tlen, lastlen;
153439488Smckusick 	caddr_t bpos, dpos, cp2;
153539488Smckusick 	int error = 0;
153639488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
153738414Smckusick 	struct mbuf *md2;
153838414Smckusick 	caddr_t dpos2;
153938414Smckusick 	int siz;
154040296Smckusick 	int more_dirs = 1;
154156289Smckusick 	u_long off, savoff;
154254740Smckusick 	struct dirent *savdp;
154340296Smckusick 	struct nfsmount *nmp;
154440296Smckusick 	struct nfsnode *np = VTONFS(vp);
154540296Smckusick 	long tresid;
154638414Smckusick 
154741398Smckusick 	nmp = VFSTONFS(vp->v_mount);
154840296Smckusick 	tresid = uiop->uio_resid;
154940296Smckusick 	/*
155040296Smckusick 	 * Loop around doing readdir rpc's of size uio_resid or nm_rsize,
155148054Smckusick 	 * whichever is smaller, truncated to a multiple of NFS_DIRBLKSIZ.
155241905Smckusick 	 * The stopping criteria is EOF or buffer full.
155340296Smckusick 	 */
155448054Smckusick 	while (more_dirs && uiop->uio_resid >= NFS_DIRBLKSIZ) {
155540296Smckusick 		nfsstats.rpccnt[NFSPROC_READDIR]++;
155652196Smckusick 		nfsm_reqhead(vp, NFSPROC_READDIR,
155756289Smckusick 			NFSX_FH + 2 * NFSX_UNSIGNED);
155840296Smckusick 		nfsm_fhtom(vp);
155956289Smckusick 		nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED);
156056289Smckusick 		off = (u_long)uiop->uio_offset;
156156289Smckusick 		*tl++ = txdr_unsigned(off);
156248054Smckusick 		*tl = txdr_unsigned(((uiop->uio_resid > nmp->nm_rsize) ?
156348054Smckusick 			nmp->nm_rsize : uiop->uio_resid) & ~(NFS_DIRBLKSIZ-1));
156452196Smckusick 		nfsm_request(vp, NFSPROC_READDIR, uiop->uio_procp, cred);
156540296Smckusick 		siz = 0;
156652196Smckusick 		nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
156748054Smckusick 		more_dirs = fxdr_unsigned(int, *tl);
156840296Smckusick 
156940296Smckusick 		/* Save the position so that we can do nfsm_mtouio() later */
157040296Smckusick 		dpos2 = dpos;
157140296Smckusick 		md2 = md;
157240296Smckusick 
157340296Smckusick 		/* loop thru the dir entries, doctoring them to 4bsd form */
157442246Smckusick #ifdef lint
157554740Smckusick 		dp = (struct dirent *)0;
157642246Smckusick #endif /* lint */
157740296Smckusick 		while (more_dirs && siz < uiop->uio_resid) {
157840296Smckusick 			savoff = off;		/* Hold onto offset and dp */
157940296Smckusick 			savdp = dp;
158056289Smckusick 			nfsm_dissecton(tl, u_long *, 2 * NFSX_UNSIGNED);
158154740Smckusick 			dp = (struct dirent *)tl;
158254740Smckusick 			dp->d_fileno = fxdr_unsigned(u_long, *tl++);
158348054Smckusick 			len = fxdr_unsigned(int, *tl);
158440296Smckusick 			if (len <= 0 || len > NFS_MAXNAMLEN) {
158540296Smckusick 				error = EBADRPC;
158640296Smckusick 				m_freem(mrep);
158740296Smckusick 				goto nfsmout;
158840296Smckusick 			}
158954986Smckusick 			dp->d_namlen = (u_char)len;
159054986Smckusick 			dp->d_type = DT_UNKNOWN;
159140296Smckusick 			nfsm_adv(len);		/* Point past name */
159240296Smckusick 			tlen = nfsm_rndup(len);
159340296Smckusick 			/*
159440296Smckusick 			 * This should not be necessary, but some servers have
159540296Smckusick 			 * broken XDR such that these bytes are not null filled.
159640296Smckusick 			 */
159740296Smckusick 			if (tlen != len) {
159840296Smckusick 				*dpos = '\0';	/* Null-terminate */
159940296Smckusick 				nfsm_adv(tlen - len);
160040296Smckusick 				len = tlen;
160140296Smckusick 			}
160256289Smckusick 			nfsm_dissecton(tl, u_long *, 2 * NFSX_UNSIGNED);
160354986Smckusick 			off = fxdr_unsigned(u_long, *tl);
160448054Smckusick 			*tl++ = 0;	/* Ensures null termination of name */
160548054Smckusick 			more_dirs = fxdr_unsigned(int, *tl);
160656289Smckusick 			dp->d_reclen = len + 4 * NFSX_UNSIGNED;
160740296Smckusick 			siz += dp->d_reclen;
160840296Smckusick 		}
160940296Smckusick 		/*
161040296Smckusick 		 * If at end of rpc data, get the eof boolean
161140296Smckusick 		 */
161240296Smckusick 		if (!more_dirs) {
161352196Smckusick 			nfsm_dissecton(tl, u_long *, NFSX_UNSIGNED);
161448054Smckusick 			more_dirs = (fxdr_unsigned(int, *tl) == 0);
161538414Smckusick 
161640296Smckusick 			/*
161740296Smckusick 			 * If at EOF, cache directory offset
161840296Smckusick 			 */
161941905Smckusick 			if (!more_dirs)
162040296Smckusick 				np->n_direofoffset = off;
162138414Smckusick 		}
162240296Smckusick 		/*
162340296Smckusick 		 * If there is too much to fit in the data buffer, use savoff and
162440296Smckusick 		 * savdp to trim off the last record.
162540296Smckusick 		 * --> we are not at eof
162640296Smckusick 		 */
162740296Smckusick 		if (siz > uiop->uio_resid) {
162840296Smckusick 			off = savoff;
162940296Smckusick 			siz -= dp->d_reclen;
163040296Smckusick 			dp = savdp;
163140296Smckusick 			more_dirs = 0;	/* Paranoia */
163240113Smckusick 		}
163340296Smckusick 		if (siz > 0) {
163441905Smckusick 			lastlen = dp->d_reclen;
163540296Smckusick 			md = md2;
163640296Smckusick 			dpos = dpos2;
163740296Smckusick 			nfsm_mtouio(uiop, siz);
163856289Smckusick 			uiop->uio_offset = (off_t)off;
163940296Smckusick 		} else
164040296Smckusick 			more_dirs = 0;	/* Ugh, never happens, but in case.. */
164140296Smckusick 		m_freem(mrep);
164238414Smckusick 	}
164341905Smckusick 	/*
164448054Smckusick 	 * Fill last record, iff any, out to a multiple of NFS_DIRBLKSIZ
164541905Smckusick 	 * by increasing d_reclen for the last record.
164641905Smckusick 	 */
164741905Smckusick 	if (uiop->uio_resid < tresid) {
164848054Smckusick 		len = uiop->uio_resid & (NFS_DIRBLKSIZ - 1);
164941905Smckusick 		if (len > 0) {
165054740Smckusick 			dp = (struct dirent *)
165141905Smckusick 				(uiop->uio_iov->iov_base - lastlen);
165241905Smckusick 			dp->d_reclen += len;
165341905Smckusick 			uiop->uio_iov->iov_base += len;
165441905Smckusick 			uiop->uio_iov->iov_len -= len;
165541905Smckusick 			uiop->uio_resid -= len;
165641905Smckusick 		}
165741905Smckusick 	}
165840296Smckusick nfsmout:
165938414Smckusick 	return (error);
166038414Smckusick }
166138414Smckusick 
166252196Smckusick /*
166356289Smckusick  * Nqnfs readdir_and_lookup RPC. Used in place of nfs_readdirrpc().
166452196Smckusick  */
166552234Sheideman int
166652196Smckusick nfs_readdirlookrpc(vp, uiop, cred)
166752196Smckusick 	struct vnode *vp;
166852196Smckusick 	register struct uio *uiop;
166952196Smckusick 	struct ucred *cred;
167052196Smckusick {
167152196Smckusick 	register int len;
167254740Smckusick 	register struct dirent *dp;
167352196Smckusick 	register u_long *tl;
167452196Smckusick 	register caddr_t cp;
167552196Smckusick 	register long t1;
167652196Smckusick 	caddr_t bpos, dpos, cp2;
167752196Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
167852196Smckusick 	struct nameidata nami, *ndp = &nami;
167952317Sheideman 	struct componentname *cnp = &ndp->ni_cnd;
168056289Smckusick 	u_long off, endoff, fileno;
168152196Smckusick 	time_t reqtime, ltime;
168252196Smckusick 	struct nfsmount *nmp;
168352196Smckusick 	struct nfsnode *np, *tp;
168452196Smckusick 	struct vnode *newvp;
168552196Smckusick 	nfsv2fh_t *fhp;
168652196Smckusick 	u_quad_t frev;
168752196Smckusick 	int error = 0, tlen, more_dirs = 1, tresid, doit, bigenough, i;
168852196Smckusick 	int cachable;
168952196Smckusick 
169052196Smckusick 	if (uiop->uio_iovcnt != 1)
169152196Smckusick 		panic("nfs rdirlook");
169252196Smckusick 	nmp = VFSTONFS(vp->v_mount);
169352196Smckusick 	tresid = uiop->uio_resid;
169452196Smckusick 	ndp->ni_dvp = vp;
169552196Smckusick 	newvp = NULLVP;
169652196Smckusick 	/*
169752196Smckusick 	 * Loop around doing readdir rpc's of size uio_resid or nm_rsize,
169852196Smckusick 	 * whichever is smaller, truncated to a multiple of NFS_DIRBLKSIZ.
169952196Smckusick 	 * The stopping criteria is EOF or buffer full.
170052196Smckusick 	 */
170152196Smckusick 	while (more_dirs && uiop->uio_resid >= NFS_DIRBLKSIZ) {
170252196Smckusick 		nfsstats.rpccnt[NQNFSPROC_READDIRLOOK]++;
170352196Smckusick 		nfsm_reqhead(vp, NQNFSPROC_READDIRLOOK,
170456289Smckusick 			NFSX_FH + 3 * NFSX_UNSIGNED);
170552196Smckusick 		nfsm_fhtom(vp);
170656289Smckusick  		nfsm_build(tl, u_long *, 3 * NFSX_UNSIGNED);
170756289Smckusick 		off = (u_long)uiop->uio_offset;
170856289Smckusick 		*tl++ = txdr_unsigned(off);
170952196Smckusick 		*tl++ = txdr_unsigned(((uiop->uio_resid > nmp->nm_rsize) ?
171052196Smckusick 			nmp->nm_rsize : uiop->uio_resid) & ~(NFS_DIRBLKSIZ-1));
171156289Smckusick 		if (nmp->nm_flag & NFSMNT_NQLOOKLEASE)
171256289Smckusick 			*tl = txdr_unsigned(nmp->nm_leaseterm);
171356289Smckusick 		else
171456289Smckusick 			*tl = 0;
171552196Smckusick 		reqtime = time.tv_sec;
171652196Smckusick 		nfsm_request(vp, NQNFSPROC_READDIRLOOK, uiop->uio_procp, cred);
171752196Smckusick 		nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
171852196Smckusick 		more_dirs = fxdr_unsigned(int, *tl);
171952196Smckusick 
172052196Smckusick 		/* loop thru the dir entries, doctoring them to 4bsd form */
172152196Smckusick 		bigenough = 1;
172252196Smckusick 		while (more_dirs && bigenough) {
172352196Smckusick 			doit = 1;
172456289Smckusick 			nfsm_dissect(tl, u_long *, 4 * NFSX_UNSIGNED);
172556289Smckusick 			if (nmp->nm_flag & NFSMNT_NQLOOKLEASE) {
172656289Smckusick 				cachable = fxdr_unsigned(int, *tl++);
172756289Smckusick 				ltime = reqtime + fxdr_unsigned(int, *tl++);
172856289Smckusick 				fxdr_hyper(tl, &frev);
172956289Smckusick 			}
173052196Smckusick 			nfsm_dissect(fhp, nfsv2fh_t *, NFSX_FH);
173152196Smckusick 			if (!bcmp(VTONFS(vp)->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) {
173252196Smckusick 				VREF(vp);
173352196Smckusick 				newvp = vp;
173452196Smckusick 				np = VTONFS(vp);
173552196Smckusick 			} else {
173652196Smckusick 				if (error = nfs_nget(vp->v_mount, fhp, &np))
173752196Smckusick 					doit = 0;
173852196Smckusick 				newvp = NFSTOV(np);
173952196Smckusick 			}
174052196Smckusick 			if (error = nfs_loadattrcache(&newvp, &md, &dpos,
174152196Smckusick 				(struct vattr *)0))
174252196Smckusick 				doit = 0;
174356289Smckusick 			nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
174452196Smckusick 			fileno = fxdr_unsigned(u_long, *tl++);
174552196Smckusick 			len = fxdr_unsigned(int, *tl);
174652196Smckusick 			if (len <= 0 || len > NFS_MAXNAMLEN) {
174752196Smckusick 				error = EBADRPC;
174852196Smckusick 				m_freem(mrep);
174952196Smckusick 				goto nfsmout;
175052196Smckusick 			}
175152196Smckusick 			tlen = (len + 4) & ~0x3;
175252196Smckusick 			if ((tlen + DIRHDSIZ) > uiop->uio_resid)
175352196Smckusick 				bigenough = 0;
175452196Smckusick 			if (bigenough && doit) {
175554740Smckusick 				dp = (struct dirent *)uiop->uio_iov->iov_base;
175654740Smckusick 				dp->d_fileno = fileno;
175752196Smckusick 				dp->d_namlen = len;
175852196Smckusick 				dp->d_reclen = tlen + DIRHDSIZ;
175954986Smckusick 				dp->d_type =
176054986Smckusick 				    IFTODT(VTTOIF(np->n_vattr.va_type));
176152196Smckusick 				uiop->uio_resid -= DIRHDSIZ;
176252196Smckusick 				uiop->uio_iov->iov_base += DIRHDSIZ;
176352196Smckusick 				uiop->uio_iov->iov_len -= DIRHDSIZ;
176452317Sheideman 				cnp->cn_nameptr = uiop->uio_iov->iov_base;
176552317Sheideman 				cnp->cn_namelen = len;
176652196Smckusick 				ndp->ni_vp = newvp;
176752196Smckusick 				nfsm_mtouio(uiop, len);
176852196Smckusick 				cp = uiop->uio_iov->iov_base;
176952196Smckusick 				tlen -= len;
177052196Smckusick 				for (i = 0; i < tlen; i++)
177152196Smckusick 					*cp++ = '\0';
177252196Smckusick 				uiop->uio_iov->iov_base += tlen;
177352196Smckusick 				uiop->uio_iov->iov_len -= tlen;
177452196Smckusick 				uiop->uio_resid -= tlen;
177552317Sheideman 				cnp->cn_hash = 0;
177652317Sheideman 				for (cp = cnp->cn_nameptr, i = 1; i <= len; i++, cp++)
177752317Sheideman 					cnp->cn_hash += (unsigned char)*cp * i;
177856289Smckusick 				if ((nmp->nm_flag & NFSMNT_NQLOOKLEASE) &&
177956289Smckusick 					ltime > time.tv_sec)
178056289Smckusick 					nqnfs_clientlease(nmp, np, NQL_READ,
178156289Smckusick 						cachable, ltime, frev);
178256927Smckusick 				if (cnp->cn_namelen <= NCHNAMLEN)
1783*57791Smckusick 				    cache_enter(ndp->ni_dvp, ndp->ni_vp, cnp);
178452196Smckusick 			} else {
178552196Smckusick 				nfsm_adv(nfsm_rndup(len));
178652196Smckusick 			}
178752196Smckusick 			if (newvp != NULLVP) {
178852196Smckusick 				vrele(newvp);
178952196Smckusick 				newvp = NULLVP;
179052196Smckusick 			}
179156289Smckusick 			nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
179252196Smckusick 			if (bigenough)
179356289Smckusick 				endoff = off = fxdr_unsigned(u_long, *tl++);
179452196Smckusick 			else
179556289Smckusick 				endoff = fxdr_unsigned(u_long, *tl++);
179652196Smckusick 			more_dirs = fxdr_unsigned(int, *tl);
179752196Smckusick 		}
179852196Smckusick 		/*
179952196Smckusick 		 * If at end of rpc data, get the eof boolean
180052196Smckusick 		 */
180152196Smckusick 		if (!more_dirs) {
180252196Smckusick 			nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
180352196Smckusick 			more_dirs = (fxdr_unsigned(int, *tl) == 0);
180452196Smckusick 
180552196Smckusick 			/*
180652196Smckusick 			 * If at EOF, cache directory offset
180752196Smckusick 			 */
180852196Smckusick 			if (!more_dirs)
180952196Smckusick 				VTONFS(vp)->n_direofoffset = endoff;
181052196Smckusick 		}
181152196Smckusick 		if (uiop->uio_resid < tresid)
181256289Smckusick 			uiop->uio_offset = (off_t)off;
181352196Smckusick 		else
181452196Smckusick 			more_dirs = 0;
181552196Smckusick 		m_freem(mrep);
181652196Smckusick 	}
181752196Smckusick 	/*
181852196Smckusick 	 * Fill last record, iff any, out to a multiple of NFS_DIRBLKSIZ
181952196Smckusick 	 * by increasing d_reclen for the last record.
182052196Smckusick 	 */
182152196Smckusick 	if (uiop->uio_resid < tresid) {
182252196Smckusick 		len = uiop->uio_resid & (NFS_DIRBLKSIZ - 1);
182352196Smckusick 		if (len > 0) {
182452196Smckusick 			dp->d_reclen += len;
182552196Smckusick 			uiop->uio_iov->iov_base += len;
182652196Smckusick 			uiop->uio_iov->iov_len -= len;
182752196Smckusick 			uiop->uio_resid -= len;
182852196Smckusick 		}
182952196Smckusick 	}
183052196Smckusick nfsmout:
183152196Smckusick 	if (newvp != NULLVP)
183252196Smckusick 		vrele(newvp);
183352196Smckusick 	return (error);
183452196Smckusick }
183539488Smckusick static char hextoasc[] = "0123456789abcdef";
183638414Smckusick 
183738414Smckusick /*
183838414Smckusick  * Silly rename. To make the NFS filesystem that is stateless look a little
183938414Smckusick  * more like the "ufs" a remove of an active vnode is translated to a rename
184038414Smckusick  * to a funny looking filename that is removed by nfs_inactive on the
184138414Smckusick  * nfsnode. There is the potential for another process on a different client
184238414Smckusick  * to create the same funny name between the nfs_lookitup() fails and the
184338414Smckusick  * nfs_rename() completes, but...
184438414Smckusick  */
184552234Sheideman int
184652317Sheideman nfs_sillyrename(dvp, vp, cnp)
184752234Sheideman 	struct vnode *dvp, *vp;
184852234Sheideman 	struct componentname *cnp;
184938414Smckusick {
185038414Smckusick 	register struct nfsnode *np;
185138414Smckusick 	register struct sillyrename *sp;
185238414Smckusick 	int error;
185338414Smckusick 	short pid;
185438414Smckusick 
185552234Sheideman 	cache_purge(dvp);
185652234Sheideman 	np = VTONFS(vp);
185751986Smckusick #ifdef SILLYSEPARATE
185838414Smckusick 	MALLOC(sp, struct sillyrename *, sizeof (struct sillyrename),
185948364Smckusick 		M_NFSREQ, M_WAITOK);
186051986Smckusick #else
186151986Smckusick 	sp = &np->n_silly;
186251986Smckusick #endif
186352234Sheideman 	sp->s_cred = crdup(cnp->cn_cred);
186452234Sheideman 	sp->s_dvp = dvp;
186552234Sheideman 	VREF(dvp);
186638414Smckusick 
186738414Smckusick 	/* Fudge together a funny name */
186852234Sheideman 	pid = cnp->cn_proc->p_pid;
186948364Smckusick 	bcopy(".nfsAxxxx4.4", sp->s_name, 13);
187048364Smckusick 	sp->s_namlen = 12;
187148364Smckusick 	sp->s_name[8] = hextoasc[pid & 0xf];
187248364Smckusick 	sp->s_name[7] = hextoasc[(pid >> 4) & 0xf];
187348364Smckusick 	sp->s_name[6] = hextoasc[(pid >> 8) & 0xf];
187448364Smckusick 	sp->s_name[5] = hextoasc[(pid >> 12) & 0xf];
187538414Smckusick 
187638414Smckusick 	/* Try lookitups until we get one that isn't there */
187752234Sheideman 	while (nfs_lookitup(sp, (nfsv2fh_t *)0, cnp->cn_proc) == 0) {
187848364Smckusick 		sp->s_name[4]++;
187948364Smckusick 		if (sp->s_name[4] > 'z') {
188038414Smckusick 			error = EINVAL;
188138414Smckusick 			goto bad;
188238414Smckusick 		}
188338414Smckusick 	}
188452234Sheideman 	if (error = nfs_renameit(dvp, cnp, sp))
188538414Smckusick 		goto bad;
188652234Sheideman 	nfs_lookitup(sp, &np->n_fh, cnp->cn_proc);
188738414Smckusick 	np->n_sillyrename = sp;
188838414Smckusick 	return (0);
188938414Smckusick bad:
189048364Smckusick 	vrele(sp->s_dvp);
189148364Smckusick 	crfree(sp->s_cred);
189251986Smckusick #ifdef SILLYSEPARATE
189348364Smckusick 	free((caddr_t)sp, M_NFSREQ);
189451986Smckusick #endif
189538414Smckusick 	return (error);
189638414Smckusick }
189738414Smckusick 
189838414Smckusick /*
189938414Smckusick  * Look up a file name for silly rename stuff.
190038414Smckusick  * Just like nfs_lookup() except that it doesn't load returned values
190138414Smckusick  * into the nfsnode table.
190238414Smckusick  * If fhp != NULL it copies the returned file handle out
190338414Smckusick  */
190452234Sheideman int
190552196Smckusick nfs_lookitup(sp, fhp, procp)
190648364Smckusick 	register struct sillyrename *sp;
190738414Smckusick 	nfsv2fh_t *fhp;
190852196Smckusick 	struct proc *procp;
190938414Smckusick {
191048364Smckusick 	register struct vnode *vp = sp->s_dvp;
191148054Smckusick 	register u_long *tl;
191239488Smckusick 	register caddr_t cp;
191339488Smckusick 	register long t1, t2;
191439488Smckusick 	caddr_t bpos, dpos, cp2;
191539488Smckusick 	u_long xid;
191656289Smckusick 	int error = 0, isnq;
191739488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
191838414Smckusick 	long len;
191938414Smckusick 
192056289Smckusick 	isnq = (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS);
192138414Smckusick 	nfsstats.rpccnt[NFSPROC_LOOKUP]++;
192248364Smckusick 	len = sp->s_namlen;
192352196Smckusick 	nfsm_reqhead(vp, NFSPROC_LOOKUP, NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len));
192456289Smckusick 	if (isnq) {
192556289Smckusick 		nfsm_build(tl, u_long *, NFSX_UNSIGNED);
192656289Smckusick 		*tl = 0;
192756289Smckusick 	}
192838414Smckusick 	nfsm_fhtom(vp);
192948364Smckusick 	nfsm_strtom(sp->s_name, len, NFS_MAXNAMLEN);
193052196Smckusick 	nfsm_request(vp, NFSPROC_LOOKUP, procp, sp->s_cred);
193138414Smckusick 	if (fhp != NULL) {
193256289Smckusick 		if (isnq)
193356289Smckusick 			nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
193452196Smckusick 		nfsm_dissect(cp, caddr_t, NFSX_FH);
193538414Smckusick 		bcopy(cp, (caddr_t)fhp, NFSX_FH);
193638414Smckusick 	}
193738414Smckusick 	nfsm_reqdone;
193838414Smckusick 	return (error);
193938414Smckusick }
194038414Smckusick 
194138414Smckusick /*
194238414Smckusick  * Kludge City..
194338414Smckusick  * - make nfs_bmap() essentially a no-op that does no translation
194441905Smckusick  * - do nfs_strategy() by faking physical I/O with nfs_readrpc/nfs_writerpc
194538414Smckusick  *   after mapping the physical addresses into Kernel Virtual space in the
194638414Smckusick  *   nfsiobuf area.
194738414Smckusick  *   (Maybe I could use the process's page mapping, but I was concerned that
194838414Smckusick  *    Kernel Write might not be enabled and also figured copyout() would do
194938414Smckusick  *    a lot more work than bcopy() and also it currently happens in the
195038414Smckusick  *    context of the swapper process (2).
195138414Smckusick  */
195252234Sheideman int
195353806Smckusick nfs_bmap(ap)
195454668Smckusick 	struct vop_bmap_args /* {
195554668Smckusick 		struct vnode *a_vp;
195654668Smckusick 		daddr_t  a_bn;
195754668Smckusick 		struct vnode **a_vpp;
195854668Smckusick 		daddr_t *a_bnp;
195956452Smargo 		int *a_runp;
196054668Smckusick 	} */ *ap;
196138414Smckusick {
196253806Smckusick 	register struct vnode *vp = ap->a_vp;
196353806Smckusick 
196453600Sheideman 	if (ap->a_vpp != NULL)
196553806Smckusick 		*ap->a_vpp = vp;
196653600Sheideman 	if (ap->a_bnp != NULL)
196753806Smckusick 		*ap->a_bnp = ap->a_bn * btodb(vp->v_mount->mnt_stat.f_iosize);
196838414Smckusick 	return (0);
196938414Smckusick }
197038414Smckusick 
197138414Smckusick /*
1972*57791Smckusick  * Strategy routine.
1973*57791Smckusick  * For async requests when nfsiod(s) are running, queue the request by
1974*57791Smckusick  * calling nfs_asyncio(), otherwise just all nfs_doio() to do the
1975*57791Smckusick  * request.
197638414Smckusick  */
197752234Sheideman int
197853806Smckusick nfs_strategy(ap)
1979*57791Smckusick 	struct vop_strategy_args *ap;
198038414Smckusick {
198153806Smckusick 	register struct buf *bp = ap->a_bp;
1982*57791Smckusick 	struct ucred *cr;
1983*57791Smckusick 	struct proc *p;
198438884Smacklem 	int error = 0;
198538884Smacklem 
1986*57791Smckusick 	if (bp->b_flags & B_PHYS)
1987*57791Smckusick 		panic("nfs physio");
1988*57791Smckusick 	if (bp->b_flags & B_ASYNC)
1989*57791Smckusick 		p = (struct proc *)0;
1990*57791Smckusick 	else
1991*57791Smckusick 		p = curproc;	/* XXX */
1992*57791Smckusick 	if (bp->b_flags & B_READ)
1993*57791Smckusick 		cr = bp->b_rcred;
1994*57791Smckusick 	else
1995*57791Smckusick 		cr = bp->b_wcred;
199638884Smacklem 	/*
199746450Skarels 	 * If the op is asynchronous and an i/o daemon is waiting
199838884Smacklem 	 * queue the request, wake it up and wait for completion
199946450Skarels 	 * otherwise just do it ourselves.
200038884Smacklem 	 */
2001*57791Smckusick 	if ((bp->b_flags & B_ASYNC) == 0 ||
2002*57791Smckusick 		nfs_asyncio(bp, NOCRED))
2003*57791Smckusick 		error = nfs_doio(bp, cr, p);
200438884Smacklem 	return (error);
200538884Smacklem }
200638884Smacklem 
200738884Smacklem /*
200848054Smckusick  * Mmap a file
200948054Smckusick  *
201048054Smckusick  * NB Currently unsupported.
201148054Smckusick  */
201248054Smckusick /* ARGSUSED */
201352234Sheideman int
201453806Smckusick nfs_mmap(ap)
201554668Smckusick 	struct vop_mmap_args /* {
201654668Smckusick 		struct vnode *a_vp;
201754668Smckusick 		int  a_fflags;
201854668Smckusick 		struct ucred *a_cred;
201954668Smckusick 		struct proc *a_p;
202054668Smckusick 	} */ *ap;
202148054Smckusick {
202248054Smckusick 
202348054Smckusick 	return (EINVAL);
202448054Smckusick }
202548054Smckusick 
202648054Smckusick /*
202738884Smacklem  * Flush all the blocks associated with a vnode.
202838884Smacklem  * 	Walk through the buffer pool and push any dirty pages
202938884Smacklem  *	associated with the vnode.
203038884Smacklem  */
203139488Smckusick /* ARGSUSED */
203252234Sheideman int
203353806Smckusick nfs_fsync(ap)
203454451Smckusick 	struct vop_fsync_args /* {
203554451Smckusick 		struct vnodeop_desc *a_desc;
203654451Smckusick 		struct vnode * a_vp;
203754451Smckusick 		struct ucred * a_cred;
203854451Smckusick 		int  a_waitfor;
203954451Smckusick 		struct proc * a_p;
204054451Smckusick 	} */ *ap;
204138884Smacklem {
204254451Smckusick 	register struct vnode *vp = ap->a_vp;
204354451Smckusick 	register struct nfsnode *np = VTONFS(vp);
204454451Smckusick 	register struct buf *bp;
204554451Smckusick 	struct buf *nbp;
2046*57791Smckusick 	struct nfsmount *nmp;
2047*57791Smckusick 	int s, error = 0, slptimeo = 0, slpflag = 0;
204838884Smacklem 
2049*57791Smckusick 	nmp = VFSTONFS(vp->v_mount);
2050*57791Smckusick 	if (nmp->nm_flag & NFSMNT_INT)
2051*57791Smckusick 		slpflag = PCATCH;
205254451Smckusick loop:
205354451Smckusick 	s = splbio();
205456468Smckusick 	for (bp = vp->v_dirtyblkhd.le_next; bp; bp = nbp) {
205556468Smckusick 		nbp = bp->b_vnbufs.qe_next;
2056*57791Smckusick 		if (bp->b_flags & B_BUSY) {
2057*57791Smckusick 			if (ap->a_waitfor != MNT_WAIT)
2058*57791Smckusick 				continue;
2059*57791Smckusick 			bp->b_flags |= B_WANTED;
2060*57791Smckusick 			error = tsleep((caddr_t)bp, slpflag | (PRIBIO + 1),
2061*57791Smckusick 				"nfsfsync", slptimeo);
2062*57791Smckusick 			splx(s);
2063*57791Smckusick 			if (error) {
2064*57791Smckusick 			    if (nfs_sigintr(nmp, (struct nfsreq *)0, ap->a_p))
2065*57791Smckusick 				return (EINTR);
2066*57791Smckusick 			    if (slpflag == PCATCH) {
2067*57791Smckusick 				slpflag = 0;
2068*57791Smckusick 				slptimeo = 2 * hz;
2069*57791Smckusick 			    }
2070*57791Smckusick 			}
2071*57791Smckusick 			goto loop;
2072*57791Smckusick 		}
207354451Smckusick 		if ((bp->b_flags & B_DELWRI) == 0)
207454451Smckusick 			panic("nfs_fsync: not dirty");
207554451Smckusick 		bremfree(bp);
207654451Smckusick 		bp->b_flags |= B_BUSY;
207754451Smckusick 		splx(s);
2078*57791Smckusick 		bp->b_flags |= B_ASYNC;
2079*57791Smckusick 		VOP_BWRITE(bp);
208054451Smckusick 		goto loop;
208138884Smacklem 	}
2082*57791Smckusick 	splx(s);
208354451Smckusick 	if (ap->a_waitfor == MNT_WAIT) {
208454451Smckusick 		while (vp->v_numoutput) {
208554451Smckusick 			vp->v_flag |= VBWAIT;
2086*57791Smckusick 			error = tsleep((caddr_t)&vp->v_numoutput,
2087*57791Smckusick 				slpflag | (PRIBIO + 1), "nfsfsync", slptimeo);
2088*57791Smckusick 			if (error) {
2089*57791Smckusick 			    if (nfs_sigintr(nmp, (struct nfsreq *)0, ap->a_p))
2090*57791Smckusick 				return (EINTR);
2091*57791Smckusick 			    if (slpflag == PCATCH) {
2092*57791Smckusick 				slpflag = 0;
2093*57791Smckusick 				slptimeo = 2 * hz;
2094*57791Smckusick 			    }
2095*57791Smckusick 			}
209654451Smckusick 		}
2097*57791Smckusick 		if (vp->v_dirtyblkhd.le_next) {
209854451Smckusick #ifdef DIAGNOSTIC
209954451Smckusick 			vprint("nfs_fsync: dirty", vp);
2100*57791Smckusick #endif
210154451Smckusick 			goto loop;
210254451Smckusick 		}
210354451Smckusick 	}
210453629Smckusick 	if (np->n_flag & NWRITEERR) {
210539751Smckusick 		error = np->n_error;
210653629Smckusick 		np->n_flag &= ~NWRITEERR;
210753629Smckusick 	}
210838884Smacklem 	return (error);
210938884Smacklem }
211039672Smckusick 
211139672Smckusick /*
211246201Smckusick  * NFS advisory byte-level locks.
211346201Smckusick  * Currently unsupported.
211446201Smckusick  */
211552234Sheideman int
211653806Smckusick nfs_advlock(ap)
211754668Smckusick 	struct vop_advlock_args /* {
211854668Smckusick 		struct vnode *a_vp;
211954668Smckusick 		caddr_t  a_id;
212054668Smckusick 		int  a_op;
212154668Smckusick 		struct flock *a_fl;
212254668Smckusick 		int  a_flags;
212354668Smckusick 	} */ *ap;
212446201Smckusick {
212546201Smckusick 
212646201Smckusick 	return (EOPNOTSUPP);
212746201Smckusick }
212846201Smckusick 
212946201Smckusick /*
213039672Smckusick  * Print out the contents of an nfsnode.
213139672Smckusick  */
213252234Sheideman int
213353806Smckusick nfs_print(ap)
213454668Smckusick 	struct vop_print_args /* {
213554668Smckusick 		struct vnode *a_vp;
213654668Smckusick 	} */ *ap;
213739672Smckusick {
213853806Smckusick 	register struct vnode *vp = ap->a_vp;
213953806Smckusick 	register struct nfsnode *np = VTONFS(vp);
214039672Smckusick 
214140294Smckusick 	printf("tag VT_NFS, fileid %d fsid 0x%x",
214240294Smckusick 		np->n_vattr.va_fileid, np->n_vattr.va_fsid);
214340294Smckusick #ifdef FIFO
214453806Smckusick 	if (vp->v_type == VFIFO)
214553806Smckusick 		fifo_printinfo(vp);
214640294Smckusick #endif /* FIFO */
214739914Smckusick 	printf("\n");
214839672Smckusick }
214951573Smckusick 
215051573Smckusick /*
215151573Smckusick  * NFS directory offset lookup.
215251573Smckusick  * Currently unsupported.
215351573Smckusick  */
215452234Sheideman int
215553806Smckusick nfs_blkatoff(ap)
215654668Smckusick 	struct vop_blkatoff_args /* {
215754668Smckusick 		struct vnode *a_vp;
215854668Smckusick 		off_t a_offset;
215954668Smckusick 		char **a_res;
216054668Smckusick 		struct buf **a_bpp;
216154668Smckusick 	} */ *ap;
216251573Smckusick {
216351573Smckusick 
216451573Smckusick 	return (EOPNOTSUPP);
216551573Smckusick }
216651573Smckusick 
216751573Smckusick /*
216851573Smckusick  * NFS flat namespace allocation.
216951573Smckusick  * Currently unsupported.
217051573Smckusick  */
217152234Sheideman int
217253806Smckusick nfs_valloc(ap)
217354668Smckusick 	struct vop_valloc_args /* {
217454668Smckusick 		struct vnode *a_pvp;
217554668Smckusick 		int a_mode;
217654668Smckusick 		struct ucred *a_cred;
217754668Smckusick 		struct vnode **a_vpp;
217854668Smckusick 	} */ *ap;
217951573Smckusick {
218051573Smckusick 
218151573Smckusick 	return (EOPNOTSUPP);
218251573Smckusick }
218351573Smckusick 
218451573Smckusick /*
218551573Smckusick  * NFS flat namespace free.
218651573Smckusick  * Currently unsupported.
218751573Smckusick  */
218853582Sheideman int
218953806Smckusick nfs_vfree(ap)
219054668Smckusick 	struct vop_vfree_args /* {
219154668Smckusick 		struct vnode *a_pvp;
219254668Smckusick 		ino_t a_ino;
219354668Smckusick 		int a_mode;
219454668Smckusick 	} */ *ap;
219551573Smckusick {
219651573Smckusick 
219753582Sheideman 	return (EOPNOTSUPP);
219851573Smckusick }
219951573Smckusick 
220051573Smckusick /*
220151573Smckusick  * NFS file truncation.
220251573Smckusick  */
220352234Sheideman int
220453806Smckusick nfs_truncate(ap)
220554668Smckusick 	struct vop_truncate_args /* {
220654668Smckusick 		struct vnode *a_vp;
220754668Smckusick 		off_t a_length;
220854668Smckusick 		int a_flags;
220954668Smckusick 		struct ucred *a_cred;
221054668Smckusick 		struct proc *a_p;
221154668Smckusick 	} */ *ap;
221251573Smckusick {
221351573Smckusick 
221451573Smckusick 	/* Use nfs_setattr */
221551573Smckusick 	printf("nfs_truncate: need to implement!!");
221651573Smckusick 	return (EOPNOTSUPP);
221751573Smckusick }
221851573Smckusick 
221951573Smckusick /*
222051573Smckusick  * NFS update.
222151573Smckusick  */
222252234Sheideman int
222353806Smckusick nfs_update(ap)
222454668Smckusick 	struct vop_update_args /* {
222554668Smckusick 		struct vnode *a_vp;
222654668Smckusick 		struct timeval *a_ta;
222754668Smckusick 		struct timeval *a_tm;
222854668Smckusick 		int a_waitfor;
222954668Smckusick 	} */ *ap;
223051573Smckusick {
223151573Smckusick 
223251573Smckusick 	/* Use nfs_setattr */
223351573Smckusick 	printf("nfs_update: need to implement!!");
223451573Smckusick 	return (EOPNOTSUPP);
223551573Smckusick }
223653629Smckusick 
223753629Smckusick /*
223856364Smckusick  * nfs special file access vnode op.
223956364Smckusick  * Essentially just get vattr and then imitate iaccess() since the device is
224056364Smckusick  * local to the client.
224156364Smckusick  */
224256364Smckusick int
224356364Smckusick nfsspec_access(ap)
224456364Smckusick 	struct vop_access_args /* {
224556364Smckusick 		struct vnode *a_vp;
224656364Smckusick 		int  a_mode;
224756364Smckusick 		struct ucred *a_cred;
224856364Smckusick 		struct proc *a_p;
224956364Smckusick 	} */ *ap;
225056364Smckusick {
225156364Smckusick 	register struct vattr *vap;
225256364Smckusick 	register gid_t *gp;
225356364Smckusick 	register struct ucred *cred = ap->a_cred;
225456364Smckusick 	mode_t mode = ap->a_mode;
225556364Smckusick 	struct vattr vattr;
225656364Smckusick 	register int i;
225756364Smckusick 	int error;
225856364Smckusick 
225956364Smckusick 	/*
226056364Smckusick 	 * If you're the super-user,
226156364Smckusick 	 * you always get access.
226256364Smckusick 	 */
226356364Smckusick 	if (cred->cr_uid == 0)
226456364Smckusick 		return (0);
226556364Smckusick 	vap = &vattr;
226656364Smckusick 	if (error = VOP_GETATTR(ap->a_vp, vap, cred, ap->a_p))
226756364Smckusick 		return (error);
226856364Smckusick 	/*
226956364Smckusick 	 * Access check is based on only one of owner, group, public.
227056364Smckusick 	 * If not owner, then check group. If not a member of the
227156364Smckusick 	 * group, then check public access.
227256364Smckusick 	 */
227356364Smckusick 	if (cred->cr_uid != vap->va_uid) {
227456364Smckusick 		mode >>= 3;
227556364Smckusick 		gp = cred->cr_groups;
227656364Smckusick 		for (i = 0; i < cred->cr_ngroups; i++, gp++)
227756364Smckusick 			if (vap->va_gid == *gp)
227856364Smckusick 				goto found;
227956364Smckusick 		mode >>= 3;
228056364Smckusick found:
228156364Smckusick 		;
228256364Smckusick 	}
228356708Smckusick 	return ((vap->va_mode & mode) == mode ? 0 : EACCES);
228456364Smckusick }
228556364Smckusick 
228656364Smckusick /*
228753629Smckusick  * Read wrapper for special devices.
228853629Smckusick  */
228953629Smckusick int
229053629Smckusick nfsspec_read(ap)
229154668Smckusick 	struct vop_read_args /* {
229254668Smckusick 		struct vnode *a_vp;
229354668Smckusick 		struct uio *a_uio;
229454668Smckusick 		int  a_ioflag;
229554668Smckusick 		struct ucred *a_cred;
229654668Smckusick 	} */ *ap;
229753629Smckusick {
229854032Smckusick 	register struct nfsnode *np = VTONFS(ap->a_vp);
229953629Smckusick 
230053629Smckusick 	/*
230153629Smckusick 	 * Set access flag.
230253629Smckusick 	 */
230354032Smckusick 	np->n_flag |= NACC;
230454032Smckusick 	np->n_atim = time;
230553629Smckusick 	return (VOCALL(spec_vnodeop_p, VOFFSET(vop_read), ap));
230653629Smckusick }
230753629Smckusick 
230853629Smckusick /*
230953629Smckusick  * Write wrapper for special devices.
231053629Smckusick  */
231153629Smckusick int
231253629Smckusick nfsspec_write(ap)
231354668Smckusick 	struct vop_write_args /* {
231454668Smckusick 		struct vnode *a_vp;
231554668Smckusick 		struct uio *a_uio;
231654668Smckusick 		int  a_ioflag;
231754668Smckusick 		struct ucred *a_cred;
231854668Smckusick 	} */ *ap;
231953629Smckusick {
232054032Smckusick 	register struct nfsnode *np = VTONFS(ap->a_vp);
232153629Smckusick 
232253629Smckusick 	/*
232354032Smckusick 	 * Set update flag.
232453629Smckusick 	 */
232554032Smckusick 	np->n_flag |= NUPD;
232654032Smckusick 	np->n_mtim = time;
232753629Smckusick 	return (VOCALL(spec_vnodeop_p, VOFFSET(vop_write), ap));
232853629Smckusick }
232953629Smckusick 
233053629Smckusick /*
233153629Smckusick  * Close wrapper for special devices.
233253629Smckusick  *
233353629Smckusick  * Update the times on the nfsnode then do device close.
233453629Smckusick  */
233553629Smckusick int
233653629Smckusick nfsspec_close(ap)
233754668Smckusick 	struct vop_close_args /* {
233854668Smckusick 		struct vnode *a_vp;
233954668Smckusick 		int  a_fflag;
234054668Smckusick 		struct ucred *a_cred;
234154668Smckusick 		struct proc *a_p;
234254668Smckusick 	} */ *ap;
234353629Smckusick {
234453806Smckusick 	register struct vnode *vp = ap->a_vp;
234553806Smckusick 	register struct nfsnode *np = VTONFS(vp);
234653629Smckusick 	struct vattr vattr;
234753629Smckusick 
234853629Smckusick 	if (np->n_flag & (NACC | NUPD)) {
234953629Smckusick 		np->n_flag |= NCHG;
235053806Smckusick 		if (vp->v_usecount == 1 &&
235153806Smckusick 		    (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) {
235253629Smckusick 			VATTR_NULL(&vattr);
235354106Smckusick 			if (np->n_flag & NACC) {
235454106Smckusick 				vattr.va_atime.ts_sec = np->n_atim.tv_sec;
235554106Smckusick 				vattr.va_atime.ts_nsec =
235654106Smckusick 				    np->n_atim.tv_usec * 1000;
235754106Smckusick 			}
235854106Smckusick 			if (np->n_flag & NUPD) {
235954106Smckusick 				vattr.va_mtime.ts_sec = np->n_mtim.tv_sec;
236054106Smckusick 				vattr.va_mtime.ts_nsec =
236154106Smckusick 				    np->n_mtim.tv_usec * 1000;
236254106Smckusick 			}
236353806Smckusick 			(void)VOP_SETATTR(vp, &vattr, ap->a_cred, ap->a_p);
236453629Smckusick 		}
236553629Smckusick 	}
236653629Smckusick 	return (VOCALL(spec_vnodeop_p, VOFFSET(vop_close), ap));
236753629Smckusick }
236853629Smckusick 
236953629Smckusick #ifdef FIFO
237053629Smckusick /*
237153629Smckusick  * Read wrapper for fifos.
237253629Smckusick  */
237353629Smckusick int
237453629Smckusick nfsfifo_read(ap)
237554668Smckusick 	struct vop_read_args /* {
237654668Smckusick 		struct vnode *a_vp;
237754668Smckusick 		struct uio *a_uio;
237854668Smckusick 		int  a_ioflag;
237954668Smckusick 		struct ucred *a_cred;
238054668Smckusick 	} */ *ap;
238153629Smckusick {
238253629Smckusick 	extern int (**fifo_vnodeop_p)();
238354032Smckusick 	register struct nfsnode *np = VTONFS(ap->a_vp);
238453629Smckusick 
238553629Smckusick 	/*
238653629Smckusick 	 * Set access flag.
238753629Smckusick 	 */
238854032Smckusick 	np->n_flag |= NACC;
238954032Smckusick 	np->n_atim = time;
239053629Smckusick 	return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_read), ap));
239153629Smckusick }
239253629Smckusick 
239353629Smckusick /*
239453629Smckusick  * Write wrapper for fifos.
239553629Smckusick  */
239653629Smckusick int
239753629Smckusick nfsfifo_write(ap)
239854668Smckusick 	struct vop_write_args /* {
239954668Smckusick 		struct vnode *a_vp;
240054668Smckusick 		struct uio *a_uio;
240154668Smckusick 		int  a_ioflag;
240254668Smckusick 		struct ucred *a_cred;
240354668Smckusick 	} */ *ap;
240453629Smckusick {
240553629Smckusick 	extern int (**fifo_vnodeop_p)();
240654032Smckusick 	register struct nfsnode *np = VTONFS(ap->a_vp);
240753629Smckusick 
240853629Smckusick 	/*
240953629Smckusick 	 * Set update flag.
241053629Smckusick 	 */
241154032Smckusick 	np->n_flag |= NUPD;
241254032Smckusick 	np->n_mtim = time;
241353629Smckusick 	return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_write), ap));
241453629Smckusick }
241553629Smckusick 
241653629Smckusick /*
241753629Smckusick  * Close wrapper for fifos.
241853629Smckusick  *
241953629Smckusick  * Update the times on the nfsnode then do fifo close.
242053629Smckusick  */
242153629Smckusick int
242253629Smckusick nfsfifo_close(ap)
242354668Smckusick 	struct vop_close_args /* {
242454668Smckusick 		struct vnode *a_vp;
242554668Smckusick 		int  a_fflag;
242654668Smckusick 		struct ucred *a_cred;
242754668Smckusick 		struct proc *a_p;
242854668Smckusick 	} */ *ap;
242953629Smckusick {
243053806Smckusick 	register struct vnode *vp = ap->a_vp;
243153806Smckusick 	register struct nfsnode *np = VTONFS(vp);
243253629Smckusick 	struct vattr vattr;
243353629Smckusick 	extern int (**fifo_vnodeop_p)();
243453629Smckusick 
243553629Smckusick 	if (np->n_flag & (NACC | NUPD)) {
243653629Smckusick 		if (np->n_flag & NACC)
243753629Smckusick 			np->n_atim = time;
243853629Smckusick 		if (np->n_flag & NUPD)
243953629Smckusick 			np->n_mtim = time;
244053629Smckusick 		np->n_flag |= NCHG;
244153806Smckusick 		if (vp->v_usecount == 1 &&
244253806Smckusick 		    (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) {
244353629Smckusick 			VATTR_NULL(&vattr);
244454106Smckusick 			if (np->n_flag & NACC) {
244554106Smckusick 				vattr.va_atime.ts_sec = np->n_atim.tv_sec;
244654106Smckusick 				vattr.va_atime.ts_nsec =
244754106Smckusick 				    np->n_atim.tv_usec * 1000;
244854106Smckusick 			}
244954106Smckusick 			if (np->n_flag & NUPD) {
245054106Smckusick 				vattr.va_mtime.ts_sec = np->n_mtim.tv_sec;
245154106Smckusick 				vattr.va_mtime.ts_nsec =
245254106Smckusick 				    np->n_mtim.tv_usec * 1000;
245354106Smckusick 			}
245453806Smckusick 			(void)VOP_SETATTR(vp, &vattr, ap->a_cred, ap->a_p);
245553629Smckusick 		}
245653629Smckusick 	}
245753629Smckusick 	return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_close), ap));
245853629Smckusick }
245953629Smckusick #endif /* FIFO */
2460