xref: /csrg-svn/sys/nfs/nfs_vnops.c (revision 52823)
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*52823Smckusick  *	@(#)nfs_vnops.c	7.69 (Berkeley) 03/03/92
1138414Smckusick  */
1238414Smckusick 
1338414Smckusick /*
1438414Smckusick  * vnode op calls for sun nfs version 2
1538414Smckusick  */
1638414Smckusick 
1738414Smckusick #include "param.h"
1838414Smckusick #include "proc.h"
1940296Smckusick #include "kernel.h"
2046981Skarels #include "systm.h"
2138414Smckusick #include "mount.h"
2238414Smckusick #include "buf.h"
2338414Smckusick #include "malloc.h"
2438414Smckusick #include "mbuf.h"
2538414Smckusick #include "conf.h"
2648054Smckusick #include "namei.h"
2738414Smckusick #include "vnode.h"
2848054Smckusick #include "specdev.h"
2948054Smckusick #include "fifo.h"
3038884Smacklem #include "map.h"
3147573Skarels 
3252196Smckusick #include "rpcv2.h"
3338414Smckusick #include "nfsv2.h"
3438414Smckusick #include "nfs.h"
3538414Smckusick #include "nfsnode.h"
3638414Smckusick #include "nfsmount.h"
3738414Smckusick #include "xdr_subs.h"
3838414Smckusick #include "nfsm_subs.h"
3952196Smckusick #include "nqnfs.h"
4038414Smckusick 
4138414Smckusick /* Defs */
4238414Smckusick #define	TRUE	1
4338414Smckusick #define	FALSE	0
4438414Smckusick 
4548054Smckusick /*
4648054Smckusick  * Global vfs data structures for nfs
4748054Smckusick  */
4838414Smckusick struct vnodeops nfsv2_vnodeops = {
4939672Smckusick 	nfs_lookup,		/* lookup */
5039672Smckusick 	nfs_create,		/* create */
5139672Smckusick 	nfs_mknod,		/* mknod */
5239672Smckusick 	nfs_open,		/* open */
5339672Smckusick 	nfs_close,		/* close */
5439672Smckusick 	nfs_access,		/* access */
5539672Smckusick 	nfs_getattr,		/* getattr */
5639672Smckusick 	nfs_setattr,		/* setattr */
5739672Smckusick 	nfs_read,		/* read */
5839672Smckusick 	nfs_write,		/* write */
5948054Smckusick 	nfs_ioctl,		/* ioctl */
6048054Smckusick 	nfs_select,		/* select */
6148054Smckusick 	nfs_mmap,		/* mmap */
6239672Smckusick 	nfs_fsync,		/* fsync */
6348054Smckusick 	nfs_seek,		/* seek */
6439672Smckusick 	nfs_remove,		/* remove */
6539672Smckusick 	nfs_link,		/* link */
6639672Smckusick 	nfs_rename,		/* rename */
6739672Smckusick 	nfs_mkdir,		/* mkdir */
6839672Smckusick 	nfs_rmdir,		/* rmdir */
6939672Smckusick 	nfs_symlink,		/* symlink */
7039672Smckusick 	nfs_readdir,		/* readdir */
7139672Smckusick 	nfs_readlink,		/* readlink */
7239672Smckusick 	nfs_abortop,		/* abortop */
7339672Smckusick 	nfs_inactive,		/* inactive */
7439672Smckusick 	nfs_reclaim,		/* reclaim */
7539672Smckusick 	nfs_lock,		/* lock */
7639672Smckusick 	nfs_unlock,		/* unlock */
7739672Smckusick 	nfs_bmap,		/* bmap */
7839672Smckusick 	nfs_strategy,		/* strategy */
7939672Smckusick 	nfs_print,		/* print */
8039906Smckusick 	nfs_islocked,		/* islocked */
8146201Smckusick 	nfs_advlock,		/* advlock */
8251573Smckusick 	nfs_blkatoff,		/* blkatoff */
8351573Smckusick 	nfs_vget,		/* vget */
8451573Smckusick 	nfs_valloc,		/* valloc */
8551573Smckusick 	nfs_vfree,		/* vfree */
8651573Smckusick 	nfs_truncate,		/* truncate */
8751573Smckusick 	nfs_update,		/* update */
8851573Smckusick 	bwrite,			/* bwrite */
8938414Smckusick };
9038414Smckusick 
9148054Smckusick /*
9248054Smckusick  * Special device vnode ops
9348054Smckusick  */
9439441Smckusick struct vnodeops spec_nfsv2nodeops = {
9539599Smckusick 	spec_lookup,		/* lookup */
9648054Smckusick 	spec_create,		/* create */
9748054Smckusick 	spec_mknod,		/* mknod */
9839599Smckusick 	spec_open,		/* open */
9939599Smckusick 	spec_close,		/* close */
10039599Smckusick 	nfs_access,		/* access */
10139599Smckusick 	nfs_getattr,		/* getattr */
10239599Smckusick 	nfs_setattr,		/* setattr */
10339599Smckusick 	spec_read,		/* read */
10439599Smckusick 	spec_write,		/* write */
10539599Smckusick 	spec_ioctl,		/* ioctl */
10639599Smckusick 	spec_select,		/* select */
10748054Smckusick 	spec_mmap,		/* mmap */
10848054Smckusick 	spec_fsync,		/* fsync */
10948054Smckusick 	spec_seek,		/* seek */
11048054Smckusick 	spec_remove,		/* remove */
11148054Smckusick 	spec_link,		/* link */
11248054Smckusick 	spec_rename,		/* rename */
11348054Smckusick 	spec_mkdir,		/* mkdir */
11448054Smckusick 	spec_rmdir,		/* rmdir */
11548054Smckusick 	spec_symlink,		/* symlink */
11648054Smckusick 	spec_readdir,		/* readdir */
11748054Smckusick 	spec_readlink,		/* readlink */
11848054Smckusick 	spec_abortop,		/* abortop */
11939599Smckusick 	nfs_inactive,		/* inactive */
12039599Smckusick 	nfs_reclaim,		/* reclaim */
12139599Smckusick 	nfs_lock,		/* lock */
12239599Smckusick 	nfs_unlock,		/* unlock */
12339672Smckusick 	spec_bmap,		/* bmap */
12439599Smckusick 	spec_strategy,		/* strategy */
12539672Smckusick 	nfs_print,		/* print */
12639906Smckusick 	nfs_islocked,		/* islocked */
12746201Smckusick 	spec_advlock,		/* advlock */
12851573Smckusick 	spec_blkatoff,		/* blkatoff */
12951573Smckusick 	spec_vget,		/* vget */
13051573Smckusick 	spec_valloc,		/* valloc */
13151573Smckusick 	spec_vfree,		/* vfree */
13251573Smckusick 	spec_truncate,		/* truncate */
13351573Smckusick 	nfs_update,		/* update */
13451573Smckusick 	bwrite,			/* bwrite */
13538414Smckusick };
13638414Smckusick 
13740294Smckusick #ifdef FIFO
13840294Smckusick struct vnodeops fifo_nfsv2nodeops = {
13940294Smckusick 	fifo_lookup,		/* lookup */
14048054Smckusick 	fifo_create,		/* create */
14148054Smckusick 	fifo_mknod,		/* mknod */
14240294Smckusick 	fifo_open,		/* open */
14340294Smckusick 	fifo_close,		/* close */
14440294Smckusick 	nfs_access,		/* access */
14540294Smckusick 	nfs_getattr,		/* getattr */
14640294Smckusick 	nfs_setattr,		/* setattr */
14740294Smckusick 	fifo_read,		/* read */
14840294Smckusick 	fifo_write,		/* write */
14940294Smckusick 	fifo_ioctl,		/* ioctl */
15040294Smckusick 	fifo_select,		/* select */
15148054Smckusick 	fifo_mmap,		/* mmap */
15248054Smckusick 	fifo_fsync,		/* fsync */
15348054Smckusick 	fifo_seek,		/* seek */
15448054Smckusick 	fifo_remove,		/* remove */
15548054Smckusick 	fifo_link,		/* link */
15648054Smckusick 	fifo_rename,		/* rename */
15748054Smckusick 	fifo_mkdir,		/* mkdir */
15848054Smckusick 	fifo_rmdir,		/* rmdir */
15948054Smckusick 	fifo_symlink,		/* symlink */
16048054Smckusick 	fifo_readdir,		/* readdir */
16148054Smckusick 	fifo_readlink,		/* readlink */
16248054Smckusick 	fifo_abortop,		/* abortop */
16340294Smckusick 	nfs_inactive,		/* inactive */
16440294Smckusick 	nfs_reclaim,		/* reclaim */
16540294Smckusick 	nfs_lock,		/* lock */
16640294Smckusick 	nfs_unlock,		/* unlock */
16740294Smckusick 	fifo_bmap,		/* bmap */
16840294Smckusick 	fifo_badop,		/* strategy */
16940294Smckusick 	nfs_print,		/* print */
17040294Smckusick 	nfs_islocked,		/* islocked */
17146201Smckusick 	fifo_advlock,		/* advlock */
17251573Smckusick 	fifo_blkatoff,		/* blkatoff */
17351573Smckusick 	fifo_vget,		/* vget */
17451573Smckusick 	fifo_valloc,		/* valloc */
17551573Smckusick 	fifo_vfree,		/* vfree */
17651573Smckusick 	fifo_truncate,		/* truncate */
17751573Smckusick 	nfs_update,		/* update */
17851573Smckusick 	bwrite,			/* bwrite */
17940294Smckusick };
18040294Smckusick #endif /* FIFO */
18140294Smckusick 
18248054Smckusick /*
18352196Smckusick  * Global variables
18448054Smckusick  */
18538414Smckusick extern u_long nfs_procids[NFS_NPROCS];
18638414Smckusick extern u_long nfs_prog, nfs_vers;
18738414Smckusick extern char nfsiobuf[MAXPHYS+NBPG];
18838884Smacklem struct buf nfs_bqueue;		/* Queue head for nfsiod's */
18941905Smckusick struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON];
19046988Smckusick int nfs_numasync = 0;
19152436Smckusick #define	DIRHDSIZ	(sizeof (struct readdir) - (MAXNAMLEN + 1))
19238414Smckusick 
19338414Smckusick /*
19438414Smckusick  * nfs null call from vfs.
19538414Smckusick  */
19652234Sheideman int
19752196Smckusick nfs_null(vp, cred, procp)
19838414Smckusick 	struct vnode *vp;
19938414Smckusick 	struct ucred *cred;
20052196Smckusick 	struct proc *procp;
20138414Smckusick {
20239488Smckusick 	caddr_t bpos, dpos;
20339488Smckusick 	int error = 0;
20439488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb;
20538414Smckusick 
20652196Smckusick 	nfsm_reqhead(vp, NFSPROC_NULL, 0);
20752196Smckusick 	nfsm_request(vp, NFSPROC_NULL, procp, cred);
20838414Smckusick 	nfsm_reqdone;
20938414Smckusick 	return (error);
21038414Smckusick }
21138414Smckusick 
21238414Smckusick /*
21338414Smckusick  * nfs access vnode op.
21438414Smckusick  * Essentially just get vattr and then imitate iaccess()
21538414Smckusick  */
21652234Sheideman int
21752196Smckusick nfs_access(vp, mode, cred, procp)
21838414Smckusick 	struct vnode *vp;
21938414Smckusick 	int mode;
22038414Smckusick 	register struct ucred *cred;
22152196Smckusick 	struct proc *procp;
22238414Smckusick {
22338414Smckusick 	register struct vattr *vap;
22438414Smckusick 	register gid_t *gp;
22538414Smckusick 	struct vattr vattr;
22638414Smckusick 	register int i;
22738414Smckusick 	int error;
22838414Smckusick 
22938414Smckusick 	/*
23038414Smckusick 	 * If you're the super-user,
23138414Smckusick 	 * you always get access.
23238414Smckusick 	 */
23338414Smckusick 	if (cred->cr_uid == 0)
23438414Smckusick 		return (0);
23538414Smckusick 	vap = &vattr;
23652196Smckusick 	if (error = nfs_getattr(vp, vap, cred, procp))
23738884Smacklem 		return (error);
23838414Smckusick 	/*
23938414Smckusick 	 * Access check is based on only one of owner, group, public.
24038414Smckusick 	 * If not owner, then check group. If not a member of the
24138414Smckusick 	 * group, then check public access.
24238414Smckusick 	 */
24338414Smckusick 	if (cred->cr_uid != vap->va_uid) {
24438414Smckusick 		mode >>= 3;
24538414Smckusick 		gp = cred->cr_groups;
24638414Smckusick 		for (i = 0; i < cred->cr_ngroups; i++, gp++)
24738414Smckusick 			if (vap->va_gid == *gp)
24838414Smckusick 				goto found;
24938414Smckusick 		mode >>= 3;
25038414Smckusick found:
25138414Smckusick 		;
25238414Smckusick 	}
25338414Smckusick 	if ((vap->va_mode & mode) != 0)
25438414Smckusick 		return (0);
25538414Smckusick 	return (EACCES);
25638414Smckusick }
25738414Smckusick 
25838414Smckusick /*
25938414Smckusick  * nfs open vnode op
26038414Smckusick  * Just check to see if the type is ok
26152196Smckusick  * and that deletion is not in progress.
26238414Smckusick  */
26339488Smckusick /* ARGSUSED */
26452234Sheideman int
26552196Smckusick nfs_open(vp, mode, cred, procp)
26652196Smckusick 	register struct vnode *vp;
26738414Smckusick 	int mode;
26838414Smckusick 	struct ucred *cred;
26952196Smckusick 	struct proc *procp;
27038414Smckusick {
27138414Smckusick 
27252196Smckusick 	if (vp->v_type != VREG && vp->v_type != VDIR && vp->v_type != VLNK)
27338414Smckusick 		return (EACCES);
27452196Smckusick 	if ((VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) == 0)
27552196Smckusick 		VTONFS(vp)->n_attrstamp = 0; /* For Open/Close consistency */
27652196Smckusick 	return (0);
27738414Smckusick }
27838414Smckusick 
27938414Smckusick /*
28038414Smckusick  * nfs close vnode op
28138884Smacklem  * For reg files, invalidate any buffer cache entries.
28238414Smckusick  */
28339488Smckusick /* ARGSUSED */
28452234Sheideman int
28552196Smckusick nfs_close(vp, fflags, cred, procp)
28638414Smckusick 	register struct vnode *vp;
28738414Smckusick 	int fflags;
28838414Smckusick 	struct ucred *cred;
28952196Smckusick 	struct proc *procp;
29038414Smckusick {
29139488Smckusick 	register struct nfsnode *np = VTONFS(vp);
29239341Smckusick 	int error = 0;
29338414Smckusick 
29452196Smckusick 	if ((np->n_flag & NMODIFIED) &&
29552196Smckusick 	    (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) == 0 &&
29652196Smckusick 	    vp->v_type == VREG) {
29741905Smckusick 		np->n_flag &= ~NMODIFIED;
29839751Smckusick 		vinvalbuf(vp, TRUE);
29941905Smckusick 		np->n_attrstamp = 0;
30039341Smckusick 		if (np->n_flag & NWRITEERR) {
30139341Smckusick 			np->n_flag &= ~NWRITEERR;
30239751Smckusick 			error = np->n_error;
30339341Smckusick 		}
30438884Smacklem 	}
30538414Smckusick 	return (error);
30638414Smckusick }
30738414Smckusick 
30838414Smckusick /*
30938414Smckusick  * nfs getattr call from vfs.
31038414Smckusick  */
31152234Sheideman int
31252196Smckusick nfs_getattr(vp, vap, cred, procp)
31339488Smckusick 	register struct vnode *vp;
31439488Smckusick 	struct vattr *vap;
31538414Smckusick 	struct ucred *cred;
31652196Smckusick 	struct proc *procp;
31738414Smckusick {
31839488Smckusick 	register caddr_t cp;
31939488Smckusick 	caddr_t bpos, dpos;
32039488Smckusick 	int error = 0;
32139488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
32238414Smckusick 
32338414Smckusick 	/* First look in the cache.. */
32438414Smckusick 	if (nfs_getattrcache(vp, vap) == 0)
32538414Smckusick 		return (0);
32638414Smckusick 	nfsstats.rpccnt[NFSPROC_GETATTR]++;
32752196Smckusick 	nfsm_reqhead(vp, NFSPROC_GETATTR, NFSX_FH);
32838414Smckusick 	nfsm_fhtom(vp);
32952196Smckusick 	nfsm_request(vp, NFSPROC_GETATTR, procp, cred);
33038414Smckusick 	nfsm_loadattr(vp, vap);
33138414Smckusick 	nfsm_reqdone;
33238414Smckusick 	return (error);
33338414Smckusick }
33438414Smckusick 
33538414Smckusick /*
33638414Smckusick  * nfs setattr call.
33738414Smckusick  */
33852234Sheideman int
33952196Smckusick nfs_setattr(vp, vap, cred, procp)
34039488Smckusick 	register struct vnode *vp;
34138414Smckusick 	register struct vattr *vap;
34238414Smckusick 	struct ucred *cred;
34352196Smckusick 	struct proc *procp;
34438414Smckusick {
34538884Smacklem 	register struct nfsv2_sattr *sp;
34639488Smckusick 	register caddr_t cp;
34739488Smckusick 	register long t1;
34852196Smckusick 	caddr_t bpos, dpos, cp2;
34952196Smckusick 	u_long *tl;
35039488Smckusick 	int error = 0;
35139488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
35252196Smckusick 	struct nfsnode *np = VTONFS(vp);
35352196Smckusick 	u_quad_t frev;
35438414Smckusick 
35538414Smckusick 	nfsstats.rpccnt[NFSPROC_SETATTR]++;
35652196Smckusick 	nfsm_reqhead(vp, NFSPROC_SETATTR, NFSX_FH+NFSX_SATTR);
35738414Smckusick 	nfsm_fhtom(vp);
35838884Smacklem 	nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR);
35938414Smckusick 	if (vap->va_mode == 0xffff)
36038884Smacklem 		sp->sa_mode = VNOVAL;
36138414Smckusick 	else
36238884Smacklem 		sp->sa_mode = vtonfs_mode(vp->v_type, vap->va_mode);
36338414Smckusick 	if (vap->va_uid == 0xffff)
36438884Smacklem 		sp->sa_uid = VNOVAL;
36538414Smckusick 	else
36638884Smacklem 		sp->sa_uid = txdr_unsigned(vap->va_uid);
36738414Smckusick 	if (vap->va_gid == 0xffff)
36838884Smacklem 		sp->sa_gid = VNOVAL;
36938414Smckusick 	else
37038884Smacklem 		sp->sa_gid = txdr_unsigned(vap->va_gid);
37138884Smacklem 	sp->sa_size = txdr_unsigned(vap->va_size);
37244988Smckusick 	sp->sa_atime.tv_sec = txdr_unsigned(vap->va_atime.tv_sec);
37344988Smckusick 	sp->sa_atime.tv_usec = txdr_unsigned(vap->va_flags);
37444988Smckusick 	txdr_time(&vap->va_mtime, &sp->sa_mtime);
37544988Smckusick 	if (vap->va_size != VNOVAL || vap->va_mtime.tv_sec != VNOVAL ||
37644988Smckusick 	    vap->va_atime.tv_sec != VNOVAL) {
37739359Smckusick 		if (np->n_flag & NMODIFIED) {
37839359Smckusick 			np->n_flag &= ~NMODIFIED;
37946988Smckusick 			if (vap->va_size == 0)
38046988Smckusick 				vinvalbuf(vp, FALSE);
38146988Smckusick 			else
38246988Smckusick 				vinvalbuf(vp, TRUE);
38339359Smckusick 		}
38439359Smckusick 	}
38552196Smckusick 	nfsm_request(vp, NFSPROC_SETATTR, procp, cred);
38638414Smckusick 	nfsm_loadattr(vp, (struct vattr *)0);
38752196Smckusick 	if ((VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) &&
38852196Smckusick 	    NQNFS_CKCACHABLE(vp, NQL_WRITE)) {
38952196Smckusick 		nfsm_dissect(tl, u_long *, 2*NFSX_UNSIGNED);
39052196Smckusick 		fxdr_hyper(tl, &frev);
39152196Smckusick 		if (QUADGT(frev, np->n_brev))
39252196Smckusick 			np->n_brev = frev;
39352196Smckusick 	}
39438414Smckusick 	nfsm_reqdone;
39538414Smckusick 	return (error);
39638414Smckusick }
39738414Smckusick 
39838414Smckusick /*
39938414Smckusick  * nfs lookup call, one step at a time...
40038414Smckusick  * First look in cache
40138414Smckusick  * If not found, unlock the directory nfsnode and do the rpc
40238414Smckusick  */
40352234Sheideman int
40452317Sheideman nfs_lookup(dvp, vpp, cnp)
40552234Sheideman 	struct vnode *dvp;
40652234Sheideman 	struct vnode **vpp;
40752234Sheideman 	struct componentname *cnp;
40838414Smckusick {
40938414Smckusick 	register struct vnode *vdp;
41048054Smckusick 	register u_long *tl;
41139488Smckusick 	register caddr_t cp;
41239488Smckusick 	register long t1, t2;
41352196Smckusick 	struct nfsmount *nmp;
41452196Smckusick 	struct nfsnode *tp;
41539488Smckusick 	caddr_t bpos, dpos, cp2;
41652196Smckusick 	time_t reqtime;
41739488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
41838414Smckusick 	struct vnode *newvp;
41938414Smckusick 	long len;
42038414Smckusick 	nfsv2fh_t *fhp;
42138414Smckusick 	struct nfsnode *np;
42252234Sheideman 	int lockparent, wantparent, error = 0;
42352196Smckusick 	int nqlflag, cachable;
42452196Smckusick 	u_quad_t frev;
42538414Smckusick 
42652234Sheideman 	*vpp = NULL;
42752234Sheideman 	if (dvp->v_type != VDIR)
42838414Smckusick 		return (ENOTDIR);
42952234Sheideman 	lockparent = cnp->cn_flags & LOCKPARENT;
43052234Sheideman 	wantparent = cnp->cn_flags & (LOCKPARENT|WANTPARENT);
43152234Sheideman 	nmp = VFSTONFS(dvp->v_mount);
43252234Sheideman 	np = VTONFS(dvp);
43352234Sheideman 	if ((error = cache_lookup(dvp, vpp, cnp)) && error != ENOENT) {
43438884Smacklem 		struct vattr vattr;
43538884Smacklem 		int vpid;
43638884Smacklem 
43752234Sheideman 		vdp = *vpp;
43838884Smacklem 		vpid = vdp->v_id;
43938414Smckusick 		/*
44038884Smacklem 		 * See the comment starting `Step through' in ufs/ufs_lookup.c
44138884Smacklem 		 * for an explanation of the locking protocol
44238414Smckusick 		 */
44352234Sheideman 		if (dvp == vdp) {
44438425Smckusick 			VREF(vdp);
44539441Smckusick 			error = 0;
44652196Smckusick 		} else
44739441Smckusick 			error = vget(vdp);
44839441Smckusick 		if (!error) {
44940251Smckusick 			if (vpid == vdp->v_id) {
45052196Smckusick 			   if (nmp->nm_flag & NFSMNT_NQNFS) {
45152234Sheideman 			        if (NQNFS_CKCACHABLE(dvp, NQL_READ)) {
45252196Smckusick 					if (QUADNE(np->n_lrev, np->n_brev) ||
45352196Smckusick 					    (np->n_flag & NMODIFIED)) {
45452196Smckusick 						np->n_direofoffset = 0;
45552234Sheideman 						cache_purge(dvp);
45652196Smckusick 						np->n_flag &= ~NMODIFIED;
45752234Sheideman 						vinvalbuf(dvp, FALSE);
45852196Smckusick 						np->n_brev = np->n_lrev;
45952196Smckusick 					} else {
46052196Smckusick 						nfsstats.lookupcache_hits++;
46152234Sheideman 						if (cnp->cn_nameiop != LOOKUP &&
46252234Sheideman 						    (cnp->cn_flags&ISLASTCN))
46352234Sheideman 						    cnp->cn_flags |= SAVENAME;
46452196Smckusick 						return (0);
46552196Smckusick 					}
46652196Smckusick 				}
46752234Sheideman 			   } else if (!nfs_getattr(vdp, &vattr, cnp->cn_cred, cnp->cn_proc) &&
46840251Smckusick 			       vattr.va_ctime.tv_sec == VTONFS(vdp)->n_ctime) {
46939441Smckusick 				nfsstats.lookupcache_hits++;
47052234Sheideman 				if (cnp->cn_nameiop != LOOKUP && (cnp->cn_flags&ISLASTCN))
47152234Sheideman 					cnp->cn_flags |= SAVENAME;
47239441Smckusick 				return (0);
47340251Smckusick 			   }
47447289Smckusick 			   cache_purge(vdp);
47539441Smckusick 			}
47652196Smckusick 			vrele(vdp);
47738884Smacklem 		}
47852234Sheideman 		*vpp = NULLVP;
47952196Smckusick 	}
48039341Smckusick 	error = 0;
48138414Smckusick 	nfsstats.lookupcache_misses++;
48238414Smckusick 	nfsstats.rpccnt[NFSPROC_LOOKUP]++;
48352234Sheideman 	len = cnp->cn_namelen;
48452234Sheideman 	nfsm_reqhead(dvp, NFSPROC_LOOKUP, NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len));
48552196Smckusick 
48652196Smckusick 	/*
48752196Smckusick 	 * For nqnfs optionally piggyback a getlease request for the name
48852196Smckusick 	 * being looked up.
48952196Smckusick 	 */
49052196Smckusick 	if (nmp->nm_flag & NFSMNT_NQNFS) {
49152196Smckusick 		if ((nmp->nm_flag & NFSMNT_NQLOOKLEASE) &&
49252234Sheideman 		    ((cnp->cn_flags&MAKEENTRY) && (cnp->cn_nameiop != DELETE || !(cnp->cn_flags&ISLASTCN)))) {
49352196Smckusick 			nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED);
49452196Smckusick 			*tl++ = txdr_unsigned(NQL_READ);
49552196Smckusick 			*tl = txdr_unsigned(nmp->nm_leaseterm);
49652196Smckusick 		} else {
49752196Smckusick 			nfsm_build(tl, u_long *, NFSX_UNSIGNED);
49852196Smckusick 			*tl = 0;
49952196Smckusick 		}
50052196Smckusick 	}
50152234Sheideman 	nfsm_fhtom(dvp);
50252234Sheideman 	nfsm_strtom(cnp->cn_nameptr, len, NFS_MAXNAMLEN);
50352196Smckusick 	reqtime = time.tv_sec;
50452234Sheideman 	nfsm_request(dvp, NFSPROC_LOOKUP, cnp->cn_proc, cnp->cn_cred);
50538414Smckusick nfsmout:
50638414Smckusick 	if (error) {
507*52823Smckusick 		if ((cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME) &&
508*52823Smckusick 		    (cnp->cn_flags & ISLASTCN) && error == ENOENT)
509*52823Smckusick 			error = EJUSTRETURN;
51052234Sheideman 		if (cnp->cn_nameiop != LOOKUP && (cnp->cn_flags&ISLASTCN))
51152234Sheideman 			cnp->cn_flags |= SAVENAME;
51240483Smckusick 		return (error);
51338414Smckusick 	}
51452196Smckusick 	if (nmp->nm_flag & NFSMNT_NQNFS) {
51552196Smckusick 		nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
51652196Smckusick 		if (*tl) {
51752196Smckusick 			nqlflag = fxdr_unsigned(int, *tl);
51852196Smckusick 			nfsm_dissect(tl, u_long *, 4*NFSX_UNSIGNED);
51952196Smckusick 			cachable = fxdr_unsigned(int, *tl++);
52052196Smckusick 			reqtime += fxdr_unsigned(int, *tl++);
52152196Smckusick 			fxdr_hyper(tl, &frev);
52252196Smckusick 		} else
52352196Smckusick 			nqlflag = 0;
52452196Smckusick 	}
52552196Smckusick 	nfsm_dissect(fhp, nfsv2fh_t *, NFSX_FH);
52638414Smckusick 
52738414Smckusick 	/*
52852196Smckusick 	 * Handle RENAME case...
52938414Smckusick 	 */
53052234Sheideman 	if (cnp->cn_nameiop == RENAME && wantparent && (cnp->cn_flags&ISLASTCN)) {
53152196Smckusick 		if (!bcmp(np->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) {
53238414Smckusick 			m_freem(mrep);
53338414Smckusick 			return (EISDIR);
53438414Smckusick 		}
53552234Sheideman 		if (error = nfs_nget(dvp->v_mount, fhp, &np)) {
53638414Smckusick 			m_freem(mrep);
53738414Smckusick 			return (error);
53838414Smckusick 		}
53938414Smckusick 		newvp = NFSTOV(np);
54039459Smckusick 		if (error =
54139459Smckusick 		    nfs_loadattrcache(&newvp, &md, &dpos, (struct vattr *)0)) {
54252196Smckusick 			vrele(newvp);
54338414Smckusick 			m_freem(mrep);
54438414Smckusick 			return (error);
54538414Smckusick 		}
54652234Sheideman 		*vpp = newvp;
54745037Smckusick 		m_freem(mrep);
54852234Sheideman 		cnp->cn_flags |= SAVENAME;
54938414Smckusick 		return (0);
55038414Smckusick 	}
55138414Smckusick 
55252196Smckusick 	if (!bcmp(np->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) {
55352234Sheideman 		VREF(dvp);
55452234Sheideman 		newvp = dvp;
55538414Smckusick 	} else {
55652234Sheideman 		if (error = nfs_nget(dvp->v_mount, fhp, &np)) {
55738414Smckusick 			m_freem(mrep);
55838414Smckusick 			return (error);
55938414Smckusick 		}
56038414Smckusick 		newvp = NFSTOV(np);
56138414Smckusick 	}
56239459Smckusick 	if (error = nfs_loadattrcache(&newvp, &md, &dpos, (struct vattr *)0)) {
56352196Smckusick 		vrele(newvp);
56438414Smckusick 		m_freem(mrep);
56538414Smckusick 		return (error);
56638414Smckusick 	}
56738414Smckusick 	m_freem(mrep);
56852234Sheideman 	*vpp = newvp;
56952234Sheideman 	if (cnp->cn_nameiop != LOOKUP && (cnp->cn_flags&ISLASTCN))
57052234Sheideman 		cnp->cn_flags |= SAVENAME;
57152234Sheideman 	if ((cnp->cn_flags&MAKEENTRY) && (cnp->cn_nameiop != DELETE || !(cnp->cn_flags&ISLASTCN))) {
57252196Smckusick 		if ((nmp->nm_flag & NFSMNT_NQNFS) == 0)
57352196Smckusick 			np->n_ctime = np->n_vattr.va_ctime.tv_sec;
57452196Smckusick 		else if (nqlflag && reqtime > time.tv_sec) {
57552196Smckusick 			if (np->n_tnext) {
57652196Smckusick 				if (np->n_tnext == (struct nfsnode *)nmp)
57752196Smckusick 					nmp->nm_tprev = np->n_tprev;
57852196Smckusick 				else
57952196Smckusick 					np->n_tnext->n_tprev = np->n_tprev;
58052196Smckusick 				if (np->n_tprev == (struct nfsnode *)nmp)
58152196Smckusick 					nmp->nm_tnext = np->n_tnext;
58252196Smckusick 				else
58352196Smckusick 					np->n_tprev->n_tnext = np->n_tnext;
58452196Smckusick 				if (nqlflag == NQL_WRITE)
58552196Smckusick 					np->n_flag |= NQNFSWRITE;
58652196Smckusick 			} else if (nqlflag == NQL_READ)
58752196Smckusick 				np->n_flag &= ~NQNFSWRITE;
58852196Smckusick 			else
58952196Smckusick 				np->n_flag |= NQNFSWRITE;
59052196Smckusick 			if (cachable)
59152196Smckusick 				np->n_flag &= ~NQNFSNONCACHE;
59252196Smckusick 			else
59352196Smckusick 				np->n_flag |= NQNFSNONCACHE;
59452196Smckusick 			np->n_expiry = reqtime;
59552196Smckusick 			np->n_lrev = frev;
59652196Smckusick 			tp = nmp->nm_tprev;
59752196Smckusick 			while (tp != (struct nfsnode *)nmp && tp->n_expiry > np->n_expiry)
59852196Smckusick 				tp = tp->n_tprev;
59952196Smckusick 			if (tp == (struct nfsnode *)nmp) {
60052196Smckusick 				np->n_tnext = nmp->nm_tnext;
60152196Smckusick 				nmp->nm_tnext = np;
60252196Smckusick 			} else {
60352196Smckusick 				np->n_tnext = tp->n_tnext;
60452196Smckusick 				tp->n_tnext = np;
60552196Smckusick 			}
60652196Smckusick 			np->n_tprev = tp;
60752196Smckusick 			if (np->n_tnext == (struct nfsnode *)nmp)
60852196Smckusick 				nmp->nm_tprev = np;
60952196Smckusick 			else
61052196Smckusick 				np->n_tnext->n_tprev = np;
61152196Smckusick 		}
61252234Sheideman 		cache_enter(dvp, *vpp, cnp);
61340251Smckusick 	}
61452196Smckusick 	return (0);
61538414Smckusick }
61638414Smckusick 
61738414Smckusick /*
61841905Smckusick  * nfs read call.
61941905Smckusick  * Just call nfs_bioread() to do the work.
62041905Smckusick  */
62152234Sheideman int
62241905Smckusick nfs_read(vp, uiop, ioflag, cred)
62341905Smckusick 	register struct vnode *vp;
62441905Smckusick 	struct uio *uiop;
62541905Smckusick 	int ioflag;
62641905Smckusick 	struct ucred *cred;
62741905Smckusick {
62841905Smckusick 	if (vp->v_type != VREG)
62941905Smckusick 		return (EPERM);
63041905Smckusick 	return (nfs_bioread(vp, uiop, ioflag, cred));
63141905Smckusick }
63241905Smckusick 
63341905Smckusick /*
63438414Smckusick  * nfs readlink call
63538414Smckusick  */
63652234Sheideman int
63738414Smckusick nfs_readlink(vp, uiop, cred)
63841905Smckusick 	struct vnode *vp;
63941905Smckusick 	struct uio *uiop;
64041905Smckusick 	struct ucred *cred;
64141905Smckusick {
64241905Smckusick 	if (vp->v_type != VLNK)
64341905Smckusick 		return (EPERM);
64441905Smckusick 	return (nfs_bioread(vp, uiop, 0, cred));
64541905Smckusick }
64641905Smckusick 
64741905Smckusick /*
64841905Smckusick  * Do a readlink rpc.
64941905Smckusick  * Called by nfs_doio() from below the buffer cache.
65041905Smckusick  */
65152234Sheideman int
65248054Smckusick nfs_readlinkrpc(vp, uiop, cred)
65339488Smckusick 	register struct vnode *vp;
65438414Smckusick 	struct uio *uiop;
65538414Smckusick 	struct ucred *cred;
65638414Smckusick {
65748054Smckusick 	register u_long *tl;
65839488Smckusick 	register caddr_t cp;
65939488Smckusick 	register long t1;
66039488Smckusick 	caddr_t bpos, dpos, cp2;
66139488Smckusick 	int error = 0;
66239488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
66338414Smckusick 	long len;
66438414Smckusick 
66538414Smckusick 	nfsstats.rpccnt[NFSPROC_READLINK]++;
66652196Smckusick 	nfsm_reqhead(vp, NFSPROC_READLINK, NFSX_FH);
66738414Smckusick 	nfsm_fhtom(vp);
66852196Smckusick 	nfsm_request(vp, NFSPROC_READLINK, uiop->uio_procp, cred);
66938414Smckusick 	nfsm_strsiz(len, NFS_MAXPATHLEN);
67038414Smckusick 	nfsm_mtouio(uiop, len);
67138414Smckusick 	nfsm_reqdone;
67238414Smckusick 	return (error);
67338414Smckusick }
67438414Smckusick 
67538414Smckusick /*
67641905Smckusick  * nfs read rpc call
67741905Smckusick  * Ditto above
67838414Smckusick  */
67952234Sheideman int
68048054Smckusick nfs_readrpc(vp, uiop, cred)
68139488Smckusick 	register struct vnode *vp;
68238414Smckusick 	struct uio *uiop;
68338414Smckusick 	struct ucred *cred;
68438414Smckusick {
68548054Smckusick 	register u_long *tl;
68639488Smckusick 	register caddr_t cp;
68739488Smckusick 	register long t1;
68839488Smckusick 	caddr_t bpos, dpos, cp2;
68939488Smckusick 	int error = 0;
69039488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
69138414Smckusick 	struct nfsmount *nmp;
69238414Smckusick 	long len, retlen, tsiz;
69338414Smckusick 
69441398Smckusick 	nmp = VFSTONFS(vp->v_mount);
69538414Smckusick 	tsiz = uiop->uio_resid;
69638414Smckusick 	while (tsiz > 0) {
69738414Smckusick 		nfsstats.rpccnt[NFSPROC_READ]++;
69838414Smckusick 		len = (tsiz > nmp->nm_rsize) ? nmp->nm_rsize : tsiz;
69952196Smckusick 		nfsm_reqhead(vp, NFSPROC_READ, NFSX_FH+NFSX_UNSIGNED*3);
70038414Smckusick 		nfsm_fhtom(vp);
70148054Smckusick 		nfsm_build(tl, u_long *, NFSX_UNSIGNED*3);
70248054Smckusick 		*tl++ = txdr_unsigned(uiop->uio_offset);
70348054Smckusick 		*tl++ = txdr_unsigned(len);
70448054Smckusick 		*tl = 0;
70552196Smckusick 		nfsm_request(vp, NFSPROC_READ, uiop->uio_procp, cred);
70638414Smckusick 		nfsm_loadattr(vp, (struct vattr *)0);
70738414Smckusick 		nfsm_strsiz(retlen, nmp->nm_rsize);
70838414Smckusick 		nfsm_mtouio(uiop, retlen);
70938414Smckusick 		m_freem(mrep);
71038414Smckusick 		if (retlen < len)
71138414Smckusick 			tsiz = 0;
71238414Smckusick 		else
71338414Smckusick 			tsiz -= len;
71438414Smckusick 	}
71538414Smckusick nfsmout:
71638414Smckusick 	return (error);
71738414Smckusick }
71838414Smckusick 
71938414Smckusick /*
72038414Smckusick  * nfs write call
72138414Smckusick  */
72252234Sheideman int
72348054Smckusick nfs_writerpc(vp, uiop, cred)
72439488Smckusick 	register struct vnode *vp;
72538414Smckusick 	struct uio *uiop;
72638414Smckusick 	struct ucred *cred;
72738414Smckusick {
72848054Smckusick 	register u_long *tl;
72939488Smckusick 	register caddr_t cp;
73039488Smckusick 	register long t1;
73152196Smckusick 	caddr_t bpos, dpos, cp2;
73239488Smckusick 	int error = 0;
73339488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
73438414Smckusick 	struct nfsmount *nmp;
73552196Smckusick 	struct nfsnode *np = VTONFS(vp);
73652196Smckusick 	u_quad_t frev;
73738414Smckusick 	long len, tsiz;
73838414Smckusick 
73941398Smckusick 	nmp = VFSTONFS(vp->v_mount);
74038414Smckusick 	tsiz = uiop->uio_resid;
74138414Smckusick 	while (tsiz > 0) {
74238414Smckusick 		nfsstats.rpccnt[NFSPROC_WRITE]++;
74338414Smckusick 		len = (tsiz > nmp->nm_wsize) ? nmp->nm_wsize : tsiz;
74452196Smckusick 		nfsm_reqhead(vp, NFSPROC_WRITE,
74552196Smckusick 			NFSX_FH+NFSX_UNSIGNED*4+nfsm_rndup(len));
74638414Smckusick 		nfsm_fhtom(vp);
74748054Smckusick 		nfsm_build(tl, u_long *, NFSX_UNSIGNED*4);
74848054Smckusick 		*(tl+1) = txdr_unsigned(uiop->uio_offset);
74948054Smckusick 		*(tl+3) = txdr_unsigned(len);
75038414Smckusick 		nfsm_uiotom(uiop, len);
75152196Smckusick 		nfsm_request(vp, NFSPROC_WRITE, uiop->uio_procp, cred);
75238414Smckusick 		nfsm_loadattr(vp, (struct vattr *)0);
75352196Smckusick 		if (nmp->nm_flag & NFSMNT_MYWRITE)
75452196Smckusick 			VTONFS(vp)->n_mtime = VTONFS(vp)->n_vattr.va_mtime.tv_sec;
75552196Smckusick 		else if ((nmp->nm_flag & NFSMNT_NQNFS) &&
75652196Smckusick 			 NQNFS_CKCACHABLE(vp, NQL_WRITE)) {
75752196Smckusick 			nfsm_dissect(tl, u_long *, 2*NFSX_UNSIGNED);
75852196Smckusick 			fxdr_hyper(tl, &frev);
75952196Smckusick 			if (QUADGT(frev, np->n_brev))
76052196Smckusick 				np->n_brev = frev;
76152196Smckusick 		}
76238414Smckusick 		m_freem(mrep);
76338414Smckusick 		tsiz -= len;
76438414Smckusick 	}
76538414Smckusick nfsmout:
76652196Smckusick 	if (error)
76752196Smckusick 		uiop->uio_resid = tsiz;
76838414Smckusick 	return (error);
76938414Smckusick }
77038414Smckusick 
77138414Smckusick /*
77239459Smckusick  * nfs mknod call
77342246Smckusick  * This is a kludge. Use a create rpc but with the IFMT bits of the mode
77442246Smckusick  * set to specify the file type and the size field for rdev.
77539459Smckusick  */
77639459Smckusick /* ARGSUSED */
77752234Sheideman int
77852317Sheideman nfs_mknod(dvp, vpp, cnp, vap)
77952234Sheideman 	struct vnode *dvp;
78052234Sheideman 	struct vnode **vpp;
78152234Sheideman 	struct componentname *cnp;
78252234Sheideman 	struct vattr *vap;
78339459Smckusick {
78442246Smckusick 	register struct nfsv2_sattr *sp;
78548054Smckusick 	register u_long *tl;
78642246Smckusick 	register caddr_t cp;
78752196Smckusick 	register long t2;
78842246Smckusick 	caddr_t bpos, dpos;
78942246Smckusick 	int error = 0;
79042246Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
79142246Smckusick 	u_long rdev;
79239459Smckusick 
79342246Smckusick 	if (vap->va_type == VCHR || vap->va_type == VBLK)
79442246Smckusick 		rdev = txdr_unsigned(vap->va_rdev);
79542246Smckusick #ifdef FIFO
79642246Smckusick 	else if (vap->va_type == VFIFO)
79742246Smckusick 		rdev = 0xffffffff;
79842246Smckusick #endif /* FIFO */
79942246Smckusick 	else {
80052234Sheideman 		VOP_ABORTOP(dvp, cnp);
80152234Sheideman 		vput(dvp);
80242246Smckusick 		return (EOPNOTSUPP);
80342246Smckusick 	}
80442246Smckusick 	nfsstats.rpccnt[NFSPROC_CREATE]++;
80552234Sheideman 	nfsm_reqhead(dvp, NFSPROC_CREATE,
80652234Sheideman 	  NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen)+NFSX_SATTR);
80752234Sheideman 	nfsm_fhtom(dvp);
80852234Sheideman 	nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
80942246Smckusick 	nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR);
81042246Smckusick 	sp->sa_mode = vtonfs_mode(vap->va_type, vap->va_mode);
81152234Sheideman 	sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid);
81252234Sheideman 	sp->sa_gid = txdr_unsigned(cnp->cn_cred->cr_gid);
81342246Smckusick 	sp->sa_size = rdev;
81442246Smckusick 	/* or should these be VNOVAL ?? */
81542246Smckusick 	txdr_time(&vap->va_atime, &sp->sa_atime);
81642246Smckusick 	txdr_time(&vap->va_mtime, &sp->sa_mtime);
81752234Sheideman 	nfsm_request(dvp, NFSPROC_CREATE, cnp->cn_proc, cnp->cn_cred);
81842246Smckusick 	nfsm_reqdone;
81952234Sheideman 	FREE(cnp->cn_pnbuf, M_NAMEI);
82052234Sheideman 	VTONFS(dvp)->n_flag |= NMODIFIED;
82152234Sheideman 	vrele(dvp);
82242246Smckusick 	return (error);
82339459Smckusick }
82439459Smckusick 
82539459Smckusick /*
82638414Smckusick  * nfs file create call
82738414Smckusick  */
82852234Sheideman int
82952317Sheideman nfs_create(dvp, vpp, cnp, vap)
83052234Sheideman 	struct vnode *dvp;
83152234Sheideman 	struct vnode **vpp;
83252234Sheideman 	struct componentname *cnp;
83352234Sheideman 	struct vattr *vap;
83438414Smckusick {
83538884Smacklem 	register struct nfsv2_sattr *sp;
83648054Smckusick 	register u_long *tl;
83739488Smckusick 	register caddr_t cp;
83839488Smckusick 	register long t1, t2;
83939488Smckusick 	caddr_t bpos, dpos, cp2;
84039488Smckusick 	int error = 0;
84139488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
84238414Smckusick 
84338414Smckusick 	nfsstats.rpccnt[NFSPROC_CREATE]++;
84452234Sheideman 	nfsm_reqhead(dvp, NFSPROC_CREATE,
84552234Sheideman 	  NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen)+NFSX_SATTR);
84652234Sheideman 	nfsm_fhtom(dvp);
84752234Sheideman 	nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
84838884Smacklem 	nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR);
84946988Smckusick 	sp->sa_mode = vtonfs_mode(vap->va_type, vap->va_mode);
85052234Sheideman 	sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid);
85152234Sheideman 	sp->sa_gid = txdr_unsigned(cnp->cn_cred->cr_gid);
85238884Smacklem 	sp->sa_size = txdr_unsigned(0);
85338414Smckusick 	/* or should these be VNOVAL ?? */
85438884Smacklem 	txdr_time(&vap->va_atime, &sp->sa_atime);
85538884Smacklem 	txdr_time(&vap->va_mtime, &sp->sa_mtime);
85652234Sheideman 	nfsm_request(dvp, NFSPROC_CREATE, cnp->cn_proc, cnp->cn_cred);
85752234Sheideman 	nfsm_mtofh(dvp, *vpp);
85838414Smckusick 	nfsm_reqdone;
85952234Sheideman 	FREE(cnp->cn_pnbuf, M_NAMEI);
86052234Sheideman 	VTONFS(dvp)->n_flag |= NMODIFIED;
86152234Sheideman 	vrele(dvp);
86238414Smckusick 	return (error);
86338414Smckusick }
86438414Smckusick 
86538414Smckusick /*
86638414Smckusick  * nfs file remove call
86741905Smckusick  * To try and make nfs semantics closer to ufs semantics, a file that has
86841905Smckusick  * other processes using the vnode is renamed instead of removed and then
86939341Smckusick  * removed later on the last close.
87041905Smckusick  * - If v_usecount > 1
87139341Smckusick  *	  If a rename is not already in the works
87239341Smckusick  *	     call nfs_sillyrename() to set it up
87339341Smckusick  *     else
87439341Smckusick  *	  do the remove rpc
87538414Smckusick  */
87652234Sheideman int
87752317Sheideman nfs_remove(dvp, vp, cnp)
87852234Sheideman 	struct vnode *dvp, *vp;
87952234Sheideman 	struct componentname *cnp;
88038414Smckusick {
88152234Sheideman 	register struct nfsnode *np = VTONFS(vp);
88248054Smckusick 	register u_long *tl;
88339488Smckusick 	register caddr_t cp;
88452196Smckusick 	register long t2;
88539488Smckusick 	caddr_t bpos, dpos;
88639488Smckusick 	int error = 0;
88739488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
88838414Smckusick 
88939810Smckusick 	if (vp->v_usecount > 1) {
89039341Smckusick 		if (!np->n_sillyrename)
89152317Sheideman 			error = nfs_sillyrename(dvp, vp, cnp);
89239341Smckusick 	} else {
89352196Smckusick 		/*
89452196Smckusick 		 * Purge the name cache so that the chance of a lookup for
89552196Smckusick 		 * the name succeeding while the remove is in progress is
89652196Smckusick 		 * minimized. Without node locking it can still happen, such
89752196Smckusick 		 * that an I/O op returns ESTALE, but since you get this if
89852196Smckusick 		 * another host removes the file..
89952196Smckusick 		 */
90052196Smckusick 		cache_purge(vp);
90152196Smckusick 		/*
90252196Smckusick 		 * Throw away biocache buffers. Mainly to avoid
90352196Smckusick 		 * unnecessary delayed writes.
90452196Smckusick 		 */
90552196Smckusick 		vinvalbuf(vp, FALSE);
90652196Smckusick 		/* Do the rpc */
90738414Smckusick 		nfsstats.rpccnt[NFSPROC_REMOVE]++;
90852234Sheideman 		nfsm_reqhead(dvp, NFSPROC_REMOVE,
90952234Sheideman 			NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen));
91052234Sheideman 		nfsm_fhtom(dvp);
91152234Sheideman 		nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
91252234Sheideman 		nfsm_request(dvp, NFSPROC_REMOVE, cnp->cn_proc, cnp->cn_cred);
91338414Smckusick 		nfsm_reqdone;
91452234Sheideman 		FREE(cnp->cn_pnbuf, M_NAMEI);
91552234Sheideman 		VTONFS(dvp)->n_flag |= NMODIFIED;
91639751Smckusick 		/*
91739751Smckusick 		 * Kludge City: If the first reply to the remove rpc is lost..
91839751Smckusick 		 *   the reply to the retransmitted request will be ENOENT
91939751Smckusick 		 *   since the file was in fact removed
92039751Smckusick 		 *   Therefore, we cheat and return success.
92139751Smckusick 		 */
92239751Smckusick 		if (error == ENOENT)
92339751Smckusick 			error = 0;
92438414Smckusick 	}
92540042Smckusick 	np->n_attrstamp = 0;
92652234Sheideman 	vrele(dvp);
92752196Smckusick 	vrele(vp);
92838414Smckusick 	return (error);
92938414Smckusick }
93038414Smckusick 
93138414Smckusick /*
93238414Smckusick  * nfs file remove rpc called from nfs_inactive
93338414Smckusick  */
93452234Sheideman int
93552196Smckusick nfs_removeit(sp, procp)
93648364Smckusick 	register struct sillyrename *sp;
93752196Smckusick 	struct proc *procp;
93838414Smckusick {
93948054Smckusick 	register u_long *tl;
94039488Smckusick 	register caddr_t cp;
94152196Smckusick 	register long t2;
94239488Smckusick 	caddr_t bpos, dpos;
94339488Smckusick 	int error = 0;
94439488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
94538414Smckusick 
94638414Smckusick 	nfsstats.rpccnt[NFSPROC_REMOVE]++;
94752196Smckusick 	nfsm_reqhead(sp->s_dvp, NFSPROC_REMOVE,
94848364Smckusick 		NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(sp->s_namlen));
94948364Smckusick 	nfsm_fhtom(sp->s_dvp);
95048364Smckusick 	nfsm_strtom(sp->s_name, sp->s_namlen, NFS_MAXNAMLEN);
95152196Smckusick 	nfsm_request(sp->s_dvp, NFSPROC_REMOVE, procp, sp->s_cred);
95238414Smckusick 	nfsm_reqdone;
95348364Smckusick 	VTONFS(sp->s_dvp)->n_flag |= NMODIFIED;
95438414Smckusick 	return (error);
95538414Smckusick }
95638414Smckusick 
95738414Smckusick /*
95838414Smckusick  * nfs file rename call
95938414Smckusick  */
96052234Sheideman int
96152234Sheideman nfs_rename(fdvp, fvp, fcnp,
96252317Sheideman 	   tdvp, tvp, tcnp)
96352234Sheideman 	struct vnode *fdvp, *fvp;
96452234Sheideman 	struct componentname *fcnp;
96552234Sheideman 	struct vnode *tdvp, *tvp;
96652234Sheideman 	struct componentname *tcnp;
96738414Smckusick {
96848054Smckusick 	register u_long *tl;
96939488Smckusick 	register caddr_t cp;
97052196Smckusick 	register long t2;
97139488Smckusick 	caddr_t bpos, dpos;
97239488Smckusick 	int error = 0;
97339488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
97438414Smckusick 
97538414Smckusick 	nfsstats.rpccnt[NFSPROC_RENAME]++;
97652234Sheideman 	nfsm_reqhead(fdvp, NFSPROC_RENAME,
97752234Sheideman 		(NFSX_FH+NFSX_UNSIGNED)*2+nfsm_rndup(fcnp->cn_namelen)+
97852234Sheideman 		nfsm_rndup(fcnp->cn_namelen)); /* or fcnp->cn_cred?*/
97952234Sheideman 	nfsm_fhtom(fdvp);
98052234Sheideman 	nfsm_strtom(fcnp->cn_nameptr, fcnp->cn_namelen, NFS_MAXNAMLEN);
98152234Sheideman 	nfsm_fhtom(tdvp);
98252234Sheideman 	nfsm_strtom(tcnp->cn_nameptr, tcnp->cn_namelen, NFS_MAXNAMLEN);
98352234Sheideman 	nfsm_request(fdvp, NFSPROC_RENAME, tcnp->cn_proc, tcnp->cn_cred);
98438414Smckusick 	nfsm_reqdone;
98552234Sheideman 	VTONFS(fdvp)->n_flag |= NMODIFIED;
98652234Sheideman 	VTONFS(tdvp)->n_flag |= NMODIFIED;
98752234Sheideman 	if (fvp->v_type == VDIR) {
98852234Sheideman 		if (tvp != NULL && tvp->v_type == VDIR)
98952234Sheideman 			cache_purge(tdvp);
99052234Sheideman 		cache_purge(fdvp);
99138414Smckusick 	}
99252234Sheideman 	if (tdvp == tvp)
99352234Sheideman 		vrele(tdvp);
99443360Smckusick 	else
99552234Sheideman 		vput(tdvp);
99652234Sheideman 	if (tvp)
99752234Sheideman 		vput(tvp);
99852234Sheideman 	vrele(fdvp);
99952234Sheideman 	vrele(fvp);
100040112Smckusick 	/*
100140112Smckusick 	 * Kludge: Map ENOENT => 0 assuming that it is a reply to a retry.
100240112Smckusick 	 */
100340112Smckusick 	if (error == ENOENT)
100440112Smckusick 		error = 0;
100538414Smckusick 	return (error);
100638414Smckusick }
100738414Smckusick 
100838414Smckusick /*
100941905Smckusick  * nfs file rename rpc called from nfs_remove() above
101038414Smckusick  */
101152234Sheideman int
101252234Sheideman nfs_renameit(sdvp, scnp, sp)
101352234Sheideman 	struct vnode *sdvp;
101452234Sheideman 	struct componentname *scnp;
101548364Smckusick 	register struct sillyrename *sp;
101638414Smckusick {
101748054Smckusick 	register u_long *tl;
101839488Smckusick 	register caddr_t cp;
101952196Smckusick 	register long t2;
102039488Smckusick 	caddr_t bpos, dpos;
102139488Smckusick 	int error = 0;
102239488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
102338414Smckusick 
102438414Smckusick 	nfsstats.rpccnt[NFSPROC_RENAME]++;
102552234Sheideman 	nfsm_reqhead(sdvp, NFSPROC_RENAME,
102652234Sheideman 		(NFSX_FH+NFSX_UNSIGNED)*2+nfsm_rndup(scnp->cn_namelen)+
102752196Smckusick 		nfsm_rndup(sp->s_namlen));
102852234Sheideman 	nfsm_fhtom(sdvp);
102952234Sheideman 	nfsm_strtom(scnp->cn_nameptr, scnp->cn_namelen, NFS_MAXNAMLEN);
103052234Sheideman 	nfsm_fhtom(sdvp);
103148364Smckusick 	nfsm_strtom(sp->s_name, sp->s_namlen, NFS_MAXNAMLEN);
103252234Sheideman 	nfsm_request(sdvp, NFSPROC_RENAME, scnp->cn_proc, scnp->cn_cred);
103338414Smckusick 	nfsm_reqdone;
103452234Sheideman 	FREE(scnp->cn_pnbuf, M_NAMEI);
103552234Sheideman 	VTONFS(sdvp)->n_flag |= NMODIFIED;
103638414Smckusick 	return (error);
103738414Smckusick }
103838414Smckusick 
103938414Smckusick /*
104038414Smckusick  * nfs hard link create call
104138414Smckusick  */
104252234Sheideman int
1043*52823Smckusick nfs_link(tdvp, vp, cnp)
1044*52823Smckusick 	struct vnode *tdvp;
104552234Sheideman 	register struct vnode *vp;   /* source vnode */
104652234Sheideman 	struct componentname *cnp;
104738414Smckusick {
104848054Smckusick 	register u_long *tl;
104939488Smckusick 	register caddr_t cp;
105052196Smckusick 	register long t2;
105139488Smckusick 	caddr_t bpos, dpos;
105239488Smckusick 	int error = 0;
105339488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
105438414Smckusick 
105538414Smckusick 	nfsstats.rpccnt[NFSPROC_LINK]++;
105652196Smckusick 	nfsm_reqhead(vp, NFSPROC_LINK,
105752234Sheideman 		NFSX_FH*2+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen));
105838414Smckusick 	nfsm_fhtom(vp);
105952234Sheideman 	nfsm_fhtom(tdvp);
106052234Sheideman 	nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
106152234Sheideman 	nfsm_request(vp, NFSPROC_LINK, cnp->cn_proc, cnp->cn_cred);
106238414Smckusick 	nfsm_reqdone;
106352234Sheideman 	FREE(cnp->cn_pnbuf, M_NAMEI);
106440042Smckusick 	VTONFS(vp)->n_attrstamp = 0;
106552234Sheideman 	VTONFS(tdvp)->n_flag |= NMODIFIED;
106652234Sheideman 	vrele(tdvp);
106740112Smckusick 	/*
106840112Smckusick 	 * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry.
106940112Smckusick 	 */
107040112Smckusick 	if (error == EEXIST)
107140112Smckusick 		error = 0;
107238414Smckusick 	return (error);
107338414Smckusick }
107438414Smckusick 
107538414Smckusick /*
107638414Smckusick  * nfs symbolic link create call
107738414Smckusick  */
107852234Sheideman /* start here */
107952234Sheideman int
108052317Sheideman nfs_symlink(dvp, vpp, cnp, vap, nm)
108152234Sheideman 	struct vnode *dvp;
108252234Sheideman 	struct vnode **vpp;
108352234Sheideman 	struct componentname *cnp;
108438414Smckusick 	struct vattr *vap;
108552196Smckusick 	char *nm;
108638414Smckusick {
108738884Smacklem 	register struct nfsv2_sattr *sp;
108848054Smckusick 	register u_long *tl;
108939488Smckusick 	register caddr_t cp;
109052196Smckusick 	register long t2;
109139488Smckusick 	caddr_t bpos, dpos;
109252196Smckusick 	int slen, error = 0;
109339488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
109438414Smckusick 
109538414Smckusick 	nfsstats.rpccnt[NFSPROC_SYMLINK]++;
109652196Smckusick 	slen = strlen(nm);
109752234Sheideman 	nfsm_reqhead(dvp, NFSPROC_SYMLINK,
109852234Sheideman 	 NFSX_FH+2*NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen)+nfsm_rndup(slen)+NFSX_SATTR);
109952234Sheideman 	nfsm_fhtom(dvp);
110052234Sheideman 	nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
110152196Smckusick 	nfsm_strtom(nm, slen, NFS_MAXPATHLEN);
110238884Smacklem 	nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR);
110338884Smacklem 	sp->sa_mode = vtonfs_mode(VLNK, vap->va_mode);
110452234Sheideman 	sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid);
110552234Sheideman 	sp->sa_gid = txdr_unsigned(cnp->cn_cred->cr_gid);
110638884Smacklem 	sp->sa_size = txdr_unsigned(VNOVAL);
110740112Smckusick 	txdr_time(&vap->va_atime, &sp->sa_atime);	/* or VNOVAL ?? */
110838884Smacklem 	txdr_time(&vap->va_mtime, &sp->sa_mtime);	/* or VNOVAL ?? */
110952234Sheideman 	nfsm_request(dvp, NFSPROC_SYMLINK, cnp->cn_proc, cnp->cn_cred);
111038414Smckusick 	nfsm_reqdone;
111152234Sheideman 	FREE(cnp->cn_pnbuf, M_NAMEI);
111252234Sheideman 	VTONFS(dvp)->n_flag |= NMODIFIED;
111352234Sheideman 	vrele(dvp);
111440112Smckusick 	/*
111540112Smckusick 	 * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry.
111640112Smckusick 	 */
111740112Smckusick 	if (error == EEXIST)
111840112Smckusick 		error = 0;
111938414Smckusick 	return (error);
112038414Smckusick }
112138414Smckusick 
112238414Smckusick /*
112338414Smckusick  * nfs make dir call
112438414Smckusick  */
112552234Sheideman int
112652317Sheideman nfs_mkdir(dvp, vpp, cnp, vap)
112752234Sheideman 	struct vnode *dvp;
112852234Sheideman 	struct vnode **vpp;
112952234Sheideman 	struct componentname *cnp;
113038414Smckusick 	struct vattr *vap;
113138414Smckusick {
113238884Smacklem 	register struct nfsv2_sattr *sp;
113348054Smckusick 	register u_long *tl;
113439488Smckusick 	register caddr_t cp;
113539488Smckusick 	register long t1, t2;
113641905Smckusick 	register int len;
113739488Smckusick 	caddr_t bpos, dpos, cp2;
113841905Smckusick 	int error = 0, firsttry = 1;
113939488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
114038414Smckusick 
114152234Sheideman 	len = cnp->cn_namelen;
114238414Smckusick 	nfsstats.rpccnt[NFSPROC_MKDIR]++;
114352234Sheideman 	nfsm_reqhead(dvp, NFSPROC_MKDIR,
114441905Smckusick 	  NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len)+NFSX_SATTR);
114552234Sheideman 	nfsm_fhtom(dvp);
114652234Sheideman 	nfsm_strtom(cnp->cn_nameptr, len, NFS_MAXNAMLEN);
114738884Smacklem 	nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR);
114838884Smacklem 	sp->sa_mode = vtonfs_mode(VDIR, vap->va_mode);
114952234Sheideman 	sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid);
115052234Sheideman 	sp->sa_gid = txdr_unsigned(cnp->cn_cred->cr_gid);
115138884Smacklem 	sp->sa_size = txdr_unsigned(VNOVAL);
115240112Smckusick 	txdr_time(&vap->va_atime, &sp->sa_atime);	/* or VNOVAL ?? */
115338884Smacklem 	txdr_time(&vap->va_mtime, &sp->sa_mtime);	/* or VNOVAL ?? */
115452234Sheideman 	nfsm_request(dvp, NFSPROC_MKDIR, cnp->cn_proc, cnp->cn_cred);
115552234Sheideman 	nfsm_mtofh(dvp, *vpp);
115638414Smckusick 	nfsm_reqdone;
115752234Sheideman 	VTONFS(dvp)->n_flag |= NMODIFIED;
115840112Smckusick 	/*
115941905Smckusick 	 * Kludge: Map EEXIST => 0 assuming that you have a reply to a retry
116041905Smckusick 	 * if we can succeed in looking up the directory.
116141905Smckusick 	 * "firsttry" is necessary since the macros may "goto nfsmout" which
116241905Smckusick 	 * is above the if on errors. (Ugh)
116340112Smckusick 	 */
116441905Smckusick 	if (error == EEXIST && firsttry) {
116541905Smckusick 		firsttry = 0;
116640112Smckusick 		error = 0;
116741905Smckusick 		nfsstats.rpccnt[NFSPROC_LOOKUP]++;
116852234Sheideman 		*vpp = NULL;
116952234Sheideman 		nfsm_reqhead(dvp, NFSPROC_LOOKUP,
117041905Smckusick 		    NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len));
117152234Sheideman 		nfsm_fhtom(dvp);
117252234Sheideman 		nfsm_strtom(cnp->cn_nameptr, len, NFS_MAXNAMLEN);
117352234Sheideman 		nfsm_request(dvp, NFSPROC_LOOKUP, cnp->cn_proc, cnp->cn_cred);
117452234Sheideman 		nfsm_mtofh(dvp, *vpp);
117552234Sheideman 		if ((*vpp)->v_type != VDIR) {
117652234Sheideman 			vput(*vpp);
117741905Smckusick 			error = EEXIST;
117841905Smckusick 		}
117941905Smckusick 		m_freem(mrep);
118041905Smckusick 	}
118152234Sheideman 	FREE(cnp->cn_pnbuf, M_NAMEI);
118252234Sheideman 	vrele(dvp);
118338414Smckusick 	return (error);
118438414Smckusick }
118538414Smckusick 
118638414Smckusick /*
118738414Smckusick  * nfs remove directory call
118838414Smckusick  */
118952234Sheideman int
119052317Sheideman nfs_rmdir(dvp, vp, cnp)
119152234Sheideman 	struct vnode *dvp, *vp;
119252234Sheideman 	struct componentname *cnp;
119338414Smckusick {
119448054Smckusick 	register u_long *tl;
119539488Smckusick 	register caddr_t cp;
119652196Smckusick 	register long t2;
119739488Smckusick 	caddr_t bpos, dpos;
119839488Smckusick 	int error = 0;
119939488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
120038414Smckusick 
120152234Sheideman 	if (dvp == vp) {
120252234Sheideman 		vrele(dvp);
120352234Sheideman 		vrele(dvp);
120452234Sheideman 		FREE(cnp->cn_pnbuf, M_NAMEI);
120538414Smckusick 		return (EINVAL);
120638414Smckusick 	}
120738414Smckusick 	nfsstats.rpccnt[NFSPROC_RMDIR]++;
120852234Sheideman 	nfsm_reqhead(dvp, NFSPROC_RMDIR,
120952234Sheideman 		NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen));
121052234Sheideman 	nfsm_fhtom(dvp);
121152234Sheideman 	nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
121252234Sheideman 	nfsm_request(dvp, NFSPROC_RMDIR, cnp->cn_proc, cnp->cn_cred);
121338414Smckusick 	nfsm_reqdone;
121452234Sheideman 	FREE(cnp->cn_pnbuf, M_NAMEI);
121552234Sheideman 	VTONFS(dvp)->n_flag |= NMODIFIED;
121652234Sheideman 	cache_purge(dvp);
121752234Sheideman 	cache_purge(vp);
121852234Sheideman 	vrele(vp);
121952234Sheideman 	vrele(dvp);
122040112Smckusick 	/*
122140112Smckusick 	 * Kludge: Map ENOENT => 0 assuming that you have a reply to a retry.
122240112Smckusick 	 */
122340112Smckusick 	if (error == ENOENT)
122440112Smckusick 		error = 0;
122538414Smckusick 	return (error);
122638414Smckusick }
122738414Smckusick 
122838414Smckusick /*
122938414Smckusick  * nfs readdir call
123038414Smckusick  * Although cookie is defined as opaque, I translate it to/from net byte
123138414Smckusick  * order so that it looks more sensible. This appears consistent with the
123238414Smckusick  * Ultrix implementation of NFS.
123338414Smckusick  */
123452234Sheideman int
123540296Smckusick nfs_readdir(vp, uiop, cred, eofflagp)
123639488Smckusick 	register struct vnode *vp;
123738414Smckusick 	struct uio *uiop;
123838414Smckusick 	struct ucred *cred;
123940296Smckusick 	int *eofflagp;
124038414Smckusick {
124141905Smckusick 	register struct nfsnode *np = VTONFS(vp);
124241905Smckusick 	int tresid, error;
124341905Smckusick 	struct vattr vattr;
124441905Smckusick 
124541905Smckusick 	if (vp->v_type != VDIR)
124641905Smckusick 		return (EPERM);
124741905Smckusick 	/*
124841905Smckusick 	 * First, check for hit on the EOF offset cache
124941905Smckusick 	 */
125041905Smckusick 	if (uiop->uio_offset != 0 && uiop->uio_offset == np->n_direofoffset &&
125152196Smckusick 	    (np->n_flag & NMODIFIED) == 0) {
125252196Smckusick 		if (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) {
125352196Smckusick 			if (NQNFS_CKCACHABLE(vp, NQL_READ)) {
125452196Smckusick 				*eofflagp = 1;
125552196Smckusick 				nfsstats.direofcache_hits++;
125652196Smckusick 				return (0);
125752196Smckusick 			}
125852196Smckusick 		} else if (nfs_getattr(vp, &vattr, cred, uiop->uio_procp) == 0 &&
125952196Smckusick 			np->n_mtime == vattr.va_mtime.tv_sec) {
126052196Smckusick 			*eofflagp = 1;
126152196Smckusick 			nfsstats.direofcache_hits++;
126252196Smckusick 			return (0);
126352196Smckusick 		}
126441905Smckusick 	}
126541905Smckusick 
126641905Smckusick 	/*
126741905Smckusick 	 * Call nfs_bioread() to do the real work.
126841905Smckusick 	 */
126941905Smckusick 	tresid = uiop->uio_resid;
127041905Smckusick 	error = nfs_bioread(vp, uiop, 0, cred);
127141905Smckusick 
127241905Smckusick 	if (!error && uiop->uio_resid == tresid) {
127341905Smckusick 		*eofflagp = 1;
127441905Smckusick 		nfsstats.direofcache_misses++;
127541905Smckusick 	} else
127641905Smckusick 		*eofflagp = 0;
127741905Smckusick 	return (error);
127841905Smckusick }
127941905Smckusick 
128041905Smckusick /*
128141905Smckusick  * Readdir rpc call.
128241905Smckusick  * Called from below the buffer cache by nfs_doio().
128341905Smckusick  */
128452234Sheideman int
128548054Smckusick nfs_readdirrpc(vp, uiop, cred)
128641905Smckusick 	register struct vnode *vp;
128741905Smckusick 	struct uio *uiop;
128841905Smckusick 	struct ucred *cred;
128941905Smckusick {
129038414Smckusick 	register long len;
129152436Smckusick 	register struct readdir *dp;
129248054Smckusick 	register u_long *tl;
129339488Smckusick 	register caddr_t cp;
129439488Smckusick 	register long t1;
129541905Smckusick 	long tlen, lastlen;
129639488Smckusick 	caddr_t bpos, dpos, cp2;
129739488Smckusick 	int error = 0;
129839488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
129938414Smckusick 	struct mbuf *md2;
130038414Smckusick 	caddr_t dpos2;
130138414Smckusick 	int siz;
130240296Smckusick 	int more_dirs = 1;
130338414Smckusick 	off_t off, savoff;
130452436Smckusick 	struct readdir *savdp;
130540296Smckusick 	struct nfsmount *nmp;
130640296Smckusick 	struct nfsnode *np = VTONFS(vp);
130740296Smckusick 	long tresid;
130838414Smckusick 
130941398Smckusick 	nmp = VFSTONFS(vp->v_mount);
131040296Smckusick 	tresid = uiop->uio_resid;
131140296Smckusick 	/*
131240296Smckusick 	 * Loop around doing readdir rpc's of size uio_resid or nm_rsize,
131348054Smckusick 	 * whichever is smaller, truncated to a multiple of NFS_DIRBLKSIZ.
131441905Smckusick 	 * The stopping criteria is EOF or buffer full.
131540296Smckusick 	 */
131648054Smckusick 	while (more_dirs && uiop->uio_resid >= NFS_DIRBLKSIZ) {
131740296Smckusick 		nfsstats.rpccnt[NFSPROC_READDIR]++;
131852196Smckusick 		nfsm_reqhead(vp, NFSPROC_READDIR,
131952196Smckusick 			NFSX_FH+2*NFSX_UNSIGNED);
132040296Smckusick 		nfsm_fhtom(vp);
132148054Smckusick 		nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED);
132248054Smckusick 		*tl++ = txdr_unsigned(uiop->uio_offset);
132348054Smckusick 		*tl = txdr_unsigned(((uiop->uio_resid > nmp->nm_rsize) ?
132448054Smckusick 			nmp->nm_rsize : uiop->uio_resid) & ~(NFS_DIRBLKSIZ-1));
132552196Smckusick 		nfsm_request(vp, NFSPROC_READDIR, uiop->uio_procp, cred);
132640296Smckusick 		siz = 0;
132752196Smckusick 		nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
132848054Smckusick 		more_dirs = fxdr_unsigned(int, *tl);
132940296Smckusick 
133040296Smckusick 		/* Save the position so that we can do nfsm_mtouio() later */
133140296Smckusick 		dpos2 = dpos;
133240296Smckusick 		md2 = md;
133340296Smckusick 
133440296Smckusick 		/* loop thru the dir entries, doctoring them to 4bsd form */
133541905Smckusick 		off = uiop->uio_offset;
133642246Smckusick #ifdef lint
133752436Smckusick 		dp = (struct readdir *)0;
133842246Smckusick #endif /* lint */
133940296Smckusick 		while (more_dirs && siz < uiop->uio_resid) {
134040296Smckusick 			savoff = off;		/* Hold onto offset and dp */
134140296Smckusick 			savdp = dp;
134252196Smckusick 			nfsm_dissecton(tl, u_long *, 2*NFSX_UNSIGNED);
134352436Smckusick 			dp = (struct readdir *)tl;
134448054Smckusick 			dp->d_ino = fxdr_unsigned(u_long, *tl++);
134548054Smckusick 			len = fxdr_unsigned(int, *tl);
134640296Smckusick 			if (len <= 0 || len > NFS_MAXNAMLEN) {
134740296Smckusick 				error = EBADRPC;
134840296Smckusick 				m_freem(mrep);
134940296Smckusick 				goto nfsmout;
135040296Smckusick 			}
135140296Smckusick 			dp->d_namlen = (u_short)len;
135240296Smckusick 			nfsm_adv(len);		/* Point past name */
135340296Smckusick 			tlen = nfsm_rndup(len);
135440296Smckusick 			/*
135540296Smckusick 			 * This should not be necessary, but some servers have
135640296Smckusick 			 * broken XDR such that these bytes are not null filled.
135740296Smckusick 			 */
135840296Smckusick 			if (tlen != len) {
135940296Smckusick 				*dpos = '\0';	/* Null-terminate */
136040296Smckusick 				nfsm_adv(tlen - len);
136140296Smckusick 				len = tlen;
136240296Smckusick 			}
136352196Smckusick 			nfsm_dissecton(tl, u_long *, 2*NFSX_UNSIGNED);
136448054Smckusick 			off = fxdr_unsigned(off_t, *tl);
136548054Smckusick 			*tl++ = 0;	/* Ensures null termination of name */
136648054Smckusick 			more_dirs = fxdr_unsigned(int, *tl);
136740296Smckusick 			dp->d_reclen = len+4*NFSX_UNSIGNED;
136840296Smckusick 			siz += dp->d_reclen;
136940296Smckusick 		}
137040296Smckusick 		/*
137140296Smckusick 		 * If at end of rpc data, get the eof boolean
137240296Smckusick 		 */
137340296Smckusick 		if (!more_dirs) {
137452196Smckusick 			nfsm_dissecton(tl, u_long *, NFSX_UNSIGNED);
137548054Smckusick 			more_dirs = (fxdr_unsigned(int, *tl) == 0);
137638414Smckusick 
137740296Smckusick 			/*
137840296Smckusick 			 * If at EOF, cache directory offset
137940296Smckusick 			 */
138041905Smckusick 			if (!more_dirs)
138140296Smckusick 				np->n_direofoffset = off;
138238414Smckusick 		}
138340296Smckusick 		/*
138440296Smckusick 		 * If there is too much to fit in the data buffer, use savoff and
138540296Smckusick 		 * savdp to trim off the last record.
138640296Smckusick 		 * --> we are not at eof
138740296Smckusick 		 */
138840296Smckusick 		if (siz > uiop->uio_resid) {
138940296Smckusick 			off = savoff;
139040296Smckusick 			siz -= dp->d_reclen;
139140296Smckusick 			dp = savdp;
139240296Smckusick 			more_dirs = 0;	/* Paranoia */
139340113Smckusick 		}
139440296Smckusick 		if (siz > 0) {
139541905Smckusick 			lastlen = dp->d_reclen;
139640296Smckusick 			md = md2;
139740296Smckusick 			dpos = dpos2;
139840296Smckusick 			nfsm_mtouio(uiop, siz);
139940296Smckusick 			uiop->uio_offset = off;
140040296Smckusick 		} else
140140296Smckusick 			more_dirs = 0;	/* Ugh, never happens, but in case.. */
140240296Smckusick 		m_freem(mrep);
140338414Smckusick 	}
140441905Smckusick 	/*
140548054Smckusick 	 * Fill last record, iff any, out to a multiple of NFS_DIRBLKSIZ
140641905Smckusick 	 * by increasing d_reclen for the last record.
140741905Smckusick 	 */
140841905Smckusick 	if (uiop->uio_resid < tresid) {
140948054Smckusick 		len = uiop->uio_resid & (NFS_DIRBLKSIZ - 1);
141041905Smckusick 		if (len > 0) {
141152436Smckusick 			dp = (struct readdir *)
141241905Smckusick 				(uiop->uio_iov->iov_base - lastlen);
141341905Smckusick 			dp->d_reclen += len;
141441905Smckusick 			uiop->uio_iov->iov_base += len;
141541905Smckusick 			uiop->uio_iov->iov_len -= len;
141641905Smckusick 			uiop->uio_resid -= len;
141741905Smckusick 		}
141841905Smckusick 	}
141940296Smckusick nfsmout:
142038414Smckusick 	return (error);
142138414Smckusick }
142238414Smckusick 
142352196Smckusick /*
142452196Smckusick  * Nqnfs readdir_and_lookup RPC. Used in place of nfs_readdirrpc() when
142552196Smckusick  * the "rdirlook" mount option is specified.
142652196Smckusick  */
142752234Sheideman int
142852196Smckusick nfs_readdirlookrpc(vp, uiop, cred)
142952196Smckusick 	struct vnode *vp;
143052196Smckusick 	register struct uio *uiop;
143152196Smckusick 	struct ucred *cred;
143252196Smckusick {
143352196Smckusick 	register int len;
143452436Smckusick 	register struct readdir *dp;
143552196Smckusick 	register u_long *tl;
143652196Smckusick 	register caddr_t cp;
143752196Smckusick 	register long t1;
143852196Smckusick 	caddr_t bpos, dpos, cp2;
143952196Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
144052196Smckusick 	struct nameidata nami, *ndp = &nami;
144152317Sheideman 	struct componentname *cnp = &ndp->ni_cnd;
144252196Smckusick 	off_t off, endoff;
144352196Smckusick 	time_t reqtime, ltime;
144452196Smckusick 	struct nfsmount *nmp;
144552196Smckusick 	struct nfsnode *np, *tp;
144652196Smckusick 	struct vnode *newvp;
144752196Smckusick 	nfsv2fh_t *fhp;
144852196Smckusick 	u_long fileno;
144952196Smckusick 	u_quad_t frev;
145052196Smckusick 	int error = 0, tlen, more_dirs = 1, tresid, doit, bigenough, i;
145152196Smckusick 	int cachable;
145252196Smckusick 
145352196Smckusick 	if (uiop->uio_iovcnt != 1)
145452196Smckusick 		panic("nfs rdirlook");
145552196Smckusick 	nmp = VFSTONFS(vp->v_mount);
145652196Smckusick 	tresid = uiop->uio_resid;
145752196Smckusick 	ndp->ni_dvp = vp;
145852196Smckusick 	newvp = NULLVP;
145952196Smckusick 	/*
146052196Smckusick 	 * Loop around doing readdir rpc's of size uio_resid or nm_rsize,
146152196Smckusick 	 * whichever is smaller, truncated to a multiple of NFS_DIRBLKSIZ.
146252196Smckusick 	 * The stopping criteria is EOF or buffer full.
146352196Smckusick 	 */
146452196Smckusick 	while (more_dirs && uiop->uio_resid >= NFS_DIRBLKSIZ) {
146552196Smckusick 		nfsstats.rpccnt[NQNFSPROC_READDIRLOOK]++;
146652196Smckusick 		nfsm_reqhead(vp, NQNFSPROC_READDIRLOOK,
146752196Smckusick 			NFSX_FH+3*NFSX_UNSIGNED);
146852196Smckusick 		nfsm_fhtom(vp);
146952196Smckusick 		nfsm_build(tl, u_long *, 3*NFSX_UNSIGNED);
147052196Smckusick 		*tl++ = txdr_unsigned(uiop->uio_offset);
147152196Smckusick 		*tl++ = txdr_unsigned(((uiop->uio_resid > nmp->nm_rsize) ?
147252196Smckusick 			nmp->nm_rsize : uiop->uio_resid) & ~(NFS_DIRBLKSIZ-1));
147352196Smckusick 		*tl = txdr_unsigned(nmp->nm_leaseterm);
147452196Smckusick 		reqtime = time.tv_sec;
147552196Smckusick 		nfsm_request(vp, NQNFSPROC_READDIRLOOK, uiop->uio_procp, cred);
147652196Smckusick 		nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
147752196Smckusick 		more_dirs = fxdr_unsigned(int, *tl);
147852196Smckusick 
147952196Smckusick 		/* loop thru the dir entries, doctoring them to 4bsd form */
148052196Smckusick 		off = uiop->uio_offset;
148152196Smckusick 		bigenough = 1;
148252196Smckusick 		while (more_dirs && bigenough) {
148352196Smckusick 			doit = 1;
148452196Smckusick 			nfsm_dissect(tl, u_long *, 4*NFSX_UNSIGNED);
148552196Smckusick 			cachable = fxdr_unsigned(int, *tl++);
148652196Smckusick 			ltime = reqtime + fxdr_unsigned(int, *tl++);
148752196Smckusick 			fxdr_hyper(tl, &frev);
148852196Smckusick 			nfsm_dissect(fhp, nfsv2fh_t *, NFSX_FH);
148952196Smckusick 			if (!bcmp(VTONFS(vp)->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) {
149052196Smckusick 				VREF(vp);
149152196Smckusick 				newvp = vp;
149252196Smckusick 				np = VTONFS(vp);
149352196Smckusick 			} else {
149452196Smckusick 				if (error = nfs_nget(vp->v_mount, fhp, &np))
149552196Smckusick 					doit = 0;
149652196Smckusick 				newvp = NFSTOV(np);
149752196Smckusick 			}
149852196Smckusick 			if (error = nfs_loadattrcache(&newvp, &md, &dpos,
149952196Smckusick 				(struct vattr *)0))
150052196Smckusick 				doit = 0;
150152196Smckusick 			nfsm_dissect(tl, u_long *, 2*NFSX_UNSIGNED);
150252196Smckusick 			fileno = fxdr_unsigned(u_long, *tl++);
150352196Smckusick 			len = fxdr_unsigned(int, *tl);
150452196Smckusick 			if (len <= 0 || len > NFS_MAXNAMLEN) {
150552196Smckusick 				error = EBADRPC;
150652196Smckusick 				m_freem(mrep);
150752196Smckusick 				goto nfsmout;
150852196Smckusick 			}
150952196Smckusick 			tlen = (len + 4) & ~0x3;
151052196Smckusick 			if ((tlen + DIRHDSIZ) > uiop->uio_resid)
151152196Smckusick 				bigenough = 0;
151252196Smckusick 			if (bigenough && doit) {
151352436Smckusick 				dp = (struct readdir *)uiop->uio_iov->iov_base;
151452196Smckusick 				dp->d_ino = fileno;
151552196Smckusick 				dp->d_namlen = len;
151652196Smckusick 				dp->d_reclen = tlen + DIRHDSIZ;
151752196Smckusick 				uiop->uio_resid -= DIRHDSIZ;
151852196Smckusick 				uiop->uio_iov->iov_base += DIRHDSIZ;
151952196Smckusick 				uiop->uio_iov->iov_len -= DIRHDSIZ;
152052317Sheideman 				cnp->cn_nameptr = uiop->uio_iov->iov_base;
152152317Sheideman 				cnp->cn_namelen = len;
152252196Smckusick 				ndp->ni_vp = newvp;
152352196Smckusick 				nfsm_mtouio(uiop, len);
152452196Smckusick 				cp = uiop->uio_iov->iov_base;
152552196Smckusick 				tlen -= len;
152652196Smckusick 				for (i = 0; i < tlen; i++)
152752196Smckusick 					*cp++ = '\0';
152852196Smckusick 				uiop->uio_iov->iov_base += tlen;
152952196Smckusick 				uiop->uio_iov->iov_len -= tlen;
153052196Smckusick 				uiop->uio_resid -= tlen;
153152317Sheideman 				cnp->cn_hash = 0;
153252317Sheideman 				for (cp = cnp->cn_nameptr, i = 1; i <= len; i++, cp++)
153352317Sheideman 					cnp->cn_hash += (unsigned char)*cp * i;
153452196Smckusick 				if (ltime > time.tv_sec) {
153552196Smckusick 					if (np->n_tnext) {
153652196Smckusick 						if (np->n_tnext == (struct nfsnode *)nmp)
153752196Smckusick 							nmp->nm_tprev = np->n_tprev;
153852196Smckusick 						else
153952196Smckusick 							np->n_tnext->n_tprev = np->n_tprev;
154052196Smckusick 						if (np->n_tprev == (struct nfsnode *)nmp)
154152196Smckusick 							nmp->nm_tnext = np->n_tnext;
154252196Smckusick 						else
154352196Smckusick 							np->n_tprev->n_tnext = np->n_tnext;
154452196Smckusick 					} else
154552196Smckusick 						np->n_flag &= ~NQNFSWRITE;
154652196Smckusick 					if (cachable)
154752196Smckusick 						np->n_flag &= ~NQNFSNONCACHE;
154852196Smckusick 					else
154952196Smckusick 						np->n_flag |= NQNFSNONCACHE;
155052196Smckusick 					np->n_expiry = ltime;
155152196Smckusick 					np->n_lrev = frev;
155252196Smckusick 					tp = nmp->nm_tprev;
155352196Smckusick 					while (tp != (struct nfsnode *)nmp && tp->n_expiry > np->n_expiry)
155452196Smckusick 						tp = tp->n_tprev;
155552196Smckusick 					if (tp == (struct nfsnode *)nmp) {
155652196Smckusick 						np->n_tnext = nmp->nm_tnext;
155752196Smckusick 						nmp->nm_tnext = np;
155852196Smckusick 					} else {
155952196Smckusick 						np->n_tnext = tp->n_tnext;
156052196Smckusick 						tp->n_tnext = np;
156152196Smckusick 					}
156252196Smckusick 					np->n_tprev = tp;
156352196Smckusick 					if (np->n_tnext == (struct nfsnode *)nmp)
156452196Smckusick 						nmp->nm_tprev = np;
156552196Smckusick 					else
156652196Smckusick 						np->n_tnext->n_tprev = np;
156752317Sheideman 					cache_enter(ndp->ni_dvp, ndp->ni_vp, cnp);
156852196Smckusick 				}
156952196Smckusick 			} else {
157052196Smckusick 				nfsm_adv(nfsm_rndup(len));
157152196Smckusick 			}
157252196Smckusick 			if (newvp != NULLVP) {
157352196Smckusick 				vrele(newvp);
157452196Smckusick 				newvp = NULLVP;
157552196Smckusick 			}
157652196Smckusick 			nfsm_dissect(tl, u_long *, 2*NFSX_UNSIGNED);
157752196Smckusick 			if (bigenough)
157852196Smckusick 				endoff = off = fxdr_unsigned(off_t, *tl++);
157952196Smckusick 			else
158052196Smckusick 				endoff = fxdr_unsigned(off_t, *tl++);
158152196Smckusick 			more_dirs = fxdr_unsigned(int, *tl);
158252196Smckusick 		}
158352196Smckusick 		/*
158452196Smckusick 		 * If at end of rpc data, get the eof boolean
158552196Smckusick 		 */
158652196Smckusick 		if (!more_dirs) {
158752196Smckusick 			nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
158852196Smckusick 			more_dirs = (fxdr_unsigned(int, *tl) == 0);
158952196Smckusick 
159052196Smckusick 			/*
159152196Smckusick 			 * If at EOF, cache directory offset
159252196Smckusick 			 */
159352196Smckusick 			if (!more_dirs)
159452196Smckusick 				VTONFS(vp)->n_direofoffset = endoff;
159552196Smckusick 		}
159652196Smckusick 		if (uiop->uio_resid < tresid)
159752196Smckusick 			uiop->uio_offset = off;
159852196Smckusick 		else
159952196Smckusick 			more_dirs = 0;
160052196Smckusick 		m_freem(mrep);
160152196Smckusick 	}
160252196Smckusick 	/*
160352196Smckusick 	 * Fill last record, iff any, out to a multiple of NFS_DIRBLKSIZ
160452196Smckusick 	 * by increasing d_reclen for the last record.
160552196Smckusick 	 */
160652196Smckusick 	if (uiop->uio_resid < tresid) {
160752196Smckusick 		len = uiop->uio_resid & (NFS_DIRBLKSIZ - 1);
160852196Smckusick 		if (len > 0) {
160952196Smckusick 			dp->d_reclen += len;
161052196Smckusick 			uiop->uio_iov->iov_base += len;
161152196Smckusick 			uiop->uio_iov->iov_len -= len;
161252196Smckusick 			uiop->uio_resid -= len;
161352196Smckusick 		}
161452196Smckusick 	}
161552196Smckusick nfsmout:
161652196Smckusick 	if (newvp != NULLVP)
161752196Smckusick 		vrele(newvp);
161852196Smckusick 	return (error);
161952196Smckusick }
162039488Smckusick static char hextoasc[] = "0123456789abcdef";
162138414Smckusick 
162238414Smckusick /*
162338414Smckusick  * Silly rename. To make the NFS filesystem that is stateless look a little
162438414Smckusick  * more like the "ufs" a remove of an active vnode is translated to a rename
162538414Smckusick  * to a funny looking filename that is removed by nfs_inactive on the
162638414Smckusick  * nfsnode. There is the potential for another process on a different client
162738414Smckusick  * to create the same funny name between the nfs_lookitup() fails and the
162838414Smckusick  * nfs_rename() completes, but...
162938414Smckusick  */
163052234Sheideman int
163152317Sheideman nfs_sillyrename(dvp, vp, cnp)
163252234Sheideman 	struct vnode *dvp, *vp;
163352234Sheideman 	struct componentname *cnp;
163438414Smckusick {
163538414Smckusick 	register struct nfsnode *np;
163638414Smckusick 	register struct sillyrename *sp;
163738414Smckusick 	int error;
163838414Smckusick 	short pid;
163938414Smckusick 
164052234Sheideman 	cache_purge(dvp);
164152234Sheideman 	np = VTONFS(vp);
164251986Smckusick #ifdef SILLYSEPARATE
164338414Smckusick 	MALLOC(sp, struct sillyrename *, sizeof (struct sillyrename),
164448364Smckusick 		M_NFSREQ, M_WAITOK);
164551986Smckusick #else
164651986Smckusick 	sp = &np->n_silly;
164751986Smckusick #endif
164852234Sheideman 	sp->s_cred = crdup(cnp->cn_cred);
164952234Sheideman 	sp->s_dvp = dvp;
165052234Sheideman 	VREF(dvp);
165138414Smckusick 
165238414Smckusick 	/* Fudge together a funny name */
165352234Sheideman 	pid = cnp->cn_proc->p_pid;
165448364Smckusick 	bcopy(".nfsAxxxx4.4", sp->s_name, 13);
165548364Smckusick 	sp->s_namlen = 12;
165648364Smckusick 	sp->s_name[8] = hextoasc[pid & 0xf];
165748364Smckusick 	sp->s_name[7] = hextoasc[(pid >> 4) & 0xf];
165848364Smckusick 	sp->s_name[6] = hextoasc[(pid >> 8) & 0xf];
165948364Smckusick 	sp->s_name[5] = hextoasc[(pid >> 12) & 0xf];
166038414Smckusick 
166138414Smckusick 	/* Try lookitups until we get one that isn't there */
166252234Sheideman 	while (nfs_lookitup(sp, (nfsv2fh_t *)0, cnp->cn_proc) == 0) {
166348364Smckusick 		sp->s_name[4]++;
166448364Smckusick 		if (sp->s_name[4] > 'z') {
166538414Smckusick 			error = EINVAL;
166638414Smckusick 			goto bad;
166738414Smckusick 		}
166838414Smckusick 	}
166952234Sheideman 	if (error = nfs_renameit(dvp, cnp, sp))
167038414Smckusick 		goto bad;
167152234Sheideman 	nfs_lookitup(sp, &np->n_fh, cnp->cn_proc);
167238414Smckusick 	np->n_sillyrename = sp;
167338414Smckusick 	return (0);
167438414Smckusick bad:
167548364Smckusick 	vrele(sp->s_dvp);
167648364Smckusick 	crfree(sp->s_cred);
167751986Smckusick #ifdef SILLYSEPARATE
167848364Smckusick 	free((caddr_t)sp, M_NFSREQ);
167951986Smckusick #endif
168038414Smckusick 	return (error);
168138414Smckusick }
168238414Smckusick 
168338414Smckusick /*
168438414Smckusick  * Look up a file name for silly rename stuff.
168538414Smckusick  * Just like nfs_lookup() except that it doesn't load returned values
168638414Smckusick  * into the nfsnode table.
168738414Smckusick  * If fhp != NULL it copies the returned file handle out
168838414Smckusick  */
168952234Sheideman int
169052196Smckusick nfs_lookitup(sp, fhp, procp)
169148364Smckusick 	register struct sillyrename *sp;
169238414Smckusick 	nfsv2fh_t *fhp;
169352196Smckusick 	struct proc *procp;
169438414Smckusick {
169548364Smckusick 	register struct vnode *vp = sp->s_dvp;
169648054Smckusick 	register u_long *tl;
169739488Smckusick 	register caddr_t cp;
169839488Smckusick 	register long t1, t2;
169939488Smckusick 	caddr_t bpos, dpos, cp2;
170039488Smckusick 	u_long xid;
170139488Smckusick 	int error = 0;
170239488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
170338414Smckusick 	long len;
170438414Smckusick 
170538414Smckusick 	nfsstats.rpccnt[NFSPROC_LOOKUP]++;
170648364Smckusick 	len = sp->s_namlen;
170752196Smckusick 	nfsm_reqhead(vp, NFSPROC_LOOKUP, NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len));
170838414Smckusick 	nfsm_fhtom(vp);
170948364Smckusick 	nfsm_strtom(sp->s_name, len, NFS_MAXNAMLEN);
171052196Smckusick 	nfsm_request(vp, NFSPROC_LOOKUP, procp, sp->s_cred);
171138414Smckusick 	if (fhp != NULL) {
171252196Smckusick 		nfsm_dissect(cp, caddr_t, NFSX_FH);
171338414Smckusick 		bcopy(cp, (caddr_t)fhp, NFSX_FH);
171438414Smckusick 	}
171538414Smckusick 	nfsm_reqdone;
171638414Smckusick 	return (error);
171738414Smckusick }
171838414Smckusick 
171938414Smckusick /*
172038414Smckusick  * Kludge City..
172138414Smckusick  * - make nfs_bmap() essentially a no-op that does no translation
172241905Smckusick  * - do nfs_strategy() by faking physical I/O with nfs_readrpc/nfs_writerpc
172338414Smckusick  *   after mapping the physical addresses into Kernel Virtual space in the
172438414Smckusick  *   nfsiobuf area.
172538414Smckusick  *   (Maybe I could use the process's page mapping, but I was concerned that
172638414Smckusick  *    Kernel Write might not be enabled and also figured copyout() would do
172738414Smckusick  *    a lot more work than bcopy() and also it currently happens in the
172838414Smckusick  *    context of the swapper process (2).
172938414Smckusick  */
173052234Sheideman int
173138414Smckusick nfs_bmap(vp, bn, vpp, bnp)
173238414Smckusick 	struct vnode *vp;
173338414Smckusick 	daddr_t bn;
173438414Smckusick 	struct vnode **vpp;
173538414Smckusick 	daddr_t *bnp;
173638414Smckusick {
173738414Smckusick 	if (vpp != NULL)
173838414Smckusick 		*vpp = vp;
173938414Smckusick 	if (bnp != NULL)
174052196Smckusick 		*bnp = bn * btodb(vp->v_mount->mnt_stat.f_iosize);
174138414Smckusick 	return (0);
174238414Smckusick }
174338414Smckusick 
174438414Smckusick /*
174538884Smacklem  * Strategy routine for phys. i/o
174638884Smacklem  * If the biod's are running, queue a request
174738884Smacklem  * otherwise just call nfs_doio() to get it done
174838414Smckusick  */
174952234Sheideman int
175038414Smckusick nfs_strategy(bp)
175138414Smckusick 	register struct buf *bp;
175238414Smckusick {
175338884Smacklem 	register struct buf *dp;
175439341Smckusick 	register int i;
175538884Smacklem 	int error = 0;
175639341Smckusick 	int fnd = 0;
175738884Smacklem 
175838884Smacklem 	/*
175941905Smckusick 	 * Set b_proc. It seems a bit silly to do it here, but since bread()
176041905Smckusick 	 * doesn't set it, I will.
176146450Skarels 	 * Set b_proc == NULL for asynchronous ops, since these may still
176241905Smckusick 	 * be hanging about after the process terminates.
176341905Smckusick 	 */
176446988Smckusick 	if ((bp->b_flags & B_PHYS) == 0) {
176546988Smckusick 		if (bp->b_flags & B_ASYNC)
176646988Smckusick 			bp->b_proc = (struct proc *)0;
176746988Smckusick 		else
176847573Skarels 			bp->b_proc = curproc;
176946988Smckusick 	}
177041905Smckusick 	/*
177146450Skarels 	 * If the op is asynchronous and an i/o daemon is waiting
177238884Smacklem 	 * queue the request, wake it up and wait for completion
177346450Skarels 	 * otherwise just do it ourselves.
177438884Smacklem 	 */
177546988Smckusick 	if ((bp->b_flags & B_ASYNC) == 0 || nfs_numasync == 0)
177646988Smckusick 		return (nfs_doio(bp));
177746988Smckusick 	for (i = 0; i < NFS_MAXASYNCDAEMON; i++) {
177846988Smckusick 		if (nfs_iodwant[i]) {
177939341Smckusick 			dp = &nfs_bqueue;
178039341Smckusick 			if (dp->b_actf == NULL) {
178139341Smckusick 				dp->b_actl = bp;
178239341Smckusick 				bp->b_actf = dp;
178339341Smckusick 			} else {
178439341Smckusick 				dp->b_actf->b_actl = bp;
178539341Smckusick 				bp->b_actf = dp->b_actf;
178639341Smckusick 			}
178739341Smckusick 			dp->b_actf = bp;
178839341Smckusick 			bp->b_actl = dp;
178939341Smckusick 			fnd++;
179039341Smckusick 			wakeup((caddr_t)&nfs_iodwant[i]);
179139341Smckusick 			break;
179238884Smacklem 		}
179339341Smckusick 	}
179439341Smckusick 	if (!fnd)
179538884Smacklem 		error = nfs_doio(bp);
179638884Smacklem 	return (error);
179738884Smacklem }
179838884Smacklem 
179938884Smacklem /*
180038884Smacklem  * Fun and games with i/o
180138884Smacklem  * Essentially play ubasetup() and disk interrupt service routine by
180238884Smacklem  * mapping the data buffer into kernel virtual space and doing the
180338884Smacklem  * nfs read or write rpc's from it.
180441905Smckusick  * If the nfsiod's are not running, this is just called from nfs_strategy(),
180541905Smckusick  * otherwise it is called by the nfsiods to do what would normally be
180638884Smacklem  * partially disk interrupt driven.
180738884Smacklem  */
180852234Sheideman int
180938884Smacklem nfs_doio(bp)
181038884Smacklem 	register struct buf *bp;
181138884Smacklem {
181238414Smckusick 	register struct uio *uiop;
181338414Smckusick 	register struct vnode *vp;
181439341Smckusick 	struct nfsnode *np;
181538884Smacklem 	struct ucred *cr;
181641539Smckusick 	int error;
181741539Smckusick 	struct uio uio;
181841539Smckusick 	struct iovec io;
181938414Smckusick 
182038414Smckusick 	vp = bp->b_vp;
182140251Smckusick 	np = VTONFS(vp);
182238414Smckusick 	uiop = &uio;
182338414Smckusick 	uiop->uio_iov = &io;
182438414Smckusick 	uiop->uio_iovcnt = 1;
182538414Smckusick 	uiop->uio_segflg = UIO_SYSSPACE;
182652196Smckusick 	uiop->uio_procp = bp->b_proc;
182739751Smckusick 
182838414Smckusick 	/*
182938884Smacklem 	 * For phys i/o, map the b_addr into kernel virtual space using
183038884Smacklem 	 * the Nfsiomap pte's
183138884Smacklem 	 * Also, add a temporary b_rcred for reading using the process's uid
183238884Smacklem 	 * and a guess at a group
183338414Smckusick 	 */
183438884Smacklem 	if (bp->b_flags & B_PHYS) {
183548054Smckusick 		if (bp->b_flags & B_DIRTY)
183648054Smckusick 			uiop->uio_procp = pageproc;
183748054Smckusick 		cr = crcopy(uiop->uio_procp->p_ucred);
183841539Smckusick 		/* mapping was already done by vmapbuf */
183941539Smckusick 		io.iov_base = bp->b_un.b_addr;
184039751Smckusick 
184138884Smacklem 		/*
184239751Smckusick 		 * And do the i/o rpc
184339751Smckusick 		 */
184439751Smckusick 		io.iov_len = uiop->uio_resid = bp->b_bcount;
184539823Smckusick 		uiop->uio_offset = bp->b_blkno * DEV_BSIZE;
184639751Smckusick 		if (bp->b_flags & B_READ) {
184739751Smckusick 			uiop->uio_rw = UIO_READ;
184839751Smckusick 			nfsstats.read_physios++;
184948054Smckusick 			bp->b_error = error = nfs_readrpc(vp, uiop, cr);
185045717Smckusick 			(void) vnode_pager_uncache(vp);
185139751Smckusick 		} else {
185239751Smckusick 			uiop->uio_rw = UIO_WRITE;
185339751Smckusick 			nfsstats.write_physios++;
185448054Smckusick 			bp->b_error = error = nfs_writerpc(vp, uiop, cr);
185539341Smckusick 		}
185639751Smckusick 
185739751Smckusick 		/*
185839751Smckusick 		 * Finally, release pte's used by physical i/o
185939751Smckusick 		 */
186038884Smacklem 		crfree(cr);
186139751Smckusick 	} else {
186239751Smckusick 		if (bp->b_flags & B_READ) {
186339751Smckusick 			io.iov_len = uiop->uio_resid = bp->b_bcount;
186439751Smckusick 			io.iov_base = bp->b_un.b_addr;
186539751Smckusick 			uiop->uio_rw = UIO_READ;
186641905Smckusick 			switch (vp->v_type) {
186741905Smckusick 			case VREG:
186841905Smckusick 				uiop->uio_offset = bp->b_blkno * DEV_BSIZE;
186941905Smckusick 				nfsstats.read_bios++;
187048054Smckusick 				error = nfs_readrpc(vp, uiop, bp->b_rcred);
187141905Smckusick 				break;
187241905Smckusick 			case VLNK:
187341905Smckusick 				uiop->uio_offset = 0;
187441905Smckusick 				nfsstats.readlink_bios++;
187548054Smckusick 				error = nfs_readlinkrpc(vp, uiop, bp->b_rcred);
187641905Smckusick 				break;
187741905Smckusick 			case VDIR:
187841905Smckusick 				uiop->uio_offset = bp->b_lblkno;
187941905Smckusick 				nfsstats.readdir_bios++;
188052196Smckusick 				if (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_RDIRALOOK)
188152196Smckusick 				    error = nfs_readdirlookrpc(vp, uiop, bp->b_rcred);
188252196Smckusick 				else
188352196Smckusick 				    error = nfs_readdirrpc(vp, uiop, bp->b_rcred);
188441905Smckusick 				/*
188541905Smckusick 				 * Save offset cookie in b_blkno.
188641905Smckusick 				 */
188741905Smckusick 				bp->b_blkno = uiop->uio_offset;
188841905Smckusick 				break;
188941905Smckusick 			};
189041905Smckusick 			bp->b_error = error;
189139751Smckusick 		} else {
189239751Smckusick 			io.iov_len = uiop->uio_resid = bp->b_dirtyend
189339751Smckusick 				- bp->b_dirtyoff;
189439823Smckusick 			uiop->uio_offset = (bp->b_blkno * DEV_BSIZE)
189539751Smckusick 				+ bp->b_dirtyoff;
189639751Smckusick 			io.iov_base = bp->b_un.b_addr + bp->b_dirtyoff;
189739751Smckusick 			uiop->uio_rw = UIO_WRITE;
189839751Smckusick 			nfsstats.write_bios++;
189941905Smckusick 			bp->b_error = error = nfs_writerpc(vp, uiop,
190048054Smckusick 				bp->b_wcred);
190139751Smckusick 			if (error) {
190239751Smckusick 				np->n_error = error;
190339751Smckusick 				np->n_flag |= NWRITEERR;
190439751Smckusick 			}
190539751Smckusick 			bp->b_dirtyoff = bp->b_dirtyend = 0;
190639751Smckusick 		}
190738884Smacklem 	}
190839751Smckusick 	if (error)
190939751Smckusick 		bp->b_flags |= B_ERROR;
191039751Smckusick 	bp->b_resid = uiop->uio_resid;
191138414Smckusick 	biodone(bp);
191238414Smckusick 	return (error);
191338414Smckusick }
191438884Smacklem 
191538884Smacklem /*
191648054Smckusick  * Mmap a file
191748054Smckusick  *
191848054Smckusick  * NB Currently unsupported.
191948054Smckusick  */
192048054Smckusick /* ARGSUSED */
192152234Sheideman int
192248054Smckusick nfs_mmap(vp, fflags, cred, p)
192348054Smckusick 	struct vnode *vp;
192448054Smckusick 	int fflags;
192548054Smckusick 	struct ucred *cred;
192648054Smckusick 	struct proc *p;
192748054Smckusick {
192848054Smckusick 
192948054Smckusick 	return (EINVAL);
193048054Smckusick }
193148054Smckusick 
193248054Smckusick /*
193338884Smacklem  * Flush all the blocks associated with a vnode.
193438884Smacklem  * 	Walk through the buffer pool and push any dirty pages
193538884Smacklem  *	associated with the vnode.
193638884Smacklem  */
193739488Smckusick /* ARGSUSED */
193852234Sheideman int
193948054Smckusick nfs_fsync(vp, fflags, cred, waitfor, p)
194038884Smacklem 	register struct vnode *vp;
194138884Smacklem 	int fflags;
194238884Smacklem 	struct ucred *cred;
194339587Smckusick 	int waitfor;
194448054Smckusick 	struct proc *p;
194538884Smacklem {
194638884Smacklem 	register struct nfsnode *np = VTONFS(vp);
194739751Smckusick 	int error = 0;
194838884Smacklem 
194938884Smacklem 	if (np->n_flag & NMODIFIED) {
195038884Smacklem 		np->n_flag &= ~NMODIFIED;
195139751Smckusick 		vflushbuf(vp, waitfor == MNT_WAIT ? B_SYNC : 0);
195238884Smacklem 	}
195339751Smckusick 	if (!error && (np->n_flag & NWRITEERR))
195439751Smckusick 		error = np->n_error;
195538884Smacklem 	return (error);
195638884Smacklem }
195739672Smckusick 
195839672Smckusick /*
195946201Smckusick  * NFS advisory byte-level locks.
196046201Smckusick  * Currently unsupported.
196146201Smckusick  */
196252234Sheideman int
196346201Smckusick nfs_advlock(vp, id, op, fl, flags)
196446201Smckusick 	struct vnode *vp;
196546201Smckusick 	caddr_t id;
196646201Smckusick 	int op;
196746201Smckusick 	struct flock *fl;
196846201Smckusick 	int flags;
196946201Smckusick {
197046201Smckusick 
197146201Smckusick 	return (EOPNOTSUPP);
197246201Smckusick }
197346201Smckusick 
197446201Smckusick /*
197539672Smckusick  * Print out the contents of an nfsnode.
197639672Smckusick  */
197752234Sheideman int
197839672Smckusick nfs_print(vp)
197939672Smckusick 	struct vnode *vp;
198039672Smckusick {
198139672Smckusick 	register struct nfsnode *np = VTONFS(vp);
198239672Smckusick 
198340294Smckusick 	printf("tag VT_NFS, fileid %d fsid 0x%x",
198440294Smckusick 		np->n_vattr.va_fileid, np->n_vattr.va_fsid);
198540294Smckusick #ifdef FIFO
198640294Smckusick 	if (vp->v_type == VFIFO)
198740294Smckusick 		fifo_printinfo(vp);
198840294Smckusick #endif /* FIFO */
198939914Smckusick 	printf("\n");
199039672Smckusick }
199151573Smckusick 
199251573Smckusick /*
199351573Smckusick  * NFS directory offset lookup.
199451573Smckusick  * Currently unsupported.
199551573Smckusick  */
199652234Sheideman int
199751573Smckusick nfs_blkatoff(vp, offset, res, bpp)
199851573Smckusick 	struct vnode *vp;
199951573Smckusick 	off_t offset;
200051573Smckusick 	char **res;
200151573Smckusick 	struct buf **bpp;
200251573Smckusick {
200351573Smckusick 
200451573Smckusick 	return (EOPNOTSUPP);
200551573Smckusick }
200651573Smckusick 
200751573Smckusick /*
200851573Smckusick  * NFS flat namespace lookup.
200951573Smckusick  * Currently unsupported.
201051573Smckusick  */
201152234Sheideman int
201251573Smckusick nfs_vget(mp, ino, vpp)
201351573Smckusick 	struct mount *mp;
201451573Smckusick 	ino_t ino;
201551573Smckusick 	struct vnode **vpp;
201651573Smckusick {
201751573Smckusick 
201851573Smckusick 	return (EOPNOTSUPP);
201951573Smckusick }
202051573Smckusick 
202151573Smckusick /*
202251573Smckusick  * NFS flat namespace allocation.
202351573Smckusick  * Currently unsupported.
202451573Smckusick  */
202552234Sheideman int
202651573Smckusick nfs_valloc(pvp, mode, cred, vpp)
202751573Smckusick 	struct vnode *pvp;
202851573Smckusick 	int mode;
202951573Smckusick 	struct ucred *cred;
203051573Smckusick 	struct vnode **vpp;
203151573Smckusick {
203251573Smckusick 
203351573Smckusick 	return (EOPNOTSUPP);
203451573Smckusick }
203551573Smckusick 
203651573Smckusick /*
203751573Smckusick  * NFS flat namespace free.
203851573Smckusick  * Currently unsupported.
203951573Smckusick  */
204051573Smckusick void
204151573Smckusick nfs_vfree(pvp, ino, mode)
204251573Smckusick 	struct vnode *pvp;
204351573Smckusick 	ino_t ino;
204451573Smckusick 	int mode;
204551573Smckusick {
204651573Smckusick 
204751573Smckusick 	return;
204851573Smckusick }
204951573Smckusick 
205051573Smckusick /*
205151573Smckusick  * NFS file truncation.
205251573Smckusick  */
205352234Sheideman int
205451573Smckusick nfs_truncate(vp, length, flags)
205551573Smckusick 	struct vnode *vp;
205651573Smckusick 	u_long length;
205751573Smckusick 	int flags;
205851573Smckusick {
205951573Smckusick 
206051573Smckusick 	/* Use nfs_setattr */
206151573Smckusick 	printf("nfs_truncate: need to implement!!");
206251573Smckusick 	return (EOPNOTSUPP);
206351573Smckusick }
206451573Smckusick 
206551573Smckusick /*
206651573Smckusick  * NFS update.
206751573Smckusick  */
206852234Sheideman int
206951573Smckusick nfs_update(vp, ta, tm, waitfor)
207051573Smckusick 	struct vnode *vp;
207151573Smckusick 	struct timeval *ta;
207251573Smckusick 	struct timeval *tm;
207351573Smckusick 	int waitfor;
207451573Smckusick {
207551573Smckusick 
207651573Smckusick 	/* Use nfs_setattr */
207751573Smckusick 	printf("nfs_update: need to implement!!");
207851573Smckusick 	return (EOPNOTSUPP);
207951573Smckusick }
2080