xref: /csrg-svn/sys/nfs/nfs_vnops.c (revision 39441)
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  *
838414Smckusick  * Redistribution and use in source and binary forms are permitted
938414Smckusick  * provided that the above copyright notice and this paragraph are
1038414Smckusick  * duplicated in all such forms and that any documentation,
1138414Smckusick  * advertising materials, and other materials related to such
1238414Smckusick  * distribution and use acknowledge that the software was developed
1338414Smckusick  * by the University of California, Berkeley.  The name of the
1438414Smckusick  * University may not be used to endorse or promote products derived
1538414Smckusick  * from this software without specific prior written permission.
1638414Smckusick  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
1738414Smckusick  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
1838414Smckusick  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1938414Smckusick  *
20*39441Smckusick  *	@(#)nfs_vnops.c	7.10 (Berkeley) 10/29/89
2138414Smckusick  */
2238414Smckusick 
2338414Smckusick /*
2438414Smckusick  * vnode op calls for sun nfs version 2
2538414Smckusick  */
2638414Smckusick 
2738414Smckusick #include "machine/pte.h"
2838414Smckusick #include "machine/mtpr.h"
2938414Smckusick #include "strings.h"
3038414Smckusick #include "param.h"
3138414Smckusick #include "user.h"
3238414Smckusick #include "proc.h"
3338414Smckusick #include "mount.h"
3438414Smckusick #include "buf.h"
3538414Smckusick #include "vm.h"
3638425Smckusick #include "../ufs/dir.h"
3738414Smckusick #include "malloc.h"
3838414Smckusick #include "mbuf.h"
3938414Smckusick #include "uio.h"
4038414Smckusick #include "ucred.h"
4138414Smckusick #include "namei.h"
4238414Smckusick #include "errno.h"
4338414Smckusick #include "file.h"
4438414Smckusick #include "conf.h"
4538414Smckusick #include "vnode.h"
4638414Smckusick #include "../ufs/inode.h"
4738884Smacklem #include "map.h"
4838414Smckusick #include "nfsv2.h"
4938414Smckusick #include "nfs.h"
5038414Smckusick #include "nfsnode.h"
5138414Smckusick #include "nfsmount.h"
5238414Smckusick #include "xdr_subs.h"
5338414Smckusick #include "nfsm_subs.h"
5438884Smacklem #include "nfsiom.h"
5538414Smckusick 
5638414Smckusick /* Defs */
5738414Smckusick #define	TRUE	1
5838414Smckusick #define	FALSE	0
5938414Smckusick 
6038414Smckusick /* Global vars */
6138414Smckusick int	nfs_lookup(),
6238414Smckusick 	nfs_create(),
6338414Smckusick 	nfs_open(),
6438414Smckusick 	nfs_close(),
6538414Smckusick 	nfs_access(),
6638414Smckusick 	nfs_getattr(),
6738414Smckusick 	nfs_setattr(),
6838414Smckusick 	nfs_read(),
6938414Smckusick 	nfs_write(),
7038414Smckusick 	vfs_noop(),
7138414Smckusick 	vfs_nullop(),
7238414Smckusick 	nfs_remove(),
7338414Smckusick 	nfs_link(),
7438414Smckusick 	nfs_rename(),
7538414Smckusick 	nfs_mkdir(),
7638414Smckusick 	nfs_rmdir(),
7738414Smckusick 	nfs_symlink(),
7838414Smckusick 	nfs_readdir(),
7938414Smckusick 	nfs_readlink(),
8038414Smckusick 	nfs_abortop(),
8138414Smckusick 	nfs_lock(),
8238414Smckusick 	nfs_unlock(),
8338414Smckusick 	nfs_bmap(),
8438414Smckusick 	nfs_strategy(),
8538884Smacklem 	nfs_fsync(),
8639394Smckusick 	nfs_inactive(),
8739394Smckusick 	nfs_reclaim();
8838414Smckusick 
8938414Smckusick struct vnodeops nfsv2_vnodeops = {
9038414Smckusick 	nfs_lookup,
9138414Smckusick 	nfs_create,
9238414Smckusick 	vfs_noop,
9338414Smckusick 	nfs_open,
9438414Smckusick 	nfs_close,
9538414Smckusick 	nfs_access,
9638414Smckusick 	nfs_getattr,
9738414Smckusick 	nfs_setattr,
9838414Smckusick 	nfs_read,
9938414Smckusick 	nfs_write,
10038414Smckusick 	vfs_noop,
10138414Smckusick 	vfs_noop,
10238414Smckusick 	vfs_noop,
10338884Smacklem 	nfs_fsync,
10438414Smckusick 	vfs_noop,
10538414Smckusick 	nfs_remove,
10638414Smckusick 	nfs_link,
10738414Smckusick 	nfs_rename,
10838414Smckusick 	nfs_mkdir,
10938414Smckusick 	nfs_rmdir,
11038414Smckusick 	nfs_symlink,
11138414Smckusick 	nfs_readdir,
11238414Smckusick 	nfs_readlink,
11338414Smckusick 	nfs_abortop,
11438414Smckusick 	nfs_inactive,
11539394Smckusick 	nfs_reclaim,
11638414Smckusick 	nfs_lock,
11738414Smckusick 	nfs_unlock,
11838414Smckusick 	nfs_bmap,
11938414Smckusick 	nfs_strategy,
12038414Smckusick };
12138414Smckusick 
12238414Smckusick /* Special device vnode ops */
123*39441Smckusick int	spec_lookup(),
124*39441Smckusick 	spec_open(),
125*39441Smckusick 	spec_read(),
126*39441Smckusick 	spec_write(),
127*39441Smckusick 	spec_strategy(),
128*39441Smckusick 	spec_ioctl(),
129*39441Smckusick 	spec_select(),
130*39441Smckusick 	spec_close(),
131*39441Smckusick 	spec_badop(),
132*39441Smckusick 	spec_nullop();
13338414Smckusick 
134*39441Smckusick struct vnodeops spec_nfsv2nodeops = {
135*39441Smckusick 	spec_lookup,
136*39441Smckusick 	spec_badop,
137*39441Smckusick 	spec_badop,
138*39441Smckusick 	spec_open,
139*39441Smckusick 	spec_close,
14038414Smckusick 	nfs_access,
14138414Smckusick 	nfs_getattr,
14238414Smckusick 	nfs_setattr,
143*39441Smckusick 	spec_read,
144*39441Smckusick 	spec_write,
145*39441Smckusick 	spec_ioctl,
146*39441Smckusick 	spec_select,
147*39441Smckusick 	spec_badop,
148*39441Smckusick 	spec_nullop,
149*39441Smckusick 	spec_badop,
150*39441Smckusick 	spec_badop,
151*39441Smckusick 	spec_badop,
152*39441Smckusick 	spec_badop,
153*39441Smckusick 	spec_badop,
154*39441Smckusick 	spec_badop,
155*39441Smckusick 	spec_badop,
156*39441Smckusick 	spec_badop,
157*39441Smckusick 	spec_badop,
158*39441Smckusick 	spec_badop,
15938414Smckusick 	nfs_inactive,
16039394Smckusick 	nfs_reclaim,
16138414Smckusick 	nfs_lock,
16238414Smckusick 	nfs_unlock,
163*39441Smckusick 	spec_badop,
164*39441Smckusick 	spec_strategy,
16538414Smckusick };
16638414Smckusick 
16738414Smckusick extern u_long nfs_procids[NFS_NPROCS];
16838414Smckusick extern u_long nfs_prog, nfs_vers;
16938414Smckusick extern char nfsiobuf[MAXPHYS+NBPG];
17038884Smacklem struct map nfsmap[NFS_MSIZ];
17138414Smckusick enum vtype v_type[NFLNK+1];
17238884Smacklem struct buf nfs_bqueue;		/* Queue head for nfsiod's */
17339341Smckusick int nfs_asyncdaemons = 0;
17439341Smckusick struct proc *nfs_iodwant[MAX_ASYNCDAEMON];
17538884Smacklem static int nfsmap_want = 0;
17638414Smckusick 
17738414Smckusick /*
17838414Smckusick  * nfs null call from vfs.
17938414Smckusick  */
18038414Smckusick nfs_null(vp, cred)
18138414Smckusick 	struct vnode *vp;
18238414Smckusick 	struct ucred *cred;
18338414Smckusick {
18438414Smckusick 	nfsm_vars;
18538414Smckusick 
18638414Smckusick 	nfsm_reqhead(nfs_procids[NFSPROC_NULL], cred, 0);
18738414Smckusick 	nfsm_request(vp);
18838414Smckusick 	nfsm_reqdone;
18938414Smckusick 	return (error);
19038414Smckusick }
19138414Smckusick 
19238414Smckusick /*
19338414Smckusick  * nfs access vnode op.
19438414Smckusick  * Essentially just get vattr and then imitate iaccess()
19538414Smckusick  */
19638414Smckusick nfs_access(vp, mode, cred)
19738414Smckusick 	struct vnode *vp;
19838414Smckusick 	int mode;
19938414Smckusick 	register struct ucred *cred;
20038414Smckusick {
20138414Smckusick 	register struct vattr *vap;
20238414Smckusick 	register gid_t *gp;
20338414Smckusick 	struct vattr vattr;
20438414Smckusick 	register int i;
20538414Smckusick 	int error;
20638414Smckusick 
20738414Smckusick 	/*
20838414Smckusick 	 * If you're the super-user,
20938414Smckusick 	 * you always get access.
21038414Smckusick 	 */
21138414Smckusick 	if (cred->cr_uid == 0)
21238414Smckusick 		return (0);
21338414Smckusick 	vap = &vattr;
21438884Smacklem 	if (error = nfs_getattr(vp, vap, cred))
21538884Smacklem 		return (error);
21638414Smckusick 	/*
21738414Smckusick 	 * Access check is based on only one of owner, group, public.
21838414Smckusick 	 * If not owner, then check group. If not a member of the
21938414Smckusick 	 * group, then check public access.
22038414Smckusick 	 */
22138414Smckusick 	if (cred->cr_uid != vap->va_uid) {
22238414Smckusick 		mode >>= 3;
22338414Smckusick 		gp = cred->cr_groups;
22438414Smckusick 		for (i = 0; i < cred->cr_ngroups; i++, gp++)
22538414Smckusick 			if (vap->va_gid == *gp)
22638414Smckusick 				goto found;
22738414Smckusick 		mode >>= 3;
22838414Smckusick found:
22938414Smckusick 		;
23038414Smckusick 	}
23138414Smckusick 	if ((vap->va_mode & mode) != 0)
23238414Smckusick 		return (0);
23338414Smckusick 	return (EACCES);
23438414Smckusick }
23538414Smckusick 
23638414Smckusick /*
23738414Smckusick  * nfs open vnode op
23838414Smckusick  * Just check to see if the type is ok
23938414Smckusick  */
24038414Smckusick nfs_open(vp, mode, cred)
24138414Smckusick 	struct vnode *vp;
24238414Smckusick 	int mode;
24338414Smckusick 	struct ucred *cred;
24438414Smckusick {
24538414Smckusick 	register enum vtype vtyp;
24638414Smckusick 
24738414Smckusick 	vtyp = vp->v_type;
24838414Smckusick 	if (vtyp == VREG || vtyp == VDIR || vtyp == VLNK)
24938414Smckusick 		return (0);
25038414Smckusick 	else
25138414Smckusick 		return (EACCES);
25238414Smckusick }
25338414Smckusick 
25438414Smckusick /*
25538414Smckusick  * nfs close vnode op
25638884Smacklem  * For reg files, invalidate any buffer cache entries.
25738414Smckusick  */
25838414Smckusick nfs_close(vp, fflags, cred)
25938414Smckusick 	register struct vnode *vp;
26038414Smckusick 	int fflags;
26138414Smckusick 	struct ucred *cred;
26238414Smckusick {
26338884Smacklem 	struct nfsnode *np = VTONFS(vp);
26438414Smckusick 	dev_t dev;
26539341Smckusick 	int error = 0;
26638414Smckusick 
26739341Smckusick 	if (vp->v_type == VREG && ((np->n_flag & NMODIFIED) ||
26839341Smckusick 	   ((np->n_flag & NBUFFERED) && np->n_sillyrename))) {
269*39441Smckusick 		nfs_lock(vp);
27039341Smckusick 		np->n_flag &= ~(NMODIFIED|NBUFFERED);
27139341Smckusick 		error = nfs_blkflush(vp, (daddr_t)0, np->n_size, TRUE);
27239341Smckusick 		if (np->n_flag & NWRITEERR) {
27339341Smckusick 			np->n_flag &= ~NWRITEERR;
27439341Smckusick 			if (!error)
27539341Smckusick 				error = np->n_error ? np->n_error : EIO;
27639341Smckusick 		}
277*39441Smckusick 		nfs_unlock(vp);
27838884Smacklem 	}
27938414Smckusick 	return (error);
28038414Smckusick }
28138414Smckusick 
28238414Smckusick /*
28338414Smckusick  * nfs getattr call from vfs.
28438414Smckusick  */
28538414Smckusick nfs_getattr(vp, vap, cred)
28638414Smckusick 	struct vnode *vp;
28738414Smckusick 	register struct vattr *vap;
28838414Smckusick 	struct ucred *cred;
28938414Smckusick {
29038414Smckusick 	nfsm_vars;
29138414Smckusick 
29238414Smckusick 	/* First look in the cache.. */
29338414Smckusick 	if (nfs_getattrcache(vp, vap) == 0)
29438414Smckusick 		return (0);
29538414Smckusick 	nfsstats.rpccnt[NFSPROC_GETATTR]++;
29638414Smckusick 	nfsm_reqhead(nfs_procids[NFSPROC_GETATTR], cred, NFSX_FH);
29738414Smckusick 	nfsm_fhtom(vp);
29838414Smckusick 	nfsm_request(vp);
29938414Smckusick 	nfsm_loadattr(vp, vap);
30038414Smckusick 	nfsm_reqdone;
30138414Smckusick 	return (error);
30238414Smckusick }
30338414Smckusick 
30438414Smckusick /*
30538414Smckusick  * nfs setattr call.
30638414Smckusick  */
30738414Smckusick nfs_setattr(vp, vap, cred)
30838414Smckusick 	struct vnode *vp;
30938414Smckusick 	register struct vattr *vap;
31038414Smckusick 	struct ucred *cred;
31138414Smckusick {
31238884Smacklem 	register struct nfsv2_sattr *sp;
31338414Smckusick 	nfsm_vars;
31439359Smckusick 	struct nfsnode *np;
31538414Smckusick 
31638414Smckusick 	nfsstats.rpccnt[NFSPROC_SETATTR]++;
31738414Smckusick 	nfsm_reqhead(nfs_procids[NFSPROC_SETATTR], cred, NFSX_FH+NFSX_SATTR);
31838414Smckusick 	nfsm_fhtom(vp);
31938884Smacklem 	nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR);
32038414Smckusick 	if (vap->va_mode == 0xffff)
32138884Smacklem 		sp->sa_mode = VNOVAL;
32238414Smckusick 	else
32338884Smacklem 		sp->sa_mode = vtonfs_mode(vp->v_type, vap->va_mode);
32438414Smckusick 	if (vap->va_uid == 0xffff)
32538884Smacklem 		sp->sa_uid = VNOVAL;
32638414Smckusick 	else
32738884Smacklem 		sp->sa_uid = txdr_unsigned(vap->va_uid);
32838414Smckusick 	if (vap->va_gid == 0xffff)
32938884Smacklem 		sp->sa_gid = VNOVAL;
33038414Smckusick 	else
33138884Smacklem 		sp->sa_gid = txdr_unsigned(vap->va_gid);
33238884Smacklem 	sp->sa_size = txdr_unsigned(vap->va_size);
33339359Smckusick 	if (vap->va_size != VNOVAL) {
33439359Smckusick 		np = VTONFS(vp);
33539359Smckusick 		if (np->n_flag & NMODIFIED) {
33639359Smckusick 			np->n_flag &= ~NMODIFIED;
33739359Smckusick 			nfs_blkflush(vp, (daddr_t)0, np->n_size, TRUE);
33839359Smckusick 		}
33939359Smckusick 	}
34038884Smacklem 	txdr_time(&vap->va_atime, &sp->sa_atime);
34138884Smacklem 	txdr_time(&vap->va_mtime, &sp->sa_mtime);
34238414Smckusick 	nfsm_request(vp);
34338414Smckusick 	nfsm_loadattr(vp, (struct vattr *)0);
34438414Smckusick 	/* should we fill in any vap fields ?? */
34538414Smckusick 	nfsm_reqdone;
34638414Smckusick 	return (error);
34738414Smckusick }
34838414Smckusick 
34938414Smckusick /*
35038414Smckusick  * nfs lookup call, one step at a time...
35138414Smckusick  * First look in cache
35238414Smckusick  * If not found, unlock the directory nfsnode and do the rpc
35338414Smckusick  */
35438414Smckusick nfs_lookup(vp, ndp)
35538414Smckusick 	register struct vnode *vp;
35638414Smckusick 	register struct nameidata *ndp;
35738414Smckusick {
35838414Smckusick 	register struct vnode *vdp;
35938414Smckusick 	nfsm_vars;
36038414Smckusick 	struct vnode *newvp;
36138414Smckusick 	long len;
36238414Smckusick 	nfsv2fh_t *fhp;
36338414Smckusick 	struct nfsnode *np;
36438414Smckusick 	int lockparent, wantparent, flag;
36538414Smckusick 	dev_t rdev;
36638414Smckusick 
36738414Smckusick 	ndp->ni_dvp = vp;
36838414Smckusick 	ndp->ni_vp = NULL;
36938414Smckusick 	if (vp->v_type != VDIR)
37038414Smckusick 		return (ENOTDIR);
37138414Smckusick 	lockparent = ndp->ni_nameiop & LOCKPARENT;
37238414Smckusick 	flag = ndp->ni_nameiop & OPFLAG;
37338414Smckusick 	wantparent = ndp->ni_nameiop & (LOCKPARENT|WANTPARENT);
37439341Smckusick 	if ((error = cache_lookup(ndp)) && error != ENOENT) {
37538884Smacklem 		struct vattr vattr;
37638884Smacklem 		int vpid;
37738884Smacklem 
378*39441Smckusick 		if (vp == ndp->ni_rdir && ndp->ni_isdotdot)
379*39441Smckusick 			panic("nfs_lookup: .. through root");
380*39441Smckusick 		vdp = ndp->ni_vp;
38138884Smacklem 		vpid = vdp->v_id;
38238414Smckusick 		/*
38338884Smacklem 		 * See the comment starting `Step through' in ufs/ufs_lookup.c
38438884Smacklem 		 * for an explanation of the locking protocol
38538414Smckusick 		 */
38638414Smckusick 		if (vp == vdp) {
38738425Smckusick 			VREF(vdp);
388*39441Smckusick 			error = 0;
38938414Smckusick 		} else if (ndp->ni_isdotdot) {
39038414Smckusick 			nfs_unlock(vp);
391*39441Smckusick 			error = vget(vdp);
39238414Smckusick 		} else {
393*39441Smckusick 			error = vget(vdp);
39438414Smckusick 			nfs_unlock(vp);
39538414Smckusick 		}
396*39441Smckusick 		if (!error) {
397*39441Smckusick 			if (vpid == vdp->v_id &&
398*39441Smckusick 			   !nfs_getattr(vdp, &vattr, ndp->ni_cred)) {
399*39441Smckusick 				nfsstats.lookupcache_hits++;
400*39441Smckusick 				return (0);
401*39441Smckusick 			} else {
402*39441Smckusick 				nfs_nput(vdp);
403*39441Smckusick 			}
40438884Smacklem 		}
40538884Smacklem 		nfs_lock(vp);
40638884Smacklem 		ndp->ni_vp = (struct vnode *)0;
40738414Smckusick 	}
40839341Smckusick 	error = 0;
40938414Smckusick 	nfsstats.lookupcache_misses++;
41038414Smckusick 	nfsstats.rpccnt[NFSPROC_LOOKUP]++;
41138414Smckusick 	len = ndp->ni_namelen;
41238414Smckusick 	nfsm_reqhead(nfs_procids[NFSPROC_LOOKUP], ndp->ni_cred, NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len));
41338414Smckusick 	nfsm_fhtom(vp);
41438414Smckusick 	nfsm_strtom(ndp->ni_ptr, len, NFS_MAXNAMLEN);
41538414Smckusick 	nfsm_request(vp);
41638414Smckusick nfsmout:
41738414Smckusick 	if (error) {
41838414Smckusick 		if ((flag == CREATE || flag == RENAME) &&
41938414Smckusick 			*ndp->ni_next == 0) {
42038414Smckusick 			if (!lockparent)
42138414Smckusick 				nfs_unlock(vp);
42238414Smckusick 		}
42338414Smckusick 		return (ENOENT);
42438414Smckusick 	}
42538414Smckusick 	nfsm_disect(fhp,nfsv2fh_t *,NFSX_FH);
42638414Smckusick 
42738414Smckusick 	/*
42838414Smckusick 	 * Handle DELETE and RENAME cases...
42938414Smckusick 	 */
43038414Smckusick 	if (flag == DELETE && *ndp->ni_next == 0) {
43138414Smckusick 		if (!bcmp(VTONFS(vp)->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) {
43238425Smckusick 			VREF(vp);
43338414Smckusick 			newvp = vp;
43438414Smckusick 			np = VTONFS(vp);
43538414Smckusick 		} else {
43638414Smckusick 			if (error = nfs_nget(vp->v_mount, fhp, &np)) {
43738414Smckusick 				m_freem(mrep);
43838414Smckusick 				return (error);
43938414Smckusick 			}
44038414Smckusick 			newvp = NFSTOV(np);
44138414Smckusick 		}
44238414Smckusick 		if (error = nfs_loadattrcache(newvp, &md, &dpos, (struct vattr *)0)) {
44338414Smckusick 			if (newvp != vp)
44438414Smckusick 				nfs_nput(newvp);
44538414Smckusick 			else
44638425Smckusick 				vrele(vp);
44738414Smckusick 			m_freem(mrep);
44838414Smckusick 			return (error);
44938414Smckusick 		}
45038414Smckusick 		ndp->ni_vp = newvp;
45138414Smckusick 		if (!lockparent)
45238414Smckusick 			nfs_unlock(vp);
45338414Smckusick 		m_freem(mrep);
45438414Smckusick 		return (0);
45538414Smckusick 	}
45638414Smckusick 
45738414Smckusick 	if (flag == RENAME && wantparent && *ndp->ni_next == 0) {
45838414Smckusick 		if (!bcmp(VTONFS(vp)->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) {
45938414Smckusick 			m_freem(mrep);
46038414Smckusick 			return (EISDIR);
46138414Smckusick 		}
46238414Smckusick 		if (error = nfs_nget(vp->v_mount, fhp, &np)) {
46338414Smckusick 			m_freem(mrep);
46438414Smckusick 			return (error);
46538414Smckusick 		}
46638414Smckusick 		newvp = NFSTOV(np);
46738414Smckusick 		if (error = nfs_loadattrcache(newvp, &md, &dpos, (struct vattr *)0)) {
46838425Smckusick 			nfs_nput(newvp);
46938414Smckusick 			m_freem(mrep);
47038414Smckusick 			return (error);
47138414Smckusick 		}
47238414Smckusick 		ndp->ni_vp = newvp;
47338414Smckusick 		if (!lockparent)
47438414Smckusick 			nfs_unlock(vp);
47538414Smckusick 		return (0);
47638414Smckusick 	}
47738414Smckusick 
47838414Smckusick 	if (!bcmp(VTONFS(vp)->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) {
47938425Smckusick 		VREF(vp);
48038414Smckusick 		newvp = vp;
48138414Smckusick 		np = VTONFS(vp);
48238414Smckusick 	} else if (ndp->ni_isdotdot) {
48338414Smckusick 		nfs_unlock(vp);
48438414Smckusick 		if (error = nfs_nget(vp->v_mount, fhp, &np)) {
48538414Smckusick 			nfs_lock(vp);
48638414Smckusick 			m_freem(mrep);
48738414Smckusick 			return (error);
48838414Smckusick 		}
48938414Smckusick 		nfs_lock(vp);
49038414Smckusick 		newvp = NFSTOV(np);
49138414Smckusick 	} else {
49238414Smckusick 		if (error = nfs_nget(vp->v_mount, fhp, &np)) {
49338414Smckusick 			m_freem(mrep);
49438414Smckusick 			return (error);
49538414Smckusick 		}
49638414Smckusick 		newvp = NFSTOV(np);
49738414Smckusick 	}
49838414Smckusick 	if (error = nfs_loadattrcache(newvp, &md, &dpos, (struct vattr *)0)) {
49938414Smckusick 		if (newvp != vp)
50038414Smckusick 			nfs_nput(newvp);
50138414Smckusick 		else
50238425Smckusick 			vrele(vp);
50338414Smckusick 		m_freem(mrep);
50438414Smckusick 		return (error);
50538414Smckusick 	}
50638414Smckusick 	m_freem(mrep);
50738414Smckusick 
50838414Smckusick 	if (vp != newvp && (!lockparent || *ndp->ni_next != '\0'))
50938414Smckusick 		nfs_unlock(vp);
51038414Smckusick 	ndp->ni_vp = newvp;
51138414Smckusick 	if (error == 0 && ndp->ni_makeentry)
51238414Smckusick 		cache_enter(ndp);
51338414Smckusick 	return (error);
51438414Smckusick }
51538414Smckusick 
51638414Smckusick /*
51738414Smckusick  * nfs readlink call
51838414Smckusick  */
51938414Smckusick nfs_readlink(vp, uiop, cred)
52038414Smckusick 	struct vnode *vp;
52138414Smckusick 	struct uio *uiop;
52238414Smckusick 	struct ucred *cred;
52338414Smckusick {
52438414Smckusick 	nfsm_vars;
52538414Smckusick 	long len;
52638414Smckusick 
52738414Smckusick 	nfsstats.rpccnt[NFSPROC_READLINK]++;
52838414Smckusick 	nfsm_reqhead(nfs_procids[NFSPROC_READLINK], cred, NFSX_FH);
52938414Smckusick 	nfsm_fhtom(vp);
53038414Smckusick 	nfsm_request(vp);
53138414Smckusick 	nfsm_strsiz(len, NFS_MAXPATHLEN);
53238414Smckusick 	nfsm_mtouio(uiop, len);
53338414Smckusick 	nfsm_reqdone;
53438414Smckusick 	return (error);
53538414Smckusick }
53638414Smckusick 
53738414Smckusick /*
53838414Smckusick  * nfs read call
53938414Smckusick  */
54038884Smacklem nfs_readrpc(vp, uiop, offp, cred)
54138414Smckusick 	struct vnode *vp;
54238414Smckusick 	struct uio *uiop;
54338414Smckusick 	off_t *offp;
54438414Smckusick 	struct ucred *cred;
54538414Smckusick {
54638414Smckusick 	nfsm_vars;
54738414Smckusick 	struct nfsmount *nmp;
54838414Smckusick 	long len, retlen, tsiz;
54938414Smckusick 
55038414Smckusick 	nmp = vfs_to_nfs(vp->v_mount);
55138414Smckusick 	tsiz = uiop->uio_resid;
55238414Smckusick 	while (tsiz > 0) {
55338414Smckusick 		nfsstats.rpccnt[NFSPROC_READ]++;
55438414Smckusick 		len = (tsiz > nmp->nm_rsize) ? nmp->nm_rsize : tsiz;
55538414Smckusick 		nfsm_reqhead(nfs_procids[NFSPROC_READ], cred, NFSX_FH+NFSX_UNSIGNED*3);
55638414Smckusick 		nfsm_fhtom(vp);
55738414Smckusick 		nfsm_build(p, u_long *, NFSX_UNSIGNED*3);
55838414Smckusick 		*p++ = txdr_unsigned(*offp);
55938414Smckusick 		*p++ = txdr_unsigned(len);
56038414Smckusick 		*p = 0;
56138414Smckusick 		nfsm_request(vp);
56238414Smckusick 		nfsm_loadattr(vp, (struct vattr *)0);
56338414Smckusick 		nfsm_strsiz(retlen, nmp->nm_rsize);
56438414Smckusick 		nfsm_mtouio(uiop, retlen);
56538414Smckusick 		m_freem(mrep);
56638414Smckusick 		*offp += retlen;
56738414Smckusick 		if (retlen < len)
56838414Smckusick 			tsiz = 0;
56938414Smckusick 		else
57038414Smckusick 			tsiz -= len;
57138414Smckusick 	}
57238414Smckusick nfsmout:
57338414Smckusick 	return (error);
57438414Smckusick }
57538414Smckusick 
57638414Smckusick /*
57738414Smckusick  * nfs write call
57838414Smckusick  */
57938884Smacklem nfs_writerpc(vp, uiop, offp, cred)
58038414Smckusick 	struct vnode *vp;
58138414Smckusick 	struct uio *uiop;
58238414Smckusick 	off_t *offp;
58338414Smckusick 	struct ucred *cred;
58438414Smckusick {
58538414Smckusick 	nfsm_vars;
58638414Smckusick 	struct nfsmount *nmp;
58738414Smckusick 	long len, tsiz;
58838414Smckusick 
58938414Smckusick 	nmp = vfs_to_nfs(vp->v_mount);
59038414Smckusick 	tsiz = uiop->uio_resid;
59138414Smckusick 	while (tsiz > 0) {
59238414Smckusick 		nfsstats.rpccnt[NFSPROC_WRITE]++;
59338414Smckusick 		len = (tsiz > nmp->nm_wsize) ? nmp->nm_wsize : tsiz;
59438414Smckusick 		nfsm_reqhead(nfs_procids[NFSPROC_WRITE], cred,
59538414Smckusick 			NFSX_FH+NFSX_UNSIGNED*4);
59638414Smckusick 		nfsm_fhtom(vp);
59738414Smckusick 		nfsm_build(p, u_long *, NFSX_UNSIGNED*4);
59838414Smckusick 		*(p+1) = txdr_unsigned(*offp);
59938414Smckusick 		*(p+3) = txdr_unsigned(len);
60038414Smckusick 		nfsm_uiotom(uiop, len);
60138414Smckusick 		nfsm_request(vp);
60238414Smckusick 		nfsm_loadattr(vp, (struct vattr *)0);
60338414Smckusick 		m_freem(mrep);
60438414Smckusick 		tsiz -= len;
60538414Smckusick 		*offp += len;
60638414Smckusick 	}
60738414Smckusick nfsmout:
60838414Smckusick 	return (error);
60938414Smckusick }
61038414Smckusick 
61138414Smckusick /*
61238414Smckusick  * nfs file create call
61338414Smckusick  */
61438414Smckusick nfs_create(ndp, vap)
61538414Smckusick 	register struct nameidata *ndp;
61638414Smckusick 	register struct vattr *vap;
61738414Smckusick {
61838884Smacklem 	register struct nfsv2_sattr *sp;
61938414Smckusick 	nfsm_vars;
62038414Smckusick 
62138414Smckusick 	nfsstats.rpccnt[NFSPROC_CREATE]++;
62238414Smckusick 	nfsm_reqhead(nfs_procids[NFSPROC_CREATE], ndp->ni_cred,
62338414Smckusick 	  NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_dent.d_namlen)+NFSX_SATTR);
62438414Smckusick 	nfsm_fhtom(ndp->ni_dvp);
62538414Smckusick 	nfsm_strtom(ndp->ni_dent.d_name, ndp->ni_dent.d_namlen, NFS_MAXNAMLEN);
62638884Smacklem 	nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR);
62738884Smacklem 	sp->sa_mode = vtonfs_mode(VREG, vap->va_mode);
62838884Smacklem 	sp->sa_uid = txdr_unsigned(ndp->ni_cred->cr_uid);
62938884Smacklem 	sp->sa_gid = txdr_unsigned(ndp->ni_cred->cr_gid);
63038884Smacklem 	sp->sa_size = txdr_unsigned(0);
63138414Smckusick 	/* or should these be VNOVAL ?? */
63238884Smacklem 	txdr_time(&vap->va_atime, &sp->sa_atime);
63338884Smacklem 	txdr_time(&vap->va_mtime, &sp->sa_mtime);
63438414Smckusick 	nfsm_request(ndp->ni_dvp);
63538414Smckusick 	nfsm_mtofh(ndp->ni_dvp, ndp->ni_vp);
63638414Smckusick 	nfsm_reqdone;
63738414Smckusick 	nfs_nput(ndp->ni_dvp);
63838414Smckusick 	return (error);
63938414Smckusick }
64038414Smckusick 
64138414Smckusick /*
64238414Smckusick  * nfs file remove call
64339341Smckusick  * To try and make nfs semantics closer to vfs semantics, a file that has
64439341Smckusick  * other references to the vnode is renamed instead of removed and then
64539341Smckusick  * removed later on the last close.
64639341Smckusick  * Unfortunately you must flush the buffer cache and cmap to get rid of
64739341Smckusick  * all extraneous vnode references before you check the reference cnt.
64839341Smckusick  * 1 - If the file could have blocks in the buffer cache
64939341Smckusick  *	  flush them out and invalidate them
65039341Smckusick  *	  mpurge the vnode to flush out cmap references
65139341Smckusick  *	  (This is necessary to update the vnode ref cnt as well as sensible
65239341Smckusick  *	   for actual removes, to free up the buffers)
65339341Smckusick  * 2 - If v_count > 1
65439341Smckusick  *	  If a rename is not already in the works
65539341Smckusick  *	     call nfs_sillyrename() to set it up
65639341Smckusick  *     else
65739341Smckusick  *	  do the remove rpc
65838414Smckusick  */
65938414Smckusick nfs_remove(ndp)
66038414Smckusick 	register struct nameidata *ndp;
66138414Smckusick {
66239341Smckusick 	register struct vnode *vp = ndp->ni_vp;
66339341Smckusick 	register struct nfsnode *np = VTONFS(ndp->ni_vp);
66438414Smckusick 	nfsm_vars;
66538414Smckusick 
66639341Smckusick 	if (vp->v_type == VREG) {
66739341Smckusick 		if (np->n_flag & (NMODIFIED|NBUFFERED)) {
66839341Smckusick 			np->n_flag &= ~(NMODIFIED|NBUFFERED);
66939341Smckusick 			nfs_blkflush(vp, (daddr_t)0, np->n_size, TRUE);
67039341Smckusick 		}
67139341Smckusick 		if (np->n_flag & NPAGEDON)
67239341Smckusick 			mpurge(vp);	/* In case cmap entries still ref it */
67339341Smckusick 	}
67439341Smckusick 	if (vp->v_count > 1) {
67539341Smckusick 		if (!np->n_sillyrename)
67639341Smckusick 			error = nfs_sillyrename(ndp, REMOVE);
67739341Smckusick 	} else {
67838414Smckusick 		nfsstats.rpccnt[NFSPROC_REMOVE]++;
67938414Smckusick 		nfsm_reqhead(nfs_procids[NFSPROC_REMOVE], ndp->ni_cred,
68038414Smckusick 			NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_dent.d_namlen));
68138414Smckusick 		nfsm_fhtom(ndp->ni_dvp);
68238414Smckusick 		nfsm_strtom(ndp->ni_dent.d_name, ndp->ni_dent.d_namlen, NFS_MAXNAMLEN);
68338414Smckusick 		nfsm_request(ndp->ni_dvp);
68438414Smckusick 		nfsm_reqdone;
68538414Smckusick 	}
68638414Smckusick 	if (ndp->ni_dvp == ndp->ni_vp)
68738425Smckusick 		vrele(ndp->ni_vp);
68838414Smckusick 	else
68938425Smckusick 		nfs_nput(ndp->ni_vp);
69038425Smckusick 	nfs_nput(ndp->ni_dvp);
69138414Smckusick 	return (error);
69238414Smckusick }
69338414Smckusick 
69438414Smckusick /*
69538414Smckusick  * nfs file remove rpc called from nfs_inactive
69638414Smckusick  */
69738414Smckusick nfs_removeit(ndp)
69838414Smckusick 	register struct nameidata *ndp;
69938414Smckusick {
70038414Smckusick 	nfsm_vars;
70138414Smckusick 
70238414Smckusick 	nfsstats.rpccnt[NFSPROC_REMOVE]++;
70338414Smckusick 	nfsm_reqhead(nfs_procids[NFSPROC_REMOVE], ndp->ni_cred,
70438414Smckusick 		NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_dent.d_namlen));
70538414Smckusick 	nfsm_fhtom(ndp->ni_dvp);
70638414Smckusick 	nfsm_strtom(ndp->ni_dent.d_name, ndp->ni_dent.d_namlen, NFS_MAXNAMLEN);
70738414Smckusick 	nfsm_request(ndp->ni_dvp);
70838414Smckusick 	nfsm_reqdone;
70938414Smckusick 	return (error);
71038414Smckusick }
71138414Smckusick 
71238414Smckusick /*
71338414Smckusick  * nfs file rename call
71438414Smckusick  */
71538414Smckusick nfs_rename(sndp, tndp)
71638414Smckusick 	register struct nameidata *sndp, *tndp;
71738414Smckusick {
71838414Smckusick 	nfsm_vars;
71938414Smckusick 
72038414Smckusick 	nfsstats.rpccnt[NFSPROC_RENAME]++;
72138414Smckusick 	nfsm_reqhead(nfs_procids[NFSPROC_RENAME], tndp->ni_cred,
72238414Smckusick 		(NFSX_FH+NFSX_UNSIGNED)*2+nfsm_rndup(sndp->ni_dent.d_namlen)+
72338414Smckusick 		nfsm_rndup(tndp->ni_dent.d_namlen)); /* or sndp->ni_cred?*/
72438414Smckusick 	nfsm_fhtom(sndp->ni_dvp);
72538414Smckusick 	nfsm_strtom(sndp->ni_dent.d_name,sndp->ni_dent.d_namlen,NFS_MAXNAMLEN);
72638414Smckusick 	nfsm_fhtom(tndp->ni_dvp);
72738414Smckusick 	nfsm_strtom(tndp->ni_dent.d_name,tndp->ni_dent.d_namlen,NFS_MAXNAMLEN);
72838414Smckusick 	nfsm_request(sndp->ni_dvp);
72938414Smckusick 	nfsm_reqdone;
73038414Smckusick 	if (sndp->ni_vp->v_type == VDIR) {
73138414Smckusick 		if (tndp->ni_vp != NULL && tndp->ni_vp->v_type == VDIR)
73238414Smckusick 			cache_purge(tndp->ni_dvp);
73338414Smckusick 		cache_purge(sndp->ni_dvp);
73438414Smckusick 	}
73538414Smckusick 	nfs_abortop(sndp);
73638414Smckusick 	nfs_abortop(tndp);
73738414Smckusick 	return (error);
73838414Smckusick }
73938414Smckusick 
74038414Smckusick /*
74138414Smckusick  * nfs file rename rpc called from above
74238414Smckusick  */
74338414Smckusick nfs_renameit(sndp, tndp)
74438414Smckusick 	register struct nameidata *sndp, *tndp;
74538414Smckusick {
74638414Smckusick 	nfsm_vars;
74738414Smckusick 
74838414Smckusick 	nfsstats.rpccnt[NFSPROC_RENAME]++;
74938414Smckusick 	nfsm_reqhead(nfs_procids[NFSPROC_RENAME], tndp->ni_cred,
75038414Smckusick 		(NFSX_FH+NFSX_UNSIGNED)*2+nfsm_rndup(sndp->ni_dent.d_namlen)+
75138414Smckusick 		nfsm_rndup(tndp->ni_dent.d_namlen)); /* or sndp->ni_cred?*/
75238414Smckusick 	nfsm_fhtom(sndp->ni_dvp);
75338414Smckusick 	nfsm_strtom(sndp->ni_dent.d_name,sndp->ni_dent.d_namlen,NFS_MAXNAMLEN);
75438414Smckusick 	nfsm_fhtom(tndp->ni_dvp);
75538414Smckusick 	nfsm_strtom(tndp->ni_dent.d_name,tndp->ni_dent.d_namlen,NFS_MAXNAMLEN);
75638414Smckusick 	nfsm_request(sndp->ni_dvp);
75738414Smckusick 	nfsm_reqdone;
75838414Smckusick 	return (error);
75938414Smckusick }
76038414Smckusick 
76138414Smckusick /*
76238414Smckusick  * nfs hard link create call
76338414Smckusick  */
76438414Smckusick nfs_link(vp, ndp)
76538414Smckusick 	struct vnode *vp;
76638414Smckusick 	register struct nameidata *ndp;
76738414Smckusick {
76838414Smckusick 	nfsm_vars;
76938414Smckusick 
77038425Smckusick 	if (ndp->ni_dvp != vp)
77138425Smckusick 		nfs_lock(vp);
77238414Smckusick 	nfsstats.rpccnt[NFSPROC_LINK]++;
77338414Smckusick 	nfsm_reqhead(nfs_procids[NFSPROC_LINK], ndp->ni_cred,
77438414Smckusick 		NFSX_FH*2+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_dent.d_namlen));
77538414Smckusick 	nfsm_fhtom(vp);
77638414Smckusick 	nfsm_fhtom(ndp->ni_dvp);
77738414Smckusick 	nfsm_strtom(ndp->ni_dent.d_name, ndp->ni_dent.d_namlen, NFS_MAXNAMLEN);
77838414Smckusick 	nfsm_request(vp);
77938414Smckusick 	nfsm_reqdone;
78038425Smckusick 	if (ndp->ni_dvp != vp)
78138425Smckusick 		nfs_unlock(vp);
78238414Smckusick 	nfs_nput(ndp->ni_dvp);
78338414Smckusick 	return (error);
78438414Smckusick }
78538414Smckusick 
78638414Smckusick /*
78738414Smckusick  * nfs symbolic link create call
78838414Smckusick  */
78938414Smckusick nfs_symlink(ndp, vap, nm)
79038414Smckusick 	struct nameidata *ndp;
79138414Smckusick 	struct vattr *vap;
79238414Smckusick 	char *nm;		/* is this the path ?? */
79338414Smckusick {
79438884Smacklem 	register struct nfsv2_sattr *sp;
79538414Smckusick 	nfsm_vars;
79638414Smckusick 
79738414Smckusick 	nfsstats.rpccnt[NFSPROC_SYMLINK]++;
79838414Smckusick 	nfsm_reqhead(nfs_procids[NFSPROC_SYMLINK], ndp->ni_cred,
79938414Smckusick 	NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_dent.d_namlen)+NFSX_UNSIGNED);
80038414Smckusick 	nfsm_fhtom(ndp->ni_dvp);
80138414Smckusick 	nfsm_strtom(ndp->ni_dent.d_name, ndp->ni_dent.d_namlen, NFS_MAXNAMLEN);
80238414Smckusick 	nfsm_strtom(nm, strlen(nm), NFS_MAXPATHLEN);
80338884Smacklem 	nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR);
80438884Smacklem 	sp->sa_mode = vtonfs_mode(VLNK, vap->va_mode);
80538884Smacklem 	sp->sa_uid = txdr_unsigned(ndp->ni_cred->cr_uid);
80638884Smacklem 	sp->sa_gid = txdr_unsigned(ndp->ni_cred->cr_gid);
80738884Smacklem 	sp->sa_size = txdr_unsigned(VNOVAL);
80838884Smacklem 	txdr_time(&vap->va_atime, &sp->sa_atime);		/* or VNOVAL ?? */
80938884Smacklem 	txdr_time(&vap->va_mtime, &sp->sa_mtime);	/* or VNOVAL ?? */
81038414Smckusick 	nfsm_request(ndp->ni_dvp);
81138414Smckusick 	nfsm_reqdone;
81238414Smckusick 	nfs_nput(ndp->ni_dvp);
81338414Smckusick 	return (error);
81438414Smckusick }
81538414Smckusick 
81638414Smckusick /*
81738414Smckusick  * nfs make dir call
81838414Smckusick  */
81938414Smckusick nfs_mkdir(ndp, vap)
82038414Smckusick 	struct nameidata *ndp;
82138414Smckusick 	struct vattr *vap;
82238414Smckusick {
82338884Smacklem 	register struct nfsv2_sattr *sp;
82438414Smckusick 	nfsm_vars;
82538414Smckusick 
82638414Smckusick 	nfsstats.rpccnt[NFSPROC_MKDIR]++;
82738414Smckusick 	nfsm_reqhead(nfs_procids[NFSPROC_MKDIR], ndp->ni_cred,
82838414Smckusick 	  NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_dent.d_namlen)+NFSX_SATTR);
82938414Smckusick 	nfsm_fhtom(ndp->ni_dvp);
83038414Smckusick 	nfsm_strtom(ndp->ni_dent.d_name, ndp->ni_dent.d_namlen, NFS_MAXNAMLEN);
83138884Smacklem 	nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR);
83238884Smacklem 	sp->sa_mode = vtonfs_mode(VDIR, vap->va_mode);
83338884Smacklem 	sp->sa_uid = txdr_unsigned(ndp->ni_cred->cr_uid);
83438884Smacklem 	sp->sa_gid = txdr_unsigned(ndp->ni_cred->cr_gid);
83538884Smacklem 	sp->sa_size = txdr_unsigned(VNOVAL);
83638884Smacklem 	txdr_time(&vap->va_atime, &sp->sa_atime);		/* or VNOVAL ?? */
83738884Smacklem 	txdr_time(&vap->va_mtime, &sp->sa_mtime);	/* or VNOVAL ?? */
83838414Smckusick 	nfsm_request(ndp->ni_dvp);
83938414Smckusick 	nfsm_mtofh(ndp->ni_dvp, ndp->ni_vp);
84038414Smckusick 	nfsm_reqdone;
84138414Smckusick 	nfs_nput(ndp->ni_dvp);
84238414Smckusick 	return (error);
84338414Smckusick }
84438414Smckusick 
84538414Smckusick /*
84638414Smckusick  * nfs remove directory call
84738414Smckusick  */
84838414Smckusick nfs_rmdir(ndp)
84938414Smckusick 	register struct nameidata *ndp;
85038414Smckusick {
85138414Smckusick 	nfsm_vars;
85238414Smckusick 
85338414Smckusick 	if (ndp->ni_dvp == ndp->ni_vp) {
85438414Smckusick 		vrele(ndp->ni_dvp);
85538414Smckusick 		nfs_nput(ndp->ni_dvp);
85638414Smckusick 		return (EINVAL);
85738414Smckusick 	}
85838414Smckusick 	nfsstats.rpccnt[NFSPROC_RMDIR]++;
85938414Smckusick 	nfsm_reqhead(nfs_procids[NFSPROC_RMDIR], ndp->ni_cred,
86038414Smckusick 		NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_dent.d_namlen));
86138414Smckusick 	nfsm_fhtom(ndp->ni_dvp);
86238414Smckusick 	nfsm_strtom(ndp->ni_dent.d_name, ndp->ni_dent.d_namlen, NFS_MAXNAMLEN);
86338414Smckusick 	nfsm_request(ndp->ni_dvp);
86438414Smckusick 	nfsm_reqdone;
86538884Smacklem 	cache_purge(ndp->ni_dvp);
86638884Smacklem 	cache_purge(ndp->ni_vp);
86738884Smacklem 	nfs_nput(ndp->ni_vp);
86838884Smacklem 	nfs_nput(ndp->ni_dvp);
86938414Smckusick 	return (error);
87038414Smckusick }
87138414Smckusick 
87238414Smckusick /*
87338414Smckusick  * nfs readdir call
87438414Smckusick  * Although cookie is defined as opaque, I translate it to/from net byte
87538414Smckusick  * order so that it looks more sensible. This appears consistent with the
87638414Smckusick  * Ultrix implementation of NFS.
87738414Smckusick  */
87838414Smckusick nfs_readdir(vp, uiop, offp, cred)
87938414Smckusick 	struct vnode *vp;
88038414Smckusick 	struct uio *uiop;
88138414Smckusick 	off_t *offp;
88238414Smckusick 	struct ucred *cred;
88338414Smckusick {
88438414Smckusick 	register long len;
88538414Smckusick 	register struct direct *dp;
88638414Smckusick 	nfsm_vars;
88738414Smckusick 	struct mbuf *md2;
88838414Smckusick 	caddr_t dpos2;
88938414Smckusick 	int siz;
89038414Smckusick 	int more_dirs, eofflg;
89138414Smckusick 	off_t off, savoff;
89238414Smckusick 	struct direct *savdp;
89338414Smckusick 
89438414Smckusick 	nfs_lock(vp);
89538414Smckusick 	nfsstats.rpccnt[NFSPROC_READDIR]++;
89638414Smckusick 	nfsm_reqhead(nfs_procids[NFSPROC_READDIR], cred, xid);
89738414Smckusick 	nfsm_fhtom(vp);
89838414Smckusick 	nfsm_build(p, u_long *, 2*NFSX_UNSIGNED);
89938414Smckusick 	off = *offp;
90038414Smckusick 	*p++ = txdr_unsigned(off);
90138414Smckusick 	*p = txdr_unsigned(uiop->uio_resid);
90238414Smckusick 	nfsm_request(vp);
90338414Smckusick 	siz = 0;
90438414Smckusick 	nfsm_disect(p, u_long *, NFSX_UNSIGNED);
90538414Smckusick 	more_dirs = fxdr_unsigned(int, *p);
90638414Smckusick 
90738414Smckusick 	/* Save the position so that we can do nfsm_mtouio() later */
90838414Smckusick 	dpos2 = dpos;
90938414Smckusick 	md2 = md;
91038414Smckusick 
91138414Smckusick 	/* loop thru the dir entries, doctoring them to 4bsd form */
91238414Smckusick 	while (more_dirs && siz < uiop->uio_resid) {
91338414Smckusick 		savoff = off;		/* Hold onto offset and dp */
91438414Smckusick 		savdp = dp;
91538414Smckusick 		nfsm_disecton(p, u_long *, 2*NFSX_UNSIGNED);
91638414Smckusick 		dp = (struct direct *)p;
91738414Smckusick 		dp->d_ino = fxdr_unsigned(u_long, *p++);
91838414Smckusick 		len = fxdr_unsigned(int, *p);
91938414Smckusick 		if (len <= 0 || len > NFS_MAXNAMLEN) {
92038414Smckusick 			error = EBADRPC;
92138414Smckusick 			m_freem(mrep);
92238414Smckusick 			goto nfsmout;
92338414Smckusick 		}
92438414Smckusick 		dp->d_namlen = (u_short)len;
92538414Smckusick 		len = nfsm_rndup(len);
92638414Smckusick 		nfsm_adv(len);
92738414Smckusick 		nfsm_disecton(p, u_long *, 2*NFSX_UNSIGNED);
92838414Smckusick 		off = fxdr_unsigned(off_t, *p);
92938414Smckusick 		*p++ = 0;		/* Ensures null termination of name */
93038414Smckusick 		more_dirs = fxdr_unsigned(int, *p);
93138414Smckusick 		dp->d_reclen = len+4*NFSX_UNSIGNED;
93238414Smckusick 		siz += dp->d_reclen;
93338414Smckusick 	}
93438414Smckusick 	/*
93538414Smckusick 	 * If at end of rpc data, get the eof boolean
93638414Smckusick 	 */
93738414Smckusick 	if (!more_dirs) {
93838414Smckusick 		nfsm_disecton(p, u_long *, NFSX_UNSIGNED);
93938414Smckusick 		eofflg = fxdr_unsigned(long, *p);
94038414Smckusick 	}
94138414Smckusick 	/*
94238414Smckusick 	 * If there is too much to fit in the data buffer, use savoff and
94338414Smckusick 	 * savdp to trim off the last record.
94438414Smckusick 	 * --> we are not at eof
94538414Smckusick 	 */
94638414Smckusick 	if (siz > uiop->uio_resid) {
94738414Smckusick 		eofflg = FALSE;
94838414Smckusick 		off = savoff;
94938414Smckusick 		siz -= dp->d_reclen;
95038414Smckusick 		dp = savdp;
95138414Smckusick 	}
95238414Smckusick 	if (siz > 0) {
95338414Smckusick #ifdef notdef
95438414Smckusick 		if (!eofflg)
95538414Smckusick 			dp->d_reclen += (uiop->uio_resid-siz);
95638414Smckusick #endif
95738414Smckusick 		md = md2;
95838414Smckusick 		dpos = dpos2;
95938414Smckusick 		nfsm_mtouio(uiop, siz);
96038414Smckusick #ifdef notdef
96138414Smckusick 		if (!eofflg)
96238414Smckusick 			uiop->uio_resid = 0;
96338414Smckusick #endif
96438414Smckusick 		*offp = off;
96538414Smckusick 	}
96638414Smckusick 	nfsm_reqdone;
96738414Smckusick 	nfs_unlock(vp);
96838414Smckusick 	return (error);
96938414Smckusick }
97038414Smckusick 
97138414Smckusick /*
97238414Smckusick  * nfs statfs call
97338414Smckusick  * (Actually a vfsop, not a vnode op)
97438414Smckusick  */
97538414Smckusick nfs_statfs(mp, sbp)
97638414Smckusick 	struct mount *mp;
97738414Smckusick 	register struct statfs *sbp;
97838414Smckusick {
97938884Smacklem 	register struct nfsv2_statfs *sfp;
98038414Smckusick 	nfsm_vars;
98138884Smacklem 	struct nfsmount *nmp;
98238414Smckusick 	struct ucred *cred;
98338414Smckusick 	struct nfsnode *np;
98438414Smckusick 	struct vnode *vp;
98538414Smckusick 
98638414Smckusick 	nmp = vfs_to_nfs(mp);
98738414Smckusick 	if (error = nfs_nget(mp, &nmp->nm_fh, &np))
98838414Smckusick 		return (error);
98938414Smckusick 	vp = NFSTOV(np);
99038414Smckusick 	nfsstats.rpccnt[NFSPROC_STATFS]++;
99138414Smckusick 	cred = crget();
99238414Smckusick 	cred->cr_ngroups = 1;
99338414Smckusick 	nfsm_reqhead(nfs_procids[NFSPROC_STATFS], cred, NFSX_FH);
99438414Smckusick 	nfsm_fhtom(vp);
99538414Smckusick 	nfsm_request(vp);
99638884Smacklem 	nfsm_disect(sfp, struct nfsv2_statfs *, NFSX_STATFS);
99738414Smckusick 	sbp->f_type = MOUNT_NFS;
99838414Smckusick 	sbp->f_flags = nmp->nm_flag;
99938884Smacklem 	sbp->f_bsize = fxdr_unsigned(long, sfp->sf_tsize);
100038884Smacklem 	sbp->f_fsize = fxdr_unsigned(long, sfp->sf_bsize);
100138884Smacklem 	sbp->f_blocks = fxdr_unsigned(long, sfp->sf_blocks);
100238884Smacklem 	sbp->f_bfree = fxdr_unsigned(long, sfp->sf_bfree);
100338884Smacklem 	sbp->f_bavail = fxdr_unsigned(long, sfp->sf_bavail);
100438739Smckusick 	sbp->f_files = 0;
100538739Smckusick 	sbp->f_ffree = 0;
100638414Smckusick 	sbp->f_fsid.val[0] = mp->m_fsid.val[0];
100738414Smckusick 	sbp->f_fsid.val[1] = mp->m_fsid.val[1];
100838414Smckusick 	bcopy(nmp->nm_path, sbp->f_mntonname, MNAMELEN);
100938414Smckusick 	bcopy(nmp->nm_host, sbp->f_mntfromname, MNAMELEN);
101038414Smckusick 	nfsm_reqdone;
101138414Smckusick 	nfs_nput(vp);
101238414Smckusick 	crfree(cred);
101338414Smckusick 	return (error);
101438414Smckusick }
101538414Smckusick 
101638414Smckusick #define	HEXTOASC(x)	"0123456789abcdef"[x]
101738414Smckusick 
101838414Smckusick /*
101938414Smckusick  * Silly rename. To make the NFS filesystem that is stateless look a little
102038414Smckusick  * more like the "ufs" a remove of an active vnode is translated to a rename
102138414Smckusick  * to a funny looking filename that is removed by nfs_inactive on the
102238414Smckusick  * nfsnode. There is the potential for another process on a different client
102338414Smckusick  * to create the same funny name between the nfs_lookitup() fails and the
102438414Smckusick  * nfs_rename() completes, but...
102538414Smckusick  */
102638414Smckusick nfs_sillyrename(ndp, flag)
102738414Smckusick 	struct nameidata *ndp;
102838414Smckusick 	int flag;
102938414Smckusick {
103038414Smckusick 	register struct nfsnode *np;
103138414Smckusick 	register struct sillyrename *sp;
103238414Smckusick 	register struct nameidata *tndp;
103338414Smckusick 	int error;
103438414Smckusick 	short pid;
103538414Smckusick 
103638414Smckusick 	np = VTONFS(ndp->ni_dvp);
103739341Smckusick 	cache_purge(ndp->ni_dvp);
103838414Smckusick 	MALLOC(sp, struct sillyrename *, sizeof (struct sillyrename),
103938884Smacklem 		M_TEMP, M_WAITOK);
104038414Smckusick 	sp->s_flag = flag;
104138414Smckusick 	bcopy((caddr_t)&np->n_fh, (caddr_t)&sp->s_fh, NFSX_FH);
104238414Smckusick 	np = VTONFS(ndp->ni_vp);
104338414Smckusick 	tndp = &sp->s_namei;
104438414Smckusick 	tndp->ni_cred = crdup(ndp->ni_cred);
104538414Smckusick 
104638414Smckusick 	/* Fudge together a funny name */
104738414Smckusick 	pid = u.u_procp->p_pid;
104838414Smckusick 	bcopy(".nfsAxxxx4.4", tndp->ni_dent.d_name, 13);
104938414Smckusick 	tndp->ni_dent.d_namlen = 12;
105038414Smckusick 	tndp->ni_dent.d_name[8] = HEXTOASC(pid & 0xf);
105138414Smckusick 	tndp->ni_dent.d_name[7] = HEXTOASC((pid >> 4) & 0xf);
105238414Smckusick 	tndp->ni_dent.d_name[6] = HEXTOASC((pid >> 8) & 0xf);
105338414Smckusick 	tndp->ni_dent.d_name[5] = HEXTOASC((pid >> 12) & 0xf);
105438414Smckusick 
105538414Smckusick 	/* Try lookitups until we get one that isn't there */
105638414Smckusick 	while (nfs_lookitup(ndp->ni_dvp, tndp, (nfsv2fh_t *)0) == 0) {
105738414Smckusick 		tndp->ni_dent.d_name[4]++;
105838414Smckusick 		if (tndp->ni_dent.d_name[4] > 'z') {
105938414Smckusick 			error = EINVAL;
106038414Smckusick 			goto bad;
106138414Smckusick 		}
106238414Smckusick 	}
106338414Smckusick 	if (error = nfs_renameit(ndp, tndp))
106438414Smckusick 		goto bad;
106538414Smckusick 	nfs_lookitup(ndp->ni_dvp, tndp, &np->n_fh);
106638414Smckusick 	np->n_sillyrename = sp;
106738414Smckusick 	return (0);
106838414Smckusick bad:
106938884Smacklem 	crfree(tndp->ni_cred);
107038414Smckusick 	free((caddr_t)sp, M_TEMP);
107138414Smckusick 	return (error);
107238414Smckusick }
107338414Smckusick 
107438414Smckusick /*
107538414Smckusick  * Look up a file name for silly rename stuff.
107638414Smckusick  * Just like nfs_lookup() except that it doesn't load returned values
107738414Smckusick  * into the nfsnode table.
107838414Smckusick  * If fhp != NULL it copies the returned file handle out
107938414Smckusick  */
108038414Smckusick nfs_lookitup(vp, ndp, fhp)
108138414Smckusick 	register struct vnode *vp;
108238414Smckusick 	register struct nameidata *ndp;
108338414Smckusick 	nfsv2fh_t *fhp;
108438414Smckusick {
108538414Smckusick 	nfsm_vars;
108638414Smckusick 	long len;
108738414Smckusick 
108838414Smckusick 	nfsstats.rpccnt[NFSPROC_LOOKUP]++;
108938414Smckusick 	ndp->ni_dvp = vp;
109038414Smckusick 	ndp->ni_vp = NULL;
109138414Smckusick 	len = ndp->ni_dent.d_namlen;
109238414Smckusick 	nfsm_reqhead(nfs_procids[NFSPROC_LOOKUP], ndp->ni_cred, NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len));
109338414Smckusick 	nfsm_fhtom(vp);
109438414Smckusick 	nfsm_strtom(ndp->ni_dent.d_name, len, NFS_MAXNAMLEN);
109538414Smckusick 	nfsm_request(vp);
109638414Smckusick 	if (fhp != NULL) {
109738414Smckusick 		nfsm_disect(cp, caddr_t, NFSX_FH);
109838414Smckusick 		bcopy(cp, (caddr_t)fhp, NFSX_FH);
109938414Smckusick 	}
110038414Smckusick 	nfsm_reqdone;
110138414Smckusick 	return (error);
110238414Smckusick }
110338414Smckusick 
110438414Smckusick /*
110538414Smckusick  * Kludge City..
110638414Smckusick  * - make nfs_bmap() essentially a no-op that does no translation
110738414Smckusick  * - do nfs_strategy() by faking physical I/O with nfs_readit/nfs_writeit
110838414Smckusick  *   after mapping the physical addresses into Kernel Virtual space in the
110938414Smckusick  *   nfsiobuf area.
111038414Smckusick  *   (Maybe I could use the process's page mapping, but I was concerned that
111138414Smckusick  *    Kernel Write might not be enabled and also figured copyout() would do
111238414Smckusick  *    a lot more work than bcopy() and also it currently happens in the
111338414Smckusick  *    context of the swapper process (2).
111438414Smckusick  */
111538414Smckusick nfs_bmap(vp, bn, vpp, bnp)
111638414Smckusick 	struct vnode *vp;
111738414Smckusick 	daddr_t bn;
111838414Smckusick 	struct vnode **vpp;
111938414Smckusick 	daddr_t *bnp;
112038414Smckusick {
112138414Smckusick 	if (vpp != NULL)
112238414Smckusick 		*vpp = vp;
112338414Smckusick 	if (bnp != NULL)
112438414Smckusick 		*bnp = bn * btodb(vp->v_mount->m_bsize);
112538414Smckusick 	return (0);
112638414Smckusick }
112738414Smckusick 
112838414Smckusick /*
112938884Smacklem  * Strategy routine for phys. i/o
113038884Smacklem  * If the biod's are running, queue a request
113138884Smacklem  * otherwise just call nfs_doio() to get it done
113238414Smckusick  */
113338414Smckusick nfs_strategy(bp)
113438414Smckusick 	register struct buf *bp;
113538414Smckusick {
113638884Smacklem 	register struct buf *dp;
113739341Smckusick 	register int i;
113838884Smacklem 	struct proc *rp;
113938884Smacklem 	int error = 0;
114039341Smckusick 	int fnd = 0;
114138884Smacklem 
114238884Smacklem 	/*
114338884Smacklem 	 * If an i/o daemon is waiting
114438884Smacklem 	 * queue the request, wake it up and wait for completion
114538884Smacklem 	 * otherwise just do it ourselves
114638884Smacklem 	 */
114739341Smckusick 	for (i = 0; i < nfs_asyncdaemons; i++) {
114839341Smckusick 		if (rp = nfs_iodwant[i]) {
114939341Smckusick 			/*
115039341Smckusick 			 * Ensure that the async_daemon is still waiting here
115139341Smckusick 			 */
115239341Smckusick 			if (rp->p_stat != SSLEEP ||
115339341Smckusick 			    rp->p_wchan != ((caddr_t)&nfs_iodwant[i])) {
115439341Smckusick 				nfs_iodwant[i] = (struct proc *)0;
115539341Smckusick 				continue;
115639341Smckusick 			}
115739341Smckusick 			dp = &nfs_bqueue;
115839341Smckusick 			if (dp->b_actf == NULL) {
115939341Smckusick 				dp->b_actl = bp;
116039341Smckusick 				bp->b_actf = dp;
116139341Smckusick 			} else {
116239341Smckusick 				dp->b_actf->b_actl = bp;
116339341Smckusick 				bp->b_actf = dp->b_actf;
116439341Smckusick 			}
116539341Smckusick 			dp->b_actf = bp;
116639341Smckusick 			bp->b_actl = dp;
116739341Smckusick 			fnd++;
116839341Smckusick 			nfs_iodwant[i] = (struct proc *)0;
116939341Smckusick 			wakeup((caddr_t)&nfs_iodwant[i]);
117039341Smckusick 			break;
117138884Smacklem 		}
117239341Smckusick 	}
117339341Smckusick 	if (!fnd)
117438884Smacklem 		error = nfs_doio(bp);
117538884Smacklem 	return (error);
117638884Smacklem }
117738884Smacklem 
117838884Smacklem /*
117938884Smacklem  * Fun and games with i/o
118038884Smacklem  * Essentially play ubasetup() and disk interrupt service routine by
118138884Smacklem  * mapping the data buffer into kernel virtual space and doing the
118238884Smacklem  * nfs read or write rpc's from it.
118338884Smacklem  * If the biod's are not running, this is just called from nfs_strategy(),
118438884Smacklem  * otherwise it is called by the biod's to do what would normally be
118538884Smacklem  * partially disk interrupt driven.
118638884Smacklem  */
118738884Smacklem nfs_doio(bp)
118838884Smacklem 	register struct buf *bp;
118938884Smacklem {
119038414Smckusick 	register struct pte *pte, *ppte;
119138414Smckusick 	register caddr_t vaddr;
119238414Smckusick 	register struct uio *uiop;
119338414Smckusick 	register struct vnode *vp;
119439341Smckusick 	struct nfsnode *np;
119538884Smacklem 	struct ucred *cr;
119638884Smacklem 	int npf, npf2;
119738884Smacklem 	int reg;
119838884Smacklem 	caddr_t vbase;
119938884Smacklem 	caddr_t addr;
120038414Smckusick 	unsigned v;
120138414Smckusick 	struct proc *rp;
120238414Smckusick 	int o, error;
120338884Smacklem 	int bcnt;
120438414Smckusick 	off_t off;
120538414Smckusick 	struct uio uio;
120638414Smckusick 	struct iovec io;
120738414Smckusick 
120838414Smckusick 	vp = bp->b_vp;
120938414Smckusick 	uiop = &uio;
121038414Smckusick 	uiop->uio_iov = &io;
121138414Smckusick 	uiop->uio_iovcnt = 1;
121238414Smckusick 	uiop->uio_segflg = UIO_SYSSPACE;
121338884Smacklem 	if (bp->b_flags & B_READ) {
121438884Smacklem 		io.iov_len = uiop->uio_resid = bp->b_bcount;
121538884Smacklem 		uiop->uio_offset = off = bp->b_blkno*DEV_BSIZE;
121638884Smacklem 		addr = bp->b_un.b_addr;
121738884Smacklem 		bcnt = bp->b_bcount;
121838884Smacklem 	} else {
121938884Smacklem 		io.iov_len = uiop->uio_resid = bp->b_dirtyend-bp->b_dirtyoff;
122038884Smacklem 		uiop->uio_offset = off = (bp->b_blkno*DEV_BSIZE)+bp->b_dirtyoff;
122138884Smacklem 		addr = bp->b_un.b_addr+bp->b_dirtyoff;
122238884Smacklem 		bcnt = bp->b_dirtyend-bp->b_dirtyoff;
122338414Smckusick 	}
122438414Smckusick 	/*
122538884Smacklem 	 * For phys i/o, map the b_addr into kernel virtual space using
122638884Smacklem 	 * the Nfsiomap pte's
122738884Smacklem 	 * Also, add a temporary b_rcred for reading using the process's uid
122838884Smacklem 	 * and a guess at a group
122938414Smckusick 	 */
123038884Smacklem 	if (bp->b_flags & B_PHYS) {
123139341Smckusick 		VTONFS(vp)->n_flag |= NPAGEDON;
123238884Smacklem 		bp->b_rcred = cr = crget();
123338884Smacklem 		rp = (bp->b_flags & B_DIRTY) ? &proc[2] : bp->b_proc;
123438884Smacklem 		cr->cr_uid = rp->p_uid;
123538884Smacklem 		cr->cr_gid = 0;		/* Anything ?? */
123638884Smacklem 		cr->cr_ngroups = 1;
123738884Smacklem 		o = (int)addr & PGOFSET;
123838884Smacklem 		npf2 = npf = btoc(bcnt + o);
123938884Smacklem 		/*
124038884Smacklem 		 * Get some mapping page table entries
124138884Smacklem 		 */
124238884Smacklem 		while ((reg = rmalloc(nfsmap, (long)npf)) == 0) {
124338884Smacklem 			nfsmap_want++;
124438884Smacklem 			sleep((caddr_t)&nfsmap_want, PZERO-1);
124538884Smacklem 		}
124638884Smacklem 		reg--;
124738884Smacklem 		/* I know it is always the else, but that may change someday */
124838884Smacklem 		if ((bp->b_flags & B_PHYS) == 0)
124938884Smacklem 			pte = kvtopte(bp->b_un.b_addr);
125038884Smacklem 		else if (bp->b_flags & B_PAGET)
125138884Smacklem 			pte = &Usrptmap[btokmx((struct pte *)bp->b_un.b_addr)];
125238884Smacklem 		else {
125338884Smacklem 			v = btop(bp->b_un.b_addr);
125438884Smacklem 			if (bp->b_flags & B_UAREA)
125538884Smacklem 				pte = &rp->p_addr[v];
125638884Smacklem 			else
125738884Smacklem 				pte = vtopte(rp, v);
125838884Smacklem 		}
125938884Smacklem 		/*
126038884Smacklem 		 * Play vmaccess() but with the Nfsiomap page table
126138884Smacklem 		 */
126238884Smacklem 		ppte = &Nfsiomap[reg];
126338884Smacklem 		vbase = vaddr = &nfsiobuf[reg*NBPG];
126438884Smacklem 		while (npf != 0) {
126538884Smacklem 			mapin(ppte, (u_int)vaddr, pte->pg_pfnum, (int)(PG_V|PG_KW));
126638414Smckusick #if defined(tahoe)
126738884Smacklem 			mtpr(P1DC, vaddr);
126838414Smckusick #endif
126938884Smacklem 			ppte++;
127038884Smacklem 			pte++;
127138884Smacklem 			vaddr += NBPG;
127238884Smacklem 			--npf;
127338884Smacklem 		}
127438884Smacklem 		io.iov_base = vbase+o;
127538884Smacklem 	} else {
127638884Smacklem 		io.iov_base = addr;
127738414Smckusick 	}
127838414Smckusick 	if (bp->b_flags & B_READ) {
127938414Smckusick 		uiop->uio_rw = UIO_READ;
128038884Smacklem 		bp->b_error = error = nfs_readrpc(vp, uiop, &off, bp->b_rcred);
128138414Smckusick 	} else {
128238414Smckusick 		uiop->uio_rw = UIO_WRITE;
128338884Smacklem 		bp->b_error = error = nfs_writerpc(vp, uiop, &off, bp->b_wcred);
128439341Smckusick 		if (error) {
128539341Smckusick 			np = VTONFS(vp);
128639341Smckusick 			np->n_error = error;
128739341Smckusick 			np->n_flag |= NWRITEERR;
128839341Smckusick 		}
128938884Smacklem 		bp->b_dirtyoff = bp->b_dirtyend = 0;
129038414Smckusick 	}
129138884Smacklem 	if (error)
129238884Smacklem 		bp->b_flags |= B_ERROR;
129338414Smckusick 	bp->b_resid = uiop->uio_resid;
129438884Smacklem 	/*
129538884Smacklem 	 * Release pte's used by physical i/o
129638884Smacklem 	 */
129738884Smacklem 	if (bp->b_flags & B_PHYS) {
129838884Smacklem 		crfree(cr);
129938884Smacklem 		rmfree(nfsmap, (long)npf2, (long)++reg);
130038884Smacklem 		if (nfsmap_want) {
130138884Smacklem 			nfsmap_want = 0;
130238884Smacklem 			wakeup((caddr_t)&nfsmap_want);
130338884Smacklem 		}
130438884Smacklem 	}
130538414Smckusick 	biodone(bp);
130638414Smckusick 	return (error);
130738414Smckusick }
130838884Smacklem 
130938884Smacklem /*
131038884Smacklem  * Flush all the blocks associated with a vnode.
131138884Smacklem  * 	Walk through the buffer pool and push any dirty pages
131238884Smacklem  *	associated with the vnode.
131338884Smacklem  */
131438884Smacklem nfs_fsync(vp, fflags, cred)
131538884Smacklem 	register struct vnode *vp;
131638884Smacklem 	int fflags;
131738884Smacklem 	struct ucred *cred;
131838884Smacklem {
131938884Smacklem 	register struct nfsnode *np = VTONFS(vp);
132038884Smacklem 	int error;
132138884Smacklem 
132238884Smacklem 	nfs_lock(vp);
132338884Smacklem 	if (np->n_flag & NMODIFIED) {
132438884Smacklem 		np->n_flag &= ~NMODIFIED;
132539341Smckusick 		error = nfs_blkflush(vp, (daddr_t)0, np->n_size, FALSE);
132638884Smacklem 	}
132738884Smacklem 	nfs_unlock(vp);
132838884Smacklem 	return (error);
132938884Smacklem }
1330