xref: /csrg-svn/sys/nfs/nfs_vnops.c (revision 51986)
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*51986Smckusick  *	@(#)nfs_vnops.c	7.64 (Berkeley) 12/16/91
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 
3251466Sbostic #include "ufs/ufs/quota.h"
3351466Sbostic #include "ufs/ufs/inode.h"
3451466Sbostic #include "ufs/ufs/dir.h"
3547573Skarels 
3638414Smckusick #include "nfsv2.h"
3738414Smckusick #include "nfs.h"
3838414Smckusick #include "nfsnode.h"
3938414Smckusick #include "nfsmount.h"
4038414Smckusick #include "xdr_subs.h"
4138414Smckusick #include "nfsm_subs.h"
4238884Smacklem #include "nfsiom.h"
4338414Smckusick 
4438414Smckusick /* Defs */
4538414Smckusick #define	TRUE	1
4638414Smckusick #define	FALSE	0
4738414Smckusick 
4848054Smckusick /*
4948054Smckusick  * Global vfs data structures for nfs
5048054Smckusick  */
5138414Smckusick struct vnodeops nfsv2_vnodeops = {
5239672Smckusick 	nfs_lookup,		/* lookup */
5339672Smckusick 	nfs_create,		/* create */
5439672Smckusick 	nfs_mknod,		/* mknod */
5539672Smckusick 	nfs_open,		/* open */
5639672Smckusick 	nfs_close,		/* close */
5739672Smckusick 	nfs_access,		/* access */
5839672Smckusick 	nfs_getattr,		/* getattr */
5939672Smckusick 	nfs_setattr,		/* setattr */
6039672Smckusick 	nfs_read,		/* read */
6139672Smckusick 	nfs_write,		/* write */
6248054Smckusick 	nfs_ioctl,		/* ioctl */
6348054Smckusick 	nfs_select,		/* select */
6448054Smckusick 	nfs_mmap,		/* mmap */
6539672Smckusick 	nfs_fsync,		/* fsync */
6648054Smckusick 	nfs_seek,		/* seek */
6739672Smckusick 	nfs_remove,		/* remove */
6839672Smckusick 	nfs_link,		/* link */
6939672Smckusick 	nfs_rename,		/* rename */
7039672Smckusick 	nfs_mkdir,		/* mkdir */
7139672Smckusick 	nfs_rmdir,		/* rmdir */
7239672Smckusick 	nfs_symlink,		/* symlink */
7339672Smckusick 	nfs_readdir,		/* readdir */
7439672Smckusick 	nfs_readlink,		/* readlink */
7539672Smckusick 	nfs_abortop,		/* abortop */
7639672Smckusick 	nfs_inactive,		/* inactive */
7739672Smckusick 	nfs_reclaim,		/* reclaim */
7839672Smckusick 	nfs_lock,		/* lock */
7939672Smckusick 	nfs_unlock,		/* unlock */
8039672Smckusick 	nfs_bmap,		/* bmap */
8139672Smckusick 	nfs_strategy,		/* strategy */
8239672Smckusick 	nfs_print,		/* print */
8339906Smckusick 	nfs_islocked,		/* islocked */
8446201Smckusick 	nfs_advlock,		/* advlock */
8551573Smckusick 	nfs_blkatoff,		/* blkatoff */
8651573Smckusick 	nfs_vget,		/* vget */
8751573Smckusick 	nfs_valloc,		/* valloc */
8851573Smckusick 	nfs_vfree,		/* vfree */
8951573Smckusick 	nfs_truncate,		/* truncate */
9051573Smckusick 	nfs_update,		/* update */
9151573Smckusick 	bwrite,			/* bwrite */
9238414Smckusick };
9338414Smckusick 
9448054Smckusick /*
9548054Smckusick  * Special device vnode ops
9648054Smckusick  */
9739441Smckusick struct vnodeops spec_nfsv2nodeops = {
9839599Smckusick 	spec_lookup,		/* lookup */
9948054Smckusick 	spec_create,		/* create */
10048054Smckusick 	spec_mknod,		/* mknod */
10139599Smckusick 	spec_open,		/* open */
10239599Smckusick 	spec_close,		/* close */
10339599Smckusick 	nfs_access,		/* access */
10439599Smckusick 	nfs_getattr,		/* getattr */
10539599Smckusick 	nfs_setattr,		/* setattr */
10639599Smckusick 	spec_read,		/* read */
10739599Smckusick 	spec_write,		/* write */
10839599Smckusick 	spec_ioctl,		/* ioctl */
10939599Smckusick 	spec_select,		/* select */
11048054Smckusick 	spec_mmap,		/* mmap */
11148054Smckusick 	spec_fsync,		/* fsync */
11248054Smckusick 	spec_seek,		/* seek */
11348054Smckusick 	spec_remove,		/* remove */
11448054Smckusick 	spec_link,		/* link */
11548054Smckusick 	spec_rename,		/* rename */
11648054Smckusick 	spec_mkdir,		/* mkdir */
11748054Smckusick 	spec_rmdir,		/* rmdir */
11848054Smckusick 	spec_symlink,		/* symlink */
11948054Smckusick 	spec_readdir,		/* readdir */
12048054Smckusick 	spec_readlink,		/* readlink */
12148054Smckusick 	spec_abortop,		/* abortop */
12239599Smckusick 	nfs_inactive,		/* inactive */
12339599Smckusick 	nfs_reclaim,		/* reclaim */
12439599Smckusick 	nfs_lock,		/* lock */
12539599Smckusick 	nfs_unlock,		/* unlock */
12639672Smckusick 	spec_bmap,		/* bmap */
12739599Smckusick 	spec_strategy,		/* strategy */
12839672Smckusick 	nfs_print,		/* print */
12939906Smckusick 	nfs_islocked,		/* islocked */
13046201Smckusick 	spec_advlock,		/* advlock */
13151573Smckusick 	spec_blkatoff,		/* blkatoff */
13251573Smckusick 	spec_vget,		/* vget */
13351573Smckusick 	spec_valloc,		/* valloc */
13451573Smckusick 	spec_vfree,		/* vfree */
13551573Smckusick 	spec_truncate,		/* truncate */
13651573Smckusick 	nfs_update,		/* update */
13751573Smckusick 	bwrite,			/* bwrite */
13838414Smckusick };
13938414Smckusick 
14040294Smckusick #ifdef FIFO
14140294Smckusick struct vnodeops fifo_nfsv2nodeops = {
14240294Smckusick 	fifo_lookup,		/* lookup */
14348054Smckusick 	fifo_create,		/* create */
14448054Smckusick 	fifo_mknod,		/* mknod */
14540294Smckusick 	fifo_open,		/* open */
14640294Smckusick 	fifo_close,		/* close */
14740294Smckusick 	nfs_access,		/* access */
14840294Smckusick 	nfs_getattr,		/* getattr */
14940294Smckusick 	nfs_setattr,		/* setattr */
15040294Smckusick 	fifo_read,		/* read */
15140294Smckusick 	fifo_write,		/* write */
15240294Smckusick 	fifo_ioctl,		/* ioctl */
15340294Smckusick 	fifo_select,		/* select */
15448054Smckusick 	fifo_mmap,		/* mmap */
15548054Smckusick 	fifo_fsync,		/* fsync */
15648054Smckusick 	fifo_seek,		/* seek */
15748054Smckusick 	fifo_remove,		/* remove */
15848054Smckusick 	fifo_link,		/* link */
15948054Smckusick 	fifo_rename,		/* rename */
16048054Smckusick 	fifo_mkdir,		/* mkdir */
16148054Smckusick 	fifo_rmdir,		/* rmdir */
16248054Smckusick 	fifo_symlink,		/* symlink */
16348054Smckusick 	fifo_readdir,		/* readdir */
16448054Smckusick 	fifo_readlink,		/* readlink */
16548054Smckusick 	fifo_abortop,		/* abortop */
16640294Smckusick 	nfs_inactive,		/* inactive */
16740294Smckusick 	nfs_reclaim,		/* reclaim */
16840294Smckusick 	nfs_lock,		/* lock */
16940294Smckusick 	nfs_unlock,		/* unlock */
17040294Smckusick 	fifo_bmap,		/* bmap */
17140294Smckusick 	fifo_badop,		/* strategy */
17240294Smckusick 	nfs_print,		/* print */
17340294Smckusick 	nfs_islocked,		/* islocked */
17446201Smckusick 	fifo_advlock,		/* advlock */
17551573Smckusick 	fifo_blkatoff,		/* blkatoff */
17651573Smckusick 	fifo_vget,		/* vget */
17751573Smckusick 	fifo_valloc,		/* valloc */
17851573Smckusick 	fifo_vfree,		/* vfree */
17951573Smckusick 	fifo_truncate,		/* truncate */
18051573Smckusick 	nfs_update,		/* update */
18151573Smckusick 	bwrite,			/* bwrite */
18240294Smckusick };
18340294Smckusick #endif /* FIFO */
18440294Smckusick 
18548054Smckusick /*
18648054Smckusick  * Global vars
18748054Smckusick  */
18838414Smckusick extern u_long nfs_procids[NFS_NPROCS];
18938414Smckusick extern u_long nfs_prog, nfs_vers;
19038414Smckusick extern char nfsiobuf[MAXPHYS+NBPG];
19138884Smacklem struct map nfsmap[NFS_MSIZ];
19238884Smacklem struct buf nfs_bqueue;		/* Queue head for nfsiod's */
19341905Smckusick struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON];
19446988Smckusick int nfs_numasync = 0;
19538884Smacklem static int nfsmap_want = 0;
19638414Smckusick 
19738414Smckusick /*
19838414Smckusick  * nfs null call from vfs.
19938414Smckusick  */
20048054Smckusick nfs_null(vp, cred, p)
20138414Smckusick 	struct vnode *vp;
20238414Smckusick 	struct ucred *cred;
20348054Smckusick 	struct proc *p;
20438414Smckusick {
20539488Smckusick 	caddr_t bpos, dpos;
20639488Smckusick 	u_long xid;
20739488Smckusick 	int error = 0;
20839488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb;
20938414Smckusick 
21038414Smckusick 	nfsm_reqhead(nfs_procids[NFSPROC_NULL], cred, 0);
21148054Smckusick 	nfsm_request(vp, NFSPROC_NULL, p, 0);
21238414Smckusick 	nfsm_reqdone;
21338414Smckusick 	return (error);
21438414Smckusick }
21538414Smckusick 
21638414Smckusick /*
21738414Smckusick  * nfs access vnode op.
21838414Smckusick  * Essentially just get vattr and then imitate iaccess()
21938414Smckusick  */
22048054Smckusick nfs_access(vp, mode, cred, p)
22138414Smckusick 	struct vnode *vp;
22238414Smckusick 	int mode;
22338414Smckusick 	register struct ucred *cred;
22448054Smckusick 	struct proc *p;
22538414Smckusick {
22638414Smckusick 	register struct vattr *vap;
22738414Smckusick 	register gid_t *gp;
22838414Smckusick 	struct vattr vattr;
22938414Smckusick 	register int i;
23038414Smckusick 	int error;
23138414Smckusick 
23238414Smckusick 	/*
23338414Smckusick 	 * If you're the super-user,
23438414Smckusick 	 * you always get access.
23538414Smckusick 	 */
23638414Smckusick 	if (cred->cr_uid == 0)
23738414Smckusick 		return (0);
23838414Smckusick 	vap = &vattr;
23948054Smckusick 	if (error = nfs_dogetattr(vp, vap, cred, 0, p))
24038884Smacklem 		return (error);
24138414Smckusick 	/*
24238414Smckusick 	 * Access check is based on only one of owner, group, public.
24338414Smckusick 	 * If not owner, then check group. If not a member of the
24438414Smckusick 	 * group, then check public access.
24538414Smckusick 	 */
24638414Smckusick 	if (cred->cr_uid != vap->va_uid) {
24738414Smckusick 		mode >>= 3;
24838414Smckusick 		gp = cred->cr_groups;
24938414Smckusick 		for (i = 0; i < cred->cr_ngroups; i++, gp++)
25038414Smckusick 			if (vap->va_gid == *gp)
25138414Smckusick 				goto found;
25238414Smckusick 		mode >>= 3;
25338414Smckusick found:
25438414Smckusick 		;
25538414Smckusick 	}
25638414Smckusick 	if ((vap->va_mode & mode) != 0)
25738414Smckusick 		return (0);
25838414Smckusick 	return (EACCES);
25938414Smckusick }
26038414Smckusick 
26138414Smckusick /*
26238414Smckusick  * nfs open vnode op
26338414Smckusick  * Just check to see if the type is ok
26438414Smckusick  */
26539488Smckusick /* ARGSUSED */
26648054Smckusick nfs_open(vp, mode, cred, p)
26738414Smckusick 	struct vnode *vp;
26838414Smckusick 	int mode;
26938414Smckusick 	struct ucred *cred;
27048054Smckusick 	struct proc *p;
27138414Smckusick {
27238414Smckusick 	register enum vtype vtyp;
27338414Smckusick 
27438414Smckusick 	vtyp = vp->v_type;
27538414Smckusick 	if (vtyp == VREG || vtyp == VDIR || vtyp == VLNK)
27638414Smckusick 		return (0);
27738414Smckusick 	else
27838414Smckusick 		return (EACCES);
27938414Smckusick }
28038414Smckusick 
28138414Smckusick /*
28238414Smckusick  * nfs close vnode op
28338884Smacklem  * For reg files, invalidate any buffer cache entries.
28438414Smckusick  */
28539488Smckusick /* ARGSUSED */
28648054Smckusick nfs_close(vp, fflags, cred, p)
28738414Smckusick 	register struct vnode *vp;
28838414Smckusick 	int fflags;
28938414Smckusick 	struct ucred *cred;
29048054Smckusick 	struct proc *p;
29138414Smckusick {
29239488Smckusick 	register struct nfsnode *np = VTONFS(vp);
29339341Smckusick 	int error = 0;
29438414Smckusick 
29541905Smckusick 	if (vp->v_type == VREG && (np->n_flag & NMODIFIED)) {
29639441Smckusick 		nfs_lock(vp);
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 		}
30439441Smckusick 		nfs_unlock(vp);
30538884Smacklem 	}
30638414Smckusick 	return (error);
30738414Smckusick }
30838414Smckusick 
30938414Smckusick /*
31038414Smckusick  * nfs getattr call from vfs.
31138414Smckusick  */
31248054Smckusick nfs_getattr(vp, vap, cred, p)
31339488Smckusick 	register struct vnode *vp;
31439488Smckusick 	struct vattr *vap;
31538414Smckusick 	struct ucred *cred;
31648054Smckusick 	struct proc *p;
31738414Smckusick {
31848054Smckusick 	return (nfs_dogetattr(vp, vap, cred, 0, p));
31943356Smckusick }
32043356Smckusick 
32148054Smckusick nfs_dogetattr(vp, vap, cred, tryhard, p)
32243356Smckusick 	register struct vnode *vp;
32343356Smckusick 	struct vattr *vap;
32443356Smckusick 	struct ucred *cred;
32543356Smckusick 	int tryhard;
32648054Smckusick 	struct proc *p;
32743356Smckusick {
32839488Smckusick 	register caddr_t cp;
32939488Smckusick 	register long t1;
33039488Smckusick 	caddr_t bpos, dpos;
33139488Smckusick 	u_long xid;
33239488Smckusick 	int error = 0;
33339488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
33438414Smckusick 
33538414Smckusick 	/* First look in the cache.. */
33638414Smckusick 	if (nfs_getattrcache(vp, vap) == 0)
33738414Smckusick 		return (0);
33838414Smckusick 	nfsstats.rpccnt[NFSPROC_GETATTR]++;
33938414Smckusick 	nfsm_reqhead(nfs_procids[NFSPROC_GETATTR], cred, NFSX_FH);
34038414Smckusick 	nfsm_fhtom(vp);
34148054Smckusick 	nfsm_request(vp, NFSPROC_GETATTR, p, tryhard);
34238414Smckusick 	nfsm_loadattr(vp, vap);
34338414Smckusick 	nfsm_reqdone;
34438414Smckusick 	return (error);
34538414Smckusick }
34638414Smckusick 
34738414Smckusick /*
34838414Smckusick  * nfs setattr call.
34938414Smckusick  */
35048054Smckusick nfs_setattr(vp, vap, cred, p)
35139488Smckusick 	register struct vnode *vp;
35238414Smckusick 	register struct vattr *vap;
35338414Smckusick 	struct ucred *cred;
35448054Smckusick 	struct proc *p;
35538414Smckusick {
35638884Smacklem 	register struct nfsv2_sattr *sp;
35739488Smckusick 	register caddr_t cp;
35839488Smckusick 	register long t1;
35939488Smckusick 	caddr_t bpos, dpos;
36039488Smckusick 	u_long xid;
36139488Smckusick 	int error = 0;
36239488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
36339359Smckusick 	struct nfsnode *np;
36438414Smckusick 
36538414Smckusick 	nfsstats.rpccnt[NFSPROC_SETATTR]++;
36638414Smckusick 	nfsm_reqhead(nfs_procids[NFSPROC_SETATTR], cred, NFSX_FH+NFSX_SATTR);
36738414Smckusick 	nfsm_fhtom(vp);
36838884Smacklem 	nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR);
36938414Smckusick 	if (vap->va_mode == 0xffff)
37038884Smacklem 		sp->sa_mode = VNOVAL;
37138414Smckusick 	else
37238884Smacklem 		sp->sa_mode = vtonfs_mode(vp->v_type, vap->va_mode);
37338414Smckusick 	if (vap->va_uid == 0xffff)
37438884Smacklem 		sp->sa_uid = VNOVAL;
37538414Smckusick 	else
37638884Smacklem 		sp->sa_uid = txdr_unsigned(vap->va_uid);
37738414Smckusick 	if (vap->va_gid == 0xffff)
37838884Smacklem 		sp->sa_gid = VNOVAL;
37938414Smckusick 	else
38038884Smacklem 		sp->sa_gid = txdr_unsigned(vap->va_gid);
38138884Smacklem 	sp->sa_size = txdr_unsigned(vap->va_size);
38244988Smckusick 	sp->sa_atime.tv_sec = txdr_unsigned(vap->va_atime.tv_sec);
38344988Smckusick 	sp->sa_atime.tv_usec = txdr_unsigned(vap->va_flags);
38444988Smckusick 	txdr_time(&vap->va_mtime, &sp->sa_mtime);
38544988Smckusick 	if (vap->va_size != VNOVAL || vap->va_mtime.tv_sec != VNOVAL ||
38644988Smckusick 	    vap->va_atime.tv_sec != VNOVAL) {
38739359Smckusick 		np = VTONFS(vp);
38839359Smckusick 		if (np->n_flag & NMODIFIED) {
38939359Smckusick 			np->n_flag &= ~NMODIFIED;
39046988Smckusick 			if (vap->va_size == 0)
39146988Smckusick 				vinvalbuf(vp, FALSE);
39246988Smckusick 			else
39346988Smckusick 				vinvalbuf(vp, TRUE);
39441905Smckusick 			np->n_attrstamp = 0;
39539359Smckusick 		}
39639359Smckusick 	}
39748054Smckusick 	nfsm_request(vp, NFSPROC_SETATTR, p, 1);
39838414Smckusick 	nfsm_loadattr(vp, (struct vattr *)0);
39938414Smckusick 	/* should we fill in any vap fields ?? */
40038414Smckusick 	nfsm_reqdone;
40138414Smckusick 	return (error);
40238414Smckusick }
40338414Smckusick 
40438414Smckusick /*
40538414Smckusick  * nfs lookup call, one step at a time...
40638414Smckusick  * First look in cache
40738414Smckusick  * If not found, unlock the directory nfsnode and do the rpc
40838414Smckusick  */
40948054Smckusick nfs_lookup(vp, ndp, p)
41038414Smckusick 	register struct vnode *vp;
41138414Smckusick 	register struct nameidata *ndp;
41248054Smckusick 	struct proc *p;
41338414Smckusick {
41438414Smckusick 	register struct vnode *vdp;
41548054Smckusick 	register u_long *tl;
41639488Smckusick 	register caddr_t cp;
41739488Smckusick 	register long t1, t2;
41839488Smckusick 	caddr_t bpos, dpos, cp2;
41939488Smckusick 	u_long xid;
42039488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
42138414Smckusick 	struct vnode *newvp;
42238414Smckusick 	long len;
42338414Smckusick 	nfsv2fh_t *fhp;
42438414Smckusick 	struct nfsnode *np;
42539488Smckusick 	int lockparent, wantparent, flag, error = 0;
42638414Smckusick 
42738414Smckusick 	ndp->ni_dvp = vp;
42838414Smckusick 	ndp->ni_vp = NULL;
42938414Smckusick 	if (vp->v_type != VDIR)
43038414Smckusick 		return (ENOTDIR);
43138414Smckusick 	lockparent = ndp->ni_nameiop & LOCKPARENT;
43246510Smckusick 	flag = ndp->ni_nameiop & OPMASK;
43338414Smckusick 	wantparent = ndp->ni_nameiop & (LOCKPARENT|WANTPARENT);
43439341Smckusick 	if ((error = cache_lookup(ndp)) && error != ENOENT) {
43538884Smacklem 		struct vattr vattr;
43638884Smacklem 		int vpid;
43738884Smacklem 
43839441Smckusick 		vdp = ndp->ni_vp;
43938884Smacklem 		vpid = vdp->v_id;
44038414Smckusick 		/*
44138884Smacklem 		 * See the comment starting `Step through' in ufs/ufs_lookup.c
44238884Smacklem 		 * for an explanation of the locking protocol
44338414Smckusick 		 */
44438414Smckusick 		if (vp == vdp) {
44538425Smckusick 			VREF(vdp);
44639441Smckusick 			error = 0;
44738414Smckusick 		} else if (ndp->ni_isdotdot) {
44838414Smckusick 			nfs_unlock(vp);
44939441Smckusick 			error = vget(vdp);
45047289Smckusick 			if (!error && lockparent && *ndp->ni_next == '\0')
45147289Smckusick 				nfs_lock(vp);
45238414Smckusick 		} else {
45339441Smckusick 			error = vget(vdp);
45447289Smckusick 			if (!lockparent || error || *ndp->ni_next != '\0')
45547289Smckusick 				nfs_unlock(vp);
45638414Smckusick 		}
45739441Smckusick 		if (!error) {
45840251Smckusick 			if (vpid == vdp->v_id) {
45948054Smckusick 			   if (!nfs_dogetattr(vdp, &vattr, ndp->ni_cred, 0, p)&&
46040251Smckusick 			       vattr.va_ctime.tv_sec == VTONFS(vdp)->n_ctime) {
46139441Smckusick 				nfsstats.lookupcache_hits++;
46249872Smckusick 				if (flag != LOOKUP && *ndp->ni_next == 0)
46349741Smckusick 					ndp->ni_nameiop |= SAVENAME;
46439441Smckusick 				return (0);
46540251Smckusick 			   }
46647289Smckusick 			   cache_purge(vdp);
46739441Smckusick 			}
46847289Smckusick 			nfs_nput(vdp);
46947289Smckusick 			if (lockparent && vdp != vp && *ndp->ni_next == '\0')
47047289Smckusick 				nfs_unlock(vp);
47138884Smacklem 		}
47241398Smckusick 		ndp->ni_vp = NULLVP;
47339751Smckusick 	} else
47439751Smckusick 		nfs_unlock(vp);
47539341Smckusick 	error = 0;
47638414Smckusick 	nfsstats.lookupcache_misses++;
47738414Smckusick 	nfsstats.rpccnt[NFSPROC_LOOKUP]++;
47838414Smckusick 	len = ndp->ni_namelen;
47938414Smckusick 	nfsm_reqhead(nfs_procids[NFSPROC_LOOKUP], ndp->ni_cred, NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len));
48038414Smckusick 	nfsm_fhtom(vp);
48138414Smckusick 	nfsm_strtom(ndp->ni_ptr, len, NFS_MAXNAMLEN);
48248054Smckusick 	nfsm_request(vp, NFSPROC_LOOKUP, p, 0);
48338414Smckusick nfsmout:
48438414Smckusick 	if (error) {
48539751Smckusick 		if (lockparent || (flag != CREATE && flag != RENAME) ||
48639751Smckusick 		    *ndp->ni_next != 0)
48739751Smckusick 			nfs_lock(vp);
48849872Smckusick 		if (flag != LOOKUP && *ndp->ni_next == 0)
48949741Smckusick 			ndp->ni_nameiop |= SAVENAME;
49040483Smckusick 		return (error);
49138414Smckusick 	}
49238414Smckusick 	nfsm_disect(fhp,nfsv2fh_t *,NFSX_FH);
49338414Smckusick 
49438414Smckusick 	/*
49538414Smckusick 	 * Handle DELETE and RENAME cases...
49638414Smckusick 	 */
49738414Smckusick 	if (flag == DELETE && *ndp->ni_next == 0) {
49838414Smckusick 		if (!bcmp(VTONFS(vp)->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) {
49938425Smckusick 			VREF(vp);
50038414Smckusick 			newvp = vp;
50138414Smckusick 			np = VTONFS(vp);
50238414Smckusick 		} else {
50338414Smckusick 			if (error = nfs_nget(vp->v_mount, fhp, &np)) {
50439751Smckusick 				nfs_lock(vp);
50538414Smckusick 				m_freem(mrep);
50638414Smckusick 				return (error);
50738414Smckusick 			}
50838414Smckusick 			newvp = NFSTOV(np);
50938414Smckusick 		}
51039459Smckusick 		if (error =
51139459Smckusick 		    nfs_loadattrcache(&newvp, &md, &dpos, (struct vattr *)0)) {
51239751Smckusick 			nfs_lock(vp);
51338414Smckusick 			if (newvp != vp)
51438414Smckusick 				nfs_nput(newvp);
51538414Smckusick 			else
51638425Smckusick 				vrele(vp);
51738414Smckusick 			m_freem(mrep);
51838414Smckusick 			return (error);
51938414Smckusick 		}
52038414Smckusick 		ndp->ni_vp = newvp;
52139751Smckusick 		if (lockparent || vp == newvp)
52239751Smckusick 			nfs_lock(vp);
52338414Smckusick 		m_freem(mrep);
52449741Smckusick 		ndp->ni_nameiop |= SAVENAME;
52538414Smckusick 		return (0);
52638414Smckusick 	}
52738414Smckusick 
52838414Smckusick 	if (flag == RENAME && wantparent && *ndp->ni_next == 0) {
52938414Smckusick 		if (!bcmp(VTONFS(vp)->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) {
53039751Smckusick 			nfs_lock(vp);
53138414Smckusick 			m_freem(mrep);
53238414Smckusick 			return (EISDIR);
53338414Smckusick 		}
53438414Smckusick 		if (error = nfs_nget(vp->v_mount, fhp, &np)) {
53539751Smckusick 			nfs_lock(vp);
53638414Smckusick 			m_freem(mrep);
53738414Smckusick 			return (error);
53838414Smckusick 		}
53938414Smckusick 		newvp = NFSTOV(np);
54039459Smckusick 		if (error =
54139459Smckusick 		    nfs_loadattrcache(&newvp, &md, &dpos, (struct vattr *)0)) {
54239751Smckusick 			nfs_lock(vp);
54338425Smckusick 			nfs_nput(newvp);
54438414Smckusick 			m_freem(mrep);
54538414Smckusick 			return (error);
54638414Smckusick 		}
54738414Smckusick 		ndp->ni_vp = newvp;
54839751Smckusick 		if (lockparent)
54939751Smckusick 			nfs_lock(vp);
55045037Smckusick 		m_freem(mrep);
55149741Smckusick 		ndp->ni_nameiop |= SAVENAME;
55238414Smckusick 		return (0);
55338414Smckusick 	}
55438414Smckusick 
55538414Smckusick 	if (!bcmp(VTONFS(vp)->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) {
55638425Smckusick 		VREF(vp);
55738414Smckusick 		newvp = vp;
55838414Smckusick 		np = VTONFS(vp);
55938414Smckusick 	} else if (ndp->ni_isdotdot) {
56038414Smckusick 		if (error = nfs_nget(vp->v_mount, fhp, &np)) {
56138414Smckusick 			nfs_lock(vp);
56238414Smckusick 			m_freem(mrep);
56338414Smckusick 			return (error);
56438414Smckusick 		}
56538414Smckusick 		newvp = NFSTOV(np);
56638414Smckusick 	} else {
56738414Smckusick 		if (error = nfs_nget(vp->v_mount, fhp, &np)) {
56839751Smckusick 			nfs_lock(vp);
56938414Smckusick 			m_freem(mrep);
57038414Smckusick 			return (error);
57138414Smckusick 		}
57238414Smckusick 		newvp = NFSTOV(np);
57338414Smckusick 	}
57439459Smckusick 	if (error = nfs_loadattrcache(&newvp, &md, &dpos, (struct vattr *)0)) {
57539751Smckusick 		nfs_lock(vp);
57638414Smckusick 		if (newvp != vp)
57738414Smckusick 			nfs_nput(newvp);
57838414Smckusick 		else
57938425Smckusick 			vrele(vp);
58038414Smckusick 		m_freem(mrep);
58138414Smckusick 		return (error);
58238414Smckusick 	}
58338414Smckusick 	m_freem(mrep);
58438414Smckusick 
58539751Smckusick 	if (vp == newvp || (lockparent && *ndp->ni_next == '\0'))
58639751Smckusick 		nfs_lock(vp);
58738414Smckusick 	ndp->ni_vp = newvp;
58849872Smckusick 	if (flag != LOOKUP && *ndp->ni_next == 0)
58949741Smckusick 		ndp->ni_nameiop |= SAVENAME;
59040251Smckusick 	if (error == 0 && ndp->ni_makeentry) {
59140251Smckusick 		np->n_ctime = np->n_vattr.va_ctime.tv_sec;
59238414Smckusick 		cache_enter(ndp);
59340251Smckusick 	}
59438414Smckusick 	return (error);
59538414Smckusick }
59638414Smckusick 
59738414Smckusick /*
59841905Smckusick  * nfs read call.
59941905Smckusick  * Just call nfs_bioread() to do the work.
60041905Smckusick  */
60141905Smckusick nfs_read(vp, uiop, ioflag, cred)
60241905Smckusick 	register struct vnode *vp;
60341905Smckusick 	struct uio *uiop;
60441905Smckusick 	int ioflag;
60541905Smckusick 	struct ucred *cred;
60641905Smckusick {
60741905Smckusick 	if (vp->v_type != VREG)
60841905Smckusick 		return (EPERM);
60941905Smckusick 	return (nfs_bioread(vp, uiop, ioflag, cred));
61041905Smckusick }
61141905Smckusick 
61241905Smckusick /*
61338414Smckusick  * nfs readlink call
61438414Smckusick  */
61538414Smckusick nfs_readlink(vp, uiop, cred)
61641905Smckusick 	struct vnode *vp;
61741905Smckusick 	struct uio *uiop;
61841905Smckusick 	struct ucred *cred;
61941905Smckusick {
62041905Smckusick 	if (vp->v_type != VLNK)
62141905Smckusick 		return (EPERM);
62241905Smckusick 	return (nfs_bioread(vp, uiop, 0, cred));
62341905Smckusick }
62441905Smckusick 
62541905Smckusick /*
62641905Smckusick  * Do a readlink rpc.
62741905Smckusick  * Called by nfs_doio() from below the buffer cache.
62841905Smckusick  */
62948054Smckusick nfs_readlinkrpc(vp, uiop, cred)
63039488Smckusick 	register struct vnode *vp;
63138414Smckusick 	struct uio *uiop;
63238414Smckusick 	struct ucred *cred;
63338414Smckusick {
63448054Smckusick 	register u_long *tl;
63539488Smckusick 	register caddr_t cp;
63639488Smckusick 	register long t1;
63739488Smckusick 	caddr_t bpos, dpos, cp2;
63839488Smckusick 	u_long xid;
63939488Smckusick 	int error = 0;
64039488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
64138414Smckusick 	long len;
64238414Smckusick 
64338414Smckusick 	nfsstats.rpccnt[NFSPROC_READLINK]++;
64438414Smckusick 	nfsm_reqhead(nfs_procids[NFSPROC_READLINK], cred, NFSX_FH);
64538414Smckusick 	nfsm_fhtom(vp);
64648054Smckusick 	nfsm_request(vp, NFSPROC_READLINK, uiop->uio_procp, 0);
64738414Smckusick 	nfsm_strsiz(len, NFS_MAXPATHLEN);
64838414Smckusick 	nfsm_mtouio(uiop, len);
64938414Smckusick 	nfsm_reqdone;
65038414Smckusick 	return (error);
65138414Smckusick }
65238414Smckusick 
65338414Smckusick /*
65441905Smckusick  * nfs read rpc call
65541905Smckusick  * Ditto above
65638414Smckusick  */
65748054Smckusick nfs_readrpc(vp, uiop, cred)
65839488Smckusick 	register struct vnode *vp;
65938414Smckusick 	struct uio *uiop;
66038414Smckusick 	struct ucred *cred;
66138414Smckusick {
66248054Smckusick 	register u_long *tl;
66339488Smckusick 	register caddr_t cp;
66439488Smckusick 	register long t1;
66539488Smckusick 	caddr_t bpos, dpos, cp2;
66639488Smckusick 	u_long xid;
66739488Smckusick 	int error = 0;
66839488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
66938414Smckusick 	struct nfsmount *nmp;
67038414Smckusick 	long len, retlen, tsiz;
67138414Smckusick 
67241398Smckusick 	nmp = VFSTONFS(vp->v_mount);
67338414Smckusick 	tsiz = uiop->uio_resid;
67438414Smckusick 	while (tsiz > 0) {
67538414Smckusick 		nfsstats.rpccnt[NFSPROC_READ]++;
67638414Smckusick 		len = (tsiz > nmp->nm_rsize) ? nmp->nm_rsize : tsiz;
67738414Smckusick 		nfsm_reqhead(nfs_procids[NFSPROC_READ], cred, NFSX_FH+NFSX_UNSIGNED*3);
67838414Smckusick 		nfsm_fhtom(vp);
67948054Smckusick 		nfsm_build(tl, u_long *, NFSX_UNSIGNED*3);
68048054Smckusick 		*tl++ = txdr_unsigned(uiop->uio_offset);
68148054Smckusick 		*tl++ = txdr_unsigned(len);
68248054Smckusick 		*tl = 0;
68348054Smckusick 		nfsm_request(vp, NFSPROC_READ, uiop->uio_procp, 1);
68438414Smckusick 		nfsm_loadattr(vp, (struct vattr *)0);
68538414Smckusick 		nfsm_strsiz(retlen, nmp->nm_rsize);
68638414Smckusick 		nfsm_mtouio(uiop, retlen);
68738414Smckusick 		m_freem(mrep);
68838414Smckusick 		if (retlen < len)
68938414Smckusick 			tsiz = 0;
69038414Smckusick 		else
69138414Smckusick 			tsiz -= len;
69238414Smckusick 	}
69338414Smckusick nfsmout:
69438414Smckusick 	return (error);
69538414Smckusick }
69638414Smckusick 
69738414Smckusick /*
69838414Smckusick  * nfs write call
69938414Smckusick  */
70048054Smckusick nfs_writerpc(vp, uiop, cred)
70139488Smckusick 	register struct vnode *vp;
70238414Smckusick 	struct uio *uiop;
70338414Smckusick 	struct ucred *cred;
70438414Smckusick {
70548054Smckusick 	register u_long *tl;
70639488Smckusick 	register caddr_t cp;
70739488Smckusick 	register long t1;
70839488Smckusick 	caddr_t bpos, dpos;
70939488Smckusick 	u_long xid;
71039488Smckusick 	int error = 0;
71139488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
71238414Smckusick 	struct nfsmount *nmp;
71338414Smckusick 	long len, tsiz;
71438414Smckusick 
71541398Smckusick 	nmp = VFSTONFS(vp->v_mount);
71638414Smckusick 	tsiz = uiop->uio_resid;
71738414Smckusick 	while (tsiz > 0) {
71838414Smckusick 		nfsstats.rpccnt[NFSPROC_WRITE]++;
71938414Smckusick 		len = (tsiz > nmp->nm_wsize) ? nmp->nm_wsize : tsiz;
72038414Smckusick 		nfsm_reqhead(nfs_procids[NFSPROC_WRITE], cred,
72138414Smckusick 			NFSX_FH+NFSX_UNSIGNED*4);
72238414Smckusick 		nfsm_fhtom(vp);
72348054Smckusick 		nfsm_build(tl, u_long *, NFSX_UNSIGNED*4);
72448054Smckusick 		*(tl+1) = txdr_unsigned(uiop->uio_offset);
72548054Smckusick 		*(tl+3) = txdr_unsigned(len);
72638414Smckusick 		nfsm_uiotom(uiop, len);
72748054Smckusick 		nfsm_request(vp, NFSPROC_WRITE, uiop->uio_procp, 1);
72838414Smckusick 		nfsm_loadattr(vp, (struct vattr *)0);
72938414Smckusick 		m_freem(mrep);
73038414Smckusick 		tsiz -= len;
73138414Smckusick 	}
73238414Smckusick nfsmout:
73338414Smckusick 	return (error);
73438414Smckusick }
73538414Smckusick 
73638414Smckusick /*
73739459Smckusick  * nfs mknod call
73842246Smckusick  * This is a kludge. Use a create rpc but with the IFMT bits of the mode
73942246Smckusick  * set to specify the file type and the size field for rdev.
74039459Smckusick  */
74139459Smckusick /* ARGSUSED */
74248054Smckusick nfs_mknod(ndp, vap, cred, p)
74339459Smckusick 	struct nameidata *ndp;
74439459Smckusick 	struct ucred *cred;
74542246Smckusick 	register struct vattr *vap;
74648054Smckusick 	struct proc *p;
74739459Smckusick {
74842246Smckusick 	register struct nfsv2_sattr *sp;
74948054Smckusick 	register u_long *tl;
75042246Smckusick 	register caddr_t cp;
75142246Smckusick 	register long t1, t2;
75242246Smckusick 	caddr_t bpos, dpos;
75342246Smckusick 	u_long xid;
75442246Smckusick 	int error = 0;
75542246Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
75642246Smckusick 	u_long rdev;
75739459Smckusick 
75842246Smckusick 	if (vap->va_type == VCHR || vap->va_type == VBLK)
75942246Smckusick 		rdev = txdr_unsigned(vap->va_rdev);
76042246Smckusick #ifdef FIFO
76142246Smckusick 	else if (vap->va_type == VFIFO)
76242246Smckusick 		rdev = 0xffffffff;
76342246Smckusick #endif /* FIFO */
76442246Smckusick 	else {
76542246Smckusick 		VOP_ABORTOP(ndp);
76642467Smckusick 		vput(ndp->ni_dvp);
76742246Smckusick 		return (EOPNOTSUPP);
76842246Smckusick 	}
76942246Smckusick 	nfsstats.rpccnt[NFSPROC_CREATE]++;
77042246Smckusick 	nfsm_reqhead(nfs_procids[NFSPROC_CREATE], ndp->ni_cred,
77149741Smckusick 	  NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_namelen)+NFSX_SATTR);
77242246Smckusick 	nfsm_fhtom(ndp->ni_dvp);
77349741Smckusick 	nfsm_strtom(ndp->ni_ptr, ndp->ni_namelen, NFS_MAXNAMLEN);
77442246Smckusick 	nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR);
77542246Smckusick 	sp->sa_mode = vtonfs_mode(vap->va_type, vap->va_mode);
77642246Smckusick 	sp->sa_uid = txdr_unsigned(ndp->ni_cred->cr_uid);
77742246Smckusick 	sp->sa_gid = txdr_unsigned(ndp->ni_cred->cr_gid);
77842246Smckusick 	sp->sa_size = rdev;
77942246Smckusick 	/* or should these be VNOVAL ?? */
78042246Smckusick 	txdr_time(&vap->va_atime, &sp->sa_atime);
78142246Smckusick 	txdr_time(&vap->va_mtime, &sp->sa_mtime);
78248054Smckusick 	nfsm_request(ndp->ni_dvp, NFSPROC_CREATE, p, 1);
78342246Smckusick 	nfsm_reqdone;
78449741Smckusick 	FREE(ndp->ni_pnbuf, M_NAMEI);
78542246Smckusick 	VTONFS(ndp->ni_dvp)->n_flag |= NMODIFIED;
78642246Smckusick 	nfs_nput(ndp->ni_dvp);
78742246Smckusick 	return (error);
78839459Smckusick }
78939459Smckusick 
79039459Smckusick /*
79138414Smckusick  * nfs file create call
79238414Smckusick  */
79348054Smckusick nfs_create(ndp, vap, p)
79438414Smckusick 	register struct nameidata *ndp;
79538414Smckusick 	register struct vattr *vap;
79648054Smckusick 	struct proc *p;
79738414Smckusick {
79838884Smacklem 	register struct nfsv2_sattr *sp;
79948054Smckusick 	register u_long *tl;
80039488Smckusick 	register caddr_t cp;
80139488Smckusick 	register long t1, t2;
80239488Smckusick 	caddr_t bpos, dpos, cp2;
80339488Smckusick 	u_long xid;
80439488Smckusick 	int error = 0;
80539488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
80638414Smckusick 
80738414Smckusick 	nfsstats.rpccnt[NFSPROC_CREATE]++;
80838414Smckusick 	nfsm_reqhead(nfs_procids[NFSPROC_CREATE], ndp->ni_cred,
80949741Smckusick 	  NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_namelen)+NFSX_SATTR);
81038414Smckusick 	nfsm_fhtom(ndp->ni_dvp);
81149741Smckusick 	nfsm_strtom(ndp->ni_ptr, ndp->ni_namelen, NFS_MAXNAMLEN);
81238884Smacklem 	nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR);
81346988Smckusick 	sp->sa_mode = vtonfs_mode(vap->va_type, vap->va_mode);
81438884Smacklem 	sp->sa_uid = txdr_unsigned(ndp->ni_cred->cr_uid);
81538884Smacklem 	sp->sa_gid = txdr_unsigned(ndp->ni_cred->cr_gid);
81638884Smacklem 	sp->sa_size = txdr_unsigned(0);
81738414Smckusick 	/* or should these be VNOVAL ?? */
81838884Smacklem 	txdr_time(&vap->va_atime, &sp->sa_atime);
81938884Smacklem 	txdr_time(&vap->va_mtime, &sp->sa_mtime);
82048054Smckusick 	nfsm_request(ndp->ni_dvp, NFSPROC_CREATE, p, 1);
82138414Smckusick 	nfsm_mtofh(ndp->ni_dvp, ndp->ni_vp);
82238414Smckusick 	nfsm_reqdone;
82349741Smckusick 	FREE(ndp->ni_pnbuf, M_NAMEI);
82441905Smckusick 	VTONFS(ndp->ni_dvp)->n_flag |= NMODIFIED;
82538414Smckusick 	nfs_nput(ndp->ni_dvp);
82638414Smckusick 	return (error);
82738414Smckusick }
82838414Smckusick 
82938414Smckusick /*
83038414Smckusick  * nfs file remove call
83141905Smckusick  * To try and make nfs semantics closer to ufs semantics, a file that has
83241905Smckusick  * other processes using the vnode is renamed instead of removed and then
83339341Smckusick  * removed later on the last close.
83441905Smckusick  * - If v_usecount > 1
83539341Smckusick  *	  If a rename is not already in the works
83639341Smckusick  *	     call nfs_sillyrename() to set it up
83739341Smckusick  *     else
83839341Smckusick  *	  do the remove rpc
83938414Smckusick  */
84048054Smckusick nfs_remove(ndp, p)
84138414Smckusick 	register struct nameidata *ndp;
84248054Smckusick 	struct proc *p;
84338414Smckusick {
84439341Smckusick 	register struct vnode *vp = ndp->ni_vp;
84539341Smckusick 	register struct nfsnode *np = VTONFS(ndp->ni_vp);
84648054Smckusick 	register u_long *tl;
84739488Smckusick 	register caddr_t cp;
84839488Smckusick 	register long t1, t2;
84939488Smckusick 	caddr_t bpos, dpos;
85039488Smckusick 	u_long xid;
85139488Smckusick 	int error = 0;
85239488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
85338414Smckusick 
85439810Smckusick 	if (vp->v_usecount > 1) {
85539341Smckusick 		if (!np->n_sillyrename)
85648364Smckusick 			error = nfs_sillyrename(ndp, p);
85739341Smckusick 	} else {
85838414Smckusick 		nfsstats.rpccnt[NFSPROC_REMOVE]++;
85938414Smckusick 		nfsm_reqhead(nfs_procids[NFSPROC_REMOVE], ndp->ni_cred,
86049741Smckusick 			NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_namelen));
86138414Smckusick 		nfsm_fhtom(ndp->ni_dvp);
86249741Smckusick 		nfsm_strtom(ndp->ni_ptr, ndp->ni_namelen, NFS_MAXNAMLEN);
86348054Smckusick 		nfsm_request(ndp->ni_dvp, NFSPROC_REMOVE, p, 1);
86438414Smckusick 		nfsm_reqdone;
86549741Smckusick 		FREE(ndp->ni_pnbuf, M_NAMEI);
86641905Smckusick 		VTONFS(ndp->ni_dvp)->n_flag |= NMODIFIED;
86739751Smckusick 		/*
86839751Smckusick 		 * Kludge City: If the first reply to the remove rpc is lost..
86939751Smckusick 		 *   the reply to the retransmitted request will be ENOENT
87039751Smckusick 		 *   since the file was in fact removed
87139751Smckusick 		 *   Therefore, we cheat and return success.
87239751Smckusick 		 */
87339751Smckusick 		if (error == ENOENT)
87439751Smckusick 			error = 0;
87538414Smckusick 	}
87640042Smckusick 	np->n_attrstamp = 0;
87740112Smckusick 	if (ndp->ni_dvp == vp)
87840112Smckusick 		vrele(vp);
87938414Smckusick 	else
88040112Smckusick 		nfs_nput(ndp->ni_dvp);
88140112Smckusick 	nfs_nput(vp);
88238414Smckusick 	return (error);
88338414Smckusick }
88438414Smckusick 
88538414Smckusick /*
88638414Smckusick  * nfs file remove rpc called from nfs_inactive
88738414Smckusick  */
88848364Smckusick nfs_removeit(sp, p)
88948364Smckusick 	register struct sillyrename *sp;
89048054Smckusick 	struct proc *p;
89138414Smckusick {
89248054Smckusick 	register u_long *tl;
89339488Smckusick 	register caddr_t cp;
89439488Smckusick 	register long t1, t2;
89539488Smckusick 	caddr_t bpos, dpos;
89639488Smckusick 	u_long xid;
89739488Smckusick 	int error = 0;
89839488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
89938414Smckusick 
90038414Smckusick 	nfsstats.rpccnt[NFSPROC_REMOVE]++;
90148364Smckusick 	nfsm_reqhead(nfs_procids[NFSPROC_REMOVE], sp->s_cred,
90248364Smckusick 		NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(sp->s_namlen));
90348364Smckusick 	nfsm_fhtom(sp->s_dvp);
90448364Smckusick 	nfsm_strtom(sp->s_name, sp->s_namlen, NFS_MAXNAMLEN);
90548364Smckusick 	nfsm_request(sp->s_dvp, NFSPROC_REMOVE, p, 1);
90638414Smckusick 	nfsm_reqdone;
90748364Smckusick 	VTONFS(sp->s_dvp)->n_flag |= NMODIFIED;
90838414Smckusick 	return (error);
90938414Smckusick }
91038414Smckusick 
91138414Smckusick /*
91238414Smckusick  * nfs file rename call
91338414Smckusick  */
91448054Smckusick nfs_rename(sndp, tndp, p)
91538414Smckusick 	register struct nameidata *sndp, *tndp;
91648054Smckusick 	struct proc *p;
91738414Smckusick {
91848054Smckusick 	register u_long *tl;
91939488Smckusick 	register caddr_t cp;
92039488Smckusick 	register long t1, t2;
92139488Smckusick 	caddr_t bpos, dpos;
92239488Smckusick 	u_long xid;
92339488Smckusick 	int error = 0;
92439488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
92538414Smckusick 
92638414Smckusick 	nfsstats.rpccnt[NFSPROC_RENAME]++;
92738414Smckusick 	nfsm_reqhead(nfs_procids[NFSPROC_RENAME], tndp->ni_cred,
92849741Smckusick 		(NFSX_FH+NFSX_UNSIGNED)*2+nfsm_rndup(sndp->ni_namelen) +
92949741Smckusick 		nfsm_rndup(tndp->ni_namelen)); /* or sndp->ni_cred?*/
93038414Smckusick 	nfsm_fhtom(sndp->ni_dvp);
93149741Smckusick 	nfsm_strtom(sndp->ni_ptr, sndp->ni_namelen, NFS_MAXNAMLEN);
93238414Smckusick 	nfsm_fhtom(tndp->ni_dvp);
93349741Smckusick 	nfsm_strtom(tndp->ni_ptr, tndp->ni_namelen, NFS_MAXNAMLEN);
93448054Smckusick 	nfsm_request(sndp->ni_dvp, NFSPROC_RENAME, p, 1);
93538414Smckusick 	nfsm_reqdone;
93641905Smckusick 	VTONFS(sndp->ni_dvp)->n_flag |= NMODIFIED;
93741905Smckusick 	VTONFS(tndp->ni_dvp)->n_flag |= NMODIFIED;
93838414Smckusick 	if (sndp->ni_vp->v_type == VDIR) {
93938414Smckusick 		if (tndp->ni_vp != NULL && tndp->ni_vp->v_type == VDIR)
94038414Smckusick 			cache_purge(tndp->ni_dvp);
94138414Smckusick 		cache_purge(sndp->ni_dvp);
94238414Smckusick 	}
94343360Smckusick 	if (tndp->ni_dvp == tndp->ni_vp)
94443360Smckusick 		vrele(tndp->ni_dvp);
94543360Smckusick 	else
94643360Smckusick 		vput(tndp->ni_dvp);
94742467Smckusick 	if (tndp->ni_vp)
94842467Smckusick 		vput(tndp->ni_vp);
94942467Smckusick 	vrele(sndp->ni_dvp);
95042467Smckusick 	vrele(sndp->ni_vp);
95140112Smckusick 	/*
95240112Smckusick 	 * Kludge: Map ENOENT => 0 assuming that it is a reply to a retry.
95340112Smckusick 	 */
95440112Smckusick 	if (error == ENOENT)
95540112Smckusick 		error = 0;
95638414Smckusick 	return (error);
95738414Smckusick }
95838414Smckusick 
95938414Smckusick /*
96041905Smckusick  * nfs file rename rpc called from nfs_remove() above
96138414Smckusick  */
96248364Smckusick nfs_renameit(sndp, sp, p)
96348364Smckusick 	register struct nameidata *sndp;
96448364Smckusick 	register struct sillyrename *sp;
96548054Smckusick 	struct proc *p;
96638414Smckusick {
96748054Smckusick 	register u_long *tl;
96839488Smckusick 	register caddr_t cp;
96939488Smckusick 	register long t1, t2;
97039488Smckusick 	caddr_t bpos, dpos;
97139488Smckusick 	u_long xid;
97239488Smckusick 	int error = 0;
97339488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
97438414Smckusick 
97538414Smckusick 	nfsstats.rpccnt[NFSPROC_RENAME]++;
97648364Smckusick 	nfsm_reqhead(nfs_procids[NFSPROC_RENAME], sp->s_cred,
97749741Smckusick 		(NFSX_FH+NFSX_UNSIGNED)*2+nfsm_rndup(sndp->ni_namelen) +
97848364Smckusick 		nfsm_rndup(sp->s_namlen)); /* or sndp->ni_cred?*/
97938414Smckusick 	nfsm_fhtom(sndp->ni_dvp);
98049741Smckusick 	nfsm_strtom(sndp->ni_ptr, sndp->ni_namelen, NFS_MAXNAMLEN);
98148364Smckusick 	nfsm_fhtom(sp->s_dvp);
98248364Smckusick 	nfsm_strtom(sp->s_name, sp->s_namlen, NFS_MAXNAMLEN);
98348054Smckusick 	nfsm_request(sndp->ni_dvp, NFSPROC_RENAME, p, 1);
98438414Smckusick 	nfsm_reqdone;
98549741Smckusick 	FREE(sndp->ni_pnbuf, M_NAMEI);
98641905Smckusick 	VTONFS(sndp->ni_dvp)->n_flag |= NMODIFIED;
98748364Smckusick 	VTONFS(sp->s_dvp)->n_flag |= NMODIFIED;
98838414Smckusick 	return (error);
98938414Smckusick }
99038414Smckusick 
99138414Smckusick /*
99238414Smckusick  * nfs hard link create call
99338414Smckusick  */
99448054Smckusick nfs_link(vp, ndp, p)
99539488Smckusick 	register struct vnode *vp;
99638414Smckusick 	register struct nameidata *ndp;
99748054Smckusick 	struct proc *p;
99838414Smckusick {
99948054Smckusick 	register u_long *tl;
100039488Smckusick 	register caddr_t cp;
100139488Smckusick 	register long t1, t2;
100239488Smckusick 	caddr_t bpos, dpos;
100339488Smckusick 	u_long xid;
100439488Smckusick 	int error = 0;
100539488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
100638414Smckusick 
100738425Smckusick 	if (ndp->ni_dvp != vp)
100838425Smckusick 		nfs_lock(vp);
100938414Smckusick 	nfsstats.rpccnt[NFSPROC_LINK]++;
101038414Smckusick 	nfsm_reqhead(nfs_procids[NFSPROC_LINK], ndp->ni_cred,
101149741Smckusick 		NFSX_FH*2+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_namelen));
101238414Smckusick 	nfsm_fhtom(vp);
101338414Smckusick 	nfsm_fhtom(ndp->ni_dvp);
101449741Smckusick 	nfsm_strtom(ndp->ni_ptr, ndp->ni_namelen, NFS_MAXNAMLEN);
101548054Smckusick 	nfsm_request(vp, NFSPROC_LINK, p, 1);
101638414Smckusick 	nfsm_reqdone;
101749741Smckusick 	FREE(ndp->ni_pnbuf, M_NAMEI);
101840042Smckusick 	VTONFS(vp)->n_attrstamp = 0;
101941905Smckusick 	VTONFS(ndp->ni_dvp)->n_flag |= NMODIFIED;
102038425Smckusick 	if (ndp->ni_dvp != vp)
102138425Smckusick 		nfs_unlock(vp);
102238414Smckusick 	nfs_nput(ndp->ni_dvp);
102340112Smckusick 	/*
102440112Smckusick 	 * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry.
102540112Smckusick 	 */
102640112Smckusick 	if (error == EEXIST)
102740112Smckusick 		error = 0;
102838414Smckusick 	return (error);
102938414Smckusick }
103038414Smckusick 
103138414Smckusick /*
103238414Smckusick  * nfs symbolic link create call
103338414Smckusick  */
103448054Smckusick nfs_symlink(ndp, vap, nm, p)
103538414Smckusick 	struct nameidata *ndp;
103638414Smckusick 	struct vattr *vap;
103738414Smckusick 	char *nm;		/* is this the path ?? */
103848054Smckusick 	struct proc *p;
103938414Smckusick {
104038884Smacklem 	register struct nfsv2_sattr *sp;
104148054Smckusick 	register u_long *tl;
104239488Smckusick 	register caddr_t cp;
104339488Smckusick 	register long t1, t2;
104439488Smckusick 	caddr_t bpos, dpos;
104539488Smckusick 	u_long xid;
104639488Smckusick 	int error = 0;
104739488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
104838414Smckusick 
104938414Smckusick 	nfsstats.rpccnt[NFSPROC_SYMLINK]++;
105038414Smckusick 	nfsm_reqhead(nfs_procids[NFSPROC_SYMLINK], ndp->ni_cred,
105149741Smckusick 	NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_namelen)+NFSX_UNSIGNED);
105238414Smckusick 	nfsm_fhtom(ndp->ni_dvp);
105349741Smckusick 	nfsm_strtom(ndp->ni_ptr, ndp->ni_namelen, NFS_MAXNAMLEN);
105438414Smckusick 	nfsm_strtom(nm, strlen(nm), NFS_MAXPATHLEN);
105538884Smacklem 	nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR);
105638884Smacklem 	sp->sa_mode = vtonfs_mode(VLNK, vap->va_mode);
105738884Smacklem 	sp->sa_uid = txdr_unsigned(ndp->ni_cred->cr_uid);
105838884Smacklem 	sp->sa_gid = txdr_unsigned(ndp->ni_cred->cr_gid);
105938884Smacklem 	sp->sa_size = txdr_unsigned(VNOVAL);
106040112Smckusick 	txdr_time(&vap->va_atime, &sp->sa_atime);	/* or VNOVAL ?? */
106138884Smacklem 	txdr_time(&vap->va_mtime, &sp->sa_mtime);	/* or VNOVAL ?? */
106248054Smckusick 	nfsm_request(ndp->ni_dvp, NFSPROC_SYMLINK, p, 1);
106338414Smckusick 	nfsm_reqdone;
106449741Smckusick 	FREE(ndp->ni_pnbuf, M_NAMEI);
106541905Smckusick 	VTONFS(ndp->ni_dvp)->n_flag |= NMODIFIED;
106638414Smckusick 	nfs_nput(ndp->ni_dvp);
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 make dir call
107738414Smckusick  */
107848054Smckusick nfs_mkdir(ndp, vap, p)
107939488Smckusick 	register struct nameidata *ndp;
108038414Smckusick 	struct vattr *vap;
108148054Smckusick 	struct proc *p;
108238414Smckusick {
108338884Smacklem 	register struct nfsv2_sattr *sp;
108448054Smckusick 	register u_long *tl;
108539488Smckusick 	register caddr_t cp;
108639488Smckusick 	register long t1, t2;
108741905Smckusick 	register int len;
108839488Smckusick 	caddr_t bpos, dpos, cp2;
108939488Smckusick 	u_long xid;
109041905Smckusick 	int error = 0, firsttry = 1;
109139488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
109238414Smckusick 
109349741Smckusick 	len = ndp->ni_namelen;
109438414Smckusick 	nfsstats.rpccnt[NFSPROC_MKDIR]++;
109538414Smckusick 	nfsm_reqhead(nfs_procids[NFSPROC_MKDIR], ndp->ni_cred,
109641905Smckusick 	  NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len)+NFSX_SATTR);
109738414Smckusick 	nfsm_fhtom(ndp->ni_dvp);
109849741Smckusick 	nfsm_strtom(ndp->ni_ptr, len, NFS_MAXNAMLEN);
109938884Smacklem 	nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR);
110038884Smacklem 	sp->sa_mode = vtonfs_mode(VDIR, vap->va_mode);
110138884Smacklem 	sp->sa_uid = txdr_unsigned(ndp->ni_cred->cr_uid);
110238884Smacklem 	sp->sa_gid = txdr_unsigned(ndp->ni_cred->cr_gid);
110338884Smacklem 	sp->sa_size = txdr_unsigned(VNOVAL);
110440112Smckusick 	txdr_time(&vap->va_atime, &sp->sa_atime);	/* or VNOVAL ?? */
110538884Smacklem 	txdr_time(&vap->va_mtime, &sp->sa_mtime);	/* or VNOVAL ?? */
110648054Smckusick 	nfsm_request(ndp->ni_dvp, NFSPROC_MKDIR, p, 1);
110738414Smckusick 	nfsm_mtofh(ndp->ni_dvp, ndp->ni_vp);
110838414Smckusick 	nfsm_reqdone;
110941905Smckusick 	VTONFS(ndp->ni_dvp)->n_flag |= NMODIFIED;
111040112Smckusick 	/*
111141905Smckusick 	 * Kludge: Map EEXIST => 0 assuming that you have a reply to a retry
111241905Smckusick 	 * if we can succeed in looking up the directory.
111341905Smckusick 	 * "firsttry" is necessary since the macros may "goto nfsmout" which
111441905Smckusick 	 * is above the if on errors. (Ugh)
111540112Smckusick 	 */
111641905Smckusick 	if (error == EEXIST && firsttry) {
111741905Smckusick 		firsttry = 0;
111840112Smckusick 		error = 0;
111941905Smckusick 		nfsstats.rpccnt[NFSPROC_LOOKUP]++;
112041905Smckusick 		ndp->ni_vp = NULL;
112141905Smckusick 		nfsm_reqhead(nfs_procids[NFSPROC_LOOKUP], ndp->ni_cred,
112241905Smckusick 		    NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len));
112341905Smckusick 		nfsm_fhtom(ndp->ni_dvp);
112449741Smckusick 		nfsm_strtom(ndp->ni_ptr, len, NFS_MAXNAMLEN);
112548054Smckusick 		nfsm_request(ndp->ni_dvp, NFSPROC_LOOKUP, p, 1);
112641905Smckusick 		nfsm_mtofh(ndp->ni_dvp, ndp->ni_vp);
112741905Smckusick 		if (ndp->ni_vp->v_type != VDIR) {
112841905Smckusick 			vput(ndp->ni_vp);
112941905Smckusick 			error = EEXIST;
113041905Smckusick 		}
113141905Smckusick 		m_freem(mrep);
113241905Smckusick 	}
113349741Smckusick 	FREE(ndp->ni_pnbuf, M_NAMEI);
113441905Smckusick 	nfs_nput(ndp->ni_dvp);
113538414Smckusick 	return (error);
113638414Smckusick }
113738414Smckusick 
113838414Smckusick /*
113938414Smckusick  * nfs remove directory call
114038414Smckusick  */
114148054Smckusick nfs_rmdir(ndp, p)
114238414Smckusick 	register struct nameidata *ndp;
114348054Smckusick 	struct proc *p;
114438414Smckusick {
114548054Smckusick 	register u_long *tl;
114639488Smckusick 	register caddr_t cp;
114739488Smckusick 	register long t1, t2;
114839488Smckusick 	caddr_t bpos, dpos;
114939488Smckusick 	u_long xid;
115039488Smckusick 	int error = 0;
115139488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
115238414Smckusick 
115338414Smckusick 	if (ndp->ni_dvp == ndp->ni_vp) {
115438414Smckusick 		vrele(ndp->ni_dvp);
115538414Smckusick 		nfs_nput(ndp->ni_dvp);
115638414Smckusick 		return (EINVAL);
115738414Smckusick 	}
115838414Smckusick 	nfsstats.rpccnt[NFSPROC_RMDIR]++;
115938414Smckusick 	nfsm_reqhead(nfs_procids[NFSPROC_RMDIR], ndp->ni_cred,
116049741Smckusick 		NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_namelen));
116138414Smckusick 	nfsm_fhtom(ndp->ni_dvp);
116249741Smckusick 	nfsm_strtom(ndp->ni_ptr, ndp->ni_namelen, NFS_MAXNAMLEN);
116348054Smckusick 	nfsm_request(ndp->ni_dvp, NFSPROC_RMDIR, p, 1);
116438414Smckusick 	nfsm_reqdone;
116549741Smckusick 	FREE(ndp->ni_pnbuf, M_NAMEI);
116641905Smckusick 	VTONFS(ndp->ni_dvp)->n_flag |= NMODIFIED;
116738884Smacklem 	cache_purge(ndp->ni_dvp);
116838884Smacklem 	cache_purge(ndp->ni_vp);
116938884Smacklem 	nfs_nput(ndp->ni_vp);
117038884Smacklem 	nfs_nput(ndp->ni_dvp);
117140112Smckusick 	/*
117240112Smckusick 	 * Kludge: Map ENOENT => 0 assuming that you have a reply to a retry.
117340112Smckusick 	 */
117440112Smckusick 	if (error == ENOENT)
117540112Smckusick 		error = 0;
117638414Smckusick 	return (error);
117738414Smckusick }
117838414Smckusick 
117938414Smckusick /*
118038414Smckusick  * nfs readdir call
118138414Smckusick  * Although cookie is defined as opaque, I translate it to/from net byte
118238414Smckusick  * order so that it looks more sensible. This appears consistent with the
118338414Smckusick  * Ultrix implementation of NFS.
118438414Smckusick  */
118540296Smckusick nfs_readdir(vp, uiop, cred, eofflagp)
118639488Smckusick 	register struct vnode *vp;
118738414Smckusick 	struct uio *uiop;
118838414Smckusick 	struct ucred *cred;
118940296Smckusick 	int *eofflagp;
119038414Smckusick {
119141905Smckusick 	register struct nfsnode *np = VTONFS(vp);
119241905Smckusick 	int tresid, error;
119341905Smckusick 	struct vattr vattr;
119441905Smckusick 
119541905Smckusick 	if (vp->v_type != VDIR)
119641905Smckusick 		return (EPERM);
119741905Smckusick 	/*
119841905Smckusick 	 * First, check for hit on the EOF offset cache
119941905Smckusick 	 */
120041905Smckusick 	if (uiop->uio_offset != 0 && uiop->uio_offset == np->n_direofoffset &&
120141905Smckusick 	    (np->n_flag & NMODIFIED) == 0 &&
120248054Smckusick 	    nfs_dogetattr(vp, &vattr, cred, 0, uiop->uio_procp) == 0 &&
120341905Smckusick 	    np->n_mtime == vattr.va_mtime.tv_sec) {
120441905Smckusick 		*eofflagp = 1;
120541905Smckusick 		nfsstats.direofcache_hits++;
120641905Smckusick 		return (0);
120741905Smckusick 	}
120841905Smckusick 
120941905Smckusick 	/*
121041905Smckusick 	 * Call nfs_bioread() to do the real work.
121141905Smckusick 	 */
121241905Smckusick 	tresid = uiop->uio_resid;
121341905Smckusick 	error = nfs_bioread(vp, uiop, 0, cred);
121441905Smckusick 
121541905Smckusick 	if (!error && uiop->uio_resid == tresid) {
121641905Smckusick 		*eofflagp = 1;
121741905Smckusick 		nfsstats.direofcache_misses++;
121841905Smckusick 	} else
121941905Smckusick 		*eofflagp = 0;
122041905Smckusick 	return (error);
122141905Smckusick }
122241905Smckusick 
122341905Smckusick /*
122441905Smckusick  * Readdir rpc call.
122541905Smckusick  * Called from below the buffer cache by nfs_doio().
122641905Smckusick  */
122748054Smckusick nfs_readdirrpc(vp, uiop, cred)
122841905Smckusick 	register struct vnode *vp;
122941905Smckusick 	struct uio *uiop;
123041905Smckusick 	struct ucred *cred;
123141905Smckusick {
123238414Smckusick 	register long len;
123338414Smckusick 	register struct direct *dp;
123448054Smckusick 	register u_long *tl;
123539488Smckusick 	register caddr_t cp;
123639488Smckusick 	register long t1;
123741905Smckusick 	long tlen, lastlen;
123839488Smckusick 	caddr_t bpos, dpos, cp2;
123939488Smckusick 	u_long xid;
124039488Smckusick 	int error = 0;
124139488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
124238414Smckusick 	struct mbuf *md2;
124338414Smckusick 	caddr_t dpos2;
124438414Smckusick 	int siz;
124540296Smckusick 	int more_dirs = 1;
124638414Smckusick 	off_t off, savoff;
124738414Smckusick 	struct direct *savdp;
124840296Smckusick 	struct nfsmount *nmp;
124940296Smckusick 	struct nfsnode *np = VTONFS(vp);
125040296Smckusick 	long tresid;
125138414Smckusick 
125241398Smckusick 	nmp = VFSTONFS(vp->v_mount);
125340296Smckusick 	tresid = uiop->uio_resid;
125440296Smckusick 	/*
125540296Smckusick 	 * Loop around doing readdir rpc's of size uio_resid or nm_rsize,
125648054Smckusick 	 * whichever is smaller, truncated to a multiple of NFS_DIRBLKSIZ.
125741905Smckusick 	 * The stopping criteria is EOF or buffer full.
125840296Smckusick 	 */
125948054Smckusick 	while (more_dirs && uiop->uio_resid >= NFS_DIRBLKSIZ) {
126040296Smckusick 		nfsstats.rpccnt[NFSPROC_READDIR]++;
126140296Smckusick 		nfsm_reqhead(nfs_procids[NFSPROC_READDIR], cred, xid);
126240296Smckusick 		nfsm_fhtom(vp);
126348054Smckusick 		nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED);
126448054Smckusick 		*tl++ = txdr_unsigned(uiop->uio_offset);
126548054Smckusick 		*tl = txdr_unsigned(((uiop->uio_resid > nmp->nm_rsize) ?
126648054Smckusick 			nmp->nm_rsize : uiop->uio_resid) & ~(NFS_DIRBLKSIZ-1));
126748054Smckusick 		nfsm_request(vp, NFSPROC_READDIR, uiop->uio_procp, 0);
126840296Smckusick 		siz = 0;
126948054Smckusick 		nfsm_disect(tl, u_long *, NFSX_UNSIGNED);
127048054Smckusick 		more_dirs = fxdr_unsigned(int, *tl);
127140296Smckusick 
127240296Smckusick 		/* Save the position so that we can do nfsm_mtouio() later */
127340296Smckusick 		dpos2 = dpos;
127440296Smckusick 		md2 = md;
127540296Smckusick 
127640296Smckusick 		/* loop thru the dir entries, doctoring them to 4bsd form */
127741905Smckusick 		off = uiop->uio_offset;
127842246Smckusick #ifdef lint
127942246Smckusick 		dp = (struct direct *)0;
128042246Smckusick #endif /* lint */
128140296Smckusick 		while (more_dirs && siz < uiop->uio_resid) {
128240296Smckusick 			savoff = off;		/* Hold onto offset and dp */
128340296Smckusick 			savdp = dp;
128448054Smckusick 			nfsm_disecton(tl, u_long *, 2*NFSX_UNSIGNED);
128548054Smckusick 			dp = (struct direct *)tl;
128648054Smckusick 			dp->d_ino = fxdr_unsigned(u_long, *tl++);
128748054Smckusick 			len = fxdr_unsigned(int, *tl);
128840296Smckusick 			if (len <= 0 || len > NFS_MAXNAMLEN) {
128940296Smckusick 				error = EBADRPC;
129040296Smckusick 				m_freem(mrep);
129140296Smckusick 				goto nfsmout;
129240296Smckusick 			}
129340296Smckusick 			dp->d_namlen = (u_short)len;
129440296Smckusick 			nfsm_adv(len);		/* Point past name */
129540296Smckusick 			tlen = nfsm_rndup(len);
129640296Smckusick 			/*
129740296Smckusick 			 * This should not be necessary, but some servers have
129840296Smckusick 			 * broken XDR such that these bytes are not null filled.
129940296Smckusick 			 */
130040296Smckusick 			if (tlen != len) {
130140296Smckusick 				*dpos = '\0';	/* Null-terminate */
130240296Smckusick 				nfsm_adv(tlen - len);
130340296Smckusick 				len = tlen;
130440296Smckusick 			}
130548054Smckusick 			nfsm_disecton(tl, u_long *, 2*NFSX_UNSIGNED);
130648054Smckusick 			off = fxdr_unsigned(off_t, *tl);
130748054Smckusick 			*tl++ = 0;	/* Ensures null termination of name */
130848054Smckusick 			more_dirs = fxdr_unsigned(int, *tl);
130940296Smckusick 			dp->d_reclen = len+4*NFSX_UNSIGNED;
131040296Smckusick 			siz += dp->d_reclen;
131140296Smckusick 		}
131240296Smckusick 		/*
131340296Smckusick 		 * If at end of rpc data, get the eof boolean
131440296Smckusick 		 */
131540296Smckusick 		if (!more_dirs) {
131648054Smckusick 			nfsm_disecton(tl, u_long *, NFSX_UNSIGNED);
131748054Smckusick 			more_dirs = (fxdr_unsigned(int, *tl) == 0);
131838414Smckusick 
131940296Smckusick 			/*
132040296Smckusick 			 * If at EOF, cache directory offset
132140296Smckusick 			 */
132241905Smckusick 			if (!more_dirs)
132340296Smckusick 				np->n_direofoffset = off;
132438414Smckusick 		}
132540296Smckusick 		/*
132640296Smckusick 		 * If there is too much to fit in the data buffer, use savoff and
132740296Smckusick 		 * savdp to trim off the last record.
132840296Smckusick 		 * --> we are not at eof
132940296Smckusick 		 */
133040296Smckusick 		if (siz > uiop->uio_resid) {
133140296Smckusick 			off = savoff;
133240296Smckusick 			siz -= dp->d_reclen;
133340296Smckusick 			dp = savdp;
133440296Smckusick 			more_dirs = 0;	/* Paranoia */
133540113Smckusick 		}
133640296Smckusick 		if (siz > 0) {
133741905Smckusick 			lastlen = dp->d_reclen;
133840296Smckusick 			md = md2;
133940296Smckusick 			dpos = dpos2;
134040296Smckusick 			nfsm_mtouio(uiop, siz);
134140296Smckusick 			uiop->uio_offset = off;
134240296Smckusick 		} else
134340296Smckusick 			more_dirs = 0;	/* Ugh, never happens, but in case.. */
134440296Smckusick 		m_freem(mrep);
134538414Smckusick 	}
134641905Smckusick 	/*
134748054Smckusick 	 * Fill last record, iff any, out to a multiple of NFS_DIRBLKSIZ
134841905Smckusick 	 * by increasing d_reclen for the last record.
134941905Smckusick 	 */
135041905Smckusick 	if (uiop->uio_resid < tresid) {
135148054Smckusick 		len = uiop->uio_resid & (NFS_DIRBLKSIZ - 1);
135241905Smckusick 		if (len > 0) {
135341905Smckusick 			dp = (struct direct *)
135441905Smckusick 				(uiop->uio_iov->iov_base - lastlen);
135541905Smckusick 			dp->d_reclen += len;
135641905Smckusick 			uiop->uio_iov->iov_base += len;
135741905Smckusick 			uiop->uio_iov->iov_len -= len;
135841905Smckusick 			uiop->uio_resid -= len;
135941905Smckusick 		}
136041905Smckusick 	}
136140296Smckusick nfsmout:
136238414Smckusick 	return (error);
136338414Smckusick }
136438414Smckusick 
136539488Smckusick static char hextoasc[] = "0123456789abcdef";
136638414Smckusick 
136738414Smckusick /*
136838414Smckusick  * Silly rename. To make the NFS filesystem that is stateless look a little
136938414Smckusick  * more like the "ufs" a remove of an active vnode is translated to a rename
137038414Smckusick  * to a funny looking filename that is removed by nfs_inactive on the
137138414Smckusick  * nfsnode. There is the potential for another process on a different client
137238414Smckusick  * to create the same funny name between the nfs_lookitup() fails and the
137338414Smckusick  * nfs_rename() completes, but...
137438414Smckusick  */
137548364Smckusick nfs_sillyrename(ndp, p)
137639488Smckusick 	register struct nameidata *ndp;
137748054Smckusick 	struct proc *p;
137838414Smckusick {
137938414Smckusick 	register struct nfsnode *np;
138038414Smckusick 	register struct sillyrename *sp;
138138414Smckusick 	int error;
138238414Smckusick 	short pid;
138338414Smckusick 
138438414Smckusick 	np = VTONFS(ndp->ni_dvp);
138539341Smckusick 	cache_purge(ndp->ni_dvp);
1386*51986Smckusick #ifdef SILLYSEPARATE
138738414Smckusick 	MALLOC(sp, struct sillyrename *, sizeof (struct sillyrename),
138848364Smckusick 		M_NFSREQ, M_WAITOK);
1389*51986Smckusick #else
1390*51986Smckusick 	sp = &np->n_silly;
1391*51986Smckusick #endif
139238414Smckusick 	bcopy((caddr_t)&np->n_fh, (caddr_t)&sp->s_fh, NFSX_FH);
139338414Smckusick 	np = VTONFS(ndp->ni_vp);
139448364Smckusick 	sp->s_cred = crdup(ndp->ni_cred);
139548364Smckusick 	sp->s_dvp = ndp->ni_dvp;
139648364Smckusick 	VREF(sp->s_dvp);
139738414Smckusick 
139838414Smckusick 	/* Fudge together a funny name */
139948054Smckusick 	pid = p->p_pid;
140048364Smckusick 	bcopy(".nfsAxxxx4.4", sp->s_name, 13);
140148364Smckusick 	sp->s_namlen = 12;
140248364Smckusick 	sp->s_name[8] = hextoasc[pid & 0xf];
140348364Smckusick 	sp->s_name[7] = hextoasc[(pid >> 4) & 0xf];
140448364Smckusick 	sp->s_name[6] = hextoasc[(pid >> 8) & 0xf];
140548364Smckusick 	sp->s_name[5] = hextoasc[(pid >> 12) & 0xf];
140638414Smckusick 
140738414Smckusick 	/* Try lookitups until we get one that isn't there */
140848364Smckusick 	while (nfs_lookitup(sp, (nfsv2fh_t *)0, p) == 0) {
140948364Smckusick 		sp->s_name[4]++;
141048364Smckusick 		if (sp->s_name[4] > 'z') {
141138414Smckusick 			error = EINVAL;
141238414Smckusick 			goto bad;
141338414Smckusick 		}
141438414Smckusick 	}
141548364Smckusick 	if (error = nfs_renameit(ndp, sp, p))
141638414Smckusick 		goto bad;
141748364Smckusick 	nfs_lookitup(sp, &np->n_fh, p);
141838414Smckusick 	np->n_sillyrename = sp;
141938414Smckusick 	return (0);
142038414Smckusick bad:
142148364Smckusick 	vrele(sp->s_dvp);
142248364Smckusick 	crfree(sp->s_cred);
1423*51986Smckusick #ifdef SILLYSEPARATE
142448364Smckusick 	free((caddr_t)sp, M_NFSREQ);
1425*51986Smckusick #endif
142638414Smckusick 	return (error);
142738414Smckusick }
142838414Smckusick 
142938414Smckusick /*
143038414Smckusick  * Look up a file name for silly rename stuff.
143138414Smckusick  * Just like nfs_lookup() except that it doesn't load returned values
143238414Smckusick  * into the nfsnode table.
143338414Smckusick  * If fhp != NULL it copies the returned file handle out
143438414Smckusick  */
143548364Smckusick nfs_lookitup(sp, fhp, p)
143648364Smckusick 	register struct sillyrename *sp;
143738414Smckusick 	nfsv2fh_t *fhp;
143848054Smckusick 	struct proc *p;
143938414Smckusick {
144048364Smckusick 	register struct vnode *vp = sp->s_dvp;
144148054Smckusick 	register u_long *tl;
144239488Smckusick 	register caddr_t cp;
144339488Smckusick 	register long t1, t2;
144439488Smckusick 	caddr_t bpos, dpos, cp2;
144539488Smckusick 	u_long xid;
144639488Smckusick 	int error = 0;
144739488Smckusick 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
144838414Smckusick 	long len;
144938414Smckusick 
145038414Smckusick 	nfsstats.rpccnt[NFSPROC_LOOKUP]++;
145148364Smckusick 	len = sp->s_namlen;
145248364Smckusick 	nfsm_reqhead(nfs_procids[NFSPROC_LOOKUP], sp->s_cred, NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len));
145338414Smckusick 	nfsm_fhtom(vp);
145448364Smckusick 	nfsm_strtom(sp->s_name, len, NFS_MAXNAMLEN);
145548054Smckusick 	nfsm_request(vp, NFSPROC_LOOKUP, p, 1);
145638414Smckusick 	if (fhp != NULL) {
145738414Smckusick 		nfsm_disect(cp, caddr_t, NFSX_FH);
145838414Smckusick 		bcopy(cp, (caddr_t)fhp, NFSX_FH);
145938414Smckusick 	}
146038414Smckusick 	nfsm_reqdone;
146138414Smckusick 	return (error);
146238414Smckusick }
146338414Smckusick 
146438414Smckusick /*
146538414Smckusick  * Kludge City..
146638414Smckusick  * - make nfs_bmap() essentially a no-op that does no translation
146741905Smckusick  * - do nfs_strategy() by faking physical I/O with nfs_readrpc/nfs_writerpc
146838414Smckusick  *   after mapping the physical addresses into Kernel Virtual space in the
146938414Smckusick  *   nfsiobuf area.
147038414Smckusick  *   (Maybe I could use the process's page mapping, but I was concerned that
147138414Smckusick  *    Kernel Write might not be enabled and also figured copyout() would do
147238414Smckusick  *    a lot more work than bcopy() and also it currently happens in the
147338414Smckusick  *    context of the swapper process (2).
147438414Smckusick  */
147538414Smckusick nfs_bmap(vp, bn, vpp, bnp)
147638414Smckusick 	struct vnode *vp;
147738414Smckusick 	daddr_t bn;
147838414Smckusick 	struct vnode **vpp;
147938414Smckusick 	daddr_t *bnp;
148038414Smckusick {
148138414Smckusick 	if (vpp != NULL)
148238414Smckusick 		*vpp = vp;
148338414Smckusick 	if (bnp != NULL)
148441398Smckusick 		*bnp = bn * btodb(vp->v_mount->mnt_stat.f_bsize);
148538414Smckusick 	return (0);
148638414Smckusick }
148738414Smckusick 
148838414Smckusick /*
148938884Smacklem  * Strategy routine for phys. i/o
149038884Smacklem  * If the biod's are running, queue a request
149138884Smacklem  * otherwise just call nfs_doio() to get it done
149238414Smckusick  */
149338414Smckusick nfs_strategy(bp)
149438414Smckusick 	register struct buf *bp;
149538414Smckusick {
149638884Smacklem 	register struct buf *dp;
149739341Smckusick 	register int i;
149838884Smacklem 	int error = 0;
149939341Smckusick 	int fnd = 0;
150038884Smacklem 
150138884Smacklem 	/*
150241905Smckusick 	 * Set b_proc. It seems a bit silly to do it here, but since bread()
150341905Smckusick 	 * doesn't set it, I will.
150446450Skarels 	 * Set b_proc == NULL for asynchronous ops, since these may still
150541905Smckusick 	 * be hanging about after the process terminates.
150641905Smckusick 	 */
150746988Smckusick 	if ((bp->b_flags & B_PHYS) == 0) {
150846988Smckusick 		if (bp->b_flags & B_ASYNC)
150946988Smckusick 			bp->b_proc = (struct proc *)0;
151046988Smckusick 		else
151147573Skarels 			bp->b_proc = curproc;
151246988Smckusick 	}
151341905Smckusick 	/*
151446450Skarels 	 * If the op is asynchronous and an i/o daemon is waiting
151538884Smacklem 	 * queue the request, wake it up and wait for completion
151646450Skarels 	 * otherwise just do it ourselves.
151738884Smacklem 	 */
151846988Smckusick 	if ((bp->b_flags & B_ASYNC) == 0 || nfs_numasync == 0)
151946988Smckusick 		return (nfs_doio(bp));
152046988Smckusick 	for (i = 0; i < NFS_MAXASYNCDAEMON; i++) {
152146988Smckusick 		if (nfs_iodwant[i]) {
152239341Smckusick 			dp = &nfs_bqueue;
152339341Smckusick 			if (dp->b_actf == NULL) {
152439341Smckusick 				dp->b_actl = bp;
152539341Smckusick 				bp->b_actf = dp;
152639341Smckusick 			} else {
152739341Smckusick 				dp->b_actf->b_actl = bp;
152839341Smckusick 				bp->b_actf = dp->b_actf;
152939341Smckusick 			}
153039341Smckusick 			dp->b_actf = bp;
153139341Smckusick 			bp->b_actl = dp;
153239341Smckusick 			fnd++;
153339341Smckusick 			wakeup((caddr_t)&nfs_iodwant[i]);
153439341Smckusick 			break;
153538884Smacklem 		}
153639341Smckusick 	}
153739341Smckusick 	if (!fnd)
153838884Smacklem 		error = nfs_doio(bp);
153938884Smacklem 	return (error);
154038884Smacklem }
154138884Smacklem 
154238884Smacklem /*
154338884Smacklem  * Fun and games with i/o
154438884Smacklem  * Essentially play ubasetup() and disk interrupt service routine by
154538884Smacklem  * mapping the data buffer into kernel virtual space and doing the
154638884Smacklem  * nfs read or write rpc's from it.
154741905Smckusick  * If the nfsiod's are not running, this is just called from nfs_strategy(),
154841905Smckusick  * otherwise it is called by the nfsiods to do what would normally be
154938884Smacklem  * partially disk interrupt driven.
155038884Smacklem  */
155138884Smacklem nfs_doio(bp)
155238884Smacklem 	register struct buf *bp;
155338884Smacklem {
155438414Smckusick 	register struct uio *uiop;
155538414Smckusick 	register struct vnode *vp;
155639341Smckusick 	struct nfsnode *np;
155738884Smacklem 	struct ucred *cr;
155841539Smckusick 	int error;
155941539Smckusick 	struct uio uio;
156041539Smckusick 	struct iovec io;
156138414Smckusick 
156238414Smckusick 	vp = bp->b_vp;
156340251Smckusick 	np = VTONFS(vp);
156438414Smckusick 	uiop = &uio;
156538414Smckusick 	uiop->uio_iov = &io;
156638414Smckusick 	uiop->uio_iovcnt = 1;
156738414Smckusick 	uiop->uio_segflg = UIO_SYSSPACE;
156848054Smckusick 	uiop->uio_procp = (struct proc *)0;
156939751Smckusick 
157038414Smckusick 	/*
157138884Smacklem 	 * For phys i/o, map the b_addr into kernel virtual space using
157238884Smacklem 	 * the Nfsiomap pte's
157338884Smacklem 	 * Also, add a temporary b_rcred for reading using the process's uid
157438884Smacklem 	 * and a guess at a group
157538414Smckusick 	 */
157638884Smacklem 	if (bp->b_flags & B_PHYS) {
157748054Smckusick 		if (bp->b_flags & B_DIRTY)
157848054Smckusick 			uiop->uio_procp = pageproc;
157948054Smckusick 		cr = crcopy(uiop->uio_procp->p_ucred);
158041539Smckusick 		/* mapping was already done by vmapbuf */
158141539Smckusick 		io.iov_base = bp->b_un.b_addr;
158239751Smckusick 
158338884Smacklem 		/*
158439751Smckusick 		 * And do the i/o rpc
158539751Smckusick 		 */
158639751Smckusick 		io.iov_len = uiop->uio_resid = bp->b_bcount;
158739823Smckusick 		uiop->uio_offset = bp->b_blkno * DEV_BSIZE;
158839751Smckusick 		if (bp->b_flags & B_READ) {
158939751Smckusick 			uiop->uio_rw = UIO_READ;
159039751Smckusick 			nfsstats.read_physios++;
159148054Smckusick 			bp->b_error = error = nfs_readrpc(vp, uiop, cr);
159245717Smckusick 			(void) vnode_pager_uncache(vp);
159339751Smckusick 		} else {
159439751Smckusick 			uiop->uio_rw = UIO_WRITE;
159539751Smckusick 			nfsstats.write_physios++;
159648054Smckusick 			bp->b_error = error = nfs_writerpc(vp, uiop, cr);
159739341Smckusick 		}
159839751Smckusick 
159939751Smckusick 		/*
160039751Smckusick 		 * Finally, release pte's used by physical i/o
160139751Smckusick 		 */
160238884Smacklem 		crfree(cr);
160339751Smckusick 	} else {
160439751Smckusick 		if (bp->b_flags & B_READ) {
160539751Smckusick 			io.iov_len = uiop->uio_resid = bp->b_bcount;
160639751Smckusick 			io.iov_base = bp->b_un.b_addr;
160739751Smckusick 			uiop->uio_rw = UIO_READ;
160841905Smckusick 			switch (vp->v_type) {
160941905Smckusick 			case VREG:
161041905Smckusick 				uiop->uio_offset = bp->b_blkno * DEV_BSIZE;
161141905Smckusick 				nfsstats.read_bios++;
161248054Smckusick 				error = nfs_readrpc(vp, uiop, bp->b_rcred);
161341905Smckusick 				break;
161441905Smckusick 			case VLNK:
161541905Smckusick 				uiop->uio_offset = 0;
161641905Smckusick 				nfsstats.readlink_bios++;
161748054Smckusick 				error = nfs_readlinkrpc(vp, uiop, bp->b_rcred);
161841905Smckusick 				break;
161941905Smckusick 			case VDIR:
162041905Smckusick 				uiop->uio_offset = bp->b_lblkno;
162141905Smckusick 				nfsstats.readdir_bios++;
162248054Smckusick 				error = nfs_readdirrpc(vp, uiop, bp->b_rcred);
162341905Smckusick 				/*
162441905Smckusick 				 * Save offset cookie in b_blkno.
162541905Smckusick 				 */
162641905Smckusick 				bp->b_blkno = uiop->uio_offset;
162741905Smckusick 				break;
162841905Smckusick 			};
162941905Smckusick 			bp->b_error = error;
163039751Smckusick 		} else {
163139751Smckusick 			io.iov_len = uiop->uio_resid = bp->b_dirtyend
163239751Smckusick 				- bp->b_dirtyoff;
163339823Smckusick 			uiop->uio_offset = (bp->b_blkno * DEV_BSIZE)
163439751Smckusick 				+ bp->b_dirtyoff;
163539751Smckusick 			io.iov_base = bp->b_un.b_addr + bp->b_dirtyoff;
163639751Smckusick 			uiop->uio_rw = UIO_WRITE;
163739751Smckusick 			nfsstats.write_bios++;
163841905Smckusick 			bp->b_error = error = nfs_writerpc(vp, uiop,
163948054Smckusick 				bp->b_wcred);
164039751Smckusick 			if (error) {
164139751Smckusick 				np->n_error = error;
164239751Smckusick 				np->n_flag |= NWRITEERR;
164339751Smckusick 			}
164439751Smckusick 			bp->b_dirtyoff = bp->b_dirtyend = 0;
164539751Smckusick 		}
164638884Smacklem 	}
164739751Smckusick 	if (error)
164839751Smckusick 		bp->b_flags |= B_ERROR;
164939751Smckusick 	bp->b_resid = uiop->uio_resid;
165038414Smckusick 	biodone(bp);
165138414Smckusick 	return (error);
165238414Smckusick }
165338884Smacklem 
165438884Smacklem /*
165548054Smckusick  * Mmap a file
165648054Smckusick  *
165748054Smckusick  * NB Currently unsupported.
165848054Smckusick  */
165948054Smckusick /* ARGSUSED */
166048054Smckusick nfs_mmap(vp, fflags, cred, p)
166148054Smckusick 	struct vnode *vp;
166248054Smckusick 	int fflags;
166348054Smckusick 	struct ucred *cred;
166448054Smckusick 	struct proc *p;
166548054Smckusick {
166648054Smckusick 
166748054Smckusick 	return (EINVAL);
166848054Smckusick }
166948054Smckusick 
167048054Smckusick /*
167138884Smacklem  * Flush all the blocks associated with a vnode.
167238884Smacklem  * 	Walk through the buffer pool and push any dirty pages
167338884Smacklem  *	associated with the vnode.
167438884Smacklem  */
167539488Smckusick /* ARGSUSED */
167648054Smckusick nfs_fsync(vp, fflags, cred, waitfor, p)
167738884Smacklem 	register struct vnode *vp;
167838884Smacklem 	int fflags;
167938884Smacklem 	struct ucred *cred;
168039587Smckusick 	int waitfor;
168148054Smckusick 	struct proc *p;
168238884Smacklem {
168338884Smacklem 	register struct nfsnode *np = VTONFS(vp);
168439751Smckusick 	int error = 0;
168538884Smacklem 
168638884Smacklem 	if (np->n_flag & NMODIFIED) {
168738884Smacklem 		np->n_flag &= ~NMODIFIED;
168839751Smckusick 		vflushbuf(vp, waitfor == MNT_WAIT ? B_SYNC : 0);
168938884Smacklem 	}
169039751Smckusick 	if (!error && (np->n_flag & NWRITEERR))
169139751Smckusick 		error = np->n_error;
169238884Smacklem 	return (error);
169338884Smacklem }
169439672Smckusick 
169539672Smckusick /*
169646201Smckusick  * NFS advisory byte-level locks.
169746201Smckusick  * Currently unsupported.
169846201Smckusick  */
169946201Smckusick nfs_advlock(vp, id, op, fl, flags)
170046201Smckusick 	struct vnode *vp;
170146201Smckusick 	caddr_t id;
170246201Smckusick 	int op;
170346201Smckusick 	struct flock *fl;
170446201Smckusick 	int flags;
170546201Smckusick {
170646201Smckusick 
170746201Smckusick 	return (EOPNOTSUPP);
170846201Smckusick }
170946201Smckusick 
171046201Smckusick /*
171139672Smckusick  * Print out the contents of an nfsnode.
171239672Smckusick  */
171339672Smckusick nfs_print(vp)
171439672Smckusick 	struct vnode *vp;
171539672Smckusick {
171639672Smckusick 	register struct nfsnode *np = VTONFS(vp);
171739672Smckusick 
171840294Smckusick 	printf("tag VT_NFS, fileid %d fsid 0x%x",
171940294Smckusick 		np->n_vattr.va_fileid, np->n_vattr.va_fsid);
172040294Smckusick #ifdef FIFO
172140294Smckusick 	if (vp->v_type == VFIFO)
172240294Smckusick 		fifo_printinfo(vp);
172340294Smckusick #endif /* FIFO */
172440294Smckusick 	printf("%s\n", (np->n_flag & NLOCKED) ? " (LOCKED)" : "");
172539914Smckusick 	if (np->n_lockholder == 0)
172639914Smckusick 		return;
172739914Smckusick 	printf("\towner pid %d", np->n_lockholder);
172839914Smckusick 	if (np->n_lockwaiter)
172939914Smckusick 		printf(" waiting pid %d", np->n_lockwaiter);
173039914Smckusick 	printf("\n");
173139672Smckusick }
173251573Smckusick 
173351573Smckusick /*
173451573Smckusick  * NFS directory offset lookup.
173551573Smckusick  * Currently unsupported.
173651573Smckusick  */
173751573Smckusick nfs_blkatoff(vp, offset, res, bpp)
173851573Smckusick 	struct vnode *vp;
173951573Smckusick 	off_t offset;
174051573Smckusick 	char **res;
174151573Smckusick 	struct buf **bpp;
174251573Smckusick {
174351573Smckusick 
174451573Smckusick 	return (EOPNOTSUPP);
174551573Smckusick }
174651573Smckusick 
174751573Smckusick /*
174851573Smckusick  * NFS flat namespace lookup.
174951573Smckusick  * Currently unsupported.
175051573Smckusick  */
175151573Smckusick nfs_vget(mp, ino, vpp)
175251573Smckusick 	struct mount *mp;
175351573Smckusick 	ino_t ino;
175451573Smckusick 	struct vnode **vpp;
175551573Smckusick {
175651573Smckusick 
175751573Smckusick 	return (EOPNOTSUPP);
175851573Smckusick }
175951573Smckusick 
176051573Smckusick /*
176151573Smckusick  * NFS flat namespace allocation.
176251573Smckusick  * Currently unsupported.
176351573Smckusick  */
176451573Smckusick nfs_valloc(pvp, mode, cred, vpp)
176551573Smckusick 	struct vnode *pvp;
176651573Smckusick 	int mode;
176751573Smckusick 	struct ucred *cred;
176851573Smckusick 	struct vnode **vpp;
176951573Smckusick {
177051573Smckusick 
177151573Smckusick 	return (EOPNOTSUPP);
177251573Smckusick }
177351573Smckusick 
177451573Smckusick /*
177551573Smckusick  * NFS flat namespace free.
177651573Smckusick  * Currently unsupported.
177751573Smckusick  */
177851573Smckusick void
177951573Smckusick nfs_vfree(pvp, ino, mode)
178051573Smckusick 	struct vnode *pvp;
178151573Smckusick 	ino_t ino;
178251573Smckusick 	int mode;
178351573Smckusick {
178451573Smckusick 
178551573Smckusick 	return;
178651573Smckusick }
178751573Smckusick 
178851573Smckusick /*
178951573Smckusick  * NFS file truncation.
179051573Smckusick  */
179151573Smckusick nfs_truncate(vp, length, flags)
179251573Smckusick 	struct vnode *vp;
179351573Smckusick 	u_long length;
179451573Smckusick 	int flags;
179551573Smckusick {
179651573Smckusick 
179751573Smckusick 	/* Use nfs_setattr */
179851573Smckusick 	printf("nfs_truncate: need to implement!!");
179951573Smckusick 	return (EOPNOTSUPP);
180051573Smckusick }
180151573Smckusick 
180251573Smckusick /*
180351573Smckusick  * NFS update.
180451573Smckusick  */
180551573Smckusick nfs_update(vp, ta, tm, waitfor)
180651573Smckusick 	struct vnode *vp;
180751573Smckusick 	struct timeval *ta;
180851573Smckusick 	struct timeval *tm;
180951573Smckusick 	int waitfor;
181051573Smckusick {
181151573Smckusick 
181251573Smckusick 	/* Use nfs_setattr */
181351573Smckusick 	printf("nfs_update: need to implement!!");
181451573Smckusick 	return (EOPNOTSUPP);
181551573Smckusick }
1816