xref: /original-bsd/sys/nfs/nfs_vnops.c (revision a6d8c59f)
1 /*
2  * Copyright (c) 1989 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Rick Macklem at The University of Guelph.
7  *
8  * %sccs.include.redist.c%
9  *
10  *	@(#)nfs_vnops.c	7.101 (Berkeley) 11/30/92
11  */
12 
13 /*
14  * vnode op calls for sun nfs version 2
15  */
16 
17 #include <sys/param.h>
18 #include <sys/proc.h>
19 #include <sys/kernel.h>
20 #include <sys/systm.h>
21 #include <sys/mount.h>
22 #include <sys/buf.h>
23 #include <sys/malloc.h>
24 #include <sys/mbuf.h>
25 #include <sys/conf.h>
26 #include <sys/namei.h>
27 #include <sys/vnode.h>
28 #include <sys/map.h>
29 #include <sys/dirent.h>
30 
31 #include <vm/vm.h>
32 
33 #include <miscfs/specfs/specdev.h>
34 #include <miscfs/fifofs/fifo.h>
35 
36 #include <nfs/rpcv2.h>
37 #include <nfs/nfsv2.h>
38 #include <nfs/nfs.h>
39 #include <nfs/nfsnode.h>
40 #include <nfs/nfsmount.h>
41 #include <nfs/xdr_subs.h>
42 #include <nfs/nfsm_subs.h>
43 #include <nfs/nqnfs.h>
44 
45 /* Defs */
46 #define	TRUE	1
47 #define	FALSE	0
48 
49 /*
50  * Global vfs data structures for nfs
51  */
52 int (**nfsv2_vnodeop_p)();
53 struct vnodeopv_entry_desc nfsv2_vnodeop_entries[] = {
54 	{ &vop_default_desc, vn_default_error },
55 	{ &vop_lookup_desc, nfs_lookup },	/* lookup */
56 	{ &vop_create_desc, nfs_create },	/* create */
57 	{ &vop_mknod_desc, nfs_mknod },		/* mknod */
58 	{ &vop_open_desc, nfs_open },		/* open */
59 	{ &vop_close_desc, nfs_close },		/* close */
60 	{ &vop_access_desc, nfs_access },	/* access */
61 	{ &vop_getattr_desc, nfs_getattr },	/* getattr */
62 	{ &vop_setattr_desc, nfs_setattr },	/* setattr */
63 	{ &vop_read_desc, nfs_read },		/* read */
64 	{ &vop_write_desc, nfs_write },		/* write */
65 	{ &vop_ioctl_desc, nfs_ioctl },		/* ioctl */
66 	{ &vop_select_desc, nfs_select },	/* select */
67 	{ &vop_mmap_desc, nfs_mmap },		/* mmap */
68 	{ &vop_fsync_desc, nfs_fsync },		/* fsync */
69 	{ &vop_seek_desc, nfs_seek },		/* seek */
70 	{ &vop_remove_desc, nfs_remove },	/* remove */
71 	{ &vop_link_desc, nfs_link },		/* link */
72 	{ &vop_rename_desc, nfs_rename },	/* rename */
73 	{ &vop_mkdir_desc, nfs_mkdir },		/* mkdir */
74 	{ &vop_rmdir_desc, nfs_rmdir },		/* rmdir */
75 	{ &vop_symlink_desc, nfs_symlink },	/* symlink */
76 	{ &vop_readdir_desc, nfs_readdir },	/* readdir */
77 	{ &vop_readlink_desc, nfs_readlink },	/* readlink */
78 	{ &vop_abortop_desc, nfs_abortop },	/* abortop */
79 	{ &vop_inactive_desc, nfs_inactive },	/* inactive */
80 	{ &vop_reclaim_desc, nfs_reclaim },	/* reclaim */
81 	{ &vop_lock_desc, nfs_lock },		/* lock */
82 	{ &vop_unlock_desc, nfs_unlock },	/* unlock */
83 	{ &vop_bmap_desc, nfs_bmap },		/* bmap */
84 	{ &vop_strategy_desc, nfs_strategy },	/* strategy */
85 	{ &vop_print_desc, nfs_print },		/* print */
86 	{ &vop_islocked_desc, nfs_islocked },	/* islocked */
87 	{ &vop_advlock_desc, nfs_advlock },	/* advlock */
88 	{ &vop_blkatoff_desc, nfs_blkatoff },	/* blkatoff */
89 	{ &vop_valloc_desc, nfs_valloc },	/* valloc */
90 	{ &vop_vfree_desc, nfs_vfree },		/* vfree */
91 	{ &vop_truncate_desc, nfs_truncate },	/* truncate */
92 	{ &vop_update_desc, nfs_update },	/* update */
93 	{ &vop_bwrite_desc, vn_bwrite },
94 	{ (struct vnodeop_desc*)NULL, (int(*)())NULL }
95 };
96 struct vnodeopv_desc nfsv2_vnodeop_opv_desc =
97 	{ &nfsv2_vnodeop_p, nfsv2_vnodeop_entries };
98 
99 /*
100  * Special device vnode ops
101  */
102 int (**spec_nfsv2nodeop_p)();
103 struct vnodeopv_entry_desc spec_nfsv2nodeop_entries[] = {
104 	{ &vop_default_desc, vn_default_error },
105 	{ &vop_lookup_desc, spec_lookup },	/* lookup */
106 	{ &vop_create_desc, spec_create },	/* create */
107 	{ &vop_mknod_desc, spec_mknod },	/* mknod */
108 	{ &vop_open_desc, spec_open },		/* open */
109 	{ &vop_close_desc, nfsspec_close },	/* close */
110 	{ &vop_access_desc, nfsspec_access },	/* access */
111 	{ &vop_getattr_desc, nfs_getattr },	/* getattr */
112 	{ &vop_setattr_desc, nfs_setattr },	/* setattr */
113 	{ &vop_read_desc, nfsspec_read },	/* read */
114 	{ &vop_write_desc, nfsspec_write },	/* write */
115 	{ &vop_ioctl_desc, spec_ioctl },	/* ioctl */
116 	{ &vop_select_desc, spec_select },	/* select */
117 	{ &vop_mmap_desc, spec_mmap },		/* mmap */
118 	{ &vop_fsync_desc, nfs_fsync },		/* fsync */
119 	{ &vop_seek_desc, spec_seek },		/* seek */
120 	{ &vop_remove_desc, spec_remove },	/* remove */
121 	{ &vop_link_desc, spec_link },		/* link */
122 	{ &vop_rename_desc, spec_rename },	/* rename */
123 	{ &vop_mkdir_desc, spec_mkdir },	/* mkdir */
124 	{ &vop_rmdir_desc, spec_rmdir },	/* rmdir */
125 	{ &vop_symlink_desc, spec_symlink },	/* symlink */
126 	{ &vop_readdir_desc, spec_readdir },	/* readdir */
127 	{ &vop_readlink_desc, spec_readlink },	/* readlink */
128 	{ &vop_abortop_desc, spec_abortop },	/* abortop */
129 	{ &vop_inactive_desc, nfs_inactive },	/* inactive */
130 	{ &vop_reclaim_desc, nfs_reclaim },	/* reclaim */
131 	{ &vop_lock_desc, nfs_lock },		/* lock */
132 	{ &vop_unlock_desc, nfs_unlock },	/* unlock */
133 	{ &vop_bmap_desc, spec_bmap },		/* bmap */
134 	{ &vop_strategy_desc, spec_strategy },	/* strategy */
135 	{ &vop_print_desc, nfs_print },		/* print */
136 	{ &vop_islocked_desc, nfs_islocked },	/* islocked */
137 	{ &vop_advlock_desc, spec_advlock },	/* advlock */
138 	{ &vop_blkatoff_desc, spec_blkatoff },	/* blkatoff */
139 	{ &vop_valloc_desc, spec_valloc },	/* valloc */
140 	{ &vop_vfree_desc, spec_vfree },	/* vfree */
141 	{ &vop_truncate_desc, spec_truncate },	/* truncate */
142 	{ &vop_update_desc, nfs_update },	/* update */
143 	{ &vop_bwrite_desc, vn_bwrite },
144 	{ (struct vnodeop_desc*)NULL, (int(*)())NULL }
145 };
146 struct vnodeopv_desc spec_nfsv2nodeop_opv_desc =
147 	{ &spec_nfsv2nodeop_p, spec_nfsv2nodeop_entries };
148 
149 #ifdef FIFO
150 int (**fifo_nfsv2nodeop_p)();
151 struct vnodeopv_entry_desc fifo_nfsv2nodeop_entries[] = {
152 	{ &vop_default_desc, vn_default_error },
153 	{ &vop_lookup_desc, fifo_lookup },	/* lookup */
154 	{ &vop_create_desc, fifo_create },	/* create */
155 	{ &vop_mknod_desc, fifo_mknod },	/* mknod */
156 	{ &vop_open_desc, fifo_open },		/* open */
157 	{ &vop_close_desc, nfsfifo_close },	/* close */
158 	{ &vop_access_desc, nfsspec_access },	/* access */
159 	{ &vop_getattr_desc, nfs_getattr },	/* getattr */
160 	{ &vop_setattr_desc, nfs_setattr },	/* setattr */
161 	{ &vop_read_desc, nfsfifo_read },	/* read */
162 	{ &vop_write_desc, nfsfifo_write },	/* write */
163 	{ &vop_ioctl_desc, fifo_ioctl },	/* ioctl */
164 	{ &vop_select_desc, fifo_select },	/* select */
165 	{ &vop_mmap_desc, fifo_mmap },		/* mmap */
166 	{ &vop_fsync_desc, nfs_fsync },		/* fsync */
167 	{ &vop_seek_desc, fifo_seek },		/* seek */
168 	{ &vop_remove_desc, fifo_remove },	/* remove */
169 	{ &vop_link_desc, fifo_link },		/* link */
170 	{ &vop_rename_desc, fifo_rename },	/* rename */
171 	{ &vop_mkdir_desc, fifo_mkdir },	/* mkdir */
172 	{ &vop_rmdir_desc, fifo_rmdir },	/* rmdir */
173 	{ &vop_symlink_desc, fifo_symlink },	/* symlink */
174 	{ &vop_readdir_desc, fifo_readdir },	/* readdir */
175 	{ &vop_readlink_desc, fifo_readlink },	/* readlink */
176 	{ &vop_abortop_desc, fifo_abortop },	/* abortop */
177 	{ &vop_inactive_desc, nfs_inactive },	/* inactive */
178 	{ &vop_reclaim_desc, nfs_reclaim },	/* reclaim */
179 	{ &vop_lock_desc, nfs_lock },		/* lock */
180 	{ &vop_unlock_desc, nfs_unlock },	/* unlock */
181 	{ &vop_bmap_desc, fifo_bmap },		/* bmap */
182 	{ &vop_strategy_desc, fifo_badop },	/* strategy */
183 	{ &vop_print_desc, nfs_print },		/* print */
184 	{ &vop_islocked_desc, nfs_islocked },	/* islocked */
185 	{ &vop_advlock_desc, fifo_advlock },	/* advlock */
186 	{ &vop_blkatoff_desc, fifo_blkatoff },	/* blkatoff */
187 	{ &vop_valloc_desc, fifo_valloc },	/* valloc */
188 	{ &vop_vfree_desc, fifo_vfree },	/* vfree */
189 	{ &vop_truncate_desc, fifo_truncate },	/* truncate */
190 	{ &vop_update_desc, nfs_update },	/* update */
191 	{ &vop_bwrite_desc, vn_bwrite },
192 	{ (struct vnodeop_desc*)NULL, (int(*)())NULL }
193 };
194 struct vnodeopv_desc fifo_nfsv2nodeop_opv_desc =
195 	{ &fifo_nfsv2nodeop_p, fifo_nfsv2nodeop_entries };
196 #endif /* FIFO */
197 
198 void nqnfs_clientlease();
199 
200 /*
201  * Global variables
202  */
203 extern u_long nfs_procids[NFS_NPROCS];
204 extern u_long nfs_prog, nfs_vers, nfs_true, nfs_false;
205 extern char nfsiobuf[MAXPHYS+NBPG];
206 struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON];
207 int nfs_numasync = 0;
208 /* Queue head for nfsiod's */
209 struct queue_entry nfs_bufq;
210 #define	DIRHDSIZ	(sizeof (struct dirent) - (MAXNAMLEN + 1))
211 
212 /*
213  * nfs null call from vfs.
214  */
215 int
216 nfs_null(vp, cred, procp)
217 	struct vnode *vp;
218 	struct ucred *cred;
219 	struct proc *procp;
220 {
221 	caddr_t bpos, dpos;
222 	int error = 0;
223 	struct mbuf *mreq, *mrep, *md, *mb;
224 
225 	nfsm_reqhead(vp, NFSPROC_NULL, 0);
226 	nfsm_request(vp, NFSPROC_NULL, procp, cred);
227 	nfsm_reqdone;
228 	return (error);
229 }
230 
231 /*
232  * nfs access vnode op.
233  * For nfs, just return ok. File accesses may fail later.
234  * For nqnfs, use the access rpc to check accessibility. If file modes are
235  * changed on the server, accesses might still fail later.
236  */
237 int
238 nfs_access(ap)
239 	struct vop_access_args /* {
240 		struct vnode *a_vp;
241 		int  a_mode;
242 		struct ucred *a_cred;
243 		struct proc *a_p;
244 	} */ *ap;
245 {
246 	register struct vnode *vp = ap->a_vp;
247 	register u_long *tl;
248 	register caddr_t cp;
249 	caddr_t bpos, dpos;
250 	int error = 0;
251 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
252 
253 	/*
254 	 * For nqnfs, do an access rpc, otherwise you are stuck emulating
255 	 * ufs_access() locally using the vattr. This may not be correct,
256 	 * since the server may apply other access criteria such as
257 	 * client uid-->server uid mapping that we do not know about, but
258 	 * this is better than just returning anything that is lying about
259 	 * in the cache.
260 	 */
261 	if (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) {
262 		nfsstats.rpccnt[NQNFSPROC_ACCESS]++;
263 		nfsm_reqhead(vp, NQNFSPROC_ACCESS, NFSX_FH + 3 * NFSX_UNSIGNED);
264 		nfsm_fhtom(vp);
265 		nfsm_build(tl, u_long *, 3 * NFSX_UNSIGNED);
266 		if (ap->a_mode & VREAD)
267 			*tl++ = nfs_true;
268 		else
269 			*tl++ = nfs_false;
270 		if (ap->a_mode & VWRITE)
271 			*tl++ = nfs_true;
272 		else
273 			*tl++ = nfs_false;
274 		if (ap->a_mode & VEXEC)
275 			*tl = nfs_true;
276 		else
277 			*tl = nfs_false;
278 		nfsm_request(vp, NQNFSPROC_ACCESS, ap->a_p, ap->a_cred);
279 		nfsm_reqdone;
280 		return (error);
281 	} else
282 		return (nfsspec_access(ap));
283 }
284 
285 /*
286  * nfs open vnode op
287  * Check to see if the type is ok
288  * and that deletion is not in progress.
289  * For paged in text files, you will need to flush the page cache
290  * if consistency is lost.
291  */
292 /* ARGSUSED */
293 int
294 nfs_open(ap)
295 	struct vop_open_args /* {
296 		struct vnode *a_vp;
297 		int  a_mode;
298 		struct ucred *a_cred;
299 		struct proc *a_p;
300 	} */ *ap;
301 {
302 	register struct vnode *vp = ap->a_vp;
303 	struct nfsnode *np = VTONFS(vp);
304 	struct nfsmount *nmp = VFSTONFS(vp->v_mount);
305 	struct vattr vattr;
306 	int error;
307 
308 	if (vp->v_type != VREG && vp->v_type != VDIR && vp->v_type != VLNK)
309 		return (EACCES);
310 	if (vp->v_flag & VTEXT) {
311 	    /*
312 	     * Get a valid lease. If cached data is stale, flush it.
313 	     */
314 	    if (nmp->nm_flag & NFSMNT_NQNFS) {
315 		if (NQNFS_CKINVALID(vp, np, NQL_READ)) {
316 		    do {
317 			error = nqnfs_getlease(vp, NQL_READ, ap->a_cred, ap->a_p);
318 		    } while (error == NQNFS_EXPIRED);
319 		    if (error)
320 			return (error);
321 		    if (np->n_lrev != np->n_brev) {
322 			NFS_VINVBUF(np, vp, TRUE, ap->a_cred, ap->a_p);
323 			(void) vnode_pager_uncache(vp);
324 			np->n_brev = np->n_lrev;
325 		    }
326 		}
327 	    } else {
328 		if (np->n_flag & NMODIFIED) {
329 			NFS_VINVBUF(np, vp, TRUE, ap->a_cred, ap->a_p);
330 			(void) vnode_pager_uncache(vp);
331 			np->n_attrstamp = 0;
332 			np->n_direofoffset = 0;
333 			if (error = VOP_GETATTR(vp, &vattr, ap->a_cred, ap->a_p))
334 				return (error);
335 			np->n_mtime = vattr.va_mtime.ts_sec;
336 		} else {
337 			if (error = VOP_GETATTR(vp, &vattr, ap->a_cred, ap->a_p))
338 				return (error);
339 			if (np->n_mtime != vattr.va_mtime.ts_sec) {
340 				np->n_direofoffset = 0;
341 				NFS_VINVBUF(np, vp, TRUE, ap->a_cred, ap->a_p);
342 				(void) vnode_pager_uncache(vp);
343 				np->n_mtime = vattr.va_mtime.ts_sec;
344 			}
345 		}
346 	    }
347 	} else if ((nmp->nm_flag & NFSMNT_NQNFS) == 0)
348 		np->n_attrstamp = 0; /* For Open/Close consistency */
349 	return (0);
350 }
351 
352 /*
353  * nfs close vnode op
354  * For reg files, invalidate any buffer cache entries.
355  */
356 /* ARGSUSED */
357 int
358 nfs_close(ap)
359 	struct vop_close_args /* {
360 		struct vnodeop_desc *a_desc;
361 		struct vnode *a_vp;
362 		int  a_fflag;
363 		struct ucred *a_cred;
364 		struct proc *a_p;
365 	} */ *ap;
366 {
367 	register struct vnode *vp = ap->a_vp;
368 	register struct nfsnode *np = VTONFS(vp);
369 	int error = 0;
370 
371 	if (vp->v_type == VREG) {
372 	    if ((VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) == 0 &&
373 		(np->n_flag & NMODIFIED)) {
374 		NFS_VINVBUFE(np, vp, TRUE, ap->a_cred, ap->a_p, error);
375 		np->n_attrstamp = 0;
376 	    }
377 	    if (np->n_flag & NWRITEERR) {
378 		np->n_flag &= ~NWRITEERR;
379 		error = np->n_error;
380 	    }
381 	}
382 	return (error);
383 }
384 
385 /*
386  * nfs getattr call from vfs.
387  */
388 int
389 nfs_getattr(ap)
390 	struct vop_getattr_args /* {
391 		struct vnode *a_vp;
392 		struct vattr *a_vap;
393 		struct ucred *a_cred;
394 		struct proc *a_p;
395 	} */ *ap;
396 {
397 	register struct vnode *vp = ap->a_vp;
398 	register struct nfsnode *np = VTONFS(vp);
399 	register caddr_t cp;
400 	caddr_t bpos, dpos;
401 	int error = 0;
402 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
403 
404 	/*
405 	 * Update local times for special files.
406 	 */
407 	if (np->n_flag & (NACC | NUPD))
408 		np->n_flag |= NCHG;
409 	/*
410 	 * First look in the cache.
411 	 */
412 	if (nfs_getattrcache(vp, ap->a_vap) == 0)
413 		return (0);
414 	nfsstats.rpccnt[NFSPROC_GETATTR]++;
415 	nfsm_reqhead(vp, NFSPROC_GETATTR, NFSX_FH);
416 	nfsm_fhtom(vp);
417 	nfsm_request(vp, NFSPROC_GETATTR, ap->a_p, ap->a_cred);
418 	nfsm_loadattr(vp, ap->a_vap);
419 	nfsm_reqdone;
420 	return (error);
421 }
422 
423 /*
424  * nfs setattr call.
425  */
426 int
427 nfs_setattr(ap)
428 	struct vop_setattr_args /* {
429 		struct vnodeop_desc *a_desc;
430 		struct vnode *a_vp;
431 		struct vattr *a_vap;
432 		struct ucred *a_cred;
433 		struct proc *a_p;
434 	} */ *ap;
435 {
436 	register struct nfsv2_sattr *sp;
437 	register caddr_t cp;
438 	register long t1;
439 	caddr_t bpos, dpos, cp2;
440 	u_long *tl;
441 	int error = 0, isnq;
442 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
443 	register struct vnode *vp = ap->a_vp;
444 	register struct nfsnode *np = VTONFS(vp);
445 	register struct vattr *vap = ap->a_vap;
446 	u_quad_t frev;
447 
448 	nfsstats.rpccnt[NFSPROC_SETATTR]++;
449 	isnq = (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS);
450 	nfsm_reqhead(vp, NFSPROC_SETATTR, NFSX_FH+NFSX_SATTR(isnq));
451 	nfsm_fhtom(vp);
452 	nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR(isnq));
453 	if (vap->va_mode == (u_short)-1)
454 		sp->sa_mode = VNOVAL;
455 	else
456 		sp->sa_mode = vtonfs_mode(vp->v_type, vap->va_mode);
457 	if (vap->va_uid == (uid_t)-1)
458 		sp->sa_uid = VNOVAL;
459 	else
460 		sp->sa_uid = txdr_unsigned(vap->va_uid);
461 	if (vap->va_gid == (gid_t)-1)
462 		sp->sa_gid = VNOVAL;
463 	else
464 		sp->sa_gid = txdr_unsigned(vap->va_gid);
465 	if (isnq) {
466 		txdr_hyper(&vap->va_size, &sp->sa_nqsize);
467 		txdr_nqtime(&vap->va_atime, &sp->sa_nqatime);
468 		txdr_nqtime(&vap->va_mtime, &sp->sa_nqmtime);
469 		sp->sa_nqflags = txdr_unsigned(vap->va_flags);
470 		sp->sa_nqrdev = VNOVAL;
471 	} else {
472 		sp->sa_nfssize = txdr_unsigned(vap->va_size);
473 		sp->sa_nfsatime.nfs_sec = txdr_unsigned(vap->va_atime.ts_sec);
474 		sp->sa_nfsatime.nfs_usec = txdr_unsigned(vap->va_flags);
475 		txdr_nfstime(&vap->va_mtime, &sp->sa_nfsmtime);
476 	}
477 	if (vap->va_size != VNOVAL || vap->va_mtime.ts_sec != VNOVAL ||
478 	    vap->va_atime.ts_sec != VNOVAL) {
479 		if (np->n_flag & NMODIFIED) {
480 			NFS_VINVBUFE(np, vp, vap->va_size? TRUE: FALSE,
481 			             ap->a_cred, ap->a_p, error);
482 		}
483 		if (vap->va_size != VNOVAL)
484 			np->n_size = np->n_vattr.va_size = vap->va_size;
485 	}
486 	nfsm_request(vp, NFSPROC_SETATTR, ap->a_p, ap->a_cred);
487 	nfsm_loadattr(vp, (struct vattr *)0);
488 	if ((VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) &&
489 	    NQNFS_CKCACHABLE(vp, NQL_WRITE)) {
490 		nfsm_dissect(tl, u_long *, 2*NFSX_UNSIGNED);
491 		fxdr_hyper(tl, &frev);
492 		if (frev > np->n_brev)
493 			np->n_brev = frev;
494 	}
495 	nfsm_reqdone;
496 	return (error);
497 }
498 
499 /*
500  * nfs lookup call, one step at a time...
501  * First look in cache
502  * If not found, unlock the directory nfsnode and do the rpc
503  */
504 int
505 nfs_lookup(ap)
506 	struct vop_lookup_args /* {
507 		struct vnodeop_desc *a_desc;
508 		struct vnode *a_dvp;
509 		struct vnode **a_vpp;
510 		struct componentname *a_cnp;
511 	} */ *ap;
512 {
513 	register struct componentname *cnp = ap->a_cnp;
514 	register struct vnode *dvp = ap->a_dvp;
515 	register struct vnode **vpp = ap->a_vpp;
516 	register int flags = cnp->cn_flags;
517 	register struct vnode *vdp;
518 	register u_long *tl;
519 	register caddr_t cp;
520 	register long t1, t2;
521 	struct nfsmount *nmp;
522 	struct nfsnode *tp;
523 	caddr_t bpos, dpos, cp2;
524 	time_t reqtime;
525 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
526 	struct vnode *newvp;
527 	long len;
528 	nfsv2fh_t *fhp;
529 	struct nfsnode *np;
530 	int lockparent, wantparent, error = 0;
531 	int nqlflag, cachable;
532 	u_quad_t frev;
533 
534 	*vpp = NULL;
535 	if (dvp->v_type != VDIR)
536 		return (ENOTDIR);
537 	lockparent = flags & LOCKPARENT;
538 	wantparent = flags & (LOCKPARENT|WANTPARENT);
539 	nmp = VFSTONFS(dvp->v_mount);
540 	np = VTONFS(dvp);
541 	if ((error = cache_lookup(dvp, vpp, cnp)) && error != ENOENT) {
542 		struct vattr vattr;
543 		int vpid;
544 
545 		vdp = *vpp;
546 		vpid = vdp->v_id;
547 		/*
548 		 * See the comment starting `Step through' in ufs/ufs_lookup.c
549 		 * for an explanation of the locking protocol
550 		 */
551 		if (dvp == vdp) {
552 			VREF(vdp);
553 			error = 0;
554 		} else
555 			error = vget(vdp);
556 		if (!error) {
557 			if (vpid == vdp->v_id) {
558 			   if (nmp->nm_flag & NFSMNT_NQNFS) {
559 				if ((nmp->nm_flag & NFSMNT_NQLOOKLEASE) == 0) {
560 					nfsstats.lookupcache_hits++;
561 					if (cnp->cn_nameiop != LOOKUP &&
562 					    (flags & ISLASTCN))
563 					    cnp->cn_flags |= SAVENAME;
564 					return (0);
565 			        } else if (NQNFS_CKCACHABLE(dvp, NQL_READ)) {
566 					if (np->n_lrev != np->n_brev ||
567 					    (np->n_flag & NMODIFIED)) {
568 						np->n_direofoffset = 0;
569 						cache_purge(dvp);
570 						NFS_VINVBUFE(np, dvp, FALSE,
571 						    cnp->cn_cred, cnp->cn_proc,
572 						    error);
573 						np->n_brev = np->n_lrev;
574 					} else {
575 						nfsstats.lookupcache_hits++;
576 						if (cnp->cn_nameiop != LOOKUP &&
577 						    (flags & ISLASTCN))
578 						    cnp->cn_flags |= SAVENAME;
579 						return (0);
580 					}
581 				}
582 			   } else if (!VOP_GETATTR(vdp, &vattr, cnp->cn_cred, cnp->cn_proc) &&
583 			       vattr.va_ctime.ts_sec == VTONFS(vdp)->n_ctime) {
584 				nfsstats.lookupcache_hits++;
585 				if (cnp->cn_nameiop != LOOKUP &&
586 				    (flags & ISLASTCN))
587 					cnp->cn_flags |= SAVENAME;
588 				return (0);
589 			   }
590 			   cache_purge(vdp);
591 			}
592 			vrele(vdp);
593 		}
594 		*vpp = NULLVP;
595 	}
596 	error = 0;
597 	nfsstats.lookupcache_misses++;
598 	nfsstats.rpccnt[NFSPROC_LOOKUP]++;
599 	len = cnp->cn_namelen;
600 	nfsm_reqhead(dvp, NFSPROC_LOOKUP, NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len));
601 
602 	/*
603 	 * For nqnfs optionally piggyback a getlease request for the name
604 	 * being looked up.
605 	 */
606 	if (nmp->nm_flag & NFSMNT_NQNFS) {
607 		nfsm_build(tl, u_long *, NFSX_UNSIGNED);
608 		if ((nmp->nm_flag & NFSMNT_NQLOOKLEASE) &&
609 		    ((cnp->cn_flags & MAKEENTRY) &&
610 		    (cnp->cn_nameiop != DELETE || !(flags & ISLASTCN))))
611 			*tl = txdr_unsigned(nmp->nm_leaseterm);
612 		else
613 			*tl = 0;
614 	}
615 	nfsm_fhtom(dvp);
616 	nfsm_strtom(cnp->cn_nameptr, len, NFS_MAXNAMLEN);
617 	reqtime = time.tv_sec;
618 	nfsm_request(dvp, NFSPROC_LOOKUP, cnp->cn_proc, cnp->cn_cred);
619 nfsmout:
620 	if (error) {
621 		if ((cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME) &&
622 		    (flags & ISLASTCN) && error == ENOENT)
623 			error = EJUSTRETURN;
624 		if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN))
625 			cnp->cn_flags |= SAVENAME;
626 		return (error);
627 	}
628 	if (nmp->nm_flag & NFSMNT_NQNFS) {
629 		nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
630 		if (*tl) {
631 			nqlflag = fxdr_unsigned(int, *tl);
632 			nfsm_dissect(tl, u_long *, 4*NFSX_UNSIGNED);
633 			cachable = fxdr_unsigned(int, *tl++);
634 			reqtime += fxdr_unsigned(int, *tl++);
635 			fxdr_hyper(tl, &frev);
636 		} else
637 			nqlflag = 0;
638 	}
639 	nfsm_dissect(fhp, nfsv2fh_t *, NFSX_FH);
640 
641 	/*
642 	 * Handle RENAME case...
643 	 */
644 	if (cnp->cn_nameiop == RENAME && wantparent && (flags & ISLASTCN)) {
645 		if (!bcmp(np->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) {
646 			m_freem(mrep);
647 			return (EISDIR);
648 		}
649 		if (error = nfs_nget(dvp->v_mount, fhp, &np)) {
650 			m_freem(mrep);
651 			return (error);
652 		}
653 		newvp = NFSTOV(np);
654 		if (error =
655 		    nfs_loadattrcache(&newvp, &md, &dpos, (struct vattr *)0)) {
656 			vrele(newvp);
657 			m_freem(mrep);
658 			return (error);
659 		}
660 		*vpp = newvp;
661 		m_freem(mrep);
662 		cnp->cn_flags |= SAVENAME;
663 		return (0);
664 	}
665 
666 	if (!bcmp(np->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) {
667 		VREF(dvp);
668 		newvp = dvp;
669 	} else {
670 		if (error = nfs_nget(dvp->v_mount, fhp, &np)) {
671 			m_freem(mrep);
672 			return (error);
673 		}
674 		newvp = NFSTOV(np);
675 	}
676 	if (error = nfs_loadattrcache(&newvp, &md, &dpos, (struct vattr *)0)) {
677 		vrele(newvp);
678 		m_freem(mrep);
679 		return (error);
680 	}
681 	m_freem(mrep);
682 	*vpp = newvp;
683 	if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN))
684 		cnp->cn_flags |= SAVENAME;
685 	if ((cnp->cn_flags & MAKEENTRY) &&
686 	    (cnp->cn_nameiop != DELETE || !(flags & ISLASTCN))) {
687 		if ((nmp->nm_flag & NFSMNT_NQNFS) == 0)
688 			np->n_ctime = np->n_vattr.va_ctime.ts_sec;
689 		else if (nqlflag && reqtime > time.tv_sec)
690 			nqnfs_clientlease(nmp, np, nqlflag, cachable, reqtime,
691 				frev);
692 		cache_enter(dvp, *vpp, cnp);
693 	}
694 	return (0);
695 }
696 
697 /*
698  * nfs read call.
699  * Just call nfs_bioread() to do the work.
700  */
701 int
702 nfs_read(ap)
703 	struct vop_read_args /* {
704 		struct vnode *a_vp;
705 		struct uio *a_uio;
706 		int  a_ioflag;
707 		struct ucred *a_cred;
708 	} */ *ap;
709 {
710 	register struct vnode *vp = ap->a_vp;
711 
712 	if (vp->v_type != VREG)
713 		return (EPERM);
714 	return (nfs_bioread(vp, ap->a_uio, ap->a_ioflag, ap->a_cred));
715 }
716 
717 /*
718  * nfs readlink call
719  */
720 int
721 nfs_readlink(ap)
722 	struct vop_readlink_args /* {
723 		struct vnode *a_vp;
724 		struct uio *a_uio;
725 		struct ucred *a_cred;
726 	} */ *ap;
727 {
728 	register struct vnode *vp = ap->a_vp;
729 
730 	if (vp->v_type != VLNK)
731 		return (EPERM);
732 	return (nfs_bioread(vp, ap->a_uio, 0, ap->a_cred));
733 }
734 
735 /*
736  * Do a readlink rpc.
737  * Called by nfs_doio() from below the buffer cache.
738  */
739 int
740 nfs_readlinkrpc(vp, uiop, cred)
741 	register struct vnode *vp;
742 	struct uio *uiop;
743 	struct ucred *cred;
744 {
745 	register u_long *tl;
746 	register caddr_t cp;
747 	register long t1;
748 	caddr_t bpos, dpos, cp2;
749 	int error = 0;
750 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
751 	long len;
752 
753 	nfsstats.rpccnt[NFSPROC_READLINK]++;
754 	nfsm_reqhead(vp, NFSPROC_READLINK, NFSX_FH);
755 	nfsm_fhtom(vp);
756 	nfsm_request(vp, NFSPROC_READLINK, uiop->uio_procp, cred);
757 	nfsm_strsiz(len, NFS_MAXPATHLEN);
758 	nfsm_mtouio(uiop, len);
759 	nfsm_reqdone;
760 	return (error);
761 }
762 
763 /*
764  * nfs read rpc call
765  * Ditto above
766  */
767 int
768 nfs_readrpc(vp, uiop, cred)
769 	register struct vnode *vp;
770 	struct uio *uiop;
771 	struct ucred *cred;
772 {
773 	register u_long *tl;
774 	register caddr_t cp;
775 	register long t1;
776 	caddr_t bpos, dpos, cp2;
777 	int error = 0;
778 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
779 	struct nfsmount *nmp;
780 	long len, retlen, tsiz;
781 
782 	nmp = VFSTONFS(vp->v_mount);
783 	tsiz = uiop->uio_resid;
784 	if (uiop->uio_offset + tsiz > 0xffffffff &&
785 	    (nmp->nm_flag & NFSMNT_NQNFS) == 0)
786 		return (EFBIG);
787 	while (tsiz > 0) {
788 		nfsstats.rpccnt[NFSPROC_READ]++;
789 		len = (tsiz > nmp->nm_rsize) ? nmp->nm_rsize : tsiz;
790 		nfsm_reqhead(vp, NFSPROC_READ, NFSX_FH+NFSX_UNSIGNED*3);
791 		nfsm_fhtom(vp);
792 		nfsm_build(tl, u_long *, NFSX_UNSIGNED*3);
793 		if (nmp->nm_flag & NFSMNT_NQNFS) {
794 			txdr_hyper(&uiop->uio_offset, tl);
795 			*(tl + 2) = txdr_unsigned(len);
796 		} else {
797 			*tl++ = txdr_unsigned(uiop->uio_offset);
798 			*tl++ = txdr_unsigned(len);
799 			*tl = 0;
800 		}
801 		nfsm_request(vp, NFSPROC_READ, uiop->uio_procp, cred);
802 		nfsm_loadattr(vp, (struct vattr *)0);
803 		nfsm_strsiz(retlen, nmp->nm_rsize);
804 		nfsm_mtouio(uiop, retlen);
805 		m_freem(mrep);
806 		if (retlen < len)
807 			tsiz = 0;
808 		else
809 			tsiz -= len;
810 	}
811 nfsmout:
812 	return (error);
813 }
814 
815 /*
816  * nfs write call
817  */
818 int
819 nfs_writerpc(vp, uiop, cred, ioflags)
820 	register struct vnode *vp;
821 	struct uio *uiop;
822 	struct ucred *cred;
823 	int ioflags;
824 {
825 	register u_long *tl;
826 	register caddr_t cp;
827 	register long t1;
828 	caddr_t bpos, dpos, cp2;
829 	int error = 0;
830 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
831 	struct nfsmount *nmp;
832 	struct nfsnode *np = VTONFS(vp);
833 	u_quad_t frev;
834 	long len, tsiz;
835 
836 	nmp = VFSTONFS(vp->v_mount);
837 	tsiz = uiop->uio_resid;
838 	if (uiop->uio_offset + tsiz > 0xffffffff &&
839 	    (nmp->nm_flag & NFSMNT_NQNFS) == 0)
840 		return (EFBIG);
841 	while (tsiz > 0) {
842 		nfsstats.rpccnt[NFSPROC_WRITE]++;
843 		len = (tsiz > nmp->nm_wsize) ? nmp->nm_wsize : tsiz;
844 		nfsm_reqhead(vp, NFSPROC_WRITE,
845 			NFSX_FH+NFSX_UNSIGNED*4+nfsm_rndup(len));
846 		nfsm_fhtom(vp);
847 		nfsm_build(tl, u_long *, NFSX_UNSIGNED * 4);
848 		if (nmp->nm_flag & NFSMNT_NQNFS) {
849 			txdr_hyper(&uiop->uio_offset, tl);
850 			tl += 2;
851 			if (ioflags & IO_APPEND)
852 				*tl++ = txdr_unsigned(1);
853 			else
854 				*tl++ = 0;
855 		} else {
856 			*++tl = txdr_unsigned(uiop->uio_offset);
857 			tl += 2;
858 		}
859 		*tl = txdr_unsigned(len);
860 		nfsm_uiotom(uiop, len);
861 		nfsm_request(vp, NFSPROC_WRITE, uiop->uio_procp, cred);
862 		nfsm_loadattr(vp, (struct vattr *)0);
863 		if (nmp->nm_flag & NFSMNT_MYWRITE)
864 			VTONFS(vp)->n_mtime = VTONFS(vp)->n_vattr.va_mtime.ts_sec;
865 		else if ((nmp->nm_flag & NFSMNT_NQNFS) &&
866 			 NQNFS_CKCACHABLE(vp, NQL_WRITE)) {
867 			nfsm_dissect(tl, u_long *, 2*NFSX_UNSIGNED);
868 			fxdr_hyper(tl, &frev);
869 			if (frev > np->n_brev)
870 				np->n_brev = frev;
871 		}
872 		m_freem(mrep);
873 		tsiz -= len;
874 	}
875 nfsmout:
876 	if (error)
877 		uiop->uio_resid = tsiz;
878 	return (error);
879 }
880 
881 /*
882  * nfs mknod call
883  * This is a kludge. Use a create rpc but with the IFMT bits of the mode
884  * set to specify the file type and the size field for rdev.
885  */
886 /* ARGSUSED */
887 int
888 nfs_mknod(ap)
889 	struct vop_mknod_args /* {
890 		struct vnode *a_dvp;
891 		struct vnode **a_vpp;
892 		struct componentname *a_cnp;
893 		struct vattr *a_vap;
894 	} */ *ap;
895 {
896 	register struct vnode *dvp = ap->a_dvp;
897 	register struct vattr *vap = ap->a_vap;
898 	register struct componentname *cnp = ap->a_cnp;
899 	register struct nfsv2_sattr *sp;
900 	register u_long *tl;
901 	register caddr_t cp;
902 	register long t1, t2;
903 	struct vnode *newvp;
904 	char *cp2;
905 	caddr_t bpos, dpos;
906 	int error = 0, isnq;
907 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
908 	u_long rdev;
909 
910 	isnq = (VFSTONFS(dvp->v_mount)->nm_flag & NFSMNT_NQNFS);
911 	if (vap->va_type == VCHR || vap->va_type == VBLK)
912 		rdev = txdr_unsigned(vap->va_rdev);
913 #ifdef FIFO
914 	else if (vap->va_type == VFIFO)
915 		rdev = 0xffffffff;
916 #endif /* FIFO */
917 	else {
918 		VOP_ABORTOP(dvp, cnp);
919 		vput(dvp);
920 		return (EOPNOTSUPP);
921 	}
922 	nfsstats.rpccnt[NFSPROC_CREATE]++;
923 	nfsm_reqhead(dvp, NFSPROC_CREATE,
924 	  NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen)+NFSX_SATTR(isnq));
925 	nfsm_fhtom(dvp);
926 	nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
927 	nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR(isnq));
928 	sp->sa_mode = vtonfs_mode(vap->va_type, vap->va_mode);
929 	sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid);
930 	sp->sa_gid = txdr_unsigned(cnp->cn_cred->cr_gid);
931 	if (isnq) {
932 		sp->sa_nqrdev = rdev;
933 		sp->sa_nqflags = 0;
934 		txdr_nqtime(&vap->va_atime, &sp->sa_nqatime);
935 		txdr_nqtime(&vap->va_mtime, &sp->sa_nqmtime);
936 	} else {
937 		sp->sa_nfssize = rdev;
938 		txdr_nfstime(&vap->va_atime, &sp->sa_nfsatime);
939 		txdr_nfstime(&vap->va_mtime, &sp->sa_nfsmtime);
940 	}
941 	nfsm_request(dvp, NFSPROC_CREATE, cnp->cn_proc, cnp->cn_cred);
942 	nfsm_mtofh(dvp, newvp);
943 	nfsm_reqdone;
944 	if (!error && (cnp->cn_flags & MAKEENTRY))
945 		cache_enter(dvp, newvp, cnp);
946 	FREE(cnp->cn_pnbuf, M_NAMEI);
947 	VTONFS(dvp)->n_flag |= NMODIFIED;
948 	vrele(dvp);
949 	return (error);
950 }
951 
952 /*
953  * nfs file create call
954  */
955 int
956 nfs_create(ap)
957 	struct vop_create_args /* {
958 		struct vnode *a_dvp;
959 		struct vnode **a_vpp;
960 		struct componentname *a_cnp;
961 		struct vattr *a_vap;
962 	} */ *ap;
963 {
964 	register struct vnode *dvp = ap->a_dvp;
965 	register struct vattr *vap = ap->a_vap;
966 	register struct componentname *cnp = ap->a_cnp;
967 	register struct nfsv2_sattr *sp;
968 	register u_long *tl;
969 	register caddr_t cp;
970 	register long t1, t2;
971 	caddr_t bpos, dpos, cp2;
972 	int error = 0, isnq;
973 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
974 
975 	nfsstats.rpccnt[NFSPROC_CREATE]++;
976 	isnq = (VFSTONFS(dvp->v_mount)->nm_flag & NFSMNT_NQNFS);
977 	nfsm_reqhead(dvp, NFSPROC_CREATE,
978 	  NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen)+NFSX_SATTR(isnq));
979 	nfsm_fhtom(dvp);
980 	nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
981 	nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR(isnq));
982 	sp->sa_mode = vtonfs_mode(vap->va_type, vap->va_mode);
983 	sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid);
984 	sp->sa_gid = txdr_unsigned(cnp->cn_cred->cr_gid);
985 	if (isnq) {
986 		u_quad_t qval = 0;
987 
988 		txdr_hyper(&qval, &sp->sa_nqsize);
989 		sp->sa_nqflags = 0;
990 		sp->sa_nqrdev = -1;
991 		txdr_nqtime(&vap->va_atime, &sp->sa_nqatime);
992 		txdr_nqtime(&vap->va_mtime, &sp->sa_nqmtime);
993 	} else {
994 		sp->sa_nfssize = 0;
995 		txdr_nfstime(&vap->va_atime, &sp->sa_nfsatime);
996 		txdr_nfstime(&vap->va_mtime, &sp->sa_nfsmtime);
997 	}
998 	nfsm_request(dvp, NFSPROC_CREATE, cnp->cn_proc, cnp->cn_cred);
999 	nfsm_mtofh(dvp, *ap->a_vpp);
1000 	nfsm_reqdone;
1001 	if (!error && (cnp->cn_flags & MAKEENTRY))
1002 		cache_enter(dvp, *ap->a_vpp, cnp);
1003 	FREE(cnp->cn_pnbuf, M_NAMEI);
1004 	VTONFS(dvp)->n_flag |= NMODIFIED;
1005 	vrele(dvp);
1006 	return (error);
1007 }
1008 
1009 /*
1010  * nfs file remove call
1011  * To try and make nfs semantics closer to ufs semantics, a file that has
1012  * other processes using the vnode is renamed instead of removed and then
1013  * removed later on the last close.
1014  * - If v_usecount > 1
1015  *	  If a rename is not already in the works
1016  *	     call nfs_sillyrename() to set it up
1017  *     else
1018  *	  do the remove rpc
1019  */
1020 int
1021 nfs_remove(ap)
1022 	struct vop_remove_args /* {
1023 		struct vnodeop_desc *a_desc;
1024 		struct vnode * a_dvp;
1025 		struct vnode * a_vp;
1026 		struct componentname * a_cnp;
1027 	} */ *ap;
1028 {
1029 	register struct vnode *vp = ap->a_vp;
1030 	register struct vnode *dvp = ap->a_dvp;
1031 	register struct componentname *cnp = ap->a_cnp;
1032 	register struct nfsnode *np = VTONFS(vp);
1033 	register u_long *tl;
1034 	register caddr_t cp;
1035 	register long t2;
1036 	caddr_t bpos, dpos;
1037 	int error = 0;
1038 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
1039 
1040 	if (vp->v_usecount > 1) {
1041 		if (!np->n_sillyrename)
1042 			error = nfs_sillyrename(dvp, vp, cnp);
1043 	} else {
1044 		/*
1045 		 * Purge the name cache so that the chance of a lookup for
1046 		 * the name succeeding while the remove is in progress is
1047 		 * minimized. Without node locking it can still happen, such
1048 		 * that an I/O op returns ESTALE, but since you get this if
1049 		 * another host removes the file..
1050 		 */
1051 		cache_purge(vp);
1052 		/*
1053 		 * Throw away biocache buffers. Mainly to avoid
1054 		 * unnecessary delayed writes.
1055 		 */
1056 		NFS_VINVBUFE(np, vp, FALSE, cnp->cn_cred, cnp->cn_proc, error);
1057 		/* Do the rpc */
1058 		nfsstats.rpccnt[NFSPROC_REMOVE]++;
1059 		nfsm_reqhead(dvp, NFSPROC_REMOVE,
1060 			NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen));
1061 		nfsm_fhtom(dvp);
1062 		nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
1063 		nfsm_request(dvp, NFSPROC_REMOVE, cnp->cn_proc, cnp->cn_cred);
1064 		nfsm_reqdone;
1065 		FREE(cnp->cn_pnbuf, M_NAMEI);
1066 		VTONFS(dvp)->n_flag |= NMODIFIED;
1067 		/*
1068 		 * Kludge City: If the first reply to the remove rpc is lost..
1069 		 *   the reply to the retransmitted request will be ENOENT
1070 		 *   since the file was in fact removed
1071 		 *   Therefore, we cheat and return success.
1072 		 */
1073 		if (error == ENOENT)
1074 			error = 0;
1075 	}
1076 	np->n_attrstamp = 0;
1077 	vrele(dvp);
1078 	vrele(vp);
1079 	return (error);
1080 }
1081 
1082 /*
1083  * nfs file remove rpc called from nfs_inactive
1084  */
1085 int
1086 nfs_removeit(sp)
1087 	register struct sillyrename *sp;
1088 {
1089 	register u_long *tl;
1090 	register caddr_t cp;
1091 	register long t2;
1092 	caddr_t bpos, dpos;
1093 	int error = 0;
1094 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
1095 
1096 	nfsstats.rpccnt[NFSPROC_REMOVE]++;
1097 	nfsm_reqhead(sp->s_dvp, NFSPROC_REMOVE,
1098 		NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(sp->s_namlen));
1099 	nfsm_fhtom(sp->s_dvp);
1100 	nfsm_strtom(sp->s_name, sp->s_namlen, NFS_MAXNAMLEN);
1101 	nfsm_request(sp->s_dvp, NFSPROC_REMOVE, NULL, sp->s_cred);
1102 	nfsm_reqdone;
1103 	VTONFS(sp->s_dvp)->n_flag |= NMODIFIED;
1104 	return (error);
1105 }
1106 
1107 /*
1108  * nfs file rename call
1109  */
1110 int
1111 nfs_rename(ap)
1112 	struct vop_rename_args  /* {
1113 		struct vnode *a_fdvp;
1114 		struct vnode *a_fvp;
1115 		struct componentname *a_fcnp;
1116 		struct vnode *a_tdvp;
1117 		struct vnode *a_tvp;
1118 		struct componentname *a_tcnp;
1119 	} */ *ap;
1120 {
1121 	register struct vnode *fvp = ap->a_fvp;
1122 	register struct vnode *tvp = ap->a_tvp;
1123 	register struct vnode *fdvp = ap->a_fdvp;
1124 	register struct vnode *tdvp = ap->a_tdvp;
1125 	register struct componentname *tcnp = ap->a_tcnp;
1126 	register struct componentname *fcnp = ap->a_fcnp;
1127 	register u_long *tl;
1128 	register caddr_t cp;
1129 	register long t2;
1130 	caddr_t bpos, dpos;
1131 	int error = 0;
1132 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
1133 
1134 	/* Check for cross-device rename */
1135 	if ((fvp->v_mount != tdvp->v_mount) ||
1136 	    (tvp && (fvp->v_mount != tvp->v_mount))) {
1137 		error = EXDEV;
1138 		goto out;
1139 	}
1140 
1141 
1142 	nfsstats.rpccnt[NFSPROC_RENAME]++;
1143 	nfsm_reqhead(fdvp, NFSPROC_RENAME,
1144 		(NFSX_FH+NFSX_UNSIGNED)*2+nfsm_rndup(fcnp->cn_namelen)+
1145 		nfsm_rndup(fcnp->cn_namelen)); /* or fcnp->cn_cred?*/
1146 	nfsm_fhtom(fdvp);
1147 	nfsm_strtom(fcnp->cn_nameptr, fcnp->cn_namelen, NFS_MAXNAMLEN);
1148 	nfsm_fhtom(tdvp);
1149 	nfsm_strtom(tcnp->cn_nameptr, tcnp->cn_namelen, NFS_MAXNAMLEN);
1150 	nfsm_request(fdvp, NFSPROC_RENAME, tcnp->cn_proc, tcnp->cn_cred);
1151 	nfsm_reqdone;
1152 	VTONFS(fdvp)->n_flag |= NMODIFIED;
1153 	VTONFS(tdvp)->n_flag |= NMODIFIED;
1154 	if (fvp->v_type == VDIR) {
1155 		if (tvp != NULL && tvp->v_type == VDIR)
1156 			cache_purge(tdvp);
1157 		cache_purge(fdvp);
1158 	}
1159 out:
1160 	if (tdvp == tvp)
1161 		vrele(tdvp);
1162 	else
1163 		vput(tdvp);
1164 	if (tvp)
1165 		vput(tvp);
1166 	vrele(fdvp);
1167 	vrele(fvp);
1168 	/*
1169 	 * Kludge: Map ENOENT => 0 assuming that it is a reply to a retry.
1170 	 */
1171 	if (error == ENOENT)
1172 		error = 0;
1173 	return (error);
1174 }
1175 
1176 /*
1177  * nfs file rename rpc called from nfs_remove() above
1178  */
1179 int
1180 nfs_renameit(sdvp, scnp, sp)
1181 	struct vnode *sdvp;
1182 	struct componentname *scnp;
1183 	register struct sillyrename *sp;
1184 {
1185 	register u_long *tl;
1186 	register caddr_t cp;
1187 	register long t2;
1188 	caddr_t bpos, dpos;
1189 	int error = 0;
1190 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
1191 
1192 	nfsstats.rpccnt[NFSPROC_RENAME]++;
1193 	nfsm_reqhead(sdvp, NFSPROC_RENAME,
1194 		(NFSX_FH+NFSX_UNSIGNED)*2+nfsm_rndup(scnp->cn_namelen)+
1195 		nfsm_rndup(sp->s_namlen));
1196 	nfsm_fhtom(sdvp);
1197 	nfsm_strtom(scnp->cn_nameptr, scnp->cn_namelen, NFS_MAXNAMLEN);
1198 	nfsm_fhtom(sdvp);
1199 	nfsm_strtom(sp->s_name, sp->s_namlen, NFS_MAXNAMLEN);
1200 	nfsm_request(sdvp, NFSPROC_RENAME, scnp->cn_proc, scnp->cn_cred);
1201 	nfsm_reqdone;
1202 	FREE(scnp->cn_pnbuf, M_NAMEI);
1203 	VTONFS(sdvp)->n_flag |= NMODIFIED;
1204 	return (error);
1205 }
1206 
1207 /*
1208  * nfs hard link create call
1209  */
1210 int
1211 nfs_link(ap)
1212 	struct vop_link_args /* {
1213 		struct vnode *a_vp;
1214 		struct vnode *a_tdvp;
1215 		struct componentname *a_cnp;
1216 	} */ *ap;
1217 {
1218 	register struct vnode *vp = ap->a_vp;
1219 	register struct vnode *tdvp = ap->a_tdvp;
1220 	register struct componentname *cnp = ap->a_cnp;
1221 	register u_long *tl;
1222 	register caddr_t cp;
1223 	register long t2;
1224 	caddr_t bpos, dpos;
1225 	int error = 0;
1226 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
1227 
1228 	if (vp->v_mount != tdvp->v_mount) {
1229 		/*VOP_ABORTOP(vp, cnp);*/
1230 		if (tdvp == vp)
1231 			vrele(vp);
1232 		else
1233 			vput(vp);
1234 		return (EXDEV);
1235 	}
1236 
1237 	nfsstats.rpccnt[NFSPROC_LINK]++;
1238 	nfsm_reqhead(tdvp, NFSPROC_LINK,
1239 		NFSX_FH*2+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen));
1240 	nfsm_fhtom(tdvp);
1241 	nfsm_fhtom(vp);
1242 	nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
1243 	nfsm_request(tdvp, NFSPROC_LINK, cnp->cn_proc, cnp->cn_cred);
1244 	nfsm_reqdone;
1245 	FREE(cnp->cn_pnbuf, M_NAMEI);
1246 	VTONFS(tdvp)->n_attrstamp = 0;
1247 	VTONFS(vp)->n_flag |= NMODIFIED;
1248 	vrele(vp);
1249 	/*
1250 	 * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry.
1251 	 */
1252 	if (error == EEXIST)
1253 		error = 0;
1254 	return (error);
1255 }
1256 
1257 /*
1258  * nfs symbolic link create call
1259  */
1260 /* start here */
1261 int
1262 nfs_symlink(ap)
1263 	struct vop_symlink_args /* {
1264 		struct vnode *a_dvp;
1265 		struct vnode **a_vpp;
1266 		struct componentname *a_cnp;
1267 		struct vattr *a_vap;
1268 		char *a_target;
1269 	} */ *ap;
1270 {
1271 	register struct vnode *dvp = ap->a_dvp;
1272 	register struct vattr *vap = ap->a_vap;
1273 	register struct componentname *cnp = ap->a_cnp;
1274 	register struct nfsv2_sattr *sp;
1275 	register u_long *tl;
1276 	register caddr_t cp;
1277 	register long t2;
1278 	caddr_t bpos, dpos;
1279 	int slen, error = 0, isnq;
1280 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
1281 
1282 	nfsstats.rpccnt[NFSPROC_SYMLINK]++;
1283 	slen = strlen(ap->a_target);
1284 	isnq = (VFSTONFS(dvp->v_mount)->nm_flag & NFSMNT_NQNFS);
1285 	nfsm_reqhead(dvp, NFSPROC_SYMLINK, NFSX_FH+2*NFSX_UNSIGNED+
1286 	    nfsm_rndup(cnp->cn_namelen)+nfsm_rndup(slen)+NFSX_SATTR(isnq));
1287 	nfsm_fhtom(dvp);
1288 	nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
1289 	nfsm_strtom(ap->a_target, slen, NFS_MAXPATHLEN);
1290 	nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR(isnq));
1291 	sp->sa_mode = vtonfs_mode(VLNK, vap->va_mode);
1292 	sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid);
1293 	sp->sa_gid = txdr_unsigned(cnp->cn_cred->cr_gid);
1294 	if (isnq) {
1295 		quad_t qval = -1;
1296 
1297 		txdr_hyper(&qval, &sp->sa_nqsize);
1298 		sp->sa_nqflags = 0;
1299 		txdr_nqtime(&vap->va_atime, &sp->sa_nqatime);
1300 		txdr_nqtime(&vap->va_mtime, &sp->sa_nqmtime);
1301 	} else {
1302 		sp->sa_nfssize = -1;
1303 		txdr_nfstime(&vap->va_atime, &sp->sa_nfsatime);
1304 		txdr_nfstime(&vap->va_mtime, &sp->sa_nfsmtime);
1305 	}
1306 	nfsm_request(dvp, NFSPROC_SYMLINK, cnp->cn_proc, cnp->cn_cred);
1307 	nfsm_reqdone;
1308 	FREE(cnp->cn_pnbuf, M_NAMEI);
1309 	VTONFS(dvp)->n_flag |= NMODIFIED;
1310 	vrele(dvp);
1311 	/*
1312 	 * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry.
1313 	 */
1314 	if (error == EEXIST)
1315 		error = 0;
1316 	return (error);
1317 }
1318 
1319 /*
1320  * nfs make dir call
1321  */
1322 int
1323 nfs_mkdir(ap)
1324 	struct vop_mkdir_args /* {
1325 		struct vnode *a_dvp;
1326 		struct vnode **a_vpp;
1327 		struct componentname *a_cnp;
1328 		struct vattr *a_vap;
1329 	} */ *ap;
1330 {
1331 	register struct vnode *dvp = ap->a_dvp;
1332 	register struct vattr *vap = ap->a_vap;
1333 	register struct componentname *cnp = ap->a_cnp;
1334 	register struct vnode **vpp = ap->a_vpp;
1335 	register struct nfsv2_sattr *sp;
1336 	register u_long *tl;
1337 	register caddr_t cp;
1338 	register long t1, t2;
1339 	register int len;
1340 	caddr_t bpos, dpos, cp2;
1341 	int error = 0, firsttry = 1, isnq;
1342 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
1343 
1344 	len = cnp->cn_namelen;
1345 	isnq = (VFSTONFS(dvp->v_mount)->nm_flag & NFSMNT_NQNFS);
1346 	nfsstats.rpccnt[NFSPROC_MKDIR]++;
1347 	nfsm_reqhead(dvp, NFSPROC_MKDIR,
1348 	  NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len)+NFSX_SATTR(isnq));
1349 	nfsm_fhtom(dvp);
1350 	nfsm_strtom(cnp->cn_nameptr, len, NFS_MAXNAMLEN);
1351 	nfsm_build(sp, struct nfsv2_sattr *, NFSX_SATTR(isnq));
1352 	sp->sa_mode = vtonfs_mode(VDIR, vap->va_mode);
1353 	sp->sa_uid = txdr_unsigned(cnp->cn_cred->cr_uid);
1354 	sp->sa_gid = txdr_unsigned(cnp->cn_cred->cr_gid);
1355 	if (isnq) {
1356 		quad_t qval = -1;
1357 
1358 		txdr_hyper(&qval, &sp->sa_nqsize);
1359 		sp->sa_nqflags = 0;
1360 		txdr_nqtime(&vap->va_atime, &sp->sa_nqatime);
1361 		txdr_nqtime(&vap->va_mtime, &sp->sa_nqmtime);
1362 	} else {
1363 		sp->sa_nfssize = -1;
1364 		txdr_nfstime(&vap->va_atime, &sp->sa_nfsatime);
1365 		txdr_nfstime(&vap->va_mtime, &sp->sa_nfsmtime);
1366 	}
1367 	nfsm_request(dvp, NFSPROC_MKDIR, cnp->cn_proc, cnp->cn_cred);
1368 	nfsm_mtofh(dvp, *vpp);
1369 	nfsm_reqdone;
1370 	VTONFS(dvp)->n_flag |= NMODIFIED;
1371 	/*
1372 	 * Kludge: Map EEXIST => 0 assuming that you have a reply to a retry
1373 	 * if we can succeed in looking up the directory.
1374 	 * "firsttry" is necessary since the macros may "goto nfsmout" which
1375 	 * is above the if on errors. (Ugh)
1376 	 */
1377 	if (error == EEXIST && firsttry) {
1378 		firsttry = 0;
1379 		error = 0;
1380 		nfsstats.rpccnt[NFSPROC_LOOKUP]++;
1381 		*vpp = NULL;
1382 		nfsm_reqhead(dvp, NFSPROC_LOOKUP,
1383 		    NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len));
1384 		nfsm_fhtom(dvp);
1385 		nfsm_strtom(cnp->cn_nameptr, len, NFS_MAXNAMLEN);
1386 		nfsm_request(dvp, NFSPROC_LOOKUP, cnp->cn_proc, cnp->cn_cred);
1387 		nfsm_mtofh(dvp, *vpp);
1388 		if ((*vpp)->v_type != VDIR) {
1389 			vput(*vpp);
1390 			error = EEXIST;
1391 		}
1392 		m_freem(mrep);
1393 	}
1394 	FREE(cnp->cn_pnbuf, M_NAMEI);
1395 	vrele(dvp);
1396 	return (error);
1397 }
1398 
1399 /*
1400  * nfs remove directory call
1401  */
1402 int
1403 nfs_rmdir(ap)
1404 	struct vop_rmdir_args /* {
1405 		struct vnode *a_dvp;
1406 		struct vnode *a_vp;
1407 		struct componentname *a_cnp;
1408 	} */ *ap;
1409 {
1410 	register struct vnode *vp = ap->a_vp;
1411 	register struct vnode *dvp = ap->a_dvp;
1412 	register struct componentname *cnp = ap->a_cnp;
1413 	register u_long *tl;
1414 	register caddr_t cp;
1415 	register long t2;
1416 	caddr_t bpos, dpos;
1417 	int error = 0;
1418 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
1419 
1420 	if (dvp == vp) {
1421 		vrele(dvp);
1422 		vrele(dvp);
1423 		FREE(cnp->cn_pnbuf, M_NAMEI);
1424 		return (EINVAL);
1425 	}
1426 	nfsstats.rpccnt[NFSPROC_RMDIR]++;
1427 	nfsm_reqhead(dvp, NFSPROC_RMDIR,
1428 		NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(cnp->cn_namelen));
1429 	nfsm_fhtom(dvp);
1430 	nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
1431 	nfsm_request(dvp, NFSPROC_RMDIR, cnp->cn_proc, cnp->cn_cred);
1432 	nfsm_reqdone;
1433 	FREE(cnp->cn_pnbuf, M_NAMEI);
1434 	VTONFS(dvp)->n_flag |= NMODIFIED;
1435 	cache_purge(dvp);
1436 	cache_purge(vp);
1437 	vrele(vp);
1438 	vrele(dvp);
1439 	/*
1440 	 * Kludge: Map ENOENT => 0 assuming that you have a reply to a retry.
1441 	 */
1442 	if (error == ENOENT)
1443 		error = 0;
1444 	return (error);
1445 }
1446 
1447 /*
1448  * nfs readdir call
1449  * Although cookie is defined as opaque, I translate it to/from net byte
1450  * order so that it looks more sensible. This appears consistent with the
1451  * Ultrix implementation of NFS.
1452  */
1453 int
1454 nfs_readdir(ap)
1455 	struct vop_readdir_args /* {
1456 		struct vnode *a_vp;
1457 		struct uio *a_uio;
1458 		struct ucred *a_cred;
1459 	} */ *ap;
1460 {
1461 	register struct vnode *vp = ap->a_vp;
1462 	register struct nfsnode *np = VTONFS(vp);
1463 	register struct uio *uio = ap->a_uio;
1464 	int tresid, error;
1465 	struct vattr vattr;
1466 
1467 	if (vp->v_type != VDIR)
1468 		return (EPERM);
1469 	/*
1470 	 * First, check for hit on the EOF offset cache
1471 	 */
1472 	if (uio->uio_offset != 0 && uio->uio_offset == np->n_direofoffset &&
1473 	    (np->n_flag & NMODIFIED) == 0) {
1474 		if (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) {
1475 			if (NQNFS_CKCACHABLE(vp, NQL_READ)) {
1476 				nfsstats.direofcache_hits++;
1477 				return (0);
1478 			}
1479 		} else if (VOP_GETATTR(vp, &vattr, ap->a_cred, uio->uio_procp) == 0 &&
1480 			np->n_mtime == vattr.va_mtime.ts_sec) {
1481 			nfsstats.direofcache_hits++;
1482 			return (0);
1483 		}
1484 	}
1485 
1486 	/*
1487 	 * Call nfs_bioread() to do the real work.
1488 	 */
1489 	tresid = uio->uio_resid;
1490 	error = nfs_bioread(vp, uio, 0, ap->a_cred);
1491 
1492 	if (!error && uio->uio_resid == tresid)
1493 		nfsstats.direofcache_misses++;
1494 	return (error);
1495 }
1496 
1497 /*
1498  * Readdir rpc call.
1499  * Called from below the buffer cache by nfs_doio().
1500  */
1501 int
1502 nfs_readdirrpc(vp, uiop, cred)
1503 	register struct vnode *vp;
1504 	struct uio *uiop;
1505 	struct ucred *cred;
1506 {
1507 	register long len;
1508 	register struct dirent *dp;
1509 	register u_long *tl;
1510 	register caddr_t cp;
1511 	register long t1;
1512 	long tlen, lastlen;
1513 	caddr_t bpos, dpos, cp2;
1514 	int error = 0;
1515 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
1516 	struct mbuf *md2;
1517 	caddr_t dpos2;
1518 	int siz;
1519 	int more_dirs = 1;
1520 	u_long off, savoff;
1521 	struct dirent *savdp;
1522 	struct nfsmount *nmp;
1523 	struct nfsnode *np = VTONFS(vp);
1524 	long tresid;
1525 
1526 	nmp = VFSTONFS(vp->v_mount);
1527 	tresid = uiop->uio_resid;
1528 	/*
1529 	 * Loop around doing readdir rpc's of size uio_resid or nm_rsize,
1530 	 * whichever is smaller, truncated to a multiple of NFS_DIRBLKSIZ.
1531 	 * The stopping criteria is EOF or buffer full.
1532 	 */
1533 	while (more_dirs && uiop->uio_resid >= NFS_DIRBLKSIZ) {
1534 		nfsstats.rpccnt[NFSPROC_READDIR]++;
1535 		nfsm_reqhead(vp, NFSPROC_READDIR,
1536 			NFSX_FH + 2 * NFSX_UNSIGNED);
1537 		nfsm_fhtom(vp);
1538 		nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED);
1539 		off = (u_long)uiop->uio_offset;
1540 		*tl++ = txdr_unsigned(off);
1541 		*tl = txdr_unsigned(((uiop->uio_resid > nmp->nm_rsize) ?
1542 			nmp->nm_rsize : uiop->uio_resid) & ~(NFS_DIRBLKSIZ-1));
1543 		nfsm_request(vp, NFSPROC_READDIR, uiop->uio_procp, cred);
1544 		siz = 0;
1545 		nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
1546 		more_dirs = fxdr_unsigned(int, *tl);
1547 
1548 		/* Save the position so that we can do nfsm_mtouio() later */
1549 		dpos2 = dpos;
1550 		md2 = md;
1551 
1552 		/* loop thru the dir entries, doctoring them to 4bsd form */
1553 #ifdef lint
1554 		dp = (struct dirent *)0;
1555 #endif /* lint */
1556 		while (more_dirs && siz < uiop->uio_resid) {
1557 			savoff = off;		/* Hold onto offset and dp */
1558 			savdp = dp;
1559 			nfsm_dissecton(tl, u_long *, 2 * NFSX_UNSIGNED);
1560 			dp = (struct dirent *)tl;
1561 			dp->d_fileno = fxdr_unsigned(u_long, *tl++);
1562 			len = fxdr_unsigned(int, *tl);
1563 			if (len <= 0 || len > NFS_MAXNAMLEN) {
1564 				error = EBADRPC;
1565 				m_freem(mrep);
1566 				goto nfsmout;
1567 			}
1568 			dp->d_namlen = (u_char)len;
1569 			dp->d_type = DT_UNKNOWN;
1570 			nfsm_adv(len);		/* Point past name */
1571 			tlen = nfsm_rndup(len);
1572 			/*
1573 			 * This should not be necessary, but some servers have
1574 			 * broken XDR such that these bytes are not null filled.
1575 			 */
1576 			if (tlen != len) {
1577 				*dpos = '\0';	/* Null-terminate */
1578 				nfsm_adv(tlen - len);
1579 				len = tlen;
1580 			}
1581 			nfsm_dissecton(tl, u_long *, 2 * NFSX_UNSIGNED);
1582 			off = fxdr_unsigned(u_long, *tl);
1583 			*tl++ = 0;	/* Ensures null termination of name */
1584 			more_dirs = fxdr_unsigned(int, *tl);
1585 			dp->d_reclen = len + 4 * NFSX_UNSIGNED;
1586 			siz += dp->d_reclen;
1587 		}
1588 		/*
1589 		 * If at end of rpc data, get the eof boolean
1590 		 */
1591 		if (!more_dirs) {
1592 			nfsm_dissecton(tl, u_long *, NFSX_UNSIGNED);
1593 			more_dirs = (fxdr_unsigned(int, *tl) == 0);
1594 
1595 			/*
1596 			 * If at EOF, cache directory offset
1597 			 */
1598 			if (!more_dirs)
1599 				np->n_direofoffset = off;
1600 		}
1601 		/*
1602 		 * If there is too much to fit in the data buffer, use savoff and
1603 		 * savdp to trim off the last record.
1604 		 * --> we are not at eof
1605 		 */
1606 		if (siz > uiop->uio_resid) {
1607 			off = savoff;
1608 			siz -= dp->d_reclen;
1609 			dp = savdp;
1610 			more_dirs = 0;	/* Paranoia */
1611 		}
1612 		if (siz > 0) {
1613 			lastlen = dp->d_reclen;
1614 			md = md2;
1615 			dpos = dpos2;
1616 			nfsm_mtouio(uiop, siz);
1617 			uiop->uio_offset = (off_t)off;
1618 		} else
1619 			more_dirs = 0;	/* Ugh, never happens, but in case.. */
1620 		m_freem(mrep);
1621 	}
1622 	/*
1623 	 * Fill last record, iff any, out to a multiple of NFS_DIRBLKSIZ
1624 	 * by increasing d_reclen for the last record.
1625 	 */
1626 	if (uiop->uio_resid < tresid) {
1627 		len = uiop->uio_resid & (NFS_DIRBLKSIZ - 1);
1628 		if (len > 0) {
1629 			dp = (struct dirent *)
1630 				(uiop->uio_iov->iov_base - lastlen);
1631 			dp->d_reclen += len;
1632 			uiop->uio_iov->iov_base += len;
1633 			uiop->uio_iov->iov_len -= len;
1634 			uiop->uio_resid -= len;
1635 		}
1636 	}
1637 nfsmout:
1638 	return (error);
1639 }
1640 
1641 /*
1642  * Nqnfs readdir_and_lookup RPC. Used in place of nfs_readdirrpc().
1643  */
1644 int
1645 nfs_readdirlookrpc(vp, uiop, cred)
1646 	struct vnode *vp;
1647 	register struct uio *uiop;
1648 	struct ucred *cred;
1649 {
1650 	register int len;
1651 	register struct dirent *dp;
1652 	register u_long *tl;
1653 	register caddr_t cp;
1654 	register long t1;
1655 	caddr_t bpos, dpos, cp2;
1656 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
1657 	struct nameidata nami, *ndp = &nami;
1658 	struct componentname *cnp = &ndp->ni_cnd;
1659 	u_long off, endoff, fileno;
1660 	time_t reqtime, ltime;
1661 	struct nfsmount *nmp;
1662 	struct nfsnode *np, *tp;
1663 	struct vnode *newvp;
1664 	nfsv2fh_t *fhp;
1665 	u_quad_t frev;
1666 	int error = 0, tlen, more_dirs = 1, tresid, doit, bigenough, i;
1667 	int cachable;
1668 
1669 	if (uiop->uio_iovcnt != 1)
1670 		panic("nfs rdirlook");
1671 	nmp = VFSTONFS(vp->v_mount);
1672 	tresid = uiop->uio_resid;
1673 	ndp->ni_dvp = vp;
1674 	newvp = NULLVP;
1675 	/*
1676 	 * Loop around doing readdir rpc's of size uio_resid or nm_rsize,
1677 	 * whichever is smaller, truncated to a multiple of NFS_DIRBLKSIZ.
1678 	 * The stopping criteria is EOF or buffer full.
1679 	 */
1680 	while (more_dirs && uiop->uio_resid >= NFS_DIRBLKSIZ) {
1681 		nfsstats.rpccnt[NQNFSPROC_READDIRLOOK]++;
1682 		nfsm_reqhead(vp, NQNFSPROC_READDIRLOOK,
1683 			NFSX_FH + 3 * NFSX_UNSIGNED);
1684 		nfsm_fhtom(vp);
1685  		nfsm_build(tl, u_long *, 3 * NFSX_UNSIGNED);
1686 		off = (u_long)uiop->uio_offset;
1687 		*tl++ = txdr_unsigned(off);
1688 		*tl++ = txdr_unsigned(((uiop->uio_resid > nmp->nm_rsize) ?
1689 			nmp->nm_rsize : uiop->uio_resid) & ~(NFS_DIRBLKSIZ-1));
1690 		if (nmp->nm_flag & NFSMNT_NQLOOKLEASE)
1691 			*tl = txdr_unsigned(nmp->nm_leaseterm);
1692 		else
1693 			*tl = 0;
1694 		reqtime = time.tv_sec;
1695 		nfsm_request(vp, NQNFSPROC_READDIRLOOK, uiop->uio_procp, cred);
1696 		nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
1697 		more_dirs = fxdr_unsigned(int, *tl);
1698 
1699 		/* loop thru the dir entries, doctoring them to 4bsd form */
1700 		bigenough = 1;
1701 		while (more_dirs && bigenough) {
1702 			doit = 1;
1703 			nfsm_dissect(tl, u_long *, 4 * NFSX_UNSIGNED);
1704 			if (nmp->nm_flag & NFSMNT_NQLOOKLEASE) {
1705 				cachable = fxdr_unsigned(int, *tl++);
1706 				ltime = reqtime + fxdr_unsigned(int, *tl++);
1707 				fxdr_hyper(tl, &frev);
1708 			}
1709 			nfsm_dissect(fhp, nfsv2fh_t *, NFSX_FH);
1710 			if (!bcmp(VTONFS(vp)->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) {
1711 				VREF(vp);
1712 				newvp = vp;
1713 				np = VTONFS(vp);
1714 			} else {
1715 				if (error = nfs_nget(vp->v_mount, fhp, &np))
1716 					doit = 0;
1717 				newvp = NFSTOV(np);
1718 			}
1719 			if (error = nfs_loadattrcache(&newvp, &md, &dpos,
1720 				(struct vattr *)0))
1721 				doit = 0;
1722 			nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
1723 			fileno = fxdr_unsigned(u_long, *tl++);
1724 			len = fxdr_unsigned(int, *tl);
1725 			if (len <= 0 || len > NFS_MAXNAMLEN) {
1726 				error = EBADRPC;
1727 				m_freem(mrep);
1728 				goto nfsmout;
1729 			}
1730 			tlen = (len + 4) & ~0x3;
1731 			if ((tlen + DIRHDSIZ) > uiop->uio_resid)
1732 				bigenough = 0;
1733 			if (bigenough && doit) {
1734 				dp = (struct dirent *)uiop->uio_iov->iov_base;
1735 				dp->d_fileno = fileno;
1736 				dp->d_namlen = len;
1737 				dp->d_reclen = tlen + DIRHDSIZ;
1738 				dp->d_type =
1739 				    IFTODT(VTTOIF(np->n_vattr.va_type));
1740 				uiop->uio_resid -= DIRHDSIZ;
1741 				uiop->uio_iov->iov_base += DIRHDSIZ;
1742 				uiop->uio_iov->iov_len -= DIRHDSIZ;
1743 				cnp->cn_nameptr = uiop->uio_iov->iov_base;
1744 				cnp->cn_namelen = len;
1745 				ndp->ni_vp = newvp;
1746 				nfsm_mtouio(uiop, len);
1747 				cp = uiop->uio_iov->iov_base;
1748 				tlen -= len;
1749 				for (i = 0; i < tlen; i++)
1750 					*cp++ = '\0';
1751 				uiop->uio_iov->iov_base += tlen;
1752 				uiop->uio_iov->iov_len -= tlen;
1753 				uiop->uio_resid -= tlen;
1754 				cnp->cn_hash = 0;
1755 				for (cp = cnp->cn_nameptr, i = 1; i <= len; i++, cp++)
1756 					cnp->cn_hash += (unsigned char)*cp * i;
1757 				if ((nmp->nm_flag & NFSMNT_NQLOOKLEASE) &&
1758 					ltime > time.tv_sec)
1759 					nqnfs_clientlease(nmp, np, NQL_READ,
1760 						cachable, ltime, frev);
1761 				if (cnp->cn_namelen <= NCHNAMLEN)
1762 					cache_enter(ndp->ni_dvp, ndp->ni_vp, cnp);
1763 			} else {
1764 				nfsm_adv(nfsm_rndup(len));
1765 			}
1766 			if (newvp != NULLVP) {
1767 				vrele(newvp);
1768 				newvp = NULLVP;
1769 			}
1770 			nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
1771 			if (bigenough)
1772 				endoff = off = fxdr_unsigned(u_long, *tl++);
1773 			else
1774 				endoff = fxdr_unsigned(u_long, *tl++);
1775 			more_dirs = fxdr_unsigned(int, *tl);
1776 		}
1777 		/*
1778 		 * If at end of rpc data, get the eof boolean
1779 		 */
1780 		if (!more_dirs) {
1781 			nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
1782 			more_dirs = (fxdr_unsigned(int, *tl) == 0);
1783 
1784 			/*
1785 			 * If at EOF, cache directory offset
1786 			 */
1787 			if (!more_dirs)
1788 				VTONFS(vp)->n_direofoffset = endoff;
1789 		}
1790 		if (uiop->uio_resid < tresid)
1791 			uiop->uio_offset = (off_t)off;
1792 		else
1793 			more_dirs = 0;
1794 		m_freem(mrep);
1795 	}
1796 	/*
1797 	 * Fill last record, iff any, out to a multiple of NFS_DIRBLKSIZ
1798 	 * by increasing d_reclen for the last record.
1799 	 */
1800 	if (uiop->uio_resid < tresid) {
1801 		len = uiop->uio_resid & (NFS_DIRBLKSIZ - 1);
1802 		if (len > 0) {
1803 			dp->d_reclen += len;
1804 			uiop->uio_iov->iov_base += len;
1805 			uiop->uio_iov->iov_len -= len;
1806 			uiop->uio_resid -= len;
1807 		}
1808 	}
1809 nfsmout:
1810 	if (newvp != NULLVP)
1811 		vrele(newvp);
1812 	return (error);
1813 }
1814 static char hextoasc[] = "0123456789abcdef";
1815 
1816 /*
1817  * Silly rename. To make the NFS filesystem that is stateless look a little
1818  * more like the "ufs" a remove of an active vnode is translated to a rename
1819  * to a funny looking filename that is removed by nfs_inactive on the
1820  * nfsnode. There is the potential for another process on a different client
1821  * to create the same funny name between the nfs_lookitup() fails and the
1822  * nfs_rename() completes, but...
1823  */
1824 int
1825 nfs_sillyrename(dvp, vp, cnp)
1826 	struct vnode *dvp, *vp;
1827 	struct componentname *cnp;
1828 {
1829 	register struct nfsnode *np;
1830 	register struct sillyrename *sp;
1831 	int error;
1832 	short pid;
1833 
1834 	cache_purge(dvp);
1835 	np = VTONFS(vp);
1836 #ifdef SILLYSEPARATE
1837 	MALLOC(sp, struct sillyrename *, sizeof (struct sillyrename),
1838 		M_NFSREQ, M_WAITOK);
1839 #else
1840 	sp = &np->n_silly;
1841 #endif
1842 	sp->s_cred = crdup(cnp->cn_cred);
1843 	sp->s_dvp = dvp;
1844 	VREF(dvp);
1845 
1846 	/* Fudge together a funny name */
1847 	pid = cnp->cn_proc->p_pid;
1848 	bcopy(".nfsAxxxx4.4", sp->s_name, 13);
1849 	sp->s_namlen = 12;
1850 	sp->s_name[8] = hextoasc[pid & 0xf];
1851 	sp->s_name[7] = hextoasc[(pid >> 4) & 0xf];
1852 	sp->s_name[6] = hextoasc[(pid >> 8) & 0xf];
1853 	sp->s_name[5] = hextoasc[(pid >> 12) & 0xf];
1854 
1855 	/* Try lookitups until we get one that isn't there */
1856 	while (nfs_lookitup(sp, (nfsv2fh_t *)0, cnp->cn_proc) == 0) {
1857 		sp->s_name[4]++;
1858 		if (sp->s_name[4] > 'z') {
1859 			error = EINVAL;
1860 			goto bad;
1861 		}
1862 	}
1863 	if (error = nfs_renameit(dvp, cnp, sp))
1864 		goto bad;
1865 	nfs_lookitup(sp, &np->n_fh, cnp->cn_proc);
1866 	np->n_sillyrename = sp;
1867 	return (0);
1868 bad:
1869 	vrele(sp->s_dvp);
1870 	crfree(sp->s_cred);
1871 #ifdef SILLYSEPARATE
1872 	free((caddr_t)sp, M_NFSREQ);
1873 #endif
1874 	return (error);
1875 }
1876 
1877 /*
1878  * Look up a file name for silly rename stuff.
1879  * Just like nfs_lookup() except that it doesn't load returned values
1880  * into the nfsnode table.
1881  * If fhp != NULL it copies the returned file handle out
1882  */
1883 int
1884 nfs_lookitup(sp, fhp, procp)
1885 	register struct sillyrename *sp;
1886 	nfsv2fh_t *fhp;
1887 	struct proc *procp;
1888 {
1889 	register struct vnode *vp = sp->s_dvp;
1890 	register u_long *tl;
1891 	register caddr_t cp;
1892 	register long t1, t2;
1893 	caddr_t bpos, dpos, cp2;
1894 	u_long xid;
1895 	int error = 0, isnq;
1896 	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
1897 	long len;
1898 
1899 	isnq = (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS);
1900 	nfsstats.rpccnt[NFSPROC_LOOKUP]++;
1901 	len = sp->s_namlen;
1902 	nfsm_reqhead(vp, NFSPROC_LOOKUP, NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len));
1903 	if (isnq) {
1904 		nfsm_build(tl, u_long *, NFSX_UNSIGNED);
1905 		*tl = 0;
1906 	}
1907 	nfsm_fhtom(vp);
1908 	nfsm_strtom(sp->s_name, len, NFS_MAXNAMLEN);
1909 	nfsm_request(vp, NFSPROC_LOOKUP, procp, sp->s_cred);
1910 	if (fhp != NULL) {
1911 		if (isnq)
1912 			nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
1913 		nfsm_dissect(cp, caddr_t, NFSX_FH);
1914 		bcopy(cp, (caddr_t)fhp, NFSX_FH);
1915 	}
1916 	nfsm_reqdone;
1917 	return (error);
1918 }
1919 
1920 /*
1921  * Kludge City..
1922  * - make nfs_bmap() essentially a no-op that does no translation
1923  * - do nfs_strategy() by faking physical I/O with nfs_readrpc/nfs_writerpc
1924  *   after mapping the physical addresses into Kernel Virtual space in the
1925  *   nfsiobuf area.
1926  *   (Maybe I could use the process's page mapping, but I was concerned that
1927  *    Kernel Write might not be enabled and also figured copyout() would do
1928  *    a lot more work than bcopy() and also it currently happens in the
1929  *    context of the swapper process (2).
1930  */
1931 int
1932 nfs_bmap(ap)
1933 	struct vop_bmap_args /* {
1934 		struct vnode *a_vp;
1935 		daddr_t  a_bn;
1936 		struct vnode **a_vpp;
1937 		daddr_t *a_bnp;
1938 		int *a_runp;
1939 	} */ *ap;
1940 {
1941 	register struct vnode *vp = ap->a_vp;
1942 
1943 	if (ap->a_vpp != NULL)
1944 		*ap->a_vpp = vp;
1945 	if (ap->a_bnp != NULL)
1946 		*ap->a_bnp = ap->a_bn * btodb(vp->v_mount->mnt_stat.f_iosize);
1947 	return (0);
1948 }
1949 
1950 /*
1951  * Strategy routine for phys. i/o
1952  * If the biod's are running, queue a request
1953  * otherwise just call nfs_doio() to get it done
1954  */
1955 int
1956 nfs_strategy(ap)
1957 	struct vop_strategy_args /* {
1958 		struct buf *a_bp;
1959 	} */ *ap;
1960 {
1961 	register struct buf *bp = ap->a_bp;
1962 	register int i;
1963 	int error = 0;
1964 	int fnd = 0;
1965 
1966 	/*
1967 	 * Set b_proc. It seems a bit silly to do it here, but since bread()
1968 	 * doesn't set it, I will.
1969 	 * Set b_proc == NULL for asynchronous ops, since these may still
1970 	 * be hanging about after the process terminates.
1971 	 */
1972 	if ((bp->b_flags & B_PHYS) == 0) {
1973 		if (bp->b_flags & B_ASYNC)
1974 			bp->b_proc = (struct proc *)0;
1975 		else
1976 			bp->b_proc = curproc;
1977 	}
1978 	/*
1979 	 * If the op is asynchronous and an i/o daemon is waiting
1980 	 * queue the request, wake it up and wait for completion
1981 	 * otherwise just do it ourselves.
1982 	 */
1983 	if ((bp->b_flags & B_ASYNC) == 0 || nfs_numasync == 0)
1984 		return (nfs_doio(bp));
1985 	for (i = 0; i < NFS_MAXASYNCDAEMON; i++) {
1986 		if (nfs_iodwant[i]) {
1987 			queue_enter_tail(&nfs_bufq, bp, struct buf *, b_freelist);
1988 			fnd++;
1989 			wakeup((caddr_t)&nfs_iodwant[i]);
1990 			break;
1991 		}
1992 	}
1993 	if (!fnd)
1994 		error = nfs_doio(bp);
1995 	return (error);
1996 }
1997 
1998 /*
1999  * Fun and games with i/o
2000  * Essentially play ubasetup() and disk interrupt service routine by
2001  * mapping the data buffer into kernel virtual space and doing the
2002  * nfs read or write rpc's from it.
2003  * If the nfsiod's are not running, this is just called from nfs_strategy(),
2004  * otherwise it is called by the nfsiods to do what would normally be
2005  * partially disk interrupt driven.
2006  */
2007 int
2008 nfs_doio(bp)
2009 	register struct buf *bp;
2010 {
2011 	register struct uio *uiop;
2012 	register struct vnode *vp;
2013 	struct nfsnode *np;
2014 	struct ucred *cr;
2015 	int error;
2016 	struct uio uio;
2017 	struct iovec io;
2018 
2019 	vp = bp->b_vp;
2020 	np = VTONFS(vp);
2021 	uiop = &uio;
2022 	uiop->uio_iov = &io;
2023 	uiop->uio_iovcnt = 1;
2024 	uiop->uio_segflg = UIO_SYSSPACE;
2025 	uiop->uio_procp = bp->b_proc;
2026 
2027 	/*
2028 	 * For phys i/o, map the b_addr into kernel virtual space using
2029 	 * the Nfsiomap pte's
2030 	 * Also, add a temporary b_rcred for reading using the process's uid
2031 	 * and a guess at a group
2032 	 */
2033 	if (bp->b_flags & B_PHYS) {
2034 		if (bp->b_flags & B_DIRTY)
2035 			uiop->uio_procp = pageproc;
2036 		cr = crdup(uiop->uio_procp->p_ucred);
2037 		/* mapping was already done by vmapbuf */
2038 		io.iov_base = bp->b_un.b_addr;
2039 
2040 		/*
2041 		 * And do the i/o rpc
2042 		 */
2043 		io.iov_len = uiop->uio_resid = bp->b_bcount;
2044 		uiop->uio_offset = bp->b_blkno * DEV_BSIZE;
2045 		if (bp->b_flags & B_READ) {
2046 			uiop->uio_rw = UIO_READ;
2047 			nfsstats.read_physios++;
2048 			bp->b_error = error = nfs_readrpc(vp, uiop, cr);
2049 			(void) vnode_pager_uncache(vp);
2050 		} else {
2051 			uiop->uio_rw = UIO_WRITE;
2052 			nfsstats.write_physios++;
2053 			bp->b_error = error = nfs_writerpc(vp, uiop, cr, 0);
2054 		}
2055 
2056 		/*
2057 		 * Finally, release pte's used by physical i/o
2058 		 */
2059 		crfree(cr);
2060 	} else {
2061 		if (bp->b_flags & B_READ) {
2062 			io.iov_len = uiop->uio_resid = bp->b_bcount;
2063 			io.iov_base = bp->b_un.b_addr;
2064 			uiop->uio_rw = UIO_READ;
2065 			switch (vp->v_type) {
2066 			case VREG:
2067 				uiop->uio_offset = bp->b_blkno * DEV_BSIZE;
2068 				nfsstats.read_bios++;
2069 				error = nfs_readrpc(vp, uiop, bp->b_rcred);
2070 				break;
2071 			case VLNK:
2072 				uiop->uio_offset = 0;
2073 				nfsstats.readlink_bios++;
2074 				error = nfs_readlinkrpc(vp, uiop, bp->b_rcred);
2075 				break;
2076 			case VDIR:
2077 				uiop->uio_offset = bp->b_lblkno;
2078 				nfsstats.readdir_bios++;
2079 				if (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS)
2080 				    error = nfs_readdirlookrpc(vp, uiop, bp->b_rcred);
2081 				else
2082 				    error = nfs_readdirrpc(vp, uiop, bp->b_rcred);
2083 				/*
2084 				 * Save offset cookie in b_blkno.
2085 				 */
2086 				bp->b_blkno = uiop->uio_offset;
2087 				break;
2088 			};
2089 			bp->b_error = error;
2090 		} else {
2091 			io.iov_len = uiop->uio_resid = bp->b_dirtyend
2092 				- bp->b_dirtyoff;
2093 			uiop->uio_offset = (bp->b_blkno * DEV_BSIZE)
2094 				+ bp->b_dirtyoff;
2095 			io.iov_base = bp->b_un.b_addr + bp->b_dirtyoff;
2096 			uiop->uio_rw = UIO_WRITE;
2097 			nfsstats.write_bios++;
2098 			bp->b_error = error = nfs_writerpc(vp, uiop,
2099 				bp->b_wcred, 0);
2100 			if (error) {
2101 				np->n_error = error;
2102 				np->n_flag |= NWRITEERR;
2103 			}
2104 			bp->b_dirtyoff = bp->b_dirtyend = 0;
2105 		}
2106 	}
2107 	if (error)
2108 		bp->b_flags |= B_ERROR;
2109 	bp->b_resid = uiop->uio_resid;
2110 	biodone(bp);
2111 	return (error);
2112 }
2113 
2114 /*
2115  * Mmap a file
2116  *
2117  * NB Currently unsupported.
2118  */
2119 /* ARGSUSED */
2120 int
2121 nfs_mmap(ap)
2122 	struct vop_mmap_args /* {
2123 		struct vnode *a_vp;
2124 		int  a_fflags;
2125 		struct ucred *a_cred;
2126 		struct proc *a_p;
2127 	} */ *ap;
2128 {
2129 
2130 	return (EINVAL);
2131 }
2132 
2133 /*
2134  * Flush all the blocks associated with a vnode.
2135  * 	Walk through the buffer pool and push any dirty pages
2136  *	associated with the vnode.
2137  */
2138 /* ARGSUSED */
2139 int
2140 nfs_fsync(ap)
2141 	struct vop_fsync_args /* {
2142 		struct vnodeop_desc *a_desc;
2143 		struct vnode * a_vp;
2144 		struct ucred * a_cred;
2145 		int  a_waitfor;
2146 		struct proc * a_p;
2147 	} */ *ap;
2148 {
2149 	register struct vnode *vp = ap->a_vp;
2150 	register struct nfsnode *np = VTONFS(vp);
2151 	register struct buf *bp;
2152 	struct buf *nbp;
2153 	int s, error = 0;
2154 
2155 loop:
2156 	s = splbio();
2157 	for (bp = vp->v_dirtyblkhd.le_next; bp; bp = nbp) {
2158 		nbp = bp->b_vnbufs.qe_next;
2159 		if ((bp->b_flags & B_BUSY))
2160 			continue;
2161 		if ((bp->b_flags & B_DELWRI) == 0)
2162 			panic("nfs_fsync: not dirty");
2163 		bremfree(bp);
2164 		bp->b_flags |= B_BUSY;
2165 		splx(s);
2166 		bawrite(bp);
2167 		goto loop;
2168 	}
2169 	if (ap->a_waitfor == MNT_WAIT) {
2170 		while (vp->v_numoutput) {
2171 			vp->v_flag |= VBWAIT;
2172 			sleep((caddr_t)&vp->v_numoutput, PRIBIO + 1);
2173 		}
2174 #ifdef DIAGNOSTIC
2175 		if (vp->v_dirtyblkhd.le_next) {
2176 			vprint("nfs_fsync: dirty", vp);
2177 			goto loop;
2178 		}
2179 #endif
2180 	}
2181 	splx(s);
2182 	np->n_flag &= ~NMODIFIED;
2183 	if (np->n_flag & NWRITEERR) {
2184 		error = np->n_error;
2185 		np->n_flag &= ~NWRITEERR;
2186 	}
2187 	return (error);
2188 }
2189 
2190 /*
2191  * NFS advisory byte-level locks.
2192  * Currently unsupported.
2193  */
2194 int
2195 nfs_advlock(ap)
2196 	struct vop_advlock_args /* {
2197 		struct vnode *a_vp;
2198 		caddr_t  a_id;
2199 		int  a_op;
2200 		struct flock *a_fl;
2201 		int  a_flags;
2202 	} */ *ap;
2203 {
2204 
2205 	return (EOPNOTSUPP);
2206 }
2207 
2208 /*
2209  * Print out the contents of an nfsnode.
2210  */
2211 int
2212 nfs_print(ap)
2213 	struct vop_print_args /* {
2214 		struct vnode *a_vp;
2215 	} */ *ap;
2216 {
2217 	register struct vnode *vp = ap->a_vp;
2218 	register struct nfsnode *np = VTONFS(vp);
2219 
2220 	printf("tag VT_NFS, fileid %d fsid 0x%x",
2221 		np->n_vattr.va_fileid, np->n_vattr.va_fsid);
2222 #ifdef FIFO
2223 	if (vp->v_type == VFIFO)
2224 		fifo_printinfo(vp);
2225 #endif /* FIFO */
2226 	printf("\n");
2227 }
2228 
2229 /*
2230  * NFS directory offset lookup.
2231  * Currently unsupported.
2232  */
2233 int
2234 nfs_blkatoff(ap)
2235 	struct vop_blkatoff_args /* {
2236 		struct vnode *a_vp;
2237 		off_t a_offset;
2238 		char **a_res;
2239 		struct buf **a_bpp;
2240 	} */ *ap;
2241 {
2242 
2243 	return (EOPNOTSUPP);
2244 }
2245 
2246 /*
2247  * NFS flat namespace allocation.
2248  * Currently unsupported.
2249  */
2250 int
2251 nfs_valloc(ap)
2252 	struct vop_valloc_args /* {
2253 		struct vnode *a_pvp;
2254 		int a_mode;
2255 		struct ucred *a_cred;
2256 		struct vnode **a_vpp;
2257 	} */ *ap;
2258 {
2259 
2260 	return (EOPNOTSUPP);
2261 }
2262 
2263 /*
2264  * NFS flat namespace free.
2265  * Currently unsupported.
2266  */
2267 int
2268 nfs_vfree(ap)
2269 	struct vop_vfree_args /* {
2270 		struct vnode *a_pvp;
2271 		ino_t a_ino;
2272 		int a_mode;
2273 	} */ *ap;
2274 {
2275 
2276 	return (EOPNOTSUPP);
2277 }
2278 
2279 /*
2280  * NFS file truncation.
2281  */
2282 int
2283 nfs_truncate(ap)
2284 	struct vop_truncate_args /* {
2285 		struct vnode *a_vp;
2286 		off_t a_length;
2287 		int a_flags;
2288 		struct ucred *a_cred;
2289 		struct proc *a_p;
2290 	} */ *ap;
2291 {
2292 
2293 	/* Use nfs_setattr */
2294 	printf("nfs_truncate: need to implement!!");
2295 	return (EOPNOTSUPP);
2296 }
2297 
2298 /*
2299  * NFS update.
2300  */
2301 int
2302 nfs_update(ap)
2303 	struct vop_update_args /* {
2304 		struct vnode *a_vp;
2305 		struct timeval *a_ta;
2306 		struct timeval *a_tm;
2307 		int a_waitfor;
2308 	} */ *ap;
2309 {
2310 
2311 	/* Use nfs_setattr */
2312 	printf("nfs_update: need to implement!!");
2313 	return (EOPNOTSUPP);
2314 }
2315 
2316 /*
2317  * nfs special file access vnode op.
2318  * Essentially just get vattr and then imitate iaccess() since the device is
2319  * local to the client.
2320  */
2321 int
2322 nfsspec_access(ap)
2323 	struct vop_access_args /* {
2324 		struct vnode *a_vp;
2325 		int  a_mode;
2326 		struct ucred *a_cred;
2327 		struct proc *a_p;
2328 	} */ *ap;
2329 {
2330 	register struct vattr *vap;
2331 	register gid_t *gp;
2332 	register struct ucred *cred = ap->a_cred;
2333 	mode_t mode = ap->a_mode;
2334 	struct vattr vattr;
2335 	register int i;
2336 	int error;
2337 
2338 	/*
2339 	 * If you're the super-user,
2340 	 * you always get access.
2341 	 */
2342 	if (cred->cr_uid == 0)
2343 		return (0);
2344 	vap = &vattr;
2345 	if (error = VOP_GETATTR(ap->a_vp, vap, cred, ap->a_p))
2346 		return (error);
2347 	/*
2348 	 * Access check is based on only one of owner, group, public.
2349 	 * If not owner, then check group. If not a member of the
2350 	 * group, then check public access.
2351 	 */
2352 	if (cred->cr_uid != vap->va_uid) {
2353 		mode >>= 3;
2354 		gp = cred->cr_groups;
2355 		for (i = 0; i < cred->cr_ngroups; i++, gp++)
2356 			if (vap->va_gid == *gp)
2357 				goto found;
2358 		mode >>= 3;
2359 found:
2360 		;
2361 	}
2362 	return ((vap->va_mode & mode) == mode ? 0 : EACCES);
2363 }
2364 
2365 /*
2366  * Read wrapper for special devices.
2367  */
2368 int
2369 nfsspec_read(ap)
2370 	struct vop_read_args /* {
2371 		struct vnode *a_vp;
2372 		struct uio *a_uio;
2373 		int  a_ioflag;
2374 		struct ucred *a_cred;
2375 	} */ *ap;
2376 {
2377 	register struct nfsnode *np = VTONFS(ap->a_vp);
2378 
2379 	/*
2380 	 * Set access flag.
2381 	 */
2382 	np->n_flag |= NACC;
2383 	np->n_atim = time;
2384 	return (VOCALL(spec_vnodeop_p, VOFFSET(vop_read), ap));
2385 }
2386 
2387 /*
2388  * Write wrapper for special devices.
2389  */
2390 int
2391 nfsspec_write(ap)
2392 	struct vop_write_args /* {
2393 		struct vnode *a_vp;
2394 		struct uio *a_uio;
2395 		int  a_ioflag;
2396 		struct ucred *a_cred;
2397 	} */ *ap;
2398 {
2399 	register struct nfsnode *np = VTONFS(ap->a_vp);
2400 
2401 	/*
2402 	 * Set update flag.
2403 	 */
2404 	np->n_flag |= NUPD;
2405 	np->n_mtim = time;
2406 	return (VOCALL(spec_vnodeop_p, VOFFSET(vop_write), ap));
2407 }
2408 
2409 /*
2410  * Close wrapper for special devices.
2411  *
2412  * Update the times on the nfsnode then do device close.
2413  */
2414 int
2415 nfsspec_close(ap)
2416 	struct vop_close_args /* {
2417 		struct vnode *a_vp;
2418 		int  a_fflag;
2419 		struct ucred *a_cred;
2420 		struct proc *a_p;
2421 	} */ *ap;
2422 {
2423 	register struct vnode *vp = ap->a_vp;
2424 	register struct nfsnode *np = VTONFS(vp);
2425 	struct vattr vattr;
2426 
2427 	if (np->n_flag & (NACC | NUPD)) {
2428 		np->n_flag |= NCHG;
2429 		if (vp->v_usecount == 1 &&
2430 		    (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) {
2431 			VATTR_NULL(&vattr);
2432 			if (np->n_flag & NACC) {
2433 				vattr.va_atime.ts_sec = np->n_atim.tv_sec;
2434 				vattr.va_atime.ts_nsec =
2435 				    np->n_atim.tv_usec * 1000;
2436 			}
2437 			if (np->n_flag & NUPD) {
2438 				vattr.va_mtime.ts_sec = np->n_mtim.tv_sec;
2439 				vattr.va_mtime.ts_nsec =
2440 				    np->n_mtim.tv_usec * 1000;
2441 			}
2442 			(void)VOP_SETATTR(vp, &vattr, ap->a_cred, ap->a_p);
2443 		}
2444 	}
2445 	return (VOCALL(spec_vnodeop_p, VOFFSET(vop_close), ap));
2446 }
2447 
2448 #ifdef FIFO
2449 /*
2450  * Read wrapper for fifos.
2451  */
2452 int
2453 nfsfifo_read(ap)
2454 	struct vop_read_args /* {
2455 		struct vnode *a_vp;
2456 		struct uio *a_uio;
2457 		int  a_ioflag;
2458 		struct ucred *a_cred;
2459 	} */ *ap;
2460 {
2461 	extern int (**fifo_vnodeop_p)();
2462 	register struct nfsnode *np = VTONFS(ap->a_vp);
2463 
2464 	/*
2465 	 * Set access flag.
2466 	 */
2467 	np->n_flag |= NACC;
2468 	np->n_atim = time;
2469 	return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_read), ap));
2470 }
2471 
2472 /*
2473  * Write wrapper for fifos.
2474  */
2475 int
2476 nfsfifo_write(ap)
2477 	struct vop_write_args /* {
2478 		struct vnode *a_vp;
2479 		struct uio *a_uio;
2480 		int  a_ioflag;
2481 		struct ucred *a_cred;
2482 	} */ *ap;
2483 {
2484 	extern int (**fifo_vnodeop_p)();
2485 	register struct nfsnode *np = VTONFS(ap->a_vp);
2486 
2487 	/*
2488 	 * Set update flag.
2489 	 */
2490 	np->n_flag |= NUPD;
2491 	np->n_mtim = time;
2492 	return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_write), ap));
2493 }
2494 
2495 /*
2496  * Close wrapper for fifos.
2497  *
2498  * Update the times on the nfsnode then do fifo close.
2499  */
2500 int
2501 nfsfifo_close(ap)
2502 	struct vop_close_args /* {
2503 		struct vnode *a_vp;
2504 		int  a_fflag;
2505 		struct ucred *a_cred;
2506 		struct proc *a_p;
2507 	} */ *ap;
2508 {
2509 	register struct vnode *vp = ap->a_vp;
2510 	register struct nfsnode *np = VTONFS(vp);
2511 	struct vattr vattr;
2512 	extern int (**fifo_vnodeop_p)();
2513 
2514 	if (np->n_flag & (NACC | NUPD)) {
2515 		if (np->n_flag & NACC)
2516 			np->n_atim = time;
2517 		if (np->n_flag & NUPD)
2518 			np->n_mtim = time;
2519 		np->n_flag |= NCHG;
2520 		if (vp->v_usecount == 1 &&
2521 		    (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) {
2522 			VATTR_NULL(&vattr);
2523 			if (np->n_flag & NACC) {
2524 				vattr.va_atime.ts_sec = np->n_atim.tv_sec;
2525 				vattr.va_atime.ts_nsec =
2526 				    np->n_atim.tv_usec * 1000;
2527 			}
2528 			if (np->n_flag & NUPD) {
2529 				vattr.va_mtime.ts_sec = np->n_mtim.tv_sec;
2530 				vattr.va_mtime.ts_nsec =
2531 				    np->n_mtim.tv_usec * 1000;
2532 			}
2533 			(void)VOP_SETATTR(vp, &vattr, ap->a_cred, ap->a_p);
2534 		}
2535 	}
2536 	return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_close), ap));
2537 }
2538 #endif /* FIFO */
2539