xref: /csrg-svn/sys/nfs/nfs_subs.c (revision 68653)
138420Smckusick /*
263485Sbostic  * Copyright (c) 1989, 1993
363485Sbostic  *	The Regents of the University of California.  All rights reserved.
438420Smckusick  *
538420Smckusick  * This code is derived from software contributed to Berkeley by
638420Smckusick  * Rick Macklem at The University of Guelph.
738420Smckusick  *
844513Sbostic  * %sccs.include.redist.c%
938420Smckusick  *
10*68653Smckusick  *	@(#)nfs_subs.c	8.6 (Berkeley) 03/30/95
1138420Smckusick  */
1238420Smckusick 
13*68653Smckusick 
1438420Smckusick /*
1538420Smckusick  * These functions support the macros and help fiddle mbuf chains for
1638420Smckusick  * the nfs op functions. They do things like create the rpc header and
1738420Smckusick  * copy data between mbuf chains and uio lists.
1838420Smckusick  */
1953322Smckusick #include <sys/param.h>
2053322Smckusick #include <sys/proc.h>
2153322Smckusick #include <sys/systm.h>
2253322Smckusick #include <sys/kernel.h>
2353322Smckusick #include <sys/mount.h>
2453322Smckusick #include <sys/vnode.h>
2553322Smckusick #include <sys/namei.h>
2653322Smckusick #include <sys/mbuf.h>
2753322Smckusick #include <sys/socket.h>
2854445Smckusick #include <sys/stat.h>
29*68653Smckusick #include <sys/malloc.h>
30*68653Smckusick #ifdef VFS_LKM
31*68653Smckusick #include <sys/sysent.h>
32*68653Smckusick #include <sys/syscall.h>
33*68653Smckusick #endif
3447573Skarels 
35*68653Smckusick #include <vm/vm.h>
36*68653Smckusick 
3753322Smckusick #include <nfs/rpcv2.h>
38*68653Smckusick #include <nfs/nfsproto.h>
3953322Smckusick #include <nfs/nfsnode.h>
4053322Smckusick #include <nfs/nfs.h>
4153322Smckusick #include <nfs/xdr_subs.h>
4253322Smckusick #include <nfs/nfsm_subs.h>
4353322Smckusick #include <nfs/nfsmount.h>
4453322Smckusick #include <nfs/nqnfs.h>
4553322Smckusick #include <nfs/nfsrtt.h>
4653322Smckusick 
4755703Smckusick #include <miscfs/specfs/specdev.h>
4855703Smckusick 
4954988Smckusick #include <netinet/in.h>
5054988Smckusick #ifdef ISO
5154988Smckusick #include <netiso/iso.h>
5254988Smckusick #endif
5354988Smckusick 
5438420Smckusick /*
5538420Smckusick  * Data items converted to xdr at startup, since they are constant
5638420Smckusick  * This is kinda hokey, but may save a little time doing byte swaps
5738420Smckusick  */
5838420Smckusick u_long nfs_xdrneg1;
5952196Smckusick u_long rpc_call, rpc_vers, rpc_reply, rpc_msgdenied, rpc_autherr,
60*68653Smckusick 	rpc_mismatch, rpc_auth_unix, rpc_msgaccepted,
6152196Smckusick 	rpc_auth_kerb;
62*68653Smckusick u_long nfs_prog, nqnfs_prog, nfs_true, nfs_false;
6352196Smckusick 
6438420Smckusick /* And other global data */
6552196Smckusick static u_long nfs_xid = 0;
66*68653Smckusick enum vtype nv2tov_type[8] = { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON, VNON };
67*68653Smckusick enum vtype nv3tov_type[8]={ VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO };
68*68653Smckusick int nfs_mount_type;
69*68653Smckusick int nfs_ticks;
70*68653Smckusick 
71*68653Smckusick /*
72*68653Smckusick  * Mapping of old NFS Version 2 RPC numbers to generic numbers.
73*68653Smckusick  */
74*68653Smckusick int nfsv3_procid[NFS_NPROCS] = {
75*68653Smckusick 	NFSPROC_NULL,
76*68653Smckusick 	NFSPROC_GETATTR,
77*68653Smckusick 	NFSPROC_SETATTR,
78*68653Smckusick 	NFSPROC_NOOP,
79*68653Smckusick 	NFSPROC_LOOKUP,
80*68653Smckusick 	NFSPROC_READLINK,
81*68653Smckusick 	NFSPROC_READ,
82*68653Smckusick 	NFSPROC_NOOP,
83*68653Smckusick 	NFSPROC_WRITE,
84*68653Smckusick 	NFSPROC_CREATE,
85*68653Smckusick 	NFSPROC_REMOVE,
86*68653Smckusick 	NFSPROC_RENAME,
87*68653Smckusick 	NFSPROC_LINK,
88*68653Smckusick 	NFSPROC_SYMLINK,
89*68653Smckusick 	NFSPROC_MKDIR,
90*68653Smckusick 	NFSPROC_RMDIR,
91*68653Smckusick 	NFSPROC_READDIR,
92*68653Smckusick 	NFSPROC_FSSTAT,
93*68653Smckusick 	NFSPROC_NOOP,
94*68653Smckusick 	NFSPROC_NOOP,
95*68653Smckusick 	NFSPROC_NOOP,
96*68653Smckusick 	NFSPROC_NOOP,
97*68653Smckusick 	NFSPROC_NOOP,
98*68653Smckusick 	NFSPROC_NOOP,
99*68653Smckusick 	NFSPROC_NOOP,
100*68653Smckusick 	NFSPROC_NOOP
101*68653Smckusick };
102*68653Smckusick 
103*68653Smckusick /*
104*68653Smckusick  * and the reverse mapping from generic to Version 2 procedure numbers
105*68653Smckusick  */
106*68653Smckusick int nfsv2_procid[NFS_NPROCS] = {
107*68653Smckusick 	NFSV2PROC_NULL,
108*68653Smckusick 	NFSV2PROC_GETATTR,
109*68653Smckusick 	NFSV2PROC_SETATTR,
110*68653Smckusick 	NFSV2PROC_LOOKUP,
111*68653Smckusick 	NFSV2PROC_NOOP,
112*68653Smckusick 	NFSV2PROC_READLINK,
113*68653Smckusick 	NFSV2PROC_READ,
114*68653Smckusick 	NFSV2PROC_WRITE,
115*68653Smckusick 	NFSV2PROC_CREATE,
116*68653Smckusick 	NFSV2PROC_MKDIR,
117*68653Smckusick 	NFSV2PROC_SYMLINK,
118*68653Smckusick 	NFSV2PROC_CREATE,
119*68653Smckusick 	NFSV2PROC_REMOVE,
120*68653Smckusick 	NFSV2PROC_RMDIR,
121*68653Smckusick 	NFSV2PROC_RENAME,
122*68653Smckusick 	NFSV2PROC_LINK,
123*68653Smckusick 	NFSV2PROC_READDIR,
124*68653Smckusick 	NFSV2PROC_NOOP,
125*68653Smckusick 	NFSV2PROC_STATFS,
126*68653Smckusick 	NFSV2PROC_NOOP,
127*68653Smckusick 	NFSV2PROC_NOOP,
128*68653Smckusick 	NFSV2PROC_NOOP,
129*68653Smckusick 	NFSV2PROC_NOOP,
130*68653Smckusick 	NFSV2PROC_NOOP,
131*68653Smckusick 	NFSV2PROC_NOOP,
132*68653Smckusick 	NFSV2PROC_NOOP,
133*68653Smckusick };
134*68653Smckusick 
135*68653Smckusick /*
136*68653Smckusick  * Maps errno values to nfs error numbers.
137*68653Smckusick  * Use NFSERR_IO as the catch all for ones not specifically defined in
138*68653Smckusick  * RFC 1094.
139*68653Smckusick  */
140*68653Smckusick static u_char nfsrv_v2errmap[ELAST] = {
141*68653Smckusick   NFSERR_PERM,	NFSERR_NOENT,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
142*68653Smckusick   NFSERR_NXIO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
143*68653Smckusick   NFSERR_IO,	NFSERR_IO,	NFSERR_ACCES,	NFSERR_IO,	NFSERR_IO,
144*68653Smckusick   NFSERR_IO,	NFSERR_EXIST,	NFSERR_IO,	NFSERR_NODEV,	NFSERR_NOTDIR,
145*68653Smckusick   NFSERR_ISDIR,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
146*68653Smckusick   NFSERR_IO,	NFSERR_FBIG,	NFSERR_NOSPC,	NFSERR_IO,	NFSERR_ROFS,
147*68653Smckusick   NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
148*68653Smckusick   NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
149*68653Smckusick   NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
150*68653Smckusick   NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
151*68653Smckusick   NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
152*68653Smckusick   NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
153*68653Smckusick   NFSERR_IO,	NFSERR_IO,	NFSERR_NAMETOL,	NFSERR_IO,	NFSERR_IO,
154*68653Smckusick   NFSERR_NOTEMPTY, NFSERR_IO,	NFSERR_IO,	NFSERR_DQUOT,	NFSERR_STALE,
155*68653Smckusick   NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
156*68653Smckusick   NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
157*68653Smckusick   NFSERR_IO,
158*68653Smckusick };
159*68653Smckusick 
160*68653Smckusick /*
161*68653Smckusick  * Maps errno values to nfs error numbers.
162*68653Smckusick  * Although it is not obvious whether or not NFS clients really care if
163*68653Smckusick  * a returned error value is in the specified list for the procedure, the
164*68653Smckusick  * safest thing to do is filter them appropriately. For Version 2, the
165*68653Smckusick  * X/Open XNFS document is the only specification that defines error values
166*68653Smckusick  * for each RPC (The RFC simply lists all possible error values for all RPCs),
167*68653Smckusick  * so I have decided to not do this for Version 2.
168*68653Smckusick  * The first entry is the default error return and the rest are the valid
169*68653Smckusick  * errors for that RPC in increasing numeric order.
170*68653Smckusick  */
171*68653Smckusick static short nfsv3err_null[] = {
172*68653Smckusick 	0,
173*68653Smckusick 	0,
174*68653Smckusick };
175*68653Smckusick 
176*68653Smckusick static short nfsv3err_getattr[] = {
177*68653Smckusick 	NFSERR_IO,
178*68653Smckusick 	NFSERR_IO,
179*68653Smckusick 	NFSERR_STALE,
180*68653Smckusick 	NFSERR_BADHANDLE,
181*68653Smckusick 	NFSERR_SERVERFAULT,
182*68653Smckusick 	0,
183*68653Smckusick };
184*68653Smckusick 
185*68653Smckusick static short nfsv3err_setattr[] = {
186*68653Smckusick 	NFSERR_IO,
187*68653Smckusick 	NFSERR_PERM,
188*68653Smckusick 	NFSERR_IO,
189*68653Smckusick 	NFSERR_ACCES,
190*68653Smckusick 	NFSERR_INVAL,
191*68653Smckusick 	NFSERR_NOSPC,
192*68653Smckusick 	NFSERR_ROFS,
193*68653Smckusick 	NFSERR_DQUOT,
194*68653Smckusick 	NFSERR_STALE,
195*68653Smckusick 	NFSERR_BADHANDLE,
196*68653Smckusick 	NFSERR_NOT_SYNC,
197*68653Smckusick 	NFSERR_SERVERFAULT,
198*68653Smckusick 	0,
199*68653Smckusick };
200*68653Smckusick 
201*68653Smckusick static short nfsv3err_lookup[] = {
202*68653Smckusick 	NFSERR_IO,
203*68653Smckusick 	NFSERR_NOENT,
204*68653Smckusick 	NFSERR_IO,
205*68653Smckusick 	NFSERR_ACCES,
206*68653Smckusick 	NFSERR_NOTDIR,
207*68653Smckusick 	NFSERR_NAMETOL,
208*68653Smckusick 	NFSERR_STALE,
209*68653Smckusick 	NFSERR_BADHANDLE,
210*68653Smckusick 	NFSERR_SERVERFAULT,
211*68653Smckusick 	0,
212*68653Smckusick };
213*68653Smckusick 
214*68653Smckusick static short nfsv3err_access[] = {
215*68653Smckusick 	NFSERR_IO,
216*68653Smckusick 	NFSERR_IO,
217*68653Smckusick 	NFSERR_STALE,
218*68653Smckusick 	NFSERR_BADHANDLE,
219*68653Smckusick 	NFSERR_SERVERFAULT,
220*68653Smckusick 	0,
221*68653Smckusick };
222*68653Smckusick 
223*68653Smckusick static short nfsv3err_readlink[] = {
224*68653Smckusick 	NFSERR_IO,
225*68653Smckusick 	NFSERR_IO,
226*68653Smckusick 	NFSERR_ACCES,
227*68653Smckusick 	NFSERR_INVAL,
228*68653Smckusick 	NFSERR_STALE,
229*68653Smckusick 	NFSERR_BADHANDLE,
230*68653Smckusick 	NFSERR_NOTSUPP,
231*68653Smckusick 	NFSERR_SERVERFAULT,
232*68653Smckusick 	0,
233*68653Smckusick };
234*68653Smckusick 
235*68653Smckusick static short nfsv3err_read[] = {
236*68653Smckusick 	NFSERR_IO,
237*68653Smckusick 	NFSERR_IO,
238*68653Smckusick 	NFSERR_NXIO,
239*68653Smckusick 	NFSERR_ACCES,
240*68653Smckusick 	NFSERR_INVAL,
241*68653Smckusick 	NFSERR_STALE,
242*68653Smckusick 	NFSERR_BADHANDLE,
243*68653Smckusick 	NFSERR_SERVERFAULT,
244*68653Smckusick 	0,
245*68653Smckusick };
246*68653Smckusick 
247*68653Smckusick static short nfsv3err_write[] = {
248*68653Smckusick 	NFSERR_IO,
249*68653Smckusick 	NFSERR_IO,
250*68653Smckusick 	NFSERR_ACCES,
251*68653Smckusick 	NFSERR_INVAL,
252*68653Smckusick 	NFSERR_FBIG,
253*68653Smckusick 	NFSERR_NOSPC,
254*68653Smckusick 	NFSERR_ROFS,
255*68653Smckusick 	NFSERR_DQUOT,
256*68653Smckusick 	NFSERR_STALE,
257*68653Smckusick 	NFSERR_BADHANDLE,
258*68653Smckusick 	NFSERR_SERVERFAULT,
259*68653Smckusick 	0,
260*68653Smckusick };
261*68653Smckusick 
262*68653Smckusick static short nfsv3err_create[] = {
263*68653Smckusick 	NFSERR_IO,
264*68653Smckusick 	NFSERR_IO,
265*68653Smckusick 	NFSERR_ACCES,
266*68653Smckusick 	NFSERR_EXIST,
267*68653Smckusick 	NFSERR_NOTDIR,
268*68653Smckusick 	NFSERR_NOSPC,
269*68653Smckusick 	NFSERR_ROFS,
270*68653Smckusick 	NFSERR_NAMETOL,
271*68653Smckusick 	NFSERR_DQUOT,
272*68653Smckusick 	NFSERR_STALE,
273*68653Smckusick 	NFSERR_BADHANDLE,
274*68653Smckusick 	NFSERR_NOTSUPP,
275*68653Smckusick 	NFSERR_SERVERFAULT,
276*68653Smckusick 	0,
277*68653Smckusick };
278*68653Smckusick 
279*68653Smckusick static short nfsv3err_mkdir[] = {
280*68653Smckusick 	NFSERR_IO,
281*68653Smckusick 	NFSERR_IO,
282*68653Smckusick 	NFSERR_ACCES,
283*68653Smckusick 	NFSERR_EXIST,
284*68653Smckusick 	NFSERR_NOTDIR,
285*68653Smckusick 	NFSERR_NOSPC,
286*68653Smckusick 	NFSERR_ROFS,
287*68653Smckusick 	NFSERR_NAMETOL,
288*68653Smckusick 	NFSERR_DQUOT,
289*68653Smckusick 	NFSERR_STALE,
290*68653Smckusick 	NFSERR_BADHANDLE,
291*68653Smckusick 	NFSERR_NOTSUPP,
292*68653Smckusick 	NFSERR_SERVERFAULT,
293*68653Smckusick 	0,
294*68653Smckusick };
295*68653Smckusick 
296*68653Smckusick static short nfsv3err_symlink[] = {
297*68653Smckusick 	NFSERR_IO,
298*68653Smckusick 	NFSERR_IO,
299*68653Smckusick 	NFSERR_ACCES,
300*68653Smckusick 	NFSERR_EXIST,
301*68653Smckusick 	NFSERR_NOTDIR,
302*68653Smckusick 	NFSERR_NOSPC,
303*68653Smckusick 	NFSERR_ROFS,
304*68653Smckusick 	NFSERR_NAMETOL,
305*68653Smckusick 	NFSERR_DQUOT,
306*68653Smckusick 	NFSERR_STALE,
307*68653Smckusick 	NFSERR_BADHANDLE,
308*68653Smckusick 	NFSERR_NOTSUPP,
309*68653Smckusick 	NFSERR_SERVERFAULT,
310*68653Smckusick 	0,
311*68653Smckusick };
312*68653Smckusick 
313*68653Smckusick static short nfsv3err_mknod[] = {
314*68653Smckusick 	NFSERR_IO,
315*68653Smckusick 	NFSERR_IO,
316*68653Smckusick 	NFSERR_ACCES,
317*68653Smckusick 	NFSERR_EXIST,
318*68653Smckusick 	NFSERR_NOTDIR,
319*68653Smckusick 	NFSERR_NOSPC,
320*68653Smckusick 	NFSERR_ROFS,
321*68653Smckusick 	NFSERR_NAMETOL,
322*68653Smckusick 	NFSERR_DQUOT,
323*68653Smckusick 	NFSERR_STALE,
324*68653Smckusick 	NFSERR_BADHANDLE,
325*68653Smckusick 	NFSERR_NOTSUPP,
326*68653Smckusick 	NFSERR_SERVERFAULT,
327*68653Smckusick 	NFSERR_BADTYPE,
328*68653Smckusick 	0,
329*68653Smckusick };
330*68653Smckusick 
331*68653Smckusick static short nfsv3err_remove[] = {
332*68653Smckusick 	NFSERR_IO,
333*68653Smckusick 	NFSERR_NOENT,
334*68653Smckusick 	NFSERR_IO,
335*68653Smckusick 	NFSERR_ACCES,
336*68653Smckusick 	NFSERR_NOTDIR,
337*68653Smckusick 	NFSERR_ROFS,
338*68653Smckusick 	NFSERR_NAMETOL,
339*68653Smckusick 	NFSERR_STALE,
340*68653Smckusick 	NFSERR_BADHANDLE,
341*68653Smckusick 	NFSERR_SERVERFAULT,
342*68653Smckusick 	0,
343*68653Smckusick };
344*68653Smckusick 
345*68653Smckusick static short nfsv3err_rmdir[] = {
346*68653Smckusick 	NFSERR_IO,
347*68653Smckusick 	NFSERR_NOENT,
348*68653Smckusick 	NFSERR_IO,
349*68653Smckusick 	NFSERR_ACCES,
350*68653Smckusick 	NFSERR_EXIST,
351*68653Smckusick 	NFSERR_NOTDIR,
352*68653Smckusick 	NFSERR_INVAL,
353*68653Smckusick 	NFSERR_ROFS,
354*68653Smckusick 	NFSERR_NAMETOL,
355*68653Smckusick 	NFSERR_NOTEMPTY,
356*68653Smckusick 	NFSERR_STALE,
357*68653Smckusick 	NFSERR_BADHANDLE,
358*68653Smckusick 	NFSERR_NOTSUPP,
359*68653Smckusick 	NFSERR_SERVERFAULT,
360*68653Smckusick 	0,
361*68653Smckusick };
362*68653Smckusick 
363*68653Smckusick static short nfsv3err_rename[] = {
364*68653Smckusick 	NFSERR_IO,
365*68653Smckusick 	NFSERR_NOENT,
366*68653Smckusick 	NFSERR_IO,
367*68653Smckusick 	NFSERR_ACCES,
368*68653Smckusick 	NFSERR_EXIST,
369*68653Smckusick 	NFSERR_XDEV,
370*68653Smckusick 	NFSERR_NOTDIR,
371*68653Smckusick 	NFSERR_ISDIR,
372*68653Smckusick 	NFSERR_INVAL,
373*68653Smckusick 	NFSERR_NOSPC,
374*68653Smckusick 	NFSERR_ROFS,
375*68653Smckusick 	NFSERR_MLINK,
376*68653Smckusick 	NFSERR_NAMETOL,
377*68653Smckusick 	NFSERR_NOTEMPTY,
378*68653Smckusick 	NFSERR_DQUOT,
379*68653Smckusick 	NFSERR_STALE,
380*68653Smckusick 	NFSERR_BADHANDLE,
381*68653Smckusick 	NFSERR_NOTSUPP,
382*68653Smckusick 	NFSERR_SERVERFAULT,
383*68653Smckusick 	0,
384*68653Smckusick };
385*68653Smckusick 
386*68653Smckusick static short nfsv3err_link[] = {
387*68653Smckusick 	NFSERR_IO,
388*68653Smckusick 	NFSERR_IO,
389*68653Smckusick 	NFSERR_ACCES,
390*68653Smckusick 	NFSERR_EXIST,
391*68653Smckusick 	NFSERR_XDEV,
392*68653Smckusick 	NFSERR_NOTDIR,
393*68653Smckusick 	NFSERR_INVAL,
394*68653Smckusick 	NFSERR_NOSPC,
395*68653Smckusick 	NFSERR_ROFS,
396*68653Smckusick 	NFSERR_MLINK,
397*68653Smckusick 	NFSERR_NAMETOL,
398*68653Smckusick 	NFSERR_DQUOT,
399*68653Smckusick 	NFSERR_STALE,
400*68653Smckusick 	NFSERR_BADHANDLE,
401*68653Smckusick 	NFSERR_NOTSUPP,
402*68653Smckusick 	NFSERR_SERVERFAULT,
403*68653Smckusick 	0,
404*68653Smckusick };
405*68653Smckusick 
406*68653Smckusick static short nfsv3err_readdir[] = {
407*68653Smckusick 	NFSERR_IO,
408*68653Smckusick 	NFSERR_IO,
409*68653Smckusick 	NFSERR_ACCES,
410*68653Smckusick 	NFSERR_NOTDIR,
411*68653Smckusick 	NFSERR_STALE,
412*68653Smckusick 	NFSERR_BADHANDLE,
413*68653Smckusick 	NFSERR_BAD_COOKIE,
414*68653Smckusick 	NFSERR_TOOSMALL,
415*68653Smckusick 	NFSERR_SERVERFAULT,
416*68653Smckusick 	0,
417*68653Smckusick };
418*68653Smckusick 
419*68653Smckusick static short nfsv3err_readdirplus[] = {
420*68653Smckusick 	NFSERR_IO,
421*68653Smckusick 	NFSERR_IO,
422*68653Smckusick 	NFSERR_ACCES,
423*68653Smckusick 	NFSERR_NOTDIR,
424*68653Smckusick 	NFSERR_STALE,
425*68653Smckusick 	NFSERR_BADHANDLE,
426*68653Smckusick 	NFSERR_BAD_COOKIE,
427*68653Smckusick 	NFSERR_NOTSUPP,
428*68653Smckusick 	NFSERR_TOOSMALL,
429*68653Smckusick 	NFSERR_SERVERFAULT,
430*68653Smckusick 	0,
431*68653Smckusick };
432*68653Smckusick 
433*68653Smckusick static short nfsv3err_fsstat[] = {
434*68653Smckusick 	NFSERR_IO,
435*68653Smckusick 	NFSERR_IO,
436*68653Smckusick 	NFSERR_STALE,
437*68653Smckusick 	NFSERR_BADHANDLE,
438*68653Smckusick 	NFSERR_SERVERFAULT,
439*68653Smckusick 	0,
440*68653Smckusick };
441*68653Smckusick 
442*68653Smckusick static short nfsv3err_fsinfo[] = {
443*68653Smckusick 	NFSERR_STALE,
444*68653Smckusick 	NFSERR_STALE,
445*68653Smckusick 	NFSERR_BADHANDLE,
446*68653Smckusick 	NFSERR_SERVERFAULT,
447*68653Smckusick 	0,
448*68653Smckusick };
449*68653Smckusick 
450*68653Smckusick static short nfsv3err_pathconf[] = {
451*68653Smckusick 	NFSERR_STALE,
452*68653Smckusick 	NFSERR_STALE,
453*68653Smckusick 	NFSERR_BADHANDLE,
454*68653Smckusick 	NFSERR_SERVERFAULT,
455*68653Smckusick 	0,
456*68653Smckusick };
457*68653Smckusick 
458*68653Smckusick static short nfsv3err_commit[] = {
459*68653Smckusick 	NFSERR_IO,
460*68653Smckusick 	NFSERR_IO,
461*68653Smckusick 	NFSERR_STALE,
462*68653Smckusick 	NFSERR_BADHANDLE,
463*68653Smckusick 	NFSERR_SERVERFAULT,
464*68653Smckusick 	0,
465*68653Smckusick };
466*68653Smckusick 
467*68653Smckusick static short *nfsrv_v3errmap[] = {
468*68653Smckusick 	nfsv3err_null,
469*68653Smckusick 	nfsv3err_getattr,
470*68653Smckusick 	nfsv3err_setattr,
471*68653Smckusick 	nfsv3err_lookup,
472*68653Smckusick 	nfsv3err_access,
473*68653Smckusick 	nfsv3err_readlink,
474*68653Smckusick 	nfsv3err_read,
475*68653Smckusick 	nfsv3err_write,
476*68653Smckusick 	nfsv3err_create,
477*68653Smckusick 	nfsv3err_mkdir,
478*68653Smckusick 	nfsv3err_symlink,
479*68653Smckusick 	nfsv3err_mknod,
480*68653Smckusick 	nfsv3err_remove,
481*68653Smckusick 	nfsv3err_rmdir,
482*68653Smckusick 	nfsv3err_rename,
483*68653Smckusick 	nfsv3err_link,
484*68653Smckusick 	nfsv3err_readdir,
485*68653Smckusick 	nfsv3err_readdirplus,
486*68653Smckusick 	nfsv3err_fsstat,
487*68653Smckusick 	nfsv3err_fsinfo,
488*68653Smckusick 	nfsv3err_pathconf,
489*68653Smckusick 	nfsv3err_commit,
490*68653Smckusick };
491*68653Smckusick 
49241902Smckusick extern struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON];
49352196Smckusick extern struct nfsrtt nfsrtt;
49452196Smckusick extern time_t nqnfsstarttime;
49552196Smckusick extern int nqsrv_clockskew;
49652196Smckusick extern int nqsrv_writeslack;
49752196Smckusick extern int nqsrv_maxlease;
498*68653Smckusick extern struct nfsstats nfsstats;
499*68653Smckusick extern int nqnfs_piggy[NFS_NPROCS];
500*68653Smckusick extern nfstype nfsv2_type[9];
501*68653Smckusick extern nfstype nfsv3_type[9];
502*68653Smckusick extern struct nfsnodehashhead *nfsnodehashtbl;
503*68653Smckusick extern u_long nfsnodehash;
50438420Smckusick 
505*68653Smckusick #ifdef VFS_LKM
506*68653Smckusick struct getfh_args;
507*68653Smckusick extern int getfh(struct proc *, struct getfh_args *, int *);
508*68653Smckusick struct nfssvc_args;
509*68653Smckusick extern int nfssvc(struct proc *, struct nfssvc_args *, int *);
510*68653Smckusick #endif
511*68653Smckusick 
51267708Smckusick LIST_HEAD(nfsnodehashhead, nfsnode);
51367708Smckusick 
51438420Smckusick /*
51538420Smckusick  * Create the header for an rpc request packet
51638420Smckusick  * The hsiz is the size of the rest of the nfs request header.
51738420Smckusick  * (just used to decide if a cluster is a good idea)
51838420Smckusick  */
51952196Smckusick struct mbuf *
52052196Smckusick nfsm_reqh(vp, procid, hsiz, bposp)
52152196Smckusick 	struct vnode *vp;
52239494Smckusick 	u_long procid;
52338420Smckusick 	int hsiz;
52452196Smckusick 	caddr_t *bposp;
52538420Smckusick {
52652196Smckusick 	register struct mbuf *mb;
52748049Smckusick 	register u_long *tl;
52852196Smckusick 	register caddr_t bpos;
52952196Smckusick 	struct mbuf *mb2;
53052196Smckusick 	struct nfsmount *nmp;
53152196Smckusick 	int nqflag;
53238420Smckusick 
53352196Smckusick 	MGET(mb, M_WAIT, MT_DATA);
53452196Smckusick 	if (hsiz >= MINCLSIZE)
53552196Smckusick 		MCLGET(mb, M_WAIT);
53652196Smckusick 	mb->m_len = 0;
53752196Smckusick 	bpos = mtod(mb, caddr_t);
53852196Smckusick 
53952196Smckusick 	/*
54052196Smckusick 	 * For NQNFS, add lease request.
54152196Smckusick 	 */
54252196Smckusick 	if (vp) {
54352196Smckusick 		nmp = VFSTONFS(vp->v_mount);
54452196Smckusick 		if (nmp->nm_flag & NFSMNT_NQNFS) {
54552196Smckusick 			nqflag = NQNFS_NEEDLEASE(vp, procid);
54652196Smckusick 			if (nqflag) {
54752196Smckusick 				nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED);
54852196Smckusick 				*tl++ = txdr_unsigned(nqflag);
54952196Smckusick 				*tl = txdr_unsigned(nmp->nm_leaseterm);
55052196Smckusick 			} else {
55152196Smckusick 				nfsm_build(tl, u_long *, NFSX_UNSIGNED);
55252196Smckusick 				*tl = 0;
55352196Smckusick 			}
55452196Smckusick 		}
55552196Smckusick 	}
55652196Smckusick 	/* Finally, return values */
55752196Smckusick 	*bposp = bpos;
55852196Smckusick 	return (mb);
55952196Smckusick }
56038420Smckusick 
56152196Smckusick /*
56252196Smckusick  * Build the RPC header and fill in the authorization info.
56352196Smckusick  * The authorization string argument is only used when the credentials
56452196Smckusick  * come from outside of the kernel.
56552196Smckusick  * Returns the head of the mbuf list.
56652196Smckusick  */
56752196Smckusick struct mbuf *
568*68653Smckusick nfsm_rpchead(cr, nmflag, procid, auth_type, auth_len, auth_str, verf_len,
569*68653Smckusick 	verf_str, mrest, mrest_len, mbp, xidp)
57052196Smckusick 	register struct ucred *cr;
571*68653Smckusick 	int nmflag;
57252196Smckusick 	int procid;
57352196Smckusick 	int auth_type;
57452196Smckusick 	int auth_len;
57552196Smckusick 	char *auth_str;
576*68653Smckusick 	int verf_len;
577*68653Smckusick 	char *verf_str;
57852196Smckusick 	struct mbuf *mrest;
57952196Smckusick 	int mrest_len;
58052196Smckusick 	struct mbuf **mbp;
58152196Smckusick 	u_long *xidp;
58252196Smckusick {
58352196Smckusick 	register struct mbuf *mb;
58452196Smckusick 	register u_long *tl;
58552196Smckusick 	register caddr_t bpos;
58652196Smckusick 	register int i;
58752196Smckusick 	struct mbuf *mreq, *mb2;
58852196Smckusick 	int siz, grpsiz, authsiz;
58952196Smckusick 
59052196Smckusick 	authsiz = nfsm_rndup(auth_len);
59152196Smckusick 	MGETHDR(mb, M_WAIT, MT_DATA);
592*68653Smckusick 	if ((authsiz + 10 * NFSX_UNSIGNED) >= MINCLSIZE) {
59352196Smckusick 		MCLGET(mb, M_WAIT);
594*68653Smckusick 	} else if ((authsiz + 10 * NFSX_UNSIGNED) < MHLEN) {
595*68653Smckusick 		MH_ALIGN(mb, authsiz + 10 * NFSX_UNSIGNED);
59652196Smckusick 	} else {
597*68653Smckusick 		MH_ALIGN(mb, 8 * NFSX_UNSIGNED);
59852196Smckusick 	}
59952196Smckusick 	mb->m_len = 0;
60052196Smckusick 	mreq = mb;
60152196Smckusick 	bpos = mtod(mb, caddr_t);
60252196Smckusick 
60338420Smckusick 	/*
60452196Smckusick 	 * First the RPC header.
60538420Smckusick 	 */
606*68653Smckusick 	nfsm_build(tl, u_long *, 8 * NFSX_UNSIGNED);
60752196Smckusick 	if (++nfs_xid == 0)
60852196Smckusick 		nfs_xid++;
60952196Smckusick 	*tl++ = *xidp = txdr_unsigned(nfs_xid);
61048049Smckusick 	*tl++ = rpc_call;
61148049Smckusick 	*tl++ = rpc_vers;
612*68653Smckusick 	if (nmflag & NFSMNT_NQNFS) {
61352196Smckusick 		*tl++ = txdr_unsigned(NQNFS_PROG);
614*68653Smckusick 		*tl++ = txdr_unsigned(NQNFS_VER3);
61552196Smckusick 	} else {
61652196Smckusick 		*tl++ = txdr_unsigned(NFS_PROG);
617*68653Smckusick 		if (nmflag & NFSMNT_NFSV3)
618*68653Smckusick 			*tl++ = txdr_unsigned(NFS_VER3);
619*68653Smckusick 		else
620*68653Smckusick 			*tl++ = txdr_unsigned(NFS_VER2);
62152196Smckusick 	}
622*68653Smckusick 	if (nmflag & NFSMNT_NFSV3)
623*68653Smckusick 		*tl++ = txdr_unsigned(procid);
624*68653Smckusick 	else
625*68653Smckusick 		*tl++ = txdr_unsigned(nfsv2_procid[procid]);
62638420Smckusick 
62752196Smckusick 	/*
62852196Smckusick 	 * And then the authorization cred.
62952196Smckusick 	 */
63052196Smckusick 	*tl++ = txdr_unsigned(auth_type);
63152196Smckusick 	*tl = txdr_unsigned(authsiz);
63252196Smckusick 	switch (auth_type) {
63352196Smckusick 	case RPCAUTH_UNIX:
63452196Smckusick 		nfsm_build(tl, u_long *, auth_len);
63552196Smckusick 		*tl++ = 0;		/* stamp ?? */
63652196Smckusick 		*tl++ = 0;		/* NULL hostname */
63752196Smckusick 		*tl++ = txdr_unsigned(cr->cr_uid);
63852196Smckusick 		*tl++ = txdr_unsigned(cr->cr_groups[0]);
63952196Smckusick 		grpsiz = (auth_len >> 2) - 5;
64052196Smckusick 		*tl++ = txdr_unsigned(grpsiz);
64152196Smckusick 		for (i = 1; i <= grpsiz; i++)
64252196Smckusick 			*tl++ = txdr_unsigned(cr->cr_groups[i]);
64352196Smckusick 		break;
644*68653Smckusick 	case RPCAUTH_KERB4:
64552196Smckusick 		siz = auth_len;
64652196Smckusick 		while (siz > 0) {
64752196Smckusick 			if (M_TRAILINGSPACE(mb) == 0) {
64852196Smckusick 				MGET(mb2, M_WAIT, MT_DATA);
64952196Smckusick 				if (siz >= MINCLSIZE)
65052196Smckusick 					MCLGET(mb2, M_WAIT);
65152196Smckusick 				mb->m_next = mb2;
65252196Smckusick 				mb = mb2;
65352196Smckusick 				mb->m_len = 0;
65452196Smckusick 				bpos = mtod(mb, caddr_t);
65552196Smckusick 			}
65655057Spendry 			i = min(siz, M_TRAILINGSPACE(mb));
65752196Smckusick 			bcopy(auth_str, bpos, i);
65852196Smckusick 			mb->m_len += i;
65952196Smckusick 			auth_str += i;
66052196Smckusick 			bpos += i;
66152196Smckusick 			siz -= i;
66238420Smckusick 		}
66357787Smckusick 		if ((siz = (nfsm_rndup(auth_len) - auth_len)) > 0) {
66452196Smckusick 			for (i = 0; i < siz; i++)
66552196Smckusick 				*bpos++ = '\0';
66652196Smckusick 			mb->m_len += siz;
66752196Smckusick 		}
66852196Smckusick 		break;
66952196Smckusick 	};
670*68653Smckusick 
671*68653Smckusick 	/*
672*68653Smckusick 	 * And the verifier...
673*68653Smckusick 	 */
674*68653Smckusick 	nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED);
675*68653Smckusick 	if (verf_str) {
676*68653Smckusick 		*tl++ = txdr_unsigned(RPCAUTH_KERB4);
677*68653Smckusick 		*tl = txdr_unsigned(verf_len);
678*68653Smckusick 		siz = verf_len;
679*68653Smckusick 		while (siz > 0) {
680*68653Smckusick 			if (M_TRAILINGSPACE(mb) == 0) {
681*68653Smckusick 				MGET(mb2, M_WAIT, MT_DATA);
682*68653Smckusick 				if (siz >= MINCLSIZE)
683*68653Smckusick 					MCLGET(mb2, M_WAIT);
684*68653Smckusick 				mb->m_next = mb2;
685*68653Smckusick 				mb = mb2;
686*68653Smckusick 				mb->m_len = 0;
687*68653Smckusick 				bpos = mtod(mb, caddr_t);
688*68653Smckusick 			}
689*68653Smckusick 			i = min(siz, M_TRAILINGSPACE(mb));
690*68653Smckusick 			bcopy(verf_str, bpos, i);
691*68653Smckusick 			mb->m_len += i;
692*68653Smckusick 			verf_str += i;
693*68653Smckusick 			bpos += i;
694*68653Smckusick 			siz -= i;
695*68653Smckusick 		}
696*68653Smckusick 		if ((siz = (nfsm_rndup(verf_len) - verf_len)) > 0) {
697*68653Smckusick 			for (i = 0; i < siz; i++)
698*68653Smckusick 				*bpos++ = '\0';
699*68653Smckusick 			mb->m_len += siz;
700*68653Smckusick 		}
701*68653Smckusick 	} else {
702*68653Smckusick 		*tl++ = txdr_unsigned(RPCAUTH_NULL);
703*68653Smckusick 		*tl = 0;
704*68653Smckusick 	}
70552196Smckusick 	mb->m_next = mrest;
706*68653Smckusick 	mreq->m_pkthdr.len = authsiz + 10 * NFSX_UNSIGNED + mrest_len;
70752196Smckusick 	mreq->m_pkthdr.rcvif = (struct ifnet *)0;
70852196Smckusick 	*mbp = mb;
70938420Smckusick 	return (mreq);
71038420Smckusick }
71138420Smckusick 
71238420Smckusick /*
71338420Smckusick  * copies mbuf chain to the uio scatter/gather list
71438420Smckusick  */
715*68653Smckusick int
71638420Smckusick nfsm_mbuftouio(mrep, uiop, siz, dpos)
71738420Smckusick 	struct mbuf **mrep;
71843353Smckusick 	register struct uio *uiop;
71938420Smckusick 	int siz;
72038420Smckusick 	caddr_t *dpos;
72138420Smckusick {
72243353Smckusick 	register char *mbufcp, *uiocp;
72338420Smckusick 	register int xfer, left, len;
72438420Smckusick 	register struct mbuf *mp;
72538420Smckusick 	long uiosiz, rem;
72641902Smckusick 	int error = 0;
72738420Smckusick 
72838420Smckusick 	mp = *mrep;
72938420Smckusick 	mbufcp = *dpos;
73038420Smckusick 	len = mtod(mp, caddr_t)+mp->m_len-mbufcp;
73138420Smckusick 	rem = nfsm_rndup(siz)-siz;
73238420Smckusick 	while (siz > 0) {
73338420Smckusick 		if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL)
73441902Smckusick 			return (EFBIG);
73538420Smckusick 		left = uiop->uio_iov->iov_len;
73638420Smckusick 		uiocp = uiop->uio_iov->iov_base;
73738420Smckusick 		if (left > siz)
73838420Smckusick 			left = siz;
73938420Smckusick 		uiosiz = left;
74038420Smckusick 		while (left > 0) {
74138420Smckusick 			while (len == 0) {
74238420Smckusick 				mp = mp->m_next;
74338420Smckusick 				if (mp == NULL)
74438420Smckusick 					return (EBADRPC);
74538420Smckusick 				mbufcp = mtod(mp, caddr_t);
74638420Smckusick 				len = mp->m_len;
74738420Smckusick 			}
74838420Smckusick 			xfer = (left > len) ? len : left;
74938420Smckusick #ifdef notdef
75038420Smckusick 			/* Not Yet.. */
75138420Smckusick 			if (uiop->uio_iov->iov_op != NULL)
75238420Smckusick 				(*(uiop->uio_iov->iov_op))
75338420Smckusick 				(mbufcp, uiocp, xfer);
75438420Smckusick 			else
75538420Smckusick #endif
75638420Smckusick 			if (uiop->uio_segflg == UIO_SYSSPACE)
75738420Smckusick 				bcopy(mbufcp, uiocp, xfer);
75838420Smckusick 			else
75938420Smckusick 				copyout(mbufcp, uiocp, xfer);
76038420Smckusick 			left -= xfer;
76138420Smckusick 			len -= xfer;
76238420Smckusick 			mbufcp += xfer;
76338420Smckusick 			uiocp += xfer;
76439585Smckusick 			uiop->uio_offset += xfer;
76538420Smckusick 			uiop->uio_resid -= xfer;
76638420Smckusick 		}
76738420Smckusick 		if (uiop->uio_iov->iov_len <= siz) {
76838420Smckusick 			uiop->uio_iovcnt--;
76938420Smckusick 			uiop->uio_iov++;
77038420Smckusick 		} else {
77138420Smckusick 			uiop->uio_iov->iov_base += uiosiz;
77238420Smckusick 			uiop->uio_iov->iov_len -= uiosiz;
77338420Smckusick 		}
77438420Smckusick 		siz -= uiosiz;
77538420Smckusick 	}
77638420Smckusick 	*dpos = mbufcp;
77738420Smckusick 	*mrep = mp;
77841902Smckusick 	if (rem > 0) {
77941902Smckusick 		if (len < rem)
78041902Smckusick 			error = nfs_adv(mrep, dpos, rem, len);
78141902Smckusick 		else
78241902Smckusick 			*dpos += rem;
78341902Smckusick 	}
78441902Smckusick 	return (error);
78538420Smckusick }
78638420Smckusick 
78738420Smckusick /*
78838420Smckusick  * copies a uio scatter/gather list to an mbuf chain...
78938420Smckusick  */
790*68653Smckusick int
79138420Smckusick nfsm_uiotombuf(uiop, mq, siz, bpos)
79238420Smckusick 	register struct uio *uiop;
79338420Smckusick 	struct mbuf **mq;
79438420Smckusick 	int siz;
79538420Smckusick 	caddr_t *bpos;
79638420Smckusick {
79743353Smckusick 	register char *uiocp;
79843353Smckusick 	register struct mbuf *mp, *mp2;
79952196Smckusick 	register int xfer, left, mlen;
80043353Smckusick 	int uiosiz, clflg, rem;
80143353Smckusick 	char *cp;
80238420Smckusick 
80338420Smckusick 	if (siz > MLEN)		/* or should it >= MCLBYTES ?? */
80438420Smckusick 		clflg = 1;
80538420Smckusick 	else
80638420Smckusick 		clflg = 0;
80738420Smckusick 	rem = nfsm_rndup(siz)-siz;
80852196Smckusick 	mp = mp2 = *mq;
80938420Smckusick 	while (siz > 0) {
81038420Smckusick 		if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL)
81141902Smckusick 			return (EINVAL);
81238420Smckusick 		left = uiop->uio_iov->iov_len;
81338420Smckusick 		uiocp = uiop->uio_iov->iov_base;
81438420Smckusick 		if (left > siz)
81538420Smckusick 			left = siz;
81638420Smckusick 		uiosiz = left;
81738420Smckusick 		while (left > 0) {
81852196Smckusick 			mlen = M_TRAILINGSPACE(mp);
81952196Smckusick 			if (mlen == 0) {
82052196Smckusick 				MGET(mp, M_WAIT, MT_DATA);
82152196Smckusick 				if (clflg)
82252196Smckusick 					MCLGET(mp, M_WAIT);
82352196Smckusick 				mp->m_len = 0;
82452196Smckusick 				mp2->m_next = mp;
82552196Smckusick 				mp2 = mp;
82652196Smckusick 				mlen = M_TRAILINGSPACE(mp);
82752196Smckusick 			}
82852196Smckusick 			xfer = (left > mlen) ? mlen : left;
82938420Smckusick #ifdef notdef
83038420Smckusick 			/* Not Yet.. */
83138420Smckusick 			if (uiop->uio_iov->iov_op != NULL)
83238420Smckusick 				(*(uiop->uio_iov->iov_op))
83352196Smckusick 				(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
83438420Smckusick 			else
83538420Smckusick #endif
83638420Smckusick 			if (uiop->uio_segflg == UIO_SYSSPACE)
83752196Smckusick 				bcopy(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
83838420Smckusick 			else
83952196Smckusick 				copyin(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
84052196Smckusick 			mp->m_len += xfer;
84138420Smckusick 			left -= xfer;
84238420Smckusick 			uiocp += xfer;
84339585Smckusick 			uiop->uio_offset += xfer;
84438420Smckusick 			uiop->uio_resid -= xfer;
84538420Smckusick 		}
84638420Smckusick 		if (uiop->uio_iov->iov_len <= siz) {
84738420Smckusick 			uiop->uio_iovcnt--;
84838420Smckusick 			uiop->uio_iov++;
84938420Smckusick 		} else {
85038420Smckusick 			uiop->uio_iov->iov_base += uiosiz;
85138420Smckusick 			uiop->uio_iov->iov_len -= uiosiz;
85238420Smckusick 		}
85338420Smckusick 		siz -= uiosiz;
85438420Smckusick 	}
85538420Smckusick 	if (rem > 0) {
85652196Smckusick 		if (rem > M_TRAILINGSPACE(mp)) {
85738420Smckusick 			MGET(mp, M_WAIT, MT_DATA);
85838420Smckusick 			mp->m_len = 0;
85938420Smckusick 			mp2->m_next = mp;
86038420Smckusick 		}
86138420Smckusick 		cp = mtod(mp, caddr_t)+mp->m_len;
86238420Smckusick 		for (left = 0; left < rem; left++)
86338420Smckusick 			*cp++ = '\0';
86438420Smckusick 		mp->m_len += rem;
86538420Smckusick 		*bpos = cp;
86638420Smckusick 	} else
86738420Smckusick 		*bpos = mtod(mp, caddr_t)+mp->m_len;
86838420Smckusick 	*mq = mp;
86941902Smckusick 	return (0);
87038420Smckusick }
87138420Smckusick 
87238420Smckusick /*
87338420Smckusick  * Help break down an mbuf chain by setting the first siz bytes contiguous
87438420Smckusick  * pointed to by returned val.
87552196Smckusick  * This is used by the macros nfsm_dissect and nfsm_dissecton for tough
87638420Smckusick  * cases. (The macros use the vars. dpos and dpos2)
87738420Smckusick  */
878*68653Smckusick int
87963482Smckusick nfsm_disct(mdp, dposp, siz, left, cp2)
88038420Smckusick 	struct mbuf **mdp;
88138420Smckusick 	caddr_t *dposp;
88238420Smckusick 	int siz;
88338420Smckusick 	int left;
88438420Smckusick 	caddr_t *cp2;
88538420Smckusick {
88638420Smckusick 	register struct mbuf *mp, *mp2;
88738420Smckusick 	register int siz2, xfer;
88852196Smckusick 	register caddr_t p;
88938420Smckusick 
89038420Smckusick 	mp = *mdp;
89138420Smckusick 	while (left == 0) {
89238420Smckusick 		*mdp = mp = mp->m_next;
89338420Smckusick 		if (mp == NULL)
89441902Smckusick 			return (EBADRPC);
89538420Smckusick 		left = mp->m_len;
89638420Smckusick 		*dposp = mtod(mp, caddr_t);
89738420Smckusick 	}
89838420Smckusick 	if (left >= siz) {
89938420Smckusick 		*cp2 = *dposp;
90038420Smckusick 		*dposp += siz;
90138420Smckusick 	} else if (mp->m_next == NULL) {
90241902Smckusick 		return (EBADRPC);
90341902Smckusick 	} else if (siz > MHLEN) {
90438420Smckusick 		panic("nfs S too big");
90538420Smckusick 	} else {
90663482Smckusick 		MGET(mp2, M_WAIT, MT_DATA);
90763482Smckusick 		mp2->m_next = mp->m_next;
90863482Smckusick 		mp->m_next = mp2;
90963482Smckusick 		mp->m_len -= left;
91063482Smckusick 		mp = mp2;
91152196Smckusick 		*cp2 = p = mtod(mp, caddr_t);
91252196Smckusick 		bcopy(*dposp, p, left);		/* Copy what was left */
91338420Smckusick 		siz2 = siz-left;
91452196Smckusick 		p += left;
91538420Smckusick 		mp2 = mp->m_next;
91641902Smckusick 		/* Loop around copying up the siz2 bytes */
91738420Smckusick 		while (siz2 > 0) {
91838420Smckusick 			if (mp2 == NULL)
91938420Smckusick 				return (EBADRPC);
92038420Smckusick 			xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2;
92141902Smckusick 			if (xfer > 0) {
92252196Smckusick 				bcopy(mtod(mp2, caddr_t), p, xfer);
92341902Smckusick 				NFSMADV(mp2, xfer);
92441902Smckusick 				mp2->m_len -= xfer;
92552196Smckusick 				p += xfer;
92641902Smckusick 				siz2 -= xfer;
92741902Smckusick 			}
92838420Smckusick 			if (siz2 > 0)
92938420Smckusick 				mp2 = mp2->m_next;
93038420Smckusick 		}
93138420Smckusick 		mp->m_len = siz;
93238420Smckusick 		*mdp = mp2;
93338420Smckusick 		*dposp = mtod(mp2, caddr_t);
93438420Smckusick 	}
93539494Smckusick 	return (0);
93638420Smckusick }
93738420Smckusick 
93838420Smckusick /*
93941902Smckusick  * Advance the position in the mbuf chain.
94038420Smckusick  */
941*68653Smckusick int
94238420Smckusick nfs_adv(mdp, dposp, offs, left)
94338420Smckusick 	struct mbuf **mdp;
94438420Smckusick 	caddr_t *dposp;
94538420Smckusick 	int offs;
94638420Smckusick 	int left;
94738420Smckusick {
94838420Smckusick 	register struct mbuf *m;
94938420Smckusick 	register int s;
95038420Smckusick 
95138420Smckusick 	m = *mdp;
95238420Smckusick 	s = left;
95338420Smckusick 	while (s < offs) {
95438420Smckusick 		offs -= s;
95538420Smckusick 		m = m->m_next;
95638420Smckusick 		if (m == NULL)
95741902Smckusick 			return (EBADRPC);
95838420Smckusick 		s = m->m_len;
95938420Smckusick 	}
96038420Smckusick 	*mdp = m;
96138420Smckusick 	*dposp = mtod(m, caddr_t)+offs;
96241902Smckusick 	return (0);
96338420Smckusick }
96438420Smckusick 
96538420Smckusick /*
96638420Smckusick  * Copy a string into mbufs for the hard cases...
96738420Smckusick  */
968*68653Smckusick int
96938420Smckusick nfsm_strtmbuf(mb, bpos, cp, siz)
97038420Smckusick 	struct mbuf **mb;
97138420Smckusick 	char **bpos;
97238420Smckusick 	char *cp;
97338420Smckusick 	long siz;
97438420Smckusick {
975*68653Smckusick 	register struct mbuf *m1 = 0, *m2;
97638420Smckusick 	long left, xfer, len, tlen;
97748049Smckusick 	u_long *tl;
97838420Smckusick 	int putsize;
97938420Smckusick 
98038420Smckusick 	putsize = 1;
98138420Smckusick 	m2 = *mb;
98252196Smckusick 	left = M_TRAILINGSPACE(m2);
98338420Smckusick 	if (left > 0) {
98448049Smckusick 		tl = ((u_long *)(*bpos));
98548049Smckusick 		*tl++ = txdr_unsigned(siz);
98638420Smckusick 		putsize = 0;
98738420Smckusick 		left -= NFSX_UNSIGNED;
98838420Smckusick 		m2->m_len += NFSX_UNSIGNED;
98938420Smckusick 		if (left > 0) {
99048049Smckusick 			bcopy(cp, (caddr_t) tl, left);
99138420Smckusick 			siz -= left;
99238420Smckusick 			cp += left;
99338420Smckusick 			m2->m_len += left;
99438420Smckusick 			left = 0;
99538420Smckusick 		}
99638420Smckusick 	}
99752196Smckusick 	/* Loop around adding mbufs */
99838420Smckusick 	while (siz > 0) {
99938420Smckusick 		MGET(m1, M_WAIT, MT_DATA);
100038420Smckusick 		if (siz > MLEN)
100141902Smckusick 			MCLGET(m1, M_WAIT);
100238420Smckusick 		m1->m_len = NFSMSIZ(m1);
100338420Smckusick 		m2->m_next = m1;
100438420Smckusick 		m2 = m1;
100548049Smckusick 		tl = mtod(m1, u_long *);
100638420Smckusick 		tlen = 0;
100738420Smckusick 		if (putsize) {
100848049Smckusick 			*tl++ = txdr_unsigned(siz);
100938420Smckusick 			m1->m_len -= NFSX_UNSIGNED;
101038420Smckusick 			tlen = NFSX_UNSIGNED;
101138420Smckusick 			putsize = 0;
101238420Smckusick 		}
101338420Smckusick 		if (siz < m1->m_len) {
101438420Smckusick 			len = nfsm_rndup(siz);
101538420Smckusick 			xfer = siz;
101638420Smckusick 			if (xfer < len)
101748049Smckusick 				*(tl+(xfer>>2)) = 0;
101838420Smckusick 		} else {
101938420Smckusick 			xfer = len = m1->m_len;
102038420Smckusick 		}
102148049Smckusick 		bcopy(cp, (caddr_t) tl, xfer);
102238420Smckusick 		m1->m_len = len+tlen;
102338420Smckusick 		siz -= xfer;
102438420Smckusick 		cp += xfer;
102538420Smckusick 	}
102638420Smckusick 	*mb = m1;
102738420Smckusick 	*bpos = mtod(m1, caddr_t)+m1->m_len;
102841902Smckusick 	return (0);
102938420Smckusick }
103038420Smckusick 
103138420Smckusick /*
103238420Smckusick  * Called once to initialize data structures...
103338420Smckusick  */
1034*68653Smckusick int
1035*68653Smckusick nfs_init(vfsp)
1036*68653Smckusick 	struct vfsconf *vfsp;
103738420Smckusick {
103838420Smckusick 	register int i;
103938420Smckusick 
1040*68653Smckusick 	/*
1041*68653Smckusick 	 * Check to see if major data structures haven't bloated.
1042*68653Smckusick 	 */
1043*68653Smckusick 	if (sizeof (struct nfsnode) > NFS_NODEALLOC) {
1044*68653Smckusick 		printf("struct nfsnode bloated (> %dbytes)\n", NFS_NODEALLOC);
1045*68653Smckusick 		printf("Try reducing NFS_SMALLFH\n");
1046*68653Smckusick 	}
1047*68653Smckusick 	if (sizeof (struct nfsmount) > NFS_MNTALLOC) {
1048*68653Smckusick 		printf("struct nfsmount bloated (> %dbytes)\n", NFS_MNTALLOC);
1049*68653Smckusick 		printf("Try reducing NFS_MUIDHASHSIZ\n");
1050*68653Smckusick 	}
1051*68653Smckusick 	if (sizeof (struct nfssvc_sock) > NFS_SVCALLOC) {
1052*68653Smckusick 		printf("struct nfssvc_sock bloated (> %dbytes)\n",NFS_SVCALLOC);
1053*68653Smckusick 		printf("Try reducing NFS_UIDHASHSIZ\n");
1054*68653Smckusick 	}
1055*68653Smckusick 	if (sizeof (struct nfsuid) > NFS_UIDALLOC) {
1056*68653Smckusick 		printf("struct nfsuid bloated (> %dbytes)\n",NFS_UIDALLOC);
1057*68653Smckusick 		printf("Try unionizing the nu_nickname and nu_flag fields\n");
1058*68653Smckusick 	}
1059*68653Smckusick 	nfs_mount_type = vfsp->vfc_typenum;
106052196Smckusick 	nfsrtt.pos = 0;
106138420Smckusick 	rpc_vers = txdr_unsigned(RPC_VER2);
106238420Smckusick 	rpc_call = txdr_unsigned(RPC_CALL);
106338420Smckusick 	rpc_reply = txdr_unsigned(RPC_REPLY);
106438420Smckusick 	rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED);
106538420Smckusick 	rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED);
106638420Smckusick 	rpc_mismatch = txdr_unsigned(RPC_MISMATCH);
106752196Smckusick 	rpc_autherr = txdr_unsigned(RPC_AUTHERR);
106838420Smckusick 	rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX);
1069*68653Smckusick 	rpc_auth_kerb = txdr_unsigned(RPCAUTH_KERB4);
107038420Smckusick 	nfs_prog = txdr_unsigned(NFS_PROG);
1071*68653Smckusick 	nqnfs_prog = txdr_unsigned(NQNFS_PROG);
107238420Smckusick 	nfs_true = txdr_unsigned(TRUE);
107338420Smckusick 	nfs_false = txdr_unsigned(FALSE);
1074*68653Smckusick 	nfs_xdrneg1 = txdr_unsigned(-1);
1075*68653Smckusick 	nfs_ticks = (hz * NFS_TICKINTVL + 500) / 1000;
1076*68653Smckusick 	if (nfs_ticks < 1)
1077*68653Smckusick 		nfs_ticks = 1;
107839345Smckusick 	/* Ensure async daemons disabled */
107941902Smckusick 	for (i = 0; i < NFS_MAXASYNCDAEMON; i++)
108039345Smckusick 		nfs_iodwant[i] = (struct proc *)0;
108165248Smckusick 	TAILQ_INIT(&nfs_bufq);
108238420Smckusick 	nfs_nhinit();			/* Init the nfsnode table */
108352979Smckusick 	nfsrv_init(0);			/* Init server data structures */
108439755Smckusick 	nfsrv_initcache();		/* Init the server request cache */
108541902Smckusick 
108641902Smckusick 	/*
108752196Smckusick 	 * Initialize the nqnfs server stuff.
108852196Smckusick 	 */
108952196Smckusick 	if (nqnfsstarttime == 0) {
109052196Smckusick 		nqnfsstarttime = boottime.tv_sec + nqsrv_maxlease
109152196Smckusick 			+ nqsrv_clockskew + nqsrv_writeslack;
109252196Smckusick 		NQLOADNOVRAM(nqnfsstarttime);
109367708Smckusick 		CIRCLEQ_INIT(&nqtimerhead);
109467708Smckusick 		nqfhhashtbl = hashinit(NQLCHSZ, M_NQLEASE, &nqfhhash);
109552196Smckusick 	}
109652196Smckusick 
109752196Smckusick 	/*
109841902Smckusick 	 * Initialize reply list and start timer
109941902Smckusick 	 */
110067708Smckusick 	TAILQ_INIT(&nfs_reqq);
1101*68653Smckusick 	nfs_timer(0);
1102*68653Smckusick 	return (0);
110338420Smckusick }
110438420Smckusick 
110538420Smckusick /*
110638420Smckusick  * Attribute cache routines.
110738420Smckusick  * nfs_loadattrcache() - loads or updates the cache contents from attributes
110838420Smckusick  *	that are on the mbuf list
110938420Smckusick  * nfs_getattrcache() - returns valid attributes if found in cache, returns
111038420Smckusick  *	error otherwise
111138420Smckusick  */
111238420Smckusick 
111338420Smckusick /*
111439444Smckusick  * Load the attribute cache (that lives in the nfsnode entry) with
111538420Smckusick  * the values on the mbuf list and
111638420Smckusick  * Iff vap not NULL
111738420Smckusick  *    copy the attributes to *vaper
111838420Smckusick  */
1119*68653Smckusick int
112039457Smckusick nfs_loadattrcache(vpp, mdp, dposp, vaper)
112139457Smckusick 	struct vnode **vpp;
112238420Smckusick 	struct mbuf **mdp;
112338420Smckusick 	caddr_t *dposp;
112438420Smckusick 	struct vattr *vaper;
112538420Smckusick {
112639457Smckusick 	register struct vnode *vp = *vpp;
112738420Smckusick 	register struct vattr *vap;
1128*68653Smckusick 	register struct nfs_fattr *fp;
112953553Sheideman 	extern int (**spec_nfsv2nodeop_p)();
113067708Smckusick 	register struct nfsnode *np;
113167708Smckusick 	register struct nfsnodehashhead *nhpp;
113239494Smckusick 	register long t1;
1133*68653Smckusick 	caddr_t cp2;
1134*68653Smckusick 	int error = 0, rdev;
113539494Smckusick 	struct mbuf *md;
113652196Smckusick 	enum vtype vtyp;
113752196Smckusick 	u_short vmode;
113856287Smckusick 	struct timespec mtime;
113939444Smckusick 	struct vnode *nvp;
1140*68653Smckusick 	quad_t tval;
1141*68653Smckusick 	int v3 = NFS_ISV3(vp);
114238420Smckusick 
114338420Smckusick 	md = *mdp;
1144*68653Smckusick 	t1 = (mtod(md, caddr_t) + md->m_len) - *dposp;
1145*68653Smckusick 	if (error = nfsm_disct(mdp, dposp, NFSX_FATTR(v3), t1, &cp2))
114638420Smckusick 		return (error);
1147*68653Smckusick 	fp = (struct nfs_fattr *)cp2;
1148*68653Smckusick 	if (v3) {
1149*68653Smckusick 		vtyp = nfsv3tov_type(fp->fa_type);
1150*68653Smckusick 		vmode = fxdr_unsigned(u_short, fp->fa_mode);
1151*68653Smckusick 		rdev = makedev(fxdr_unsigned(u_char, fp->fa3_rdev.specdata1),
1152*68653Smckusick 			fxdr_unsigned(u_char, fp->fa3_rdev.specdata2));
1153*68653Smckusick 		fxdr_nfsv3time(&fp->fa3_mtime, &mtime);
115456287Smckusick 	} else {
1155*68653Smckusick 		vtyp = nfsv2tov_type(fp->fa_type);
1156*68653Smckusick 		vmode = fxdr_unsigned(u_short, fp->fa_mode);
1157*68653Smckusick 		if (vtyp == VNON || vtyp == VREG)
1158*68653Smckusick 			vtyp = IFTOVT(vmode);
1159*68653Smckusick 		rdev = fxdr_unsigned(long, fp->fa2_rdev);
1160*68653Smckusick 		fxdr_nfsv2time(&fp->fa2_mtime, &mtime);
1161*68653Smckusick 
1162*68653Smckusick 		/*
1163*68653Smckusick 		 * Really ugly NFSv2 kludge.
1164*68653Smckusick 		 */
1165*68653Smckusick 		if (vtyp == VCHR && rdev == 0xffffffff)
1166*68653Smckusick 			vtyp = VFIFO;
116756287Smckusick 	}
1168*68653Smckusick 
116939444Smckusick 	/*
117039444Smckusick 	 * If v_type == VNON it is a new node, so fill in the v_type,
117139444Smckusick 	 * n_mtime fields. Check to see if it represents a special
117239444Smckusick 	 * device, and if so, check for a possible alias. Once the
117339444Smckusick 	 * correct vnode has been obtained, fill in the rest of the
117439444Smckusick 	 * information.
117539444Smckusick 	 */
117638420Smckusick 	np = VTONFS(vp);
117739444Smckusick 	if (vp->v_type == VNON) {
1178*68653Smckusick 		vp->v_type = vtyp;
117940295Smckusick 		if (vp->v_type == VFIFO) {
118053553Sheideman 			extern int (**fifo_nfsv2nodeop_p)();
118153553Sheideman 			vp->v_op = fifo_nfsv2nodeop_p;
118240295Smckusick 		}
118339444Smckusick 		if (vp->v_type == VCHR || vp->v_type == VBLK) {
118453553Sheideman 			vp->v_op = spec_nfsv2nodeop_p;
1185*68653Smckusick 			nvp = checkalias(vp, (dev_t)rdev, vp->v_mount);
1186*68653Smckusick 			if (nvp) {
118739444Smckusick 				/*
118851984Smckusick 				 * Discard unneeded vnode, but save its nfsnode.
118951984Smckusick 				 */
119067708Smckusick 				LIST_REMOVE(np, n_hash);
119151984Smckusick 				nvp->v_data = vp->v_data;
119251984Smckusick 				vp->v_data = NULL;
119353553Sheideman 				vp->v_op = spec_vnodeop_p;
119451984Smckusick 				vrele(vp);
119551984Smckusick 				vgone(vp);
119651984Smckusick 				/*
119739444Smckusick 				 * Reinitialize aliased node.
119839444Smckusick 				 */
119939444Smckusick 				np->n_vnode = nvp;
1200*68653Smckusick 				nhpp = NFSNOHASH(nfs_hash(np->n_fhp, np->n_fhsize));
120167708Smckusick 				LIST_INSERT_HEAD(nhpp, np, n_hash);
120251984Smckusick 				*vpp = vp = nvp;
120339444Smckusick 			}
120439444Smckusick 		}
120556287Smckusick 		np->n_mtime = mtime.ts_sec;
120639444Smckusick 	}
120738420Smckusick 	vap = &np->n_vattr;
120852196Smckusick 	vap->va_type = vtyp;
120952196Smckusick 	vap->va_mode = (vmode & 07777);
121056287Smckusick 	vap->va_rdev = (dev_t)rdev;
121156287Smckusick 	vap->va_mtime = mtime;
121256287Smckusick 	vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0];
1213*68653Smckusick 	if (v3) {
1214*68653Smckusick 		vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink);
1215*68653Smckusick 		vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid);
1216*68653Smckusick 		vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid);
1217*68653Smckusick 		fxdr_hyper(&fp->fa3_size, &vap->va_size);
1218*68653Smckusick 		vap->va_blocksize = NFS_FABLKSIZE;
1219*68653Smckusick 		fxdr_hyper(&fp->fa3_used, &vap->va_bytes);
1220*68653Smckusick 		vap->va_fileid = fxdr_unsigned(int, fp->fa3_fileid.nfsuquad[1]);
1221*68653Smckusick 		fxdr_nfsv3time(&fp->fa3_atime, &vap->va_atime);
1222*68653Smckusick 		fxdr_nfsv3time(&fp->fa3_ctime, &vap->va_ctime);
1223*68653Smckusick 		vap->va_flags = 0;
1224*68653Smckusick 		vap->va_filerev = 0;
122556287Smckusick 	} else {
1226*68653Smckusick 		vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink);
1227*68653Smckusick 		vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid);
1228*68653Smckusick 		vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid);
1229*68653Smckusick 		vap->va_size = fxdr_unsigned(u_long, fp->fa2_size);
1230*68653Smckusick 		vap->va_blocksize = fxdr_unsigned(long, fp->fa2_blocksize);
1231*68653Smckusick 		vap->va_bytes = fxdr_unsigned(long, fp->fa2_blocks) * NFS_FABLKSIZE;
1232*68653Smckusick 		vap->va_fileid = fxdr_unsigned(long, fp->fa2_fileid);
1233*68653Smckusick 		fxdr_nfsv2time(&fp->fa2_atime, &vap->va_atime);
123458881Smckusick 		vap->va_flags = 0;
1235*68653Smckusick 		vap->va_ctime.ts_sec = fxdr_unsigned(long, fp->fa2_ctime.nfsv2_sec);
123656287Smckusick 		vap->va_ctime.ts_nsec = 0;
1237*68653Smckusick 		vap->va_gen = fxdr_unsigned(u_long, fp->fa2_ctime.nfsv2_usec);
123856287Smckusick 		vap->va_filerev = 0;
123956287Smckusick 	}
124057787Smckusick 	if (vap->va_size != np->n_size) {
124157787Smckusick 		if (vap->va_type == VREG) {
124257787Smckusick 			if (np->n_flag & NMODIFIED) {
124357787Smckusick 				if (vap->va_size < np->n_size)
124457787Smckusick 					vap->va_size = np->n_size;
124557787Smckusick 				else
124657787Smckusick 					np->n_size = vap->va_size;
124757787Smckusick 			} else
124857787Smckusick 				np->n_size = vap->va_size;
124957787Smckusick 			vnode_pager_setsize(vp, (u_long)np->n_size);
125057787Smckusick 		} else
125157787Smckusick 			np->n_size = vap->va_size;
125245716Smckusick 	}
125338420Smckusick 	np->n_attrstamp = time.tv_sec;
125438884Smacklem 	if (vaper != NULL) {
125538420Smckusick 		bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(*vap));
125653628Smckusick 		if (np->n_flag & NCHG) {
1257*68653Smckusick 			if (np->n_flag & NACC)
1258*68653Smckusick 				vaper->va_atime = np->n_atim;
1259*68653Smckusick 			if (np->n_flag & NUPD)
1260*68653Smckusick 				vaper->va_mtime = np->n_mtim;
126153628Smckusick 		}
126238884Smacklem 	}
126338420Smckusick 	return (0);
126438420Smckusick }
126538420Smckusick 
126638420Smckusick /*
126738420Smckusick  * Check the time stamp
126838420Smckusick  * If the cache is valid, copy contents to *vap and return 0
126938420Smckusick  * otherwise return an error
127038420Smckusick  */
1271*68653Smckusick int
127257787Smckusick nfs_getattrcache(vp, vaper)
127338420Smckusick 	register struct vnode *vp;
127457787Smckusick 	struct vattr *vaper;
127538420Smckusick {
127657787Smckusick 	register struct nfsnode *np = VTONFS(vp);
127757787Smckusick 	register struct vattr *vap;
127838420Smckusick 
1279*68653Smckusick 	if ((time.tv_sec - np->n_attrstamp) >= NFS_ATTRTIMEO(np)) {
128038420Smckusick 		nfsstats.attrcache_misses++;
128138420Smckusick 		return (ENOENT);
128238420Smckusick 	}
128352196Smckusick 	nfsstats.attrcache_hits++;
128457787Smckusick 	vap = &np->n_vattr;
128557787Smckusick 	if (vap->va_size != np->n_size) {
128657787Smckusick 		if (vap->va_type == VREG) {
128757787Smckusick 			if (np->n_flag & NMODIFIED) {
128857787Smckusick 				if (vap->va_size < np->n_size)
128957787Smckusick 					vap->va_size = np->n_size;
129057787Smckusick 				else
129157787Smckusick 					np->n_size = vap->va_size;
129257787Smckusick 			} else
129357787Smckusick 				np->n_size = vap->va_size;
129457787Smckusick 			vnode_pager_setsize(vp, (u_long)np->n_size);
129557787Smckusick 		} else
129657787Smckusick 			np->n_size = vap->va_size;
129757787Smckusick 	}
129857787Smckusick 	bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(struct vattr));
129953628Smckusick 	if (np->n_flag & NCHG) {
1300*68653Smckusick 		if (np->n_flag & NACC)
1301*68653Smckusick 			vaper->va_atime = np->n_atim;
1302*68653Smckusick 		if (np->n_flag & NUPD)
1303*68653Smckusick 			vaper->va_mtime = np->n_mtim;
130453628Smckusick 	}
130552196Smckusick 	return (0);
130638420Smckusick }
130738420Smckusick 
130838420Smckusick /*
130952196Smckusick  * Set up nameidata for a lookup() call and do it
131038420Smckusick  */
1311*68653Smckusick int
1312*68653Smckusick nfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, retdirp, p, kerbflag)
131338420Smckusick 	register struct nameidata *ndp;
131438420Smckusick 	fhandle_t *fhp;
131538420Smckusick 	int len;
131652196Smckusick 	struct nfssvc_sock *slp;
131752196Smckusick 	struct mbuf *nam;
131838420Smckusick 	struct mbuf **mdp;
131938420Smckusick 	caddr_t *dposp;
1320*68653Smckusick 	struct vnode **retdirp;
132149739Smckusick 	struct proc *p;
1322*68653Smckusick 	int kerbflag;
132338420Smckusick {
132438420Smckusick 	register int i, rem;
132538420Smckusick 	register struct mbuf *md;
132649739Smckusick 	register char *fromcp, *tocp;
132746514Smckusick 	struct vnode *dp;
132852315Sheideman 	int error, rdonly;
132952315Sheideman 	struct componentname *cnp = &ndp->ni_cnd;
133038420Smckusick 
1331*68653Smckusick 	*retdirp = (struct vnode *)0;
133252315Sheideman 	MALLOC(cnp->cn_pnbuf, char *, len + 1, M_NAMEI, M_WAITOK);
133349739Smckusick 	/*
133449739Smckusick 	 * Copy the name from the mbuf list to ndp->ni_pnbuf
133549739Smckusick 	 * and set the various ndp fields appropriately.
133649739Smckusick 	 */
133749739Smckusick 	fromcp = *dposp;
133852315Sheideman 	tocp = cnp->cn_pnbuf;
133949739Smckusick 	md = *mdp;
134049739Smckusick 	rem = mtod(md, caddr_t) + md->m_len - fromcp;
134152315Sheideman 	cnp->cn_hash = 0;
134249739Smckusick 	for (i = 0; i < len; i++) {
134349739Smckusick 		while (rem == 0) {
134449739Smckusick 			md = md->m_next;
134549739Smckusick 			if (md == NULL) {
134649739Smckusick 				error = EBADRPC;
134749739Smckusick 				goto out;
134842244Smckusick 			}
134949739Smckusick 			fromcp = mtod(md, caddr_t);
135049739Smckusick 			rem = md->m_len;
135138420Smckusick 		}
135249739Smckusick 		if (*fromcp == '\0' || *fromcp == '/') {
1353*68653Smckusick 			error = EACCES;
135449739Smckusick 			goto out;
135542244Smckusick 		}
135652315Sheideman 		cnp->cn_hash += (unsigned char)*fromcp;
135749739Smckusick 		*tocp++ = *fromcp++;
135849739Smckusick 		rem--;
135949739Smckusick 	}
136049739Smckusick 	*tocp = '\0';
136149739Smckusick 	*mdp = md;
136249739Smckusick 	*dposp = fromcp;
136349739Smckusick 	len = nfsm_rndup(len)-len;
136449739Smckusick 	if (len > 0) {
136549739Smckusick 		if (rem >= len)
136649739Smckusick 			*dposp += len;
136749739Smckusick 		else if (error = nfs_adv(mdp, dposp, len, rem))
136849739Smckusick 			goto out;
136949739Smckusick 	}
137052315Sheideman 	ndp->ni_pathlen = tocp - cnp->cn_pnbuf;
137152315Sheideman 	cnp->cn_nameptr = cnp->cn_pnbuf;
137246514Smckusick 	/*
137346514Smckusick 	 * Extract and set starting directory.
137446514Smckusick 	 */
137552315Sheideman 	if (error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cnd.cn_cred, slp,
1376*68653Smckusick 	    nam, &rdonly, kerbflag))
137749739Smckusick 		goto out;
137838425Smckusick 	if (dp->v_type != VDIR) {
137941902Smckusick 		vrele(dp);
138049739Smckusick 		error = ENOTDIR;
138149739Smckusick 		goto out;
138238425Smckusick 	}
1383*68653Smckusick 	VREF(dp);
1384*68653Smckusick 	*retdirp = dp;
138546514Smckusick 	ndp->ni_startdir = dp;
138652196Smckusick 	if (rdonly)
138752315Sheideman 		cnp->cn_flags |= (NOCROSSMOUNT | RDONLY);
138852196Smckusick 	else
138952315Sheideman 		cnp->cn_flags |= NOCROSSMOUNT;
139039345Smckusick 	/*
139149739Smckusick 	 * And call lookup() to do the real work
139238420Smckusick 	 */
139352315Sheideman 	cnp->cn_proc = p;
139452315Sheideman 	if (error = lookup(ndp))
139549739Smckusick 		goto out;
139649739Smckusick 	/*
139749739Smckusick 	 * Check for encountering a symbolic link
139849739Smckusick 	 */
139952315Sheideman 	if (cnp->cn_flags & ISSYMLINK) {
140052315Sheideman 		if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1)
140149739Smckusick 			vput(ndp->ni_dvp);
140249739Smckusick 		else
140349739Smckusick 			vrele(ndp->ni_dvp);
140449739Smckusick 		vput(ndp->ni_vp);
140549739Smckusick 		ndp->ni_vp = NULL;
140649739Smckusick 		error = EINVAL;
140749739Smckusick 		goto out;
140849739Smckusick 	}
140949739Smckusick 	/*
141049739Smckusick 	 * Check for saved name request
141149739Smckusick 	 */
141252315Sheideman 	if (cnp->cn_flags & (SAVENAME | SAVESTART)) {
141352315Sheideman 		cnp->cn_flags |= HASBUF;
141449739Smckusick 		return (0);
141549739Smckusick 	}
141649739Smckusick out:
141752315Sheideman 	FREE(cnp->cn_pnbuf, M_NAMEI);
141838420Smckusick 	return (error);
141938420Smckusick }
142038420Smckusick 
142138420Smckusick /*
142238420Smckusick  * A fiddled version of m_adj() that ensures null fill to a long
142338420Smckusick  * boundary and only trims off the back end
142438420Smckusick  */
142552196Smckusick void
142638420Smckusick nfsm_adj(mp, len, nul)
142738420Smckusick 	struct mbuf *mp;
142838420Smckusick 	register int len;
142938420Smckusick 	int nul;
143038420Smckusick {
143138420Smckusick 	register struct mbuf *m;
143238420Smckusick 	register int count, i;
143338420Smckusick 	register char *cp;
143438420Smckusick 
143538420Smckusick 	/*
143638420Smckusick 	 * Trim from tail.  Scan the mbuf chain,
143738420Smckusick 	 * calculating its length and finding the last mbuf.
143838420Smckusick 	 * If the adjustment only affects this mbuf, then just
143938420Smckusick 	 * adjust and return.  Otherwise, rescan and truncate
144038420Smckusick 	 * after the remaining size.
144138420Smckusick 	 */
144238420Smckusick 	count = 0;
144338420Smckusick 	m = mp;
144438420Smckusick 	for (;;) {
144538420Smckusick 		count += m->m_len;
144638420Smckusick 		if (m->m_next == (struct mbuf *)0)
144738420Smckusick 			break;
144838420Smckusick 		m = m->m_next;
144938420Smckusick 	}
145038579Smckusick 	if (m->m_len > len) {
145138420Smckusick 		m->m_len -= len;
145238420Smckusick 		if (nul > 0) {
145338420Smckusick 			cp = mtod(m, caddr_t)+m->m_len-nul;
145438420Smckusick 			for (i = 0; i < nul; i++)
145538420Smckusick 				*cp++ = '\0';
145638420Smckusick 		}
145738420Smckusick 		return;
145838420Smckusick 	}
145938420Smckusick 	count -= len;
146038420Smckusick 	if (count < 0)
146138420Smckusick 		count = 0;
146238420Smckusick 	/*
146338420Smckusick 	 * Correct length for chain is "count".
146438420Smckusick 	 * Find the mbuf with last data, adjust its length,
146538420Smckusick 	 * and toss data from remaining mbufs on chain.
146638420Smckusick 	 */
146738420Smckusick 	for (m = mp; m; m = m->m_next) {
146838420Smckusick 		if (m->m_len >= count) {
146938420Smckusick 			m->m_len = count;
147038420Smckusick 			if (nul > 0) {
147138420Smckusick 				cp = mtod(m, caddr_t)+m->m_len-nul;
147238420Smckusick 				for (i = 0; i < nul; i++)
147338420Smckusick 					*cp++ = '\0';
147438420Smckusick 			}
147538420Smckusick 			break;
147638420Smckusick 		}
147738420Smckusick 		count -= m->m_len;
147838420Smckusick 	}
1479*68653Smckusick 	for (m = m->m_next;m;m = m->m_next)
148038420Smckusick 		m->m_len = 0;
148138420Smckusick }
148238420Smckusick 
148338420Smckusick /*
1484*68653Smckusick  * Make these functions instead of macros, so that the kernel text size
1485*68653Smckusick  * doesn't get too big...
1486*68653Smckusick  */
1487*68653Smckusick void
1488*68653Smckusick nfsm_srvwcc(nfsd, before_ret, before_vap, after_ret, after_vap, mbp, bposp)
1489*68653Smckusick 	struct nfsrv_descript *nfsd;
1490*68653Smckusick 	int before_ret;
1491*68653Smckusick 	register struct vattr *before_vap;
1492*68653Smckusick 	int after_ret;
1493*68653Smckusick 	struct vattr *after_vap;
1494*68653Smckusick 	struct mbuf **mbp;
1495*68653Smckusick 	char **bposp;
1496*68653Smckusick {
1497*68653Smckusick 	register struct mbuf *mb = *mbp, *mb2;
1498*68653Smckusick 	register char *bpos = *bposp;
1499*68653Smckusick 	register u_long *tl;
1500*68653Smckusick 
1501*68653Smckusick 	if (before_ret) {
1502*68653Smckusick 		nfsm_build(tl, u_long *, NFSX_UNSIGNED);
1503*68653Smckusick 		*tl = nfs_false;
1504*68653Smckusick 	} else {
1505*68653Smckusick 		nfsm_build(tl, u_long *, 7 * NFSX_UNSIGNED);
1506*68653Smckusick 		*tl++ = nfs_true;
1507*68653Smckusick 		txdr_hyper(&(before_vap->va_size), tl);
1508*68653Smckusick 		tl += 2;
1509*68653Smckusick 		txdr_nfsv3time(&(before_vap->va_mtime), tl);
1510*68653Smckusick 		tl += 2;
1511*68653Smckusick 		txdr_nfsv3time(&(before_vap->va_ctime), tl);
1512*68653Smckusick 	}
1513*68653Smckusick 	*bposp = bpos;
1514*68653Smckusick 	*mbp = mb;
1515*68653Smckusick 	nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp);
1516*68653Smckusick }
1517*68653Smckusick 
1518*68653Smckusick void
1519*68653Smckusick nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp)
1520*68653Smckusick 	struct nfsrv_descript *nfsd;
1521*68653Smckusick 	int after_ret;
1522*68653Smckusick 	struct vattr *after_vap;
1523*68653Smckusick 	struct mbuf **mbp;
1524*68653Smckusick 	char **bposp;
1525*68653Smckusick {
1526*68653Smckusick 	register struct mbuf *mb = *mbp, *mb2;
1527*68653Smckusick 	register char *bpos = *bposp;
1528*68653Smckusick 	register u_long *tl;
1529*68653Smckusick 	register struct nfs_fattr *fp;
1530*68653Smckusick 
1531*68653Smckusick 	if (after_ret) {
1532*68653Smckusick 		nfsm_build(tl, u_long *, NFSX_UNSIGNED);
1533*68653Smckusick 		*tl = nfs_false;
1534*68653Smckusick 	} else {
1535*68653Smckusick 		nfsm_build(tl, u_long *, NFSX_UNSIGNED + NFSX_V3FATTR);
1536*68653Smckusick 		*tl++ = nfs_true;
1537*68653Smckusick 		fp = (struct nfs_fattr *)tl;
1538*68653Smckusick 		nfsm_srvfattr(nfsd, after_vap, fp);
1539*68653Smckusick 	}
1540*68653Smckusick 	*mbp = mb;
1541*68653Smckusick 	*bposp = bpos;
1542*68653Smckusick }
1543*68653Smckusick 
1544*68653Smckusick void
1545*68653Smckusick nfsm_srvfattr(nfsd, vap, fp)
1546*68653Smckusick 	register struct nfsrv_descript *nfsd;
1547*68653Smckusick 	register struct vattr *vap;
1548*68653Smckusick 	register struct nfs_fattr *fp;
1549*68653Smckusick {
1550*68653Smckusick 
1551*68653Smckusick 	fp->fa_nlink = txdr_unsigned(vap->va_nlink);
1552*68653Smckusick 	fp->fa_uid = txdr_unsigned(vap->va_uid);
1553*68653Smckusick 	fp->fa_gid = txdr_unsigned(vap->va_gid);
1554*68653Smckusick 	if (nfsd->nd_flag & ND_NFSV3) {
1555*68653Smckusick 		fp->fa_type = vtonfsv3_type(vap->va_type);
1556*68653Smckusick 		fp->fa_mode = vtonfsv3_mode(vap->va_mode);
1557*68653Smckusick 		txdr_hyper(&vap->va_size, &fp->fa3_size);
1558*68653Smckusick 		txdr_hyper(&vap->va_bytes, &fp->fa3_used);
1559*68653Smckusick 		fp->fa3_rdev.specdata1 = txdr_unsigned(major(vap->va_rdev));
1560*68653Smckusick 		fp->fa3_rdev.specdata2 = txdr_unsigned(minor(vap->va_rdev));
1561*68653Smckusick 		fp->fa3_fsid.nfsuquad[0] = 0;
1562*68653Smckusick 		fp->fa3_fsid.nfsuquad[1] = txdr_unsigned(vap->va_fsid);
1563*68653Smckusick 		fp->fa3_fileid.nfsuquad[0] = 0;
1564*68653Smckusick 		fp->fa3_fileid.nfsuquad[1] = txdr_unsigned(vap->va_fileid);
1565*68653Smckusick 		txdr_nfsv3time(&vap->va_atime, &fp->fa3_atime);
1566*68653Smckusick 		txdr_nfsv3time(&vap->va_mtime, &fp->fa3_mtime);
1567*68653Smckusick 		txdr_nfsv3time(&vap->va_ctime, &fp->fa3_ctime);
1568*68653Smckusick 	} else {
1569*68653Smckusick 		fp->fa_type = vtonfsv2_type(vap->va_type);
1570*68653Smckusick 		fp->fa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode);
1571*68653Smckusick 		fp->fa2_size = txdr_unsigned(vap->va_size);
1572*68653Smckusick 		fp->fa2_blocksize = txdr_unsigned(vap->va_blocksize);
1573*68653Smckusick 		if (vap->va_type == VFIFO)
1574*68653Smckusick 			fp->fa2_rdev = 0xffffffff;
1575*68653Smckusick 		else
1576*68653Smckusick 			fp->fa2_rdev = txdr_unsigned(vap->va_rdev);
1577*68653Smckusick 		fp->fa2_blocks = txdr_unsigned(vap->va_bytes / NFS_FABLKSIZE);
1578*68653Smckusick 		fp->fa2_fsid = txdr_unsigned(vap->va_fsid);
1579*68653Smckusick 		fp->fa2_fileid = txdr_unsigned(vap->va_fileid);
1580*68653Smckusick 		txdr_nfsv2time(&vap->va_atime, &fp->fa2_atime);
1581*68653Smckusick 		txdr_nfsv2time(&vap->va_mtime, &fp->fa2_mtime);
1582*68653Smckusick 		txdr_nfsv2time(&vap->va_ctime, &fp->fa2_ctime);
1583*68653Smckusick 	}
1584*68653Smckusick }
1585*68653Smckusick 
1586*68653Smckusick /*
158738420Smckusick  * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked)
158838420Smckusick  * 	- look up fsid in mount list (if not found ret error)
158954739Smckusick  *	- get vp and export rights by calling VFS_FHTOVP()
159054739Smckusick  *	- if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon
159138420Smckusick  *	- if not lockflag unlock it with VOP_UNLOCK()
159238420Smckusick  */
1593*68653Smckusick int
1594*68653Smckusick nfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp, kerbflag)
159538420Smckusick 	fhandle_t *fhp;
159638420Smckusick 	int lockflag;
159738420Smckusick 	struct vnode **vpp;
159838420Smckusick 	struct ucred *cred;
159952196Smckusick 	struct nfssvc_sock *slp;
160052196Smckusick 	struct mbuf *nam;
160152196Smckusick 	int *rdonlyp;
1602*68653Smckusick 	int kerbflag;
160338420Smckusick {
160438420Smckusick 	register struct mount *mp;
160552196Smckusick 	register struct nfsuid *uidp;
160657787Smckusick 	register int i;
160754739Smckusick 	struct ucred *credanon;
160854739Smckusick 	int error, exflags;
160938420Smckusick 
161052196Smckusick 	*vpp = (struct vnode *)0;
1611*68653Smckusick 	mp = vfs_getvfs(&fhp->fh_fsid);
1612*68653Smckusick 	if (!mp)
161338420Smckusick 		return (ESTALE);
1614*68653Smckusick 	error = VFS_FHTOVP(mp, &fhp->fh_fid, nam, vpp, &exflags, &credanon);
1615*68653Smckusick 	if (error)
161654739Smckusick 		return (error);
161752196Smckusick 	/*
161852196Smckusick 	 * Check/setup credentials.
161952196Smckusick 	 */
162054739Smckusick 	if (exflags & MNT_EXKERB) {
1621*68653Smckusick 		if (!kerbflag) {
162257787Smckusick 			vput(*vpp);
1623*68653Smckusick 			return (NFSERR_AUTHERR | AUTH_TOOWEAK);
162457787Smckusick 		}
1625*68653Smckusick 	} else if (kerbflag) {
1626*68653Smckusick 		vput(*vpp);
1627*68653Smckusick 		return (NFSERR_AUTHERR | AUTH_TOOWEAK);
162857787Smckusick 	} else if (cred->cr_uid == 0 || (exflags & MNT_EXPORTANON)) {
162957787Smckusick 		cred->cr_uid = credanon->cr_uid;
163057787Smckusick 		for (i = 0; i < credanon->cr_ngroups && i < NGROUPS; i++)
163157787Smckusick 			cred->cr_groups[i] = credanon->cr_groups[i];
163267567Smckusick 		cred->cr_ngroups = i;
163357787Smckusick 	}
163454739Smckusick 	if (exflags & MNT_EXRDONLY)
163552196Smckusick 		*rdonlyp = 1;
163645282Smckusick 	else
163752196Smckusick 		*rdonlyp = 0;
163852196Smckusick 	if (!lockflag)
163952196Smckusick 		VOP_UNLOCK(*vpp);
164052196Smckusick 	return (0);
164145282Smckusick }
164254988Smckusick 
164354988Smckusick /*
164454988Smckusick  * This function compares two net addresses by family and returns TRUE
164554988Smckusick  * if they are the same host.
164654988Smckusick  * If there is any doubt, return FALSE.
164754988Smckusick  * The AF_INET family is handled as a special case so that address mbufs
164854988Smckusick  * don't need to be saved to store "struct in_addr", which is only 4 bytes.
164954988Smckusick  */
1650*68653Smckusick int
165156363Smckusick netaddr_match(family, haddr, nam)
165254988Smckusick 	int family;
165354988Smckusick 	union nethostaddr *haddr;
165454988Smckusick 	struct mbuf *nam;
165554988Smckusick {
165654988Smckusick 	register struct sockaddr_in *inetaddr;
165754988Smckusick 
165854988Smckusick 	switch (family) {
165954988Smckusick 	case AF_INET:
166054988Smckusick 		inetaddr = mtod(nam, struct sockaddr_in *);
166156363Smckusick 		if (inetaddr->sin_family == AF_INET &&
166256363Smckusick 		    inetaddr->sin_addr.s_addr == haddr->had_inetaddr)
166354988Smckusick 			return (1);
166454988Smckusick 		break;
166554988Smckusick #ifdef ISO
166654988Smckusick 	case AF_ISO:
166756363Smckusick 	    {
166856363Smckusick 		register struct sockaddr_iso *isoaddr1, *isoaddr2;
166956363Smckusick 
167054988Smckusick 		isoaddr1 = mtod(nam, struct sockaddr_iso *);
167154988Smckusick 		isoaddr2 = mtod(haddr->had_nam, struct sockaddr_iso *);
167256363Smckusick 		if (isoaddr1->siso_family == AF_ISO &&
167356363Smckusick 		    isoaddr1->siso_nlen > 0 &&
167454988Smckusick 		    isoaddr1->siso_nlen == isoaddr2->siso_nlen &&
167554988Smckusick 		    SAME_ISOADDR(isoaddr1, isoaddr2))
167654988Smckusick 			return (1);
167754988Smckusick 		break;
167856363Smckusick 	    }
167954988Smckusick #endif	/* ISO */
168054988Smckusick 	default:
168154988Smckusick 		break;
168254988Smckusick 	};
168354988Smckusick 	return (0);
168454988Smckusick }
1685*68653Smckusick 
1686*68653Smckusick static nfsuint64 nfs_nullcookie = { 0, 0 };
1687*68653Smckusick /*
1688*68653Smckusick  * This function finds the directory cookie that corresponds to the
1689*68653Smckusick  * logical byte offset given.
1690*68653Smckusick  */
1691*68653Smckusick nfsuint64 *
1692*68653Smckusick nfs_getcookie(np, off, add)
1693*68653Smckusick 	register struct nfsnode *np;
1694*68653Smckusick 	off_t off;
1695*68653Smckusick 	int add;
1696*68653Smckusick {
1697*68653Smckusick 	register struct nfsdmap *dp, *dp2;
1698*68653Smckusick 	register int pos;
1699*68653Smckusick 
1700*68653Smckusick 	pos = off / NFS_DIRBLKSIZ;
1701*68653Smckusick 	if (pos == 0) {
1702*68653Smckusick #ifdef DIAGNOSTIC
1703*68653Smckusick 		if (add)
1704*68653Smckusick 			panic("nfs getcookie add at 0");
1705*68653Smckusick #endif
1706*68653Smckusick 		return (&nfs_nullcookie);
1707*68653Smckusick 	}
1708*68653Smckusick 	pos--;
1709*68653Smckusick 	dp = np->n_cookies.lh_first;
1710*68653Smckusick 	if (!dp) {
1711*68653Smckusick 		if (add) {
1712*68653Smckusick 			MALLOC(dp, struct nfsdmap *, sizeof (struct nfsdmap),
1713*68653Smckusick 				M_NFSDIROFF, M_WAITOK);
1714*68653Smckusick 			dp->ndm_eocookie = 0;
1715*68653Smckusick 			LIST_INSERT_HEAD(&np->n_cookies, dp, ndm_list);
1716*68653Smckusick 		} else
1717*68653Smckusick 			return ((nfsuint64 *)0);
1718*68653Smckusick 	}
1719*68653Smckusick 	while (pos >= NFSNUMCOOKIES) {
1720*68653Smckusick 		pos -= NFSNUMCOOKIES;
1721*68653Smckusick 		if (dp->ndm_list.le_next) {
1722*68653Smckusick 			if (!add && dp->ndm_eocookie < NFSNUMCOOKIES &&
1723*68653Smckusick 				pos >= dp->ndm_eocookie)
1724*68653Smckusick 				return ((nfsuint64 *)0);
1725*68653Smckusick 			dp = dp->ndm_list.le_next;
1726*68653Smckusick 		} else if (add) {
1727*68653Smckusick 			MALLOC(dp2, struct nfsdmap *, sizeof (struct nfsdmap),
1728*68653Smckusick 				M_NFSDIROFF, M_WAITOK);
1729*68653Smckusick 			dp2->ndm_eocookie = 0;
1730*68653Smckusick 			LIST_INSERT_AFTER(dp, dp2, ndm_list);
1731*68653Smckusick 			dp = dp2;
1732*68653Smckusick 		} else
1733*68653Smckusick 			return ((nfsuint64 *)0);
1734*68653Smckusick 	}
1735*68653Smckusick 	if (pos >= dp->ndm_eocookie) {
1736*68653Smckusick 		if (add)
1737*68653Smckusick 			dp->ndm_eocookie = pos + 1;
1738*68653Smckusick 		else
1739*68653Smckusick 			return ((nfsuint64 *)0);
1740*68653Smckusick 	}
1741*68653Smckusick 	return (&dp->ndm_cookies[pos]);
1742*68653Smckusick }
1743*68653Smckusick 
1744*68653Smckusick /*
1745*68653Smckusick  * Invalidate cached directory information, except for the actual directory
1746*68653Smckusick  * blocks (which are invalidated separately).
1747*68653Smckusick  * Done mainly to avoid the use of stale offset cookies.
1748*68653Smckusick  */
1749*68653Smckusick void
1750*68653Smckusick nfs_invaldir(vp)
1751*68653Smckusick 	register struct vnode *vp;
1752*68653Smckusick {
1753*68653Smckusick 	register struct nfsnode *np = VTONFS(vp);
1754*68653Smckusick 
1755*68653Smckusick #ifdef DIAGNOSTIC
1756*68653Smckusick 	if (vp->v_type != VDIR)
1757*68653Smckusick 		panic("nfs: invaldir not dir");
1758*68653Smckusick #endif
1759*68653Smckusick 	np->n_direofoffset = 0;
1760*68653Smckusick 	np->n_cookieverf.nfsuquad[0] = 0;
1761*68653Smckusick 	np->n_cookieverf.nfsuquad[1] = 0;
1762*68653Smckusick 	if (np->n_cookies.lh_first)
1763*68653Smckusick 		np->n_cookies.lh_first->ndm_eocookie = 0;
1764*68653Smckusick }
1765*68653Smckusick 
1766*68653Smckusick /*
1767*68653Smckusick  * The write verifier has changed (probably due to a server reboot), so all
1768*68653Smckusick  * B_NEEDCOMMIT blocks will have to be written again. Since they are on the
1769*68653Smckusick  * dirty block list as B_DELWRI, all this takes is clearing the B_NEEDCOMMIT
1770*68653Smckusick  * flag. Once done the new write verifier can be set for the mount point.
1771*68653Smckusick  */
1772*68653Smckusick void
1773*68653Smckusick nfs_clearcommit(mp)
1774*68653Smckusick 	struct mount *mp;
1775*68653Smckusick {
1776*68653Smckusick 	register struct vnode *vp, *nvp;
1777*68653Smckusick 	register struct buf *bp, *nbp;
1778*68653Smckusick 	int s;
1779*68653Smckusick 
1780*68653Smckusick 	s = splbio();
1781*68653Smckusick loop:
1782*68653Smckusick 	for (vp = mp->mnt_vnodelist.lh_first; vp; vp = nvp) {
1783*68653Smckusick 		if (vp->v_mount != mp)	/* Paranoia */
1784*68653Smckusick 			goto loop;
1785*68653Smckusick 		nvp = vp->v_mntvnodes.le_next;
1786*68653Smckusick 		for (bp = vp->v_dirtyblkhd.lh_first; bp; bp = nbp) {
1787*68653Smckusick 			nbp = bp->b_vnbufs.le_next;
1788*68653Smckusick 			if ((bp->b_flags & (B_BUSY | B_DELWRI | B_NEEDCOMMIT))
1789*68653Smckusick 				== (B_DELWRI | B_NEEDCOMMIT))
1790*68653Smckusick 				bp->b_flags &= ~B_NEEDCOMMIT;
1791*68653Smckusick 		}
1792*68653Smckusick 	}
1793*68653Smckusick 	splx(s);
1794*68653Smckusick }
1795*68653Smckusick 
1796*68653Smckusick /*
1797*68653Smckusick  * Map errnos to NFS error numbers. For Version 3 also filter out error
1798*68653Smckusick  * numbers not specified for the associated procedure.
1799*68653Smckusick  */
1800*68653Smckusick int
1801*68653Smckusick nfsrv_errmap(nd, err)
1802*68653Smckusick 	struct nfsrv_descript *nd;
1803*68653Smckusick 	register int err;
1804*68653Smckusick {
1805*68653Smckusick 	register short *defaulterrp, *errp;
1806*68653Smckusick 
1807*68653Smckusick 	if (nd->nd_flag & ND_NFSV3) {
1808*68653Smckusick 	    if (nd->nd_procnum <= NFSPROC_COMMIT) {
1809*68653Smckusick 		errp = defaulterrp = nfsrv_v3errmap[nd->nd_procnum];
1810*68653Smckusick 		while (*++errp) {
1811*68653Smckusick 			if (*errp == err)
1812*68653Smckusick 				return (err);
1813*68653Smckusick 			else if (*errp > err)
1814*68653Smckusick 				break;
1815*68653Smckusick 		}
1816*68653Smckusick 		return ((int)*defaulterrp);
1817*68653Smckusick 	    } else
1818*68653Smckusick 		return (err & 0xffff);
1819*68653Smckusick 	}
1820*68653Smckusick 	if (err <= ELAST)
1821*68653Smckusick 		return ((int)nfsrv_v2errmap[err - 1]);
1822*68653Smckusick 	return (NFSERR_IO);
1823*68653Smckusick }
1824