nfs_subs.c revision 10219
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_subs.c	8.3 (Berkeley) 1/4/94
37 * $Id: nfs_subs.c,v 1.22 1995/07/29 11:42:22 bde Exp $
38 */
39
40/*
41 * These functions support the macros and help fiddle mbuf chains for
42 * the nfs op functions. They do things like create the rpc header and
43 * copy data between mbuf chains and uio lists.
44 */
45#include <sys/param.h>
46#include <sys/proc.h>
47#include <sys/systm.h>
48#include <sys/kernel.h>
49#include <sys/mount.h>
50#include <sys/vnode.h>
51#include <sys/namei.h>
52#include <sys/mbuf.h>
53#include <sys/socket.h>
54#include <sys/stat.h>
55#include <sys/malloc.h>
56#ifdef VFS_LKM
57#include <sys/sysent.h>
58#include <sys/syscall.h>
59#endif
60
61#include <vm/vm.h>
62#include <vm/vnode_pager.h>
63
64#include <nfs/rpcv2.h>
65#include <nfs/nfsproto.h>
66#include <nfs/nfsnode.h>
67#include <nfs/nfs.h>
68#include <nfs/xdr_subs.h>
69#include <nfs/nfsm_subs.h>
70#include <nfs/nfsmount.h>
71#include <nfs/nqnfs.h>
72#include <nfs/nfsrtt.h>
73
74#include <miscfs/specfs/specdev.h>
75
76#include <netinet/in.h>
77#ifdef ISO
78#include <netiso/iso.h>
79#endif
80
81/*
82 * Data items converted to xdr at startup, since they are constant
83 * This is kinda hokey, but may save a little time doing byte swaps
84 */
85u_long nfs_xdrneg1;
86u_long rpc_call, rpc_vers, rpc_reply, rpc_msgdenied, rpc_autherr,
87	rpc_mismatch, rpc_auth_unix, rpc_msgaccepted,
88	rpc_auth_kerb;
89u_long nfs_prog, nqnfs_prog, nfs_true, nfs_false;
90
91/* And other global data */
92static u_long nfs_xid = 0;
93enum vtype nv2tov_type[8] = { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON, VNON };
94enum vtype nv3tov_type[8]={ VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO };
95int nfs_ticks;
96
97struct nfs_reqq nfs_reqq;
98struct nfssvc_sockhead nfssvc_sockhead;
99int nfssvc_sockhead_flag;
100struct nfsd_head nfsd_head;
101int nfsd_head_flag;
102struct nfs_bufq nfs_bufq;
103struct nqtimerhead nqtimerhead;
104struct nqfhhashhead *nqfhhashtbl;
105u_long nqfhhash;
106
107/*
108 * Mapping of old NFS Version 2 RPC numbers to generic numbers.
109 */
110int nfsv3_procid[NFS_NPROCS] = {
111	NFSPROC_NULL,
112	NFSPROC_GETATTR,
113	NFSPROC_SETATTR,
114	NFSPROC_NOOP,
115	NFSPROC_LOOKUP,
116	NFSPROC_READLINK,
117	NFSPROC_READ,
118	NFSPROC_NOOP,
119	NFSPROC_WRITE,
120	NFSPROC_CREATE,
121	NFSPROC_REMOVE,
122	NFSPROC_RENAME,
123	NFSPROC_LINK,
124	NFSPROC_SYMLINK,
125	NFSPROC_MKDIR,
126	NFSPROC_RMDIR,
127	NFSPROC_READDIR,
128	NFSPROC_FSSTAT,
129	NFSPROC_NOOP,
130	NFSPROC_NOOP,
131	NFSPROC_NOOP,
132	NFSPROC_NOOP,
133	NFSPROC_NOOP,
134	NFSPROC_NOOP,
135	NFSPROC_NOOP,
136	NFSPROC_NOOP
137};
138
139/*
140 * and the reverse mapping from generic to Version 2 procedure numbers
141 */
142int nfsv2_procid[NFS_NPROCS] = {
143	NFSV2PROC_NULL,
144	NFSV2PROC_GETATTR,
145	NFSV2PROC_SETATTR,
146	NFSV2PROC_LOOKUP,
147	NFSV2PROC_NOOP,
148	NFSV2PROC_READLINK,
149	NFSV2PROC_READ,
150	NFSV2PROC_WRITE,
151	NFSV2PROC_CREATE,
152	NFSV2PROC_MKDIR,
153	NFSV2PROC_SYMLINK,
154	NFSV2PROC_CREATE,
155	NFSV2PROC_REMOVE,
156	NFSV2PROC_RMDIR,
157	NFSV2PROC_RENAME,
158	NFSV2PROC_LINK,
159	NFSV2PROC_READDIR,
160	NFSV2PROC_NOOP,
161	NFSV2PROC_STATFS,
162	NFSV2PROC_NOOP,
163	NFSV2PROC_NOOP,
164	NFSV2PROC_NOOP,
165	NFSV2PROC_NOOP,
166	NFSV2PROC_NOOP,
167	NFSV2PROC_NOOP,
168	NFSV2PROC_NOOP,
169};
170
171/*
172 * Maps errno values to nfs error numbers.
173 * Use NFSERR_IO as the catch all for ones not specifically defined in
174 * RFC 1094.
175 */
176static u_char nfsrv_v2errmap[ELAST] = {
177  NFSERR_PERM,	NFSERR_NOENT,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
178  NFSERR_NXIO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
179  NFSERR_IO,	NFSERR_IO,	NFSERR_ACCES,	NFSERR_IO,	NFSERR_IO,
180  NFSERR_IO,	NFSERR_EXIST,	NFSERR_IO,	NFSERR_NODEV,	NFSERR_NOTDIR,
181  NFSERR_ISDIR,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
182  NFSERR_IO,	NFSERR_FBIG,	NFSERR_NOSPC,	NFSERR_IO,	NFSERR_ROFS,
183  NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
184  NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
185  NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
186  NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
187  NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
188  NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
189  NFSERR_IO,	NFSERR_IO,	NFSERR_NAMETOL,	NFSERR_IO,	NFSERR_IO,
190  NFSERR_NOTEMPTY, NFSERR_IO,	NFSERR_IO,	NFSERR_DQUOT,	NFSERR_STALE,
191  NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
192  NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
193  NFSERR_IO,
194};
195
196/*
197 * Maps errno values to nfs error numbers.
198 * Although it is not obvious whether or not NFS clients really care if
199 * a returned error value is in the specified list for the procedure, the
200 * safest thing to do is filter them appropriately. For Version 2, the
201 * X/Open XNFS document is the only specification that defines error values
202 * for each RPC (The RFC simply lists all possible error values for all RPCs),
203 * so I have decided to not do this for Version 2.
204 * The first entry is the default error return and the rest are the valid
205 * errors for that RPC in increasing numeric order.
206 */
207static short nfsv3err_null[] = {
208	0,
209	0,
210};
211
212static short nfsv3err_getattr[] = {
213	NFSERR_IO,
214	NFSERR_IO,
215	NFSERR_STALE,
216	NFSERR_BADHANDLE,
217	NFSERR_SERVERFAULT,
218	0,
219};
220
221static short nfsv3err_setattr[] = {
222	NFSERR_IO,
223	NFSERR_PERM,
224	NFSERR_IO,
225	NFSERR_ACCES,
226	NFSERR_INVAL,
227	NFSERR_NOSPC,
228	NFSERR_ROFS,
229	NFSERR_DQUOT,
230	NFSERR_STALE,
231	NFSERR_BADHANDLE,
232	NFSERR_NOT_SYNC,
233	NFSERR_SERVERFAULT,
234	0,
235};
236
237static short nfsv3err_lookup[] = {
238	NFSERR_IO,
239	NFSERR_NOENT,
240	NFSERR_IO,
241	NFSERR_ACCES,
242	NFSERR_NOTDIR,
243	NFSERR_NAMETOL,
244	NFSERR_STALE,
245	NFSERR_BADHANDLE,
246	NFSERR_SERVERFAULT,
247	0,
248};
249
250static short nfsv3err_access[] = {
251	NFSERR_IO,
252	NFSERR_IO,
253	NFSERR_STALE,
254	NFSERR_BADHANDLE,
255	NFSERR_SERVERFAULT,
256	0,
257};
258
259static short nfsv3err_readlink[] = {
260	NFSERR_IO,
261	NFSERR_IO,
262	NFSERR_ACCES,
263	NFSERR_INVAL,
264	NFSERR_STALE,
265	NFSERR_BADHANDLE,
266	NFSERR_NOTSUPP,
267	NFSERR_SERVERFAULT,
268	0,
269};
270
271static short nfsv3err_read[] = {
272	NFSERR_IO,
273	NFSERR_IO,
274	NFSERR_NXIO,
275	NFSERR_ACCES,
276	NFSERR_INVAL,
277	NFSERR_STALE,
278	NFSERR_BADHANDLE,
279	NFSERR_SERVERFAULT,
280	0,
281};
282
283static short nfsv3err_write[] = {
284	NFSERR_IO,
285	NFSERR_IO,
286	NFSERR_ACCES,
287	NFSERR_INVAL,
288	NFSERR_FBIG,
289	NFSERR_NOSPC,
290	NFSERR_ROFS,
291	NFSERR_DQUOT,
292	NFSERR_STALE,
293	NFSERR_BADHANDLE,
294	NFSERR_SERVERFAULT,
295	0,
296};
297
298static short nfsv3err_create[] = {
299	NFSERR_IO,
300	NFSERR_IO,
301	NFSERR_ACCES,
302	NFSERR_EXIST,
303	NFSERR_NOTDIR,
304	NFSERR_NOSPC,
305	NFSERR_ROFS,
306	NFSERR_NAMETOL,
307	NFSERR_DQUOT,
308	NFSERR_STALE,
309	NFSERR_BADHANDLE,
310	NFSERR_NOTSUPP,
311	NFSERR_SERVERFAULT,
312	0,
313};
314
315static short nfsv3err_mkdir[] = {
316	NFSERR_IO,
317	NFSERR_IO,
318	NFSERR_ACCES,
319	NFSERR_EXIST,
320	NFSERR_NOTDIR,
321	NFSERR_NOSPC,
322	NFSERR_ROFS,
323	NFSERR_NAMETOL,
324	NFSERR_DQUOT,
325	NFSERR_STALE,
326	NFSERR_BADHANDLE,
327	NFSERR_NOTSUPP,
328	NFSERR_SERVERFAULT,
329	0,
330};
331
332static short nfsv3err_symlink[] = {
333	NFSERR_IO,
334	NFSERR_IO,
335	NFSERR_ACCES,
336	NFSERR_EXIST,
337	NFSERR_NOTDIR,
338	NFSERR_NOSPC,
339	NFSERR_ROFS,
340	NFSERR_NAMETOL,
341	NFSERR_DQUOT,
342	NFSERR_STALE,
343	NFSERR_BADHANDLE,
344	NFSERR_NOTSUPP,
345	NFSERR_SERVERFAULT,
346	0,
347};
348
349static short nfsv3err_mknod[] = {
350	NFSERR_IO,
351	NFSERR_IO,
352	NFSERR_ACCES,
353	NFSERR_EXIST,
354	NFSERR_NOTDIR,
355	NFSERR_NOSPC,
356	NFSERR_ROFS,
357	NFSERR_NAMETOL,
358	NFSERR_DQUOT,
359	NFSERR_STALE,
360	NFSERR_BADHANDLE,
361	NFSERR_NOTSUPP,
362	NFSERR_SERVERFAULT,
363	NFSERR_BADTYPE,
364	0,
365};
366
367static short nfsv3err_remove[] = {
368	NFSERR_IO,
369	NFSERR_NOENT,
370	NFSERR_IO,
371	NFSERR_ACCES,
372	NFSERR_NOTDIR,
373	NFSERR_ROFS,
374	NFSERR_NAMETOL,
375	NFSERR_STALE,
376	NFSERR_BADHANDLE,
377	NFSERR_SERVERFAULT,
378	0,
379};
380
381static short nfsv3err_rmdir[] = {
382	NFSERR_IO,
383	NFSERR_NOENT,
384	NFSERR_IO,
385	NFSERR_ACCES,
386	NFSERR_EXIST,
387	NFSERR_NOTDIR,
388	NFSERR_INVAL,
389	NFSERR_ROFS,
390	NFSERR_NAMETOL,
391	NFSERR_NOTEMPTY,
392	NFSERR_STALE,
393	NFSERR_BADHANDLE,
394	NFSERR_NOTSUPP,
395	NFSERR_SERVERFAULT,
396	0,
397};
398
399static short nfsv3err_rename[] = {
400	NFSERR_IO,
401	NFSERR_NOENT,
402	NFSERR_IO,
403	NFSERR_ACCES,
404	NFSERR_EXIST,
405	NFSERR_XDEV,
406	NFSERR_NOTDIR,
407	NFSERR_ISDIR,
408	NFSERR_INVAL,
409	NFSERR_NOSPC,
410	NFSERR_ROFS,
411	NFSERR_MLINK,
412	NFSERR_NAMETOL,
413	NFSERR_NOTEMPTY,
414	NFSERR_DQUOT,
415	NFSERR_STALE,
416	NFSERR_BADHANDLE,
417	NFSERR_NOTSUPP,
418	NFSERR_SERVERFAULT,
419	0,
420};
421
422static short nfsv3err_link[] = {
423	NFSERR_IO,
424	NFSERR_IO,
425	NFSERR_ACCES,
426	NFSERR_EXIST,
427	NFSERR_XDEV,
428	NFSERR_NOTDIR,
429	NFSERR_INVAL,
430	NFSERR_NOSPC,
431	NFSERR_ROFS,
432	NFSERR_MLINK,
433	NFSERR_NAMETOL,
434	NFSERR_DQUOT,
435	NFSERR_STALE,
436	NFSERR_BADHANDLE,
437	NFSERR_NOTSUPP,
438	NFSERR_SERVERFAULT,
439	0,
440};
441
442static short nfsv3err_readdir[] = {
443	NFSERR_IO,
444	NFSERR_IO,
445	NFSERR_ACCES,
446	NFSERR_NOTDIR,
447	NFSERR_STALE,
448	NFSERR_BADHANDLE,
449	NFSERR_BAD_COOKIE,
450	NFSERR_TOOSMALL,
451	NFSERR_SERVERFAULT,
452	0,
453};
454
455static short nfsv3err_readdirplus[] = {
456	NFSERR_IO,
457	NFSERR_IO,
458	NFSERR_ACCES,
459	NFSERR_NOTDIR,
460	NFSERR_STALE,
461	NFSERR_BADHANDLE,
462	NFSERR_BAD_COOKIE,
463	NFSERR_NOTSUPP,
464	NFSERR_TOOSMALL,
465	NFSERR_SERVERFAULT,
466	0,
467};
468
469static short nfsv3err_fsstat[] = {
470	NFSERR_IO,
471	NFSERR_IO,
472	NFSERR_STALE,
473	NFSERR_BADHANDLE,
474	NFSERR_SERVERFAULT,
475	0,
476};
477
478static short nfsv3err_fsinfo[] = {
479	NFSERR_STALE,
480	NFSERR_STALE,
481	NFSERR_BADHANDLE,
482	NFSERR_SERVERFAULT,
483	0,
484};
485
486static short nfsv3err_pathconf[] = {
487	NFSERR_STALE,
488	NFSERR_STALE,
489	NFSERR_BADHANDLE,
490	NFSERR_SERVERFAULT,
491	0,
492};
493
494static short nfsv3err_commit[] = {
495	NFSERR_IO,
496	NFSERR_IO,
497	NFSERR_STALE,
498	NFSERR_BADHANDLE,
499	NFSERR_SERVERFAULT,
500	0,
501};
502
503static short *nfsrv_v3errmap[] = {
504	nfsv3err_null,
505	nfsv3err_getattr,
506	nfsv3err_setattr,
507	nfsv3err_lookup,
508	nfsv3err_access,
509	nfsv3err_readlink,
510	nfsv3err_read,
511	nfsv3err_write,
512	nfsv3err_create,
513	nfsv3err_mkdir,
514	nfsv3err_symlink,
515	nfsv3err_mknod,
516	nfsv3err_remove,
517	nfsv3err_rmdir,
518	nfsv3err_rename,
519	nfsv3err_link,
520	nfsv3err_readdir,
521	nfsv3err_readdirplus,
522	nfsv3err_fsstat,
523	nfsv3err_fsinfo,
524	nfsv3err_pathconf,
525	nfsv3err_commit,
526};
527
528extern struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON];
529extern struct nfsrtt nfsrtt;
530extern time_t nqnfsstarttime;
531extern int nqsrv_clockskew;
532extern int nqsrv_writeslack;
533extern int nqsrv_maxlease;
534extern struct nfsstats nfsstats;
535extern int nqnfs_piggy[NFS_NPROCS];
536extern nfstype nfsv2_type[9];
537extern nfstype nfsv3_type[9];
538extern struct nfsnodehashhead *nfsnodehashtbl;
539extern u_long nfsnodehash;
540
541#ifdef VFS_LKM
542struct getfh_args;
543extern int getfh(struct proc *, struct getfh_args *, int *);
544struct nfssvc_args;
545extern int nfssvc(struct proc *, struct nfssvc_args *, int *);
546#endif
547
548LIST_HEAD(nfsnodehashhead, nfsnode);
549
550/*
551 * Create the header for an rpc request packet
552 * The hsiz is the size of the rest of the nfs request header.
553 * (just used to decide if a cluster is a good idea)
554 */
555struct mbuf *
556nfsm_reqh(vp, procid, hsiz, bposp)
557	struct vnode *vp;
558	u_long procid;
559	int hsiz;
560	caddr_t *bposp;
561{
562	register struct mbuf *mb;
563	register u_long *tl;
564	register caddr_t bpos;
565	struct mbuf *mb2;
566	struct nfsmount *nmp;
567	int nqflag;
568
569	MGET(mb, M_WAIT, MT_DATA);
570	if (hsiz >= MINCLSIZE)
571		MCLGET(mb, M_WAIT);
572	mb->m_len = 0;
573	bpos = mtod(mb, caddr_t);
574
575	/*
576	 * For NQNFS, add lease request.
577	 */
578	if (vp) {
579		nmp = VFSTONFS(vp->v_mount);
580		if (nmp->nm_flag & NFSMNT_NQNFS) {
581			nqflag = NQNFS_NEEDLEASE(vp, procid);
582			if (nqflag) {
583				nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED);
584				*tl++ = txdr_unsigned(nqflag);
585				*tl = txdr_unsigned(nmp->nm_leaseterm);
586			} else {
587				nfsm_build(tl, u_long *, NFSX_UNSIGNED);
588				*tl = 0;
589			}
590		}
591	}
592	/* Finally, return values */
593	*bposp = bpos;
594	return (mb);
595}
596
597/*
598 * Build the RPC header and fill in the authorization info.
599 * The authorization string argument is only used when the credentials
600 * come from outside of the kernel.
601 * Returns the head of the mbuf list.
602 */
603struct mbuf *
604nfsm_rpchead(cr, nmflag, procid, auth_type, auth_len, auth_str, verf_len,
605	verf_str, mrest, mrest_len, mbp, xidp)
606	register struct ucred *cr;
607	int nmflag;
608	int procid;
609	int auth_type;
610	int auth_len;
611	char *auth_str;
612	int verf_len;
613	char *verf_str;
614	struct mbuf *mrest;
615	int mrest_len;
616	struct mbuf **mbp;
617	u_long *xidp;
618{
619	register struct mbuf *mb;
620	register u_long *tl;
621	register caddr_t bpos;
622	register int i;
623	struct mbuf *mreq, *mb2;
624	int siz, grpsiz, authsiz;
625
626	authsiz = nfsm_rndup(auth_len);
627	MGETHDR(mb, M_WAIT, MT_DATA);
628	if ((authsiz + 10 * NFSX_UNSIGNED) >= MINCLSIZE) {
629		MCLGET(mb, M_WAIT);
630	} else if ((authsiz + 10 * NFSX_UNSIGNED) < MHLEN) {
631		MH_ALIGN(mb, authsiz + 10 * NFSX_UNSIGNED);
632	} else {
633		MH_ALIGN(mb, 8 * NFSX_UNSIGNED);
634	}
635	mb->m_len = 0;
636	mreq = mb;
637	bpos = mtod(mb, caddr_t);
638
639	/*
640	 * First the RPC header.
641	 */
642	nfsm_build(tl, u_long *, 8 * NFSX_UNSIGNED);
643	if (++nfs_xid == 0)
644		nfs_xid++;
645	*tl++ = *xidp = txdr_unsigned(nfs_xid);
646	*tl++ = rpc_call;
647	*tl++ = rpc_vers;
648	if (nmflag & NFSMNT_NQNFS) {
649		*tl++ = txdr_unsigned(NQNFS_PROG);
650		*tl++ = txdr_unsigned(NQNFS_VER3);
651	} else {
652		*tl++ = txdr_unsigned(NFS_PROG);
653		if (nmflag & NFSMNT_NFSV3)
654			*tl++ = txdr_unsigned(NFS_VER3);
655		else
656			*tl++ = txdr_unsigned(NFS_VER2);
657	}
658	if (nmflag & NFSMNT_NFSV3)
659		*tl++ = txdr_unsigned(procid);
660	else
661		*tl++ = txdr_unsigned(nfsv2_procid[procid]);
662
663	/*
664	 * And then the authorization cred.
665	 */
666	*tl++ = txdr_unsigned(auth_type);
667	*tl = txdr_unsigned(authsiz);
668	switch (auth_type) {
669	case RPCAUTH_UNIX:
670		nfsm_build(tl, u_long *, auth_len);
671		*tl++ = 0;		/* stamp ?? */
672		*tl++ = 0;		/* NULL hostname */
673		*tl++ = txdr_unsigned(cr->cr_uid);
674		*tl++ = txdr_unsigned(cr->cr_groups[0]);
675		grpsiz = (auth_len >> 2) - 5;
676		*tl++ = txdr_unsigned(grpsiz);
677		for (i = 1; i <= grpsiz; i++)
678			*tl++ = txdr_unsigned(cr->cr_groups[i]);
679		break;
680	case RPCAUTH_KERB4:
681		siz = auth_len;
682		while (siz > 0) {
683			if (M_TRAILINGSPACE(mb) == 0) {
684				MGET(mb2, M_WAIT, MT_DATA);
685				if (siz >= MINCLSIZE)
686					MCLGET(mb2, M_WAIT);
687				mb->m_next = mb2;
688				mb = mb2;
689				mb->m_len = 0;
690				bpos = mtod(mb, caddr_t);
691			}
692			i = min(siz, M_TRAILINGSPACE(mb));
693			bcopy(auth_str, bpos, i);
694			mb->m_len += i;
695			auth_str += i;
696			bpos += i;
697			siz -= i;
698		}
699		if ((siz = (nfsm_rndup(auth_len) - auth_len)) > 0) {
700			for (i = 0; i < siz; i++)
701				*bpos++ = '\0';
702			mb->m_len += siz;
703		}
704		break;
705	};
706
707	/*
708	 * And the verifier...
709	 */
710	nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED);
711	if (verf_str) {
712		*tl++ = txdr_unsigned(RPCAUTH_KERB4);
713		*tl = txdr_unsigned(verf_len);
714		siz = verf_len;
715		while (siz > 0) {
716			if (M_TRAILINGSPACE(mb) == 0) {
717				MGET(mb2, M_WAIT, MT_DATA);
718				if (siz >= MINCLSIZE)
719					MCLGET(mb2, M_WAIT);
720				mb->m_next = mb2;
721				mb = mb2;
722				mb->m_len = 0;
723				bpos = mtod(mb, caddr_t);
724			}
725			i = min(siz, M_TRAILINGSPACE(mb));
726			bcopy(verf_str, bpos, i);
727			mb->m_len += i;
728			verf_str += i;
729			bpos += i;
730			siz -= i;
731		}
732		if ((siz = (nfsm_rndup(verf_len) - verf_len)) > 0) {
733			for (i = 0; i < siz; i++)
734				*bpos++ = '\0';
735			mb->m_len += siz;
736		}
737	} else {
738		*tl++ = txdr_unsigned(RPCAUTH_NULL);
739		*tl = 0;
740	}
741	mb->m_next = mrest;
742	mreq->m_pkthdr.len = authsiz + 10 * NFSX_UNSIGNED + mrest_len;
743	mreq->m_pkthdr.rcvif = (struct ifnet *)0;
744	*mbp = mb;
745	return (mreq);
746}
747
748/*
749 * copies mbuf chain to the uio scatter/gather list
750 */
751int
752nfsm_mbuftouio(mrep, uiop, siz, dpos)
753	struct mbuf **mrep;
754	register struct uio *uiop;
755	int siz;
756	caddr_t *dpos;
757{
758	register char *mbufcp, *uiocp;
759	register int xfer, left, len;
760	register struct mbuf *mp;
761	long uiosiz, rem;
762	int error = 0;
763
764	mp = *mrep;
765	mbufcp = *dpos;
766	len = mtod(mp, caddr_t)+mp->m_len-mbufcp;
767	rem = nfsm_rndup(siz)-siz;
768	while (siz > 0) {
769		if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL)
770			return (EFBIG);
771		left = uiop->uio_iov->iov_len;
772		uiocp = uiop->uio_iov->iov_base;
773		if (left > siz)
774			left = siz;
775		uiosiz = left;
776		while (left > 0) {
777			while (len == 0) {
778				mp = mp->m_next;
779				if (mp == NULL)
780					return (EBADRPC);
781				mbufcp = mtod(mp, caddr_t);
782				len = mp->m_len;
783			}
784			xfer = (left > len) ? len : left;
785#ifdef notdef
786			/* Not Yet.. */
787			if (uiop->uio_iov->iov_op != NULL)
788				(*(uiop->uio_iov->iov_op))
789				(mbufcp, uiocp, xfer);
790			else
791#endif
792			if (uiop->uio_segflg == UIO_SYSSPACE)
793				bcopy(mbufcp, uiocp, xfer);
794			else
795				copyout(mbufcp, uiocp, xfer);
796			left -= xfer;
797			len -= xfer;
798			mbufcp += xfer;
799			uiocp += xfer;
800			uiop->uio_offset += xfer;
801			uiop->uio_resid -= xfer;
802		}
803		if (uiop->uio_iov->iov_len <= siz) {
804			uiop->uio_iovcnt--;
805			uiop->uio_iov++;
806		} else {
807			uiop->uio_iov->iov_base += uiosiz;
808			uiop->uio_iov->iov_len -= uiosiz;
809		}
810		siz -= uiosiz;
811	}
812	*dpos = mbufcp;
813	*mrep = mp;
814	if (rem > 0) {
815		if (len < rem)
816			error = nfs_adv(mrep, dpos, rem, len);
817		else
818			*dpos += rem;
819	}
820	return (error);
821}
822
823/*
824 * copies a uio scatter/gather list to an mbuf chain...
825 */
826int
827nfsm_uiotombuf(uiop, mq, siz, bpos)
828	register struct uio *uiop;
829	struct mbuf **mq;
830	int siz;
831	caddr_t *bpos;
832{
833	register char *uiocp;
834	register struct mbuf *mp, *mp2;
835	register int xfer, left, mlen;
836	int uiosiz, clflg, rem;
837	char *cp;
838
839	if (siz > MLEN)		/* or should it >= MCLBYTES ?? */
840		clflg = 1;
841	else
842		clflg = 0;
843	rem = nfsm_rndup(siz)-siz;
844	mp = mp2 = *mq;
845	while (siz > 0) {
846		if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL)
847			return (EINVAL);
848		left = uiop->uio_iov->iov_len;
849		uiocp = uiop->uio_iov->iov_base;
850		if (left > siz)
851			left = siz;
852		uiosiz = left;
853		while (left > 0) {
854			mlen = M_TRAILINGSPACE(mp);
855			if (mlen == 0) {
856				MGET(mp, M_WAIT, MT_DATA);
857				if (clflg)
858					MCLGET(mp, M_WAIT);
859				mp->m_len = 0;
860				mp2->m_next = mp;
861				mp2 = mp;
862				mlen = M_TRAILINGSPACE(mp);
863			}
864			xfer = (left > mlen) ? mlen : left;
865#ifdef notdef
866			/* Not Yet.. */
867			if (uiop->uio_iov->iov_op != NULL)
868				(*(uiop->uio_iov->iov_op))
869				(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
870			else
871#endif
872			if (uiop->uio_segflg == UIO_SYSSPACE)
873				bcopy(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
874			else
875				copyin(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
876			mp->m_len += xfer;
877			left -= xfer;
878			uiocp += xfer;
879			uiop->uio_offset += xfer;
880			uiop->uio_resid -= xfer;
881		}
882		if (uiop->uio_iov->iov_len <= siz) {
883			uiop->uio_iovcnt--;
884			uiop->uio_iov++;
885		} else {
886			uiop->uio_iov->iov_base += uiosiz;
887			uiop->uio_iov->iov_len -= uiosiz;
888		}
889		siz -= uiosiz;
890	}
891	if (rem > 0) {
892		if (rem > M_TRAILINGSPACE(mp)) {
893			MGET(mp, M_WAIT, MT_DATA);
894			mp->m_len = 0;
895			mp2->m_next = mp;
896		}
897		cp = mtod(mp, caddr_t)+mp->m_len;
898		for (left = 0; left < rem; left++)
899			*cp++ = '\0';
900		mp->m_len += rem;
901		*bpos = cp;
902	} else
903		*bpos = mtod(mp, caddr_t)+mp->m_len;
904	*mq = mp;
905	return (0);
906}
907
908/*
909 * Help break down an mbuf chain by setting the first siz bytes contiguous
910 * pointed to by returned val.
911 * This is used by the macros nfsm_dissect and nfsm_dissecton for tough
912 * cases. (The macros use the vars. dpos and dpos2)
913 */
914int
915nfsm_disct(mdp, dposp, siz, left, cp2)
916	struct mbuf **mdp;
917	caddr_t *dposp;
918	int siz;
919	int left;
920	caddr_t *cp2;
921{
922	register struct mbuf *mp, *mp2;
923	register int siz2, xfer;
924	register caddr_t p;
925
926	mp = *mdp;
927	while (left == 0) {
928		*mdp = mp = mp->m_next;
929		if (mp == NULL)
930			return (EBADRPC);
931		left = mp->m_len;
932		*dposp = mtod(mp, caddr_t);
933	}
934	if (left >= siz) {
935		*cp2 = *dposp;
936		*dposp += siz;
937	} else if (mp->m_next == NULL) {
938		return (EBADRPC);
939	} else if (siz > MHLEN) {
940		panic("nfs S too big");
941	} else {
942		MGET(mp2, M_WAIT, MT_DATA);
943		mp2->m_next = mp->m_next;
944		mp->m_next = mp2;
945		mp->m_len -= left;
946		mp = mp2;
947		*cp2 = p = mtod(mp, caddr_t);
948		bcopy(*dposp, p, left);		/* Copy what was left */
949		siz2 = siz-left;
950		p += left;
951		mp2 = mp->m_next;
952		/* Loop around copying up the siz2 bytes */
953		while (siz2 > 0) {
954			if (mp2 == NULL)
955				return (EBADRPC);
956			xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2;
957			if (xfer > 0) {
958				bcopy(mtod(mp2, caddr_t), p, xfer);
959				NFSMADV(mp2, xfer);
960				mp2->m_len -= xfer;
961				p += xfer;
962				siz2 -= xfer;
963			}
964			if (siz2 > 0)
965				mp2 = mp2->m_next;
966		}
967		mp->m_len = siz;
968		*mdp = mp2;
969		*dposp = mtod(mp2, caddr_t);
970	}
971	return (0);
972}
973
974/*
975 * Advance the position in the mbuf chain.
976 */
977int
978nfs_adv(mdp, dposp, offs, left)
979	struct mbuf **mdp;
980	caddr_t *dposp;
981	int offs;
982	int left;
983{
984	register struct mbuf *m;
985	register int s;
986
987	m = *mdp;
988	s = left;
989	while (s < offs) {
990		offs -= s;
991		m = m->m_next;
992		if (m == NULL)
993			return (EBADRPC);
994		s = m->m_len;
995	}
996	*mdp = m;
997	*dposp = mtod(m, caddr_t)+offs;
998	return (0);
999}
1000
1001/*
1002 * Copy a string into mbufs for the hard cases...
1003 */
1004int
1005nfsm_strtmbuf(mb, bpos, cp, siz)
1006	struct mbuf **mb;
1007	char **bpos;
1008	char *cp;
1009	long siz;
1010{
1011	register struct mbuf *m1 = 0, *m2;
1012	long left, xfer, len, tlen;
1013	u_long *tl;
1014	int putsize;
1015
1016	putsize = 1;
1017	m2 = *mb;
1018	left = M_TRAILINGSPACE(m2);
1019	if (left > 0) {
1020		tl = ((u_long *)(*bpos));
1021		*tl++ = txdr_unsigned(siz);
1022		putsize = 0;
1023		left -= NFSX_UNSIGNED;
1024		m2->m_len += NFSX_UNSIGNED;
1025		if (left > 0) {
1026			bcopy(cp, (caddr_t) tl, left);
1027			siz -= left;
1028			cp += left;
1029			m2->m_len += left;
1030			left = 0;
1031		}
1032	}
1033	/* Loop around adding mbufs */
1034	while (siz > 0) {
1035		MGET(m1, M_WAIT, MT_DATA);
1036		if (siz > MLEN)
1037			MCLGET(m1, M_WAIT);
1038		m1->m_len = NFSMSIZ(m1);
1039		m2->m_next = m1;
1040		m2 = m1;
1041		tl = mtod(m1, u_long *);
1042		tlen = 0;
1043		if (putsize) {
1044			*tl++ = txdr_unsigned(siz);
1045			m1->m_len -= NFSX_UNSIGNED;
1046			tlen = NFSX_UNSIGNED;
1047			putsize = 0;
1048		}
1049		if (siz < m1->m_len) {
1050			len = nfsm_rndup(siz);
1051			xfer = siz;
1052			if (xfer < len)
1053				*(tl+(xfer>>2)) = 0;
1054		} else {
1055			xfer = len = m1->m_len;
1056		}
1057		bcopy(cp, (caddr_t) tl, xfer);
1058		m1->m_len = len+tlen;
1059		siz -= xfer;
1060		cp += xfer;
1061	}
1062	*mb = m1;
1063	*bpos = mtod(m1, caddr_t)+m1->m_len;
1064	return (0);
1065}
1066
1067/*
1068 * Called once to initialize data structures...
1069 */
1070int
1071nfs_init()
1072{
1073	register int i;
1074
1075	/*
1076	 * Check to see if major data structures haven't bloated.
1077	 */
1078	if (sizeof (struct nfsnode) > NFS_NODEALLOC) {
1079		printf("struct nfsnode bloated (> %dbytes)\n", NFS_NODEALLOC);
1080		printf("Try reducing NFS_SMALLFH\n");
1081	}
1082	if (sizeof (struct nfsmount) > NFS_MNTALLOC) {
1083		printf("struct nfsmount bloated (> %dbytes)\n", NFS_MNTALLOC);
1084		printf("Try reducing NFS_MUIDHASHSIZ\n");
1085	}
1086	if (sizeof (struct nfssvc_sock) > NFS_SVCALLOC) {
1087		printf("struct nfssvc_sock bloated (> %dbytes)\n",NFS_SVCALLOC);
1088		printf("Try reducing NFS_UIDHASHSIZ\n");
1089	}
1090	if (sizeof (struct nfsuid) > NFS_UIDALLOC) {
1091		printf("struct nfsuid bloated (> %dbytes)\n",NFS_UIDALLOC);
1092		printf("Try unionizing the nu_nickname and nu_flag fields\n");
1093	}
1094	nfsrtt.pos = 0;
1095	rpc_vers = txdr_unsigned(RPC_VER2);
1096	rpc_call = txdr_unsigned(RPC_CALL);
1097	rpc_reply = txdr_unsigned(RPC_REPLY);
1098	rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED);
1099	rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED);
1100	rpc_mismatch = txdr_unsigned(RPC_MISMATCH);
1101	rpc_autherr = txdr_unsigned(RPC_AUTHERR);
1102	rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX);
1103	rpc_auth_kerb = txdr_unsigned(RPCAUTH_KERB4);
1104	nfs_prog = txdr_unsigned(NFS_PROG);
1105	nqnfs_prog = txdr_unsigned(NQNFS_PROG);
1106	nfs_true = txdr_unsigned(TRUE);
1107	nfs_false = txdr_unsigned(FALSE);
1108	nfs_xdrneg1 = txdr_unsigned(-1);
1109	nfs_ticks = (hz * NFS_TICKINTVL + 500) / 1000;
1110	if (nfs_ticks < 1)
1111		nfs_ticks = 1;
1112	/* Ensure async daemons disabled */
1113	for (i = 0; i < NFS_MAXASYNCDAEMON; i++)
1114		nfs_iodwant[i] = (struct proc *)0;
1115	TAILQ_INIT(&nfs_bufq);
1116	nfs_nhinit();			/* Init the nfsnode table */
1117	nfsrv_init(0);			/* Init server data structures */
1118	nfsrv_initcache();		/* Init the server request cache */
1119
1120	/*
1121	 * Initialize the nqnfs server stuff.
1122	 */
1123	if (nqnfsstarttime == 0) {
1124		nqnfsstarttime = boottime.tv_sec + nqsrv_maxlease
1125			+ nqsrv_clockskew + nqsrv_writeslack;
1126		NQLOADNOVRAM(nqnfsstarttime);
1127		CIRCLEQ_INIT(&nqtimerhead);
1128		nqfhhashtbl = hashinit(NQLCHSZ, M_NQLEASE, &nqfhhash);
1129	}
1130
1131	/*
1132	 * Initialize reply list and start timer
1133	 */
1134	TAILQ_INIT(&nfs_reqq);
1135	nfs_timer(0);
1136
1137#ifdef __FreeBSD__
1138	/*
1139	 * Set up lease_check and lease_updatetime so that other parts
1140	 * of the system can call us, if we are loadable.
1141	 */
1142	lease_check = nfs_lease_check;
1143	lease_updatetime = nfs_lease_updatetime;
1144	vfsconf[MOUNT_NFS]->vfc_refcount++; /* make us non-unloadable */
1145#ifdef VFS_LKM
1146	sysent[SYS_nfssvc].sy_narg = 2;
1147	sysent[SYS_nfssvc].sy_call = nfssvc;
1148	sysent[SYS_getfh].sy_narg = 2;
1149	sysent[SYS_getfh].sy_call = getfh;
1150#endif
1151#endif
1152
1153	return (0);
1154}
1155
1156/*
1157 * Attribute cache routines.
1158 * nfs_loadattrcache() - loads or updates the cache contents from attributes
1159 *	that are on the mbuf list
1160 * nfs_getattrcache() - returns valid attributes if found in cache, returns
1161 *	error otherwise
1162 */
1163
1164/*
1165 * Load the attribute cache (that lives in the nfsnode entry) with
1166 * the values on the mbuf list and
1167 * Iff vap not NULL
1168 *    copy the attributes to *vaper
1169 */
1170int
1171nfs_loadattrcache(vpp, mdp, dposp, vaper)
1172	struct vnode **vpp;
1173	struct mbuf **mdp;
1174	caddr_t *dposp;
1175	struct vattr *vaper;
1176{
1177	register struct vnode *vp = *vpp;
1178	register struct vattr *vap;
1179	register struct nfs_fattr *fp;
1180	register struct nfsnode *np;
1181	register struct nfsnodehashhead *nhpp;
1182	register long t1;
1183	caddr_t cp2;
1184	int error = 0, rdev;
1185	struct mbuf *md;
1186	enum vtype vtyp;
1187	u_short vmode;
1188	struct timespec mtime;
1189	struct vnode *nvp;
1190	quad_t tval;
1191	int v3 = NFS_ISV3(vp);
1192
1193	md = *mdp;
1194	t1 = (mtod(md, caddr_t) + md->m_len) - *dposp;
1195	if (error = nfsm_disct(mdp, dposp, NFSX_FATTR(v3), t1, &cp2))
1196		return (error);
1197	fp = (struct nfs_fattr *)cp2;
1198	if (v3) {
1199		vtyp = nfsv3tov_type(fp->fa_type);
1200		vmode = fxdr_unsigned(u_short, fp->fa_mode);
1201		rdev = makedev(fxdr_unsigned(u_char, fp->fa3_rdev.specdata1),
1202			fxdr_unsigned(u_char, fp->fa3_rdev.specdata2));
1203		fxdr_nfsv3time(&fp->fa3_mtime, &mtime);
1204	} else {
1205		vtyp = nfsv2tov_type(fp->fa_type);
1206		vmode = fxdr_unsigned(u_short, fp->fa_mode);
1207		/*
1208		 * XXX
1209		 *
1210		 * The duplicate information returned in fa_type and fa_mode
1211		 * is an ambiguity in the NFS version 2 protocol.
1212		 *
1213		 * VREG should be taken literally as a regular file.  If a
1214		 * server intents to return some type information differently
1215		 * in the upper bits of the mode field (e.g. for sockets, or
1216		 * FIFOs), NFSv2 mandates fa_type to be VNON.  Anyway, we
1217		 * leave the examination of the mode bits even in the VREG
1218		 * case to avoid breakage for bogus servers, but we make sure
1219		 * that there are actually type bits set in the upper part of
1220		 * fa_mode (and failing that, trust the va_type field).
1221		 *
1222		 * NFSv3 cleared the issue, and requires fa_mode to not
1223		 * contain any type information (while also introduing sockets
1224		 * and FIFOs for fa_type).
1225		 */
1226		if (vtyp == VNON || (vtyp == VREG && (vmode & S_IFMT) != 0))
1227			vtyp = IFTOVT(vmode);
1228		rdev = fxdr_unsigned(long, fp->fa2_rdev);
1229		fxdr_nfsv2time(&fp->fa2_mtime, &mtime);
1230
1231		/*
1232		 * Really ugly NFSv2 kludge.
1233		 */
1234		if (vtyp == VCHR && rdev == 0xffffffff)
1235			vtyp = VFIFO;
1236	}
1237
1238	/*
1239	 * If v_type == VNON it is a new node, so fill in the v_type,
1240	 * n_mtime fields. Check to see if it represents a special
1241	 * device, and if so, check for a possible alias. Once the
1242	 * correct vnode has been obtained, fill in the rest of the
1243	 * information.
1244	 */
1245	np = VTONFS(vp);
1246	if (vp->v_type != vtyp) {
1247		/*
1248		 * If we had a lock and it turns out that the vnode
1249		 * is an object which we don't want to lock (e.g. VDIR)
1250		 * to avoid nasty hanging problems on a server crash,
1251		 * then release it here.
1252		 */
1253		if (vtyp != VREG && VOP_ISLOCKED(vp))
1254			VOP_UNLOCK(vp);
1255		vp->v_type = vtyp;
1256		if (vp->v_type == VFIFO) {
1257			vp->v_op = fifo_nfsv2nodeop_p;
1258		}
1259		if (vp->v_type == VCHR || vp->v_type == VBLK) {
1260			vp->v_op = spec_nfsv2nodeop_p;
1261			nvp = checkalias(vp, (dev_t)rdev, vp->v_mount);
1262			if (nvp) {
1263				/*
1264				 * Discard unneeded vnode, but save its nfsnode.
1265				 */
1266				LIST_REMOVE(np, n_hash);
1267				nvp->v_data = vp->v_data;
1268				vp->v_data = NULL;
1269				vp->v_op = spec_vnodeop_p;
1270				vrele(vp);
1271				vgone(vp);
1272				/*
1273				 * Reinitialize aliased node.
1274				 */
1275				np->n_vnode = nvp;
1276				nhpp = NFSNOHASH(nfs_hash(np->n_fhp, np->n_fhsize));
1277				LIST_INSERT_HEAD(nhpp, np, n_hash);
1278				*vpp = vp = nvp;
1279			}
1280		}
1281		np->n_mtime = mtime.ts_sec;
1282	}
1283	vap = &np->n_vattr;
1284	vap->va_type = vtyp;
1285	vap->va_mode = (vmode & 07777);
1286	vap->va_rdev = (dev_t)rdev;
1287	vap->va_mtime = mtime;
1288	vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0];
1289	if (v3) {
1290		vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink);
1291		vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid);
1292		vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid);
1293		fxdr_hyper(&fp->fa3_size, &vap->va_size);
1294		vap->va_blocksize = NFS_FABLKSIZE;
1295		fxdr_hyper(&fp->fa3_used, &vap->va_bytes);
1296		vap->va_fileid = fxdr_unsigned(int, fp->fa3_fileid.nfsuquad[1]);
1297		fxdr_nfsv3time(&fp->fa3_atime, &vap->va_atime);
1298		fxdr_nfsv3time(&fp->fa3_ctime, &vap->va_ctime);
1299		vap->va_flags = 0;
1300		vap->va_filerev = 0;
1301	} else {
1302		vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink);
1303		vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid);
1304		vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid);
1305		vap->va_size = fxdr_unsigned(u_long, fp->fa2_size);
1306		vap->va_blocksize = fxdr_unsigned(long, fp->fa2_blocksize);
1307		vap->va_bytes = fxdr_unsigned(long, fp->fa2_blocks) * NFS_FABLKSIZE;
1308		vap->va_fileid = fxdr_unsigned(long, fp->fa2_fileid);
1309		fxdr_nfsv2time(&fp->fa2_atime, &vap->va_atime);
1310		vap->va_flags = 0;
1311		vap->va_ctime.ts_sec = fxdr_unsigned(long, fp->fa2_ctime.nfsv2_sec);
1312		vap->va_ctime.ts_nsec = 0;
1313		vap->va_gen = fxdr_unsigned(u_long, fp->fa2_ctime.nfsv2_usec);
1314		vap->va_filerev = 0;
1315	}
1316	if (vap->va_size != np->n_size) {
1317		if (vap->va_type == VREG) {
1318			if (np->n_flag & NMODIFIED) {
1319				if (vap->va_size < np->n_size)
1320					vap->va_size = np->n_size;
1321				else
1322					np->n_size = vap->va_size;
1323			} else
1324				np->n_size = vap->va_size;
1325			vnode_pager_setsize(vp, (u_long)np->n_size);
1326		} else
1327			np->n_size = vap->va_size;
1328	}
1329	np->n_attrstamp = time.tv_sec;
1330	if (vaper != NULL) {
1331		bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(*vap));
1332		if (np->n_flag & NCHG) {
1333			if (np->n_flag & NACC)
1334				vaper->va_atime = np->n_atim;
1335			if (np->n_flag & NUPD)
1336				vaper->va_mtime = np->n_mtim;
1337		}
1338	}
1339	return (0);
1340}
1341
1342/*
1343 * Check the time stamp
1344 * If the cache is valid, copy contents to *vap and return 0
1345 * otherwise return an error
1346 */
1347int
1348nfs_getattrcache(vp, vaper)
1349	register struct vnode *vp;
1350	struct vattr *vaper;
1351{
1352	register struct nfsnode *np = VTONFS(vp);
1353	register struct vattr *vap;
1354
1355	if ((time.tv_sec - np->n_attrstamp) >= NFS_ATTRTIMEO(np)) {
1356		nfsstats.attrcache_misses++;
1357		return (ENOENT);
1358	}
1359	nfsstats.attrcache_hits++;
1360	vap = &np->n_vattr;
1361	if (vap->va_size != np->n_size) {
1362		if (vap->va_type == VREG) {
1363			if (np->n_flag & NMODIFIED) {
1364				if (vap->va_size < np->n_size)
1365					vap->va_size = np->n_size;
1366				else
1367					np->n_size = vap->va_size;
1368			} else
1369				np->n_size = vap->va_size;
1370			vnode_pager_setsize(vp, (u_long)np->n_size);
1371		} else
1372			np->n_size = vap->va_size;
1373	}
1374	bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(struct vattr));
1375	if (np->n_flag & NCHG) {
1376		if (np->n_flag & NACC)
1377			vaper->va_atime = np->n_atim;
1378		if (np->n_flag & NUPD)
1379			vaper->va_mtime = np->n_mtim;
1380	}
1381	return (0);
1382}
1383
1384/*
1385 * Set up nameidata for a lookup() call and do it
1386 */
1387int
1388nfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, retdirp, p, kerbflag)
1389	register struct nameidata *ndp;
1390	fhandle_t *fhp;
1391	int len;
1392	struct nfssvc_sock *slp;
1393	struct mbuf *nam;
1394	struct mbuf **mdp;
1395	caddr_t *dposp;
1396	struct vnode **retdirp;
1397	struct proc *p;
1398	int kerbflag;
1399{
1400	register int i, rem;
1401	register struct mbuf *md;
1402	register char *fromcp, *tocp;
1403	struct vnode *dp;
1404	int error, rdonly;
1405	struct componentname *cnp = &ndp->ni_cnd;
1406
1407	*retdirp = (struct vnode *)0;
1408	MALLOC(cnp->cn_pnbuf, char *, len + 1, M_NAMEI, M_WAITOK);
1409	/*
1410	 * Copy the name from the mbuf list to ndp->ni_pnbuf
1411	 * and set the various ndp fields appropriately.
1412	 */
1413	fromcp = *dposp;
1414	tocp = cnp->cn_pnbuf;
1415	md = *mdp;
1416	rem = mtod(md, caddr_t) + md->m_len - fromcp;
1417	cnp->cn_hash = 0;
1418	for (i = 0; i < len; i++) {
1419		while (rem == 0) {
1420			md = md->m_next;
1421			if (md == NULL) {
1422				error = EBADRPC;
1423				goto out;
1424			}
1425			fromcp = mtod(md, caddr_t);
1426			rem = md->m_len;
1427		}
1428		if (*fromcp == '\0' || *fromcp == '/') {
1429			error = EACCES;
1430			goto out;
1431		}
1432		cnp->cn_hash += (unsigned char)*fromcp;
1433		*tocp++ = *fromcp++;
1434		rem--;
1435	}
1436	*tocp = '\0';
1437	*mdp = md;
1438	*dposp = fromcp;
1439	len = nfsm_rndup(len)-len;
1440	if (len > 0) {
1441		if (rem >= len)
1442			*dposp += len;
1443		else if (error = nfs_adv(mdp, dposp, len, rem))
1444			goto out;
1445	}
1446	ndp->ni_pathlen = tocp - cnp->cn_pnbuf;
1447	cnp->cn_nameptr = cnp->cn_pnbuf;
1448	/*
1449	 * Extract and set starting directory.
1450	 */
1451	if (error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cnd.cn_cred, slp,
1452	    nam, &rdonly, kerbflag))
1453		goto out;
1454	if (dp->v_type != VDIR) {
1455		nfsrv_vrele(dp);
1456		error = ENOTDIR;
1457		goto out;
1458	}
1459	VREF(dp);
1460	*retdirp = dp;
1461	ndp->ni_startdir = dp;
1462	if (rdonly)
1463		cnp->cn_flags |= (NOCROSSMOUNT | RDONLY);
1464	else
1465		cnp->cn_flags |= NOCROSSMOUNT;
1466	/*
1467	 * And call lookup() to do the real work
1468	 */
1469	cnp->cn_proc = p;
1470	if (error = lookup(ndp))
1471		goto out;
1472	/*
1473	 * Check for encountering a symbolic link
1474	 */
1475	if (cnp->cn_flags & ISSYMLINK) {
1476		if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1)
1477			vput(ndp->ni_dvp);
1478		else
1479			vrele(ndp->ni_dvp);
1480		vput(ndp->ni_vp);
1481		ndp->ni_vp = NULL;
1482		error = EINVAL;
1483		goto out;
1484	}
1485
1486	nfsrv_vmio(ndp->ni_vp);
1487
1488	/*
1489	 * Check for saved name request
1490	 */
1491	if (cnp->cn_flags & (SAVENAME | SAVESTART)) {
1492		cnp->cn_flags |= HASBUF;
1493		return (0);
1494	}
1495out:
1496	FREE(cnp->cn_pnbuf, M_NAMEI);
1497	return (error);
1498}
1499
1500/*
1501 * A fiddled version of m_adj() that ensures null fill to a long
1502 * boundary and only trims off the back end
1503 */
1504void
1505nfsm_adj(mp, len, nul)
1506	struct mbuf *mp;
1507	register int len;
1508	int nul;
1509{
1510	register struct mbuf *m;
1511	register int count, i;
1512	register char *cp;
1513
1514	/*
1515	 * Trim from tail.  Scan the mbuf chain,
1516	 * calculating its length and finding the last mbuf.
1517	 * If the adjustment only affects this mbuf, then just
1518	 * adjust and return.  Otherwise, rescan and truncate
1519	 * after the remaining size.
1520	 */
1521	count = 0;
1522	m = mp;
1523	for (;;) {
1524		count += m->m_len;
1525		if (m->m_next == (struct mbuf *)0)
1526			break;
1527		m = m->m_next;
1528	}
1529	if (m->m_len > len) {
1530		m->m_len -= len;
1531		if (nul > 0) {
1532			cp = mtod(m, caddr_t)+m->m_len-nul;
1533			for (i = 0; i < nul; i++)
1534				*cp++ = '\0';
1535		}
1536		return;
1537	}
1538	count -= len;
1539	if (count < 0)
1540		count = 0;
1541	/*
1542	 * Correct length for chain is "count".
1543	 * Find the mbuf with last data, adjust its length,
1544	 * and toss data from remaining mbufs on chain.
1545	 */
1546	for (m = mp; m; m = m->m_next) {
1547		if (m->m_len >= count) {
1548			m->m_len = count;
1549			if (nul > 0) {
1550				cp = mtod(m, caddr_t)+m->m_len-nul;
1551				for (i = 0; i < nul; i++)
1552					*cp++ = '\0';
1553			}
1554			break;
1555		}
1556		count -= m->m_len;
1557	}
1558	for (m = m->m_next;m;m = m->m_next)
1559		m->m_len = 0;
1560}
1561
1562/*
1563 * Make these functions instead of macros, so that the kernel text size
1564 * doesn't get too big...
1565 */
1566void
1567nfsm_srvwcc(nfsd, before_ret, before_vap, after_ret, after_vap, mbp, bposp)
1568	struct nfsrv_descript *nfsd;
1569	int before_ret;
1570	register struct vattr *before_vap;
1571	int after_ret;
1572	struct vattr *after_vap;
1573	struct mbuf **mbp;
1574	char **bposp;
1575{
1576	register struct mbuf *mb = *mbp, *mb2;
1577	register char *bpos = *bposp;
1578	register u_long *tl;
1579
1580	if (before_ret) {
1581		nfsm_build(tl, u_long *, NFSX_UNSIGNED);
1582		*tl = nfs_false;
1583	} else {
1584		nfsm_build(tl, u_long *, 7 * NFSX_UNSIGNED);
1585		*tl++ = nfs_true;
1586		txdr_hyper(&(before_vap->va_size), tl);
1587		tl += 2;
1588		txdr_nfsv3time(&(before_vap->va_mtime), tl);
1589		tl += 2;
1590		txdr_nfsv3time(&(before_vap->va_ctime), tl);
1591	}
1592	*bposp = bpos;
1593	*mbp = mb;
1594	nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp);
1595}
1596
1597void
1598nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp)
1599	struct nfsrv_descript *nfsd;
1600	int after_ret;
1601	struct vattr *after_vap;
1602	struct mbuf **mbp;
1603	char **bposp;
1604{
1605	register struct mbuf *mb = *mbp, *mb2;
1606	register char *bpos = *bposp;
1607	register u_long *tl;
1608	register struct nfs_fattr *fp;
1609
1610	if (after_ret) {
1611		nfsm_build(tl, u_long *, NFSX_UNSIGNED);
1612		*tl = nfs_false;
1613	} else {
1614		nfsm_build(tl, u_long *, NFSX_UNSIGNED + NFSX_V3FATTR);
1615		*tl++ = nfs_true;
1616		fp = (struct nfs_fattr *)tl;
1617		nfsm_srvfattr(nfsd, after_vap, fp);
1618	}
1619	*mbp = mb;
1620	*bposp = bpos;
1621}
1622
1623void
1624nfsm_srvfattr(nfsd, vap, fp)
1625	register struct nfsrv_descript *nfsd;
1626	register struct vattr *vap;
1627	register struct nfs_fattr *fp;
1628{
1629
1630	fp->fa_nlink = txdr_unsigned(vap->va_nlink);
1631	fp->fa_uid = txdr_unsigned(vap->va_uid);
1632	fp->fa_gid = txdr_unsigned(vap->va_gid);
1633	if (nfsd->nd_flag & ND_NFSV3) {
1634		fp->fa_type = vtonfsv3_type(vap->va_type);
1635		fp->fa_mode = vtonfsv3_mode(vap->va_mode);
1636		txdr_hyper(&vap->va_size, &fp->fa3_size);
1637		txdr_hyper(&vap->va_bytes, &fp->fa3_used);
1638		fp->fa3_rdev.specdata1 = txdr_unsigned(major(vap->va_rdev));
1639		fp->fa3_rdev.specdata2 = txdr_unsigned(minor(vap->va_rdev));
1640		fp->fa3_fsid.nfsuquad[0] = 0;
1641		fp->fa3_fsid.nfsuquad[1] = txdr_unsigned(vap->va_fsid);
1642		fp->fa3_fileid.nfsuquad[0] = 0;
1643		fp->fa3_fileid.nfsuquad[1] = txdr_unsigned(vap->va_fileid);
1644		txdr_nfsv3time(&vap->va_atime, &fp->fa3_atime);
1645		txdr_nfsv3time(&vap->va_mtime, &fp->fa3_mtime);
1646		txdr_nfsv3time(&vap->va_ctime, &fp->fa3_ctime);
1647	} else {
1648		fp->fa_type = vtonfsv2_type(vap->va_type);
1649		fp->fa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode);
1650		fp->fa2_size = txdr_unsigned(vap->va_size);
1651		fp->fa2_blocksize = txdr_unsigned(vap->va_blocksize);
1652		if (vap->va_type == VFIFO)
1653			fp->fa2_rdev = 0xffffffff;
1654		else
1655			fp->fa2_rdev = txdr_unsigned(vap->va_rdev);
1656		fp->fa2_blocks = txdr_unsigned(vap->va_bytes / NFS_FABLKSIZE);
1657		fp->fa2_fsid = txdr_unsigned(vap->va_fsid);
1658		fp->fa2_fileid = txdr_unsigned(vap->va_fileid);
1659		txdr_nfsv2time(&vap->va_atime, &fp->fa2_atime);
1660		txdr_nfsv2time(&vap->va_mtime, &fp->fa2_mtime);
1661		txdr_nfsv2time(&vap->va_ctime, &fp->fa2_ctime);
1662	}
1663}
1664
1665/*
1666 * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked)
1667 * 	- look up fsid in mount list (if not found ret error)
1668 *	- get vp and export rights by calling VFS_FHTOVP()
1669 *	- if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon
1670 *	- if not lockflag unlock it with VOP_UNLOCK()
1671 */
1672int
1673nfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp, kerbflag)
1674	fhandle_t *fhp;
1675	int lockflag;
1676	struct vnode **vpp;
1677	struct ucred *cred;
1678	struct nfssvc_sock *slp;
1679	struct mbuf *nam;
1680	int *rdonlyp;
1681	int kerbflag;
1682{
1683	register struct mount *mp;
1684	register struct nfsuid *uidp;
1685	register int i;
1686	struct ucred *credanon;
1687	int error, exflags;
1688
1689	*vpp = (struct vnode *)0;
1690	mp = getvfs(&fhp->fh_fsid);
1691	if (!mp)
1692		return (ESTALE);
1693	error = VFS_FHTOVP(mp, &fhp->fh_fid, nam, vpp, &exflags, &credanon);
1694	if (error)
1695		return (error);
1696	/*
1697	 * Check/setup credentials.
1698	 */
1699	if (exflags & MNT_EXKERB) {
1700		if (!kerbflag) {
1701			vput(*vpp);
1702			return (NFSERR_AUTHERR | AUTH_TOOWEAK);
1703		}
1704	} else if (kerbflag) {
1705		vput(*vpp);
1706		return (NFSERR_AUTHERR | AUTH_TOOWEAK);
1707	} else if (cred->cr_uid == 0 || (exflags & MNT_EXPORTANON)) {
1708		cred->cr_uid = credanon->cr_uid;
1709		for (i = 0; i < credanon->cr_ngroups && i < NGROUPS; i++)
1710			cred->cr_groups[i] = credanon->cr_groups[i];
1711		cred->cr_ngroups = i;
1712	}
1713	if (exflags & MNT_EXRDONLY)
1714		*rdonlyp = 1;
1715	else
1716		*rdonlyp = 0;
1717
1718	nfsrv_vmio(*vpp);
1719
1720	if (!lockflag)
1721		VOP_UNLOCK(*vpp);
1722	return (0);
1723}
1724
1725/*
1726 * This function compares two net addresses by family and returns TRUE
1727 * if they are the same host.
1728 * If there is any doubt, return FALSE.
1729 * The AF_INET family is handled as a special case so that address mbufs
1730 * don't need to be saved to store "struct in_addr", which is only 4 bytes.
1731 */
1732int
1733netaddr_match(family, haddr, nam)
1734	int family;
1735	union nethostaddr *haddr;
1736	struct mbuf *nam;
1737{
1738	register struct sockaddr_in *inetaddr;
1739
1740	switch (family) {
1741	case AF_INET:
1742		inetaddr = mtod(nam, struct sockaddr_in *);
1743		if (inetaddr->sin_family == AF_INET &&
1744		    inetaddr->sin_addr.s_addr == haddr->had_inetaddr)
1745			return (1);
1746		break;
1747#ifdef ISO
1748	case AF_ISO:
1749	    {
1750		register struct sockaddr_iso *isoaddr1, *isoaddr2;
1751
1752		isoaddr1 = mtod(nam, struct sockaddr_iso *);
1753		isoaddr2 = mtod(haddr->had_nam, struct sockaddr_iso *);
1754		if (isoaddr1->siso_family == AF_ISO &&
1755		    isoaddr1->siso_nlen > 0 &&
1756		    isoaddr1->siso_nlen == isoaddr2->siso_nlen &&
1757		    SAME_ISOADDR(isoaddr1, isoaddr2))
1758			return (1);
1759		break;
1760	    }
1761#endif	/* ISO */
1762	default:
1763		break;
1764	};
1765	return (0);
1766}
1767
1768static nfsuint64 nfs_nullcookie = { 0, 0 };
1769/*
1770 * This function finds the directory cookie that corresponds to the
1771 * logical byte offset given.
1772 */
1773nfsuint64 *
1774nfs_getcookie(np, off, add)
1775	register struct nfsnode *np;
1776	off_t off;
1777	int add;
1778{
1779	register struct nfsdmap *dp, *dp2;
1780	register int pos;
1781
1782	pos = off / NFS_DIRBLKSIZ;
1783	if (pos == 0) {
1784#ifdef DIAGNOSTIC
1785		if (add)
1786			panic("nfs getcookie add at 0");
1787#endif
1788		return (&nfs_nullcookie);
1789	}
1790	pos--;
1791	dp = np->n_cookies.lh_first;
1792	if (!dp) {
1793		if (add) {
1794			MALLOC(dp, struct nfsdmap *, sizeof (struct nfsdmap),
1795				M_NFSDIROFF, M_WAITOK);
1796			dp->ndm_eocookie = 0;
1797			LIST_INSERT_HEAD(&np->n_cookies, dp, ndm_list);
1798		} else
1799			return ((nfsuint64 *)0);
1800	}
1801	while (pos >= NFSNUMCOOKIES) {
1802		pos -= NFSNUMCOOKIES;
1803		if (dp->ndm_list.le_next) {
1804			if (!add && dp->ndm_eocookie < NFSNUMCOOKIES &&
1805				pos >= dp->ndm_eocookie)
1806				return ((nfsuint64 *)0);
1807			dp = dp->ndm_list.le_next;
1808		} else if (add) {
1809			MALLOC(dp2, struct nfsdmap *, sizeof (struct nfsdmap),
1810				M_NFSDIROFF, M_WAITOK);
1811			dp2->ndm_eocookie = 0;
1812			LIST_INSERT_AFTER(dp, dp2, ndm_list);
1813			dp = dp2;
1814		} else
1815			return ((nfsuint64 *)0);
1816	}
1817	if (pos >= dp->ndm_eocookie) {
1818		if (add)
1819			dp->ndm_eocookie = pos + 1;
1820		else
1821			return ((nfsuint64 *)0);
1822	}
1823	return (&dp->ndm_cookies[pos]);
1824}
1825
1826/*
1827 * Invalidate cached directory information, except for the actual directory
1828 * blocks (which are invalidated separately).
1829 * Done mainly to avoid the use of stale offset cookies.
1830 */
1831void
1832nfs_invaldir(vp)
1833	register struct vnode *vp;
1834{
1835	register struct nfsnode *np = VTONFS(vp);
1836
1837#ifdef DIAGNOSTIC
1838	if (vp->v_type != VDIR)
1839		panic("nfs: invaldir not dir");
1840#endif
1841	np->n_direofoffset = 0;
1842	np->n_cookieverf.nfsuquad[0] = 0;
1843	np->n_cookieverf.nfsuquad[1] = 0;
1844	if (np->n_cookies.lh_first)
1845		np->n_cookies.lh_first->ndm_eocookie = 0;
1846}
1847
1848/*
1849 * The write verifier has changed (probably due to a server reboot), so all
1850 * B_NEEDCOMMIT blocks will have to be written again. Since they are on the
1851 * dirty block list as B_DELWRI, all this takes is clearing the B_NEEDCOMMIT
1852 * flag. Once done the new write verifier can be set for the mount point.
1853 */
1854void
1855nfs_clearcommit(mp)
1856	struct mount *mp;
1857{
1858	register struct vnode *vp, *nvp;
1859	register struct buf *bp, *nbp;
1860	int s;
1861
1862	s = splbio();
1863loop:
1864	for (vp = mp->mnt_vnodelist.lh_first; vp; vp = nvp) {
1865		if (vp->v_mount != mp)	/* Paranoia */
1866			goto loop;
1867		nvp = vp->v_mntvnodes.le_next;
1868		for (bp = vp->v_dirtyblkhd.lh_first; bp; bp = nbp) {
1869			nbp = bp->b_vnbufs.le_next;
1870			if ((bp->b_flags & (B_BUSY | B_DELWRI | B_NEEDCOMMIT))
1871				== (B_DELWRI | B_NEEDCOMMIT))
1872				bp->b_flags &= ~B_NEEDCOMMIT;
1873		}
1874	}
1875	splx(s);
1876}
1877
1878/*
1879 * Map errnos to NFS error numbers. For Version 3 also filter out error
1880 * numbers not specified for the associated procedure.
1881 */
1882int
1883nfsrv_errmap(nd, err)
1884	struct nfsrv_descript *nd;
1885	register int err;
1886{
1887	register short *defaulterrp, *errp;
1888
1889	if (nd->nd_flag & ND_NFSV3) {
1890	    if (nd->nd_procnum <= NFSPROC_COMMIT) {
1891		errp = defaulterrp = nfsrv_v3errmap[nd->nd_procnum];
1892		while (*++errp) {
1893			if (*errp == err)
1894				return (err);
1895			else if (*errp > err)
1896				break;
1897		}
1898		return ((int)*defaulterrp);
1899	    } else
1900		return (err & 0xffff);
1901	}
1902	if (err <= ELAST)
1903		return ((int)nfsrv_v2errmap[err - 1]);
1904	return (NFSERR_IO);
1905}
1906
1907int
1908nfsrv_vmio(struct vnode *vp) {
1909	vm_object_t object;
1910
1911	if ((vp == NULL) || (vp->v_type != VREG))
1912		return 1;
1913
1914retry:
1915	if ((vp->v_flag & VVMIO) == 0) {
1916		struct vattr vat;
1917		struct proc *p = curproc;
1918
1919		if (VOP_GETATTR(vp, &vat, p->p_ucred, p) != 0)
1920			panic("nfsrv_vmio: VOP_GETATTR failed");
1921
1922		(void) vnode_pager_alloc(vp, vat.va_size, 0, 0);
1923
1924		vp->v_flag |= VVMIO;
1925	} else {
1926		if ((object = vp->v_object) &&
1927			(object->flags & OBJ_DEAD)) {
1928			tsleep(object, PVM, "nfdead", 0);
1929			goto retry;
1930		}
1931		if (!object)
1932			panic("nfsrv_vmio: VMIO object missing");
1933		vm_object_reference(object);
1934	}
1935	return 0;
1936}
1937int
1938nfsrv_vput(struct vnode *vp) {
1939	if ((vp->v_flag & VVMIO) && vp->v_object) {
1940		vput(vp);
1941		vm_object_deallocate(vp->v_object);
1942	} else {
1943		vput(vp);
1944	}
1945	return 0;
1946}
1947int
1948nfsrv_vrele(struct vnode *vp) {
1949	if ((vp->v_flag & VVMIO) && vp->v_object) {
1950		vrele(vp);
1951		vm_object_deallocate(vp->v_object);
1952	} else {
1953		vrele(vp);
1954	}
1955	return 0;
1956}
1957