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