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