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