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