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