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