Deleted Added
full compact
nfs_subs.c (59391) nfs_subs.c (60041)
1/*
2 * Copyright (c) 1989, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Rick Macklem at The University of Guelph.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by the University of
19 * California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 *
36 * @(#)nfs_subs.c 8.8 (Berkeley) 5/22/95
1/*
2 * Copyright (c) 1989, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Rick Macklem at The University of Guelph.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by the University of
19 * California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 *
36 * @(#)nfs_subs.c 8.8 (Berkeley) 5/22/95
37 * $FreeBSD: head/sys/nfsclient/nfs_subs.c 59391 2000-04-19 14:58:28Z phk $
37 * $FreeBSD: head/sys/nfsclient/nfs_subs.c 60041 2000-05-05 09:59:14Z phk $
38 */
39
40/*
41 * These functions support the macros and help fiddle mbuf chains for
42 * the nfs op functions. They do things like create the rpc header and
43 * copy data between mbuf chains and uio lists.
44 */
45#include <sys/param.h>
46#include <sys/systm.h>
47#include <sys/kernel.h>
38 */
39
40/*
41 * These functions support the macros and help fiddle mbuf chains for
42 * the nfs op functions. They do things like create the rpc header and
43 * copy data between mbuf chains and uio lists.
44 */
45#include <sys/param.h>
46#include <sys/systm.h>
47#include <sys/kernel.h>
48#include <sys/bio.h>
48#include <sys/buf.h>
49#include <sys/proc.h>
50#include <sys/mount.h>
51#include <sys/vnode.h>
52#include <sys/namei.h>
53#include <sys/mbuf.h>
54#include <sys/socket.h>
55#include <sys/stat.h>
56#include <sys/malloc.h>
57#include <sys/sysent.h>
58#include <sys/syscall.h>
59
60#include <vm/vm.h>
61#include <vm/vm_object.h>
62#include <vm/vm_extern.h>
63#include <vm/vm_zone.h>
64
65#include <nfs/rpcv2.h>
66#include <nfs/nfsproto.h>
67#include <nfs/nfs.h>
68#include <nfs/nfsnode.h>
69#include <nfs/xdr_subs.h>
70#include <nfs/nfsm_subs.h>
71#include <nfs/nfsmount.h>
72#include <nfs/nqnfs.h>
73#include <nfs/nfsrtt.h>
74
75#include <netinet/in.h>
76
77/*
78 * Data items converted to xdr at startup, since they are constant
79 * This is kinda hokey, but may save a little time doing byte swaps
80 */
81u_int32_t nfs_xdrneg1;
82u_int32_t rpc_call, rpc_vers, rpc_reply, rpc_msgdenied, rpc_autherr,
83 rpc_mismatch, rpc_auth_unix, rpc_msgaccepted,
84 rpc_auth_kerb;
85u_int32_t nfs_prog, nqnfs_prog, nfs_true, nfs_false;
86
87/* And other global data */
88static u_int32_t nfs_xid = 0;
89static enum vtype nv2tov_type[8]= {
90 VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON, VNON
91};
92enum vtype nv3tov_type[8]= {
93 VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO
94};
95
96int nfs_ticks;
97int nfs_pbuf_freecnt = -1; /* start out unlimited */
98
99struct nfs_reqq nfs_reqq;
100struct nfssvc_sockhead nfssvc_sockhead;
101int nfssvc_sockhead_flag;
102struct nfsd_head nfsd_head;
103int nfsd_head_flag;
104struct nfs_bufq nfs_bufq;
105struct nqtimerhead nqtimerhead;
106struct nqfhhashhead *nqfhhashtbl;
107u_long nqfhhash;
108
109static void (*nfs_prev_lease_updatetime) __P((int));
110static int nfs_prev_nfssvc_sy_narg;
111static sy_call_t *nfs_prev_nfssvc_sy_call;
112
113#ifndef NFS_NOSERVER
114
115static vop_t *nfs_prev_vop_lease_check;
116
117/*
118 * Mapping of old NFS Version 2 RPC numbers to generic numbers.
119 */
120int nfsv3_procid[NFS_NPROCS] = {
121 NFSPROC_NULL,
122 NFSPROC_GETATTR,
123 NFSPROC_SETATTR,
124 NFSPROC_NOOP,
125 NFSPROC_LOOKUP,
126 NFSPROC_READLINK,
127 NFSPROC_READ,
128 NFSPROC_NOOP,
129 NFSPROC_WRITE,
130 NFSPROC_CREATE,
131 NFSPROC_REMOVE,
132 NFSPROC_RENAME,
133 NFSPROC_LINK,
134 NFSPROC_SYMLINK,
135 NFSPROC_MKDIR,
136 NFSPROC_RMDIR,
137 NFSPROC_READDIR,
138 NFSPROC_FSSTAT,
139 NFSPROC_NOOP,
140 NFSPROC_NOOP,
141 NFSPROC_NOOP,
142 NFSPROC_NOOP,
143 NFSPROC_NOOP,
144 NFSPROC_NOOP,
145 NFSPROC_NOOP,
146 NFSPROC_NOOP
147};
148
149#endif /* NFS_NOSERVER */
150/*
151 * and the reverse mapping from generic to Version 2 procedure numbers
152 */
153int nfsv2_procid[NFS_NPROCS] = {
154 NFSV2PROC_NULL,
155 NFSV2PROC_GETATTR,
156 NFSV2PROC_SETATTR,
157 NFSV2PROC_LOOKUP,
158 NFSV2PROC_NOOP,
159 NFSV2PROC_READLINK,
160 NFSV2PROC_READ,
161 NFSV2PROC_WRITE,
162 NFSV2PROC_CREATE,
163 NFSV2PROC_MKDIR,
164 NFSV2PROC_SYMLINK,
165 NFSV2PROC_CREATE,
166 NFSV2PROC_REMOVE,
167 NFSV2PROC_RMDIR,
168 NFSV2PROC_RENAME,
169 NFSV2PROC_LINK,
170 NFSV2PROC_READDIR,
171 NFSV2PROC_NOOP,
172 NFSV2PROC_STATFS,
173 NFSV2PROC_NOOP,
174 NFSV2PROC_NOOP,
175 NFSV2PROC_NOOP,
176 NFSV2PROC_NOOP,
177 NFSV2PROC_NOOP,
178 NFSV2PROC_NOOP,
179 NFSV2PROC_NOOP,
180};
181
182#ifndef NFS_NOSERVER
183/*
184 * Maps errno values to nfs error numbers.
185 * Use NFSERR_IO as the catch all for ones not specifically defined in
186 * RFC 1094.
187 */
188static u_char nfsrv_v2errmap[ELAST] = {
189 NFSERR_PERM, NFSERR_NOENT, NFSERR_IO, NFSERR_IO, NFSERR_IO,
190 NFSERR_NXIO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
191 NFSERR_IO, NFSERR_IO, NFSERR_ACCES, NFSERR_IO, NFSERR_IO,
192 NFSERR_IO, NFSERR_EXIST, NFSERR_IO, NFSERR_NODEV, NFSERR_NOTDIR,
193 NFSERR_ISDIR, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
194 NFSERR_IO, NFSERR_FBIG, NFSERR_NOSPC, NFSERR_IO, NFSERR_ROFS,
195 NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
196 NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
197 NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
198 NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
199 NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
200 NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
201 NFSERR_IO, NFSERR_IO, NFSERR_NAMETOL, NFSERR_IO, NFSERR_IO,
202 NFSERR_NOTEMPTY, NFSERR_IO, NFSERR_IO, NFSERR_DQUOT, NFSERR_STALE,
203 NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
204 NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
205 NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
206 NFSERR_IO /* << Last is 86 */
207};
208
209/*
210 * Maps errno values to nfs error numbers.
211 * Although it is not obvious whether or not NFS clients really care if
212 * a returned error value is in the specified list for the procedure, the
213 * safest thing to do is filter them appropriately. For Version 2, the
214 * X/Open XNFS document is the only specification that defines error values
215 * for each RPC (The RFC simply lists all possible error values for all RPCs),
216 * so I have decided to not do this for Version 2.
217 * The first entry is the default error return and the rest are the valid
218 * errors for that RPC in increasing numeric order.
219 */
220static short nfsv3err_null[] = {
221 0,
222 0,
223};
224
225static short nfsv3err_getattr[] = {
226 NFSERR_IO,
227 NFSERR_IO,
228 NFSERR_STALE,
229 NFSERR_BADHANDLE,
230 NFSERR_SERVERFAULT,
231 0,
232};
233
234static short nfsv3err_setattr[] = {
235 NFSERR_IO,
236 NFSERR_PERM,
237 NFSERR_IO,
238 NFSERR_ACCES,
239 NFSERR_INVAL,
240 NFSERR_NOSPC,
241 NFSERR_ROFS,
242 NFSERR_DQUOT,
243 NFSERR_STALE,
244 NFSERR_BADHANDLE,
245 NFSERR_NOT_SYNC,
246 NFSERR_SERVERFAULT,
247 0,
248};
249
250static short nfsv3err_lookup[] = {
251 NFSERR_IO,
252 NFSERR_NOENT,
253 NFSERR_IO,
254 NFSERR_ACCES,
255 NFSERR_NOTDIR,
256 NFSERR_NAMETOL,
257 NFSERR_STALE,
258 NFSERR_BADHANDLE,
259 NFSERR_SERVERFAULT,
260 0,
261};
262
263static short nfsv3err_access[] = {
264 NFSERR_IO,
265 NFSERR_IO,
266 NFSERR_STALE,
267 NFSERR_BADHANDLE,
268 NFSERR_SERVERFAULT,
269 0,
270};
271
272static short nfsv3err_readlink[] = {
273 NFSERR_IO,
274 NFSERR_IO,
275 NFSERR_ACCES,
276 NFSERR_INVAL,
277 NFSERR_STALE,
278 NFSERR_BADHANDLE,
279 NFSERR_NOTSUPP,
280 NFSERR_SERVERFAULT,
281 0,
282};
283
284static short nfsv3err_read[] = {
285 NFSERR_IO,
286 NFSERR_IO,
287 NFSERR_NXIO,
288 NFSERR_ACCES,
289 NFSERR_INVAL,
290 NFSERR_STALE,
291 NFSERR_BADHANDLE,
292 NFSERR_SERVERFAULT,
293 0,
294};
295
296static short nfsv3err_write[] = {
297 NFSERR_IO,
298 NFSERR_IO,
299 NFSERR_ACCES,
300 NFSERR_INVAL,
301 NFSERR_FBIG,
302 NFSERR_NOSPC,
303 NFSERR_ROFS,
304 NFSERR_DQUOT,
305 NFSERR_STALE,
306 NFSERR_BADHANDLE,
307 NFSERR_SERVERFAULT,
308 0,
309};
310
311static short nfsv3err_create[] = {
312 NFSERR_IO,
313 NFSERR_IO,
314 NFSERR_ACCES,
315 NFSERR_EXIST,
316 NFSERR_NOTDIR,
317 NFSERR_NOSPC,
318 NFSERR_ROFS,
319 NFSERR_NAMETOL,
320 NFSERR_DQUOT,
321 NFSERR_STALE,
322 NFSERR_BADHANDLE,
323 NFSERR_NOTSUPP,
324 NFSERR_SERVERFAULT,
325 0,
326};
327
328static short nfsv3err_mkdir[] = {
329 NFSERR_IO,
330 NFSERR_IO,
331 NFSERR_ACCES,
332 NFSERR_EXIST,
333 NFSERR_NOTDIR,
334 NFSERR_NOSPC,
335 NFSERR_ROFS,
336 NFSERR_NAMETOL,
337 NFSERR_DQUOT,
338 NFSERR_STALE,
339 NFSERR_BADHANDLE,
340 NFSERR_NOTSUPP,
341 NFSERR_SERVERFAULT,
342 0,
343};
344
345static short nfsv3err_symlink[] = {
346 NFSERR_IO,
347 NFSERR_IO,
348 NFSERR_ACCES,
349 NFSERR_EXIST,
350 NFSERR_NOTDIR,
351 NFSERR_NOSPC,
352 NFSERR_ROFS,
353 NFSERR_NAMETOL,
354 NFSERR_DQUOT,
355 NFSERR_STALE,
356 NFSERR_BADHANDLE,
357 NFSERR_NOTSUPP,
358 NFSERR_SERVERFAULT,
359 0,
360};
361
362static short nfsv3err_mknod[] = {
363 NFSERR_IO,
364 NFSERR_IO,
365 NFSERR_ACCES,
366 NFSERR_EXIST,
367 NFSERR_NOTDIR,
368 NFSERR_NOSPC,
369 NFSERR_ROFS,
370 NFSERR_NAMETOL,
371 NFSERR_DQUOT,
372 NFSERR_STALE,
373 NFSERR_BADHANDLE,
374 NFSERR_NOTSUPP,
375 NFSERR_SERVERFAULT,
376 NFSERR_BADTYPE,
377 0,
378};
379
380static short nfsv3err_remove[] = {
381 NFSERR_IO,
382 NFSERR_NOENT,
383 NFSERR_IO,
384 NFSERR_ACCES,
385 NFSERR_NOTDIR,
386 NFSERR_ROFS,
387 NFSERR_NAMETOL,
388 NFSERR_STALE,
389 NFSERR_BADHANDLE,
390 NFSERR_SERVERFAULT,
391 0,
392};
393
394static short nfsv3err_rmdir[] = {
395 NFSERR_IO,
396 NFSERR_NOENT,
397 NFSERR_IO,
398 NFSERR_ACCES,
399 NFSERR_EXIST,
400 NFSERR_NOTDIR,
401 NFSERR_INVAL,
402 NFSERR_ROFS,
403 NFSERR_NAMETOL,
404 NFSERR_NOTEMPTY,
405 NFSERR_STALE,
406 NFSERR_BADHANDLE,
407 NFSERR_NOTSUPP,
408 NFSERR_SERVERFAULT,
409 0,
410};
411
412static short nfsv3err_rename[] = {
413 NFSERR_IO,
414 NFSERR_NOENT,
415 NFSERR_IO,
416 NFSERR_ACCES,
417 NFSERR_EXIST,
418 NFSERR_XDEV,
419 NFSERR_NOTDIR,
420 NFSERR_ISDIR,
421 NFSERR_INVAL,
422 NFSERR_NOSPC,
423 NFSERR_ROFS,
424 NFSERR_MLINK,
425 NFSERR_NAMETOL,
426 NFSERR_NOTEMPTY,
427 NFSERR_DQUOT,
428 NFSERR_STALE,
429 NFSERR_BADHANDLE,
430 NFSERR_NOTSUPP,
431 NFSERR_SERVERFAULT,
432 0,
433};
434
435static short nfsv3err_link[] = {
436 NFSERR_IO,
437 NFSERR_IO,
438 NFSERR_ACCES,
439 NFSERR_EXIST,
440 NFSERR_XDEV,
441 NFSERR_NOTDIR,
442 NFSERR_INVAL,
443 NFSERR_NOSPC,
444 NFSERR_ROFS,
445 NFSERR_MLINK,
446 NFSERR_NAMETOL,
447 NFSERR_DQUOT,
448 NFSERR_STALE,
449 NFSERR_BADHANDLE,
450 NFSERR_NOTSUPP,
451 NFSERR_SERVERFAULT,
452 0,
453};
454
455static short nfsv3err_readdir[] = {
456 NFSERR_IO,
457 NFSERR_IO,
458 NFSERR_ACCES,
459 NFSERR_NOTDIR,
460 NFSERR_STALE,
461 NFSERR_BADHANDLE,
462 NFSERR_BAD_COOKIE,
463 NFSERR_TOOSMALL,
464 NFSERR_SERVERFAULT,
465 0,
466};
467
468static short nfsv3err_readdirplus[] = {
469 NFSERR_IO,
470 NFSERR_IO,
471 NFSERR_ACCES,
472 NFSERR_NOTDIR,
473 NFSERR_STALE,
474 NFSERR_BADHANDLE,
475 NFSERR_BAD_COOKIE,
476 NFSERR_NOTSUPP,
477 NFSERR_TOOSMALL,
478 NFSERR_SERVERFAULT,
479 0,
480};
481
482static short nfsv3err_fsstat[] = {
483 NFSERR_IO,
484 NFSERR_IO,
485 NFSERR_STALE,
486 NFSERR_BADHANDLE,
487 NFSERR_SERVERFAULT,
488 0,
489};
490
491static short nfsv3err_fsinfo[] = {
492 NFSERR_STALE,
493 NFSERR_STALE,
494 NFSERR_BADHANDLE,
495 NFSERR_SERVERFAULT,
496 0,
497};
498
499static short nfsv3err_pathconf[] = {
500 NFSERR_STALE,
501 NFSERR_STALE,
502 NFSERR_BADHANDLE,
503 NFSERR_SERVERFAULT,
504 0,
505};
506
507static short nfsv3err_commit[] = {
508 NFSERR_IO,
509 NFSERR_IO,
510 NFSERR_STALE,
511 NFSERR_BADHANDLE,
512 NFSERR_SERVERFAULT,
513 0,
514};
515
516static short *nfsrv_v3errmap[] = {
517 nfsv3err_null,
518 nfsv3err_getattr,
519 nfsv3err_setattr,
520 nfsv3err_lookup,
521 nfsv3err_access,
522 nfsv3err_readlink,
523 nfsv3err_read,
524 nfsv3err_write,
525 nfsv3err_create,
526 nfsv3err_mkdir,
527 nfsv3err_symlink,
528 nfsv3err_mknod,
529 nfsv3err_remove,
530 nfsv3err_rmdir,
531 nfsv3err_rename,
532 nfsv3err_link,
533 nfsv3err_readdir,
534 nfsv3err_readdirplus,
535 nfsv3err_fsstat,
536 nfsv3err_fsinfo,
537 nfsv3err_pathconf,
538 nfsv3err_commit,
539};
540
541#endif /* NFS_NOSERVER */
542
543extern struct nfsrtt nfsrtt;
544extern time_t nqnfsstarttime;
545extern int nqsrv_clockskew;
546extern int nqsrv_writeslack;
547extern int nqsrv_maxlease;
548extern struct nfsstats nfsstats;
549extern int nqnfs_piggy[NFS_NPROCS];
550extern nfstype nfsv2_type[9];
551extern nfstype nfsv3_type[9];
552extern struct nfsnodehashhead *nfsnodehashtbl;
553extern u_long nfsnodehash;
554
555struct nfssvc_args;
556extern int nfssvc(struct proc *, struct nfssvc_args *, int *);
557
558LIST_HEAD(nfsnodehashhead, nfsnode);
559
560int nfs_webnamei __P((struct nameidata *, struct vnode *, struct proc *));
561
562u_quad_t
563nfs_curusec()
564{
565 struct timeval tv;
566
567 getmicrotime(&tv);
568 return ((u_quad_t)tv.tv_sec * 1000000 + (u_quad_t)tv.tv_usec);
569}
570
571/*
572 * Create the header for an rpc request packet
573 * The hsiz is the size of the rest of the nfs request header.
574 * (just used to decide if a cluster is a good idea)
575 */
576struct mbuf *
577nfsm_reqh(vp, procid, hsiz, bposp)
578 struct vnode *vp;
579 u_long procid;
580 int hsiz;
581 caddr_t *bposp;
582{
583 register struct mbuf *mb;
584 register u_int32_t *tl;
585 register caddr_t bpos;
586 struct mbuf *mb2;
587 struct nfsmount *nmp;
588 int nqflag;
589
590 MGET(mb, M_WAIT, MT_DATA);
591 if (hsiz >= MINCLSIZE)
592 MCLGET(mb, M_WAIT);
593 mb->m_len = 0;
594 bpos = mtod(mb, caddr_t);
595
596 /*
597 * For NQNFS, add lease request.
598 */
599 if (vp) {
600 nmp = VFSTONFS(vp->v_mount);
601 if (nmp->nm_flag & NFSMNT_NQNFS) {
602 nqflag = NQNFS_NEEDLEASE(vp, procid);
603 if (nqflag) {
604 nfsm_build(tl, u_int32_t *, 2*NFSX_UNSIGNED);
605 *tl++ = txdr_unsigned(nqflag);
606 *tl = txdr_unsigned(nmp->nm_leaseterm);
607 } else {
608 nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED);
609 *tl = 0;
610 }
611 }
612 }
613 /* Finally, return values */
614 *bposp = bpos;
615 return (mb);
616}
617
618/*
619 * Build the RPC header and fill in the authorization info.
620 * The authorization string argument is only used when the credentials
621 * come from outside of the kernel.
622 * Returns the head of the mbuf list.
623 */
624struct mbuf *
625nfsm_rpchead(cr, nmflag, procid, auth_type, auth_len, auth_str, verf_len,
626 verf_str, mrest, mrest_len, mbp, xidp)
627 register struct ucred *cr;
628 int nmflag;
629 int procid;
630 int auth_type;
631 int auth_len;
632 char *auth_str;
633 int verf_len;
634 char *verf_str;
635 struct mbuf *mrest;
636 int mrest_len;
637 struct mbuf **mbp;
638 u_int32_t *xidp;
639{
640 register struct mbuf *mb;
641 register u_int32_t *tl;
642 register caddr_t bpos;
643 register int i;
644 struct mbuf *mreq, *mb2;
645 int siz, grpsiz, authsiz;
646
647 authsiz = nfsm_rndup(auth_len);
648 MGETHDR(mb, M_WAIT, MT_DATA);
649 if ((authsiz + 10 * NFSX_UNSIGNED) >= MINCLSIZE) {
650 MCLGET(mb, M_WAIT);
651 } else if ((authsiz + 10 * NFSX_UNSIGNED) < MHLEN) {
652 MH_ALIGN(mb, authsiz + 10 * NFSX_UNSIGNED);
653 } else {
654 MH_ALIGN(mb, 8 * NFSX_UNSIGNED);
655 }
656 mb->m_len = 0;
657 mreq = mb;
658 bpos = mtod(mb, caddr_t);
659
660 /*
661 * First the RPC header.
662 */
663 nfsm_build(tl, u_int32_t *, 8 * NFSX_UNSIGNED);
664
665 /* Get a pretty random xid to start with */
666 if (!nfs_xid)
667 nfs_xid = random();
668 /*
669 * Skip zero xid if it should ever happen.
670 */
671 if (++nfs_xid == 0)
672 nfs_xid++;
673
674 *tl++ = *xidp = txdr_unsigned(nfs_xid);
675 *tl++ = rpc_call;
676 *tl++ = rpc_vers;
677 if (nmflag & NFSMNT_NQNFS) {
678 *tl++ = txdr_unsigned(NQNFS_PROG);
679 *tl++ = txdr_unsigned(NQNFS_VER3);
680 } else {
681 *tl++ = txdr_unsigned(NFS_PROG);
682 if (nmflag & NFSMNT_NFSV3)
683 *tl++ = txdr_unsigned(NFS_VER3);
684 else
685 *tl++ = txdr_unsigned(NFS_VER2);
686 }
687 if (nmflag & NFSMNT_NFSV3)
688 *tl++ = txdr_unsigned(procid);
689 else
690 *tl++ = txdr_unsigned(nfsv2_procid[procid]);
691
692 /*
693 * And then the authorization cred.
694 */
695 *tl++ = txdr_unsigned(auth_type);
696 *tl = txdr_unsigned(authsiz);
697 switch (auth_type) {
698 case RPCAUTH_UNIX:
699 nfsm_build(tl, u_int32_t *, auth_len);
700 *tl++ = 0; /* stamp ?? */
701 *tl++ = 0; /* NULL hostname */
702 *tl++ = txdr_unsigned(cr->cr_uid);
703 *tl++ = txdr_unsigned(cr->cr_groups[0]);
704 grpsiz = (auth_len >> 2) - 5;
705 *tl++ = txdr_unsigned(grpsiz);
706 for (i = 1; i <= grpsiz; i++)
707 *tl++ = txdr_unsigned(cr->cr_groups[i]);
708 break;
709 case RPCAUTH_KERB4:
710 siz = auth_len;
711 while (siz > 0) {
712 if (M_TRAILINGSPACE(mb) == 0) {
713 MGET(mb2, M_WAIT, MT_DATA);
714 if (siz >= MINCLSIZE)
715 MCLGET(mb2, M_WAIT);
716 mb->m_next = mb2;
717 mb = mb2;
718 mb->m_len = 0;
719 bpos = mtod(mb, caddr_t);
720 }
721 i = min(siz, M_TRAILINGSPACE(mb));
722 bcopy(auth_str, bpos, i);
723 mb->m_len += i;
724 auth_str += i;
725 bpos += i;
726 siz -= i;
727 }
728 if ((siz = (nfsm_rndup(auth_len) - auth_len)) > 0) {
729 for (i = 0; i < siz; i++)
730 *bpos++ = '\0';
731 mb->m_len += siz;
732 }
733 break;
734 };
735
736 /*
737 * And the verifier...
738 */
739 nfsm_build(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
740 if (verf_str) {
741 *tl++ = txdr_unsigned(RPCAUTH_KERB4);
742 *tl = txdr_unsigned(verf_len);
743 siz = verf_len;
744 while (siz > 0) {
745 if (M_TRAILINGSPACE(mb) == 0) {
746 MGET(mb2, M_WAIT, MT_DATA);
747 if (siz >= MINCLSIZE)
748 MCLGET(mb2, M_WAIT);
749 mb->m_next = mb2;
750 mb = mb2;
751 mb->m_len = 0;
752 bpos = mtod(mb, caddr_t);
753 }
754 i = min(siz, M_TRAILINGSPACE(mb));
755 bcopy(verf_str, bpos, i);
756 mb->m_len += i;
757 verf_str += i;
758 bpos += i;
759 siz -= i;
760 }
761 if ((siz = (nfsm_rndup(verf_len) - verf_len)) > 0) {
762 for (i = 0; i < siz; i++)
763 *bpos++ = '\0';
764 mb->m_len += siz;
765 }
766 } else {
767 *tl++ = txdr_unsigned(RPCAUTH_NULL);
768 *tl = 0;
769 }
770 mb->m_next = mrest;
771 mreq->m_pkthdr.len = authsiz + 10 * NFSX_UNSIGNED + mrest_len;
772 mreq->m_pkthdr.rcvif = (struct ifnet *)0;
773 *mbp = mb;
774 return (mreq);
775}
776
777/*
778 * copies mbuf chain to the uio scatter/gather list
779 */
780int
781nfsm_mbuftouio(mrep, uiop, siz, dpos)
782 struct mbuf **mrep;
783 register struct uio *uiop;
784 int siz;
785 caddr_t *dpos;
786{
787 register char *mbufcp, *uiocp;
788 register int xfer, left, len;
789 register struct mbuf *mp;
790 long uiosiz, rem;
791 int error = 0;
792
793 mp = *mrep;
794 mbufcp = *dpos;
795 len = mtod(mp, caddr_t)+mp->m_len-mbufcp;
796 rem = nfsm_rndup(siz)-siz;
797 while (siz > 0) {
798 if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL)
799 return (EFBIG);
800 left = uiop->uio_iov->iov_len;
801 uiocp = uiop->uio_iov->iov_base;
802 if (left > siz)
803 left = siz;
804 uiosiz = left;
805 while (left > 0) {
806 while (len == 0) {
807 mp = mp->m_next;
808 if (mp == NULL)
809 return (EBADRPC);
810 mbufcp = mtod(mp, caddr_t);
811 len = mp->m_len;
812 }
813 xfer = (left > len) ? len : left;
814#ifdef notdef
815 /* Not Yet.. */
816 if (uiop->uio_iov->iov_op != NULL)
817 (*(uiop->uio_iov->iov_op))
818 (mbufcp, uiocp, xfer);
819 else
820#endif
821 if (uiop->uio_segflg == UIO_SYSSPACE)
822 bcopy(mbufcp, uiocp, xfer);
823 else
824 copyout(mbufcp, uiocp, xfer);
825 left -= xfer;
826 len -= xfer;
827 mbufcp += xfer;
828 uiocp += xfer;
829 uiop->uio_offset += xfer;
830 uiop->uio_resid -= xfer;
831 }
832 if (uiop->uio_iov->iov_len <= siz) {
833 uiop->uio_iovcnt--;
834 uiop->uio_iov++;
835 } else {
836 uiop->uio_iov->iov_base += uiosiz;
837 uiop->uio_iov->iov_len -= uiosiz;
838 }
839 siz -= uiosiz;
840 }
841 *dpos = mbufcp;
842 *mrep = mp;
843 if (rem > 0) {
844 if (len < rem)
845 error = nfs_adv(mrep, dpos, rem, len);
846 else
847 *dpos += rem;
848 }
849 return (error);
850}
851
852/*
853 * copies a uio scatter/gather list to an mbuf chain.
854 * NOTE: can ony handle iovcnt == 1
855 */
856int
857nfsm_uiotombuf(uiop, mq, siz, bpos)
858 register struct uio *uiop;
859 struct mbuf **mq;
860 int siz;
861 caddr_t *bpos;
862{
863 register char *uiocp;
864 register struct mbuf *mp, *mp2;
865 register int xfer, left, mlen;
866 int uiosiz, clflg, rem;
867 char *cp;
868
869#ifdef DIAGNOSTIC
870 if (uiop->uio_iovcnt != 1)
871 panic("nfsm_uiotombuf: iovcnt != 1");
872#endif
873
874 if (siz > MLEN) /* or should it >= MCLBYTES ?? */
875 clflg = 1;
876 else
877 clflg = 0;
878 rem = nfsm_rndup(siz)-siz;
879 mp = mp2 = *mq;
880 while (siz > 0) {
881 left = uiop->uio_iov->iov_len;
882 uiocp = uiop->uio_iov->iov_base;
883 if (left > siz)
884 left = siz;
885 uiosiz = left;
886 while (left > 0) {
887 mlen = M_TRAILINGSPACE(mp);
888 if (mlen == 0) {
889 MGET(mp, M_WAIT, MT_DATA);
890 if (clflg)
891 MCLGET(mp, M_WAIT);
892 mp->m_len = 0;
893 mp2->m_next = mp;
894 mp2 = mp;
895 mlen = M_TRAILINGSPACE(mp);
896 }
897 xfer = (left > mlen) ? mlen : left;
898#ifdef notdef
899 /* Not Yet.. */
900 if (uiop->uio_iov->iov_op != NULL)
901 (*(uiop->uio_iov->iov_op))
902 (uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
903 else
904#endif
905 if (uiop->uio_segflg == UIO_SYSSPACE)
906 bcopy(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
907 else
908 copyin(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
909 mp->m_len += xfer;
910 left -= xfer;
911 uiocp += xfer;
912 uiop->uio_offset += xfer;
913 uiop->uio_resid -= xfer;
914 }
915 uiop->uio_iov->iov_base += uiosiz;
916 uiop->uio_iov->iov_len -= uiosiz;
917 siz -= uiosiz;
918 }
919 if (rem > 0) {
920 if (rem > M_TRAILINGSPACE(mp)) {
921 MGET(mp, M_WAIT, MT_DATA);
922 mp->m_len = 0;
923 mp2->m_next = mp;
924 }
925 cp = mtod(mp, caddr_t)+mp->m_len;
926 for (left = 0; left < rem; left++)
927 *cp++ = '\0';
928 mp->m_len += rem;
929 *bpos = cp;
930 } else
931 *bpos = mtod(mp, caddr_t)+mp->m_len;
932 *mq = mp;
933 return (0);
934}
935
936/*
937 * Help break down an mbuf chain by setting the first siz bytes contiguous
938 * pointed to by returned val.
939 * This is used by the macros nfsm_dissect and nfsm_dissecton for tough
940 * cases. (The macros use the vars. dpos and dpos2)
941 */
942int
943nfsm_disct(mdp, dposp, siz, left, cp2)
944 struct mbuf **mdp;
945 caddr_t *dposp;
946 int siz;
947 int left;
948 caddr_t *cp2;
949{
950 register struct mbuf *mp, *mp2;
951 register int siz2, xfer;
952 register caddr_t p;
953
954 mp = *mdp;
955 while (left == 0) {
956 *mdp = mp = mp->m_next;
957 if (mp == NULL)
958 return (EBADRPC);
959 left = mp->m_len;
960 *dposp = mtod(mp, caddr_t);
961 }
962 if (left >= siz) {
963 *cp2 = *dposp;
964 *dposp += siz;
965 } else if (mp->m_next == NULL) {
966 return (EBADRPC);
967 } else if (siz > MHLEN) {
968 panic("nfs S too big");
969 } else {
970 MGET(mp2, M_WAIT, MT_DATA);
971 mp2->m_next = mp->m_next;
972 mp->m_next = mp2;
973 mp->m_len -= left;
974 mp = mp2;
975 *cp2 = p = mtod(mp, caddr_t);
976 bcopy(*dposp, p, left); /* Copy what was left */
977 siz2 = siz-left;
978 p += left;
979 mp2 = mp->m_next;
980 /* Loop around copying up the siz2 bytes */
981 while (siz2 > 0) {
982 if (mp2 == NULL)
983 return (EBADRPC);
984 xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2;
985 if (xfer > 0) {
986 bcopy(mtod(mp2, caddr_t), p, xfer);
987 NFSMADV(mp2, xfer);
988 mp2->m_len -= xfer;
989 p += xfer;
990 siz2 -= xfer;
991 }
992 if (siz2 > 0)
993 mp2 = mp2->m_next;
994 }
995 mp->m_len = siz;
996 *mdp = mp2;
997 *dposp = mtod(mp2, caddr_t);
998 }
999 return (0);
1000}
1001
1002/*
1003 * Advance the position in the mbuf chain.
1004 */
1005int
1006nfs_adv(mdp, dposp, offs, left)
1007 struct mbuf **mdp;
1008 caddr_t *dposp;
1009 int offs;
1010 int left;
1011{
1012 register struct mbuf *m;
1013 register int s;
1014
1015 m = *mdp;
1016 s = left;
1017 while (s < offs) {
1018 offs -= s;
1019 m = m->m_next;
1020 if (m == NULL)
1021 return (EBADRPC);
1022 s = m->m_len;
1023 }
1024 *mdp = m;
1025 *dposp = mtod(m, caddr_t)+offs;
1026 return (0);
1027}
1028
1029/*
1030 * Copy a string into mbufs for the hard cases...
1031 */
1032int
1033nfsm_strtmbuf(mb, bpos, cp, siz)
1034 struct mbuf **mb;
1035 char **bpos;
1036 const char *cp;
1037 long siz;
1038{
1039 register struct mbuf *m1 = NULL, *m2;
1040 long left, xfer, len, tlen;
1041 u_int32_t *tl;
1042 int putsize;
1043
1044 putsize = 1;
1045 m2 = *mb;
1046 left = M_TRAILINGSPACE(m2);
1047 if (left > 0) {
1048 tl = ((u_int32_t *)(*bpos));
1049 *tl++ = txdr_unsigned(siz);
1050 putsize = 0;
1051 left -= NFSX_UNSIGNED;
1052 m2->m_len += NFSX_UNSIGNED;
1053 if (left > 0) {
1054 bcopy(cp, (caddr_t) tl, left);
1055 siz -= left;
1056 cp += left;
1057 m2->m_len += left;
1058 left = 0;
1059 }
1060 }
1061 /* Loop around adding mbufs */
1062 while (siz > 0) {
1063 MGET(m1, M_WAIT, MT_DATA);
1064 if (siz > MLEN)
1065 MCLGET(m1, M_WAIT);
1066 m1->m_len = NFSMSIZ(m1);
1067 m2->m_next = m1;
1068 m2 = m1;
1069 tl = mtod(m1, u_int32_t *);
1070 tlen = 0;
1071 if (putsize) {
1072 *tl++ = txdr_unsigned(siz);
1073 m1->m_len -= NFSX_UNSIGNED;
1074 tlen = NFSX_UNSIGNED;
1075 putsize = 0;
1076 }
1077 if (siz < m1->m_len) {
1078 len = nfsm_rndup(siz);
1079 xfer = siz;
1080 if (xfer < len)
1081 *(tl+(xfer>>2)) = 0;
1082 } else {
1083 xfer = len = m1->m_len;
1084 }
1085 bcopy(cp, (caddr_t) tl, xfer);
1086 m1->m_len = len+tlen;
1087 siz -= xfer;
1088 cp += xfer;
1089 }
1090 *mb = m1;
1091 *bpos = mtod(m1, caddr_t)+m1->m_len;
1092 return (0);
1093}
1094
1095/*
1096 * Called once to initialize data structures...
1097 */
1098int
1099nfs_init(vfsp)
1100 struct vfsconf *vfsp;
1101{
1102 register int i;
1103
1104 nfsmount_zone = zinit("NFSMOUNT", sizeof(struct nfsmount), 0, 0, 1);
1105
1106 nfs_mount_type = vfsp->vfc_typenum;
1107 nfsrtt.pos = 0;
1108 rpc_vers = txdr_unsigned(RPC_VER2);
1109 rpc_call = txdr_unsigned(RPC_CALL);
1110 rpc_reply = txdr_unsigned(RPC_REPLY);
1111 rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED);
1112 rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED);
1113 rpc_mismatch = txdr_unsigned(RPC_MISMATCH);
1114 rpc_autherr = txdr_unsigned(RPC_AUTHERR);
1115 rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX);
1116 rpc_auth_kerb = txdr_unsigned(RPCAUTH_KERB4);
1117 nfs_prog = txdr_unsigned(NFS_PROG);
1118 nqnfs_prog = txdr_unsigned(NQNFS_PROG);
1119 nfs_true = txdr_unsigned(TRUE);
1120 nfs_false = txdr_unsigned(FALSE);
1121 nfs_xdrneg1 = txdr_unsigned(-1);
1122 nfs_ticks = (hz * NFS_TICKINTVL + 500) / 1000;
1123 if (nfs_ticks < 1)
1124 nfs_ticks = 1;
1125 /* Ensure async daemons disabled */
1126 for (i = 0; i < NFS_MAXASYNCDAEMON; i++) {
1127 nfs_iodwant[i] = (struct proc *)0;
1128 nfs_iodmount[i] = (struct nfsmount *)0;
1129 }
1130 nfs_nhinit(); /* Init the nfsnode table */
1131#ifndef NFS_NOSERVER
1132 nfsrv_init(0); /* Init server data structures */
1133 nfsrv_initcache(); /* Init the server request cache */
1134#endif
1135
1136 /*
1137 * Initialize the nqnfs server stuff.
1138 */
1139 if (nqnfsstarttime == 0) {
1140 nqnfsstarttime = boottime.tv_sec + nqsrv_maxlease
1141 + nqsrv_clockskew + nqsrv_writeslack;
1142 NQLOADNOVRAM(nqnfsstarttime);
1143 CIRCLEQ_INIT(&nqtimerhead);
1144 nqfhhashtbl = hashinit(NQLCHSZ, M_NQLEASE, &nqfhhash);
1145 }
1146
1147 /*
1148 * Initialize reply list and start timer
1149 */
1150 TAILQ_INIT(&nfs_reqq);
1151
1152 nfs_timer(0);
1153
1154 /*
1155 * Set up lease_check and lease_updatetime so that other parts
1156 * of the system can call us, if we are loadable.
1157 */
1158#ifndef NFS_NOSERVER
1159 nfs_prev_vop_lease_check = default_vnodeop_p[VOFFSET(vop_lease)];
1160 default_vnodeop_p[VOFFSET(vop_lease)] = (vop_t *)nqnfs_vop_lease_check;
1161#endif
1162 nfs_prev_lease_updatetime = lease_updatetime;
1163 lease_updatetime = nfs_lease_updatetime;
1164 nfs_prev_nfssvc_sy_narg = sysent[SYS_nfssvc].sy_narg;
1165 sysent[SYS_nfssvc].sy_narg = 2;
1166 nfs_prev_nfssvc_sy_call = sysent[SYS_nfssvc].sy_call;
1167 sysent[SYS_nfssvc].sy_call = (sy_call_t *)nfssvc;
1168
1169 nfs_pbuf_freecnt = nswbuf / 2 + 1;
1170
1171 return (0);
1172}
1173
1174int
1175nfs_uninit(vfsp)
1176 struct vfsconf *vfsp;
1177{
1178
1179 untimeout(nfs_timer, (void *)NULL, nfs_timer_handle);
1180 nfs_mount_type = -1;
1181#ifndef NFS_NOSERVER
1182 default_vnodeop_p[VOFFSET(vop_lease)] = nfs_prev_vop_lease_check;
1183#endif
1184 lease_updatetime = nfs_prev_lease_updatetime;
1185 sysent[SYS_nfssvc].sy_narg = nfs_prev_nfssvc_sy_narg;
1186 sysent[SYS_nfssvc].sy_call = nfs_prev_nfssvc_sy_call;
1187 return (0);
1188}
1189
1190/*
1191 * Attribute cache routines.
1192 * nfs_loadattrcache() - loads or updates the cache contents from attributes
1193 * that are on the mbuf list
1194 * nfs_getattrcache() - returns valid attributes if found in cache, returns
1195 * error otherwise
1196 */
1197
1198/*
1199 * Load the attribute cache (that lives in the nfsnode entry) with
1200 * the values on the mbuf list and
1201 * Iff vap not NULL
1202 * copy the attributes to *vaper
1203 */
1204int
1205nfs_loadattrcache(vpp, mdp, dposp, vaper)
1206 struct vnode **vpp;
1207 struct mbuf **mdp;
1208 caddr_t *dposp;
1209 struct vattr *vaper;
1210{
1211 register struct vnode *vp = *vpp;
1212 register struct vattr *vap;
1213 register struct nfs_fattr *fp;
1214 register struct nfsnode *np;
1215 register int32_t t1;
1216 caddr_t cp2;
1217 int error = 0, rdev;
1218 struct mbuf *md;
1219 enum vtype vtyp;
1220 u_short vmode;
1221 struct timespec mtime;
1222 int v3 = NFS_ISV3(vp);
1223
1224 md = *mdp;
1225 t1 = (mtod(md, caddr_t) + md->m_len) - *dposp;
1226 if ((error = nfsm_disct(mdp, dposp, NFSX_FATTR(v3), t1, &cp2)) != 0)
1227 return (error);
1228 fp = (struct nfs_fattr *)cp2;
1229 if (v3) {
1230 vtyp = nfsv3tov_type(fp->fa_type);
1231 vmode = fxdr_unsigned(u_short, fp->fa_mode);
1232 rdev = makeudev(fxdr_unsigned(int, fp->fa3_rdev.specdata1),
1233 fxdr_unsigned(int, fp->fa3_rdev.specdata2));
1234 fxdr_nfsv3time(&fp->fa3_mtime, &mtime);
1235 } else {
1236 vtyp = nfsv2tov_type(fp->fa_type);
1237 vmode = fxdr_unsigned(u_short, fp->fa_mode);
1238 /*
1239 * XXX
1240 *
1241 * The duplicate information returned in fa_type and fa_mode
1242 * is an ambiguity in the NFS version 2 protocol.
1243 *
1244 * VREG should be taken literally as a regular file. If a
1245 * server intents to return some type information differently
1246 * in the upper bits of the mode field (e.g. for sockets, or
1247 * FIFOs), NFSv2 mandates fa_type to be VNON. Anyway, we
1248 * leave the examination of the mode bits even in the VREG
1249 * case to avoid breakage for bogus servers, but we make sure
1250 * that there are actually type bits set in the upper part of
1251 * fa_mode (and failing that, trust the va_type field).
1252 *
1253 * NFSv3 cleared the issue, and requires fa_mode to not
1254 * contain any type information (while also introduing sockets
1255 * and FIFOs for fa_type).
1256 */
1257 if (vtyp == VNON || (vtyp == VREG && (vmode & S_IFMT) != 0))
1258 vtyp = IFTOVT(vmode);
1259 rdev = fxdr_unsigned(int32_t, fp->fa2_rdev);
1260 fxdr_nfsv2time(&fp->fa2_mtime, &mtime);
1261
1262 /*
1263 * Really ugly NFSv2 kludge.
1264 */
1265 if (vtyp == VCHR && rdev == 0xffffffff)
1266 vtyp = VFIFO;
1267 }
1268
1269 /*
1270 * If v_type == VNON it is a new node, so fill in the v_type,
1271 * n_mtime fields. Check to see if it represents a special
1272 * device, and if so, check for a possible alias. Once the
1273 * correct vnode has been obtained, fill in the rest of the
1274 * information.
1275 */
1276 np = VTONFS(vp);
1277 if (vp->v_type != vtyp) {
1278 vp->v_type = vtyp;
1279 if (vp->v_type == VFIFO) {
1280 vp->v_op = fifo_nfsv2nodeop_p;
1281 }
1282 if (vp->v_type == VCHR || vp->v_type == VBLK) {
1283 vp->v_op = spec_nfsv2nodeop_p;
1284 addaliasu(vp, rdev);
1285 }
1286 np->n_mtime = mtime.tv_sec;
1287 }
1288 vap = &np->n_vattr;
1289 vap->va_type = vtyp;
1290 vap->va_mode = (vmode & 07777);
1291 vap->va_rdev = rdev;
1292 vap->va_mtime = mtime;
1293 vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0];
1294 if (v3) {
1295 vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink);
1296 vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid);
1297 vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid);
1298 vap->va_size = fxdr_hyper(&fp->fa3_size);
1299 vap->va_blocksize = NFS_FABLKSIZE;
1300 vap->va_bytes = fxdr_hyper(&fp->fa3_used);
1301 vap->va_fileid = fxdr_unsigned(int32_t,
1302 fp->fa3_fileid.nfsuquad[1]);
1303 fxdr_nfsv3time(&fp->fa3_atime, &vap->va_atime);
1304 fxdr_nfsv3time(&fp->fa3_ctime, &vap->va_ctime);
1305 vap->va_flags = 0;
1306 vap->va_filerev = 0;
1307 } else {
1308 vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink);
1309 vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid);
1310 vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid);
1311 vap->va_size = fxdr_unsigned(u_int32_t, fp->fa2_size);
1312 vap->va_blocksize = fxdr_unsigned(int32_t, fp->fa2_blocksize);
1313 vap->va_bytes = (u_quad_t)fxdr_unsigned(int32_t, fp->fa2_blocks)
1314 * NFS_FABLKSIZE;
1315 vap->va_fileid = fxdr_unsigned(int32_t, fp->fa2_fileid);
1316 fxdr_nfsv2time(&fp->fa2_atime, &vap->va_atime);
1317 vap->va_flags = 0;
1318 vap->va_ctime.tv_sec = fxdr_unsigned(u_int32_t,
1319 fp->fa2_ctime.nfsv2_sec);
1320 vap->va_ctime.tv_nsec = 0;
1321 vap->va_gen = fxdr_unsigned(u_int32_t,fp->fa2_ctime.nfsv2_usec);
1322 vap->va_filerev = 0;
1323 }
1324 if (vap->va_size != np->n_size) {
1325 if (vap->va_type == VREG) {
1326 if (np->n_flag & NMODIFIED) {
1327 if (vap->va_size < np->n_size)
1328 vap->va_size = np->n_size;
1329 else
1330 np->n_size = vap->va_size;
1331 } else {
1332 np->n_size = vap->va_size;
1333 }
1334 vnode_pager_setsize(vp, np->n_size);
1335 } else {
1336 np->n_size = vap->va_size;
1337 }
1338 }
1339 np->n_attrstamp = time_second;
1340 if (vaper != NULL) {
1341 bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(*vap));
1342 if (np->n_flag & NCHG) {
1343 if (np->n_flag & NACC)
1344 vaper->va_atime = np->n_atim;
1345 if (np->n_flag & NUPD)
1346 vaper->va_mtime = np->n_mtim;
1347 }
1348 }
1349 return (0);
1350}
1351
1352#ifdef NFS_ACDEBUG
1353#include <sys/sysctl.h>
1354SYSCTL_DECL(_vfs_nfs);
1355static int nfs_acdebug;
1356SYSCTL_INT(_vfs_nfs, OID_AUTO, acdebug, CTLFLAG_RW, &nfs_acdebug, 0, "");
1357#endif
1358
1359/*
1360 * Check the time stamp
1361 * If the cache is valid, copy contents to *vap and return 0
1362 * otherwise return an error
1363 */
1364int
1365nfs_getattrcache(vp, vaper)
1366 register struct vnode *vp;
1367 struct vattr *vaper;
1368{
1369 register struct nfsnode *np;
1370 register struct vattr *vap;
1371 struct nfsmount *nmp;
1372 int timeo;
1373
1374 np = VTONFS(vp);
1375 vap = &np->n_vattr;
1376 nmp = VFSTONFS(vp->v_mount);
1377 /* XXX n_mtime doesn't seem to be updated on a miss-and-reload */
1378 timeo = (time_second - np->n_mtime) / 10;
1379
1380#ifdef NFS_ACDEBUG
1381 if (nfs_acdebug>1)
1382 printf("nfs_getattrcache: initial timeo = %d\n", timeo);
1383#endif
1384
1385 if (vap->va_type == VDIR) {
1386 if ((np->n_flag & NMODIFIED) || timeo < nmp->nm_acdirmin)
1387 timeo = nmp->nm_acdirmin;
1388 else if (timeo > nmp->nm_acdirmax)
1389 timeo = nmp->nm_acdirmax;
1390 } else {
1391 if ((np->n_flag & NMODIFIED) || timeo < nmp->nm_acregmin)
1392 timeo = nmp->nm_acregmin;
1393 else if (timeo > nmp->nm_acregmax)
1394 timeo = nmp->nm_acregmax;
1395 }
1396
1397#ifdef NFS_ACDEBUG
1398 if (nfs_acdebug > 2)
1399 printf("acregmin %d; acregmax %d; acdirmin %d; acdirmax %d\n",
1400 nmp->nm_acregmin, nmp->nm_acregmax,
1401 nmp->nm_acdirmin, nmp->nm_acdirmax);
1402
1403 if (nfs_acdebug)
1404 printf("nfs_getattrcache: age = %d; final timeo = %d\n",
1405 (time_second - np->n_attrstamp), timeo);
1406#endif
1407
1408 if ((time_second - np->n_attrstamp) >= timeo) {
1409 nfsstats.attrcache_misses++;
1410 return (ENOENT);
1411 }
1412 nfsstats.attrcache_hits++;
1413 if (vap->va_size != np->n_size) {
1414 if (vap->va_type == VREG) {
1415 if (np->n_flag & NMODIFIED) {
1416 if (vap->va_size < np->n_size)
1417 vap->va_size = np->n_size;
1418 else
1419 np->n_size = vap->va_size;
1420 } else {
1421 np->n_size = vap->va_size;
1422 }
1423 vnode_pager_setsize(vp, np->n_size);
1424 } else {
1425 np->n_size = vap->va_size;
1426 }
1427 }
1428 bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(struct vattr));
1429 if (np->n_flag & NCHG) {
1430 if (np->n_flag & NACC)
1431 vaper->va_atime = np->n_atim;
1432 if (np->n_flag & NUPD)
1433 vaper->va_mtime = np->n_mtim;
1434 }
1435 return (0);
1436}
1437
1438#ifndef NFS_NOSERVER
1439/*
1440 * Set up nameidata for a lookup() call and do it.
1441 *
1442 * If pubflag is set, this call is done for a lookup operation on the
1443 * public filehandle. In that case we allow crossing mountpoints and
1444 * absolute pathnames. However, the caller is expected to check that
1445 * the lookup result is within the public fs, and deny access if
1446 * it is not.
1447 *
1448 * nfs_namei() clears out garbage fields that namei() might leave garbage.
1449 * This is mainly ni_vp and ni_dvp when an error occurs, and ni_dvp when no
1450 * error occurs but the parent was not requested.
1451 *
1452 * dirp may be set whether an error is returned or not, and must be
1453 * released by the caller.
1454 */
1455int
1456nfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, retdirp, p, kerbflag, pubflag)
1457 register struct nameidata *ndp;
1458 fhandle_t *fhp;
1459 int len;
1460 struct nfssvc_sock *slp;
1461 struct sockaddr *nam;
1462 struct mbuf **mdp;
1463 caddr_t *dposp;
1464 struct vnode **retdirp;
1465 struct proc *p;
1466 int kerbflag, pubflag;
1467{
1468 register int i, rem;
1469 register struct mbuf *md;
1470 register char *fromcp, *tocp, *cp;
1471 struct iovec aiov;
1472 struct uio auio;
1473 struct vnode *dp;
1474 int error, rdonly, linklen;
1475 struct componentname *cnp = &ndp->ni_cnd;
1476
1477 *retdirp = (struct vnode *)0;
1478 cnp->cn_pnbuf = zalloc(namei_zone);
1479
1480 /*
1481 * Copy the name from the mbuf list to ndp->ni_pnbuf
1482 * and set the various ndp fields appropriately.
1483 */
1484 fromcp = *dposp;
1485 tocp = cnp->cn_pnbuf;
1486 md = *mdp;
1487 rem = mtod(md, caddr_t) + md->m_len - fromcp;
1488 for (i = 0; i < len; i++) {
1489 while (rem == 0) {
1490 md = md->m_next;
1491 if (md == NULL) {
1492 error = EBADRPC;
1493 goto out;
1494 }
1495 fromcp = mtod(md, caddr_t);
1496 rem = md->m_len;
1497 }
1498 if (*fromcp == '\0' || (!pubflag && *fromcp == '/')) {
1499 error = EACCES;
1500 goto out;
1501 }
1502 *tocp++ = *fromcp++;
1503 rem--;
1504 }
1505 *tocp = '\0';
1506 *mdp = md;
1507 *dposp = fromcp;
1508 len = nfsm_rndup(len)-len;
1509 if (len > 0) {
1510 if (rem >= len)
1511 *dposp += len;
1512 else if ((error = nfs_adv(mdp, dposp, len, rem)) != 0)
1513 goto out;
1514 }
1515
1516 /*
1517 * Extract and set starting directory.
1518 */
1519 error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cnd.cn_cred, slp,
1520 nam, &rdonly, kerbflag, pubflag);
1521 if (error)
1522 goto out;
1523 if (dp->v_type != VDIR) {
1524 vrele(dp);
1525 error = ENOTDIR;
1526 goto out;
1527 }
1528
1529 if (rdonly)
1530 cnp->cn_flags |= RDONLY;
1531
1532 /*
1533 * Set return directory. Reference to dp is implicitly transfered
1534 * to the returned pointer
1535 */
1536 *retdirp = dp;
1537
1538 if (pubflag) {
1539 /*
1540 * Oh joy. For WebNFS, handle those pesky '%' escapes,
1541 * and the 'native path' indicator.
1542 */
1543 cp = zalloc(namei_zone);
1544 fromcp = cnp->cn_pnbuf;
1545 tocp = cp;
1546 if ((unsigned char)*fromcp >= WEBNFS_SPECCHAR_START) {
1547 switch ((unsigned char)*fromcp) {
1548 case WEBNFS_NATIVE_CHAR:
1549 /*
1550 * 'Native' path for us is the same
1551 * as a path according to the NFS spec,
1552 * just skip the escape char.
1553 */
1554 fromcp++;
1555 break;
1556 /*
1557 * More may be added in the future, range 0x80-0xff
1558 */
1559 default:
1560 error = EIO;
1561 zfree(namei_zone, cp);
1562 goto out;
1563 }
1564 }
1565 /*
1566 * Translate the '%' escapes, URL-style.
1567 */
1568 while (*fromcp != '\0') {
1569 if (*fromcp == WEBNFS_ESC_CHAR) {
1570 if (fromcp[1] != '\0' && fromcp[2] != '\0') {
1571 fromcp++;
1572 *tocp++ = HEXSTRTOI(fromcp);
1573 fromcp += 2;
1574 continue;
1575 } else {
1576 error = ENOENT;
1577 zfree(namei_zone, cp);
1578 goto out;
1579 }
1580 } else
1581 *tocp++ = *fromcp++;
1582 }
1583 *tocp = '\0';
1584 zfree(namei_zone, cnp->cn_pnbuf);
1585 cnp->cn_pnbuf = cp;
1586 }
1587
1588 ndp->ni_pathlen = (tocp - cnp->cn_pnbuf) + 1;
1589 ndp->ni_segflg = UIO_SYSSPACE;
1590
1591 if (pubflag) {
1592 ndp->ni_rootdir = rootvnode;
1593 ndp->ni_loopcnt = 0;
1594 if (cnp->cn_pnbuf[0] == '/')
1595 dp = rootvnode;
1596 } else {
1597 cnp->cn_flags |= NOCROSSMOUNT;
1598 }
1599
1600 /*
1601 * Initialize for scan, set ni_startdir and bump ref on dp again
1602 * becuase lookup() will dereference ni_startdir.
1603 */
1604
1605 cnp->cn_proc = p;
1606 VREF(dp);
1607 ndp->ni_startdir = dp;
1608
1609 for (;;) {
1610 cnp->cn_nameptr = cnp->cn_pnbuf;
1611 /*
1612 * Call lookup() to do the real work. If an error occurs,
1613 * ndp->ni_vp and ni_dvp are left uninitialized or NULL and
1614 * we do not have to dereference anything before returning.
1615 * In either case ni_startdir will be dereferenced and NULLed
1616 * out.
1617 */
1618 error = lookup(ndp);
1619 if (error)
1620 break;
1621
1622 /*
1623 * Check for encountering a symbolic link. Trivial
1624 * termination occurs if no symlink encountered.
1625 * Note: zfree is safe because error is 0, so we will
1626 * not zfree it again when we break.
1627 */
1628 if ((cnp->cn_flags & ISSYMLINK) == 0) {
1629 nfsrv_object_create(ndp->ni_vp);
1630 if (cnp->cn_flags & (SAVENAME | SAVESTART))
1631 cnp->cn_flags |= HASBUF;
1632 else
1633 zfree(namei_zone, cnp->cn_pnbuf);
1634 break;
1635 }
1636
1637 /*
1638 * Validate symlink
1639 */
1640 if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1)
1641 VOP_UNLOCK(ndp->ni_dvp, 0, p);
1642 if (!pubflag) {
1643 error = EINVAL;
1644 goto badlink2;
1645 }
1646
1647 if (ndp->ni_loopcnt++ >= MAXSYMLINKS) {
1648 error = ELOOP;
1649 goto badlink2;
1650 }
1651 if (ndp->ni_pathlen > 1)
1652 cp = zalloc(namei_zone);
1653 else
1654 cp = cnp->cn_pnbuf;
1655 aiov.iov_base = cp;
1656 aiov.iov_len = MAXPATHLEN;
1657 auio.uio_iov = &aiov;
1658 auio.uio_iovcnt = 1;
1659 auio.uio_offset = 0;
1660 auio.uio_rw = UIO_READ;
1661 auio.uio_segflg = UIO_SYSSPACE;
1662 auio.uio_procp = (struct proc *)0;
1663 auio.uio_resid = MAXPATHLEN;
1664 error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred);
1665 if (error) {
1666 badlink1:
1667 if (ndp->ni_pathlen > 1)
1668 zfree(namei_zone, cp);
1669 badlink2:
1670 vrele(ndp->ni_dvp);
1671 vput(ndp->ni_vp);
1672 break;
1673 }
1674 linklen = MAXPATHLEN - auio.uio_resid;
1675 if (linklen == 0) {
1676 error = ENOENT;
1677 goto badlink1;
1678 }
1679 if (linklen + ndp->ni_pathlen >= MAXPATHLEN) {
1680 error = ENAMETOOLONG;
1681 goto badlink1;
1682 }
1683
1684 /*
1685 * Adjust or replace path
1686 */
1687 if (ndp->ni_pathlen > 1) {
1688 bcopy(ndp->ni_next, cp + linklen, ndp->ni_pathlen);
1689 zfree(namei_zone, cnp->cn_pnbuf);
1690 cnp->cn_pnbuf = cp;
1691 } else
1692 cnp->cn_pnbuf[linklen] = '\0';
1693 ndp->ni_pathlen += linklen;
1694
1695 /*
1696 * Cleanup refs for next loop and check if root directory
1697 * should replace current directory. Normally ni_dvp
1698 * becomes the new base directory and is cleaned up when
1699 * we loop. Explicitly null pointers after invalidation
1700 * to clarify operation.
1701 */
1702 vput(ndp->ni_vp);
1703 ndp->ni_vp = NULL;
1704
1705 if (cnp->cn_pnbuf[0] == '/') {
1706 vrele(ndp->ni_dvp);
1707 ndp->ni_dvp = ndp->ni_rootdir;
1708 VREF(ndp->ni_dvp);
1709 }
1710 ndp->ni_startdir = ndp->ni_dvp;
1711 ndp->ni_dvp = NULL;
1712 }
1713
1714 /*
1715 * nfs_namei() guarentees that fields will not contain garbage
1716 * whether an error occurs or not. This allows the caller to track
1717 * cleanup state trivially.
1718 */
1719out:
1720 if (error) {
1721 zfree(namei_zone, cnp->cn_pnbuf);
1722 ndp->ni_vp = NULL;
1723 ndp->ni_dvp = NULL;
1724 ndp->ni_startdir = NULL;
1725 cnp->cn_flags &= ~HASBUF;
1726 } else if ((ndp->ni_cnd.cn_flags & (WANTPARENT|LOCKPARENT)) == 0) {
1727 ndp->ni_dvp = NULL;
1728 }
1729 return (error);
1730}
1731
1732/*
1733 * A fiddled version of m_adj() that ensures null fill to a long
1734 * boundary and only trims off the back end
1735 */
1736void
1737nfsm_adj(mp, len, nul)
1738 struct mbuf *mp;
1739 register int len;
1740 int nul;
1741{
1742 register struct mbuf *m;
1743 register int count, i;
1744 register char *cp;
1745
1746 /*
1747 * Trim from tail. Scan the mbuf chain,
1748 * calculating its length and finding the last mbuf.
1749 * If the adjustment only affects this mbuf, then just
1750 * adjust and return. Otherwise, rescan and truncate
1751 * after the remaining size.
1752 */
1753 count = 0;
1754 m = mp;
1755 for (;;) {
1756 count += m->m_len;
1757 if (m->m_next == (struct mbuf *)0)
1758 break;
1759 m = m->m_next;
1760 }
1761 if (m->m_len > len) {
1762 m->m_len -= len;
1763 if (nul > 0) {
1764 cp = mtod(m, caddr_t)+m->m_len-nul;
1765 for (i = 0; i < nul; i++)
1766 *cp++ = '\0';
1767 }
1768 return;
1769 }
1770 count -= len;
1771 if (count < 0)
1772 count = 0;
1773 /*
1774 * Correct length for chain is "count".
1775 * Find the mbuf with last data, adjust its length,
1776 * and toss data from remaining mbufs on chain.
1777 */
1778 for (m = mp; m; m = m->m_next) {
1779 if (m->m_len >= count) {
1780 m->m_len = count;
1781 if (nul > 0) {
1782 cp = mtod(m, caddr_t)+m->m_len-nul;
1783 for (i = 0; i < nul; i++)
1784 *cp++ = '\0';
1785 }
1786 break;
1787 }
1788 count -= m->m_len;
1789 }
1790 for (m = m->m_next;m;m = m->m_next)
1791 m->m_len = 0;
1792}
1793
1794/*
1795 * Make these functions instead of macros, so that the kernel text size
1796 * doesn't get too big...
1797 */
1798void
1799nfsm_srvwcc(nfsd, before_ret, before_vap, after_ret, after_vap, mbp, bposp)
1800 struct nfsrv_descript *nfsd;
1801 int before_ret;
1802 register struct vattr *before_vap;
1803 int after_ret;
1804 struct vattr *after_vap;
1805 struct mbuf **mbp;
1806 char **bposp;
1807{
1808 register struct mbuf *mb = *mbp, *mb2;
1809 register char *bpos = *bposp;
1810 register u_int32_t *tl;
1811
1812 if (before_ret) {
1813 nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED);
1814 *tl = nfs_false;
1815 } else {
1816 nfsm_build(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
1817 *tl++ = nfs_true;
1818 txdr_hyper(before_vap->va_size, tl);
1819 tl += 2;
1820 txdr_nfsv3time(&(before_vap->va_mtime), tl);
1821 tl += 2;
1822 txdr_nfsv3time(&(before_vap->va_ctime), tl);
1823 }
1824 *bposp = bpos;
1825 *mbp = mb;
1826 nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp);
1827}
1828
1829void
1830nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp)
1831 struct nfsrv_descript *nfsd;
1832 int after_ret;
1833 struct vattr *after_vap;
1834 struct mbuf **mbp;
1835 char **bposp;
1836{
1837 register struct mbuf *mb = *mbp, *mb2;
1838 register char *bpos = *bposp;
1839 register u_int32_t *tl;
1840 register struct nfs_fattr *fp;
1841
1842 if (after_ret) {
1843 nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED);
1844 *tl = nfs_false;
1845 } else {
1846 nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_V3FATTR);
1847 *tl++ = nfs_true;
1848 fp = (struct nfs_fattr *)tl;
1849 nfsm_srvfattr(nfsd, after_vap, fp);
1850 }
1851 *mbp = mb;
1852 *bposp = bpos;
1853}
1854
1855void
1856nfsm_srvfattr(nfsd, vap, fp)
1857 register struct nfsrv_descript *nfsd;
1858 register struct vattr *vap;
1859 register struct nfs_fattr *fp;
1860{
1861
1862 fp->fa_nlink = txdr_unsigned(vap->va_nlink);
1863 fp->fa_uid = txdr_unsigned(vap->va_uid);
1864 fp->fa_gid = txdr_unsigned(vap->va_gid);
1865 if (nfsd->nd_flag & ND_NFSV3) {
1866 fp->fa_type = vtonfsv3_type(vap->va_type);
1867 fp->fa_mode = vtonfsv3_mode(vap->va_mode);
1868 txdr_hyper(vap->va_size, &fp->fa3_size);
1869 txdr_hyper(vap->va_bytes, &fp->fa3_used);
1870 fp->fa3_rdev.specdata1 = txdr_unsigned(umajor(vap->va_rdev));
1871 fp->fa3_rdev.specdata2 = txdr_unsigned(uminor(vap->va_rdev));
1872 fp->fa3_fsid.nfsuquad[0] = 0;
1873 fp->fa3_fsid.nfsuquad[1] = txdr_unsigned(vap->va_fsid);
1874 fp->fa3_fileid.nfsuquad[0] = 0;
1875 fp->fa3_fileid.nfsuquad[1] = txdr_unsigned(vap->va_fileid);
1876 txdr_nfsv3time(&vap->va_atime, &fp->fa3_atime);
1877 txdr_nfsv3time(&vap->va_mtime, &fp->fa3_mtime);
1878 txdr_nfsv3time(&vap->va_ctime, &fp->fa3_ctime);
1879 } else {
1880 fp->fa_type = vtonfsv2_type(vap->va_type);
1881 fp->fa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode);
1882 fp->fa2_size = txdr_unsigned(vap->va_size);
1883 fp->fa2_blocksize = txdr_unsigned(vap->va_blocksize);
1884 if (vap->va_type == VFIFO)
1885 fp->fa2_rdev = 0xffffffff;
1886 else
1887 fp->fa2_rdev = txdr_unsigned(vap->va_rdev);
1888 fp->fa2_blocks = txdr_unsigned(vap->va_bytes / NFS_FABLKSIZE);
1889 fp->fa2_fsid = txdr_unsigned(vap->va_fsid);
1890 fp->fa2_fileid = txdr_unsigned(vap->va_fileid);
1891 txdr_nfsv2time(&vap->va_atime, &fp->fa2_atime);
1892 txdr_nfsv2time(&vap->va_mtime, &fp->fa2_mtime);
1893 txdr_nfsv2time(&vap->va_ctime, &fp->fa2_ctime);
1894 }
1895}
1896
1897/*
1898 * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked)
1899 * - look up fsid in mount list (if not found ret error)
1900 * - get vp and export rights by calling VFS_FHTOVP()
1901 * - if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon
1902 * - if not lockflag unlock it with VOP_UNLOCK()
1903 */
1904int
1905nfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp, kerbflag, pubflag)
1906 fhandle_t *fhp;
1907 int lockflag;
1908 struct vnode **vpp;
1909 struct ucred *cred;
1910 struct nfssvc_sock *slp;
1911 struct sockaddr *nam;
1912 int *rdonlyp;
1913 int kerbflag;
1914 int pubflag;
1915{
1916 struct proc *p = curproc; /* XXX */
1917 register struct mount *mp;
1918 register int i;
1919 struct ucred *credanon;
1920 int error, exflags;
1921#ifdef MNT_EXNORESPORT /* XXX needs mountd and /etc/exports help yet */
1922 struct sockaddr_int *saddr;
1923#endif
1924
1925 *vpp = (struct vnode *)0;
1926
1927 if (nfs_ispublicfh(fhp)) {
1928 if (!pubflag || !nfs_pub.np_valid)
1929 return (ESTALE);
1930 fhp = &nfs_pub.np_handle;
1931 }
1932
1933 mp = vfs_getvfs(&fhp->fh_fsid);
1934 if (!mp)
1935 return (ESTALE);
1936 error = VFS_CHECKEXP(mp, nam, &exflags, &credanon);
1937 if (error)
1938 return (error);
1939 error = VFS_FHTOVP(mp, &fhp->fh_fid, vpp);
1940 if (error)
1941 return (error);
1942#ifdef MNT_EXNORESPORT
1943 if (!(exflags & (MNT_EXNORESPORT|MNT_EXPUBLIC))) {
1944 saddr = (struct sockaddr_in *)nam;
1945 if (saddr->sin_family == AF_INET &&
1946 ntohs(saddr->sin_port) >= IPPORT_RESERVED) {
1947 vput(*vpp);
1948 *vpp = NULL;
1949 return (NFSERR_AUTHERR | AUTH_TOOWEAK);
1950 }
1951 }
1952#endif
1953 /*
1954 * Check/setup credentials.
1955 */
1956 if (exflags & MNT_EXKERB) {
1957 if (!kerbflag) {
1958 vput(*vpp);
1959 *vpp = NULL;
1960 return (NFSERR_AUTHERR | AUTH_TOOWEAK);
1961 }
1962 } else if (kerbflag) {
1963 vput(*vpp);
1964 *vpp = NULL;
1965 return (NFSERR_AUTHERR | AUTH_TOOWEAK);
1966 } else if (cred->cr_uid == 0 || (exflags & MNT_EXPORTANON)) {
1967 cred->cr_uid = credanon->cr_uid;
1968 for (i = 0; i < credanon->cr_ngroups && i < NGROUPS; i++)
1969 cred->cr_groups[i] = credanon->cr_groups[i];
1970 cred->cr_ngroups = i;
1971 }
1972 if (exflags & MNT_EXRDONLY)
1973 *rdonlyp = 1;
1974 else
1975 *rdonlyp = 0;
1976
1977 nfsrv_object_create(*vpp);
1978
1979 if (!lockflag)
1980 VOP_UNLOCK(*vpp, 0, p);
1981 return (0);
1982}
1983
1984
1985/*
1986 * WebNFS: check if a filehandle is a public filehandle. For v3, this
1987 * means a length of 0, for v2 it means all zeroes. nfsm_srvmtofh has
1988 * transformed this to all zeroes in both cases, so check for it.
1989 */
1990int
1991nfs_ispublicfh(fhp)
1992 fhandle_t *fhp;
1993{
1994 char *cp = (char *)fhp;
1995 int i;
1996
1997 for (i = 0; i < NFSX_V3FH; i++)
1998 if (*cp++ != 0)
1999 return (FALSE);
2000 return (TRUE);
2001}
2002
2003#endif /* NFS_NOSERVER */
2004/*
2005 * This function compares two net addresses by family and returns TRUE
2006 * if they are the same host.
2007 * If there is any doubt, return FALSE.
2008 * The AF_INET family is handled as a special case so that address mbufs
2009 * don't need to be saved to store "struct in_addr", which is only 4 bytes.
2010 */
2011int
2012netaddr_match(family, haddr, nam)
2013 int family;
2014 union nethostaddr *haddr;
2015 struct sockaddr *nam;
2016{
2017 register struct sockaddr_in *inetaddr;
2018
2019 switch (family) {
2020 case AF_INET:
2021 inetaddr = (struct sockaddr_in *)nam;
2022 if (inetaddr->sin_family == AF_INET &&
2023 inetaddr->sin_addr.s_addr == haddr->had_inetaddr)
2024 return (1);
2025 break;
2026 default:
2027 break;
2028 };
2029 return (0);
2030}
2031
2032static nfsuint64 nfs_nullcookie = { { 0, 0 } };
2033/*
2034 * This function finds the directory cookie that corresponds to the
2035 * logical byte offset given.
2036 */
2037nfsuint64 *
2038nfs_getcookie(np, off, add)
2039 register struct nfsnode *np;
2040 off_t off;
2041 int add;
2042{
2043 register struct nfsdmap *dp, *dp2;
2044 register int pos;
2045
2046 pos = (uoff_t)off / NFS_DIRBLKSIZ;
2047 if (pos == 0 || off < 0) {
2048#ifdef DIAGNOSTIC
2049 if (add)
2050 panic("nfs getcookie add at <= 0");
2051#endif
2052 return (&nfs_nullcookie);
2053 }
2054 pos--;
2055 dp = np->n_cookies.lh_first;
2056 if (!dp) {
2057 if (add) {
2058 MALLOC(dp, struct nfsdmap *, sizeof (struct nfsdmap),
2059 M_NFSDIROFF, M_WAITOK);
2060 dp->ndm_eocookie = 0;
2061 LIST_INSERT_HEAD(&np->n_cookies, dp, ndm_list);
2062 } else
2063 return ((nfsuint64 *)0);
2064 }
2065 while (pos >= NFSNUMCOOKIES) {
2066 pos -= NFSNUMCOOKIES;
2067 if (dp->ndm_list.le_next) {
2068 if (!add && dp->ndm_eocookie < NFSNUMCOOKIES &&
2069 pos >= dp->ndm_eocookie)
2070 return ((nfsuint64 *)0);
2071 dp = dp->ndm_list.le_next;
2072 } else if (add) {
2073 MALLOC(dp2, struct nfsdmap *, sizeof (struct nfsdmap),
2074 M_NFSDIROFF, M_WAITOK);
2075 dp2->ndm_eocookie = 0;
2076 LIST_INSERT_AFTER(dp, dp2, ndm_list);
2077 dp = dp2;
2078 } else
2079 return ((nfsuint64 *)0);
2080 }
2081 if (pos >= dp->ndm_eocookie) {
2082 if (add)
2083 dp->ndm_eocookie = pos + 1;
2084 else
2085 return ((nfsuint64 *)0);
2086 }
2087 return (&dp->ndm_cookies[pos]);
2088}
2089
2090/*
2091 * Invalidate cached directory information, except for the actual directory
2092 * blocks (which are invalidated separately).
2093 * Done mainly to avoid the use of stale offset cookies.
2094 */
2095void
2096nfs_invaldir(vp)
2097 register struct vnode *vp;
2098{
2099 register struct nfsnode *np = VTONFS(vp);
2100
2101#ifdef DIAGNOSTIC
2102 if (vp->v_type != VDIR)
2103 panic("nfs: invaldir not dir");
2104#endif
2105 np->n_direofoffset = 0;
2106 np->n_cookieverf.nfsuquad[0] = 0;
2107 np->n_cookieverf.nfsuquad[1] = 0;
2108 if (np->n_cookies.lh_first)
2109 np->n_cookies.lh_first->ndm_eocookie = 0;
2110}
2111
2112/*
2113 * The write verifier has changed (probably due to a server reboot), so all
2114 * B_NEEDCOMMIT blocks will have to be written again. Since they are on the
2115 * dirty block list as B_DELWRI, all this takes is clearing the B_NEEDCOMMIT
2116 * and B_CLUSTEROK flags. Once done the new write verifier can be set for the
2117 * mount point.
2118 *
2119 * B_CLUSTEROK must be cleared along with B_NEEDCOMMIT because stage 1 data
2120 * writes are not clusterable.
2121 */
2122void
2123nfs_clearcommit(mp)
2124 struct mount *mp;
2125{
2126 register struct vnode *vp, *nvp;
2127 register struct buf *bp, *nbp;
2128 int s;
2129
2130 s = splbio();
2131loop:
2132 for (vp = mp->mnt_vnodelist.lh_first; vp; vp = nvp) {
2133 if (vp->v_mount != mp) /* Paranoia */
2134 goto loop;
2135 nvp = vp->v_mntvnodes.le_next;
2136 for (bp = TAILQ_FIRST(&vp->v_dirtyblkhd); bp; bp = nbp) {
2137 nbp = TAILQ_NEXT(bp, b_vnbufs);
2138 if (BUF_REFCNT(bp) == 0 &&
2139 (bp->b_flags & (B_DELWRI | B_NEEDCOMMIT))
2140 == (B_DELWRI | B_NEEDCOMMIT))
2141 bp->b_flags &= ~(B_NEEDCOMMIT | B_CLUSTEROK);
2142 }
2143 }
2144 splx(s);
2145}
2146
2147#ifndef NFS_NOSERVER
2148/*
2149 * Map errnos to NFS error numbers. For Version 3 also filter out error
2150 * numbers not specified for the associated procedure.
2151 */
2152int
2153nfsrv_errmap(nd, err)
2154 struct nfsrv_descript *nd;
2155 register int err;
2156{
2157 register short *defaulterrp, *errp;
2158
2159 if (nd->nd_flag & ND_NFSV3) {
2160 if (nd->nd_procnum <= NFSPROC_COMMIT) {
2161 errp = defaulterrp = nfsrv_v3errmap[nd->nd_procnum];
2162 while (*++errp) {
2163 if (*errp == err)
2164 return (err);
2165 else if (*errp > err)
2166 break;
2167 }
2168 return ((int)*defaulterrp);
2169 } else
2170 return (err & 0xffff);
2171 }
2172 if (err <= ELAST)
2173 return ((int)nfsrv_v2errmap[err - 1]);
2174 return (NFSERR_IO);
2175}
2176
2177int
2178nfsrv_object_create(vp)
2179 struct vnode *vp;
2180{
2181
2182 if (vp == NULL || vp->v_type != VREG)
2183 return (1);
2184 return (vfs_object_create(vp, curproc,
2185 curproc ? curproc->p_ucred : NULL));
2186}
2187
2188/*
2189 * Sort the group list in increasing numerical order.
2190 * (Insertion sort by Chris Torek, who was grossed out by the bubble sort
2191 * that used to be here.)
2192 */
2193void
2194nfsrvw_sort(list, num)
2195 register gid_t *list;
2196 register int num;
2197{
2198 register int i, j;
2199 gid_t v;
2200
2201 /* Insertion sort. */
2202 for (i = 1; i < num; i++) {
2203 v = list[i];
2204 /* find correct slot for value v, moving others up */
2205 for (j = i; --j >= 0 && v < list[j];)
2206 list[j + 1] = list[j];
2207 list[j + 1] = v;
2208 }
2209}
2210
2211/*
2212 * copy credentials making sure that the result can be compared with bcmp().
2213 */
2214void
2215nfsrv_setcred(incred, outcred)
2216 register struct ucred *incred, *outcred;
2217{
2218 register int i;
2219
2220 bzero((caddr_t)outcred, sizeof (struct ucred));
2221 outcred->cr_ref = 1;
2222 outcred->cr_uid = incred->cr_uid;
2223 outcred->cr_ngroups = incred->cr_ngroups;
2224 for (i = 0; i < incred->cr_ngroups; i++)
2225 outcred->cr_groups[i] = incred->cr_groups[i];
2226 nfsrvw_sort(outcred->cr_groups, outcred->cr_ngroups);
2227}
2228#endif /* NFS_NOSERVER */
49#include <sys/buf.h>
50#include <sys/proc.h>
51#include <sys/mount.h>
52#include <sys/vnode.h>
53#include <sys/namei.h>
54#include <sys/mbuf.h>
55#include <sys/socket.h>
56#include <sys/stat.h>
57#include <sys/malloc.h>
58#include <sys/sysent.h>
59#include <sys/syscall.h>
60
61#include <vm/vm.h>
62#include <vm/vm_object.h>
63#include <vm/vm_extern.h>
64#include <vm/vm_zone.h>
65
66#include <nfs/rpcv2.h>
67#include <nfs/nfsproto.h>
68#include <nfs/nfs.h>
69#include <nfs/nfsnode.h>
70#include <nfs/xdr_subs.h>
71#include <nfs/nfsm_subs.h>
72#include <nfs/nfsmount.h>
73#include <nfs/nqnfs.h>
74#include <nfs/nfsrtt.h>
75
76#include <netinet/in.h>
77
78/*
79 * Data items converted to xdr at startup, since they are constant
80 * This is kinda hokey, but may save a little time doing byte swaps
81 */
82u_int32_t nfs_xdrneg1;
83u_int32_t rpc_call, rpc_vers, rpc_reply, rpc_msgdenied, rpc_autherr,
84 rpc_mismatch, rpc_auth_unix, rpc_msgaccepted,
85 rpc_auth_kerb;
86u_int32_t nfs_prog, nqnfs_prog, nfs_true, nfs_false;
87
88/* And other global data */
89static u_int32_t nfs_xid = 0;
90static enum vtype nv2tov_type[8]= {
91 VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON, VNON
92};
93enum vtype nv3tov_type[8]= {
94 VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO
95};
96
97int nfs_ticks;
98int nfs_pbuf_freecnt = -1; /* start out unlimited */
99
100struct nfs_reqq nfs_reqq;
101struct nfssvc_sockhead nfssvc_sockhead;
102int nfssvc_sockhead_flag;
103struct nfsd_head nfsd_head;
104int nfsd_head_flag;
105struct nfs_bufq nfs_bufq;
106struct nqtimerhead nqtimerhead;
107struct nqfhhashhead *nqfhhashtbl;
108u_long nqfhhash;
109
110static void (*nfs_prev_lease_updatetime) __P((int));
111static int nfs_prev_nfssvc_sy_narg;
112static sy_call_t *nfs_prev_nfssvc_sy_call;
113
114#ifndef NFS_NOSERVER
115
116static vop_t *nfs_prev_vop_lease_check;
117
118/*
119 * Mapping of old NFS Version 2 RPC numbers to generic numbers.
120 */
121int nfsv3_procid[NFS_NPROCS] = {
122 NFSPROC_NULL,
123 NFSPROC_GETATTR,
124 NFSPROC_SETATTR,
125 NFSPROC_NOOP,
126 NFSPROC_LOOKUP,
127 NFSPROC_READLINK,
128 NFSPROC_READ,
129 NFSPROC_NOOP,
130 NFSPROC_WRITE,
131 NFSPROC_CREATE,
132 NFSPROC_REMOVE,
133 NFSPROC_RENAME,
134 NFSPROC_LINK,
135 NFSPROC_SYMLINK,
136 NFSPROC_MKDIR,
137 NFSPROC_RMDIR,
138 NFSPROC_READDIR,
139 NFSPROC_FSSTAT,
140 NFSPROC_NOOP,
141 NFSPROC_NOOP,
142 NFSPROC_NOOP,
143 NFSPROC_NOOP,
144 NFSPROC_NOOP,
145 NFSPROC_NOOP,
146 NFSPROC_NOOP,
147 NFSPROC_NOOP
148};
149
150#endif /* NFS_NOSERVER */
151/*
152 * and the reverse mapping from generic to Version 2 procedure numbers
153 */
154int nfsv2_procid[NFS_NPROCS] = {
155 NFSV2PROC_NULL,
156 NFSV2PROC_GETATTR,
157 NFSV2PROC_SETATTR,
158 NFSV2PROC_LOOKUP,
159 NFSV2PROC_NOOP,
160 NFSV2PROC_READLINK,
161 NFSV2PROC_READ,
162 NFSV2PROC_WRITE,
163 NFSV2PROC_CREATE,
164 NFSV2PROC_MKDIR,
165 NFSV2PROC_SYMLINK,
166 NFSV2PROC_CREATE,
167 NFSV2PROC_REMOVE,
168 NFSV2PROC_RMDIR,
169 NFSV2PROC_RENAME,
170 NFSV2PROC_LINK,
171 NFSV2PROC_READDIR,
172 NFSV2PROC_NOOP,
173 NFSV2PROC_STATFS,
174 NFSV2PROC_NOOP,
175 NFSV2PROC_NOOP,
176 NFSV2PROC_NOOP,
177 NFSV2PROC_NOOP,
178 NFSV2PROC_NOOP,
179 NFSV2PROC_NOOP,
180 NFSV2PROC_NOOP,
181};
182
183#ifndef NFS_NOSERVER
184/*
185 * Maps errno values to nfs error numbers.
186 * Use NFSERR_IO as the catch all for ones not specifically defined in
187 * RFC 1094.
188 */
189static u_char nfsrv_v2errmap[ELAST] = {
190 NFSERR_PERM, NFSERR_NOENT, NFSERR_IO, NFSERR_IO, NFSERR_IO,
191 NFSERR_NXIO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
192 NFSERR_IO, NFSERR_IO, NFSERR_ACCES, NFSERR_IO, NFSERR_IO,
193 NFSERR_IO, NFSERR_EXIST, NFSERR_IO, NFSERR_NODEV, NFSERR_NOTDIR,
194 NFSERR_ISDIR, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
195 NFSERR_IO, NFSERR_FBIG, NFSERR_NOSPC, NFSERR_IO, NFSERR_ROFS,
196 NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
197 NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
198 NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
199 NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
200 NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
201 NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
202 NFSERR_IO, NFSERR_IO, NFSERR_NAMETOL, NFSERR_IO, NFSERR_IO,
203 NFSERR_NOTEMPTY, NFSERR_IO, NFSERR_IO, NFSERR_DQUOT, NFSERR_STALE,
204 NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
205 NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
206 NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
207 NFSERR_IO /* << Last is 86 */
208};
209
210/*
211 * Maps errno values to nfs error numbers.
212 * Although it is not obvious whether or not NFS clients really care if
213 * a returned error value is in the specified list for the procedure, the
214 * safest thing to do is filter them appropriately. For Version 2, the
215 * X/Open XNFS document is the only specification that defines error values
216 * for each RPC (The RFC simply lists all possible error values for all RPCs),
217 * so I have decided to not do this for Version 2.
218 * The first entry is the default error return and the rest are the valid
219 * errors for that RPC in increasing numeric order.
220 */
221static short nfsv3err_null[] = {
222 0,
223 0,
224};
225
226static short nfsv3err_getattr[] = {
227 NFSERR_IO,
228 NFSERR_IO,
229 NFSERR_STALE,
230 NFSERR_BADHANDLE,
231 NFSERR_SERVERFAULT,
232 0,
233};
234
235static short nfsv3err_setattr[] = {
236 NFSERR_IO,
237 NFSERR_PERM,
238 NFSERR_IO,
239 NFSERR_ACCES,
240 NFSERR_INVAL,
241 NFSERR_NOSPC,
242 NFSERR_ROFS,
243 NFSERR_DQUOT,
244 NFSERR_STALE,
245 NFSERR_BADHANDLE,
246 NFSERR_NOT_SYNC,
247 NFSERR_SERVERFAULT,
248 0,
249};
250
251static short nfsv3err_lookup[] = {
252 NFSERR_IO,
253 NFSERR_NOENT,
254 NFSERR_IO,
255 NFSERR_ACCES,
256 NFSERR_NOTDIR,
257 NFSERR_NAMETOL,
258 NFSERR_STALE,
259 NFSERR_BADHANDLE,
260 NFSERR_SERVERFAULT,
261 0,
262};
263
264static short nfsv3err_access[] = {
265 NFSERR_IO,
266 NFSERR_IO,
267 NFSERR_STALE,
268 NFSERR_BADHANDLE,
269 NFSERR_SERVERFAULT,
270 0,
271};
272
273static short nfsv3err_readlink[] = {
274 NFSERR_IO,
275 NFSERR_IO,
276 NFSERR_ACCES,
277 NFSERR_INVAL,
278 NFSERR_STALE,
279 NFSERR_BADHANDLE,
280 NFSERR_NOTSUPP,
281 NFSERR_SERVERFAULT,
282 0,
283};
284
285static short nfsv3err_read[] = {
286 NFSERR_IO,
287 NFSERR_IO,
288 NFSERR_NXIO,
289 NFSERR_ACCES,
290 NFSERR_INVAL,
291 NFSERR_STALE,
292 NFSERR_BADHANDLE,
293 NFSERR_SERVERFAULT,
294 0,
295};
296
297static short nfsv3err_write[] = {
298 NFSERR_IO,
299 NFSERR_IO,
300 NFSERR_ACCES,
301 NFSERR_INVAL,
302 NFSERR_FBIG,
303 NFSERR_NOSPC,
304 NFSERR_ROFS,
305 NFSERR_DQUOT,
306 NFSERR_STALE,
307 NFSERR_BADHANDLE,
308 NFSERR_SERVERFAULT,
309 0,
310};
311
312static short nfsv3err_create[] = {
313 NFSERR_IO,
314 NFSERR_IO,
315 NFSERR_ACCES,
316 NFSERR_EXIST,
317 NFSERR_NOTDIR,
318 NFSERR_NOSPC,
319 NFSERR_ROFS,
320 NFSERR_NAMETOL,
321 NFSERR_DQUOT,
322 NFSERR_STALE,
323 NFSERR_BADHANDLE,
324 NFSERR_NOTSUPP,
325 NFSERR_SERVERFAULT,
326 0,
327};
328
329static short nfsv3err_mkdir[] = {
330 NFSERR_IO,
331 NFSERR_IO,
332 NFSERR_ACCES,
333 NFSERR_EXIST,
334 NFSERR_NOTDIR,
335 NFSERR_NOSPC,
336 NFSERR_ROFS,
337 NFSERR_NAMETOL,
338 NFSERR_DQUOT,
339 NFSERR_STALE,
340 NFSERR_BADHANDLE,
341 NFSERR_NOTSUPP,
342 NFSERR_SERVERFAULT,
343 0,
344};
345
346static short nfsv3err_symlink[] = {
347 NFSERR_IO,
348 NFSERR_IO,
349 NFSERR_ACCES,
350 NFSERR_EXIST,
351 NFSERR_NOTDIR,
352 NFSERR_NOSPC,
353 NFSERR_ROFS,
354 NFSERR_NAMETOL,
355 NFSERR_DQUOT,
356 NFSERR_STALE,
357 NFSERR_BADHANDLE,
358 NFSERR_NOTSUPP,
359 NFSERR_SERVERFAULT,
360 0,
361};
362
363static short nfsv3err_mknod[] = {
364 NFSERR_IO,
365 NFSERR_IO,
366 NFSERR_ACCES,
367 NFSERR_EXIST,
368 NFSERR_NOTDIR,
369 NFSERR_NOSPC,
370 NFSERR_ROFS,
371 NFSERR_NAMETOL,
372 NFSERR_DQUOT,
373 NFSERR_STALE,
374 NFSERR_BADHANDLE,
375 NFSERR_NOTSUPP,
376 NFSERR_SERVERFAULT,
377 NFSERR_BADTYPE,
378 0,
379};
380
381static short nfsv3err_remove[] = {
382 NFSERR_IO,
383 NFSERR_NOENT,
384 NFSERR_IO,
385 NFSERR_ACCES,
386 NFSERR_NOTDIR,
387 NFSERR_ROFS,
388 NFSERR_NAMETOL,
389 NFSERR_STALE,
390 NFSERR_BADHANDLE,
391 NFSERR_SERVERFAULT,
392 0,
393};
394
395static short nfsv3err_rmdir[] = {
396 NFSERR_IO,
397 NFSERR_NOENT,
398 NFSERR_IO,
399 NFSERR_ACCES,
400 NFSERR_EXIST,
401 NFSERR_NOTDIR,
402 NFSERR_INVAL,
403 NFSERR_ROFS,
404 NFSERR_NAMETOL,
405 NFSERR_NOTEMPTY,
406 NFSERR_STALE,
407 NFSERR_BADHANDLE,
408 NFSERR_NOTSUPP,
409 NFSERR_SERVERFAULT,
410 0,
411};
412
413static short nfsv3err_rename[] = {
414 NFSERR_IO,
415 NFSERR_NOENT,
416 NFSERR_IO,
417 NFSERR_ACCES,
418 NFSERR_EXIST,
419 NFSERR_XDEV,
420 NFSERR_NOTDIR,
421 NFSERR_ISDIR,
422 NFSERR_INVAL,
423 NFSERR_NOSPC,
424 NFSERR_ROFS,
425 NFSERR_MLINK,
426 NFSERR_NAMETOL,
427 NFSERR_NOTEMPTY,
428 NFSERR_DQUOT,
429 NFSERR_STALE,
430 NFSERR_BADHANDLE,
431 NFSERR_NOTSUPP,
432 NFSERR_SERVERFAULT,
433 0,
434};
435
436static short nfsv3err_link[] = {
437 NFSERR_IO,
438 NFSERR_IO,
439 NFSERR_ACCES,
440 NFSERR_EXIST,
441 NFSERR_XDEV,
442 NFSERR_NOTDIR,
443 NFSERR_INVAL,
444 NFSERR_NOSPC,
445 NFSERR_ROFS,
446 NFSERR_MLINK,
447 NFSERR_NAMETOL,
448 NFSERR_DQUOT,
449 NFSERR_STALE,
450 NFSERR_BADHANDLE,
451 NFSERR_NOTSUPP,
452 NFSERR_SERVERFAULT,
453 0,
454};
455
456static short nfsv3err_readdir[] = {
457 NFSERR_IO,
458 NFSERR_IO,
459 NFSERR_ACCES,
460 NFSERR_NOTDIR,
461 NFSERR_STALE,
462 NFSERR_BADHANDLE,
463 NFSERR_BAD_COOKIE,
464 NFSERR_TOOSMALL,
465 NFSERR_SERVERFAULT,
466 0,
467};
468
469static short nfsv3err_readdirplus[] = {
470 NFSERR_IO,
471 NFSERR_IO,
472 NFSERR_ACCES,
473 NFSERR_NOTDIR,
474 NFSERR_STALE,
475 NFSERR_BADHANDLE,
476 NFSERR_BAD_COOKIE,
477 NFSERR_NOTSUPP,
478 NFSERR_TOOSMALL,
479 NFSERR_SERVERFAULT,
480 0,
481};
482
483static short nfsv3err_fsstat[] = {
484 NFSERR_IO,
485 NFSERR_IO,
486 NFSERR_STALE,
487 NFSERR_BADHANDLE,
488 NFSERR_SERVERFAULT,
489 0,
490};
491
492static short nfsv3err_fsinfo[] = {
493 NFSERR_STALE,
494 NFSERR_STALE,
495 NFSERR_BADHANDLE,
496 NFSERR_SERVERFAULT,
497 0,
498};
499
500static short nfsv3err_pathconf[] = {
501 NFSERR_STALE,
502 NFSERR_STALE,
503 NFSERR_BADHANDLE,
504 NFSERR_SERVERFAULT,
505 0,
506};
507
508static short nfsv3err_commit[] = {
509 NFSERR_IO,
510 NFSERR_IO,
511 NFSERR_STALE,
512 NFSERR_BADHANDLE,
513 NFSERR_SERVERFAULT,
514 0,
515};
516
517static short *nfsrv_v3errmap[] = {
518 nfsv3err_null,
519 nfsv3err_getattr,
520 nfsv3err_setattr,
521 nfsv3err_lookup,
522 nfsv3err_access,
523 nfsv3err_readlink,
524 nfsv3err_read,
525 nfsv3err_write,
526 nfsv3err_create,
527 nfsv3err_mkdir,
528 nfsv3err_symlink,
529 nfsv3err_mknod,
530 nfsv3err_remove,
531 nfsv3err_rmdir,
532 nfsv3err_rename,
533 nfsv3err_link,
534 nfsv3err_readdir,
535 nfsv3err_readdirplus,
536 nfsv3err_fsstat,
537 nfsv3err_fsinfo,
538 nfsv3err_pathconf,
539 nfsv3err_commit,
540};
541
542#endif /* NFS_NOSERVER */
543
544extern struct nfsrtt nfsrtt;
545extern time_t nqnfsstarttime;
546extern int nqsrv_clockskew;
547extern int nqsrv_writeslack;
548extern int nqsrv_maxlease;
549extern struct nfsstats nfsstats;
550extern int nqnfs_piggy[NFS_NPROCS];
551extern nfstype nfsv2_type[9];
552extern nfstype nfsv3_type[9];
553extern struct nfsnodehashhead *nfsnodehashtbl;
554extern u_long nfsnodehash;
555
556struct nfssvc_args;
557extern int nfssvc(struct proc *, struct nfssvc_args *, int *);
558
559LIST_HEAD(nfsnodehashhead, nfsnode);
560
561int nfs_webnamei __P((struct nameidata *, struct vnode *, struct proc *));
562
563u_quad_t
564nfs_curusec()
565{
566 struct timeval tv;
567
568 getmicrotime(&tv);
569 return ((u_quad_t)tv.tv_sec * 1000000 + (u_quad_t)tv.tv_usec);
570}
571
572/*
573 * Create the header for an rpc request packet
574 * The hsiz is the size of the rest of the nfs request header.
575 * (just used to decide if a cluster is a good idea)
576 */
577struct mbuf *
578nfsm_reqh(vp, procid, hsiz, bposp)
579 struct vnode *vp;
580 u_long procid;
581 int hsiz;
582 caddr_t *bposp;
583{
584 register struct mbuf *mb;
585 register u_int32_t *tl;
586 register caddr_t bpos;
587 struct mbuf *mb2;
588 struct nfsmount *nmp;
589 int nqflag;
590
591 MGET(mb, M_WAIT, MT_DATA);
592 if (hsiz >= MINCLSIZE)
593 MCLGET(mb, M_WAIT);
594 mb->m_len = 0;
595 bpos = mtod(mb, caddr_t);
596
597 /*
598 * For NQNFS, add lease request.
599 */
600 if (vp) {
601 nmp = VFSTONFS(vp->v_mount);
602 if (nmp->nm_flag & NFSMNT_NQNFS) {
603 nqflag = NQNFS_NEEDLEASE(vp, procid);
604 if (nqflag) {
605 nfsm_build(tl, u_int32_t *, 2*NFSX_UNSIGNED);
606 *tl++ = txdr_unsigned(nqflag);
607 *tl = txdr_unsigned(nmp->nm_leaseterm);
608 } else {
609 nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED);
610 *tl = 0;
611 }
612 }
613 }
614 /* Finally, return values */
615 *bposp = bpos;
616 return (mb);
617}
618
619/*
620 * Build the RPC header and fill in the authorization info.
621 * The authorization string argument is only used when the credentials
622 * come from outside of the kernel.
623 * Returns the head of the mbuf list.
624 */
625struct mbuf *
626nfsm_rpchead(cr, nmflag, procid, auth_type, auth_len, auth_str, verf_len,
627 verf_str, mrest, mrest_len, mbp, xidp)
628 register struct ucred *cr;
629 int nmflag;
630 int procid;
631 int auth_type;
632 int auth_len;
633 char *auth_str;
634 int verf_len;
635 char *verf_str;
636 struct mbuf *mrest;
637 int mrest_len;
638 struct mbuf **mbp;
639 u_int32_t *xidp;
640{
641 register struct mbuf *mb;
642 register u_int32_t *tl;
643 register caddr_t bpos;
644 register int i;
645 struct mbuf *mreq, *mb2;
646 int siz, grpsiz, authsiz;
647
648 authsiz = nfsm_rndup(auth_len);
649 MGETHDR(mb, M_WAIT, MT_DATA);
650 if ((authsiz + 10 * NFSX_UNSIGNED) >= MINCLSIZE) {
651 MCLGET(mb, M_WAIT);
652 } else if ((authsiz + 10 * NFSX_UNSIGNED) < MHLEN) {
653 MH_ALIGN(mb, authsiz + 10 * NFSX_UNSIGNED);
654 } else {
655 MH_ALIGN(mb, 8 * NFSX_UNSIGNED);
656 }
657 mb->m_len = 0;
658 mreq = mb;
659 bpos = mtod(mb, caddr_t);
660
661 /*
662 * First the RPC header.
663 */
664 nfsm_build(tl, u_int32_t *, 8 * NFSX_UNSIGNED);
665
666 /* Get a pretty random xid to start with */
667 if (!nfs_xid)
668 nfs_xid = random();
669 /*
670 * Skip zero xid if it should ever happen.
671 */
672 if (++nfs_xid == 0)
673 nfs_xid++;
674
675 *tl++ = *xidp = txdr_unsigned(nfs_xid);
676 *tl++ = rpc_call;
677 *tl++ = rpc_vers;
678 if (nmflag & NFSMNT_NQNFS) {
679 *tl++ = txdr_unsigned(NQNFS_PROG);
680 *tl++ = txdr_unsigned(NQNFS_VER3);
681 } else {
682 *tl++ = txdr_unsigned(NFS_PROG);
683 if (nmflag & NFSMNT_NFSV3)
684 *tl++ = txdr_unsigned(NFS_VER3);
685 else
686 *tl++ = txdr_unsigned(NFS_VER2);
687 }
688 if (nmflag & NFSMNT_NFSV3)
689 *tl++ = txdr_unsigned(procid);
690 else
691 *tl++ = txdr_unsigned(nfsv2_procid[procid]);
692
693 /*
694 * And then the authorization cred.
695 */
696 *tl++ = txdr_unsigned(auth_type);
697 *tl = txdr_unsigned(authsiz);
698 switch (auth_type) {
699 case RPCAUTH_UNIX:
700 nfsm_build(tl, u_int32_t *, auth_len);
701 *tl++ = 0; /* stamp ?? */
702 *tl++ = 0; /* NULL hostname */
703 *tl++ = txdr_unsigned(cr->cr_uid);
704 *tl++ = txdr_unsigned(cr->cr_groups[0]);
705 grpsiz = (auth_len >> 2) - 5;
706 *tl++ = txdr_unsigned(grpsiz);
707 for (i = 1; i <= grpsiz; i++)
708 *tl++ = txdr_unsigned(cr->cr_groups[i]);
709 break;
710 case RPCAUTH_KERB4:
711 siz = auth_len;
712 while (siz > 0) {
713 if (M_TRAILINGSPACE(mb) == 0) {
714 MGET(mb2, M_WAIT, MT_DATA);
715 if (siz >= MINCLSIZE)
716 MCLGET(mb2, M_WAIT);
717 mb->m_next = mb2;
718 mb = mb2;
719 mb->m_len = 0;
720 bpos = mtod(mb, caddr_t);
721 }
722 i = min(siz, M_TRAILINGSPACE(mb));
723 bcopy(auth_str, bpos, i);
724 mb->m_len += i;
725 auth_str += i;
726 bpos += i;
727 siz -= i;
728 }
729 if ((siz = (nfsm_rndup(auth_len) - auth_len)) > 0) {
730 for (i = 0; i < siz; i++)
731 *bpos++ = '\0';
732 mb->m_len += siz;
733 }
734 break;
735 };
736
737 /*
738 * And the verifier...
739 */
740 nfsm_build(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
741 if (verf_str) {
742 *tl++ = txdr_unsigned(RPCAUTH_KERB4);
743 *tl = txdr_unsigned(verf_len);
744 siz = verf_len;
745 while (siz > 0) {
746 if (M_TRAILINGSPACE(mb) == 0) {
747 MGET(mb2, M_WAIT, MT_DATA);
748 if (siz >= MINCLSIZE)
749 MCLGET(mb2, M_WAIT);
750 mb->m_next = mb2;
751 mb = mb2;
752 mb->m_len = 0;
753 bpos = mtod(mb, caddr_t);
754 }
755 i = min(siz, M_TRAILINGSPACE(mb));
756 bcopy(verf_str, bpos, i);
757 mb->m_len += i;
758 verf_str += i;
759 bpos += i;
760 siz -= i;
761 }
762 if ((siz = (nfsm_rndup(verf_len) - verf_len)) > 0) {
763 for (i = 0; i < siz; i++)
764 *bpos++ = '\0';
765 mb->m_len += siz;
766 }
767 } else {
768 *tl++ = txdr_unsigned(RPCAUTH_NULL);
769 *tl = 0;
770 }
771 mb->m_next = mrest;
772 mreq->m_pkthdr.len = authsiz + 10 * NFSX_UNSIGNED + mrest_len;
773 mreq->m_pkthdr.rcvif = (struct ifnet *)0;
774 *mbp = mb;
775 return (mreq);
776}
777
778/*
779 * copies mbuf chain to the uio scatter/gather list
780 */
781int
782nfsm_mbuftouio(mrep, uiop, siz, dpos)
783 struct mbuf **mrep;
784 register struct uio *uiop;
785 int siz;
786 caddr_t *dpos;
787{
788 register char *mbufcp, *uiocp;
789 register int xfer, left, len;
790 register struct mbuf *mp;
791 long uiosiz, rem;
792 int error = 0;
793
794 mp = *mrep;
795 mbufcp = *dpos;
796 len = mtod(mp, caddr_t)+mp->m_len-mbufcp;
797 rem = nfsm_rndup(siz)-siz;
798 while (siz > 0) {
799 if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL)
800 return (EFBIG);
801 left = uiop->uio_iov->iov_len;
802 uiocp = uiop->uio_iov->iov_base;
803 if (left > siz)
804 left = siz;
805 uiosiz = left;
806 while (left > 0) {
807 while (len == 0) {
808 mp = mp->m_next;
809 if (mp == NULL)
810 return (EBADRPC);
811 mbufcp = mtod(mp, caddr_t);
812 len = mp->m_len;
813 }
814 xfer = (left > len) ? len : left;
815#ifdef notdef
816 /* Not Yet.. */
817 if (uiop->uio_iov->iov_op != NULL)
818 (*(uiop->uio_iov->iov_op))
819 (mbufcp, uiocp, xfer);
820 else
821#endif
822 if (uiop->uio_segflg == UIO_SYSSPACE)
823 bcopy(mbufcp, uiocp, xfer);
824 else
825 copyout(mbufcp, uiocp, xfer);
826 left -= xfer;
827 len -= xfer;
828 mbufcp += xfer;
829 uiocp += xfer;
830 uiop->uio_offset += xfer;
831 uiop->uio_resid -= xfer;
832 }
833 if (uiop->uio_iov->iov_len <= siz) {
834 uiop->uio_iovcnt--;
835 uiop->uio_iov++;
836 } else {
837 uiop->uio_iov->iov_base += uiosiz;
838 uiop->uio_iov->iov_len -= uiosiz;
839 }
840 siz -= uiosiz;
841 }
842 *dpos = mbufcp;
843 *mrep = mp;
844 if (rem > 0) {
845 if (len < rem)
846 error = nfs_adv(mrep, dpos, rem, len);
847 else
848 *dpos += rem;
849 }
850 return (error);
851}
852
853/*
854 * copies a uio scatter/gather list to an mbuf chain.
855 * NOTE: can ony handle iovcnt == 1
856 */
857int
858nfsm_uiotombuf(uiop, mq, siz, bpos)
859 register struct uio *uiop;
860 struct mbuf **mq;
861 int siz;
862 caddr_t *bpos;
863{
864 register char *uiocp;
865 register struct mbuf *mp, *mp2;
866 register int xfer, left, mlen;
867 int uiosiz, clflg, rem;
868 char *cp;
869
870#ifdef DIAGNOSTIC
871 if (uiop->uio_iovcnt != 1)
872 panic("nfsm_uiotombuf: iovcnt != 1");
873#endif
874
875 if (siz > MLEN) /* or should it >= MCLBYTES ?? */
876 clflg = 1;
877 else
878 clflg = 0;
879 rem = nfsm_rndup(siz)-siz;
880 mp = mp2 = *mq;
881 while (siz > 0) {
882 left = uiop->uio_iov->iov_len;
883 uiocp = uiop->uio_iov->iov_base;
884 if (left > siz)
885 left = siz;
886 uiosiz = left;
887 while (left > 0) {
888 mlen = M_TRAILINGSPACE(mp);
889 if (mlen == 0) {
890 MGET(mp, M_WAIT, MT_DATA);
891 if (clflg)
892 MCLGET(mp, M_WAIT);
893 mp->m_len = 0;
894 mp2->m_next = mp;
895 mp2 = mp;
896 mlen = M_TRAILINGSPACE(mp);
897 }
898 xfer = (left > mlen) ? mlen : left;
899#ifdef notdef
900 /* Not Yet.. */
901 if (uiop->uio_iov->iov_op != NULL)
902 (*(uiop->uio_iov->iov_op))
903 (uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
904 else
905#endif
906 if (uiop->uio_segflg == UIO_SYSSPACE)
907 bcopy(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
908 else
909 copyin(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
910 mp->m_len += xfer;
911 left -= xfer;
912 uiocp += xfer;
913 uiop->uio_offset += xfer;
914 uiop->uio_resid -= xfer;
915 }
916 uiop->uio_iov->iov_base += uiosiz;
917 uiop->uio_iov->iov_len -= uiosiz;
918 siz -= uiosiz;
919 }
920 if (rem > 0) {
921 if (rem > M_TRAILINGSPACE(mp)) {
922 MGET(mp, M_WAIT, MT_DATA);
923 mp->m_len = 0;
924 mp2->m_next = mp;
925 }
926 cp = mtod(mp, caddr_t)+mp->m_len;
927 for (left = 0; left < rem; left++)
928 *cp++ = '\0';
929 mp->m_len += rem;
930 *bpos = cp;
931 } else
932 *bpos = mtod(mp, caddr_t)+mp->m_len;
933 *mq = mp;
934 return (0);
935}
936
937/*
938 * Help break down an mbuf chain by setting the first siz bytes contiguous
939 * pointed to by returned val.
940 * This is used by the macros nfsm_dissect and nfsm_dissecton for tough
941 * cases. (The macros use the vars. dpos and dpos2)
942 */
943int
944nfsm_disct(mdp, dposp, siz, left, cp2)
945 struct mbuf **mdp;
946 caddr_t *dposp;
947 int siz;
948 int left;
949 caddr_t *cp2;
950{
951 register struct mbuf *mp, *mp2;
952 register int siz2, xfer;
953 register caddr_t p;
954
955 mp = *mdp;
956 while (left == 0) {
957 *mdp = mp = mp->m_next;
958 if (mp == NULL)
959 return (EBADRPC);
960 left = mp->m_len;
961 *dposp = mtod(mp, caddr_t);
962 }
963 if (left >= siz) {
964 *cp2 = *dposp;
965 *dposp += siz;
966 } else if (mp->m_next == NULL) {
967 return (EBADRPC);
968 } else if (siz > MHLEN) {
969 panic("nfs S too big");
970 } else {
971 MGET(mp2, M_WAIT, MT_DATA);
972 mp2->m_next = mp->m_next;
973 mp->m_next = mp2;
974 mp->m_len -= left;
975 mp = mp2;
976 *cp2 = p = mtod(mp, caddr_t);
977 bcopy(*dposp, p, left); /* Copy what was left */
978 siz2 = siz-left;
979 p += left;
980 mp2 = mp->m_next;
981 /* Loop around copying up the siz2 bytes */
982 while (siz2 > 0) {
983 if (mp2 == NULL)
984 return (EBADRPC);
985 xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2;
986 if (xfer > 0) {
987 bcopy(mtod(mp2, caddr_t), p, xfer);
988 NFSMADV(mp2, xfer);
989 mp2->m_len -= xfer;
990 p += xfer;
991 siz2 -= xfer;
992 }
993 if (siz2 > 0)
994 mp2 = mp2->m_next;
995 }
996 mp->m_len = siz;
997 *mdp = mp2;
998 *dposp = mtod(mp2, caddr_t);
999 }
1000 return (0);
1001}
1002
1003/*
1004 * Advance the position in the mbuf chain.
1005 */
1006int
1007nfs_adv(mdp, dposp, offs, left)
1008 struct mbuf **mdp;
1009 caddr_t *dposp;
1010 int offs;
1011 int left;
1012{
1013 register struct mbuf *m;
1014 register int s;
1015
1016 m = *mdp;
1017 s = left;
1018 while (s < offs) {
1019 offs -= s;
1020 m = m->m_next;
1021 if (m == NULL)
1022 return (EBADRPC);
1023 s = m->m_len;
1024 }
1025 *mdp = m;
1026 *dposp = mtod(m, caddr_t)+offs;
1027 return (0);
1028}
1029
1030/*
1031 * Copy a string into mbufs for the hard cases...
1032 */
1033int
1034nfsm_strtmbuf(mb, bpos, cp, siz)
1035 struct mbuf **mb;
1036 char **bpos;
1037 const char *cp;
1038 long siz;
1039{
1040 register struct mbuf *m1 = NULL, *m2;
1041 long left, xfer, len, tlen;
1042 u_int32_t *tl;
1043 int putsize;
1044
1045 putsize = 1;
1046 m2 = *mb;
1047 left = M_TRAILINGSPACE(m2);
1048 if (left > 0) {
1049 tl = ((u_int32_t *)(*bpos));
1050 *tl++ = txdr_unsigned(siz);
1051 putsize = 0;
1052 left -= NFSX_UNSIGNED;
1053 m2->m_len += NFSX_UNSIGNED;
1054 if (left > 0) {
1055 bcopy(cp, (caddr_t) tl, left);
1056 siz -= left;
1057 cp += left;
1058 m2->m_len += left;
1059 left = 0;
1060 }
1061 }
1062 /* Loop around adding mbufs */
1063 while (siz > 0) {
1064 MGET(m1, M_WAIT, MT_DATA);
1065 if (siz > MLEN)
1066 MCLGET(m1, M_WAIT);
1067 m1->m_len = NFSMSIZ(m1);
1068 m2->m_next = m1;
1069 m2 = m1;
1070 tl = mtod(m1, u_int32_t *);
1071 tlen = 0;
1072 if (putsize) {
1073 *tl++ = txdr_unsigned(siz);
1074 m1->m_len -= NFSX_UNSIGNED;
1075 tlen = NFSX_UNSIGNED;
1076 putsize = 0;
1077 }
1078 if (siz < m1->m_len) {
1079 len = nfsm_rndup(siz);
1080 xfer = siz;
1081 if (xfer < len)
1082 *(tl+(xfer>>2)) = 0;
1083 } else {
1084 xfer = len = m1->m_len;
1085 }
1086 bcopy(cp, (caddr_t) tl, xfer);
1087 m1->m_len = len+tlen;
1088 siz -= xfer;
1089 cp += xfer;
1090 }
1091 *mb = m1;
1092 *bpos = mtod(m1, caddr_t)+m1->m_len;
1093 return (0);
1094}
1095
1096/*
1097 * Called once to initialize data structures...
1098 */
1099int
1100nfs_init(vfsp)
1101 struct vfsconf *vfsp;
1102{
1103 register int i;
1104
1105 nfsmount_zone = zinit("NFSMOUNT", sizeof(struct nfsmount), 0, 0, 1);
1106
1107 nfs_mount_type = vfsp->vfc_typenum;
1108 nfsrtt.pos = 0;
1109 rpc_vers = txdr_unsigned(RPC_VER2);
1110 rpc_call = txdr_unsigned(RPC_CALL);
1111 rpc_reply = txdr_unsigned(RPC_REPLY);
1112 rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED);
1113 rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED);
1114 rpc_mismatch = txdr_unsigned(RPC_MISMATCH);
1115 rpc_autherr = txdr_unsigned(RPC_AUTHERR);
1116 rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX);
1117 rpc_auth_kerb = txdr_unsigned(RPCAUTH_KERB4);
1118 nfs_prog = txdr_unsigned(NFS_PROG);
1119 nqnfs_prog = txdr_unsigned(NQNFS_PROG);
1120 nfs_true = txdr_unsigned(TRUE);
1121 nfs_false = txdr_unsigned(FALSE);
1122 nfs_xdrneg1 = txdr_unsigned(-1);
1123 nfs_ticks = (hz * NFS_TICKINTVL + 500) / 1000;
1124 if (nfs_ticks < 1)
1125 nfs_ticks = 1;
1126 /* Ensure async daemons disabled */
1127 for (i = 0; i < NFS_MAXASYNCDAEMON; i++) {
1128 nfs_iodwant[i] = (struct proc *)0;
1129 nfs_iodmount[i] = (struct nfsmount *)0;
1130 }
1131 nfs_nhinit(); /* Init the nfsnode table */
1132#ifndef NFS_NOSERVER
1133 nfsrv_init(0); /* Init server data structures */
1134 nfsrv_initcache(); /* Init the server request cache */
1135#endif
1136
1137 /*
1138 * Initialize the nqnfs server stuff.
1139 */
1140 if (nqnfsstarttime == 0) {
1141 nqnfsstarttime = boottime.tv_sec + nqsrv_maxlease
1142 + nqsrv_clockskew + nqsrv_writeslack;
1143 NQLOADNOVRAM(nqnfsstarttime);
1144 CIRCLEQ_INIT(&nqtimerhead);
1145 nqfhhashtbl = hashinit(NQLCHSZ, M_NQLEASE, &nqfhhash);
1146 }
1147
1148 /*
1149 * Initialize reply list and start timer
1150 */
1151 TAILQ_INIT(&nfs_reqq);
1152
1153 nfs_timer(0);
1154
1155 /*
1156 * Set up lease_check and lease_updatetime so that other parts
1157 * of the system can call us, if we are loadable.
1158 */
1159#ifndef NFS_NOSERVER
1160 nfs_prev_vop_lease_check = default_vnodeop_p[VOFFSET(vop_lease)];
1161 default_vnodeop_p[VOFFSET(vop_lease)] = (vop_t *)nqnfs_vop_lease_check;
1162#endif
1163 nfs_prev_lease_updatetime = lease_updatetime;
1164 lease_updatetime = nfs_lease_updatetime;
1165 nfs_prev_nfssvc_sy_narg = sysent[SYS_nfssvc].sy_narg;
1166 sysent[SYS_nfssvc].sy_narg = 2;
1167 nfs_prev_nfssvc_sy_call = sysent[SYS_nfssvc].sy_call;
1168 sysent[SYS_nfssvc].sy_call = (sy_call_t *)nfssvc;
1169
1170 nfs_pbuf_freecnt = nswbuf / 2 + 1;
1171
1172 return (0);
1173}
1174
1175int
1176nfs_uninit(vfsp)
1177 struct vfsconf *vfsp;
1178{
1179
1180 untimeout(nfs_timer, (void *)NULL, nfs_timer_handle);
1181 nfs_mount_type = -1;
1182#ifndef NFS_NOSERVER
1183 default_vnodeop_p[VOFFSET(vop_lease)] = nfs_prev_vop_lease_check;
1184#endif
1185 lease_updatetime = nfs_prev_lease_updatetime;
1186 sysent[SYS_nfssvc].sy_narg = nfs_prev_nfssvc_sy_narg;
1187 sysent[SYS_nfssvc].sy_call = nfs_prev_nfssvc_sy_call;
1188 return (0);
1189}
1190
1191/*
1192 * Attribute cache routines.
1193 * nfs_loadattrcache() - loads or updates the cache contents from attributes
1194 * that are on the mbuf list
1195 * nfs_getattrcache() - returns valid attributes if found in cache, returns
1196 * error otherwise
1197 */
1198
1199/*
1200 * Load the attribute cache (that lives in the nfsnode entry) with
1201 * the values on the mbuf list and
1202 * Iff vap not NULL
1203 * copy the attributes to *vaper
1204 */
1205int
1206nfs_loadattrcache(vpp, mdp, dposp, vaper)
1207 struct vnode **vpp;
1208 struct mbuf **mdp;
1209 caddr_t *dposp;
1210 struct vattr *vaper;
1211{
1212 register struct vnode *vp = *vpp;
1213 register struct vattr *vap;
1214 register struct nfs_fattr *fp;
1215 register struct nfsnode *np;
1216 register int32_t t1;
1217 caddr_t cp2;
1218 int error = 0, rdev;
1219 struct mbuf *md;
1220 enum vtype vtyp;
1221 u_short vmode;
1222 struct timespec mtime;
1223 int v3 = NFS_ISV3(vp);
1224
1225 md = *mdp;
1226 t1 = (mtod(md, caddr_t) + md->m_len) - *dposp;
1227 if ((error = nfsm_disct(mdp, dposp, NFSX_FATTR(v3), t1, &cp2)) != 0)
1228 return (error);
1229 fp = (struct nfs_fattr *)cp2;
1230 if (v3) {
1231 vtyp = nfsv3tov_type(fp->fa_type);
1232 vmode = fxdr_unsigned(u_short, fp->fa_mode);
1233 rdev = makeudev(fxdr_unsigned(int, fp->fa3_rdev.specdata1),
1234 fxdr_unsigned(int, fp->fa3_rdev.specdata2));
1235 fxdr_nfsv3time(&fp->fa3_mtime, &mtime);
1236 } else {
1237 vtyp = nfsv2tov_type(fp->fa_type);
1238 vmode = fxdr_unsigned(u_short, fp->fa_mode);
1239 /*
1240 * XXX
1241 *
1242 * The duplicate information returned in fa_type and fa_mode
1243 * is an ambiguity in the NFS version 2 protocol.
1244 *
1245 * VREG should be taken literally as a regular file. If a
1246 * server intents to return some type information differently
1247 * in the upper bits of the mode field (e.g. for sockets, or
1248 * FIFOs), NFSv2 mandates fa_type to be VNON. Anyway, we
1249 * leave the examination of the mode bits even in the VREG
1250 * case to avoid breakage for bogus servers, but we make sure
1251 * that there are actually type bits set in the upper part of
1252 * fa_mode (and failing that, trust the va_type field).
1253 *
1254 * NFSv3 cleared the issue, and requires fa_mode to not
1255 * contain any type information (while also introduing sockets
1256 * and FIFOs for fa_type).
1257 */
1258 if (vtyp == VNON || (vtyp == VREG && (vmode & S_IFMT) != 0))
1259 vtyp = IFTOVT(vmode);
1260 rdev = fxdr_unsigned(int32_t, fp->fa2_rdev);
1261 fxdr_nfsv2time(&fp->fa2_mtime, &mtime);
1262
1263 /*
1264 * Really ugly NFSv2 kludge.
1265 */
1266 if (vtyp == VCHR && rdev == 0xffffffff)
1267 vtyp = VFIFO;
1268 }
1269
1270 /*
1271 * If v_type == VNON it is a new node, so fill in the v_type,
1272 * n_mtime fields. Check to see if it represents a special
1273 * device, and if so, check for a possible alias. Once the
1274 * correct vnode has been obtained, fill in the rest of the
1275 * information.
1276 */
1277 np = VTONFS(vp);
1278 if (vp->v_type != vtyp) {
1279 vp->v_type = vtyp;
1280 if (vp->v_type == VFIFO) {
1281 vp->v_op = fifo_nfsv2nodeop_p;
1282 }
1283 if (vp->v_type == VCHR || vp->v_type == VBLK) {
1284 vp->v_op = spec_nfsv2nodeop_p;
1285 addaliasu(vp, rdev);
1286 }
1287 np->n_mtime = mtime.tv_sec;
1288 }
1289 vap = &np->n_vattr;
1290 vap->va_type = vtyp;
1291 vap->va_mode = (vmode & 07777);
1292 vap->va_rdev = rdev;
1293 vap->va_mtime = mtime;
1294 vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0];
1295 if (v3) {
1296 vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink);
1297 vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid);
1298 vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid);
1299 vap->va_size = fxdr_hyper(&fp->fa3_size);
1300 vap->va_blocksize = NFS_FABLKSIZE;
1301 vap->va_bytes = fxdr_hyper(&fp->fa3_used);
1302 vap->va_fileid = fxdr_unsigned(int32_t,
1303 fp->fa3_fileid.nfsuquad[1]);
1304 fxdr_nfsv3time(&fp->fa3_atime, &vap->va_atime);
1305 fxdr_nfsv3time(&fp->fa3_ctime, &vap->va_ctime);
1306 vap->va_flags = 0;
1307 vap->va_filerev = 0;
1308 } else {
1309 vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink);
1310 vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid);
1311 vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid);
1312 vap->va_size = fxdr_unsigned(u_int32_t, fp->fa2_size);
1313 vap->va_blocksize = fxdr_unsigned(int32_t, fp->fa2_blocksize);
1314 vap->va_bytes = (u_quad_t)fxdr_unsigned(int32_t, fp->fa2_blocks)
1315 * NFS_FABLKSIZE;
1316 vap->va_fileid = fxdr_unsigned(int32_t, fp->fa2_fileid);
1317 fxdr_nfsv2time(&fp->fa2_atime, &vap->va_atime);
1318 vap->va_flags = 0;
1319 vap->va_ctime.tv_sec = fxdr_unsigned(u_int32_t,
1320 fp->fa2_ctime.nfsv2_sec);
1321 vap->va_ctime.tv_nsec = 0;
1322 vap->va_gen = fxdr_unsigned(u_int32_t,fp->fa2_ctime.nfsv2_usec);
1323 vap->va_filerev = 0;
1324 }
1325 if (vap->va_size != np->n_size) {
1326 if (vap->va_type == VREG) {
1327 if (np->n_flag & NMODIFIED) {
1328 if (vap->va_size < np->n_size)
1329 vap->va_size = np->n_size;
1330 else
1331 np->n_size = vap->va_size;
1332 } else {
1333 np->n_size = vap->va_size;
1334 }
1335 vnode_pager_setsize(vp, np->n_size);
1336 } else {
1337 np->n_size = vap->va_size;
1338 }
1339 }
1340 np->n_attrstamp = time_second;
1341 if (vaper != NULL) {
1342 bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(*vap));
1343 if (np->n_flag & NCHG) {
1344 if (np->n_flag & NACC)
1345 vaper->va_atime = np->n_atim;
1346 if (np->n_flag & NUPD)
1347 vaper->va_mtime = np->n_mtim;
1348 }
1349 }
1350 return (0);
1351}
1352
1353#ifdef NFS_ACDEBUG
1354#include <sys/sysctl.h>
1355SYSCTL_DECL(_vfs_nfs);
1356static int nfs_acdebug;
1357SYSCTL_INT(_vfs_nfs, OID_AUTO, acdebug, CTLFLAG_RW, &nfs_acdebug, 0, "");
1358#endif
1359
1360/*
1361 * Check the time stamp
1362 * If the cache is valid, copy contents to *vap and return 0
1363 * otherwise return an error
1364 */
1365int
1366nfs_getattrcache(vp, vaper)
1367 register struct vnode *vp;
1368 struct vattr *vaper;
1369{
1370 register struct nfsnode *np;
1371 register struct vattr *vap;
1372 struct nfsmount *nmp;
1373 int timeo;
1374
1375 np = VTONFS(vp);
1376 vap = &np->n_vattr;
1377 nmp = VFSTONFS(vp->v_mount);
1378 /* XXX n_mtime doesn't seem to be updated on a miss-and-reload */
1379 timeo = (time_second - np->n_mtime) / 10;
1380
1381#ifdef NFS_ACDEBUG
1382 if (nfs_acdebug>1)
1383 printf("nfs_getattrcache: initial timeo = %d\n", timeo);
1384#endif
1385
1386 if (vap->va_type == VDIR) {
1387 if ((np->n_flag & NMODIFIED) || timeo < nmp->nm_acdirmin)
1388 timeo = nmp->nm_acdirmin;
1389 else if (timeo > nmp->nm_acdirmax)
1390 timeo = nmp->nm_acdirmax;
1391 } else {
1392 if ((np->n_flag & NMODIFIED) || timeo < nmp->nm_acregmin)
1393 timeo = nmp->nm_acregmin;
1394 else if (timeo > nmp->nm_acregmax)
1395 timeo = nmp->nm_acregmax;
1396 }
1397
1398#ifdef NFS_ACDEBUG
1399 if (nfs_acdebug > 2)
1400 printf("acregmin %d; acregmax %d; acdirmin %d; acdirmax %d\n",
1401 nmp->nm_acregmin, nmp->nm_acregmax,
1402 nmp->nm_acdirmin, nmp->nm_acdirmax);
1403
1404 if (nfs_acdebug)
1405 printf("nfs_getattrcache: age = %d; final timeo = %d\n",
1406 (time_second - np->n_attrstamp), timeo);
1407#endif
1408
1409 if ((time_second - np->n_attrstamp) >= timeo) {
1410 nfsstats.attrcache_misses++;
1411 return (ENOENT);
1412 }
1413 nfsstats.attrcache_hits++;
1414 if (vap->va_size != np->n_size) {
1415 if (vap->va_type == VREG) {
1416 if (np->n_flag & NMODIFIED) {
1417 if (vap->va_size < np->n_size)
1418 vap->va_size = np->n_size;
1419 else
1420 np->n_size = vap->va_size;
1421 } else {
1422 np->n_size = vap->va_size;
1423 }
1424 vnode_pager_setsize(vp, np->n_size);
1425 } else {
1426 np->n_size = vap->va_size;
1427 }
1428 }
1429 bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(struct vattr));
1430 if (np->n_flag & NCHG) {
1431 if (np->n_flag & NACC)
1432 vaper->va_atime = np->n_atim;
1433 if (np->n_flag & NUPD)
1434 vaper->va_mtime = np->n_mtim;
1435 }
1436 return (0);
1437}
1438
1439#ifndef NFS_NOSERVER
1440/*
1441 * Set up nameidata for a lookup() call and do it.
1442 *
1443 * If pubflag is set, this call is done for a lookup operation on the
1444 * public filehandle. In that case we allow crossing mountpoints and
1445 * absolute pathnames. However, the caller is expected to check that
1446 * the lookup result is within the public fs, and deny access if
1447 * it is not.
1448 *
1449 * nfs_namei() clears out garbage fields that namei() might leave garbage.
1450 * This is mainly ni_vp and ni_dvp when an error occurs, and ni_dvp when no
1451 * error occurs but the parent was not requested.
1452 *
1453 * dirp may be set whether an error is returned or not, and must be
1454 * released by the caller.
1455 */
1456int
1457nfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, retdirp, p, kerbflag, pubflag)
1458 register struct nameidata *ndp;
1459 fhandle_t *fhp;
1460 int len;
1461 struct nfssvc_sock *slp;
1462 struct sockaddr *nam;
1463 struct mbuf **mdp;
1464 caddr_t *dposp;
1465 struct vnode **retdirp;
1466 struct proc *p;
1467 int kerbflag, pubflag;
1468{
1469 register int i, rem;
1470 register struct mbuf *md;
1471 register char *fromcp, *tocp, *cp;
1472 struct iovec aiov;
1473 struct uio auio;
1474 struct vnode *dp;
1475 int error, rdonly, linklen;
1476 struct componentname *cnp = &ndp->ni_cnd;
1477
1478 *retdirp = (struct vnode *)0;
1479 cnp->cn_pnbuf = zalloc(namei_zone);
1480
1481 /*
1482 * Copy the name from the mbuf list to ndp->ni_pnbuf
1483 * and set the various ndp fields appropriately.
1484 */
1485 fromcp = *dposp;
1486 tocp = cnp->cn_pnbuf;
1487 md = *mdp;
1488 rem = mtod(md, caddr_t) + md->m_len - fromcp;
1489 for (i = 0; i < len; i++) {
1490 while (rem == 0) {
1491 md = md->m_next;
1492 if (md == NULL) {
1493 error = EBADRPC;
1494 goto out;
1495 }
1496 fromcp = mtod(md, caddr_t);
1497 rem = md->m_len;
1498 }
1499 if (*fromcp == '\0' || (!pubflag && *fromcp == '/')) {
1500 error = EACCES;
1501 goto out;
1502 }
1503 *tocp++ = *fromcp++;
1504 rem--;
1505 }
1506 *tocp = '\0';
1507 *mdp = md;
1508 *dposp = fromcp;
1509 len = nfsm_rndup(len)-len;
1510 if (len > 0) {
1511 if (rem >= len)
1512 *dposp += len;
1513 else if ((error = nfs_adv(mdp, dposp, len, rem)) != 0)
1514 goto out;
1515 }
1516
1517 /*
1518 * Extract and set starting directory.
1519 */
1520 error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cnd.cn_cred, slp,
1521 nam, &rdonly, kerbflag, pubflag);
1522 if (error)
1523 goto out;
1524 if (dp->v_type != VDIR) {
1525 vrele(dp);
1526 error = ENOTDIR;
1527 goto out;
1528 }
1529
1530 if (rdonly)
1531 cnp->cn_flags |= RDONLY;
1532
1533 /*
1534 * Set return directory. Reference to dp is implicitly transfered
1535 * to the returned pointer
1536 */
1537 *retdirp = dp;
1538
1539 if (pubflag) {
1540 /*
1541 * Oh joy. For WebNFS, handle those pesky '%' escapes,
1542 * and the 'native path' indicator.
1543 */
1544 cp = zalloc(namei_zone);
1545 fromcp = cnp->cn_pnbuf;
1546 tocp = cp;
1547 if ((unsigned char)*fromcp >= WEBNFS_SPECCHAR_START) {
1548 switch ((unsigned char)*fromcp) {
1549 case WEBNFS_NATIVE_CHAR:
1550 /*
1551 * 'Native' path for us is the same
1552 * as a path according to the NFS spec,
1553 * just skip the escape char.
1554 */
1555 fromcp++;
1556 break;
1557 /*
1558 * More may be added in the future, range 0x80-0xff
1559 */
1560 default:
1561 error = EIO;
1562 zfree(namei_zone, cp);
1563 goto out;
1564 }
1565 }
1566 /*
1567 * Translate the '%' escapes, URL-style.
1568 */
1569 while (*fromcp != '\0') {
1570 if (*fromcp == WEBNFS_ESC_CHAR) {
1571 if (fromcp[1] != '\0' && fromcp[2] != '\0') {
1572 fromcp++;
1573 *tocp++ = HEXSTRTOI(fromcp);
1574 fromcp += 2;
1575 continue;
1576 } else {
1577 error = ENOENT;
1578 zfree(namei_zone, cp);
1579 goto out;
1580 }
1581 } else
1582 *tocp++ = *fromcp++;
1583 }
1584 *tocp = '\0';
1585 zfree(namei_zone, cnp->cn_pnbuf);
1586 cnp->cn_pnbuf = cp;
1587 }
1588
1589 ndp->ni_pathlen = (tocp - cnp->cn_pnbuf) + 1;
1590 ndp->ni_segflg = UIO_SYSSPACE;
1591
1592 if (pubflag) {
1593 ndp->ni_rootdir = rootvnode;
1594 ndp->ni_loopcnt = 0;
1595 if (cnp->cn_pnbuf[0] == '/')
1596 dp = rootvnode;
1597 } else {
1598 cnp->cn_flags |= NOCROSSMOUNT;
1599 }
1600
1601 /*
1602 * Initialize for scan, set ni_startdir and bump ref on dp again
1603 * becuase lookup() will dereference ni_startdir.
1604 */
1605
1606 cnp->cn_proc = p;
1607 VREF(dp);
1608 ndp->ni_startdir = dp;
1609
1610 for (;;) {
1611 cnp->cn_nameptr = cnp->cn_pnbuf;
1612 /*
1613 * Call lookup() to do the real work. If an error occurs,
1614 * ndp->ni_vp and ni_dvp are left uninitialized or NULL and
1615 * we do not have to dereference anything before returning.
1616 * In either case ni_startdir will be dereferenced and NULLed
1617 * out.
1618 */
1619 error = lookup(ndp);
1620 if (error)
1621 break;
1622
1623 /*
1624 * Check for encountering a symbolic link. Trivial
1625 * termination occurs if no symlink encountered.
1626 * Note: zfree is safe because error is 0, so we will
1627 * not zfree it again when we break.
1628 */
1629 if ((cnp->cn_flags & ISSYMLINK) == 0) {
1630 nfsrv_object_create(ndp->ni_vp);
1631 if (cnp->cn_flags & (SAVENAME | SAVESTART))
1632 cnp->cn_flags |= HASBUF;
1633 else
1634 zfree(namei_zone, cnp->cn_pnbuf);
1635 break;
1636 }
1637
1638 /*
1639 * Validate symlink
1640 */
1641 if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1)
1642 VOP_UNLOCK(ndp->ni_dvp, 0, p);
1643 if (!pubflag) {
1644 error = EINVAL;
1645 goto badlink2;
1646 }
1647
1648 if (ndp->ni_loopcnt++ >= MAXSYMLINKS) {
1649 error = ELOOP;
1650 goto badlink2;
1651 }
1652 if (ndp->ni_pathlen > 1)
1653 cp = zalloc(namei_zone);
1654 else
1655 cp = cnp->cn_pnbuf;
1656 aiov.iov_base = cp;
1657 aiov.iov_len = MAXPATHLEN;
1658 auio.uio_iov = &aiov;
1659 auio.uio_iovcnt = 1;
1660 auio.uio_offset = 0;
1661 auio.uio_rw = UIO_READ;
1662 auio.uio_segflg = UIO_SYSSPACE;
1663 auio.uio_procp = (struct proc *)0;
1664 auio.uio_resid = MAXPATHLEN;
1665 error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred);
1666 if (error) {
1667 badlink1:
1668 if (ndp->ni_pathlen > 1)
1669 zfree(namei_zone, cp);
1670 badlink2:
1671 vrele(ndp->ni_dvp);
1672 vput(ndp->ni_vp);
1673 break;
1674 }
1675 linklen = MAXPATHLEN - auio.uio_resid;
1676 if (linklen == 0) {
1677 error = ENOENT;
1678 goto badlink1;
1679 }
1680 if (linklen + ndp->ni_pathlen >= MAXPATHLEN) {
1681 error = ENAMETOOLONG;
1682 goto badlink1;
1683 }
1684
1685 /*
1686 * Adjust or replace path
1687 */
1688 if (ndp->ni_pathlen > 1) {
1689 bcopy(ndp->ni_next, cp + linklen, ndp->ni_pathlen);
1690 zfree(namei_zone, cnp->cn_pnbuf);
1691 cnp->cn_pnbuf = cp;
1692 } else
1693 cnp->cn_pnbuf[linklen] = '\0';
1694 ndp->ni_pathlen += linklen;
1695
1696 /*
1697 * Cleanup refs for next loop and check if root directory
1698 * should replace current directory. Normally ni_dvp
1699 * becomes the new base directory and is cleaned up when
1700 * we loop. Explicitly null pointers after invalidation
1701 * to clarify operation.
1702 */
1703 vput(ndp->ni_vp);
1704 ndp->ni_vp = NULL;
1705
1706 if (cnp->cn_pnbuf[0] == '/') {
1707 vrele(ndp->ni_dvp);
1708 ndp->ni_dvp = ndp->ni_rootdir;
1709 VREF(ndp->ni_dvp);
1710 }
1711 ndp->ni_startdir = ndp->ni_dvp;
1712 ndp->ni_dvp = NULL;
1713 }
1714
1715 /*
1716 * nfs_namei() guarentees that fields will not contain garbage
1717 * whether an error occurs or not. This allows the caller to track
1718 * cleanup state trivially.
1719 */
1720out:
1721 if (error) {
1722 zfree(namei_zone, cnp->cn_pnbuf);
1723 ndp->ni_vp = NULL;
1724 ndp->ni_dvp = NULL;
1725 ndp->ni_startdir = NULL;
1726 cnp->cn_flags &= ~HASBUF;
1727 } else if ((ndp->ni_cnd.cn_flags & (WANTPARENT|LOCKPARENT)) == 0) {
1728 ndp->ni_dvp = NULL;
1729 }
1730 return (error);
1731}
1732
1733/*
1734 * A fiddled version of m_adj() that ensures null fill to a long
1735 * boundary and only trims off the back end
1736 */
1737void
1738nfsm_adj(mp, len, nul)
1739 struct mbuf *mp;
1740 register int len;
1741 int nul;
1742{
1743 register struct mbuf *m;
1744 register int count, i;
1745 register char *cp;
1746
1747 /*
1748 * Trim from tail. Scan the mbuf chain,
1749 * calculating its length and finding the last mbuf.
1750 * If the adjustment only affects this mbuf, then just
1751 * adjust and return. Otherwise, rescan and truncate
1752 * after the remaining size.
1753 */
1754 count = 0;
1755 m = mp;
1756 for (;;) {
1757 count += m->m_len;
1758 if (m->m_next == (struct mbuf *)0)
1759 break;
1760 m = m->m_next;
1761 }
1762 if (m->m_len > len) {
1763 m->m_len -= len;
1764 if (nul > 0) {
1765 cp = mtod(m, caddr_t)+m->m_len-nul;
1766 for (i = 0; i < nul; i++)
1767 *cp++ = '\0';
1768 }
1769 return;
1770 }
1771 count -= len;
1772 if (count < 0)
1773 count = 0;
1774 /*
1775 * Correct length for chain is "count".
1776 * Find the mbuf with last data, adjust its length,
1777 * and toss data from remaining mbufs on chain.
1778 */
1779 for (m = mp; m; m = m->m_next) {
1780 if (m->m_len >= count) {
1781 m->m_len = count;
1782 if (nul > 0) {
1783 cp = mtod(m, caddr_t)+m->m_len-nul;
1784 for (i = 0; i < nul; i++)
1785 *cp++ = '\0';
1786 }
1787 break;
1788 }
1789 count -= m->m_len;
1790 }
1791 for (m = m->m_next;m;m = m->m_next)
1792 m->m_len = 0;
1793}
1794
1795/*
1796 * Make these functions instead of macros, so that the kernel text size
1797 * doesn't get too big...
1798 */
1799void
1800nfsm_srvwcc(nfsd, before_ret, before_vap, after_ret, after_vap, mbp, bposp)
1801 struct nfsrv_descript *nfsd;
1802 int before_ret;
1803 register struct vattr *before_vap;
1804 int after_ret;
1805 struct vattr *after_vap;
1806 struct mbuf **mbp;
1807 char **bposp;
1808{
1809 register struct mbuf *mb = *mbp, *mb2;
1810 register char *bpos = *bposp;
1811 register u_int32_t *tl;
1812
1813 if (before_ret) {
1814 nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED);
1815 *tl = nfs_false;
1816 } else {
1817 nfsm_build(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
1818 *tl++ = nfs_true;
1819 txdr_hyper(before_vap->va_size, tl);
1820 tl += 2;
1821 txdr_nfsv3time(&(before_vap->va_mtime), tl);
1822 tl += 2;
1823 txdr_nfsv3time(&(before_vap->va_ctime), tl);
1824 }
1825 *bposp = bpos;
1826 *mbp = mb;
1827 nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp);
1828}
1829
1830void
1831nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp)
1832 struct nfsrv_descript *nfsd;
1833 int after_ret;
1834 struct vattr *after_vap;
1835 struct mbuf **mbp;
1836 char **bposp;
1837{
1838 register struct mbuf *mb = *mbp, *mb2;
1839 register char *bpos = *bposp;
1840 register u_int32_t *tl;
1841 register struct nfs_fattr *fp;
1842
1843 if (after_ret) {
1844 nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED);
1845 *tl = nfs_false;
1846 } else {
1847 nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_V3FATTR);
1848 *tl++ = nfs_true;
1849 fp = (struct nfs_fattr *)tl;
1850 nfsm_srvfattr(nfsd, after_vap, fp);
1851 }
1852 *mbp = mb;
1853 *bposp = bpos;
1854}
1855
1856void
1857nfsm_srvfattr(nfsd, vap, fp)
1858 register struct nfsrv_descript *nfsd;
1859 register struct vattr *vap;
1860 register struct nfs_fattr *fp;
1861{
1862
1863 fp->fa_nlink = txdr_unsigned(vap->va_nlink);
1864 fp->fa_uid = txdr_unsigned(vap->va_uid);
1865 fp->fa_gid = txdr_unsigned(vap->va_gid);
1866 if (nfsd->nd_flag & ND_NFSV3) {
1867 fp->fa_type = vtonfsv3_type(vap->va_type);
1868 fp->fa_mode = vtonfsv3_mode(vap->va_mode);
1869 txdr_hyper(vap->va_size, &fp->fa3_size);
1870 txdr_hyper(vap->va_bytes, &fp->fa3_used);
1871 fp->fa3_rdev.specdata1 = txdr_unsigned(umajor(vap->va_rdev));
1872 fp->fa3_rdev.specdata2 = txdr_unsigned(uminor(vap->va_rdev));
1873 fp->fa3_fsid.nfsuquad[0] = 0;
1874 fp->fa3_fsid.nfsuquad[1] = txdr_unsigned(vap->va_fsid);
1875 fp->fa3_fileid.nfsuquad[0] = 0;
1876 fp->fa3_fileid.nfsuquad[1] = txdr_unsigned(vap->va_fileid);
1877 txdr_nfsv3time(&vap->va_atime, &fp->fa3_atime);
1878 txdr_nfsv3time(&vap->va_mtime, &fp->fa3_mtime);
1879 txdr_nfsv3time(&vap->va_ctime, &fp->fa3_ctime);
1880 } else {
1881 fp->fa_type = vtonfsv2_type(vap->va_type);
1882 fp->fa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode);
1883 fp->fa2_size = txdr_unsigned(vap->va_size);
1884 fp->fa2_blocksize = txdr_unsigned(vap->va_blocksize);
1885 if (vap->va_type == VFIFO)
1886 fp->fa2_rdev = 0xffffffff;
1887 else
1888 fp->fa2_rdev = txdr_unsigned(vap->va_rdev);
1889 fp->fa2_blocks = txdr_unsigned(vap->va_bytes / NFS_FABLKSIZE);
1890 fp->fa2_fsid = txdr_unsigned(vap->va_fsid);
1891 fp->fa2_fileid = txdr_unsigned(vap->va_fileid);
1892 txdr_nfsv2time(&vap->va_atime, &fp->fa2_atime);
1893 txdr_nfsv2time(&vap->va_mtime, &fp->fa2_mtime);
1894 txdr_nfsv2time(&vap->va_ctime, &fp->fa2_ctime);
1895 }
1896}
1897
1898/*
1899 * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked)
1900 * - look up fsid in mount list (if not found ret error)
1901 * - get vp and export rights by calling VFS_FHTOVP()
1902 * - if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon
1903 * - if not lockflag unlock it with VOP_UNLOCK()
1904 */
1905int
1906nfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp, kerbflag, pubflag)
1907 fhandle_t *fhp;
1908 int lockflag;
1909 struct vnode **vpp;
1910 struct ucred *cred;
1911 struct nfssvc_sock *slp;
1912 struct sockaddr *nam;
1913 int *rdonlyp;
1914 int kerbflag;
1915 int pubflag;
1916{
1917 struct proc *p = curproc; /* XXX */
1918 register struct mount *mp;
1919 register int i;
1920 struct ucred *credanon;
1921 int error, exflags;
1922#ifdef MNT_EXNORESPORT /* XXX needs mountd and /etc/exports help yet */
1923 struct sockaddr_int *saddr;
1924#endif
1925
1926 *vpp = (struct vnode *)0;
1927
1928 if (nfs_ispublicfh(fhp)) {
1929 if (!pubflag || !nfs_pub.np_valid)
1930 return (ESTALE);
1931 fhp = &nfs_pub.np_handle;
1932 }
1933
1934 mp = vfs_getvfs(&fhp->fh_fsid);
1935 if (!mp)
1936 return (ESTALE);
1937 error = VFS_CHECKEXP(mp, nam, &exflags, &credanon);
1938 if (error)
1939 return (error);
1940 error = VFS_FHTOVP(mp, &fhp->fh_fid, vpp);
1941 if (error)
1942 return (error);
1943#ifdef MNT_EXNORESPORT
1944 if (!(exflags & (MNT_EXNORESPORT|MNT_EXPUBLIC))) {
1945 saddr = (struct sockaddr_in *)nam;
1946 if (saddr->sin_family == AF_INET &&
1947 ntohs(saddr->sin_port) >= IPPORT_RESERVED) {
1948 vput(*vpp);
1949 *vpp = NULL;
1950 return (NFSERR_AUTHERR | AUTH_TOOWEAK);
1951 }
1952 }
1953#endif
1954 /*
1955 * Check/setup credentials.
1956 */
1957 if (exflags & MNT_EXKERB) {
1958 if (!kerbflag) {
1959 vput(*vpp);
1960 *vpp = NULL;
1961 return (NFSERR_AUTHERR | AUTH_TOOWEAK);
1962 }
1963 } else if (kerbflag) {
1964 vput(*vpp);
1965 *vpp = NULL;
1966 return (NFSERR_AUTHERR | AUTH_TOOWEAK);
1967 } else if (cred->cr_uid == 0 || (exflags & MNT_EXPORTANON)) {
1968 cred->cr_uid = credanon->cr_uid;
1969 for (i = 0; i < credanon->cr_ngroups && i < NGROUPS; i++)
1970 cred->cr_groups[i] = credanon->cr_groups[i];
1971 cred->cr_ngroups = i;
1972 }
1973 if (exflags & MNT_EXRDONLY)
1974 *rdonlyp = 1;
1975 else
1976 *rdonlyp = 0;
1977
1978 nfsrv_object_create(*vpp);
1979
1980 if (!lockflag)
1981 VOP_UNLOCK(*vpp, 0, p);
1982 return (0);
1983}
1984
1985
1986/*
1987 * WebNFS: check if a filehandle is a public filehandle. For v3, this
1988 * means a length of 0, for v2 it means all zeroes. nfsm_srvmtofh has
1989 * transformed this to all zeroes in both cases, so check for it.
1990 */
1991int
1992nfs_ispublicfh(fhp)
1993 fhandle_t *fhp;
1994{
1995 char *cp = (char *)fhp;
1996 int i;
1997
1998 for (i = 0; i < NFSX_V3FH; i++)
1999 if (*cp++ != 0)
2000 return (FALSE);
2001 return (TRUE);
2002}
2003
2004#endif /* NFS_NOSERVER */
2005/*
2006 * This function compares two net addresses by family and returns TRUE
2007 * if they are the same host.
2008 * If there is any doubt, return FALSE.
2009 * The AF_INET family is handled as a special case so that address mbufs
2010 * don't need to be saved to store "struct in_addr", which is only 4 bytes.
2011 */
2012int
2013netaddr_match(family, haddr, nam)
2014 int family;
2015 union nethostaddr *haddr;
2016 struct sockaddr *nam;
2017{
2018 register struct sockaddr_in *inetaddr;
2019
2020 switch (family) {
2021 case AF_INET:
2022 inetaddr = (struct sockaddr_in *)nam;
2023 if (inetaddr->sin_family == AF_INET &&
2024 inetaddr->sin_addr.s_addr == haddr->had_inetaddr)
2025 return (1);
2026 break;
2027 default:
2028 break;
2029 };
2030 return (0);
2031}
2032
2033static nfsuint64 nfs_nullcookie = { { 0, 0 } };
2034/*
2035 * This function finds the directory cookie that corresponds to the
2036 * logical byte offset given.
2037 */
2038nfsuint64 *
2039nfs_getcookie(np, off, add)
2040 register struct nfsnode *np;
2041 off_t off;
2042 int add;
2043{
2044 register struct nfsdmap *dp, *dp2;
2045 register int pos;
2046
2047 pos = (uoff_t)off / NFS_DIRBLKSIZ;
2048 if (pos == 0 || off < 0) {
2049#ifdef DIAGNOSTIC
2050 if (add)
2051 panic("nfs getcookie add at <= 0");
2052#endif
2053 return (&nfs_nullcookie);
2054 }
2055 pos--;
2056 dp = np->n_cookies.lh_first;
2057 if (!dp) {
2058 if (add) {
2059 MALLOC(dp, struct nfsdmap *, sizeof (struct nfsdmap),
2060 M_NFSDIROFF, M_WAITOK);
2061 dp->ndm_eocookie = 0;
2062 LIST_INSERT_HEAD(&np->n_cookies, dp, ndm_list);
2063 } else
2064 return ((nfsuint64 *)0);
2065 }
2066 while (pos >= NFSNUMCOOKIES) {
2067 pos -= NFSNUMCOOKIES;
2068 if (dp->ndm_list.le_next) {
2069 if (!add && dp->ndm_eocookie < NFSNUMCOOKIES &&
2070 pos >= dp->ndm_eocookie)
2071 return ((nfsuint64 *)0);
2072 dp = dp->ndm_list.le_next;
2073 } else if (add) {
2074 MALLOC(dp2, struct nfsdmap *, sizeof (struct nfsdmap),
2075 M_NFSDIROFF, M_WAITOK);
2076 dp2->ndm_eocookie = 0;
2077 LIST_INSERT_AFTER(dp, dp2, ndm_list);
2078 dp = dp2;
2079 } else
2080 return ((nfsuint64 *)0);
2081 }
2082 if (pos >= dp->ndm_eocookie) {
2083 if (add)
2084 dp->ndm_eocookie = pos + 1;
2085 else
2086 return ((nfsuint64 *)0);
2087 }
2088 return (&dp->ndm_cookies[pos]);
2089}
2090
2091/*
2092 * Invalidate cached directory information, except for the actual directory
2093 * blocks (which are invalidated separately).
2094 * Done mainly to avoid the use of stale offset cookies.
2095 */
2096void
2097nfs_invaldir(vp)
2098 register struct vnode *vp;
2099{
2100 register struct nfsnode *np = VTONFS(vp);
2101
2102#ifdef DIAGNOSTIC
2103 if (vp->v_type != VDIR)
2104 panic("nfs: invaldir not dir");
2105#endif
2106 np->n_direofoffset = 0;
2107 np->n_cookieverf.nfsuquad[0] = 0;
2108 np->n_cookieverf.nfsuquad[1] = 0;
2109 if (np->n_cookies.lh_first)
2110 np->n_cookies.lh_first->ndm_eocookie = 0;
2111}
2112
2113/*
2114 * The write verifier has changed (probably due to a server reboot), so all
2115 * B_NEEDCOMMIT blocks will have to be written again. Since they are on the
2116 * dirty block list as B_DELWRI, all this takes is clearing the B_NEEDCOMMIT
2117 * and B_CLUSTEROK flags. Once done the new write verifier can be set for the
2118 * mount point.
2119 *
2120 * B_CLUSTEROK must be cleared along with B_NEEDCOMMIT because stage 1 data
2121 * writes are not clusterable.
2122 */
2123void
2124nfs_clearcommit(mp)
2125 struct mount *mp;
2126{
2127 register struct vnode *vp, *nvp;
2128 register struct buf *bp, *nbp;
2129 int s;
2130
2131 s = splbio();
2132loop:
2133 for (vp = mp->mnt_vnodelist.lh_first; vp; vp = nvp) {
2134 if (vp->v_mount != mp) /* Paranoia */
2135 goto loop;
2136 nvp = vp->v_mntvnodes.le_next;
2137 for (bp = TAILQ_FIRST(&vp->v_dirtyblkhd); bp; bp = nbp) {
2138 nbp = TAILQ_NEXT(bp, b_vnbufs);
2139 if (BUF_REFCNT(bp) == 0 &&
2140 (bp->b_flags & (B_DELWRI | B_NEEDCOMMIT))
2141 == (B_DELWRI | B_NEEDCOMMIT))
2142 bp->b_flags &= ~(B_NEEDCOMMIT | B_CLUSTEROK);
2143 }
2144 }
2145 splx(s);
2146}
2147
2148#ifndef NFS_NOSERVER
2149/*
2150 * Map errnos to NFS error numbers. For Version 3 also filter out error
2151 * numbers not specified for the associated procedure.
2152 */
2153int
2154nfsrv_errmap(nd, err)
2155 struct nfsrv_descript *nd;
2156 register int err;
2157{
2158 register short *defaulterrp, *errp;
2159
2160 if (nd->nd_flag & ND_NFSV3) {
2161 if (nd->nd_procnum <= NFSPROC_COMMIT) {
2162 errp = defaulterrp = nfsrv_v3errmap[nd->nd_procnum];
2163 while (*++errp) {
2164 if (*errp == err)
2165 return (err);
2166 else if (*errp > err)
2167 break;
2168 }
2169 return ((int)*defaulterrp);
2170 } else
2171 return (err & 0xffff);
2172 }
2173 if (err <= ELAST)
2174 return ((int)nfsrv_v2errmap[err - 1]);
2175 return (NFSERR_IO);
2176}
2177
2178int
2179nfsrv_object_create(vp)
2180 struct vnode *vp;
2181{
2182
2183 if (vp == NULL || vp->v_type != VREG)
2184 return (1);
2185 return (vfs_object_create(vp, curproc,
2186 curproc ? curproc->p_ucred : NULL));
2187}
2188
2189/*
2190 * Sort the group list in increasing numerical order.
2191 * (Insertion sort by Chris Torek, who was grossed out by the bubble sort
2192 * that used to be here.)
2193 */
2194void
2195nfsrvw_sort(list, num)
2196 register gid_t *list;
2197 register int num;
2198{
2199 register int i, j;
2200 gid_t v;
2201
2202 /* Insertion sort. */
2203 for (i = 1; i < num; i++) {
2204 v = list[i];
2205 /* find correct slot for value v, moving others up */
2206 for (j = i; --j >= 0 && v < list[j];)
2207 list[j + 1] = list[j];
2208 list[j + 1] = v;
2209 }
2210}
2211
2212/*
2213 * copy credentials making sure that the result can be compared with bcmp().
2214 */
2215void
2216nfsrv_setcred(incred, outcred)
2217 register struct ucred *incred, *outcred;
2218{
2219 register int i;
2220
2221 bzero((caddr_t)outcred, sizeof (struct ucred));
2222 outcred->cr_ref = 1;
2223 outcred->cr_uid = incred->cr_uid;
2224 outcred->cr_ngroups = incred->cr_ngroups;
2225 for (i = 0; i < incred->cr_ngroups; i++)
2226 outcred->cr_groups[i] = incred->cr_groups[i];
2227 nfsrvw_sort(outcred->cr_groups, outcred->cr_ngroups);
2228}
2229#endif /* NFS_NOSERVER */