xref: /csrg-svn/sys/nfs/nfs_vnops.c (revision 60400)
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*60400Smckusick  *	@(#)nfs_vnops.c	7.107 (Berkeley) 05/25/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 */
87*60400Smckusick 	{ &vop_pathconf_desc, nfs_pathconf },	/* pathconf */
8853806Smckusick 	{ &vop_advlock_desc, nfs_advlock },	/* advlock */
8953806Smckusick 	{ &vop_blkatoff_desc, nfs_blkatoff },	/* blkatoff */
9053806Smckusick 	{ &vop_valloc_desc, nfs_valloc },	/* valloc */
9153554Sheideman 	{ &vop_vfree_desc, nfs_vfree },		/* vfree */
9253806Smckusick 	{ &vop_truncate_desc, nfs_truncate },	/* truncate */
9353806Smckusick 	{ &vop_update_desc, nfs_update },	/* update */
9457809Smckusick 	{ &vop_bwrite_desc, vn_bwrite },
9553554Sheideman 	{ (struct vnodeop_desc*)NULL, (int(*)())NULL }
9638414Smckusick };
9753554Sheideman struct vnodeopv_desc nfsv2_vnodeop_opv_desc =
9853554Sheideman 	{ &nfsv2_vnodeop_p, nfsv2_vnodeop_entries };
9938414Smckusick 
10048054Smckusick /*
10148054Smckusick  * Special device vnode ops
10248054Smckusick  */
10353554Sheideman int (**spec_nfsv2nodeop_p)();
10453554Sheideman struct vnodeopv_entry_desc spec_nfsv2nodeop_entries[] = {
10553554Sheideman 	{ &vop_default_desc, vn_default_error },
10653806Smckusick 	{ &vop_lookup_desc, spec_lookup },	/* lookup */
10753806Smckusick 	{ &vop_create_desc, spec_create },	/* create */
10853806Smckusick 	{ &vop_mknod_desc, spec_mknod },	/* mknod */
10953554Sheideman 	{ &vop_open_desc, spec_open },		/* open */
11053806Smckusick 	{ &vop_close_desc, nfsspec_close },	/* close */
11156364Smckusick 	{ &vop_access_desc, nfsspec_access },	/* access */
11253806Smckusick 	{ &vop_getattr_desc, nfs_getattr },	/* getattr */
11353806Smckusick 	{ &vop_setattr_desc, nfs_setattr },	/* setattr */
11453806Smckusick 	{ &vop_read_desc, nfsspec_read },	/* read */
11553806Smckusick 	{ &vop_write_desc, nfsspec_write },	/* write */
11653806Smckusick 	{ &vop_ioctl_desc, spec_ioctl },	/* ioctl */
11753806Smckusick 	{ &vop_select_desc, spec_select },	/* select */
11853554Sheideman 	{ &vop_mmap_desc, spec_mmap },		/* mmap */
11954451Smckusick 	{ &vop_fsync_desc, nfs_fsync },		/* fsync */
12053554Sheideman 	{ &vop_seek_desc, spec_seek },		/* seek */
12153806Smckusick 	{ &vop_remove_desc, spec_remove },	/* remove */
12253554Sheideman 	{ &vop_link_desc, spec_link },		/* link */
12353806Smckusick 	{ &vop_rename_desc, spec_rename },	/* rename */
12453806Smckusick 	{ &vop_mkdir_desc, spec_mkdir },	/* mkdir */
12553806Smckusick 	{ &vop_rmdir_desc, spec_rmdir },	/* rmdir */
12653806Smckusick 	{ &vop_symlink_desc, spec_symlink },	/* symlink */
12753806Smckusick 	{ &vop_readdir_desc, spec_readdir },	/* readdir */
12853806Smckusick 	{ &vop_readlink_desc, spec_readlink },	/* readlink */
12953806Smckusick 	{ &vop_abortop_desc, spec_abortop },	/* abortop */
13053806Smckusick 	{ &vop_inactive_desc, nfs_inactive },	/* inactive */
13153806Smckusick 	{ &vop_reclaim_desc, nfs_reclaim },	/* reclaim */
13253554Sheideman 	{ &vop_lock_desc, nfs_lock },		/* lock */
13353806Smckusick 	{ &vop_unlock_desc, nfs_unlock },	/* unlock */
13453554Sheideman 	{ &vop_bmap_desc, spec_bmap },		/* bmap */
13553806Smckusick 	{ &vop_strategy_desc, spec_strategy },	/* strategy */
13653554Sheideman 	{ &vop_print_desc, nfs_print },		/* print */
13753806Smckusick 	{ &vop_islocked_desc, nfs_islocked },	/* islocked */
138*60400Smckusick 	{ &vop_pathconf_desc, spec_pathconf },	/* pathconf */
13953806Smckusick 	{ &vop_advlock_desc, spec_advlock },	/* advlock */
14053806Smckusick 	{ &vop_blkatoff_desc, spec_blkatoff },	/* blkatoff */
14153806Smckusick 	{ &vop_valloc_desc, spec_valloc },	/* valloc */
14253806Smckusick 	{ &vop_vfree_desc, spec_vfree },	/* vfree */
14353806Smckusick 	{ &vop_truncate_desc, spec_truncate },	/* truncate */
14453806Smckusick 	{ &vop_update_desc, nfs_update },	/* update */
14557809Smckusick 	{ &vop_bwrite_desc, vn_bwrite },
14653554Sheideman 	{ (struct vnodeop_desc*)NULL, (int(*)())NULL }
14738414Smckusick };
14853554Sheideman struct vnodeopv_desc spec_nfsv2nodeop_opv_desc =
14953554Sheideman 	{ &spec_nfsv2nodeop_p, spec_nfsv2nodeop_entries };
15038414Smckusick 
15140294Smckusick #ifdef FIFO
15253554Sheideman int (**fifo_nfsv2nodeop_p)();
15353554Sheideman struct vnodeopv_entry_desc fifo_nfsv2nodeop_entries[] = {
15453554Sheideman 	{ &vop_default_desc, vn_default_error },
15553806Smckusick 	{ &vop_lookup_desc, fifo_lookup },	/* lookup */
15653806Smckusick 	{ &vop_create_desc, fifo_create },	/* create */
15753806Smckusick 	{ &vop_mknod_desc, fifo_mknod },	/* mknod */
15853554Sheideman 	{ &vop_open_desc, fifo_open },		/* open */
15953806Smckusick 	{ &vop_close_desc, nfsfifo_close },	/* close */
16056364Smckusick 	{ &vop_access_desc, nfsspec_access },	/* access */
16153806Smckusick 	{ &vop_getattr_desc, nfs_getattr },	/* getattr */
16253806Smckusick 	{ &vop_setattr_desc, nfs_setattr },	/* setattr */
16353806Smckusick 	{ &vop_read_desc, nfsfifo_read },	/* read */
16453806Smckusick 	{ &vop_write_desc, nfsfifo_write },	/* write */
16553806Smckusick 	{ &vop_ioctl_desc, fifo_ioctl },	/* ioctl */
16653806Smckusick 	{ &vop_select_desc, fifo_select },	/* select */
16753554Sheideman 	{ &vop_mmap_desc, fifo_mmap },		/* mmap */
16854451Smckusick 	{ &vop_fsync_desc, nfs_fsync },		/* fsync */
16953554Sheideman 	{ &vop_seek_desc, fifo_seek },		/* seek */
17053806Smckusick 	{ &vop_remove_desc, fifo_remove },	/* remove */
17153554Sheideman 	{ &vop_link_desc, fifo_link },		/* link */
17253806Smckusick 	{ &vop_rename_desc, fifo_rename },	/* rename */
17353806Smckusick 	{ &vop_mkdir_desc, fifo_mkdir },	/* mkdir */
17453806Smckusick 	{ &vop_rmdir_desc, fifo_rmdir },	/* rmdir */
17553806Smckusick 	{ &vop_symlink_desc, fifo_symlink },	/* symlink */
17653806Smckusick 	{ &vop_readdir_desc, fifo_readdir },	/* readdir */
17753806Smckusick 	{ &vop_readlink_desc, fifo_readlink },	/* readlink */
17853806Smckusick 	{ &vop_abortop_desc, fifo_abortop },	/* abortop */
17953806Smckusick 	{ &vop_inactive_desc, nfs_inactive },	/* inactive */
18053806Smckusick 	{ &vop_reclaim_desc, nfs_reclaim },	/* reclaim */
18153554Sheideman 	{ &vop_lock_desc, nfs_lock },		/* lock */
18253806Smckusick 	{ &vop_unlock_desc, nfs_unlock },	/* unlock */
18353554Sheideman 	{ &vop_bmap_desc, fifo_bmap },		/* bmap */
18453806Smckusick 	{ &vop_strategy_desc, fifo_badop },	/* strategy */
18553554Sheideman 	{ &vop_print_desc, nfs_print },		/* print */
18653806Smckusick 	{ &vop_islocked_desc, nfs_islocked },	/* islocked */
187*60400Smckusick 	{ &vop_pathconf_desc, fifo_pathconf },	/* pathconf */
18853806Smckusick 	{ &vop_advlock_desc, fifo_advlock },	/* advlock */
18953806Smckusick 	{ &vop_blkatoff_desc, fifo_blkatoff },	/* blkatoff */
19053806Smckusick 	{ &vop_valloc_desc, fifo_valloc },	/* valloc */
19153806Smckusick 	{ &vop_vfree_desc, fifo_vfree },	/* vfree */
19253806Smckusick 	{ &vop_truncate_desc, fifo_truncate },	/* truncate */
19353806Smckusick 	{ &vop_update_desc, nfs_update },	/* update */
19457809Smckusick 	{ &vop_bwrite_desc, vn_bwrite },
19553554Sheideman 	{ (struct vnodeop_desc*)NULL, (int(*)())NULL }
19640294Smckusick };
19753554Sheideman struct vnodeopv_desc fifo_nfsv2nodeop_opv_desc =
19853554Sheideman 	{ &fifo_nfsv2nodeop_p, fifo_nfsv2nodeop_entries };
19940294Smckusick #endif /* FIFO */
20040294Smckusick 
20156289Smckusick void nqnfs_clientlease();
20256289Smckusick 
20348054Smckusick /*
20452196Smckusick  * Global variables
20548054Smckusick  */
20638414Smckusick extern u_long nfs_procids[NFS_NPROCS];
20756364Smckusick extern u_long nfs_prog, nfs_vers, nfs_true, nfs_false;
20838414Smckusick extern char nfsiobuf[MAXPHYS+NBPG];
20941905Smckusick struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON];
21046988Smckusick int nfs_numasync = 0;
21156390Smckusick /* Queue head for nfsiod's */
21256468Smckusick struct queue_entry nfs_bufq;
21354740Smckusick #define	DIRHDSIZ	(sizeof (struct dirent) - (MAXNAMLEN + 1))
21438414Smckusick 
21538414Smckusick /*
21638414Smckusick  * nfs null call from vfs.
21738414Smckusick  */
21852234Sheideman int
21952196Smckusick nfs_null(vp, cred, procp)
22038414Smckusick 	struct vnode *vp;
22138414Smckusick 	struct ucred *cred;
22252196Smckusick 	struct proc *procp;
22338414Smckusick {
22439488Smckusick 	caddr_t bpos, dpos;
22539488Smckusick 	int error = 0;
22639488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb;
22738414Smckusick 
22852196Smckusick 	nfsm_reqhead(vp, NFSPROC_NULL, 0);
22952196Smckusick 	nfsm_request(vp, NFSPROC_NULL, procp, cred);
23038414Smckusick 	nfsm_reqdone;
23138414Smckusick 	return (error);
23238414Smckusick }
23338414Smckusick 
23438414Smckusick /*
23538414Smckusick  * nfs access vnode op.
23656364Smckusick  * For nfs, just return ok. File accesses may fail later.
23756364Smckusick  * For nqnfs, use the access rpc to check accessibility. If file modes are
23856364Smckusick  * changed on the server, accesses might still fail later.
23938414Smckusick  */
24052234Sheideman int
24153806Smckusick nfs_access(ap)
24254668Smckusick 	struct vop_access_args /* {
24354668Smckusick 		struct vnode *a_vp;
24454668Smckusick 		int  a_mode;
24554668Smckusick 		struct ucred *a_cred;
24654668Smckusick 		struct proc *a_p;
24754668Smckusick 	} */ *ap;
24838414Smckusick {
24956364Smckusick 	register struct vnode *vp = ap->a_vp;
25056364Smckusick 	register u_long *tl;
25156364Smckusick 	register caddr_t cp;
25256364Smckusick 	caddr_t bpos, dpos;
25356364Smckusick 	int error = 0;
25456364Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
25538414Smckusick 
25638414Smckusick 	/*
25756708Smckusick 	 * For nqnfs, do an access rpc, otherwise you are stuck emulating
25856708Smckusick 	 * ufs_access() locally using the vattr. This may not be correct,
25956708Smckusick 	 * since the server may apply other access criteria such as
26056708Smckusick 	 * client uid-->server uid mapping that we do not know about, but
26156708Smckusick 	 * this is better than just returning anything that is lying about
26256708Smckusick 	 * in the cache.
26338414Smckusick 	 */
26456364Smckusick 	if (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) {
26556364Smckusick 		nfsstats.rpccnt[NQNFSPROC_ACCESS]++;
26656364Smckusick 		nfsm_reqhead(vp, NQNFSPROC_ACCESS, NFSX_FH + 3 * NFSX_UNSIGNED);
26756364Smckusick 		nfsm_fhtom(vp);
26856364Smckusick 		nfsm_build(tl, u_long *, 3 * NFSX_UNSIGNED);
26956364Smckusick 		if (ap->a_mode & VREAD)
27056364Smckusick 			*tl++ = nfs_true;
27156364Smckusick 		else
27256364Smckusick 			*tl++ = nfs_false;
27356364Smckusick 		if (ap->a_mode & VWRITE)
27456364Smckusick 			*tl++ = nfs_true;
27556364Smckusick 		else
27656364Smckusick 			*tl++ = nfs_false;
27756364Smckusick 		if (ap->a_mode & VEXEC)
27856364Smckusick 			*tl = nfs_true;
27956364Smckusick 		else
28056364Smckusick 			*tl = nfs_false;
28156364Smckusick 		nfsm_request(vp, NQNFSPROC_ACCESS, ap->a_p, ap->a_cred);
28256364Smckusick 		nfsm_reqdone;
28338884Smacklem 		return (error);
28456364Smckusick 	} else
28556708Smckusick 		return (nfsspec_access(ap));
28638414Smckusick }
28738414Smckusick 
28838414Smckusick /*
28938414Smckusick  * nfs open vnode op
29056289Smckusick  * Check to see if the type is ok
29152196Smckusick  * and that deletion is not in progress.
29256289Smckusick  * For paged in text files, you will need to flush the page cache
29356289Smckusick  * if consistency is lost.
29438414Smckusick  */
29539488Smckusick /* ARGSUSED */
29652234Sheideman int
29753806Smckusick nfs_open(ap)
29854668Smckusick 	struct vop_open_args /* {
29954668Smckusick 		struct vnode *a_vp;
30054668Smckusick 		int  a_mode;
30154668Smckusick 		struct ucred *a_cred;
30254668Smckusick 		struct proc *a_p;
30354668Smckusick 	} */ *ap;
30438414Smckusick {
30553806Smckusick 	register struct vnode *vp = ap->a_vp;
30656289Smckusick 	struct nfsnode *np = VTONFS(vp);
30756289Smckusick 	struct nfsmount *nmp = VFSTONFS(vp->v_mount);
30856289Smckusick 	struct vattr vattr;
30956289Smckusick 	int error;
31038414Smckusick 
31153806Smckusick 	if (vp->v_type != VREG && vp->v_type != VDIR && vp->v_type != VLNK)
31238414Smckusick 		return (EACCES);
31356289Smckusick 	if (vp->v_flag & VTEXT) {
31456289Smckusick 	    /*
31556289Smckusick 	     * Get a valid lease. If cached data is stale, flush it.
31656289Smckusick 	     */
31756289Smckusick 	    if (nmp->nm_flag & NFSMNT_NQNFS) {
31856289Smckusick 		if (NQNFS_CKINVALID(vp, np, NQL_READ)) {
31956289Smckusick 		    do {
32056289Smckusick 			error = nqnfs_getlease(vp, NQL_READ, ap->a_cred, ap->a_p);
32156289Smckusick 		    } while (error == NQNFS_EXPIRED);
32256289Smckusick 		    if (error)
32356289Smckusick 			return (error);
32459706Smckusick 		    if (np->n_lrev != np->n_brev ||
32559706Smckusick 			(np->n_flag & NQNFSNONCACHE)) {
32657791Smckusick 			if ((error = nfs_vinvalbuf(vp, V_SAVE, ap->a_cred,
32757791Smckusick 				ap->a_p, 1)) == EINTR)
32857791Smckusick 				return (error);
32956289Smckusick 			(void) vnode_pager_uncache(vp);
33056289Smckusick 			np->n_brev = np->n_lrev;
33156289Smckusick 		    }
33256289Smckusick 		}
33356289Smckusick 	    } else {
33456289Smckusick 		if (np->n_flag & NMODIFIED) {
33557791Smckusick 			if ((error = nfs_vinvalbuf(vp, V_SAVE, ap->a_cred,
33657791Smckusick 				ap->a_p, 1)) == EINTR)
33757791Smckusick 				return (error);
33856289Smckusick 			(void) vnode_pager_uncache(vp);
33956289Smckusick 			np->n_attrstamp = 0;
34056289Smckusick 			np->n_direofoffset = 0;
34156289Smckusick 			if (error = VOP_GETATTR(vp, &vattr, ap->a_cred, ap->a_p))
34256289Smckusick 				return (error);
34356289Smckusick 			np->n_mtime = vattr.va_mtime.ts_sec;
34456289Smckusick 		} else {
34556289Smckusick 			if (error = VOP_GETATTR(vp, &vattr, ap->a_cred, ap->a_p))
34656289Smckusick 				return (error);
34756289Smckusick 			if (np->n_mtime != vattr.va_mtime.ts_sec) {
34856289Smckusick 				np->n_direofoffset = 0;
34957791Smckusick 				if ((error = nfs_vinvalbuf(vp, V_SAVE,
35057791Smckusick 					ap->a_cred, ap->a_p, 1)) == EINTR)
35157791Smckusick 					return (error);
35256289Smckusick 				(void) vnode_pager_uncache(vp);
35356289Smckusick 				np->n_mtime = vattr.va_mtime.ts_sec;
35456289Smckusick 			}
35556289Smckusick 		}
35656289Smckusick 	    }
35756289Smckusick 	} else if ((nmp->nm_flag & NFSMNT_NQNFS) == 0)
35856289Smckusick 		np->n_attrstamp = 0; /* For Open/Close consistency */
35952196Smckusick 	return (0);
36038414Smckusick }
36138414Smckusick 
36238414Smckusick /*
36338414Smckusick  * nfs close vnode op
36438884Smacklem  * For reg files, invalidate any buffer cache entries.
36538414Smckusick  */
36639488Smckusick /* ARGSUSED */
36752234Sheideman int
36853806Smckusick nfs_close(ap)
36954451Smckusick 	struct vop_close_args /* {
37054451Smckusick 		struct vnodeop_desc *a_desc;
37154451Smckusick 		struct vnode *a_vp;
37254451Smckusick 		int  a_fflag;
37354451Smckusick 		struct ucred *a_cred;
37454451Smckusick 		struct proc *a_p;
37554451Smckusick 	} */ *ap;
37638414Smckusick {
37753806Smckusick 	register struct vnode *vp = ap->a_vp;
37853806Smckusick 	register struct nfsnode *np = VTONFS(vp);
37939341Smckusick 	int error = 0;
38038414Smckusick 
38153806Smckusick 	if (vp->v_type == VREG) {
38253806Smckusick 	    if ((VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) == 0 &&
38353629Smckusick 		(np->n_flag & NMODIFIED)) {
38457791Smckusick 		error = nfs_vinvalbuf(vp, V_SAVE, ap->a_cred, ap->a_p, 1);
38541905Smckusick 		np->n_attrstamp = 0;
38653629Smckusick 	    }
38753629Smckusick 	    if (np->n_flag & NWRITEERR) {
38853629Smckusick 		np->n_flag &= ~NWRITEERR;
38953629Smckusick 		error = np->n_error;
39053629Smckusick 	    }
39138884Smacklem 	}
39238414Smckusick 	return (error);
39338414Smckusick }
39438414Smckusick 
39538414Smckusick /*
39638414Smckusick  * nfs getattr call from vfs.
39738414Smckusick  */
39852234Sheideman int
39953805Smckusick nfs_getattr(ap)
40054668Smckusick 	struct vop_getattr_args /* {
40154668Smckusick 		struct vnode *a_vp;
40254668Smckusick 		struct vattr *a_vap;
40354668Smckusick 		struct ucred *a_cred;
40454668Smckusick 		struct proc *a_p;
40554668Smckusick 	} */ *ap;
40638414Smckusick {
40753805Smckusick 	register struct vnode *vp = ap->a_vp;
40853805Smckusick 	register struct nfsnode *np = VTONFS(vp);
40939488Smckusick 	register caddr_t cp;
41039488Smckusick 	caddr_t bpos, dpos;
41139488Smckusick 	int error = 0;
41239488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
41338414Smckusick 
41453805Smckusick 	/*
41553805Smckusick 	 * Update local times for special files.
41653805Smckusick 	 */
41756329Smckusick 	if (np->n_flag & (NACC | NUPD))
41853805Smckusick 		np->n_flag |= NCHG;
41953805Smckusick 	/*
42053805Smckusick 	 * First look in the cache.
42153805Smckusick 	 */
42253805Smckusick 	if (nfs_getattrcache(vp, ap->a_vap) == 0)
42338414Smckusick 		return (0);
42438414Smckusick 	nfsstats.rpccnt[NFSPROC_GETATTR]++;
42553805Smckusick 	nfsm_reqhead(vp, NFSPROC_GETATTR, NFSX_FH);
42653805Smckusick 	nfsm_fhtom(vp);
42753805Smckusick 	nfsm_request(vp, NFSPROC_GETATTR, ap->a_p, ap->a_cred);
42853805Smckusick 	nfsm_loadattr(vp, ap->a_vap);
42938414Smckusick 	nfsm_reqdone;
43038414Smckusick 	return (error);
43138414Smckusick }
43238414Smckusick 
43338414Smckusick /*
43438414Smckusick  * nfs setattr call.
43538414Smckusick  */
43652234Sheideman int
43753806Smckusick nfs_setattr(ap)
43854451Smckusick 	struct vop_setattr_args /* {
43954451Smckusick 		struct vnodeop_desc *a_desc;
44054451Smckusick 		struct vnode *a_vp;
44154451Smckusick 		struct vattr *a_vap;
44254451Smckusick 		struct ucred *a_cred;
44354451Smckusick 		struct proc *a_p;
44454451Smckusick 	} */ *ap;
44538414Smckusick {
44638884Smacklem 	register struct nfsv2_sattr *sp;
44739488Smckusick 	register caddr_t cp;
44839488Smckusick 	register long t1;
44952196Smckusick 	caddr_t bpos, dpos, cp2;
45052196Smckusick 	u_long *tl;
45156289Smckusick 	int error = 0, isnq;
45239488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
45353806Smckusick 	register struct vnode *vp = ap->a_vp;
45453806Smckusick 	register struct nfsnode *np = VTONFS(vp);
45553806Smckusick 	register struct vattr *vap = ap->a_vap;
45652196Smckusick 	u_quad_t frev;
45738414Smckusick 
45857791Smckusick 	if (vap->va_size != VNOVAL || vap->va_mtime.ts_sec != VNOVAL ||
45957791Smckusick 		vap->va_atime.ts_sec != VNOVAL) {
46057791Smckusick 		if (vap->va_size != VNOVAL) {
46157791Smckusick 			if (np->n_flag & NMODIFIED) {
46257791Smckusick 			    if (vap->va_size == 0)
46357791Smckusick 				error = nfs_vinvalbuf(vp, 0, ap->a_cred,
46457791Smckusick 					ap->a_p, 1);
46557791Smckusick 			    else
46657791Smckusick 				error = nfs_vinvalbuf(vp, V_SAVE, ap->a_cred,
46757791Smckusick 					ap->a_p, 1);
46857791Smckusick 			    if (error)
46957791Smckusick 				return (error);
47057791Smckusick 			}
47157791Smckusick 			np->n_size = np->n_vattr.va_size = vap->va_size;
47257791Smckusick 			vnode_pager_setsize(vp, (u_long)np->n_size);
47357791Smckusick 		} else if ((np->n_flag & NMODIFIED) &&
47457791Smckusick 			(error = nfs_vinvalbuf(vp, V_SAVE, ap->a_cred,
47557791Smckusick 			 ap->a_p, 1)) == EINTR)
47657791Smckusick 			return (error);
47757791Smckusick 	}
47838414Smckusick 	nfsstats.rpccnt[NFSPROC_SETATTR]++;
47956289Smckusick 	isnq = (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS);
48056289Smckusick 	nfsm_reqhead(vp, NFSPROC_SETATTR, NFSX_FH+NFSX_SATTR(isnq));
48153806Smckusick 	nfsm_fhtom(vp);
48256289Smckusick 	nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR(isnq));
48356289Smckusick 	if (vap->va_mode == (u_short)-1)
48438884Smacklem 		sp->sa_mode = VNOVAL;
48538414Smckusick 	else
48653806Smckusick 		sp->sa_mode = vtonfs_mode(vp->v_type, vap->va_mode);
48756289Smckusick 	if (vap->va_uid == (uid_t)-1)
48838884Smacklem 		sp->sa_uid = VNOVAL;
48938414Smckusick 	else
49053806Smckusick 		sp->sa_uid = txdr_unsigned(vap->va_uid);
49156289Smckusick 	if (vap->va_gid == (gid_t)-1)
49238884Smacklem 		sp->sa_gid = VNOVAL;
49338414Smckusick 	else
49453806Smckusick 		sp->sa_gid = txdr_unsigned(vap->va_gid);
49556289Smckusick 	if (isnq) {
49656289Smckusick 		txdr_hyper(&vap->va_size, &sp->sa_nqsize);
49756289Smckusick 		txdr_nqtime(&vap->va_atime, &sp->sa_nqatime);
49856289Smckusick 		txdr_nqtime(&vap->va_mtime, &sp->sa_nqmtime);
49956289Smckusick 		sp->sa_nqflags = txdr_unsigned(vap->va_flags);
50056289Smckusick 		sp->sa_nqrdev = VNOVAL;
50156289Smckusick 	} else {
50256289Smckusick 		sp->sa_nfssize = txdr_unsigned(vap->va_size);
50358882Smckusick 		txdr_nfstime(&vap->va_atime, &sp->sa_nfsatime);
50456289Smckusick 		txdr_nfstime(&vap->va_mtime, &sp->sa_nfsmtime);
50556289Smckusick 	}
50653806Smckusick 	nfsm_request(vp, NFSPROC_SETATTR, ap->a_p, ap->a_cred);
50753806Smckusick 	nfsm_loadattr(vp, (struct vattr *)0);
50853806Smckusick 	if ((VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) &&
50953806Smckusick 	    NQNFS_CKCACHABLE(vp, NQL_WRITE)) {
51052196Smckusick 		nfsm_dissect(tl, u_long *, 2*NFSX_UNSIGNED);
51152196Smckusick 		fxdr_hyper(tl, &frev);
51254451Smckusick 		if (frev > np->n_brev)
51352196Smckusick 			np->n_brev = frev;
51452196Smckusick 	}
51538414Smckusick 	nfsm_reqdone;
51638414Smckusick 	return (error);
51738414Smckusick }
51838414Smckusick 
51938414Smckusick /*
52038414Smckusick  * nfs lookup call, one step at a time...
52138414Smckusick  * First look in cache
52238414Smckusick  * If not found, unlock the directory nfsnode and do the rpc
52338414Smckusick  */
52452234Sheideman int
52553806Smckusick nfs_lookup(ap)
52654451Smckusick 	struct vop_lookup_args /* {
52754451Smckusick 		struct vnodeop_desc *a_desc;
52854451Smckusick 		struct vnode *a_dvp;
52954451Smckusick 		struct vnode **a_vpp;
53054451Smckusick 		struct componentname *a_cnp;
53154451Smckusick 	} */ *ap;
53238414Smckusick {
53353806Smckusick 	register struct componentname *cnp = ap->a_cnp;
53453806Smckusick 	register struct vnode *dvp = ap->a_dvp;
53554668Smckusick 	register struct vnode **vpp = ap->a_vpp;
53655184Smckusick 	register int flags = cnp->cn_flags;
53738414Smckusick 	register struct vnode *vdp;
53848054Smckusick 	register u_long *tl;
53939488Smckusick 	register caddr_t cp;
54039488Smckusick 	register long t1, t2;
54152196Smckusick 	struct nfsmount *nmp;
54252196Smckusick 	struct nfsnode *tp;
54339488Smckusick 	caddr_t bpos, dpos, cp2;
54452196Smckusick 	time_t reqtime;
54539488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
54638414Smckusick 	struct vnode *newvp;
54738414Smckusick 	long len;
54838414Smckusick 	nfsv2fh_t *fhp;
54938414Smckusick 	struct nfsnode *np;
55052234Sheideman 	int lockparent, wantparent, error = 0;
55152196Smckusick 	int nqlflag, cachable;
55252196Smckusick 	u_quad_t frev;
55338414Smckusick 
55454668Smckusick 	*vpp = NULL;
55553806Smckusick 	if (dvp->v_type != VDIR)
55638414Smckusick 		return (ENOTDIR);
55755184Smckusick 	lockparent = flags & LOCKPARENT;
55855184Smckusick 	wantparent = flags & (LOCKPARENT|WANTPARENT);
55953806Smckusick 	nmp = VFSTONFS(dvp->v_mount);
56053806Smckusick 	np = VTONFS(dvp);
56154668Smckusick 	if ((error = cache_lookup(dvp, vpp, cnp)) && error != ENOENT) {
56238884Smacklem 		struct vattr vattr;
56338884Smacklem 		int vpid;
56438884Smacklem 
56554668Smckusick 		vdp = *vpp;
56638884Smacklem 		vpid = vdp->v_id;
56738414Smckusick 		/*
56838884Smacklem 		 * See the comment starting `Step through' in ufs/ufs_lookup.c
56938884Smacklem 		 * for an explanation of the locking protocol
57038414Smckusick 		 */
57153806Smckusick 		if (dvp == vdp) {
57238425Smckusick 			VREF(vdp);
57339441Smckusick 			error = 0;
57452196Smckusick 		} else
57539441Smckusick 			error = vget(vdp);
57639441Smckusick 		if (!error) {
57740251Smckusick 			if (vpid == vdp->v_id) {
57852196Smckusick 			   if (nmp->nm_flag & NFSMNT_NQNFS) {
57956289Smckusick 				if ((nmp->nm_flag & NFSMNT_NQLOOKLEASE) == 0) {
58056289Smckusick 					nfsstats.lookupcache_hits++;
58156289Smckusick 					if (cnp->cn_nameiop != LOOKUP &&
58256289Smckusick 					    (flags & ISLASTCN))
58356289Smckusick 					    cnp->cn_flags |= SAVENAME;
58456289Smckusick 					return (0);
58556289Smckusick 			        } else if (NQNFS_CKCACHABLE(dvp, NQL_READ)) {
58654451Smckusick 					if (np->n_lrev != np->n_brev ||
58752196Smckusick 					    (np->n_flag & NMODIFIED)) {
58852196Smckusick 						np->n_direofoffset = 0;
58953806Smckusick 						cache_purge(dvp);
59057791Smckusick 						error = nfs_vinvalbuf(dvp, 0,
59156660Smckusick 						    cnp->cn_cred, cnp->cn_proc,
59257791Smckusick 						    1);
59357791Smckusick 						if (error == EINTR)
59457791Smckusick 							return (error);
59552196Smckusick 						np->n_brev = np->n_lrev;
59652196Smckusick 					} else {
59752196Smckusick 						nfsstats.lookupcache_hits++;
59853806Smckusick 						if (cnp->cn_nameiop != LOOKUP &&
59955184Smckusick 						    (flags & ISLASTCN))
60053806Smckusick 						    cnp->cn_flags |= SAVENAME;
60152196Smckusick 						return (0);
60252196Smckusick 					}
60352196Smckusick 				}
60453806Smckusick 			   } else if (!VOP_GETATTR(vdp, &vattr, cnp->cn_cred, cnp->cn_proc) &&
60554106Smckusick 			       vattr.va_ctime.ts_sec == VTONFS(vdp)->n_ctime) {
60639441Smckusick 				nfsstats.lookupcache_hits++;
60753806Smckusick 				if (cnp->cn_nameiop != LOOKUP &&
60855184Smckusick 				    (flags & ISLASTCN))
60953806Smckusick 					cnp->cn_flags |= SAVENAME;
61039441Smckusick 				return (0);
61140251Smckusick 			   }
61247289Smckusick 			   cache_purge(vdp);
61339441Smckusick 			}
61452196Smckusick 			vrele(vdp);
61538884Smacklem 		}
61654668Smckusick 		*vpp = NULLVP;
61752196Smckusick 	}
61839341Smckusick 	error = 0;
61938414Smckusick 	nfsstats.lookupcache_misses++;
62038414Smckusick 	nfsstats.rpccnt[NFSPROC_LOOKUP]++;
62153806Smckusick 	len = cnp->cn_namelen;
62253806Smckusick 	nfsm_reqhead(dvp, NFSPROC_LOOKUP, NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len));
62352196Smckusick 
62452196Smckusick 	/*
62552196Smckusick 	 * For nqnfs optionally piggyback a getlease request for the name
62652196Smckusick 	 * being looked up.
62752196Smckusick 	 */
62852196Smckusick 	if (nmp->nm_flag & NFSMNT_NQNFS) {
62956289Smckusick 		nfsm_build(tl, u_long *, NFSX_UNSIGNED);
63052196Smckusick 		if ((nmp->nm_flag & NFSMNT_NQLOOKLEASE) &&
63155184Smckusick 		    ((cnp->cn_flags & MAKEENTRY) &&
63256289Smckusick 		    (cnp->cn_nameiop != DELETE || !(flags & ISLASTCN))))
63352196Smckusick 			*tl = txdr_unsigned(nmp->nm_leaseterm);
63456289Smckusick 		else
63552196Smckusick 			*tl = 0;
63652196Smckusick 	}
63753806Smckusick 	nfsm_fhtom(dvp);
63853806Smckusick 	nfsm_strtom(cnp->cn_nameptr, len, NFS_MAXNAMLEN);
63952196Smckusick 	reqtime = time.tv_sec;
64053806Smckusick 	nfsm_request(dvp, NFSPROC_LOOKUP, cnp->cn_proc, cnp->cn_cred);
64138414Smckusick nfsmout:
64238414Smckusick 	if (error) {
64353806Smckusick 		if ((cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME) &&
64455184Smckusick 		    (flags & ISLASTCN) && error == ENOENT)
64552823Smckusick 			error = EJUSTRETURN;
64655184Smckusick 		if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN))
64753806Smckusick 			cnp->cn_flags |= SAVENAME;
64840483Smckusick 		return (error);
64938414Smckusick 	}
65052196Smckusick 	if (nmp->nm_flag & NFSMNT_NQNFS) {
65152196Smckusick 		nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
65252196Smckusick 		if (*tl) {
65352196Smckusick 			nqlflag = fxdr_unsigned(int, *tl);
65452196Smckusick 			nfsm_dissect(tl, u_long *, 4*NFSX_UNSIGNED);
65552196Smckusick 			cachable = fxdr_unsigned(int, *tl++);
65652196Smckusick 			reqtime += fxdr_unsigned(int, *tl++);
65752196Smckusick 			fxdr_hyper(tl, &frev);
65852196Smckusick 		} else
65952196Smckusick 			nqlflag = 0;
66052196Smckusick 	}
66152196Smckusick 	nfsm_dissect(fhp, nfsv2fh_t *, NFSX_FH);
66238414Smckusick 
66338414Smckusick 	/*
66452196Smckusick 	 * Handle RENAME case...
66538414Smckusick 	 */
66655184Smckusick 	if (cnp->cn_nameiop == RENAME && wantparent && (flags & ISLASTCN)) {
66752196Smckusick 		if (!bcmp(np->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) {
66838414Smckusick 			m_freem(mrep);
66938414Smckusick 			return (EISDIR);
67038414Smckusick 		}
67153806Smckusick 		if (error = nfs_nget(dvp->v_mount, fhp, &np)) {
67238414Smckusick 			m_freem(mrep);
67338414Smckusick 			return (error);
67438414Smckusick 		}
67538414Smckusick 		newvp = NFSTOV(np);
67639459Smckusick 		if (error =
67739459Smckusick 		    nfs_loadattrcache(&newvp, &md, &dpos, (struct vattr *)0)) {
67852196Smckusick 			vrele(newvp);
67938414Smckusick 			m_freem(mrep);
68038414Smckusick 			return (error);
68138414Smckusick 		}
68254668Smckusick 		*vpp = newvp;
68345037Smckusick 		m_freem(mrep);
68453806Smckusick 		cnp->cn_flags |= SAVENAME;
68538414Smckusick 		return (0);
68638414Smckusick 	}
68738414Smckusick 
68852196Smckusick 	if (!bcmp(np->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) {
68953806Smckusick 		VREF(dvp);
69053806Smckusick 		newvp = dvp;
69138414Smckusick 	} else {
69253806Smckusick 		if (error = nfs_nget(dvp->v_mount, fhp, &np)) {
69338414Smckusick 			m_freem(mrep);
69438414Smckusick 			return (error);
69538414Smckusick 		}
69638414Smckusick 		newvp = NFSTOV(np);
69738414Smckusick 	}
69839459Smckusick 	if (error = nfs_loadattrcache(&newvp, &md, &dpos, (struct vattr *)0)) {
69952196Smckusick 		vrele(newvp);
70038414Smckusick 		m_freem(mrep);
70138414Smckusick 		return (error);
70238414Smckusick 	}
70338414Smckusick 	m_freem(mrep);
70454668Smckusick 	*vpp = newvp;
70555184Smckusick 	if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN))
70653806Smckusick 		cnp->cn_flags |= SAVENAME;
70755184Smckusick 	if ((cnp->cn_flags & MAKEENTRY) &&
70855184Smckusick 	    (cnp->cn_nameiop != DELETE || !(flags & ISLASTCN))) {
70952196Smckusick 		if ((nmp->nm_flag & NFSMNT_NQNFS) == 0)
71054106Smckusick 			np->n_ctime = np->n_vattr.va_ctime.ts_sec;
71156289Smckusick 		else if (nqlflag && reqtime > time.tv_sec)
71256289Smckusick 			nqnfs_clientlease(nmp, np, nqlflag, cachable, reqtime,
71356289Smckusick 				frev);
71454668Smckusick 		cache_enter(dvp, *vpp, cnp);
71540251Smckusick 	}
71652196Smckusick 	return (0);
71738414Smckusick }
71838414Smckusick 
71938414Smckusick /*
72041905Smckusick  * nfs read call.
72141905Smckusick  * Just call nfs_bioread() to do the work.
72241905Smckusick  */
72352234Sheideman int
72453806Smckusick nfs_read(ap)
72554668Smckusick 	struct vop_read_args /* {
72654668Smckusick 		struct vnode *a_vp;
72754668Smckusick 		struct uio *a_uio;
72854668Smckusick 		int  a_ioflag;
72954668Smckusick 		struct ucred *a_cred;
73054668Smckusick 	} */ *ap;
73141905Smckusick {
73253806Smckusick 	register struct vnode *vp = ap->a_vp;
73353806Smckusick 
73453806Smckusick 	if (vp->v_type != VREG)
73541905Smckusick 		return (EPERM);
73653806Smckusick 	return (nfs_bioread(vp, ap->a_uio, ap->a_ioflag, ap->a_cred));
73741905Smckusick }
73841905Smckusick 
73941905Smckusick /*
74038414Smckusick  * nfs readlink call
74138414Smckusick  */
74252234Sheideman int
74353806Smckusick nfs_readlink(ap)
74454668Smckusick 	struct vop_readlink_args /* {
74554668Smckusick 		struct vnode *a_vp;
74654668Smckusick 		struct uio *a_uio;
74754668Smckusick 		struct ucred *a_cred;
74854668Smckusick 	} */ *ap;
74941905Smckusick {
75053806Smckusick 	register struct vnode *vp = ap->a_vp;
75153806Smckusick 
75253806Smckusick 	if (vp->v_type != VLNK)
75341905Smckusick 		return (EPERM);
75453806Smckusick 	return (nfs_bioread(vp, ap->a_uio, 0, ap->a_cred));
75541905Smckusick }
75641905Smckusick 
75741905Smckusick /*
75841905Smckusick  * Do a readlink rpc.
75941905Smckusick  * Called by nfs_doio() from below the buffer cache.
76041905Smckusick  */
76152234Sheideman int
76248054Smckusick nfs_readlinkrpc(vp, uiop, cred)
76339488Smckusick 	register struct vnode *vp;
76438414Smckusick 	struct uio *uiop;
76538414Smckusick 	struct ucred *cred;
76638414Smckusick {
76748054Smckusick 	register u_long *tl;
76839488Smckusick 	register caddr_t cp;
76939488Smckusick 	register long t1;
77039488Smckusick 	caddr_t bpos, dpos, cp2;
77139488Smckusick 	int error = 0;
77239488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
77338414Smckusick 	long len;
77438414Smckusick 
77538414Smckusick 	nfsstats.rpccnt[NFSPROC_READLINK]++;
77652196Smckusick 	nfsm_reqhead(vp, NFSPROC_READLINK, NFSX_FH);
77738414Smckusick 	nfsm_fhtom(vp);
77852196Smckusick 	nfsm_request(vp, NFSPROC_READLINK, uiop->uio_procp, cred);
77938414Smckusick 	nfsm_strsiz(len, NFS_MAXPATHLEN);
78038414Smckusick 	nfsm_mtouio(uiop, len);
78138414Smckusick 	nfsm_reqdone;
78238414Smckusick 	return (error);
78338414Smckusick }
78438414Smckusick 
78538414Smckusick /*
78641905Smckusick  * nfs read rpc call
78741905Smckusick  * Ditto above
78838414Smckusick  */
78952234Sheideman int
79048054Smckusick nfs_readrpc(vp, uiop, cred)
79139488Smckusick 	register struct vnode *vp;
79238414Smckusick 	struct uio *uiop;
79338414Smckusick 	struct ucred *cred;
79438414Smckusick {
79548054Smckusick 	register u_long *tl;
79639488Smckusick 	register caddr_t cp;
79739488Smckusick 	register long t1;
79839488Smckusick 	caddr_t bpos, dpos, cp2;
79939488Smckusick 	int error = 0;
80039488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
80138414Smckusick 	struct nfsmount *nmp;
80238414Smckusick 	long len, retlen, tsiz;
80338414Smckusick 
80441398Smckusick 	nmp = VFSTONFS(vp->v_mount);
80538414Smckusick 	tsiz = uiop->uio_resid;
80656289Smckusick 	if (uiop->uio_offset + tsiz > 0xffffffff &&
80756289Smckusick 	    (nmp->nm_flag & NFSMNT_NQNFS) == 0)
80856289Smckusick 		return (EFBIG);
80938414Smckusick 	while (tsiz > 0) {
81038414Smckusick 		nfsstats.rpccnt[NFSPROC_READ]++;
81138414Smckusick 		len = (tsiz > nmp->nm_rsize) ? nmp->nm_rsize : tsiz;
81252196Smckusick 		nfsm_reqhead(vp, NFSPROC_READ, NFSX_FH+NFSX_UNSIGNED*3);
81338414Smckusick 		nfsm_fhtom(vp);
81448054Smckusick 		nfsm_build(tl, u_long *, NFSX_UNSIGNED*3);
81556289Smckusick 		if (nmp->nm_flag & NFSMNT_NQNFS) {
81656289Smckusick 			txdr_hyper(&uiop->uio_offset, tl);
81756289Smckusick 			*(tl + 2) = txdr_unsigned(len);
81856289Smckusick 		} else {
81956289Smckusick 			*tl++ = txdr_unsigned(uiop->uio_offset);
82056289Smckusick 			*tl++ = txdr_unsigned(len);
82156289Smckusick 			*tl = 0;
82256289Smckusick 		}
82352196Smckusick 		nfsm_request(vp, NFSPROC_READ, uiop->uio_procp, cred);
82438414Smckusick 		nfsm_loadattr(vp, (struct vattr *)0);
82538414Smckusick 		nfsm_strsiz(retlen, nmp->nm_rsize);
82638414Smckusick 		nfsm_mtouio(uiop, retlen);
82738414Smckusick 		m_freem(mrep);
82838414Smckusick 		if (retlen < len)
82938414Smckusick 			tsiz = 0;
83038414Smckusick 		else
83138414Smckusick 			tsiz -= len;
83238414Smckusick 	}
83338414Smckusick nfsmout:
83438414Smckusick 	return (error);
83538414Smckusick }
83638414Smckusick 
83738414Smckusick /*
83838414Smckusick  * nfs write call
83938414Smckusick  */
84052234Sheideman int
84156289Smckusick nfs_writerpc(vp, uiop, cred, ioflags)
84239488Smckusick 	register struct vnode *vp;
84338414Smckusick 	struct uio *uiop;
84438414Smckusick 	struct ucred *cred;
84556289Smckusick 	int ioflags;
84638414Smckusick {
84748054Smckusick 	register u_long *tl;
84839488Smckusick 	register caddr_t cp;
84939488Smckusick 	register long t1;
85052196Smckusick 	caddr_t bpos, dpos, cp2;
85139488Smckusick 	int error = 0;
85239488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
85338414Smckusick 	struct nfsmount *nmp;
85452196Smckusick 	struct nfsnode *np = VTONFS(vp);
85552196Smckusick 	u_quad_t frev;
85638414Smckusick 	long len, tsiz;
85738414Smckusick 
85841398Smckusick 	nmp = VFSTONFS(vp->v_mount);
85938414Smckusick 	tsiz = uiop->uio_resid;
86056289Smckusick 	if (uiop->uio_offset + tsiz > 0xffffffff &&
86156289Smckusick 	    (nmp->nm_flag & NFSMNT_NQNFS) == 0)
86256289Smckusick 		return (EFBIG);
86338414Smckusick 	while (tsiz > 0) {
86438414Smckusick 		nfsstats.rpccnt[NFSPROC_WRITE]++;
86538414Smckusick 		len = (tsiz > nmp->nm_wsize) ? nmp->nm_wsize : tsiz;
86652196Smckusick 		nfsm_reqhead(vp, NFSPROC_WRITE,
86752196Smckusick 			NFSX_FH+NFSX_UNSIGNED*4+nfsm_rndup(len));
86838414Smckusick 		nfsm_fhtom(vp);
86956289Smckusick 		nfsm_build(tl, u_long *, NFSX_UNSIGNED * 4);
87056289Smckusick 		if (nmp->nm_flag & NFSMNT_NQNFS) {
87156289Smckusick 			txdr_hyper(&uiop->uio_offset, tl);
87256289Smckusick 			tl += 2;
87356289Smckusick 			if (ioflags & IO_APPEND)
87456289Smckusick 				*tl++ = txdr_unsigned(1);
87556289Smckusick 			else
87656289Smckusick 				*tl++ = 0;
87756289Smckusick 		} else {
87856289Smckusick 			*++tl = txdr_unsigned(uiop->uio_offset);
87956289Smckusick 			tl += 2;
88056289Smckusick 		}
88156289Smckusick 		*tl = txdr_unsigned(len);
88238414Smckusick 		nfsm_uiotom(uiop, len);
88352196Smckusick 		nfsm_request(vp, NFSPROC_WRITE, uiop->uio_procp, cred);
88438414Smckusick 		nfsm_loadattr(vp, (struct vattr *)0);
88552196Smckusick 		if (nmp->nm_flag & NFSMNT_MYWRITE)
88654106Smckusick 			VTONFS(vp)->n_mtime = VTONFS(vp)->n_vattr.va_mtime.ts_sec;
88752196Smckusick 		else if ((nmp->nm_flag & NFSMNT_NQNFS) &&
88852196Smckusick 			 NQNFS_CKCACHABLE(vp, NQL_WRITE)) {
88952196Smckusick 			nfsm_dissect(tl, u_long *, 2*NFSX_UNSIGNED);
89052196Smckusick 			fxdr_hyper(tl, &frev);
89154451Smckusick 			if (frev > np->n_brev)
89252196Smckusick 				np->n_brev = frev;
89352196Smckusick 		}
89438414Smckusick 		m_freem(mrep);
89538414Smckusick 		tsiz -= len;
89638414Smckusick 	}
89738414Smckusick nfsmout:
89852196Smckusick 	if (error)
89952196Smckusick 		uiop->uio_resid = tsiz;
90038414Smckusick 	return (error);
90138414Smckusick }
90238414Smckusick 
90338414Smckusick /*
90439459Smckusick  * nfs mknod call
90542246Smckusick  * This is a kludge. Use a create rpc but with the IFMT bits of the mode
90642246Smckusick  * set to specify the file type and the size field for rdev.
90739459Smckusick  */
90839459Smckusick /* ARGSUSED */
90952234Sheideman int
91053806Smckusick nfs_mknod(ap)
91154668Smckusick 	struct vop_mknod_args /* {
91254668Smckusick 		struct vnode *a_dvp;
91354668Smckusick 		struct vnode **a_vpp;
91454668Smckusick 		struct componentname *a_cnp;
91554668Smckusick 		struct vattr *a_vap;
91654668Smckusick 	} */ *ap;
91739459Smckusick {
91853806Smckusick 	register struct vnode *dvp = ap->a_dvp;
91953806Smckusick 	register struct vattr *vap = ap->a_vap;
92053806Smckusick 	register struct componentname *cnp = ap->a_cnp;
92142246Smckusick 	register struct nfsv2_sattr *sp;
92248054Smckusick 	register u_long *tl;
92342246Smckusick 	register caddr_t cp;
92456289Smckusick 	register long t1, t2;
92556289Smckusick 	struct vnode *newvp;
92659116Smckusick 	struct vattr vattr;
92756289Smckusick 	char *cp2;
92842246Smckusick 	caddr_t bpos, dpos;
92956289Smckusick 	int error = 0, isnq;
93042246Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
93142246Smckusick 	u_long rdev;
93239459Smckusick 
93356289Smckusick 	isnq = (VFSTONFS(dvp->v_mount)->nm_flag & NFSMNT_NQNFS);
93453806Smckusick 	if (vap->va_type == VCHR || vap->va_type == VBLK)
93553806Smckusick 		rdev = txdr_unsigned(vap->va_rdev);
93642246Smckusick #ifdef FIFO
93753806Smckusick 	else if (vap->va_type == VFIFO)
93842246Smckusick 		rdev = 0xffffffff;
93942246Smckusick #endif /* FIFO */
94042246Smckusick 	else {
94153806Smckusick 		VOP_ABORTOP(dvp, cnp);
94253806Smckusick 		vput(dvp);
94342246Smckusick 		return (EOPNOTSUPP);
94442246Smckusick 	}
94559116Smckusick 	if (error = VOP_GETATTR(dvp, &vattr, cnp->cn_cred, cnp->cn_proc)) {
94659116Smckusick 		VOP_ABORTOP(dvp, cnp);
94759116Smckusick 		vput(dvp);
94859116Smckusick 		return (error);
94959116Smckusick 	}
95042246Smckusick 	nfsstats.rpccnt[NFSPROC_CREATE]++;
95153806Smckusick 	nfsm_reqhead(dvp, NFSPROC_CREATE,
95256289Smckusick 	  NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen)+NFSX_SATTR(isnq));
95353806Smckusick 	nfsm_fhtom(dvp);
95453806Smckusick 	nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
95556289Smckusick 	nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR(isnq));
95653806Smckusick 	sp->sa_mode = vtonfs_mode(vap->va_type, vap->va_mode);
95753806Smckusick 	sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid);
95859116Smckusick 	sp->sa_gid = txdr_unsigned(vattr.va_gid);
95956289Smckusick 	if (isnq) {
96056289Smckusick 		sp->sa_nqrdev = rdev;
96156289Smckusick 		sp->sa_nqflags = 0;
96256289Smckusick 		txdr_nqtime(&vap->va_atime, &sp->sa_nqatime);
96356289Smckusick 		txdr_nqtime(&vap->va_mtime, &sp->sa_nqmtime);
96456289Smckusick 	} else {
96556289Smckusick 		sp->sa_nfssize = rdev;
96656289Smckusick 		txdr_nfstime(&vap->va_atime, &sp->sa_nfsatime);
96756289Smckusick 		txdr_nfstime(&vap->va_mtime, &sp->sa_nfsmtime);
96856289Smckusick 	}
96953806Smckusick 	nfsm_request(dvp, NFSPROC_CREATE, cnp->cn_proc, cnp->cn_cred);
97056289Smckusick 	nfsm_mtofh(dvp, newvp);
97142246Smckusick 	nfsm_reqdone;
97256927Smckusick 	if (!error && (cnp->cn_flags & MAKEENTRY))
97356289Smckusick 		cache_enter(dvp, newvp, cnp);
97453806Smckusick 	FREE(cnp->cn_pnbuf, M_NAMEI);
97553806Smckusick 	VTONFS(dvp)->n_flag |= NMODIFIED;
97653806Smckusick 	vrele(dvp);
97742246Smckusick 	return (error);
97839459Smckusick }
97939459Smckusick 
98039459Smckusick /*
98138414Smckusick  * nfs file create call
98238414Smckusick  */
98352234Sheideman int
98453806Smckusick nfs_create(ap)
98554668Smckusick 	struct vop_create_args /* {
98654668Smckusick 		struct vnode *a_dvp;
98754668Smckusick 		struct vnode **a_vpp;
98854668Smckusick 		struct componentname *a_cnp;
98954668Smckusick 		struct vattr *a_vap;
99054668Smckusick 	} */ *ap;
99138414Smckusick {
99253806Smckusick 	register struct vnode *dvp = ap->a_dvp;
99353806Smckusick 	register struct vattr *vap = ap->a_vap;
99453806Smckusick 	register struct componentname *cnp = ap->a_cnp;
99538884Smacklem 	register struct nfsv2_sattr *sp;
99648054Smckusick 	register u_long *tl;
99739488Smckusick 	register caddr_t cp;
99839488Smckusick 	register long t1, t2;
99939488Smckusick 	caddr_t bpos, dpos, cp2;
100056289Smckusick 	int error = 0, isnq;
100139488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
100259116Smckusick 	struct vattr vattr;
100338414Smckusick 
100459116Smckusick 	if (error = VOP_GETATTR(dvp, &vattr, cnp->cn_cred, cnp->cn_proc)) {
100559116Smckusick 		VOP_ABORTOP(dvp, cnp);
100659116Smckusick 		vput(dvp);
100759116Smckusick 		return (error);
100859116Smckusick 	}
100938414Smckusick 	nfsstats.rpccnt[NFSPROC_CREATE]++;
101056289Smckusick 	isnq = (VFSTONFS(dvp->v_mount)->nm_flag & NFSMNT_NQNFS);
101153806Smckusick 	nfsm_reqhead(dvp, NFSPROC_CREATE,
101256289Smckusick 	  NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen)+NFSX_SATTR(isnq));
101353806Smckusick 	nfsm_fhtom(dvp);
101453806Smckusick 	nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
101556289Smckusick 	nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR(isnq));
101653806Smckusick 	sp->sa_mode = vtonfs_mode(vap->va_type, vap->va_mode);
101753806Smckusick 	sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid);
101859116Smckusick 	sp->sa_gid = txdr_unsigned(vattr.va_gid);
101956289Smckusick 	if (isnq) {
102056289Smckusick 		u_quad_t qval = 0;
102156289Smckusick 
102256289Smckusick 		txdr_hyper(&qval, &sp->sa_nqsize);
102356289Smckusick 		sp->sa_nqflags = 0;
102456289Smckusick 		sp->sa_nqrdev = -1;
102556289Smckusick 		txdr_nqtime(&vap->va_atime, &sp->sa_nqatime);
102656289Smckusick 		txdr_nqtime(&vap->va_mtime, &sp->sa_nqmtime);
102756289Smckusick 	} else {
102856289Smckusick 		sp->sa_nfssize = 0;
102956289Smckusick 		txdr_nfstime(&vap->va_atime, &sp->sa_nfsatime);
103056289Smckusick 		txdr_nfstime(&vap->va_mtime, &sp->sa_nfsmtime);
103156289Smckusick 	}
103253806Smckusick 	nfsm_request(dvp, NFSPROC_CREATE, cnp->cn_proc, cnp->cn_cred);
103353806Smckusick 	nfsm_mtofh(dvp, *ap->a_vpp);
103438414Smckusick 	nfsm_reqdone;
103556927Smckusick 	if (!error && (cnp->cn_flags & MAKEENTRY))
103656289Smckusick 		cache_enter(dvp, *ap->a_vpp, cnp);
103753806Smckusick 	FREE(cnp->cn_pnbuf, M_NAMEI);
103853806Smckusick 	VTONFS(dvp)->n_flag |= NMODIFIED;
103953806Smckusick 	vrele(dvp);
104038414Smckusick 	return (error);
104138414Smckusick }
104238414Smckusick 
104338414Smckusick /*
104438414Smckusick  * nfs file remove call
104541905Smckusick  * To try and make nfs semantics closer to ufs semantics, a file that has
104641905Smckusick  * other processes using the vnode is renamed instead of removed and then
104739341Smckusick  * removed later on the last close.
104841905Smckusick  * - If v_usecount > 1
104939341Smckusick  *	  If a rename is not already in the works
105039341Smckusick  *	     call nfs_sillyrename() to set it up
105139341Smckusick  *     else
105239341Smckusick  *	  do the remove rpc
105338414Smckusick  */
105452234Sheideman int
105553806Smckusick nfs_remove(ap)
105654451Smckusick 	struct vop_remove_args /* {
105754451Smckusick 		struct vnodeop_desc *a_desc;
105854451Smckusick 		struct vnode * a_dvp;
105954451Smckusick 		struct vnode * a_vp;
106054451Smckusick 		struct componentname * a_cnp;
106154451Smckusick 	} */ *ap;
106238414Smckusick {
106353806Smckusick 	register struct vnode *vp = ap->a_vp;
106453806Smckusick 	register struct vnode *dvp = ap->a_dvp;
106553806Smckusick 	register struct componentname *cnp = ap->a_cnp;
106653806Smckusick 	register struct nfsnode *np = VTONFS(vp);
106748054Smckusick 	register u_long *tl;
106839488Smckusick 	register caddr_t cp;
106952196Smckusick 	register long t2;
107039488Smckusick 	caddr_t bpos, dpos;
107139488Smckusick 	int error = 0;
107239488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
107338414Smckusick 
107453806Smckusick 	if (vp->v_usecount > 1) {
107539341Smckusick 		if (!np->n_sillyrename)
107653806Smckusick 			error = nfs_sillyrename(dvp, vp, cnp);
107739341Smckusick 	} else {
107852196Smckusick 		/*
107952196Smckusick 		 * Purge the name cache so that the chance of a lookup for
108052196Smckusick 		 * the name succeeding while the remove is in progress is
108152196Smckusick 		 * minimized. Without node locking it can still happen, such
108252196Smckusick 		 * that an I/O op returns ESTALE, but since you get this if
108352196Smckusick 		 * another host removes the file..
108452196Smckusick 		 */
108553806Smckusick 		cache_purge(vp);
108652196Smckusick 		/*
108752196Smckusick 		 * Throw away biocache buffers. Mainly to avoid
108852196Smckusick 		 * unnecessary delayed writes.
108952196Smckusick 		 */
109057791Smckusick 		error = nfs_vinvalbuf(vp, 0, cnp->cn_cred, cnp->cn_proc, 1);
109157791Smckusick 		if (error == EINTR)
109257791Smckusick 			return (error);
109352196Smckusick 		/* Do the rpc */
109438414Smckusick 		nfsstats.rpccnt[NFSPROC_REMOVE]++;
109553806Smckusick 		nfsm_reqhead(dvp, NFSPROC_REMOVE,
109653806Smckusick 			NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen));
109753806Smckusick 		nfsm_fhtom(dvp);
109853806Smckusick 		nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
109953806Smckusick 		nfsm_request(dvp, NFSPROC_REMOVE, cnp->cn_proc, cnp->cn_cred);
110038414Smckusick 		nfsm_reqdone;
110153806Smckusick 		FREE(cnp->cn_pnbuf, M_NAMEI);
110253806Smckusick 		VTONFS(dvp)->n_flag |= NMODIFIED;
110339751Smckusick 		/*
110439751Smckusick 		 * Kludge City: If the first reply to the remove rpc is lost..
110539751Smckusick 		 *   the reply to the retransmitted request will be ENOENT
110639751Smckusick 		 *   since the file was in fact removed
110739751Smckusick 		 *   Therefore, we cheat and return success.
110839751Smckusick 		 */
110939751Smckusick 		if (error == ENOENT)
111039751Smckusick 			error = 0;
111138414Smckusick 	}
111240042Smckusick 	np->n_attrstamp = 0;
111353806Smckusick 	vrele(dvp);
111453806Smckusick 	vrele(vp);
111538414Smckusick 	return (error);
111638414Smckusick }
111738414Smckusick 
111838414Smckusick /*
111938414Smckusick  * nfs file remove rpc called from nfs_inactive
112038414Smckusick  */
112152234Sheideman int
112254451Smckusick nfs_removeit(sp)
112348364Smckusick 	register struct sillyrename *sp;
112438414Smckusick {
112548054Smckusick 	register u_long *tl;
112639488Smckusick 	register caddr_t cp;
112752196Smckusick 	register long t2;
112839488Smckusick 	caddr_t bpos, dpos;
112939488Smckusick 	int error = 0;
113039488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
113138414Smckusick 
113238414Smckusick 	nfsstats.rpccnt[NFSPROC_REMOVE]++;
113352196Smckusick 	nfsm_reqhead(sp->s_dvp, NFSPROC_REMOVE,
113448364Smckusick 		NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(sp->s_namlen));
113548364Smckusick 	nfsm_fhtom(sp->s_dvp);
113648364Smckusick 	nfsm_strtom(sp->s_name, sp->s_namlen, NFS_MAXNAMLEN);
113754451Smckusick 	nfsm_request(sp->s_dvp, NFSPROC_REMOVE, NULL, sp->s_cred);
113838414Smckusick 	nfsm_reqdone;
113948364Smckusick 	VTONFS(sp->s_dvp)->n_flag |= NMODIFIED;
114038414Smckusick 	return (error);
114138414Smckusick }
114238414Smckusick 
114338414Smckusick /*
114438414Smckusick  * nfs file rename call
114538414Smckusick  */
114652234Sheideman int
114753806Smckusick nfs_rename(ap)
114854668Smckusick 	struct vop_rename_args  /* {
114954668Smckusick 		struct vnode *a_fdvp;
115054668Smckusick 		struct vnode *a_fvp;
115154668Smckusick 		struct componentname *a_fcnp;
115254668Smckusick 		struct vnode *a_tdvp;
115354668Smckusick 		struct vnode *a_tvp;
115454668Smckusick 		struct componentname *a_tcnp;
115554668Smckusick 	} */ *ap;
115638414Smckusick {
115753806Smckusick 	register struct vnode *fvp = ap->a_fvp;
115853806Smckusick 	register struct vnode *tvp = ap->a_tvp;
115953806Smckusick 	register struct vnode *fdvp = ap->a_fdvp;
116053806Smckusick 	register struct vnode *tdvp = ap->a_tdvp;
116153806Smckusick 	register struct componentname *tcnp = ap->a_tcnp;
116253806Smckusick 	register struct componentname *fcnp = ap->a_fcnp;
116348054Smckusick 	register u_long *tl;
116439488Smckusick 	register caddr_t cp;
116552196Smckusick 	register long t2;
116639488Smckusick 	caddr_t bpos, dpos;
116739488Smckusick 	int error = 0;
116839488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
116938414Smckusick 
117053804Spendry 	/* Check for cross-device rename */
117153806Smckusick 	if ((fvp->v_mount != tdvp->v_mount) ||
117253806Smckusick 	    (tvp && (fvp->v_mount != tvp->v_mount))) {
117353804Spendry 		error = EXDEV;
117453804Spendry 		goto out;
117553804Spendry 	}
117653804Spendry 
117753804Spendry 
117838414Smckusick 	nfsstats.rpccnt[NFSPROC_RENAME]++;
117953806Smckusick 	nfsm_reqhead(fdvp, NFSPROC_RENAME,
118053806Smckusick 		(NFSX_FH+NFSX_UNSIGNED)*2+nfsm_rndup(fcnp->cn_namelen)+
118153806Smckusick 		nfsm_rndup(fcnp->cn_namelen)); /* or fcnp->cn_cred?*/
118253806Smckusick 	nfsm_fhtom(fdvp);
118353806Smckusick 	nfsm_strtom(fcnp->cn_nameptr, fcnp->cn_namelen, NFS_MAXNAMLEN);
118453806Smckusick 	nfsm_fhtom(tdvp);
118553806Smckusick 	nfsm_strtom(tcnp->cn_nameptr, tcnp->cn_namelen, NFS_MAXNAMLEN);
118653806Smckusick 	nfsm_request(fdvp, NFSPROC_RENAME, tcnp->cn_proc, tcnp->cn_cred);
118738414Smckusick 	nfsm_reqdone;
118853806Smckusick 	VTONFS(fdvp)->n_flag |= NMODIFIED;
118953806Smckusick 	VTONFS(tdvp)->n_flag |= NMODIFIED;
119053806Smckusick 	if (fvp->v_type == VDIR) {
119153806Smckusick 		if (tvp != NULL && tvp->v_type == VDIR)
119253806Smckusick 			cache_purge(tdvp);
119353806Smckusick 		cache_purge(fdvp);
119438414Smckusick 	}
119553804Spendry out:
119653806Smckusick 	if (tdvp == tvp)
119753806Smckusick 		vrele(tdvp);
119843360Smckusick 	else
119953806Smckusick 		vput(tdvp);
120053806Smckusick 	if (tvp)
120153806Smckusick 		vput(tvp);
120253806Smckusick 	vrele(fdvp);
120353806Smckusick 	vrele(fvp);
120440112Smckusick 	/*
120540112Smckusick 	 * Kludge: Map ENOENT => 0 assuming that it is a reply to a retry.
120640112Smckusick 	 */
120740112Smckusick 	if (error == ENOENT)
120840112Smckusick 		error = 0;
120938414Smckusick 	return (error);
121038414Smckusick }
121138414Smckusick 
121238414Smckusick /*
121341905Smckusick  * nfs file rename rpc called from nfs_remove() above
121438414Smckusick  */
121552234Sheideman int
121652234Sheideman nfs_renameit(sdvp, scnp, sp)
121752234Sheideman 	struct vnode *sdvp;
121852234Sheideman 	struct componentname *scnp;
121948364Smckusick 	register struct sillyrename *sp;
122038414Smckusick {
122148054Smckusick 	register u_long *tl;
122239488Smckusick 	register caddr_t cp;
122352196Smckusick 	register long t2;
122439488Smckusick 	caddr_t bpos, dpos;
122539488Smckusick 	int error = 0;
122639488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
122738414Smckusick 
122838414Smckusick 	nfsstats.rpccnt[NFSPROC_RENAME]++;
122952234Sheideman 	nfsm_reqhead(sdvp, NFSPROC_RENAME,
123052234Sheideman 		(NFSX_FH+NFSX_UNSIGNED)*2+nfsm_rndup(scnp->cn_namelen)+
123152196Smckusick 		nfsm_rndup(sp->s_namlen));
123252234Sheideman 	nfsm_fhtom(sdvp);
123352234Sheideman 	nfsm_strtom(scnp->cn_nameptr, scnp->cn_namelen, NFS_MAXNAMLEN);
123452234Sheideman 	nfsm_fhtom(sdvp);
123548364Smckusick 	nfsm_strtom(sp->s_name, sp->s_namlen, NFS_MAXNAMLEN);
123652234Sheideman 	nfsm_request(sdvp, NFSPROC_RENAME, scnp->cn_proc, scnp->cn_cred);
123738414Smckusick 	nfsm_reqdone;
123852234Sheideman 	FREE(scnp->cn_pnbuf, M_NAMEI);
123952234Sheideman 	VTONFS(sdvp)->n_flag |= NMODIFIED;
124038414Smckusick 	return (error);
124138414Smckusick }
124238414Smckusick 
124338414Smckusick /*
124438414Smckusick  * nfs hard link create call
124538414Smckusick  */
124652234Sheideman int
124753806Smckusick nfs_link(ap)
124854668Smckusick 	struct vop_link_args /* {
124954668Smckusick 		struct vnode *a_vp;
125054668Smckusick 		struct vnode *a_tdvp;
125154668Smckusick 		struct componentname *a_cnp;
125254668Smckusick 	} */ *ap;
125338414Smckusick {
125453806Smckusick 	register struct vnode *vp = ap->a_vp;
125553806Smckusick 	register struct vnode *tdvp = ap->a_tdvp;
125653806Smckusick 	register struct componentname *cnp = ap->a_cnp;
125748054Smckusick 	register u_long *tl;
125839488Smckusick 	register caddr_t cp;
125952196Smckusick 	register long t2;
126039488Smckusick 	caddr_t bpos, dpos;
126139488Smckusick 	int error = 0;
126239488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
126338414Smckusick 
126453806Smckusick 	if (vp->v_mount != tdvp->v_mount) {
126553806Smckusick 		/*VOP_ABORTOP(vp, cnp);*/
126653806Smckusick 		if (tdvp == vp)
126753806Smckusick 			vrele(vp);
126853804Spendry 		else
126953806Smckusick 			vput(vp);
127053804Spendry 		return (EXDEV);
127153804Spendry 	}
127253804Spendry 
127338414Smckusick 	nfsstats.rpccnt[NFSPROC_LINK]++;
127453806Smckusick 	nfsm_reqhead(tdvp, NFSPROC_LINK,
127553806Smckusick 		NFSX_FH*2+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen));
127653806Smckusick 	nfsm_fhtom(tdvp);
127753806Smckusick 	nfsm_fhtom(vp);
127853806Smckusick 	nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
127953806Smckusick 	nfsm_request(tdvp, NFSPROC_LINK, cnp->cn_proc, cnp->cn_cred);
128038414Smckusick 	nfsm_reqdone;
128153806Smckusick 	FREE(cnp->cn_pnbuf, M_NAMEI);
128253806Smckusick 	VTONFS(tdvp)->n_attrstamp = 0;
128353806Smckusick 	VTONFS(vp)->n_flag |= NMODIFIED;
128453806Smckusick 	vrele(vp);
128540112Smckusick 	/*
128640112Smckusick 	 * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry.
128740112Smckusick 	 */
128840112Smckusick 	if (error == EEXIST)
128940112Smckusick 		error = 0;
129038414Smckusick 	return (error);
129138414Smckusick }
129238414Smckusick 
129338414Smckusick /*
129438414Smckusick  * nfs symbolic link create call
129538414Smckusick  */
129652234Sheideman /* start here */
129752234Sheideman int
129853806Smckusick nfs_symlink(ap)
129954668Smckusick 	struct vop_symlink_args /* {
130054668Smckusick 		struct vnode *a_dvp;
130154668Smckusick 		struct vnode **a_vpp;
130254668Smckusick 		struct componentname *a_cnp;
130354668Smckusick 		struct vattr *a_vap;
130454668Smckusick 		char *a_target;
130554668Smckusick 	} */ *ap;
130638414Smckusick {
130753806Smckusick 	register struct vnode *dvp = ap->a_dvp;
130853806Smckusick 	register struct vattr *vap = ap->a_vap;
130953806Smckusick 	register struct componentname *cnp = ap->a_cnp;
131038884Smacklem 	register struct nfsv2_sattr *sp;
131148054Smckusick 	register u_long *tl;
131239488Smckusick 	register caddr_t cp;
131352196Smckusick 	register long t2;
131439488Smckusick 	caddr_t bpos, dpos;
131556289Smckusick 	int slen, error = 0, isnq;
131639488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
131738414Smckusick 
131838414Smckusick 	nfsstats.rpccnt[NFSPROC_SYMLINK]++;
131953600Sheideman 	slen = strlen(ap->a_target);
132056289Smckusick 	isnq = (VFSTONFS(dvp->v_mount)->nm_flag & NFSMNT_NQNFS);
132153806Smckusick 	nfsm_reqhead(dvp, NFSPROC_SYMLINK, NFSX_FH+2*NFSX_UNSIGNED+
132256289Smckusick 	    nfsm_rndup(cnp->cn_namelen)+nfsm_rndup(slen)+NFSX_SATTR(isnq));
132353806Smckusick 	nfsm_fhtom(dvp);
132453806Smckusick 	nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
132553600Sheideman 	nfsm_strtom(ap->a_target, slen, NFS_MAXPATHLEN);
132656289Smckusick 	nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR(isnq));
132753806Smckusick 	sp->sa_mode = vtonfs_mode(VLNK, vap->va_mode);
132853806Smckusick 	sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid);
132953806Smckusick 	sp->sa_gid = txdr_unsigned(cnp->cn_cred->cr_gid);
133056289Smckusick 	if (isnq) {
133156289Smckusick 		quad_t qval = -1;
133256289Smckusick 
133356289Smckusick 		txdr_hyper(&qval, &sp->sa_nqsize);
133456289Smckusick 		sp->sa_nqflags = 0;
133556289Smckusick 		txdr_nqtime(&vap->va_atime, &sp->sa_nqatime);
133656289Smckusick 		txdr_nqtime(&vap->va_mtime, &sp->sa_nqmtime);
133756289Smckusick 	} else {
133856289Smckusick 		sp->sa_nfssize = -1;
133956289Smckusick 		txdr_nfstime(&vap->va_atime, &sp->sa_nfsatime);
134056289Smckusick 		txdr_nfstime(&vap->va_mtime, &sp->sa_nfsmtime);
134156289Smckusick 	}
134253806Smckusick 	nfsm_request(dvp, NFSPROC_SYMLINK, cnp->cn_proc, cnp->cn_cred);
134338414Smckusick 	nfsm_reqdone;
134453806Smckusick 	FREE(cnp->cn_pnbuf, M_NAMEI);
134553806Smckusick 	VTONFS(dvp)->n_flag |= NMODIFIED;
134653806Smckusick 	vrele(dvp);
134740112Smckusick 	/*
134840112Smckusick 	 * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry.
134940112Smckusick 	 */
135040112Smckusick 	if (error == EEXIST)
135140112Smckusick 		error = 0;
135238414Smckusick 	return (error);
135338414Smckusick }
135438414Smckusick 
135538414Smckusick /*
135638414Smckusick  * nfs make dir call
135738414Smckusick  */
135852234Sheideman int
135953806Smckusick nfs_mkdir(ap)
136054668Smckusick 	struct vop_mkdir_args /* {
136154668Smckusick 		struct vnode *a_dvp;
136254668Smckusick 		struct vnode **a_vpp;
136354668Smckusick 		struct componentname *a_cnp;
136454668Smckusick 		struct vattr *a_vap;
136554668Smckusick 	} */ *ap;
136638414Smckusick {
136753806Smckusick 	register struct vnode *dvp = ap->a_dvp;
136853806Smckusick 	register struct vattr *vap = ap->a_vap;
136953806Smckusick 	register struct componentname *cnp = ap->a_cnp;
137054668Smckusick 	register struct vnode **vpp = ap->a_vpp;
137138884Smacklem 	register struct nfsv2_sattr *sp;
137248054Smckusick 	register u_long *tl;
137339488Smckusick 	register caddr_t cp;
137439488Smckusick 	register long t1, t2;
137541905Smckusick 	register int len;
137639488Smckusick 	caddr_t bpos, dpos, cp2;
137756289Smckusick 	int error = 0, firsttry = 1, isnq;
137839488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
137959116Smckusick 	struct vattr vattr;
138038414Smckusick 
138159116Smckusick 	if (error = VOP_GETATTR(dvp, &vattr, cnp->cn_cred, cnp->cn_proc)) {
138259116Smckusick 		VOP_ABORTOP(dvp, cnp);
138359116Smckusick 		vput(dvp);
138459116Smckusick 		return (error);
138559116Smckusick 	}
138653806Smckusick 	len = cnp->cn_namelen;
138756289Smckusick 	isnq = (VFSTONFS(dvp->v_mount)->nm_flag & NFSMNT_NQNFS);
138838414Smckusick 	nfsstats.rpccnt[NFSPROC_MKDIR]++;
138953806Smckusick 	nfsm_reqhead(dvp, NFSPROC_MKDIR,
139056289Smckusick 	  NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len)+NFSX_SATTR(isnq));
139153806Smckusick 	nfsm_fhtom(dvp);
139253806Smckusick 	nfsm_strtom(cnp->cn_nameptr, len, NFS_MAXNAMLEN);
139356289Smckusick 	nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR(isnq));
139453806Smckusick 	sp->sa_mode = vtonfs_mode(VDIR, vap->va_mode);
139553806Smckusick 	sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid);
139659116Smckusick 	sp->sa_gid = txdr_unsigned(vattr.va_gid);
139756289Smckusick 	if (isnq) {
139856289Smckusick 		quad_t qval = -1;
139956289Smckusick 
140056289Smckusick 		txdr_hyper(&qval, &sp->sa_nqsize);
140156289Smckusick 		sp->sa_nqflags = 0;
140256289Smckusick 		txdr_nqtime(&vap->va_atime, &sp->sa_nqatime);
140356289Smckusick 		txdr_nqtime(&vap->va_mtime, &sp->sa_nqmtime);
140456289Smckusick 	} else {
140556289Smckusick 		sp->sa_nfssize = -1;
140656289Smckusick 		txdr_nfstime(&vap->va_atime, &sp->sa_nfsatime);
140756289Smckusick 		txdr_nfstime(&vap->va_mtime, &sp->sa_nfsmtime);
140856289Smckusick 	}
140953806Smckusick 	nfsm_request(dvp, NFSPROC_MKDIR, cnp->cn_proc, cnp->cn_cred);
141054668Smckusick 	nfsm_mtofh(dvp, *vpp);
141138414Smckusick 	nfsm_reqdone;
141253806Smckusick 	VTONFS(dvp)->n_flag |= NMODIFIED;
141340112Smckusick 	/*
141441905Smckusick 	 * Kludge: Map EEXIST => 0 assuming that you have a reply to a retry
141541905Smckusick 	 * if we can succeed in looking up the directory.
141641905Smckusick 	 * "firsttry" is necessary since the macros may "goto nfsmout" which
141741905Smckusick 	 * is above the if on errors. (Ugh)
141840112Smckusick 	 */
141941905Smckusick 	if (error == EEXIST && firsttry) {
142041905Smckusick 		firsttry = 0;
142140112Smckusick 		error = 0;
142241905Smckusick 		nfsstats.rpccnt[NFSPROC_LOOKUP]++;
142354668Smckusick 		*vpp = NULL;
142453806Smckusick 		nfsm_reqhead(dvp, NFSPROC_LOOKUP,
142541905Smckusick 		    NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len));
142653806Smckusick 		nfsm_fhtom(dvp);
142753806Smckusick 		nfsm_strtom(cnp->cn_nameptr, len, NFS_MAXNAMLEN);
142853806Smckusick 		nfsm_request(dvp, NFSPROC_LOOKUP, cnp->cn_proc, cnp->cn_cred);
142954668Smckusick 		nfsm_mtofh(dvp, *vpp);
143054668Smckusick 		if ((*vpp)->v_type != VDIR) {
143154668Smckusick 			vput(*vpp);
143241905Smckusick 			error = EEXIST;
143341905Smckusick 		}
143441905Smckusick 		m_freem(mrep);
143541905Smckusick 	}
143653806Smckusick 	FREE(cnp->cn_pnbuf, M_NAMEI);
143753806Smckusick 	vrele(dvp);
143838414Smckusick 	return (error);
143938414Smckusick }
144038414Smckusick 
144138414Smckusick /*
144238414Smckusick  * nfs remove directory call
144338414Smckusick  */
144452234Sheideman int
144553806Smckusick nfs_rmdir(ap)
144654668Smckusick 	struct vop_rmdir_args /* {
144754668Smckusick 		struct vnode *a_dvp;
144854668Smckusick 		struct vnode *a_vp;
144954668Smckusick 		struct componentname *a_cnp;
145054668Smckusick 	} */ *ap;
145138414Smckusick {
145253806Smckusick 	register struct vnode *vp = ap->a_vp;
145353806Smckusick 	register struct vnode *dvp = ap->a_dvp;
145453806Smckusick 	register struct componentname *cnp = ap->a_cnp;
145548054Smckusick 	register u_long *tl;
145639488Smckusick 	register caddr_t cp;
145752196Smckusick 	register long t2;
145839488Smckusick 	caddr_t bpos, dpos;
145939488Smckusick 	int error = 0;
146039488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
146138414Smckusick 
146253806Smckusick 	if (dvp == vp) {
146353806Smckusick 		vrele(dvp);
146453806Smckusick 		vrele(dvp);
146553806Smckusick 		FREE(cnp->cn_pnbuf, M_NAMEI);
146638414Smckusick 		return (EINVAL);
146738414Smckusick 	}
146838414Smckusick 	nfsstats.rpccnt[NFSPROC_RMDIR]++;
146953806Smckusick 	nfsm_reqhead(dvp, NFSPROC_RMDIR,
147053806Smckusick 		NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen));
147153806Smckusick 	nfsm_fhtom(dvp);
147253806Smckusick 	nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
147353806Smckusick 	nfsm_request(dvp, NFSPROC_RMDIR, cnp->cn_proc, cnp->cn_cred);
147438414Smckusick 	nfsm_reqdone;
147553806Smckusick 	FREE(cnp->cn_pnbuf, M_NAMEI);
147653806Smckusick 	VTONFS(dvp)->n_flag |= NMODIFIED;
147753806Smckusick 	cache_purge(dvp);
147853806Smckusick 	cache_purge(vp);
147953806Smckusick 	vrele(vp);
148053806Smckusick 	vrele(dvp);
148140112Smckusick 	/*
148240112Smckusick 	 * Kludge: Map ENOENT => 0 assuming that you have a reply to a retry.
148340112Smckusick 	 */
148440112Smckusick 	if (error == ENOENT)
148540112Smckusick 		error = 0;
148638414Smckusick 	return (error);
148738414Smckusick }
148838414Smckusick 
148938414Smckusick /*
149038414Smckusick  * nfs readdir call
149138414Smckusick  * Although cookie is defined as opaque, I translate it to/from net byte
149238414Smckusick  * order so that it looks more sensible. This appears consistent with the
149338414Smckusick  * Ultrix implementation of NFS.
149438414Smckusick  */
149552234Sheideman int
149653806Smckusick nfs_readdir(ap)
149754668Smckusick 	struct vop_readdir_args /* {
149854668Smckusick 		struct vnode *a_vp;
149954668Smckusick 		struct uio *a_uio;
150054668Smckusick 		struct ucred *a_cred;
150154668Smckusick 	} */ *ap;
150238414Smckusick {
150353806Smckusick 	register struct vnode *vp = ap->a_vp;
150453806Smckusick 	register struct nfsnode *np = VTONFS(vp);
150553806Smckusick 	register struct uio *uio = ap->a_uio;
150641905Smckusick 	int tresid, error;
150741905Smckusick 	struct vattr vattr;
150841905Smckusick 
150953806Smckusick 	if (vp->v_type != VDIR)
151041905Smckusick 		return (EPERM);
151141905Smckusick 	/*
151241905Smckusick 	 * First, check for hit on the EOF offset cache
151341905Smckusick 	 */
151453806Smckusick 	if (uio->uio_offset != 0 && uio->uio_offset == np->n_direofoffset &&
151552196Smckusick 	    (np->n_flag & NMODIFIED) == 0) {
151653806Smckusick 		if (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) {
151753806Smckusick 			if (NQNFS_CKCACHABLE(vp, NQL_READ)) {
151852196Smckusick 				nfsstats.direofcache_hits++;
151952196Smckusick 				return (0);
152052196Smckusick 			}
152153806Smckusick 		} else if (VOP_GETATTR(vp, &vattr, ap->a_cred, uio->uio_procp) == 0 &&
152254106Smckusick 			np->n_mtime == vattr.va_mtime.ts_sec) {
152352196Smckusick 			nfsstats.direofcache_hits++;
152452196Smckusick 			return (0);
152552196Smckusick 		}
152641905Smckusick 	}
152741905Smckusick 
152841905Smckusick 	/*
152941905Smckusick 	 * Call nfs_bioread() to do the real work.
153041905Smckusick 	 */
153153806Smckusick 	tresid = uio->uio_resid;
153253806Smckusick 	error = nfs_bioread(vp, uio, 0, ap->a_cred);
153341905Smckusick 
153454451Smckusick 	if (!error && uio->uio_resid == tresid)
153541905Smckusick 		nfsstats.direofcache_misses++;
153641905Smckusick 	return (error);
153741905Smckusick }
153841905Smckusick 
153941905Smckusick /*
154041905Smckusick  * Readdir rpc call.
154141905Smckusick  * Called from below the buffer cache by nfs_doio().
154241905Smckusick  */
154352234Sheideman int
154448054Smckusick nfs_readdirrpc(vp, uiop, cred)
154541905Smckusick 	register struct vnode *vp;
154641905Smckusick 	struct uio *uiop;
154741905Smckusick 	struct ucred *cred;
154841905Smckusick {
154938414Smckusick 	register long len;
155054740Smckusick 	register struct dirent *dp;
155148054Smckusick 	register u_long *tl;
155239488Smckusick 	register caddr_t cp;
155339488Smckusick 	register long t1;
155441905Smckusick 	long tlen, lastlen;
155539488Smckusick 	caddr_t bpos, dpos, cp2;
155639488Smckusick 	int error = 0;
155739488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
155838414Smckusick 	struct mbuf *md2;
155938414Smckusick 	caddr_t dpos2;
156038414Smckusick 	int siz;
156140296Smckusick 	int more_dirs = 1;
156256289Smckusick 	u_long off, savoff;
156354740Smckusick 	struct dirent *savdp;
156440296Smckusick 	struct nfsmount *nmp;
156540296Smckusick 	struct nfsnode *np = VTONFS(vp);
156640296Smckusick 	long tresid;
156738414Smckusick 
156841398Smckusick 	nmp = VFSTONFS(vp->v_mount);
156940296Smckusick 	tresid = uiop->uio_resid;
157040296Smckusick 	/*
157140296Smckusick 	 * Loop around doing readdir rpc's of size uio_resid or nm_rsize,
157248054Smckusick 	 * whichever is smaller, truncated to a multiple of NFS_DIRBLKSIZ.
157341905Smckusick 	 * The stopping criteria is EOF or buffer full.
157440296Smckusick 	 */
157548054Smckusick 	while (more_dirs && uiop->uio_resid >= NFS_DIRBLKSIZ) {
157640296Smckusick 		nfsstats.rpccnt[NFSPROC_READDIR]++;
157752196Smckusick 		nfsm_reqhead(vp, NFSPROC_READDIR,
157856289Smckusick 			NFSX_FH + 2 * NFSX_UNSIGNED);
157940296Smckusick 		nfsm_fhtom(vp);
158056289Smckusick 		nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED);
158156289Smckusick 		off = (u_long)uiop->uio_offset;
158256289Smckusick 		*tl++ = txdr_unsigned(off);
158348054Smckusick 		*tl = txdr_unsigned(((uiop->uio_resid > nmp->nm_rsize) ?
158448054Smckusick 			nmp->nm_rsize : uiop->uio_resid) & ~(NFS_DIRBLKSIZ-1));
158552196Smckusick 		nfsm_request(vp, NFSPROC_READDIR, uiop->uio_procp, cred);
158640296Smckusick 		siz = 0;
158752196Smckusick 		nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
158848054Smckusick 		more_dirs = fxdr_unsigned(int, *tl);
158940296Smckusick 
159040296Smckusick 		/* Save the position so that we can do nfsm_mtouio() later */
159140296Smckusick 		dpos2 = dpos;
159240296Smckusick 		md2 = md;
159340296Smckusick 
159440296Smckusick 		/* loop thru the dir entries, doctoring them to 4bsd form */
159542246Smckusick #ifdef lint
159654740Smckusick 		dp = (struct dirent *)0;
159742246Smckusick #endif /* lint */
159840296Smckusick 		while (more_dirs && siz < uiop->uio_resid) {
159940296Smckusick 			savoff = off;		/* Hold onto offset and dp */
160040296Smckusick 			savdp = dp;
160156289Smckusick 			nfsm_dissecton(tl, u_long *, 2 * NFSX_UNSIGNED);
160254740Smckusick 			dp = (struct dirent *)tl;
160354740Smckusick 			dp->d_fileno = fxdr_unsigned(u_long, *tl++);
160448054Smckusick 			len = fxdr_unsigned(int, *tl);
160540296Smckusick 			if (len <= 0 || len > NFS_MAXNAMLEN) {
160640296Smckusick 				error = EBADRPC;
160740296Smckusick 				m_freem(mrep);
160840296Smckusick 				goto nfsmout;
160940296Smckusick 			}
161054986Smckusick 			dp->d_namlen = (u_char)len;
161154986Smckusick 			dp->d_type = DT_UNKNOWN;
161240296Smckusick 			nfsm_adv(len);		/* Point past name */
161340296Smckusick 			tlen = nfsm_rndup(len);
161440296Smckusick 			/*
161540296Smckusick 			 * This should not be necessary, but some servers have
161640296Smckusick 			 * broken XDR such that these bytes are not null filled.
161740296Smckusick 			 */
161840296Smckusick 			if (tlen != len) {
161940296Smckusick 				*dpos = '\0';	/* Null-terminate */
162040296Smckusick 				nfsm_adv(tlen - len);
162140296Smckusick 				len = tlen;
162240296Smckusick 			}
162356289Smckusick 			nfsm_dissecton(tl, u_long *, 2 * NFSX_UNSIGNED);
162454986Smckusick 			off = fxdr_unsigned(u_long, *tl);
162548054Smckusick 			*tl++ = 0;	/* Ensures null termination of name */
162648054Smckusick 			more_dirs = fxdr_unsigned(int, *tl);
162756289Smckusick 			dp->d_reclen = len + 4 * NFSX_UNSIGNED;
162840296Smckusick 			siz += dp->d_reclen;
162940296Smckusick 		}
163040296Smckusick 		/*
163140296Smckusick 		 * If at end of rpc data, get the eof boolean
163240296Smckusick 		 */
163340296Smckusick 		if (!more_dirs) {
163452196Smckusick 			nfsm_dissecton(tl, u_long *, NFSX_UNSIGNED);
163548054Smckusick 			more_dirs = (fxdr_unsigned(int, *tl) == 0);
163638414Smckusick 
163740296Smckusick 			/*
163840296Smckusick 			 * If at EOF, cache directory offset
163940296Smckusick 			 */
164041905Smckusick 			if (!more_dirs)
164140296Smckusick 				np->n_direofoffset = off;
164238414Smckusick 		}
164340296Smckusick 		/*
164440296Smckusick 		 * If there is too much to fit in the data buffer, use savoff and
164540296Smckusick 		 * savdp to trim off the last record.
164640296Smckusick 		 * --> we are not at eof
164740296Smckusick 		 */
164840296Smckusick 		if (siz > uiop->uio_resid) {
164940296Smckusick 			off = savoff;
165040296Smckusick 			siz -= dp->d_reclen;
165140296Smckusick 			dp = savdp;
165240296Smckusick 			more_dirs = 0;	/* Paranoia */
165340113Smckusick 		}
165440296Smckusick 		if (siz > 0) {
165541905Smckusick 			lastlen = dp->d_reclen;
165640296Smckusick 			md = md2;
165740296Smckusick 			dpos = dpos2;
165840296Smckusick 			nfsm_mtouio(uiop, siz);
165956289Smckusick 			uiop->uio_offset = (off_t)off;
166040296Smckusick 		} else
166140296Smckusick 			more_dirs = 0;	/* Ugh, never happens, but in case.. */
166240296Smckusick 		m_freem(mrep);
166338414Smckusick 	}
166441905Smckusick 	/*
166548054Smckusick 	 * Fill last record, iff any, out to a multiple of NFS_DIRBLKSIZ
166641905Smckusick 	 * by increasing d_reclen for the last record.
166741905Smckusick 	 */
166841905Smckusick 	if (uiop->uio_resid < tresid) {
166948054Smckusick 		len = uiop->uio_resid & (NFS_DIRBLKSIZ - 1);
167041905Smckusick 		if (len > 0) {
167154740Smckusick 			dp = (struct dirent *)
167241905Smckusick 				(uiop->uio_iov->iov_base - lastlen);
167341905Smckusick 			dp->d_reclen += len;
167441905Smckusick 			uiop->uio_iov->iov_base += len;
167541905Smckusick 			uiop->uio_iov->iov_len -= len;
167641905Smckusick 			uiop->uio_resid -= len;
167741905Smckusick 		}
167841905Smckusick 	}
167940296Smckusick nfsmout:
168038414Smckusick 	return (error);
168138414Smckusick }
168238414Smckusick 
168352196Smckusick /*
168456289Smckusick  * Nqnfs readdir_and_lookup RPC. Used in place of nfs_readdirrpc().
168552196Smckusick  */
168652234Sheideman int
168752196Smckusick nfs_readdirlookrpc(vp, uiop, cred)
168852196Smckusick 	struct vnode *vp;
168952196Smckusick 	register struct uio *uiop;
169052196Smckusick 	struct ucred *cred;
169152196Smckusick {
169252196Smckusick 	register int len;
169354740Smckusick 	register struct dirent *dp;
169452196Smckusick 	register u_long *tl;
169552196Smckusick 	register caddr_t cp;
169652196Smckusick 	register long t1;
169752196Smckusick 	caddr_t bpos, dpos, cp2;
169852196Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
169952196Smckusick 	struct nameidata nami, *ndp = &nami;
170052317Sheideman 	struct componentname *cnp = &ndp->ni_cnd;
170156289Smckusick 	u_long off, endoff, fileno;
170252196Smckusick 	time_t reqtime, ltime;
170352196Smckusick 	struct nfsmount *nmp;
170452196Smckusick 	struct nfsnode *np, *tp;
170552196Smckusick 	struct vnode *newvp;
170652196Smckusick 	nfsv2fh_t *fhp;
170752196Smckusick 	u_quad_t frev;
170852196Smckusick 	int error = 0, tlen, more_dirs = 1, tresid, doit, bigenough, i;
170952196Smckusick 	int cachable;
171052196Smckusick 
171152196Smckusick 	if (uiop->uio_iovcnt != 1)
171252196Smckusick 		panic("nfs rdirlook");
171352196Smckusick 	nmp = VFSTONFS(vp->v_mount);
171452196Smckusick 	tresid = uiop->uio_resid;
171552196Smckusick 	ndp->ni_dvp = vp;
171652196Smckusick 	newvp = NULLVP;
171752196Smckusick 	/*
171852196Smckusick 	 * Loop around doing readdir rpc's of size uio_resid or nm_rsize,
171952196Smckusick 	 * whichever is smaller, truncated to a multiple of NFS_DIRBLKSIZ.
172052196Smckusick 	 * The stopping criteria is EOF or buffer full.
172152196Smckusick 	 */
172252196Smckusick 	while (more_dirs && uiop->uio_resid >= NFS_DIRBLKSIZ) {
172352196Smckusick 		nfsstats.rpccnt[NQNFSPROC_READDIRLOOK]++;
172452196Smckusick 		nfsm_reqhead(vp, NQNFSPROC_READDIRLOOK,
172556289Smckusick 			NFSX_FH + 3 * NFSX_UNSIGNED);
172652196Smckusick 		nfsm_fhtom(vp);
172756289Smckusick  		nfsm_build(tl, u_long *, 3 * NFSX_UNSIGNED);
172856289Smckusick 		off = (u_long)uiop->uio_offset;
172956289Smckusick 		*tl++ = txdr_unsigned(off);
173052196Smckusick 		*tl++ = txdr_unsigned(((uiop->uio_resid > nmp->nm_rsize) ?
173152196Smckusick 			nmp->nm_rsize : uiop->uio_resid) & ~(NFS_DIRBLKSIZ-1));
173256289Smckusick 		if (nmp->nm_flag & NFSMNT_NQLOOKLEASE)
173356289Smckusick 			*tl = txdr_unsigned(nmp->nm_leaseterm);
173456289Smckusick 		else
173556289Smckusick 			*tl = 0;
173652196Smckusick 		reqtime = time.tv_sec;
173752196Smckusick 		nfsm_request(vp, NQNFSPROC_READDIRLOOK, uiop->uio_procp, cred);
173852196Smckusick 		nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
173952196Smckusick 		more_dirs = fxdr_unsigned(int, *tl);
174052196Smckusick 
174152196Smckusick 		/* loop thru the dir entries, doctoring them to 4bsd form */
174252196Smckusick 		bigenough = 1;
174352196Smckusick 		while (more_dirs && bigenough) {
174452196Smckusick 			doit = 1;
174556289Smckusick 			nfsm_dissect(tl, u_long *, 4 * NFSX_UNSIGNED);
174656289Smckusick 			if (nmp->nm_flag & NFSMNT_NQLOOKLEASE) {
174756289Smckusick 				cachable = fxdr_unsigned(int, *tl++);
174856289Smckusick 				ltime = reqtime + fxdr_unsigned(int, *tl++);
174956289Smckusick 				fxdr_hyper(tl, &frev);
175056289Smckusick 			}
175152196Smckusick 			nfsm_dissect(fhp, nfsv2fh_t *, NFSX_FH);
175252196Smckusick 			if (!bcmp(VTONFS(vp)->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) {
175352196Smckusick 				VREF(vp);
175452196Smckusick 				newvp = vp;
175552196Smckusick 				np = VTONFS(vp);
175652196Smckusick 			} else {
175752196Smckusick 				if (error = nfs_nget(vp->v_mount, fhp, &np))
175852196Smckusick 					doit = 0;
175952196Smckusick 				newvp = NFSTOV(np);
176052196Smckusick 			}
176152196Smckusick 			if (error = nfs_loadattrcache(&newvp, &md, &dpos,
176252196Smckusick 				(struct vattr *)0))
176352196Smckusick 				doit = 0;
176456289Smckusick 			nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
176552196Smckusick 			fileno = fxdr_unsigned(u_long, *tl++);
176652196Smckusick 			len = fxdr_unsigned(int, *tl);
176752196Smckusick 			if (len <= 0 || len > NFS_MAXNAMLEN) {
176852196Smckusick 				error = EBADRPC;
176952196Smckusick 				m_freem(mrep);
177052196Smckusick 				goto nfsmout;
177152196Smckusick 			}
177252196Smckusick 			tlen = (len + 4) & ~0x3;
177352196Smckusick 			if ((tlen + DIRHDSIZ) > uiop->uio_resid)
177452196Smckusick 				bigenough = 0;
177552196Smckusick 			if (bigenough && doit) {
177654740Smckusick 				dp = (struct dirent *)uiop->uio_iov->iov_base;
177754740Smckusick 				dp->d_fileno = fileno;
177852196Smckusick 				dp->d_namlen = len;
177952196Smckusick 				dp->d_reclen = tlen + DIRHDSIZ;
178054986Smckusick 				dp->d_type =
178154986Smckusick 				    IFTODT(VTTOIF(np->n_vattr.va_type));
178252196Smckusick 				uiop->uio_resid -= DIRHDSIZ;
178352196Smckusick 				uiop->uio_iov->iov_base += DIRHDSIZ;
178452196Smckusick 				uiop->uio_iov->iov_len -= DIRHDSIZ;
178552317Sheideman 				cnp->cn_nameptr = uiop->uio_iov->iov_base;
178652317Sheideman 				cnp->cn_namelen = len;
178752196Smckusick 				ndp->ni_vp = newvp;
178852196Smckusick 				nfsm_mtouio(uiop, len);
178952196Smckusick 				cp = uiop->uio_iov->iov_base;
179052196Smckusick 				tlen -= len;
179152196Smckusick 				for (i = 0; i < tlen; i++)
179252196Smckusick 					*cp++ = '\0';
179352196Smckusick 				uiop->uio_iov->iov_base += tlen;
179452196Smckusick 				uiop->uio_iov->iov_len -= tlen;
179552196Smckusick 				uiop->uio_resid -= tlen;
179652317Sheideman 				cnp->cn_hash = 0;
179752317Sheideman 				for (cp = cnp->cn_nameptr, i = 1; i <= len; i++, cp++)
179852317Sheideman 					cnp->cn_hash += (unsigned char)*cp * i;
179956289Smckusick 				if ((nmp->nm_flag & NFSMNT_NQLOOKLEASE) &&
180056289Smckusick 					ltime > time.tv_sec)
180156289Smckusick 					nqnfs_clientlease(nmp, np, NQL_READ,
180256289Smckusick 						cachable, ltime, frev);
180356927Smckusick 				if (cnp->cn_namelen <= NCHNAMLEN)
180457791Smckusick 				    cache_enter(ndp->ni_dvp, ndp->ni_vp, cnp);
180552196Smckusick 			} else {
180652196Smckusick 				nfsm_adv(nfsm_rndup(len));
180752196Smckusick 			}
180852196Smckusick 			if (newvp != NULLVP) {
180952196Smckusick 				vrele(newvp);
181052196Smckusick 				newvp = NULLVP;
181152196Smckusick 			}
181256289Smckusick 			nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
181352196Smckusick 			if (bigenough)
181456289Smckusick 				endoff = off = fxdr_unsigned(u_long, *tl++);
181552196Smckusick 			else
181656289Smckusick 				endoff = fxdr_unsigned(u_long, *tl++);
181752196Smckusick 			more_dirs = fxdr_unsigned(int, *tl);
181852196Smckusick 		}
181952196Smckusick 		/*
182052196Smckusick 		 * If at end of rpc data, get the eof boolean
182152196Smckusick 		 */
182252196Smckusick 		if (!more_dirs) {
182352196Smckusick 			nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
182452196Smckusick 			more_dirs = (fxdr_unsigned(int, *tl) == 0);
182552196Smckusick 
182652196Smckusick 			/*
182752196Smckusick 			 * If at EOF, cache directory offset
182852196Smckusick 			 */
182952196Smckusick 			if (!more_dirs)
183052196Smckusick 				VTONFS(vp)->n_direofoffset = endoff;
183152196Smckusick 		}
183252196Smckusick 		if (uiop->uio_resid < tresid)
183356289Smckusick 			uiop->uio_offset = (off_t)off;
183452196Smckusick 		else
183552196Smckusick 			more_dirs = 0;
183652196Smckusick 		m_freem(mrep);
183752196Smckusick 	}
183852196Smckusick 	/*
183952196Smckusick 	 * Fill last record, iff any, out to a multiple of NFS_DIRBLKSIZ
184052196Smckusick 	 * by increasing d_reclen for the last record.
184152196Smckusick 	 */
184252196Smckusick 	if (uiop->uio_resid < tresid) {
184352196Smckusick 		len = uiop->uio_resid & (NFS_DIRBLKSIZ - 1);
184452196Smckusick 		if (len > 0) {
184552196Smckusick 			dp->d_reclen += len;
184652196Smckusick 			uiop->uio_iov->iov_base += len;
184752196Smckusick 			uiop->uio_iov->iov_len -= len;
184852196Smckusick 			uiop->uio_resid -= len;
184952196Smckusick 		}
185052196Smckusick 	}
185152196Smckusick nfsmout:
185252196Smckusick 	if (newvp != NULLVP)
185352196Smckusick 		vrele(newvp);
185452196Smckusick 	return (error);
185552196Smckusick }
185639488Smckusick static char hextoasc[] = "0123456789abcdef";
185738414Smckusick 
185838414Smckusick /*
185938414Smckusick  * Silly rename. To make the NFS filesystem that is stateless look a little
186038414Smckusick  * more like the "ufs" a remove of an active vnode is translated to a rename
186138414Smckusick  * to a funny looking filename that is removed by nfs_inactive on the
186238414Smckusick  * nfsnode. There is the potential for another process on a different client
186338414Smckusick  * to create the same funny name between the nfs_lookitup() fails and the
186438414Smckusick  * nfs_rename() completes, but...
186538414Smckusick  */
186652234Sheideman int
186752317Sheideman nfs_sillyrename(dvp, vp, cnp)
186852234Sheideman 	struct vnode *dvp, *vp;
186952234Sheideman 	struct componentname *cnp;
187038414Smckusick {
187138414Smckusick 	register struct nfsnode *np;
187238414Smckusick 	register struct sillyrename *sp;
187338414Smckusick 	int error;
187438414Smckusick 	short pid;
187538414Smckusick 
187652234Sheideman 	cache_purge(dvp);
187752234Sheideman 	np = VTONFS(vp);
187851986Smckusick #ifdef SILLYSEPARATE
187938414Smckusick 	MALLOC(sp, struct sillyrename *, sizeof (struct sillyrename),
188048364Smckusick 		M_NFSREQ, M_WAITOK);
188151986Smckusick #else
188251986Smckusick 	sp = &np->n_silly;
188351986Smckusick #endif
188452234Sheideman 	sp->s_cred = crdup(cnp->cn_cred);
188552234Sheideman 	sp->s_dvp = dvp;
188652234Sheideman 	VREF(dvp);
188738414Smckusick 
188838414Smckusick 	/* Fudge together a funny name */
188952234Sheideman 	pid = cnp->cn_proc->p_pid;
189048364Smckusick 	bcopy(".nfsAxxxx4.4", sp->s_name, 13);
189148364Smckusick 	sp->s_namlen = 12;
189248364Smckusick 	sp->s_name[8] = hextoasc[pid & 0xf];
189348364Smckusick 	sp->s_name[7] = hextoasc[(pid >> 4) & 0xf];
189448364Smckusick 	sp->s_name[6] = hextoasc[(pid >> 8) & 0xf];
189548364Smckusick 	sp->s_name[5] = hextoasc[(pid >> 12) & 0xf];
189638414Smckusick 
189738414Smckusick 	/* Try lookitups until we get one that isn't there */
189852234Sheideman 	while (nfs_lookitup(sp, (nfsv2fh_t *)0, cnp->cn_proc) == 0) {
189948364Smckusick 		sp->s_name[4]++;
190048364Smckusick 		if (sp->s_name[4] > 'z') {
190138414Smckusick 			error = EINVAL;
190238414Smckusick 			goto bad;
190338414Smckusick 		}
190438414Smckusick 	}
190552234Sheideman 	if (error = nfs_renameit(dvp, cnp, sp))
190638414Smckusick 		goto bad;
190752234Sheideman 	nfs_lookitup(sp, &np->n_fh, cnp->cn_proc);
190838414Smckusick 	np->n_sillyrename = sp;
190938414Smckusick 	return (0);
191038414Smckusick bad:
191148364Smckusick 	vrele(sp->s_dvp);
191248364Smckusick 	crfree(sp->s_cred);
191351986Smckusick #ifdef SILLYSEPARATE
191448364Smckusick 	free((caddr_t)sp, M_NFSREQ);
191551986Smckusick #endif
191638414Smckusick 	return (error);
191738414Smckusick }
191838414Smckusick 
191938414Smckusick /*
192038414Smckusick  * Look up a file name for silly rename stuff.
192138414Smckusick  * Just like nfs_lookup() except that it doesn't load returned values
192238414Smckusick  * into the nfsnode table.
192338414Smckusick  * If fhp != NULL it copies the returned file handle out
192438414Smckusick  */
192552234Sheideman int
192652196Smckusick nfs_lookitup(sp, fhp, procp)
192748364Smckusick 	register struct sillyrename *sp;
192838414Smckusick 	nfsv2fh_t *fhp;
192952196Smckusick 	struct proc *procp;
193038414Smckusick {
193148364Smckusick 	register struct vnode *vp = sp->s_dvp;
193248054Smckusick 	register u_long *tl;
193339488Smckusick 	register caddr_t cp;
193439488Smckusick 	register long t1, t2;
193539488Smckusick 	caddr_t bpos, dpos, cp2;
193639488Smckusick 	u_long xid;
193756289Smckusick 	int error = 0, isnq;
193839488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
193938414Smckusick 	long len;
194038414Smckusick 
194156289Smckusick 	isnq = (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS);
194238414Smckusick 	nfsstats.rpccnt[NFSPROC_LOOKUP]++;
194348364Smckusick 	len = sp->s_namlen;
194452196Smckusick 	nfsm_reqhead(vp, NFSPROC_LOOKUP, NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len));
194556289Smckusick 	if (isnq) {
194656289Smckusick 		nfsm_build(tl, u_long *, NFSX_UNSIGNED);
194756289Smckusick 		*tl = 0;
194856289Smckusick 	}
194938414Smckusick 	nfsm_fhtom(vp);
195048364Smckusick 	nfsm_strtom(sp->s_name, len, NFS_MAXNAMLEN);
195152196Smckusick 	nfsm_request(vp, NFSPROC_LOOKUP, procp, sp->s_cred);
195238414Smckusick 	if (fhp != NULL) {
195356289Smckusick 		if (isnq)
195456289Smckusick 			nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
195552196Smckusick 		nfsm_dissect(cp, caddr_t, NFSX_FH);
195638414Smckusick 		bcopy(cp, (caddr_t)fhp, NFSX_FH);
195738414Smckusick 	}
195838414Smckusick 	nfsm_reqdone;
195938414Smckusick 	return (error);
196038414Smckusick }
196138414Smckusick 
196238414Smckusick /*
196338414Smckusick  * Kludge City..
196438414Smckusick  * - make nfs_bmap() essentially a no-op that does no translation
196541905Smckusick  * - do nfs_strategy() by faking physical I/O with nfs_readrpc/nfs_writerpc
196638414Smckusick  *   after mapping the physical addresses into Kernel Virtual space in the
196738414Smckusick  *   nfsiobuf area.
196838414Smckusick  *   (Maybe I could use the process's page mapping, but I was concerned that
196938414Smckusick  *    Kernel Write might not be enabled and also figured copyout() would do
197038414Smckusick  *    a lot more work than bcopy() and also it currently happens in the
197138414Smckusick  *    context of the swapper process (2).
197238414Smckusick  */
197352234Sheideman int
197453806Smckusick nfs_bmap(ap)
197554668Smckusick 	struct vop_bmap_args /* {
197654668Smckusick 		struct vnode *a_vp;
197754668Smckusick 		daddr_t  a_bn;
197854668Smckusick 		struct vnode **a_vpp;
197954668Smckusick 		daddr_t *a_bnp;
198056452Smargo 		int *a_runp;
198154668Smckusick 	} */ *ap;
198238414Smckusick {
198353806Smckusick 	register struct vnode *vp = ap->a_vp;
198453806Smckusick 
198553600Sheideman 	if (ap->a_vpp != NULL)
198653806Smckusick 		*ap->a_vpp = vp;
198753600Sheideman 	if (ap->a_bnp != NULL)
198853806Smckusick 		*ap->a_bnp = ap->a_bn * btodb(vp->v_mount->mnt_stat.f_iosize);
198938414Smckusick 	return (0);
199038414Smckusick }
199138414Smckusick 
199238414Smckusick /*
199357791Smckusick  * Strategy routine.
199457791Smckusick  * For async requests when nfsiod(s) are running, queue the request by
199557791Smckusick  * calling nfs_asyncio(), otherwise just all nfs_doio() to do the
199657791Smckusick  * request.
199738414Smckusick  */
199852234Sheideman int
199953806Smckusick nfs_strategy(ap)
200057791Smckusick 	struct vop_strategy_args *ap;
200138414Smckusick {
200253806Smckusick 	register struct buf *bp = ap->a_bp;
200357791Smckusick 	struct ucred *cr;
200457791Smckusick 	struct proc *p;
200538884Smacklem 	int error = 0;
200638884Smacklem 
200757791Smckusick 	if (bp->b_flags & B_PHYS)
200857791Smckusick 		panic("nfs physio");
200957791Smckusick 	if (bp->b_flags & B_ASYNC)
201057791Smckusick 		p = (struct proc *)0;
201157791Smckusick 	else
201257791Smckusick 		p = curproc;	/* XXX */
201357791Smckusick 	if (bp->b_flags & B_READ)
201457791Smckusick 		cr = bp->b_rcred;
201557791Smckusick 	else
201657791Smckusick 		cr = bp->b_wcred;
201738884Smacklem 	/*
201846450Skarels 	 * If the op is asynchronous and an i/o daemon is waiting
201938884Smacklem 	 * queue the request, wake it up and wait for completion
202046450Skarels 	 * otherwise just do it ourselves.
202138884Smacklem 	 */
202257791Smckusick 	if ((bp->b_flags & B_ASYNC) == 0 ||
202357791Smckusick 		nfs_asyncio(bp, NOCRED))
202457791Smckusick 		error = nfs_doio(bp, cr, p);
202538884Smacklem 	return (error);
202638884Smacklem }
202738884Smacklem 
202838884Smacklem /*
202948054Smckusick  * Mmap a file
203048054Smckusick  *
203148054Smckusick  * NB Currently unsupported.
203248054Smckusick  */
203348054Smckusick /* ARGSUSED */
203452234Sheideman int
203553806Smckusick nfs_mmap(ap)
203654668Smckusick 	struct vop_mmap_args /* {
203754668Smckusick 		struct vnode *a_vp;
203854668Smckusick 		int  a_fflags;
203954668Smckusick 		struct ucred *a_cred;
204054668Smckusick 		struct proc *a_p;
204154668Smckusick 	} */ *ap;
204248054Smckusick {
204348054Smckusick 
204448054Smckusick 	return (EINVAL);
204548054Smckusick }
204648054Smckusick 
204748054Smckusick /*
204838884Smacklem  * Flush all the blocks associated with a vnode.
204938884Smacklem  * 	Walk through the buffer pool and push any dirty pages
205038884Smacklem  *	associated with the vnode.
205138884Smacklem  */
205239488Smckusick /* ARGSUSED */
205352234Sheideman int
205453806Smckusick nfs_fsync(ap)
205554451Smckusick 	struct vop_fsync_args /* {
205654451Smckusick 		struct vnodeop_desc *a_desc;
205754451Smckusick 		struct vnode * a_vp;
205854451Smckusick 		struct ucred * a_cred;
205954451Smckusick 		int  a_waitfor;
206054451Smckusick 		struct proc * a_p;
206154451Smckusick 	} */ *ap;
206238884Smacklem {
206354451Smckusick 	register struct vnode *vp = ap->a_vp;
206454451Smckusick 	register struct nfsnode *np = VTONFS(vp);
206554451Smckusick 	register struct buf *bp;
206654451Smckusick 	struct buf *nbp;
206757791Smckusick 	struct nfsmount *nmp;
206857791Smckusick 	int s, error = 0, slptimeo = 0, slpflag = 0;
206938884Smacklem 
207057791Smckusick 	nmp = VFSTONFS(vp->v_mount);
207157791Smckusick 	if (nmp->nm_flag & NFSMNT_INT)
207257791Smckusick 		slpflag = PCATCH;
207354451Smckusick loop:
207454451Smckusick 	s = splbio();
207556468Smckusick 	for (bp = vp->v_dirtyblkhd.le_next; bp; bp = nbp) {
207656468Smckusick 		nbp = bp->b_vnbufs.qe_next;
207757791Smckusick 		if (bp->b_flags & B_BUSY) {
207857791Smckusick 			if (ap->a_waitfor != MNT_WAIT)
207957791Smckusick 				continue;
208057791Smckusick 			bp->b_flags |= B_WANTED;
208157791Smckusick 			error = tsleep((caddr_t)bp, slpflag | (PRIBIO + 1),
208257791Smckusick 				"nfsfsync", slptimeo);
208357791Smckusick 			splx(s);
208457791Smckusick 			if (error) {
208557791Smckusick 			    if (nfs_sigintr(nmp, (struct nfsreq *)0, ap->a_p))
208657791Smckusick 				return (EINTR);
208757791Smckusick 			    if (slpflag == PCATCH) {
208857791Smckusick 				slpflag = 0;
208957791Smckusick 				slptimeo = 2 * hz;
209057791Smckusick 			    }
209157791Smckusick 			}
209257791Smckusick 			goto loop;
209357791Smckusick 		}
209454451Smckusick 		if ((bp->b_flags & B_DELWRI) == 0)
209554451Smckusick 			panic("nfs_fsync: not dirty");
209654451Smckusick 		bremfree(bp);
209754451Smckusick 		bp->b_flags |= B_BUSY;
209854451Smckusick 		splx(s);
209957791Smckusick 		bp->b_flags |= B_ASYNC;
210057791Smckusick 		VOP_BWRITE(bp);
210154451Smckusick 		goto loop;
210238884Smacklem 	}
210357791Smckusick 	splx(s);
210454451Smckusick 	if (ap->a_waitfor == MNT_WAIT) {
210554451Smckusick 		while (vp->v_numoutput) {
210654451Smckusick 			vp->v_flag |= VBWAIT;
210757791Smckusick 			error = tsleep((caddr_t)&vp->v_numoutput,
210857791Smckusick 				slpflag | (PRIBIO + 1), "nfsfsync", slptimeo);
210957791Smckusick 			if (error) {
211057791Smckusick 			    if (nfs_sigintr(nmp, (struct nfsreq *)0, ap->a_p))
211157791Smckusick 				return (EINTR);
211257791Smckusick 			    if (slpflag == PCATCH) {
211357791Smckusick 				slpflag = 0;
211457791Smckusick 				slptimeo = 2 * hz;
211557791Smckusick 			    }
211657791Smckusick 			}
211754451Smckusick 		}
211857791Smckusick 		if (vp->v_dirtyblkhd.le_next) {
211954451Smckusick #ifdef DIAGNOSTIC
212054451Smckusick 			vprint("nfs_fsync: dirty", vp);
212157791Smckusick #endif
212254451Smckusick 			goto loop;
212354451Smckusick 		}
212454451Smckusick 	}
212553629Smckusick 	if (np->n_flag & NWRITEERR) {
212639751Smckusick 		error = np->n_error;
212753629Smckusick 		np->n_flag &= ~NWRITEERR;
212853629Smckusick 	}
212938884Smacklem 	return (error);
213038884Smacklem }
213139672Smckusick 
213239672Smckusick /*
2133*60400Smckusick  * Return POSIX pathconf information applicable to nfs.
2134*60400Smckusick  *
2135*60400Smckusick  * Currently the NFS protocol does not support getting such
2136*60400Smckusick  * information from the remote server.
2137*60400Smckusick  */
2138*60400Smckusick /* ARGSUSED */
2139*60400Smckusick nfs_pathconf(ap)
2140*60400Smckusick 	struct vop_pathconf_args /* {
2141*60400Smckusick 		struct vnode *a_vp;
2142*60400Smckusick 		int a_name;
2143*60400Smckusick 		int *a_retval;
2144*60400Smckusick 	} */ *ap;
2145*60400Smckusick {
2146*60400Smckusick 
2147*60400Smckusick 	return (EINVAL);
2148*60400Smckusick }
2149*60400Smckusick 
2150*60400Smckusick /*
215146201Smckusick  * NFS advisory byte-level locks.
215246201Smckusick  * Currently unsupported.
215346201Smckusick  */
215452234Sheideman int
215553806Smckusick nfs_advlock(ap)
215654668Smckusick 	struct vop_advlock_args /* {
215754668Smckusick 		struct vnode *a_vp;
215854668Smckusick 		caddr_t  a_id;
215954668Smckusick 		int  a_op;
216054668Smckusick 		struct flock *a_fl;
216154668Smckusick 		int  a_flags;
216254668Smckusick 	} */ *ap;
216346201Smckusick {
216446201Smckusick 
216546201Smckusick 	return (EOPNOTSUPP);
216646201Smckusick }
216746201Smckusick 
216846201Smckusick /*
216939672Smckusick  * Print out the contents of an nfsnode.
217039672Smckusick  */
217152234Sheideman int
217253806Smckusick nfs_print(ap)
217354668Smckusick 	struct vop_print_args /* {
217454668Smckusick 		struct vnode *a_vp;
217554668Smckusick 	} */ *ap;
217639672Smckusick {
217753806Smckusick 	register struct vnode *vp = ap->a_vp;
217853806Smckusick 	register struct nfsnode *np = VTONFS(vp);
217939672Smckusick 
218040294Smckusick 	printf("tag VT_NFS, fileid %d fsid 0x%x",
218140294Smckusick 		np->n_vattr.va_fileid, np->n_vattr.va_fsid);
218240294Smckusick #ifdef FIFO
218353806Smckusick 	if (vp->v_type == VFIFO)
218453806Smckusick 		fifo_printinfo(vp);
218540294Smckusick #endif /* FIFO */
218639914Smckusick 	printf("\n");
218739672Smckusick }
218851573Smckusick 
218951573Smckusick /*
219051573Smckusick  * NFS directory offset lookup.
219151573Smckusick  * Currently unsupported.
219251573Smckusick  */
219352234Sheideman int
219453806Smckusick nfs_blkatoff(ap)
219554668Smckusick 	struct vop_blkatoff_args /* {
219654668Smckusick 		struct vnode *a_vp;
219754668Smckusick 		off_t a_offset;
219854668Smckusick 		char **a_res;
219954668Smckusick 		struct buf **a_bpp;
220054668Smckusick 	} */ *ap;
220151573Smckusick {
220251573Smckusick 
220351573Smckusick 	return (EOPNOTSUPP);
220451573Smckusick }
220551573Smckusick 
220651573Smckusick /*
220751573Smckusick  * NFS flat namespace allocation.
220851573Smckusick  * Currently unsupported.
220951573Smckusick  */
221052234Sheideman int
221153806Smckusick nfs_valloc(ap)
221254668Smckusick 	struct vop_valloc_args /* {
221354668Smckusick 		struct vnode *a_pvp;
221454668Smckusick 		int a_mode;
221554668Smckusick 		struct ucred *a_cred;
221654668Smckusick 		struct vnode **a_vpp;
221754668Smckusick 	} */ *ap;
221851573Smckusick {
221951573Smckusick 
222051573Smckusick 	return (EOPNOTSUPP);
222151573Smckusick }
222251573Smckusick 
222351573Smckusick /*
222451573Smckusick  * NFS flat namespace free.
222551573Smckusick  * Currently unsupported.
222651573Smckusick  */
222753582Sheideman int
222853806Smckusick nfs_vfree(ap)
222954668Smckusick 	struct vop_vfree_args /* {
223054668Smckusick 		struct vnode *a_pvp;
223154668Smckusick 		ino_t a_ino;
223254668Smckusick 		int a_mode;
223354668Smckusick 	} */ *ap;
223451573Smckusick {
223551573Smckusick 
223653582Sheideman 	return (EOPNOTSUPP);
223751573Smckusick }
223851573Smckusick 
223951573Smckusick /*
224051573Smckusick  * NFS file truncation.
224151573Smckusick  */
224252234Sheideman int
224353806Smckusick nfs_truncate(ap)
224454668Smckusick 	struct vop_truncate_args /* {
224554668Smckusick 		struct vnode *a_vp;
224654668Smckusick 		off_t a_length;
224754668Smckusick 		int a_flags;
224854668Smckusick 		struct ucred *a_cred;
224954668Smckusick 		struct proc *a_p;
225054668Smckusick 	} */ *ap;
225151573Smckusick {
225251573Smckusick 
225351573Smckusick 	/* Use nfs_setattr */
225451573Smckusick 	printf("nfs_truncate: need to implement!!");
225551573Smckusick 	return (EOPNOTSUPP);
225651573Smckusick }
225751573Smckusick 
225851573Smckusick /*
225951573Smckusick  * NFS update.
226051573Smckusick  */
226152234Sheideman int
226253806Smckusick nfs_update(ap)
226354668Smckusick 	struct vop_update_args /* {
226454668Smckusick 		struct vnode *a_vp;
226554668Smckusick 		struct timeval *a_ta;
226654668Smckusick 		struct timeval *a_tm;
226754668Smckusick 		int a_waitfor;
226854668Smckusick 	} */ *ap;
226951573Smckusick {
227051573Smckusick 
227151573Smckusick 	/* Use nfs_setattr */
227251573Smckusick 	printf("nfs_update: need to implement!!");
227351573Smckusick 	return (EOPNOTSUPP);
227451573Smckusick }
227553629Smckusick 
227653629Smckusick /*
227756364Smckusick  * nfs special file access vnode op.
227856364Smckusick  * Essentially just get vattr and then imitate iaccess() since the device is
227956364Smckusick  * local to the client.
228056364Smckusick  */
228156364Smckusick int
228256364Smckusick nfsspec_access(ap)
228356364Smckusick 	struct vop_access_args /* {
228456364Smckusick 		struct vnode *a_vp;
228556364Smckusick 		int  a_mode;
228656364Smckusick 		struct ucred *a_cred;
228756364Smckusick 		struct proc *a_p;
228856364Smckusick 	} */ *ap;
228956364Smckusick {
229056364Smckusick 	register struct vattr *vap;
229156364Smckusick 	register gid_t *gp;
229256364Smckusick 	register struct ucred *cred = ap->a_cred;
229356364Smckusick 	mode_t mode = ap->a_mode;
229456364Smckusick 	struct vattr vattr;
229556364Smckusick 	register int i;
229656364Smckusick 	int error;
229756364Smckusick 
229856364Smckusick 	/*
229956364Smckusick 	 * If you're the super-user,
230056364Smckusick 	 * you always get access.
230156364Smckusick 	 */
230256364Smckusick 	if (cred->cr_uid == 0)
230356364Smckusick 		return (0);
230456364Smckusick 	vap = &vattr;
230556364Smckusick 	if (error = VOP_GETATTR(ap->a_vp, vap, cred, ap->a_p))
230656364Smckusick 		return (error);
230756364Smckusick 	/*
230856364Smckusick 	 * Access check is based on only one of owner, group, public.
230956364Smckusick 	 * If not owner, then check group. If not a member of the
231056364Smckusick 	 * group, then check public access.
231156364Smckusick 	 */
231256364Smckusick 	if (cred->cr_uid != vap->va_uid) {
231356364Smckusick 		mode >>= 3;
231456364Smckusick 		gp = cred->cr_groups;
231556364Smckusick 		for (i = 0; i < cred->cr_ngroups; i++, gp++)
231656364Smckusick 			if (vap->va_gid == *gp)
231756364Smckusick 				goto found;
231856364Smckusick 		mode >>= 3;
231956364Smckusick found:
232056364Smckusick 		;
232156364Smckusick 	}
232256708Smckusick 	return ((vap->va_mode & mode) == mode ? 0 : EACCES);
232356364Smckusick }
232456364Smckusick 
232556364Smckusick /*
232653629Smckusick  * Read wrapper for special devices.
232753629Smckusick  */
232853629Smckusick int
232953629Smckusick nfsspec_read(ap)
233054668Smckusick 	struct vop_read_args /* {
233154668Smckusick 		struct vnode *a_vp;
233254668Smckusick 		struct uio *a_uio;
233354668Smckusick 		int  a_ioflag;
233454668Smckusick 		struct ucred *a_cred;
233554668Smckusick 	} */ *ap;
233653629Smckusick {
233754032Smckusick 	register struct nfsnode *np = VTONFS(ap->a_vp);
233853629Smckusick 
233953629Smckusick 	/*
234053629Smckusick 	 * Set access flag.
234153629Smckusick 	 */
234254032Smckusick 	np->n_flag |= NACC;
234354032Smckusick 	np->n_atim = time;
234453629Smckusick 	return (VOCALL(spec_vnodeop_p, VOFFSET(vop_read), ap));
234553629Smckusick }
234653629Smckusick 
234753629Smckusick /*
234853629Smckusick  * Write wrapper for special devices.
234953629Smckusick  */
235053629Smckusick int
235153629Smckusick nfsspec_write(ap)
235254668Smckusick 	struct vop_write_args /* {
235354668Smckusick 		struct vnode *a_vp;
235454668Smckusick 		struct uio *a_uio;
235554668Smckusick 		int  a_ioflag;
235654668Smckusick 		struct ucred *a_cred;
235754668Smckusick 	} */ *ap;
235853629Smckusick {
235954032Smckusick 	register struct nfsnode *np = VTONFS(ap->a_vp);
236053629Smckusick 
236153629Smckusick 	/*
236254032Smckusick 	 * Set update flag.
236353629Smckusick 	 */
236454032Smckusick 	np->n_flag |= NUPD;
236554032Smckusick 	np->n_mtim = time;
236653629Smckusick 	return (VOCALL(spec_vnodeop_p, VOFFSET(vop_write), ap));
236753629Smckusick }
236853629Smckusick 
236953629Smckusick /*
237053629Smckusick  * Close wrapper for special devices.
237153629Smckusick  *
237253629Smckusick  * Update the times on the nfsnode then do device close.
237353629Smckusick  */
237453629Smckusick int
237553629Smckusick nfsspec_close(ap)
237654668Smckusick 	struct vop_close_args /* {
237754668Smckusick 		struct vnode *a_vp;
237854668Smckusick 		int  a_fflag;
237954668Smckusick 		struct ucred *a_cred;
238054668Smckusick 		struct proc *a_p;
238154668Smckusick 	} */ *ap;
238253629Smckusick {
238353806Smckusick 	register struct vnode *vp = ap->a_vp;
238453806Smckusick 	register struct nfsnode *np = VTONFS(vp);
238553629Smckusick 	struct vattr vattr;
238653629Smckusick 
238753629Smckusick 	if (np->n_flag & (NACC | NUPD)) {
238853629Smckusick 		np->n_flag |= NCHG;
238953806Smckusick 		if (vp->v_usecount == 1 &&
239053806Smckusick 		    (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) {
239153629Smckusick 			VATTR_NULL(&vattr);
239254106Smckusick 			if (np->n_flag & NACC) {
239354106Smckusick 				vattr.va_atime.ts_sec = np->n_atim.tv_sec;
239454106Smckusick 				vattr.va_atime.ts_nsec =
239554106Smckusick 				    np->n_atim.tv_usec * 1000;
239654106Smckusick 			}
239754106Smckusick 			if (np->n_flag & NUPD) {
239854106Smckusick 				vattr.va_mtime.ts_sec = np->n_mtim.tv_sec;
239954106Smckusick 				vattr.va_mtime.ts_nsec =
240054106Smckusick 				    np->n_mtim.tv_usec * 1000;
240154106Smckusick 			}
240253806Smckusick 			(void)VOP_SETATTR(vp, &vattr, ap->a_cred, ap->a_p);
240353629Smckusick 		}
240453629Smckusick 	}
240553629Smckusick 	return (VOCALL(spec_vnodeop_p, VOFFSET(vop_close), ap));
240653629Smckusick }
240753629Smckusick 
240853629Smckusick #ifdef FIFO
240953629Smckusick /*
241053629Smckusick  * Read wrapper for fifos.
241153629Smckusick  */
241253629Smckusick int
241353629Smckusick nfsfifo_read(ap)
241454668Smckusick 	struct vop_read_args /* {
241554668Smckusick 		struct vnode *a_vp;
241654668Smckusick 		struct uio *a_uio;
241754668Smckusick 		int  a_ioflag;
241854668Smckusick 		struct ucred *a_cred;
241954668Smckusick 	} */ *ap;
242053629Smckusick {
242153629Smckusick 	extern int (**fifo_vnodeop_p)();
242254032Smckusick 	register struct nfsnode *np = VTONFS(ap->a_vp);
242353629Smckusick 
242453629Smckusick 	/*
242553629Smckusick 	 * Set access flag.
242653629Smckusick 	 */
242754032Smckusick 	np->n_flag |= NACC;
242854032Smckusick 	np->n_atim = time;
242953629Smckusick 	return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_read), ap));
243053629Smckusick }
243153629Smckusick 
243253629Smckusick /*
243353629Smckusick  * Write wrapper for fifos.
243453629Smckusick  */
243553629Smckusick int
243653629Smckusick nfsfifo_write(ap)
243754668Smckusick 	struct vop_write_args /* {
243854668Smckusick 		struct vnode *a_vp;
243954668Smckusick 		struct uio *a_uio;
244054668Smckusick 		int  a_ioflag;
244154668Smckusick 		struct ucred *a_cred;
244254668Smckusick 	} */ *ap;
244353629Smckusick {
244453629Smckusick 	extern int (**fifo_vnodeop_p)();
244554032Smckusick 	register struct nfsnode *np = VTONFS(ap->a_vp);
244653629Smckusick 
244753629Smckusick 	/*
244853629Smckusick 	 * Set update flag.
244953629Smckusick 	 */
245054032Smckusick 	np->n_flag |= NUPD;
245154032Smckusick 	np->n_mtim = time;
245253629Smckusick 	return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_write), ap));
245353629Smckusick }
245453629Smckusick 
245553629Smckusick /*
245653629Smckusick  * Close wrapper for fifos.
245753629Smckusick  *
245853629Smckusick  * Update the times on the nfsnode then do fifo close.
245953629Smckusick  */
246053629Smckusick int
246153629Smckusick nfsfifo_close(ap)
246254668Smckusick 	struct vop_close_args /* {
246354668Smckusick 		struct vnode *a_vp;
246454668Smckusick 		int  a_fflag;
246554668Smckusick 		struct ucred *a_cred;
246654668Smckusick 		struct proc *a_p;
246754668Smckusick 	} */ *ap;
246853629Smckusick {
246953806Smckusick 	register struct vnode *vp = ap->a_vp;
247053806Smckusick 	register struct nfsnode *np = VTONFS(vp);
247153629Smckusick 	struct vattr vattr;
247253629Smckusick 	extern int (**fifo_vnodeop_p)();
247353629Smckusick 
247453629Smckusick 	if (np->n_flag & (NACC | NUPD)) {
247553629Smckusick 		if (np->n_flag & NACC)
247653629Smckusick 			np->n_atim = time;
247753629Smckusick 		if (np->n_flag & NUPD)
247853629Smckusick 			np->n_mtim = time;
247953629Smckusick 		np->n_flag |= NCHG;
248053806Smckusick 		if (vp->v_usecount == 1 &&
248153806Smckusick 		    (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) {
248253629Smckusick 			VATTR_NULL(&vattr);
248354106Smckusick 			if (np->n_flag & NACC) {
248454106Smckusick 				vattr.va_atime.ts_sec = np->n_atim.tv_sec;
248554106Smckusick 				vattr.va_atime.ts_nsec =
248654106Smckusick 				    np->n_atim.tv_usec * 1000;
248754106Smckusick 			}
248854106Smckusick 			if (np->n_flag & NUPD) {
248954106Smckusick 				vattr.va_mtime.ts_sec = np->n_mtim.tv_sec;
249054106Smckusick 				vattr.va_mtime.ts_nsec =
249154106Smckusick 				    np->n_mtim.tv_usec * 1000;
249254106Smckusick 			}
249353806Smckusick 			(void)VOP_SETATTR(vp, &vattr, ap->a_cred, ap->a_p);
249453629Smckusick 		}
249553629Smckusick 	}
249653629Smckusick 	return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_close), ap));
249753629Smckusick }
249853629Smckusick #endif /* FIFO */
2499