nfs_subs.c revision 36176
1139749Simp/*
2578Srgrimes * Copyright (c) 1989, 1993
3578Srgrimes *	The Regents of the University of California.  All rights reserved.
41197Srgrimes *
56604Sache * This code is derived from software contributed to Berkeley by
61197Srgrimes * Rick Macklem at The University of Guelph.
71197Srgrimes *
81197Srgrimes * Redistribution and use in source and binary forms, with or without
91197Srgrimes * modification, are permitted provided that the following conditions
10578Srgrimes * are met:
11578Srgrimes * 1. Redistributions of source code must retain the above copyright
12578Srgrimes *    notice, this list of conditions and the following disclaimer.
13578Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
14578Srgrimes *    notice, this list of conditions and the following disclaimer in the
15578Srgrimes *    documentation and/or other materials provided with the distribution.
16578Srgrimes * 3. All advertising materials mentioning features or use of this software
17578Srgrimes *    must display the following acknowledgement:
18578Srgrimes *	This product includes software developed by the University of
19578Srgrimes *	California, Berkeley and its contributors.
20578Srgrimes * 4. Neither the name of the University nor the names of its contributors
21578Srgrimes *    may be used to endorse or promote products derived from this software
22578Srgrimes *    without specific prior written permission.
231197Srgrimes *
24578Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25578Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26578Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27578Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28578Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29578Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30578Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31578Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32578Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33578Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34578Srgrimes * SUCH DAMAGE.
35578Srgrimes *
36578Srgrimes *	@(#)nfs_subs.c	8.3 (Berkeley) 1/4/94
37578Srgrimes * $Id: nfs_subs.c,v 1.53 1998/04/06 11:41:07 phk Exp $
38578Srgrimes */
39578Srgrimes
40578Srgrimes/*
41578Srgrimes * These functions support the macros and help fiddle mbuf chains for
42578Srgrimes * the nfs op functions. They do things like create the rpc header and
43578Srgrimes * copy data between mbuf chains and uio lists.
44119418Sobrien */
45119418Sobrien#include <sys/param.h>
46119418Sobrien#include <sys/buf.h>
47260276Sdim#include <sys/proc.h>
48578Srgrimes#include <sys/systm.h>
492056Swollman#include <sys/kernel.h>
502056Swollman#include <sys/mount.h>
5161011Speter#include <sys/vnode.h>
522056Swollman#include <sys/namei.h>
5324131Sbde#include <sys/mbuf.h>
5460041Sphk#include <sys/socket.h>
552056Swollman#include <sys/stat.h>
56104545Smdodd#include <sys/malloc.h>
5761011Speter#include <sys/sysent.h>
583816Swollman#include <sys/syscall.h>
59104445Smdodd
60104445Smdodd#include <vm/vm.h>
61104445Smdodd#include <vm/vm_object.h>
627430Sbde#include <vm/vm_extern.h>
63104445Smdodd#include <vm/vm_zone.h>
64104445Smdodd
65104445Smdodd#include <nfs/rpcv2.h>
66104445Smdodd#include <nfs/nfsproto.h>
67578Srgrimes#include <nfs/nfs.h>
68115477Sphk#include <nfs/nfsnode.h>
698375Srgrimes#include <nfs/xdr_subs.h>
70104445Smdodd#include <nfs/nfsm_subs.h>
71104445Smdodd#include <nfs/nfsmount.h>
72104445Smdodd#include <nfs/nqnfs.h>
738375Srgrimes#include <nfs/nfsrtt.h>
748375Srgrimes
758375Srgrimes#include <miscfs/specfs/specdev.h>
76578Srgrimes
772395Sache#include <netinet/in.h>
78578Srgrimes#ifdef ISO
79578Srgrimes#include <netiso/iso.h>
8014654Sache#endif
8114654Sache
8214654Sache/*
8314654Sache * Data items converted to xdr at startup, since they are constant
8414654Sache * This is kinda hokey, but may save a little time doing byte swaps
8514654Sache */
8614654Sacheu_long nfs_xdrneg1;
8714654Sacheu_long rpc_call, rpc_vers, rpc_reply, rpc_msgdenied, rpc_autherr,
8814654Sache	rpc_mismatch, rpc_auth_unix, rpc_msgaccepted,
89578Srgrimes	rpc_auth_kerb;
90578Srgrimesu_long nfs_prog, nqnfs_prog, nfs_true, nfs_false;
91578Srgrimes
92578Srgrimes/* And other global data */
93578Srgrimesstatic u_long nfs_xid = 0;
94578Srgrimesstatic enum vtype nv2tov_type[8]= {
95578Srgrimes	VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON,  VNON
961241Sjkh};
971241Sjkhenum vtype nv3tov_type[8]= {
981241Sjkh	VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO
991241Sjkh};
1001241Sjkh
1011237Sjkhint nfs_mount_type;
1022477Sacheint nfs_ticks;
1032477Sache
1044480Sachestruct nfs_reqq nfs_reqq;
1054480Sachestruct nfssvc_sockhead nfssvc_sockhead;
1064480Sacheint nfssvc_sockhead_flag;
10713874Sachestruct nfsd_head nfsd_head;
10813874Sacheint nfsd_head_flag;
10913874Sachestruct nfs_bufq nfs_bufq;
1104480Sachestruct nqtimerhead nqtimerhead;
111578Srgrimesstruct nqfhhashhead *nqfhhashtbl;
112578Srgrimesu_long nqfhhash;
113578Srgrimes
114578Srgrimes#ifndef NFS_NOSERVER
115578Srgrimes/*
116578Srgrimes * Mapping of old NFS Version 2 RPC numbers to generic numbers.
117578Srgrimes */
118578Srgrimesint nfsv3_procid[NFS_NPROCS] = {
119104445Smdodd	NFSPROC_NULL,
12011872Sphk	NFSPROC_GETATTR,
121104445Smdodd	NFSPROC_SETATTR,
12211872Sphk	NFSPROC_NOOP,
123104445Smdodd	NFSPROC_LOOKUP,
124104445Smdodd	NFSPROC_READLINK,
125104445Smdodd	NFSPROC_READ,
126104445Smdodd	NFSPROC_NOOP,
127104445Smdodd	NFSPROC_WRITE,
128104445Smdodd	NFSPROC_CREATE,
129104445Smdodd	NFSPROC_REMOVE,
130104445Smdodd	NFSPROC_RENAME,
131104445Smdodd	NFSPROC_LINK,
132104445Smdodd	NFSPROC_SYMLINK,
133104445Smdodd	NFSPROC_MKDIR,
134104445Smdodd	NFSPROC_RMDIR,
135104445Smdodd	NFSPROC_READDIR,
136104445Smdodd	NFSPROC_FSSTAT,
137141031Ssobomax	NFSPROC_NOOP,
138141031Ssobomax	NFSPROC_NOOP,
139104445Smdodd	NFSPROC_NOOP,
140104445Smdodd	NFSPROC_NOOP,
141104445Smdodd	NFSPROC_NOOP,
14231016Sphk	NFSPROC_NOOP,
143104445Smdodd	NFSPROC_NOOP,
14431016Sphk	NFSPROC_NOOP
145104445Smdodd};
146104445Smdodd
147104445Smdodd#endif /* NFS_NOSERVER */
148104445Smdodd/*
149104445Smdodd * and the reverse mapping from generic to Version 2 procedure numbers
150104445Smdodd */
151104445Smdoddint nfsv2_procid[NFS_NPROCS] = {
152104445Smdodd	NFSV2PROC_NULL,
153104445Smdodd	NFSV2PROC_GETATTR,
154104445Smdodd	NFSV2PROC_SETATTR,
155104445Smdodd	NFSV2PROC_LOOKUP,
156130585Sphk	NFSV2PROC_NOOP,
157578Srgrimes	NFSV2PROC_READLINK,
158104445Smdodd	NFSV2PROC_READ,
159104445Smdodd	NFSV2PROC_WRITE,
160104445Smdodd	NFSV2PROC_CREATE,
161104445Smdodd	NFSV2PROC_MKDIR,
162578Srgrimes	NFSV2PROC_SYMLINK,
16337389Sjulian	NFSV2PROC_CREATE,
164126080Sphk	NFSV2PROC_REMOVE,
165111815Sphk	NFSV2PROC_RMDIR,
166111815Sphk	NFSV2PROC_RENAME,
167111815Sphk	NFSV2PROC_LINK,
168111815Sphk	NFSV2PROC_READDIR,
169111815Sphk	NFSV2PROC_NOOP,
170111815Sphk	NFSV2PROC_STATFS,
171126080Sphk	NFSV2PROC_NOOP,
17247625Sphk	NFSV2PROC_NOOP,
17337389Sjulian	NFSV2PROC_NOOP,
174578Srgrimes	NFSV2PROC_NOOP,
175578Srgrimes	NFSV2PROC_NOOP,
176578Srgrimes	NFSV2PROC_NOOP,
1776604Sache	NFSV2PROC_NOOP,
1786604Sache};
1796604Sache
1806604Sache#ifndef NFS_NOSERVER
181578Srgrimes/*
1822477Sache * Maps errno values to nfs error numbers.
1832477Sache * Use NFSERR_IO as the catch all for ones not specifically defined in
184578Srgrimes * RFC 1094.
185578Srgrimes */
1862477Sachestatic u_char nfsrv_v2errmap[ELAST] = {
18710069Sjoerg  NFSERR_PERM,	NFSERR_NOENT,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
188578Srgrimes  NFSERR_NXIO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
189104445Smdodd  NFSERR_IO,	NFSERR_IO,	NFSERR_ACCES,	NFSERR_IO,	NFSERR_IO,
190104445Smdodd  NFSERR_IO,	NFSERR_EXIST,	NFSERR_IO,	NFSERR_NODEV,	NFSERR_NOTDIR,
191578Srgrimes  NFSERR_ISDIR,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
192104445Smdodd  NFSERR_IO,	NFSERR_FBIG,	NFSERR_NOSPC,	NFSERR_IO,	NFSERR_ROFS,
1938876Srgrimes  NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
194104445Smdodd  NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
195104445Smdodd  NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
196106490Smdodd  NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
197104445Smdodd  NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
198106490Smdodd  NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
199578Srgrimes  NFSERR_IO,	NFSERR_IO,	NFSERR_NAMETOL,	NFSERR_IO,	NFSERR_IO,
200578Srgrimes  NFSERR_NOTEMPTY, NFSERR_IO,	NFSERR_IO,	NFSERR_DQUOT,	NFSERR_STALE,
201578Srgrimes  NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
202104445Smdodd  NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
203578Srgrimes  NFSERR_IO,
2044480Sache};
205104545Smdodd
206104445Smdodd/*
207104445Smdodd * Maps errno values to nfs error numbers.
208104545Smdodd * Although it is not obvious whether or not NFS clients really care if
209104445Smdodd * a returned error value is in the specified list for the procedure, the
210106490Smdodd * safest thing to do is filter them appropriately. For Version 2, the
211578Srgrimes * X/Open XNFS document is the only specification that defines error values
212578Srgrimes * for each RPC (The RFC simply lists all possible error values for all RPCs),
213104441Smdodd * so I have decided to not do this for Version 2.
214130585Sphk * The first entry is the default error return and the rest are the valid
215578Srgrimes * errors for that RPC in increasing numeric order.
216104445Smdodd */
217104545Smdoddstatic short nfsv3err_null[] = {
2188876Srgrimes	0,
219104445Smdodd	0,
2208876Srgrimes};
221578Srgrimes
222106490Smdoddstatic short nfsv3err_getattr[] = {
223106490Smdodd	NFSERR_IO,
224578Srgrimes	NFSERR_IO,
225578Srgrimes	NFSERR_STALE,
226106490Smdodd	NFSERR_BADHANDLE,
227106490Smdodd	NFSERR_SERVERFAULT,
228578Srgrimes	0,
229104445Smdodd};
230106490Smdodd
231578Srgrimesstatic short nfsv3err_setattr[] = {
232106490Smdodd	NFSERR_IO,
233106490Smdodd	NFSERR_PERM,
2346604Sache	NFSERR_IO,
235106490Smdodd	NFSERR_ACCES,
236104445Smdodd	NFSERR_INVAL,
237106490Smdodd	NFSERR_NOSPC,
2386604Sache	NFSERR_ROFS,
2396604Sache	NFSERR_DQUOT,
2406604Sache	NFSERR_STALE,
2416604Sache	NFSERR_BADHANDLE,
242106490Smdodd	NFSERR_NOT_SYNC,
243104445Smdodd	NFSERR_SERVERFAULT,
244106490Smdodd	0,
2452477Sache};
246106490Smdodd
247104445Smdoddstatic short nfsv3err_lookup[] = {
248106490Smdodd	NFSERR_IO,
2492477Sache	NFSERR_NOENT,
250106490Smdodd	NFSERR_IO,
251104445Smdodd	NFSERR_ACCES,
252106490Smdodd	NFSERR_NOTDIR,
2536604Sache	NFSERR_NAMETOL,
254578Srgrimes	NFSERR_STALE,
255111731Sphk	NFSERR_BADHANDLE,
256104445Smdodd	NFSERR_SERVERFAULT,
257106490Smdodd	0,
258104545Smdodd};
259578Srgrimes
260106490Smdoddstatic short nfsv3err_access[] = {
261106490Smdodd	NFSERR_IO,
262106490Smdodd	NFSERR_IO,
263578Srgrimes	NFSERR_STALE,
264104545Smdodd	NFSERR_BADHANDLE,
265106490Smdodd	NFSERR_SERVERFAULT,
266106490Smdodd	0,
26751111Sjulian};
268106490Smdodd
269578Srgrimesstatic short nfsv3err_readlink[] = {
270578Srgrimes	NFSERR_IO,
271104441Smdodd	NFSERR_IO,
272130585Sphk	NFSERR_ACCES,
273578Srgrimes	NFSERR_INVAL,
274104445Smdodd	NFSERR_STALE,
2758876Srgrimes	NFSERR_BADHANDLE,
276104445Smdodd	NFSERR_NOTSUPP,
2778876Srgrimes	NFSERR_SERVERFAULT,
278106490Smdodd	0,
279106490Smdodd};
280578Srgrimes
281104445Smdoddstatic short nfsv3err_read[] = {
282106490Smdodd	NFSERR_IO,
283106490Smdodd	NFSERR_IO,
284578Srgrimes	NFSERR_NXIO,
285106490Smdodd	NFSERR_ACCES,
286578Srgrimes	NFSERR_INVAL,
287578Srgrimes	NFSERR_STALE,
288104441Smdodd	NFSERR_BADHANDLE,
28959249Sphk	NFSERR_SERVERFAULT,
290578Srgrimes	0,
291104445Smdodd};
2928876Srgrimes
293104445Smdoddstatic short nfsv3err_write[] = {
294578Srgrimes	NFSERR_IO,
295578Srgrimes	NFSERR_IO,
296106490Smdodd	NFSERR_ACCES,
297104545Smdodd	NFSERR_INVAL,
29859249Sphk	NFSERR_FBIG,
299578Srgrimes	NFSERR_NOSPC,
300578Srgrimes	NFSERR_ROFS,
301578Srgrimes	NFSERR_DQUOT,
302578Srgrimes	NFSERR_STALE,
30359249Sphk	NFSERR_BADHANDLE,
30459249Sphk	NFSERR_SERVERFAULT,
305578Srgrimes	0,
306578Srgrimes};
3078876Srgrimes
308578Srgrimesstatic short nfsv3err_create[] = {
30959249Sphk	NFSERR_IO,
310578Srgrimes	NFSERR_IO,
3118876Srgrimes	NFSERR_ACCES,
312106490Smdodd	NFSERR_EXIST,
313104545Smdodd	NFSERR_NOTDIR,
314104545Smdodd	NFSERR_NOSPC,
315578Srgrimes	NFSERR_ROFS,
3168876Srgrimes	NFSERR_NAMETOL,
317104545Smdodd	NFSERR_DQUOT,
318104545Smdodd	NFSERR_STALE,
319578Srgrimes	NFSERR_BADHANDLE,
320112946Sphk	NFSERR_NOTSUPP,
3218876Srgrimes	NFSERR_SERVERFAULT,
322578Srgrimes	0,
323104445Smdodd};
324578Srgrimes
325578Srgrimesstatic short nfsv3err_mkdir[] = {
326578Srgrimes	NFSERR_IO,
32759249Sphk	NFSERR_IO,
328578Srgrimes	NFSERR_ACCES,
32959249Sphk	NFSERR_EXIST,
330578Srgrimes	NFSERR_NOTDIR,
331578Srgrimes	NFSERR_NOSPC,
332578Srgrimes	NFSERR_ROFS,
333578Srgrimes	NFSERR_NAMETOL,
334104441Smdodd	NFSERR_DQUOT,
335104445Smdodd	NFSERR_STALE,
336578Srgrimes	NFSERR_BADHANDLE,
33759249Sphk	NFSERR_NOTSUPP,
3388876Srgrimes	NFSERR_SERVERFAULT,
339106490Smdodd	0,
340578Srgrimes};
3412477Sache
342578Srgrimesstatic short nfsv3err_symlink[] = {
343137045Sphk	NFSERR_IO,
34415574Sphk	NFSERR_IO,
345578Srgrimes	NFSERR_ACCES,
346578Srgrimes	NFSERR_EXIST,
347106490Smdodd	NFSERR_NOTDIR,
348578Srgrimes	NFSERR_NOSPC,
349578Srgrimes	NFSERR_ROFS,
350578Srgrimes	NFSERR_NAMETOL,
351578Srgrimes	NFSERR_DQUOT,
352578Srgrimes	NFSERR_STALE,
353106490Smdodd	NFSERR_BADHANDLE,
354106490Smdodd	NFSERR_NOTSUPP,
355578Srgrimes	NFSERR_SERVERFAULT,
356106490Smdodd	0,
357578Srgrimes};
358578Srgrimes
359578Srgrimesstatic short nfsv3err_mknod[] = {
360104441Smdodd	NFSERR_IO,
361130585Sphk	NFSERR_IO,
362578Srgrimes	NFSERR_ACCES,
363104445Smdodd	NFSERR_EXIST,
364104545Smdodd	NFSERR_NOTDIR,
3658876Srgrimes	NFSERR_NOSPC,
366104445Smdodd	NFSERR_ROFS,
367578Srgrimes	NFSERR_NAMETOL,
368104445Smdodd	NFSERR_DQUOT,
369106490Smdodd	NFSERR_STALE,
37037618Sbde	NFSERR_BADHANDLE,
371578Srgrimes	NFSERR_NOTSUPP,
372578Srgrimes	NFSERR_SERVERFAULT,
37314285Sache	NFSERR_BADTYPE,
37414285Sache	0,
37514285Sache};
37614285Sache
37714285Sachestatic short nfsv3err_remove[] = {
37814285Sache	NFSERR_IO,
37914285Sache	NFSERR_NOENT,
38014285Sache	NFSERR_IO,
381106490Smdodd	NFSERR_ACCES,
38214285Sache	NFSERR_NOTDIR,
383104445Smdodd	NFSERR_ROFS,
38414285Sache	NFSERR_NAMETOL,
385106490Smdodd	NFSERR_STALE,
386106490Smdodd	NFSERR_BADHANDLE,
38714285Sache	NFSERR_SERVERFAULT,
388106490Smdodd	0,
389106490Smdodd};
39014285Sache
391104445Smdoddstatic short nfsv3err_rmdir[] = {
39214285Sache	NFSERR_IO,
393104445Smdodd	NFSERR_NOENT,
39414285Sache	NFSERR_IO,
395104445Smdodd	NFSERR_ACCES,
39614285Sache	NFSERR_EXIST,
397104445Smdodd	NFSERR_NOTDIR,
39814285Sache	NFSERR_INVAL,
39914285Sache	NFSERR_ROFS,
400106490Smdodd	NFSERR_NAMETOL,
401106490Smdodd	NFSERR_NOTEMPTY,
402106490Smdodd	NFSERR_STALE,
40314285Sache	NFSERR_BADHANDLE,
404106490Smdodd	NFSERR_NOTSUPP,
405104445Smdodd	NFSERR_SERVERFAULT,
406106490Smdodd	0,
40714285Sache};
40814285Sache
40914285Sachestatic short nfsv3err_rename[] = {
410106490Smdodd	NFSERR_IO,
411106490Smdodd	NFSERR_NOENT,
412111731Sphk	NFSERR_IO,
41314285Sache	NFSERR_ACCES,
414106490Smdodd	NFSERR_EXIST,
415106490Smdodd	NFSERR_XDEV,
416106490Smdodd	NFSERR_NOTDIR,
417104445Smdodd	NFSERR_ISDIR,
418106490Smdodd	NFSERR_INVAL,
419106490Smdodd	NFSERR_NOSPC,
42014285Sache	NFSERR_ROFS,
42114285Sache	NFSERR_MLINK,
42214285Sache	NFSERR_NAMETOL,
423104545Smdodd	NFSERR_NOTEMPTY,
424106490Smdodd	NFSERR_DQUOT,
425104545Smdodd	NFSERR_STALE,
426104545Smdodd	NFSERR_BADHANDLE,
427106490Smdodd	NFSERR_NOTSUPP,
428104545Smdodd	NFSERR_SERVERFAULT,
429104545Smdodd	0,
430578Srgrimes};
431104445Smdodd
432578Srgrimesstatic short nfsv3err_link[] = {
433104445Smdodd	NFSERR_IO,
4342477Sache	NFSERR_IO,
435104445Smdodd	NFSERR_ACCES,
436141031Ssobomax	NFSERR_EXIST,
437141031Ssobomax	NFSERR_XDEV,
438578Srgrimes	NFSERR_NOTDIR,
439141031Ssobomax	NFSERR_INVAL,
440578Srgrimes	NFSERR_NOSPC,
441104445Smdodd	NFSERR_ROFS,
442578Srgrimes	NFSERR_MLINK,
443104445Smdodd	NFSERR_NAMETOL,
444578Srgrimes	NFSERR_DQUOT,
445104445Smdodd	NFSERR_STALE,
446578Srgrimes	NFSERR_BADHANDLE,
447104445Smdodd	NFSERR_NOTSUPP,
448578Srgrimes	NFSERR_SERVERFAULT,
449104445Smdodd	0,
450106490Smdodd};
451106490Smdodd
452578Srgrimesstatic short nfsv3err_readdir[] = {
453104445Smdodd	NFSERR_IO,
454578Srgrimes	NFSERR_IO,
455106490Smdodd	NFSERR_ACCES,
456578Srgrimes	NFSERR_NOTDIR,
457578Srgrimes	NFSERR_STALE,
458578Srgrimes	NFSERR_BADHANDLE,
459578Srgrimes	NFSERR_BAD_COOKIE,
460104441Smdodd	NFSERR_TOOSMALL,
461130585Sphk	NFSERR_SERVERFAULT,
462578Srgrimes	0,
463104445Smdodd};
464578Srgrimes
465578Srgrimesstatic short nfsv3err_readdirplus[] = {
466104445Smdodd	NFSERR_IO,
467104445Smdodd	NFSERR_IO,
468104445Smdodd	NFSERR_ACCES,
469106490Smdodd	NFSERR_NOTDIR,
470106490Smdodd	NFSERR_STALE,
471106490Smdodd	NFSERR_BADHANDLE,
472106490Smdodd	NFSERR_BAD_COOKIE,
473578Srgrimes	NFSERR_NOTSUPP,
474106490Smdodd	NFSERR_TOOSMALL,
475578Srgrimes	NFSERR_SERVERFAULT,
476578Srgrimes	0,
477578Srgrimes};
478578Srgrimes
479578Srgrimesstatic short nfsv3err_fsstat[] = {
480578Srgrimes	NFSERR_IO,
481578Srgrimes	NFSERR_IO,
4821197Srgrimes	NFSERR_STALE,
4831197Srgrimes	NFSERR_BADHANDLE,
484578Srgrimes	NFSERR_SERVERFAULT,
485578Srgrimes	0,
486578Srgrimes};
487578Srgrimes
4881197Srgrimesstatic short nfsv3err_fsinfo[] = {
4891197Srgrimes	NFSERR_STALE,
490578Srgrimes	NFSERR_STALE,
491578Srgrimes	NFSERR_BADHANDLE,
492578Srgrimes	NFSERR_SERVERFAULT,
493578Srgrimes	0,
49411872Sphk};
4951197Srgrimes
496104445Smdoddstatic short nfsv3err_pathconf[] = {
497578Srgrimes	NFSERR_STALE,
498104445Smdodd	NFSERR_STALE,
499578Srgrimes	NFSERR_BADHANDLE,
50011872Sphk	NFSERR_SERVERFAULT,
501578Srgrimes	0,
5021197Srgrimes};
5031197Srgrimes
504104445Smdoddstatic short nfsv3err_commit[] = {
5051197Srgrimes	NFSERR_IO,
5061197Srgrimes	NFSERR_IO,
5071197Srgrimes	NFSERR_STALE,
5081197Srgrimes	NFSERR_BADHANDLE,
509104445Smdodd	NFSERR_SERVERFAULT,
510106490Smdodd	0,
5111197Srgrimes};
51213598Sjoerg
513104445Smdoddstatic short *nfsrv_v3errmap[] = {
514106490Smdodd	nfsv3err_null,
5151197Srgrimes	nfsv3err_getattr,
5161197Srgrimes	nfsv3err_setattr,
517978Sjkh	nfsv3err_lookup,
518578Srgrimes	nfsv3err_access,
519104445Smdodd	nfsv3err_readlink,
520104445Smdodd	nfsv3err_read,
521578Srgrimes	nfsv3err_write,
5221197Srgrimes	nfsv3err_create,
5231197Srgrimes	nfsv3err_mkdir,
524578Srgrimes	nfsv3err_symlink,
525104445Smdodd	nfsv3err_mknod,
526578Srgrimes	nfsv3err_remove,
527578Srgrimes	nfsv3err_rmdir,
528578Srgrimes	nfsv3err_rename,
529104445Smdodd	nfsv3err_link,
530578Srgrimes	nfsv3err_readdir,
531104445Smdodd	nfsv3err_readdirplus,
532578Srgrimes	nfsv3err_fsstat,
533578Srgrimes	nfsv3err_fsinfo,
534578Srgrimes	nfsv3err_pathconf,
535104445Smdodd	nfsv3err_commit,
536578Srgrimes};
5371197Srgrimes
5381197Srgrimes#endif /* NFS_NOSERVER */
5391197Srgrimes
5401197Srgrimesextern struct nfsrtt nfsrtt;
5412477Sacheextern time_t nqnfsstarttime;
542104445Smdoddextern int nqsrv_clockskew;
543578Srgrimesextern int nqsrv_writeslack;
5441197Srgrimesextern int nqsrv_maxlease;
545104445Smdoddextern struct nfsstats nfsstats;
546104445Smdoddextern int nqnfs_piggy[NFS_NPROCS];
547104445Smdoddextern nfstype nfsv2_type[9];
5481197Srgrimesextern nfstype nfsv3_type[9];
549104445Smdoddextern struct nfsnodehashhead *nfsnodehashtbl;
5501197Srgrimesextern u_long nfsnodehash;
551104445Smdodd
552104445Smdoddstruct getfh_args;
553104445Smdoddextern int getfh(struct proc *, struct getfh_args *, int *);
5541197Srgrimesstruct nfssvc_args;
5555178Sacheextern int nfssvc(struct proc *, struct nfssvc_args *, int *);
556104445Smdodd
5575226SacheLIST_HEAD(nfsnodehashhead, nfsnode);
558104445Smdodd
559104445Smdoddint nfs_webnamei __P((struct nameidata *, struct vnode *, struct proc *));
5601197Srgrimes
561104445Smdoddu_quad_t
5624480Sachenfs_curusec()
5634480Sache{
56413874Sache	struct timeval tv;
565104445Smdodd
566104445Smdodd	getmicrotime(&tv);
56713874Sache	return ((u_quad_t)tv.tv_sec * 1000000 + (u_quad_t)tv.tv_usec);
568104445Smdodd}
569104445Smdodd
5704480Sache/*
571104445Smdodd * Create the header for an rpc request packet
572104445Smdodd * The hsiz is the size of the rest of the nfs request header.
5734480Sache * (just used to decide if a cluster is a good idea)
5744480Sache */
5754480Sachestruct mbuf *
576104445Smdoddnfsm_reqh(vp, procid, hsiz, bposp)
577104445Smdodd	struct vnode *vp;
5784480Sache	u_long procid;
5794480Sache	int hsiz;
580104445Smdodd	caddr_t *bposp;
581104445Smdodd{
582104445Smdodd	register struct mbuf *mb;
5834480Sache	register u_long *tl;
5844480Sache	register caddr_t bpos;
585104445Smdodd	struct mbuf *mb2;
586104445Smdodd	struct nfsmount *nmp;
5874480Sache	int nqflag;
5884480Sache
5895226Sache	MGET(mb, M_WAIT, MT_DATA);
590104445Smdodd	if (hsiz >= MINCLSIZE)
591104445Smdodd		MCLGET(mb, M_WAIT);
592104445Smdodd	mb->m_len = 0;
593104445Smdodd	bpos = mtod(mb, caddr_t);
594106490Smdodd
595578Srgrimes	/*
596578Srgrimes	 * For NQNFS, add lease request.
597978Sjkh	 */
5981197Srgrimes	if (vp) {
599104445Smdodd		nmp = VFSTONFS(vp->v_mount);
600578Srgrimes		if (nmp->nm_flag & NFSMNT_NQNFS) {
601578Srgrimes			nqflag = NQNFS_NEEDLEASE(vp, procid);
602578Srgrimes			if (nqflag) {
6035226Sache				nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED);
6042477Sache				*tl++ = txdr_unsigned(nqflag);
605104445Smdodd				*tl = txdr_unsigned(nmp->nm_leaseterm);
606106490Smdodd			} else {
6072477Sache				nfsm_build(tl, u_long *, NFSX_UNSIGNED);
608578Srgrimes				*tl = 0;
609106490Smdodd			}
610578Srgrimes		}
611578Srgrimes	}
6121197Srgrimes	/* Finally, return values */
613104445Smdodd	*bposp = bpos;
614578Srgrimes	return (mb);
615578Srgrimes}
616578Srgrimes
617104445Smdodd/*
618104445Smdodd * Build the RPC header and fill in the authorization info.
619106490Smdodd * The authorization string argument is only used when the credentials
620578Srgrimes * come from outside of the kernel.
621578Srgrimes * Returns the head of the mbuf list.
622578Srgrimes */
623106490Smdoddstruct mbuf *
624578Srgrimesnfsm_rpchead(cr, nmflag, procid, auth_type, auth_len, auth_str, verf_len,
625578Srgrimes	verf_str, mrest, mrest_len, mbp, xidp)
6261197Srgrimes	register struct ucred *cr;
627104445Smdodd	int nmflag;
628578Srgrimes	int procid;
629578Srgrimes	int auth_type;
630578Srgrimes	int auth_len;
631578Srgrimes	char *auth_str;
632578Srgrimes	int verf_len;
633104445Smdodd	char *verf_str;
634104445Smdodd	struct mbuf *mrest;
6356604Sache	int mrest_len;
636106490Smdodd	struct mbuf **mbp;
637106490Smdodd	u_long *xidp;
6386604Sache{
639578Srgrimes	register struct mbuf *mb;
640106490Smdodd	register u_long *tl;
641578Srgrimes	register caddr_t bpos;
642104445Smdodd	register int i;
643106490Smdodd	struct mbuf *mreq, *mb2;
644106490Smdodd	int siz, grpsiz, authsiz;
645578Srgrimes	static u_long base;
646578Srgrimes
6472477Sache	authsiz = nfsm_rndup(auth_len);
648104445Smdodd	MGETHDR(mb, M_WAIT, MT_DATA);
649578Srgrimes	if ((authsiz + 10 * NFSX_UNSIGNED) >= MINCLSIZE) {
650104445Smdodd		MCLGET(mb, M_WAIT);
651578Srgrimes	} else if ((authsiz + 10 * NFSX_UNSIGNED) < MHLEN) {
652106490Smdodd		MH_ALIGN(mb, authsiz + 10 * NFSX_UNSIGNED);
653106490Smdodd	} else {
6548375Srgrimes		MH_ALIGN(mb, 8 * NFSX_UNSIGNED);
655104445Smdodd	}
656106490Smdodd	mb->m_len = 0;
657578Srgrimes	mreq = mb;
658578Srgrimes	bpos = mtod(mb, caddr_t);
659106490Smdodd
660106490Smdodd	/*
661106490Smdodd	 * First the RPC header.
662106490Smdodd	 */
663106490Smdodd	nfsm_build(tl, u_long *, 8 * NFSX_UNSIGNED);
664578Srgrimes
665578Srgrimes	/* Get a pretty random xid to start with */
6661197Srgrimes	if (!nfs_xid)
667104445Smdodd		nfs_xid = random();
668578Srgrimes	/*
669578Srgrimes	 * Skip zero xid if it should ever happen.
6708876Srgrimes	 */
671578Srgrimes	if (++nfs_xid == 0)
672578Srgrimes		nfs_xid++;
673104445Smdodd
674104445Smdodd	*tl++ = *xidp = txdr_unsigned(nfs_xid);
675106490Smdodd	*tl++ = rpc_call;
676578Srgrimes	*tl++ = rpc_vers;
677578Srgrimes	if (nmflag & NFSMNT_NQNFS) {
678578Srgrimes		*tl++ = txdr_unsigned(NQNFS_PROG);
679106490Smdodd		*tl++ = txdr_unsigned(NQNFS_VER3);
680578Srgrimes	} else {
681578Srgrimes		*tl++ = txdr_unsigned(NFS_PROG);
6821197Srgrimes		if (nmflag & NFSMNT_NFSV3)
683104445Smdodd			*tl++ = txdr_unsigned(NFS_VER3);
684578Srgrimes		else
6852477Sache			*tl++ = txdr_unsigned(NFS_VER2);
6868876Srgrimes	}
6872477Sache	if (nmflag & NFSMNT_NFSV3)
688578Srgrimes		*tl++ = txdr_unsigned(procid);
689104445Smdodd	else
690104445Smdodd		*tl++ = txdr_unsigned(nfsv2_procid[procid]);
691578Srgrimes
692578Srgrimes	/*
6932477Sache	 * And then the authorization cred.
694104445Smdodd	 */
695106490Smdodd	*tl++ = txdr_unsigned(auth_type);
6962477Sache	*tl = txdr_unsigned(authsiz);
697578Srgrimes	switch (auth_type) {
698104445Smdodd	case RPCAUTH_UNIX:
699106490Smdodd		nfsm_build(tl, u_long *, auth_len);
700578Srgrimes		*tl++ = 0;		/* stamp ?? */
7012477Sache		*tl++ = 0;		/* NULL hostname */
702106490Smdodd		*tl++ = txdr_unsigned(cr->cr_uid);
703578Srgrimes		*tl++ = txdr_unsigned(cr->cr_groups[0]);
704578Srgrimes		grpsiz = (auth_len >> 2) - 5;
7051197Srgrimes		*tl++ = txdr_unsigned(grpsiz);
7061197Srgrimes		for (i = 1; i <= grpsiz; i++)
707578Srgrimes			*tl++ = txdr_unsigned(cr->cr_groups[i]);
708578Srgrimes		break;
709578Srgrimes	case RPCAUTH_KERB4:
71013770Sache		siz = auth_len;
71113770Sache		while (siz > 0) {
71213770Sache			if (M_TRAILINGSPACE(mb) == 0) {
71313770Sache				MGET(mb2, M_WAIT, MT_DATA);
714578Srgrimes				if (siz >= MINCLSIZE)
715578Srgrimes					MCLGET(mb2, M_WAIT);
7161197Srgrimes				mb->m_next = mb2;
71713770Sache				mb = mb2;
718578Srgrimes				mb->m_len = 0;
71913770Sache				bpos = mtod(mb, caddr_t);
72013770Sache			}
721578Srgrimes			i = min(siz, M_TRAILINGSPACE(mb));
722578Srgrimes			bcopy(auth_str, bpos, i);
7231197Srgrimes			mb->m_len += i;
724104445Smdodd			auth_str += i;
725578Srgrimes			bpos += i;
726578Srgrimes			siz -= i;
727578Srgrimes		}
728106490Smdodd		if ((siz = (nfsm_rndup(auth_len) - auth_len)) > 0) {
729578Srgrimes			for (i = 0; i < siz; i++)
7302477Sache				*bpos++ = '\0';
7312477Sache			mb->m_len += siz;
732578Srgrimes		}
733104445Smdodd		break;
734106490Smdodd	};
735578Srgrimes
736578Srgrimes	/*
737106490Smdodd	 * And the verifier...
738104445Smdodd	 */
739106490Smdodd	nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED);
740578Srgrimes	if (verf_str) {
741578Srgrimes		*tl++ = txdr_unsigned(RPCAUTH_KERB4);
742106490Smdodd		*tl = txdr_unsigned(verf_len);
743106490Smdodd		siz = verf_len;
7446604Sache		while (siz > 0) {
745106490Smdodd			if (M_TRAILINGSPACE(mb) == 0) {
746106490Smdodd				MGET(mb2, M_WAIT, MT_DATA);
747578Srgrimes				if (siz >= MINCLSIZE)
748578Srgrimes					MCLGET(mb2, M_WAIT);
749106490Smdodd				mb->m_next = mb2;
750578Srgrimes				mb = mb2;
751578Srgrimes				mb->m_len = 0;
752578Srgrimes				bpos = mtod(mb, caddr_t);
753578Srgrimes			}
754578Srgrimes			i = min(siz, M_TRAILINGSPACE(mb));
755578Srgrimes			bcopy(verf_str, bpos, i);
756578Srgrimes			mb->m_len += i;
757578Srgrimes			verf_str += i;
7581197Srgrimes			bpos += i;
75925056Sbde			siz -= i;
76025056Sbde		}
761104445Smdodd		if ((siz = (nfsm_rndup(verf_len) - verf_len)) > 0) {
762104445Smdodd			for (i = 0; i < siz; i++)
763104445Smdodd				*bpos++ = '\0';
764104445Smdodd			mb->m_len += siz;
765104445Smdodd		}
76625056Sbde	} else {
76725056Sbde		*tl++ = txdr_unsigned(RPCAUTH_NULL);
76825056Sbde		*tl = 0;
769104445Smdodd	}
770578Srgrimes	mb->m_next = mrest;
771104445Smdodd	mreq->m_pkthdr.len = authsiz + 10 * NFSX_UNSIGNED + mrest_len;
772104445Smdodd	mreq->m_pkthdr.rcvif = (struct ifnet *)0;
773104445Smdodd	*mbp = mb;
774578Srgrimes	return (mreq);
775104445Smdodd}
776578Srgrimes
777578Srgrimes/*
778104445Smdodd * copies mbuf chain to the uio scatter/gather list
779104445Smdodd */
780104445Smdoddint
781578Srgrimesnfsm_mbuftouio(mrep, uiop, siz, dpos)
782578Srgrimes	struct mbuf **mrep;
783578Srgrimes	register struct uio *uiop;
784104445Smdodd	int siz;
785578Srgrimes	caddr_t *dpos;
786578Srgrimes{
7876604Sache	register char *mbufcp, *uiocp;
788578Srgrimes	register int xfer, left, len;
789104445Smdodd	register struct mbuf *mp;
790578Srgrimes	long uiosiz, rem;
791104445Smdodd	int error = 0;
792104445Smdodd
793578Srgrimes	mp = *mrep;
794578Srgrimes	mbufcp = *dpos;
795104445Smdodd	len = mtod(mp, caddr_t)+mp->m_len-mbufcp;
796104445Smdodd	rem = nfsm_rndup(siz)-siz;
797578Srgrimes	while (siz > 0) {
798104445Smdodd		if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL)
799104445Smdodd			return (EFBIG);
800104445Smdodd		left = uiop->uio_iov->iov_len;
801578Srgrimes		uiocp = uiop->uio_iov->iov_base;
802578Srgrimes		if (left > siz)
803106490Smdodd			left = siz;
804106490Smdodd		uiosiz = left;
8056028Sache		while (left > 0) {
806104445Smdodd			while (len == 0) {
8072477Sache				mp = mp->m_next;
8081197Srgrimes				if (mp == NULL)
8098375Srgrimes					return (EBADRPC);
810578Srgrimes				mbufcp = mtod(mp, caddr_t);
811106490Smdodd				len = mp->m_len;
812104445Smdodd			}
813578Srgrimes			xfer = (left > len) ? len : left;
814578Srgrimes#ifdef notdef
8156604Sache			/* Not Yet.. */
8166028Sache			if (uiop->uio_iov->iov_op != NULL)
817578Srgrimes				(*(uiop->uio_iov->iov_op))
818106490Smdodd				(mbufcp, uiocp, xfer);
8194389Sache			else
820578Srgrimes#endif
821578Srgrimes			if (uiop->uio_segflg == UIO_SYSSPACE)
8224389Sache				bcopy(mbufcp, uiocp, xfer);
823106490Smdodd			else
824578Srgrimes				copyout(mbufcp, uiocp, xfer);
825578Srgrimes			left -= xfer;
826106490Smdodd			len -= xfer;
8272477Sache			mbufcp += xfer;
8282477Sache			uiocp += xfer;
829578Srgrimes			uiop->uio_offset += xfer;
8302477Sache			uiop->uio_resid -= xfer;
831106490Smdodd		}
8322477Sache		if (uiop->uio_iov->iov_len <= siz) {
833104445Smdodd			uiop->uio_iovcnt--;
834104445Smdodd			uiop->uio_iov++;
8352477Sache		} else {
836104445Smdodd			uiop->uio_iov->iov_base += uiosiz;
837104445Smdodd			uiop->uio_iov->iov_len -= uiosiz;
838578Srgrimes		}
839578Srgrimes		siz -= uiosiz;
840104445Smdodd	}
841578Srgrimes	*dpos = mbufcp;
842578Srgrimes	*mrep = mp;
843578Srgrimes	if (rem > 0) {
844578Srgrimes		if (len < rem)
845104445Smdodd			error = nfs_adv(mrep, dpos, rem, len);
846104445Smdodd		else
847578Srgrimes			*dpos += rem;
848104445Smdodd	}
849578Srgrimes	return (error);
850578Srgrimes}
851104445Smdodd
852104445Smdodd/*
853104445Smdodd * copies a uio scatter/gather list to an mbuf chain.
854578Srgrimes * NOTE: can ony handle iovcnt == 1
855578Srgrimes */
856106490Smdoddint
857106490Smdoddnfsm_uiotombuf(uiop, mq, siz, bpos)
858106490Smdodd	register struct uio *uiop;
8596028Sache	struct mbuf **mq;
8606028Sache	int siz;
861104445Smdodd	caddr_t *bpos;
8622477Sache{
863106490Smdodd	register char *uiocp;
8641197Srgrimes	register struct mbuf *mp, *mp2;
8658375Srgrimes	register int xfer, left, mlen;
8662477Sache	int uiosiz, clflg, rem;
867578Srgrimes	char *cp;
86859249Sphk
869578Srgrimes	if (uiop->uio_iovcnt != 1)
870578Srgrimes		panic("nfsm_uiotombuf: iovcnt != 1");
871578Srgrimes
872121212Sphk	if (siz > MLEN)		/* or should it >= MCLBYTES ?? */
873578Srgrimes		clflg = 1;
8748456Srgrimes	else
8758375Srgrimes		clflg = 0;
876578Srgrimes	rem = nfsm_rndup(siz)-siz;
877578Srgrimes	mp = mp2 = *mq;
878578Srgrimes	while (siz > 0) {
8796028Sache		left = uiop->uio_iov->iov_len;
880578Srgrimes		uiocp = uiop->uio_iov->iov_base;
881106719Smdodd		if (left > siz)
882106490Smdodd			left = siz;
883104445Smdodd		uiosiz = left;
884104445Smdodd		while (left > 0) {
885104445Smdodd			mlen = M_TRAILINGSPACE(mp);
886104445Smdodd			if (mlen == 0) {
887104445Smdodd				MGET(mp, M_WAIT, MT_DATA);
888104445Smdodd				if (clflg)
889106719Smdodd					MCLGET(mp, M_WAIT);
8902477Sache				mp->m_len = 0;
8912762Sache				mp2->m_next = mp;
8922762Sache				mp2 = mp;
893104445Smdodd				mlen = M_TRAILINGSPACE(mp);
8945226Sache			}
8952762Sache			xfer = (left > mlen) ? mlen : left;
8962762Sache#ifdef notdef
8972762Sache			/* Not Yet.. */
8982762Sache			if (uiop->uio_iov->iov_op != NULL)
899578Srgrimes				(*(uiop->uio_iov->iov_op))
900104445Smdodd				(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
901104445Smdodd			else
902578Srgrimes#endif
903578Srgrimes			if (uiop->uio_segflg == UIO_SYSSPACE)
904104445Smdodd				bcopy(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
905104445Smdodd			else
906578Srgrimes				copyin(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
907104445Smdodd			mp->m_len += xfer;
9085226Sache			left -= xfer;
9091197Srgrimes			uiocp += xfer;
9108375Srgrimes			uiop->uio_offset += xfer;
9112762Sache			uiop->uio_resid -= xfer;
912578Srgrimes		}
91359249Sphk		uiop->uio_iov->iov_base += uiosiz;
9142477Sache		uiop->uio_iov->iov_len -= uiosiz;
915104445Smdodd		siz -= uiosiz;
916578Srgrimes	}
917104445Smdodd	if (rem > 0) {
918104445Smdodd		if (rem > M_TRAILINGSPACE(mp)) {
919578Srgrimes			MGET(mp, M_WAIT, MT_DATA);
920104445Smdodd			mp->m_len = 0;
9212477Sache			mp2->m_next = mp;
9225226Sache		}
923104445Smdodd		cp = mtod(mp, caddr_t)+mp->m_len;
924104445Smdodd		for (left = 0; left < rem; left++)
925104445Smdodd			*cp++ = '\0';
926104445Smdodd		mp->m_len += rem;
9272477Sache		*bpos = cp;
9282477Sache	} else
929578Srgrimes		*bpos = mtod(mp, caddr_t)+mp->m_len;
930578Srgrimes	*mq = mp;
931578Srgrimes	return (0);
932578Srgrimes}
933578Srgrimes
934578Srgrimes/*
93559249Sphk * Help break down an mbuf chain by setting the first siz bytes contiguous
936578Srgrimes * pointed to by returned val.
937578Srgrimes * This is used by the macros nfsm_dissect and nfsm_dissecton for tough
938106490Smdodd * cases. (The macros use the vars. dpos and dpos2)
939104445Smdodd */
940578Srgrimesint
941578Srgrimesnfsm_disct(mdp, dposp, siz, left, cp2)
9425226Sache	struct mbuf **mdp;
943106490Smdodd	caddr_t *dposp;
944106490Smdodd	int siz;
9456028Sache	int left;
946104445Smdodd	caddr_t *cp2;
9472477Sache{
9482477Sache	register struct mbuf *mp, *mp2;
949104445Smdodd	register int siz2, xfer;
950104445Smdodd	register caddr_t p;
951578Srgrimes
952578Srgrimes	mp = *mdp;
953104445Smdodd	while (left == 0) {
954578Srgrimes		*mdp = mp = mp->m_next;
955578Srgrimes		if (mp == NULL)
956578Srgrimes			return (EBADRPC);
957578Srgrimes		left = mp->m_len;
958578Srgrimes		*dposp = mtod(mp, caddr_t);
959578Srgrimes	}
960104445Smdodd	if (left >= siz) {
961578Srgrimes		*cp2 = *dposp;
962578Srgrimes		*dposp += siz;
963578Srgrimes	} else if (mp->m_next == NULL) {
9642477Sache		return (EBADRPC);
965578Srgrimes	} else if (siz > MHLEN) {
96659249Sphk		panic("nfs S too big");
96759249Sphk	} else {
968578Srgrimes		MGET(mp2, M_WAIT, MT_DATA);
9692477Sache		mp2->m_next = mp->m_next;
970106490Smdodd		mp->m_next = mp2;
971104445Smdodd		mp->m_len -= left;
972578Srgrimes		mp = mp2;
973578Srgrimes		*cp2 = p = mtod(mp, caddr_t);
9742477Sache		bcopy(*dposp, p, left);		/* Copy what was left */
975104445Smdodd		siz2 = siz-left;
9762477Sache		p += left;
9772477Sache		mp2 = mp->m_next;
978578Srgrimes		/* Loop around copying up the siz2 bytes */
979104445Smdodd		while (siz2 > 0) {
980104445Smdodd			if (mp2 == NULL)
981578Srgrimes				return (EBADRPC);
982104445Smdodd			xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2;
983104445Smdodd			if (xfer > 0) {
984106490Smdodd				bcopy(mtod(mp2, caddr_t), p, xfer);
985106490Smdodd				NFSMADV(mp2, xfer);
986578Srgrimes				mp2->m_len -= xfer;
987578Srgrimes				p += xfer;
988578Srgrimes				siz2 -= xfer;
989578Srgrimes			}
990578Srgrimes			if (siz2 > 0)
9911197Srgrimes				mp2 = mp2->m_next;
992104445Smdodd		}
9932477Sache		mp->m_len = siz;
9942477Sache		*mdp = mp2;
995104445Smdodd		*dposp = mtod(mp2, caddr_t);
996104445Smdodd	}
997104445Smdodd	return (0);
998106490Smdodd}
999106490Smdodd
10006604Sache/*
10016604Sache * Advance the position in the mbuf chain.
10026604Sache */
1003104445Smdoddint
10046604Sachenfs_adv(mdp, dposp, offs, left)
10056604Sache	struct mbuf **mdp;
10066604Sache	caddr_t *dposp;
1007104445Smdodd	int offs;
1008106490Smdodd	int left;
1009106490Smdodd{
1010104445Smdodd	register struct mbuf *m;
10116604Sache	register int s;
1012104445Smdodd
1013106490Smdodd	m = *mdp;
10146604Sache	s = left;
1015104445Smdodd	while (s < offs) {
1016106490Smdodd		offs -= s;
1017106490Smdodd		m = m->m_next;
10186604Sache		if (m == NULL)
10196604Sache			return (EBADRPC);
1020106490Smdodd		s = m->m_len;
10216604Sache	}
1022106490Smdodd	*mdp = m;
10236604Sache	*dposp = mtod(m, caddr_t)+offs;
10246604Sache	return (0);
10256604Sache}
1026104445Smdodd
10276604Sache/*
1028104445Smdodd * Copy a string into mbufs for the hard cases...
10296604Sache */
1030104445Smdoddint
1031106490Smdoddnfsm_strtmbuf(mb, bpos, cp, siz)
1032106490Smdodd	struct mbuf **mb;
1033106490Smdodd	char **bpos;
1034104445Smdodd	char *cp;
1035106490Smdodd	long siz;
1036104445Smdodd{
1037104445Smdodd	register struct mbuf *m1 = 0, *m2;
1038106490Smdodd	long left, xfer, len, tlen;
1039106490Smdodd	u_long *tl;
10402477Sache	int putsize;
10412477Sache
10422477Sache	putsize = 1;
1043104445Smdodd	m2 = *mb;
104413866Sache	left = M_TRAILINGSPACE(m2);
104513866Sache	if (left > 0) {
1046104445Smdodd		tl = ((u_long *)(*bpos));
1047106490Smdodd		*tl++ = txdr_unsigned(siz);
1048106490Smdodd		putsize = 0;
1049104445Smdodd		left -= NFSX_UNSIGNED;
1050106490Smdodd		m2->m_len += NFSX_UNSIGNED;
105113866Sache		if (left > 0) {
105213866Sache			bcopy(cp, (caddr_t) tl, left);
105313866Sache			siz -= left;
1054104445Smdodd			cp += left;
10552477Sache			m2->m_len += left;
10562477Sache			left = 0;
1057104445Smdodd		}
1058106490Smdodd	}
1059106490Smdodd	/* Loop around adding mbufs */
1060106490Smdodd	while (siz > 0) {
10612477Sache		MGET(m1, M_WAIT, MT_DATA);
10622477Sache		if (siz > MLEN)
10632477Sache			MCLGET(m1, M_WAIT);
1064104445Smdodd		m1->m_len = NFSMSIZ(m1);
10652477Sache		m2->m_next = m1;
10662477Sache		m2 = m1;
1067106490Smdodd		tl = mtod(m1, u_long *);
1068106490Smdodd		tlen = 0;
1069106490Smdodd		if (putsize) {
1070106490Smdodd			*tl++ = txdr_unsigned(siz);
10712477Sache			m1->m_len -= NFSX_UNSIGNED;
10722477Sache			tlen = NFSX_UNSIGNED;
10732477Sache			putsize = 0;
1074104445Smdodd		}
1075578Srgrimes		if (siz < m1->m_len) {
10762477Sache			len = nfsm_rndup(siz);
1077578Srgrimes			xfer = siz;
1078106490Smdodd			if (xfer < len)
1079106490Smdodd				*(tl+(xfer>>2)) = 0;
1080106490Smdodd		} else {
1081104445Smdodd			xfer = len = m1->m_len;
1082578Srgrimes		}
1083578Srgrimes		bcopy(cp, (caddr_t) tl, xfer);
1084106490Smdodd		m1->m_len = len+tlen;
1085104445Smdodd		siz -= xfer;
1086104445Smdodd		cp += xfer;
1087104445Smdodd	}
1088106490Smdodd	*mb = m1;
1089106490Smdodd	*bpos = mtod(m1, caddr_t)+m1->m_len;
10902477Sache	return (0);
10912477Sache}
1092104445Smdodd
10932477Sache/*
10942477Sache * Called once to initialize data structures...
1095578Srgrimes */
1096578Srgrimesint
1097106490Smdoddnfs_init(vfsp)
1098578Srgrimes	struct vfsconf *vfsp;
1099578Srgrimes{
11001197Srgrimes	register int i;
1101104445Smdodd
1102578Srgrimes	/*
11032477Sache	 * Check to see if major data structures haven't bloated.
1104578Srgrimes	 */
1105104445Smdodd	if (sizeof (struct nfsnode) > NFS_NODEALLOC) {
1106106490Smdodd		printf("struct nfsnode bloated (> %dbytes)\n", NFS_NODEALLOC);
1107578Srgrimes		printf("Try reducing NFS_SMALLFH\n");
1108106490Smdodd	}
1109106490Smdodd	if (sizeof (struct nfsmount) > NFS_MNTALLOC) {
111013874Sache		printf("struct nfsmount bloated (> %dbytes)\n", NFS_MNTALLOC);
111113874Sache		printf("Try reducing NFS_MUIDHASHSIZ\n");
111213874Sache	}
1113578Srgrimes	if (sizeof (struct nfssvc_sock) > NFS_SVCALLOC) {
1114106490Smdodd		printf("struct nfssvc_sock bloated (> %dbytes)\n",NFS_SVCALLOC);
1115578Srgrimes		printf("Try reducing NFS_UIDHASHSIZ\n");
1116578Srgrimes	}
11171197Srgrimes	if (sizeof (struct nfsuid) > NFS_UIDALLOC) {
1118104445Smdodd		printf("struct nfsuid bloated (> %dbytes)\n",NFS_UIDALLOC);
1119578Srgrimes		printf("Try unionizing the nu_nickname and nu_flag fields\n");
1120578Srgrimes	}
1121578Srgrimes	nfs_mount_type = vfsp->vfc_typenum;
1122578Srgrimes	nfsrtt.pos = 0;
1123578Srgrimes	rpc_vers = txdr_unsigned(RPC_VER2);
1124578Srgrimes	rpc_call = txdr_unsigned(RPC_CALL);
1125106490Smdodd	rpc_reply = txdr_unsigned(RPC_REPLY);
1126106490Smdodd	rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED);
1127578Srgrimes	rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED);
1128106490Smdodd	rpc_mismatch = txdr_unsigned(RPC_MISMATCH);
1129104445Smdodd	rpc_autherr = txdr_unsigned(RPC_AUTHERR);
1130578Srgrimes	rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX);
1131104445Smdodd	rpc_auth_kerb = txdr_unsigned(RPCAUTH_KERB4);
1132106490Smdodd	nfs_prog = txdr_unsigned(NFS_PROG);
1133578Srgrimes	nqnfs_prog = txdr_unsigned(NQNFS_PROG);
1134104445Smdodd	nfs_true = txdr_unsigned(TRUE);
1135106490Smdodd	nfs_false = txdr_unsigned(FALSE);
11366665Sache	nfs_xdrneg1 = txdr_unsigned(-1);
1137104445Smdodd	nfs_ticks = (hz * NFS_TICKINTVL + 500) / 1000;
1138106490Smdodd	if (nfs_ticks < 1)
1139578Srgrimes		nfs_ticks = 1;
1140106490Smdodd	/* Ensure async daemons disabled */
1141104445Smdodd	for (i = 0; i < NFS_MAXASYNCDAEMON; i++) {
11422477Sache		nfs_iodwant[i] = (struct proc *)0;
1143578Srgrimes		nfs_iodmount[i] = (struct nfsmount *)0;
1144106490Smdodd	}
1145578Srgrimes	nfs_nhinit();			/* Init the nfsnode table */
11466612Sache#ifndef NFS_NOSERVER
1147578Srgrimes	nfsrv_init(0);			/* Init server data structures */
1148104445Smdodd	nfsrv_initcache();		/* Init the server request cache */
1149578Srgrimes#endif
11502477Sache
1151106490Smdodd	/*
1152106490Smdodd	 * Initialize the nqnfs server stuff.
1153578Srgrimes	 */
1154578Srgrimes	if (nqnfsstarttime == 0) {
11551197Srgrimes		nqnfsstarttime = boottime.tv_sec + nqsrv_maxlease
1156578Srgrimes			+ nqsrv_clockskew + nqsrv_writeslack;
1157578Srgrimes		NQLOADNOVRAM(nqnfsstarttime);
1158104445Smdodd		CIRCLEQ_INIT(&nqtimerhead);
1159106490Smdodd		nqfhhashtbl = hashinit(NQLCHSZ, M_NQLEASE, &nqfhhash);
1160578Srgrimes	}
11612477Sache
1162106490Smdodd	/*
1163578Srgrimes	 * Initialize reply list and start timer
1164578Srgrimes	 */
1165578Srgrimes	TAILQ_INIT(&nfs_reqq);
1166106490Smdodd
1167106490Smdodd	nfs_timer(0);
1168106490Smdodd
1169106490Smdodd
1170106490Smdodd	/*
1171106490Smdodd	 * Set up lease_check and lease_updatetime so that other parts
1172106490Smdodd	 * of the system can call us, if we are loadable.
1173578Srgrimes	 */
1174106490Smdodd#ifndef NFS_NOSERVER
11752477Sache	default_vnodeop_p[VOFFSET(vop_lease)] = (vop_t *)nqnfs_vop_lease_check;
11762477Sache#endif
1177104445Smdodd	lease_updatetime = nfs_lease_updatetime;
1178104445Smdodd	vfsp->vfc_refcount++; /* make us non-unloadable */
1179106490Smdodd	sysent[SYS_nfssvc].sy_narg = 2;
1180106490Smdodd	sysent[SYS_nfssvc].sy_call = (sy_call_t *)nfssvc;
1181106490Smdodd#ifndef NFS_NOSERVER
1182106490Smdodd	sysent[SYS_getfh].sy_narg = 2;
1183106490Smdodd	sysent[SYS_getfh].sy_call = (sy_call_t *)getfh;
11842477Sache#endif
11852477Sache
1186106490Smdodd	return (0);
1187578Srgrimes}
1188106490Smdodd
1189578Srgrimes/*
1190578Srgrimes * Attribute cache routines.
119131016Sphk * nfs_loadattrcache() - loads or updates the cache contents from attributes
11921197Srgrimes *	that are on the mbuf list
1193104445Smdodd * nfs_getattrcache() - returns valid attributes if found in cache, returns
119425460Sjoerg *	error otherwise
119525460Sjoerg */
119625460Sjoerg
119725460Sjoerg/*
119825460Sjoerg * Load the attribute cache (that lives in the nfsnode entry) with
119925460Sjoerg * the values on the mbuf list and
1200106490Smdodd * Iff vap not NULL
120125460Sjoerg *    copy the attributes to *vaper
120225460Sjoerg */
1203104445Smdoddint
1204106490Smdoddnfs_loadattrcache(vpp, mdp, dposp, vaper)
120525460Sjoerg	struct vnode **vpp;
120625460Sjoerg	struct mbuf **mdp;
120725460Sjoerg	caddr_t *dposp;
120825460Sjoerg	struct vattr *vaper;
120925460Sjoerg{
121025460Sjoerg	register struct vnode *vp = *vpp;
121125460Sjoerg	register struct vattr *vap;
121225460Sjoerg	register struct nfs_fattr *fp;
1213106490Smdodd	register struct nfsnode *np;
121425460Sjoerg	register long t1;
121525460Sjoerg	caddr_t cp2;
1216104445Smdodd	int error = 0, rdev;
1217106490Smdodd	struct mbuf *md;
121825460Sjoerg	enum vtype vtyp;
121925460Sjoerg	u_short vmode;
1220106490Smdodd	struct timespec mtime;
1221106490Smdodd	struct vnode *nvp;
122225460Sjoerg	int v3 = NFS_ISV3(vp);
1223106490Smdodd
1224106490Smdodd	md = *mdp;
122525460Sjoerg	t1 = (mtod(md, caddr_t) + md->m_len) - *dposp;
1226106490Smdodd	if (error = nfsm_disct(mdp, dposp, NFSX_FATTR(v3), t1, &cp2))
1227106490Smdodd		return (error);
122825460Sjoerg	fp = (struct nfs_fattr *)cp2;
122925460Sjoerg	if (v3) {
123025460Sjoerg		vtyp = nfsv3tov_type(fp->fa_type);
1231106490Smdodd		vmode = fxdr_unsigned(u_short, fp->fa_mode);
1232106490Smdodd		rdev = makedev(fxdr_unsigned(int, fp->fa3_rdev.specdata1),
1233106490Smdodd			fxdr_unsigned(int, fp->fa3_rdev.specdata2));
123425460Sjoerg		fxdr_nfsv3time(&fp->fa3_mtime, &mtime);
123525460Sjoerg	} else {
1236106490Smdodd		vtyp = nfsv2tov_type(fp->fa_type);
123725460Sjoerg		vmode = fxdr_unsigned(u_short, fp->fa_mode);
123825460Sjoerg		/*
1239106490Smdodd		 * XXX
124025460Sjoerg		 *
124131016Sphk		 * The duplicate information returned in fa_type and fa_mode
124225460Sjoerg		 * is an ambiguity in the NFS version 2 protocol.
124325460Sjoerg		 *
1244104445Smdodd		 * VREG should be taken literally as a regular file.  If a
1245578Srgrimes		 * server intents to return some type information differently
12462477Sache		 * in the upper bits of the mode field (e.g. for sockets, or
1247578Srgrimes		 * FIFOs), NFSv2 mandates fa_type to be VNON.  Anyway, we
124813743Sache		 * leave the examination of the mode bits even in the VREG
1249578Srgrimes		 * case to avoid breakage for bogus servers, but we make sure
125013743Sache		 * that there are actually type bits set in the upper part of
125113743Sache		 * fa_mode (and failing that, trust the va_type field).
125246571Speter		 *
125346571Speter		 * NFSv3 cleared the issue, and requires fa_mode to not
12542477Sache		 * contain any type information (while also introduing sockets
1255106490Smdodd		 * and FIFOs for fa_type).
1256578Srgrimes		 */
1257578Srgrimes		if (vtyp == VNON || (vtyp == VREG && (vmode & S_IFMT) != 0))
1258104445Smdodd			vtyp = IFTOVT(vmode);
1259106490Smdodd		rdev = fxdr_unsigned(long, fp->fa2_rdev);
1260578Srgrimes		fxdr_nfsv2time(&fp->fa2_mtime, &mtime);
126113732Sache
126213732Sache		/*
126313732Sache		 * Really ugly NFSv2 kludge.
126413732Sache		 */
126513732Sache		if (vtyp == VCHR && rdev == 0xffffffff)
126613732Sache			vtyp = VFIFO;
126713732Sache	}
1268106490Smdodd
126913732Sache	/*
127013743Sache	 * If v_type == VNON it is a new node, so fill in the v_type,
127113743Sache	 * n_mtime fields. Check to see if it represents a special
127213743Sache	 * device, and if so, check for a possible alias. Once the
127313743Sache	 * correct vnode has been obtained, fill in the rest of the
127413743Sache	 * information.
1275106490Smdodd	 */
127613743Sache	np = VTONFS(vp);
127713732Sache	if (vp->v_type != vtyp) {
1278104445Smdodd		vp->v_type = vtyp;
1279106490Smdodd		if (vp->v_type == VFIFO) {
128013732Sache			vp->v_op = fifo_nfsv2nodeop_p;
128113732Sache		}
128213732Sache		if (vp->v_type == VCHR || vp->v_type == VBLK) {
1283106490Smdodd			vp->v_op = spec_nfsv2nodeop_p;
128413732Sache			nvp = checkalias(vp, (dev_t)rdev, vp->v_mount);
1285106490Smdodd			if (nvp) {
1286106490Smdodd				/*
128713732Sache				 * Discard unneeded vnode, but save its nfsnode.
1288106490Smdodd				 * Since the nfsnode does not have a lock, its
1289106490Smdodd				 * vnode lock has to be carried over.
129013732Sache				 */
129113732Sache				nvp->v_vnlock = vp->v_vnlock;
129213732Sache				vp->v_vnlock = NULL;
1293106490Smdodd				nvp->v_data = vp->v_data;
1294106490Smdodd				vp->v_data = NULL;
1295106490Smdodd				vp->v_op = spec_vnodeop_p;
129613732Sache				vrele(vp);
129713732Sache				vgone(vp);
1298106490Smdodd				/*
129913732Sache				 * Reinitialize aliased node.
13002477Sache				 */
13012477Sache				np->n_vnode = nvp;
130213732Sache				*vpp = vp = nvp;
1303578Srgrimes			}
1304578Srgrimes		}
1305578Srgrimes		np->n_mtime = mtime.tv_sec;
130613732Sache	}
1307578Srgrimes	vap = &np->n_vattr;
1308578Srgrimes	vap->va_type = vtyp;
13091197Srgrimes	vap->va_mode = (vmode & 07777);
1310104445Smdodd	vap->va_rdev = (dev_t)rdev;
1311578Srgrimes	vap->va_mtime = mtime;
1312578Srgrimes	vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0];
13136604Sache	if (v3) {
1314106490Smdodd		vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink);
1315106490Smdodd		vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid);
1316106490Smdodd		vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid);
1317106490Smdodd		fxdr_hyper(&fp->fa3_size, &vap->va_size);
1318104445Smdodd		vap->va_blocksize = NFS_FABLKSIZE;
1319104445Smdodd		fxdr_hyper(&fp->fa3_used, &vap->va_bytes);
1320106490Smdodd		vap->va_fileid = fxdr_unsigned(int, fp->fa3_fileid.nfsuquad[1]);
1321106490Smdodd		fxdr_nfsv3time(&fp->fa3_atime, &vap->va_atime);
13226604Sache		fxdr_nfsv3time(&fp->fa3_ctime, &vap->va_ctime);
1323106490Smdodd		vap->va_flags = 0;
1324104445Smdodd		vap->va_filerev = 0;
1325106490Smdodd	} else {
1326106490Smdodd		vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink);
1327106490Smdodd		vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid);
1328578Srgrimes		vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid);
1329578Srgrimes		vap->va_size = fxdr_unsigned(u_long, fp->fa2_size);
13301197Srgrimes		vap->va_blocksize = fxdr_unsigned(long, fp->fa2_blocksize);
1331104445Smdodd		vap->va_bytes = fxdr_unsigned(long, fp->fa2_blocks) * NFS_FABLKSIZE;
1332578Srgrimes		vap->va_fileid = fxdr_unsigned(long, fp->fa2_fileid);
1333578Srgrimes		fxdr_nfsv2time(&fp->fa2_atime, &vap->va_atime);
1334104445Smdodd		vap->va_flags = 0;
1335106490Smdodd		vap->va_ctime.tv_sec = fxdr_unsigned(long, fp->fa2_ctime.nfsv2_sec);
1336104445Smdodd		vap->va_ctime.tv_nsec = 0;
1337106490Smdodd		vap->va_gen = fxdr_unsigned(u_long, fp->fa2_ctime.nfsv2_usec);
1338106490Smdodd		vap->va_filerev = 0;
1339104445Smdodd	}
1340104445Smdodd	if (vap->va_size != np->n_size) {
1341104445Smdodd		if (vap->va_type == VREG) {
1342104445Smdodd			if (np->n_flag & NMODIFIED) {
1343104445Smdodd				if (vap->va_size < np->n_size)
1344104445Smdodd					vap->va_size = np->n_size;
1345104445Smdodd				else
1346104445Smdodd					np->n_size = vap->va_size;
1347104445Smdodd			} else
1348104445Smdodd				np->n_size = vap->va_size;
1349104445Smdodd			vnode_pager_setsize(vp, (u_long)np->n_size);
13501197Srgrimes		} else
1351106490Smdodd			np->n_size = vap->va_size;
1352578Srgrimes	}
1353578Srgrimes	np->n_attrstamp = time_second;
13541197Srgrimes	if (vaper != NULL) {
1355141031Ssobomax		bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(*vap));
1356578Srgrimes		if (np->n_flag & NCHG) {
1357578Srgrimes			if (np->n_flag & NACC)
1358578Srgrimes				vaper->va_atime = np->n_atim;
135913770Sache			if (np->n_flag & NUPD)
1360578Srgrimes				vaper->va_mtime = np->n_mtim;
1361106490Smdodd		}
1362104445Smdodd	}
1363104445Smdodd	return (0);
1364104445Smdodd}
13652477Sache
1366104445Smdodd#ifdef NFS_ACDEBUG
1367104445Smdodd#include <sys/sysctl.h>
1368106490Smdoddstatic int nfs_acdebug;
13692477SacheSYSCTL_INT(_vfs_nfs, OID_AUTO, acdebug, CTLFLAG_RW, &nfs_acdebug, 0, "");
1370104445Smdodd#endif
1371104445Smdodd
1372106490Smdodd/*
13732477Sache * Check the time stamp
1374104445Smdodd * If the cache is valid, copy contents to *vap and return 0
1375106490Smdodd * otherwise return an error
13762477Sache */
1377104445Smdoddint
1378106490Smdoddnfs_getattrcache(vp, vaper)
1379578Srgrimes	register struct vnode *vp;
1380106490Smdodd	struct vattr *vaper;
1381104445Smdodd{
138213886Sache	register struct nfsnode *np;
1383104445Smdodd	register struct vattr *vap;
138413886Sache	struct nfsmount *nmp;
138513886Sache	int timeo;
138613886Sache
138713732Sache	np = VTONFS(vp);
138813886Sache	vap = &np->n_vattr;
138913886Sache	nmp = VFSTONFS(vp->v_mount);
139013886Sache	/* XXX n_mtime doesn't seem to be updated on a miss-and-reload */
139113886Sache	timeo = (time_second - np->n_mtime) / 10;
139213886Sache
139313886Sache#ifdef NFS_ACDEBUG
1394104445Smdodd	if (nfs_acdebug>1)
139513886Sache		printf("nfs_getattrcache: initial timeo = %d\n", timeo);
139613886Sache#endif
139713886Sache
139813886Sache	if (vap->va_type == VDIR) {
139913886Sache		if ((np->n_flag & NMODIFIED) || timeo < nmp->nm_acdirmin)
140013886Sache			timeo = nmp->nm_acdirmin;
140113886Sache		else if (timeo > nmp->nm_acdirmax)
140213886Sache			timeo = nmp->nm_acdirmax;
140313886Sache	} else {
140413886Sache		if ((np->n_flag & NMODIFIED) || timeo < nmp->nm_acregmin)
140513886Sache			timeo = nmp->nm_acregmin;
140613886Sache		else if (timeo > nmp->nm_acregmax)
140713886Sache			timeo = nmp->nm_acregmax;
140813886Sache	}
140913886Sache
141013886Sache#ifdef NFS_ACDEBUG
141113886Sache	if (nfs_acdebug > 2)
141213886Sache		printf("acregmin %d; acregmax %d; acdirmin %d; acdirmax %d\n",
141313886Sache			nmp->nm_acregmin, nmp->nm_acregmax,
141413886Sache			nmp->nm_acdirmin, nmp->nm_acdirmax);
141513886Sache
141613886Sache	if (nfs_acdebug)
141713886Sache		printf("nfs_getattrcache: age = %d; final timeo = %d\n",r
141813732Sache			(time_second - np->n_attrstamp), timeo);
14196665Sache#endif
1420578Srgrimes
1421141031Ssobomax	if ((time_second - np->n_attrstamp) >= timeo) {
1422141031Ssobomax		nfsstats.attrcache_misses++;
1423141031Ssobomax		return (ENOENT);
1424141061Smaxim	}
1425578Srgrimes	nfsstats.attrcache_hits++;
1426578Srgrimes	if (vap->va_size != np->n_size) {
14271197Srgrimes		if (vap->va_type == VREG) {
1428104445Smdodd			if (np->n_flag & NMODIFIED) {
14292477Sache				if (vap->va_size < np->n_size)
14302477Sache					vap->va_size = np->n_size;
14312477Sache				else
1432106490Smdodd					np->n_size = vap->va_size;
1433104445Smdodd			} else
143413833Sache				np->n_size = vap->va_size;
143513833Sache			vnode_pager_setsize(vp, (u_long)np->n_size);
143613833Sache		} else
143713833Sache			np->n_size = vap->va_size;
143813833Sache	}
143913833Sache	bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(struct vattr));
1440106490Smdodd	if (np->n_flag & NCHG) {
1441106490Smdodd		if (np->n_flag & NACC)
1442106490Smdodd			vaper->va_atime = np->n_atim;
1443106490Smdodd		if (np->n_flag & NUPD)
144413833Sache			vaper->va_mtime = np->n_mtim;
144513833Sache	}
144613833Sache	return (0);
144713833Sache}
144813833Sache
144913833Sache#ifndef NFS_NOSERVER
145013833Sache/*
145113833Sache * Set up nameidata for a lookup() call and do it.
1452104445Smdodd *
1453106490Smdodd * If pubflag is set, this call is done for a lookup operation on the
14542477Sache * public filehandle. In that case we allow crossing mountpoints and
1455104445Smdodd * absolute pathnames. However, the caller is expected to check that
14562477Sache * the lookup result is within the public fs, and deny access if
14572477Sache * it is not.
14582477Sache */
1459104445Smdoddint
1460578Srgrimesnfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, retdirp, p, kerbflag, pubflag)
1461578Srgrimes	register struct nameidata *ndp;
1462578Srgrimes	fhandle_t *fhp;
1463578Srgrimes	int len;
14644390Sache	struct nfssvc_sock *slp;
1465578Srgrimes	struct sockaddr *nam;
1466104445Smdodd	struct mbuf **mdp;
1467106490Smdodd	caddr_t *dposp;
1468578Srgrimes	struct vnode **retdirp;
1469106490Smdodd	struct proc *p;
1470104445Smdodd	int kerbflag, pubflag;
14712477Sache{
14722477Sache	register int i, rem;
1473106490Smdodd	register struct mbuf *md;
1474106490Smdodd	register char *fromcp, *tocp, *cp;
14752477Sache	struct iovec aiov;
1476106490Smdodd	struct uio auio;
1477106490Smdodd	struct vnode *dp;
1478106490Smdodd	int error, rdonly, linklen;
1479578Srgrimes	struct componentname *cnp = &ndp->ni_cnd;
14804390Sache
1481106490Smdodd	*retdirp = (struct vnode *)0;
1482106490Smdodd	cnp->cn_pnbuf = zalloc(namei_zone);
14834390Sache
1484578Srgrimes	/*
1485104445Smdodd	 * Copy the name from the mbuf list to ndp->ni_pnbuf
1486106490Smdodd	 * and set the various ndp fields appropriately.
148713833Sache	 */
1488104445Smdodd	fromcp = *dposp;
1489578Srgrimes	tocp = cnp->cn_pnbuf;
1490578Srgrimes	md = *mdp;
14911197Srgrimes	rem = mtod(md, caddr_t) + md->m_len - fromcp;
1492104445Smdodd	cnp->cn_hash = 0;
149313833Sache	for (i = 0; i < len; i++) {
149413833Sache		while (rem == 0) {
149513833Sache			md = md->m_next;
1496106490Smdodd			if (md == NULL) {
1497104445Smdodd				error = EBADRPC;
1498104445Smdodd				goto out;
149913833Sache			}
1500106490Smdodd			fromcp = mtod(md, caddr_t);
150113833Sache			rem = md->m_len;
1502106490Smdodd		}
1503106490Smdodd		if (*fromcp == '\0' || (!pubflag && *fromcp == '/')) {
150413833Sache			error = EACCES;
150513833Sache			goto out;
150613833Sache		}
150713833Sache		cnp->cn_hash += (unsigned char)*fromcp;
1508104445Smdodd		*tocp++ = *fromcp++;
1509106490Smdodd		rem--;
151013833Sache	}
1511104445Smdodd	*tocp = '\0';
151213833Sache	*mdp = md;
151313833Sache	*dposp = fromcp;
151413833Sache	len = nfsm_rndup(len)-len;
1515104445Smdodd	if (len > 0) {
1516578Srgrimes		if (rem >= len)
15172477Sache			*dposp += len;
1518578Srgrimes		else if ((error = nfs_adv(mdp, dposp, len, rem)) != 0)
1519106490Smdodd			goto out;
15201197Srgrimes	}
15212477Sache
1522106719Smdodd	/*
1523104445Smdodd	 * Extract and set starting directory.
1524104445Smdodd	 */
1525104445Smdodd	error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cnd.cn_cred, slp,
1526104445Smdodd	    nam, &rdonly, kerbflag, pubflag);
1527104445Smdodd	if (error)
1528104445Smdodd		goto out;
1529104445Smdodd	if (dp->v_type != VDIR) {
1530106719Smdodd		vrele(dp);
15312477Sache		error = ENOTDIR;
1532104445Smdodd		goto out;
15332477Sache	}
15342477Sache
15352477Sache	if (rdonly)
15362477Sache		cnp->cn_flags |= RDONLY;
15372477Sache
1538578Srgrimes	*retdirp = dp;
1539578Srgrimes
15402477Sache	if (pubflag) {
1541104445Smdodd		/*
1542106490Smdodd		 * Oh joy. For WebNFS, handle those pesky '%' escapes,
15431197Srgrimes		 * and the 'native path' indicator.
1544106490Smdodd		 */
1545104445Smdodd		cp = zalloc(namei_zone);
1546104445Smdodd		fromcp = cnp->cn_pnbuf;
15472477Sache		tocp = cp;
1548106490Smdodd		if ((unsigned char)*fromcp >= WEBNFS_SPECCHAR_START) {
1549106490Smdodd			switch ((unsigned char)*fromcp) {
1550106490Smdodd			case WEBNFS_NATIVE_CHAR:
1551578Srgrimes				/*
1552578Srgrimes				 * 'Native' path for us is the same
15531197Srgrimes				 * as a path according to the NFS spec,
1554104445Smdodd				 * just skip the escape char.
1555578Srgrimes				 */
1556578Srgrimes				fromcp++;
1557578Srgrimes				break;
1558578Srgrimes			/*
1559578Srgrimes			 * More may be added in the future, range 0x80-0xff
1560106490Smdodd			 */
1561106490Smdodd			default:
1562106490Smdodd				error = EIO;
1563104445Smdodd				zfree(namei_zone, cp);
1564104445Smdodd				goto out;
1565106490Smdodd			}
1566106490Smdodd		}
1567578Srgrimes		/*
1568578Srgrimes		 * Translate the '%' escapes, URL-style.
1569578Srgrimes		 */
1570104445Smdodd		while (*fromcp != '\0') {
1571106490Smdodd			if (*fromcp == WEBNFS_ESC_CHAR) {
1572578Srgrimes				if (fromcp[1] != '\0' && fromcp[2] != '\0') {
1573578Srgrimes					fromcp++;
1574106490Smdodd					*tocp++ = HEXSTRTOI(fromcp);
1575106490Smdodd					fromcp += 2;
1576106490Smdodd					continue;
1577578Srgrimes				} else {
1578578Srgrimes					error = ENOENT;
1579104445Smdodd					zfree(namei_zone, cp);
1580106490Smdodd					goto out;
1581578Srgrimes				}
1582578Srgrimes			} else
1583106490Smdodd				*tocp++ = *fromcp++;
1584106490Smdodd		}
1585578Srgrimes		*tocp = '\0';
1586578Srgrimes		zfree(namei_zone, cnp->cn_pnbuf);
15871197Srgrimes		cnp->cn_pnbuf = cp;
1588104445Smdodd	}
1589578Srgrimes
1590578Srgrimes	ndp->ni_pathlen = (tocp - cnp->cn_pnbuf) + 1;
1591106490Smdodd	ndp->ni_segflg = UIO_SYSSPACE;
1592106490Smdodd
1593106490Smdodd	if (pubflag) {
1594578Srgrimes		ndp->ni_rootdir = rootvnode;
1595		ndp->ni_loopcnt = 0;
1596		if (cnp->cn_pnbuf[0] == '/')
1597			dp = rootvnode;
1598	} else {
1599		cnp->cn_flags |= NOCROSSMOUNT;
1600	}
1601
1602	cnp->cn_proc = p;
1603	VREF(dp);
1604
1605    for (;;) {
1606	cnp->cn_nameptr = cnp->cn_pnbuf;
1607	ndp->ni_startdir = dp;
1608	/*
1609	 * And call lookup() to do the real work
1610	 */
1611	error = lookup(ndp);
1612	if (error)
1613		break;
1614	/*
1615	 * Check for encountering a symbolic link
1616	 */
1617	if ((cnp->cn_flags & ISSYMLINK) == 0) {
1618		nfsrv_object_create(ndp->ni_vp);
1619		if (cnp->cn_flags & (SAVENAME | SAVESTART)) {
1620			cnp->cn_flags |= HASBUF;
1621			return (0);
1622		}
1623		break;
1624	} else {
1625		if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1)
1626			VOP_UNLOCK(ndp->ni_dvp, 0, p);
1627		if (!pubflag) {
1628			vrele(ndp->ni_dvp);
1629			vput(ndp->ni_vp);
1630			ndp->ni_vp = NULL;
1631			error = EINVAL;
1632			break;
1633		}
1634
1635		if (ndp->ni_loopcnt++ >= MAXSYMLINKS) {
1636			error = ELOOP;
1637			break;
1638		}
1639		if (ndp->ni_pathlen > 1)
1640			cp = zalloc(namei_zone);
1641		else
1642			cp = cnp->cn_pnbuf;
1643		aiov.iov_base = cp;
1644		aiov.iov_len = MAXPATHLEN;
1645		auio.uio_iov = &aiov;
1646		auio.uio_iovcnt = 1;
1647		auio.uio_offset = 0;
1648		auio.uio_rw = UIO_READ;
1649		auio.uio_segflg = UIO_SYSSPACE;
1650		auio.uio_procp = (struct proc *)0;
1651		auio.uio_resid = MAXPATHLEN;
1652		error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred);
1653		if (error) {
1654		badlink:
1655			if (ndp->ni_pathlen > 1)
1656				zfree(namei_zone, cp);
1657			break;
1658		}
1659		linklen = MAXPATHLEN - auio.uio_resid;
1660		if (linklen == 0) {
1661			error = ENOENT;
1662			goto badlink;
1663		}
1664		if (linklen + ndp->ni_pathlen >= MAXPATHLEN) {
1665			error = ENAMETOOLONG;
1666			goto badlink;
1667		}
1668		if (ndp->ni_pathlen > 1) {
1669			bcopy(ndp->ni_next, cp + linklen, ndp->ni_pathlen);
1670			zfree(namei_zone, cnp->cn_pnbuf);
1671			cnp->cn_pnbuf = cp;
1672		} else
1673			cnp->cn_pnbuf[linklen] = '\0';
1674		ndp->ni_pathlen += linklen;
1675		vput(ndp->ni_vp);
1676		dp = ndp->ni_dvp;
1677		/*
1678		 * Check if root directory should replace current directory.
1679		 */
1680		if (cnp->cn_pnbuf[0] == '/') {
1681			vrele(dp);
1682			dp = ndp->ni_rootdir;
1683			VREF(dp);
1684		}
1685	}
1686   }
1687out:
1688	zfree(namei_zone, cnp->cn_pnbuf);
1689	return (error);
1690}
1691
1692/*
1693 * A fiddled version of m_adj() that ensures null fill to a long
1694 * boundary and only trims off the back end
1695 */
1696void
1697nfsm_adj(mp, len, nul)
1698	struct mbuf *mp;
1699	register int len;
1700	int nul;
1701{
1702	register struct mbuf *m;
1703	register int count, i;
1704	register char *cp;
1705
1706	/*
1707	 * Trim from tail.  Scan the mbuf chain,
1708	 * calculating its length and finding the last mbuf.
1709	 * If the adjustment only affects this mbuf, then just
1710	 * adjust and return.  Otherwise, rescan and truncate
1711	 * after the remaining size.
1712	 */
1713	count = 0;
1714	m = mp;
1715	for (;;) {
1716		count += m->m_len;
1717		if (m->m_next == (struct mbuf *)0)
1718			break;
1719		m = m->m_next;
1720	}
1721	if (m->m_len > len) {
1722		m->m_len -= len;
1723		if (nul > 0) {
1724			cp = mtod(m, caddr_t)+m->m_len-nul;
1725			for (i = 0; i < nul; i++)
1726				*cp++ = '\0';
1727		}
1728		return;
1729	}
1730	count -= len;
1731	if (count < 0)
1732		count = 0;
1733	/*
1734	 * Correct length for chain is "count".
1735	 * Find the mbuf with last data, adjust its length,
1736	 * and toss data from remaining mbufs on chain.
1737	 */
1738	for (m = mp; m; m = m->m_next) {
1739		if (m->m_len >= count) {
1740			m->m_len = count;
1741			if (nul > 0) {
1742				cp = mtod(m, caddr_t)+m->m_len-nul;
1743				for (i = 0; i < nul; i++)
1744					*cp++ = '\0';
1745			}
1746			break;
1747		}
1748		count -= m->m_len;
1749	}
1750	for (m = m->m_next;m;m = m->m_next)
1751		m->m_len = 0;
1752}
1753
1754/*
1755 * Make these functions instead of macros, so that the kernel text size
1756 * doesn't get too big...
1757 */
1758void
1759nfsm_srvwcc(nfsd, before_ret, before_vap, after_ret, after_vap, mbp, bposp)
1760	struct nfsrv_descript *nfsd;
1761	int before_ret;
1762	register struct vattr *before_vap;
1763	int after_ret;
1764	struct vattr *after_vap;
1765	struct mbuf **mbp;
1766	char **bposp;
1767{
1768	register struct mbuf *mb = *mbp, *mb2;
1769	register char *bpos = *bposp;
1770	register u_long *tl;
1771
1772	if (before_ret) {
1773		nfsm_build(tl, u_long *, NFSX_UNSIGNED);
1774		*tl = nfs_false;
1775	} else {
1776		nfsm_build(tl, u_long *, 7 * NFSX_UNSIGNED);
1777		*tl++ = nfs_true;
1778		txdr_hyper(&(before_vap->va_size), tl);
1779		tl += 2;
1780		txdr_nfsv3time(&(before_vap->va_mtime), tl);
1781		tl += 2;
1782		txdr_nfsv3time(&(before_vap->va_ctime), tl);
1783	}
1784	*bposp = bpos;
1785	*mbp = mb;
1786	nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp);
1787}
1788
1789void
1790nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp)
1791	struct nfsrv_descript *nfsd;
1792	int after_ret;
1793	struct vattr *after_vap;
1794	struct mbuf **mbp;
1795	char **bposp;
1796{
1797	register struct mbuf *mb = *mbp, *mb2;
1798	register char *bpos = *bposp;
1799	register u_long *tl;
1800	register struct nfs_fattr *fp;
1801
1802	if (after_ret) {
1803		nfsm_build(tl, u_long *, NFSX_UNSIGNED);
1804		*tl = nfs_false;
1805	} else {
1806		nfsm_build(tl, u_long *, NFSX_UNSIGNED + NFSX_V3FATTR);
1807		*tl++ = nfs_true;
1808		fp = (struct nfs_fattr *)tl;
1809		nfsm_srvfattr(nfsd, after_vap, fp);
1810	}
1811	*mbp = mb;
1812	*bposp = bpos;
1813}
1814
1815void
1816nfsm_srvfattr(nfsd, vap, fp)
1817	register struct nfsrv_descript *nfsd;
1818	register struct vattr *vap;
1819	register struct nfs_fattr *fp;
1820{
1821
1822	fp->fa_nlink = txdr_unsigned(vap->va_nlink);
1823	fp->fa_uid = txdr_unsigned(vap->va_uid);
1824	fp->fa_gid = txdr_unsigned(vap->va_gid);
1825	if (nfsd->nd_flag & ND_NFSV3) {
1826		fp->fa_type = vtonfsv3_type(vap->va_type);
1827		fp->fa_mode = vtonfsv3_mode(vap->va_mode);
1828		txdr_hyper(&vap->va_size, &fp->fa3_size);
1829		txdr_hyper(&vap->va_bytes, &fp->fa3_used);
1830		fp->fa3_rdev.specdata1 = txdr_unsigned(major(vap->va_rdev));
1831		fp->fa3_rdev.specdata2 = txdr_unsigned(minor(vap->va_rdev));
1832		fp->fa3_fsid.nfsuquad[0] = 0;
1833		fp->fa3_fsid.nfsuquad[1] = txdr_unsigned(vap->va_fsid);
1834		fp->fa3_fileid.nfsuquad[0] = 0;
1835		fp->fa3_fileid.nfsuquad[1] = txdr_unsigned(vap->va_fileid);
1836		txdr_nfsv3time(&vap->va_atime, &fp->fa3_atime);
1837		txdr_nfsv3time(&vap->va_mtime, &fp->fa3_mtime);
1838		txdr_nfsv3time(&vap->va_ctime, &fp->fa3_ctime);
1839	} else {
1840		fp->fa_type = vtonfsv2_type(vap->va_type);
1841		fp->fa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode);
1842		fp->fa2_size = txdr_unsigned(vap->va_size);
1843		fp->fa2_blocksize = txdr_unsigned(vap->va_blocksize);
1844		if (vap->va_type == VFIFO)
1845			fp->fa2_rdev = 0xffffffff;
1846		else
1847			fp->fa2_rdev = txdr_unsigned(vap->va_rdev);
1848		fp->fa2_blocks = txdr_unsigned(vap->va_bytes / NFS_FABLKSIZE);
1849		fp->fa2_fsid = txdr_unsigned(vap->va_fsid);
1850		fp->fa2_fileid = txdr_unsigned(vap->va_fileid);
1851		txdr_nfsv2time(&vap->va_atime, &fp->fa2_atime);
1852		txdr_nfsv2time(&vap->va_mtime, &fp->fa2_mtime);
1853		txdr_nfsv2time(&vap->va_ctime, &fp->fa2_ctime);
1854	}
1855}
1856
1857/*
1858 * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked)
1859 * 	- look up fsid in mount list (if not found ret error)
1860 *	- get vp and export rights by calling VFS_FHTOVP()
1861 *	- if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon
1862 *	- if not lockflag unlock it with VOP_UNLOCK()
1863 */
1864int
1865nfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp, kerbflag, pubflag)
1866	fhandle_t *fhp;
1867	int lockflag;
1868	struct vnode **vpp;
1869	struct ucred *cred;
1870	struct nfssvc_sock *slp;
1871	struct sockaddr *nam;
1872	int *rdonlyp;
1873	int kerbflag;
1874	int pubflag;
1875{
1876	struct proc *p = curproc; /* XXX */
1877	register struct mount *mp;
1878	register int i;
1879	struct ucred *credanon;
1880	int error, exflags;
1881
1882	*vpp = (struct vnode *)0;
1883
1884	if (nfs_ispublicfh(fhp)) {
1885		if (!pubflag || !nfs_pub.np_valid)
1886			return (ESTALE);
1887		fhp = &nfs_pub.np_handle;
1888	}
1889
1890	mp = vfs_getvfs(&fhp->fh_fsid);
1891	if (!mp)
1892		return (ESTALE);
1893	error = VFS_FHTOVP(mp, &fhp->fh_fid, nam, vpp, &exflags, &credanon);
1894	if (error)
1895		return (error);
1896	/*
1897	 * Check/setup credentials.
1898	 */
1899	if (exflags & MNT_EXKERB) {
1900		if (!kerbflag) {
1901			vput(*vpp);
1902			return (NFSERR_AUTHERR | AUTH_TOOWEAK);
1903		}
1904	} else if (kerbflag) {
1905		vput(*vpp);
1906		return (NFSERR_AUTHERR | AUTH_TOOWEAK);
1907	} else if (cred->cr_uid == 0 || (exflags & MNT_EXPORTANON)) {
1908		cred->cr_uid = credanon->cr_uid;
1909		for (i = 0; i < credanon->cr_ngroups && i < NGROUPS; i++)
1910			cred->cr_groups[i] = credanon->cr_groups[i];
1911		cred->cr_ngroups = i;
1912	}
1913	if (exflags & MNT_EXRDONLY)
1914		*rdonlyp = 1;
1915	else
1916		*rdonlyp = 0;
1917
1918	nfsrv_object_create(*vpp);
1919
1920	if (!lockflag)
1921		VOP_UNLOCK(*vpp, 0, p);
1922	return (0);
1923}
1924
1925
1926/*
1927 * WebNFS: check if a filehandle is a public filehandle. For v3, this
1928 * means a length of 0, for v2 it means all zeroes. nfsm_srvmtofh has
1929 * transformed this to all zeroes in both cases, so check for it.
1930 */
1931int
1932nfs_ispublicfh(fhp)
1933	fhandle_t *fhp;
1934{
1935	char *cp = (char *)fhp;
1936	int i;
1937
1938	for (i = 0; i < NFSX_V3FH; i++)
1939		if (*cp++ != 0)
1940			return (FALSE);
1941	return (TRUE);
1942}
1943
1944#endif /* NFS_NOSERVER */
1945/*
1946 * This function compares two net addresses by family and returns TRUE
1947 * if they are the same host.
1948 * If there is any doubt, return FALSE.
1949 * The AF_INET family is handled as a special case so that address mbufs
1950 * don't need to be saved to store "struct in_addr", which is only 4 bytes.
1951 */
1952int
1953netaddr_match(family, haddr, nam)
1954	int family;
1955	union nethostaddr *haddr;
1956	struct sockaddr *nam;
1957{
1958	register struct sockaddr_in *inetaddr;
1959
1960	switch (family) {
1961	case AF_INET:
1962		inetaddr = (struct sockaddr_in *)nam;
1963		if (inetaddr->sin_family == AF_INET &&
1964		    inetaddr->sin_addr.s_addr == haddr->had_inetaddr)
1965			return (1);
1966		break;
1967#ifdef ISO
1968	case AF_ISO:
1969	    {
1970		register struct sockaddr_iso *isoaddr1, *isoaddr2;
1971
1972		isoaddr1 = (struct sockaddr_iso *)nam;
1973		isoaddr2 = (struct sockaddr_iso *)haddr->had_nam;
1974		if (isoaddr1->siso_family == AF_ISO &&
1975		    isoaddr1->siso_nlen > 0 &&
1976		    isoaddr1->siso_nlen == isoaddr2->siso_nlen &&
1977		    SAME_ISOADDR(isoaddr1, isoaddr2))
1978			return (1);
1979		break;
1980	    }
1981#endif	/* ISO */
1982	default:
1983		break;
1984	};
1985	return (0);
1986}
1987
1988static nfsuint64 nfs_nullcookie = { 0, 0 };
1989/*
1990 * This function finds the directory cookie that corresponds to the
1991 * logical byte offset given.
1992 */
1993nfsuint64 *
1994nfs_getcookie(np, off, add)
1995	register struct nfsnode *np;
1996	off_t off;
1997	int add;
1998{
1999	register struct nfsdmap *dp, *dp2;
2000	register int pos;
2001
2002	pos = off / NFS_DIRBLKSIZ;
2003	if (pos == 0) {
2004#ifdef DIAGNOSTIC
2005		if (add)
2006			panic("nfs getcookie add at 0");
2007#endif
2008		return (&nfs_nullcookie);
2009	}
2010	pos--;
2011	dp = np->n_cookies.lh_first;
2012	if (!dp) {
2013		if (add) {
2014			MALLOC(dp, struct nfsdmap *, sizeof (struct nfsdmap),
2015				M_NFSDIROFF, M_WAITOK);
2016			dp->ndm_eocookie = 0;
2017			LIST_INSERT_HEAD(&np->n_cookies, dp, ndm_list);
2018		} else
2019			return ((nfsuint64 *)0);
2020	}
2021	while (pos >= NFSNUMCOOKIES) {
2022		pos -= NFSNUMCOOKIES;
2023		if (dp->ndm_list.le_next) {
2024			if (!add && dp->ndm_eocookie < NFSNUMCOOKIES &&
2025				pos >= dp->ndm_eocookie)
2026				return ((nfsuint64 *)0);
2027			dp = dp->ndm_list.le_next;
2028		} else if (add) {
2029			MALLOC(dp2, struct nfsdmap *, sizeof (struct nfsdmap),
2030				M_NFSDIROFF, M_WAITOK);
2031			dp2->ndm_eocookie = 0;
2032			LIST_INSERT_AFTER(dp, dp2, ndm_list);
2033			dp = dp2;
2034		} else
2035			return ((nfsuint64 *)0);
2036	}
2037	if (pos >= dp->ndm_eocookie) {
2038		if (add)
2039			dp->ndm_eocookie = pos + 1;
2040		else
2041			return ((nfsuint64 *)0);
2042	}
2043	return (&dp->ndm_cookies[pos]);
2044}
2045
2046/*
2047 * Invalidate cached directory information, except for the actual directory
2048 * blocks (which are invalidated separately).
2049 * Done mainly to avoid the use of stale offset cookies.
2050 */
2051void
2052nfs_invaldir(vp)
2053	register struct vnode *vp;
2054{
2055	register struct nfsnode *np = VTONFS(vp);
2056
2057#ifdef DIAGNOSTIC
2058	if (vp->v_type != VDIR)
2059		panic("nfs: invaldir not dir");
2060#endif
2061	np->n_direofoffset = 0;
2062	np->n_cookieverf.nfsuquad[0] = 0;
2063	np->n_cookieverf.nfsuquad[1] = 0;
2064	if (np->n_cookies.lh_first)
2065		np->n_cookies.lh_first->ndm_eocookie = 0;
2066}
2067
2068/*
2069 * The write verifier has changed (probably due to a server reboot), so all
2070 * B_NEEDCOMMIT blocks will have to be written again. Since they are on the
2071 * dirty block list as B_DELWRI, all this takes is clearing the B_NEEDCOMMIT
2072 * flag. Once done the new write verifier can be set for the mount point.
2073 */
2074void
2075nfs_clearcommit(mp)
2076	struct mount *mp;
2077{
2078	register struct vnode *vp, *nvp;
2079	register struct buf *bp, *nbp;
2080	int s;
2081
2082	s = splbio();
2083loop:
2084	for (vp = mp->mnt_vnodelist.lh_first; vp; vp = nvp) {
2085		if (vp->v_mount != mp)	/* Paranoia */
2086			goto loop;
2087		nvp = vp->v_mntvnodes.le_next;
2088		for (bp = vp->v_dirtyblkhd.lh_first; bp; bp = nbp) {
2089			nbp = bp->b_vnbufs.le_next;
2090			if ((bp->b_flags & (B_BUSY | B_DELWRI | B_NEEDCOMMIT))
2091				== (B_DELWRI | B_NEEDCOMMIT))
2092				bp->b_flags &= ~B_NEEDCOMMIT;
2093		}
2094	}
2095	splx(s);
2096}
2097
2098#ifndef NFS_NOSERVER
2099/*
2100 * Map errnos to NFS error numbers. For Version 3 also filter out error
2101 * numbers not specified for the associated procedure.
2102 */
2103int
2104nfsrv_errmap(nd, err)
2105	struct nfsrv_descript *nd;
2106	register int err;
2107{
2108	register short *defaulterrp, *errp;
2109
2110	if (nd->nd_flag & ND_NFSV3) {
2111	    if (nd->nd_procnum <= NFSPROC_COMMIT) {
2112		errp = defaulterrp = nfsrv_v3errmap[nd->nd_procnum];
2113		while (*++errp) {
2114			if (*errp == err)
2115				return (err);
2116			else if (*errp > err)
2117				break;
2118		}
2119		return ((int)*defaulterrp);
2120	    } else
2121		return (err & 0xffff);
2122	}
2123	if (err <= ELAST)
2124		return ((int)nfsrv_v2errmap[err - 1]);
2125	return (NFSERR_IO);
2126}
2127
2128int
2129nfsrv_object_create(vp)
2130	struct vnode *vp;
2131{
2132
2133	if (vp == NULL || vp->v_type != VREG)
2134		return (1);
2135	return (vfs_object_create(vp, curproc,
2136				  curproc ? curproc->p_ucred : NULL, 1));
2137}
2138#endif /* NFS_NOSERVER */
2139