]> git.saurik.com Git - apple/xnu.git/blame - bsd/nfs/nfs_subs.c
xnu-792.25.20.tar.gz
[apple/xnu.git] / bsd / nfs / nfs_subs.c
CommitLineData
1c79356b 1/*
5d5c5d0d
A
2 * Copyright (c) 2000-2005 Apple Computer, Inc. All rights reserved.
3 *
6601e61a 4 * @APPLE_LICENSE_HEADER_START@
1c79356b 5 *
6601e61a
A
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
8f6c56a5 11 *
6601e61a
A
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
8f6c56a5
A
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
6601e61a
A
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
8f6c56a5 19 *
6601e61a 20 * @APPLE_LICENSE_HEADER_END@
1c79356b
A
21 */
22/* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
23/*
24 * Copyright (c) 1989, 1993
25 * The Regents of the University of California. All rights reserved.
26 *
27 * This code is derived from software contributed to Berkeley by
28 * Rick Macklem at The University of Guelph.
29 *
30 * Redistribution and use in source and binary forms, with or without
31 * modification, are permitted provided that the following conditions
32 * are met:
33 * 1. Redistributions of source code must retain the above copyright
34 * notice, this list of conditions and the following disclaimer.
35 * 2. Redistributions in binary form must reproduce the above copyright
36 * notice, this list of conditions and the following disclaimer in the
37 * documentation and/or other materials provided with the distribution.
38 * 3. All advertising materials mentioning features or use of this software
39 * must display the following acknowledgement:
40 * This product includes software developed by the University of
41 * California, Berkeley and its contributors.
42 * 4. Neither the name of the University nor the names of its contributors
43 * may be used to endorse or promote products derived from this software
44 * without specific prior written permission.
45 *
46 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
47 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
48 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
49 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
50 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
51 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
52 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
53 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
54 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
55 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
56 * SUCH DAMAGE.
57 *
58 * @(#)nfs_subs.c 8.8 (Berkeley) 5/22/95
59 * FreeBSD-Id: nfs_subs.c,v 1.47 1997/11/07 08:53:24 phk Exp $
60 */
61
62/*
63 * These functions support the macros and help fiddle mbuf chains for
64 * the nfs op functions. They do things like create the rpc header and
65 * copy data between mbuf chains and uio lists.
66 */
67#include <sys/param.h>
68#include <sys/proc.h>
91447636 69#include <sys/kauth.h>
1c79356b
A
70#include <sys/systm.h>
71#include <sys/kernel.h>
91447636
A
72#include <sys/mount_internal.h>
73#include <sys/vnode_internal.h>
74#include <sys/kpi_mbuf.h>
1c79356b
A
75#include <sys/socket.h>
76#include <sys/stat.h>
77#include <sys/malloc.h>
78#include <sys/syscall.h>
55e303ae 79#include <sys/sysctl.h>
91447636 80#include <sys/ubc_internal.h>
e5568f75 81#include <sys/fcntl.h>
91447636
A
82#include <sys/uio_internal.h>
83#include <sys/domain.h>
84#include <libkern/OSAtomic.h>
1c79356b
A
85
86#include <sys/vm.h>
87#include <sys/vmparam.h>
1c79356b
A
88
89#include <sys/time.h>
90#include <kern/clock.h>
91
92#include <nfs/rpcv2.h>
93#include <nfs/nfsproto.h>
94#include <nfs/nfs.h>
95#include <nfs/nfsnode.h>
96#include <nfs/xdr_subs.h>
97#include <nfs/nfsm_subs.h>
98#include <nfs/nfsmount.h>
1c79356b 99#include <nfs/nfsrtt.h>
e5568f75 100#include <nfs/nfs_lock.h>
1c79356b
A
101
102#include <miscfs/specfs/specdev.h>
103
104#include <netinet/in.h>
105#if ISO
106#include <netiso/iso.h>
107#endif
108
fa4905b1
A
109#include <sys/kdebug.h>
110
55e303ae
A
111SYSCTL_DECL(_vfs_generic);
112SYSCTL_NODE(_vfs_generic, OID_AUTO, nfs, CTLFLAG_RW, 0, "nfs hinge");
113
fa4905b1
A
114#define FSDBG(A, B, C, D, E) \
115 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, (A))) | DBG_FUNC_NONE, \
116 (int)(B), (int)(C), (int)(D), (int)(E), 0)
117#define FSDBG_TOP(A, B, C, D, E) \
118 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, (A))) | DBG_FUNC_START, \
119 (int)(B), (int)(C), (int)(D), (int)(E), 0)
120#define FSDBG_BOT(A, B, C, D, E) \
121 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, (A))) | DBG_FUNC_END, \
122 (int)(B), (int)(C), (int)(D), (int)(E), 0)
1c79356b
A
123/*
124 * Data items converted to xdr at startup, since they are constant
125 * This is kinda hokey, but may save a little time doing byte swaps
126 */
127u_long nfs_xdrneg1;
128u_long rpc_call, rpc_vers, rpc_reply, rpc_msgdenied, rpc_autherr,
129 rpc_mismatch, rpc_auth_unix, rpc_msgaccepted,
130 rpc_auth_kerb;
91447636
A
131u_long nfs_prog, nfs_true, nfs_false;
132__private_extern__ int nfs_mbuf_mlen = 0, nfs_mbuf_mhlen = 0,
133 nfs_mbuf_minclsize = 0, nfs_mbuf_mclbytes = 0;
1c79356b
A
134
135/* And other global data */
136static u_long nfs_xid = 0;
fa4905b1 137u_long nfs_xidwrap = 0; /* to build a (non-wwrapping) 64 bit xid */
1c79356b
A
138static enum vtype nv2tov_type[8]= {
139 VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON, VNON
140};
141enum vtype nv3tov_type[8]= {
142 VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO
143};
144
145int nfs_mount_type;
146int nfs_ticks;
147
91447636
A
148lck_grp_t *nfsd_lck_grp;
149lck_grp_attr_t *nfsd_lck_grp_attr;
150lck_attr_t *nfsd_lck_attr;
151lck_mtx_t *nfsd_mutex;
152
153lck_grp_attr_t *nfs_slp_group_attr;
154lck_attr_t *nfs_slp_lock_attr;
155lck_grp_t *nfs_slp_rwlock_group;
156lck_grp_t *nfs_slp_mutex_group;
157
1c79356b 158struct nfs_reqq nfs_reqq;
743b1565 159struct nfssvc_sockhead nfssvc_sockhead, nfssvc_deadsockhead;
1c79356b
A
160struct nfsd_head nfsd_head;
161int nfsd_head_flag;
91447636
A
162
163struct nfsexpfslist nfs_exports;
164struct nfsexphashhead *nfsexphashtbl;
165u_long nfsexphash;
166lck_grp_attr_t *nfs_export_group_attr;
167lck_attr_t *nfs_export_lock_attr;
168lck_grp_t *nfs_export_rwlock_group;
169lck_rw_t nfs_export_rwlock;
1c79356b
A
170
171#ifndef NFS_NOSERVER
172/*
173 * Mapping of old NFS Version 2 RPC numbers to generic numbers.
174 */
175int nfsv3_procid[NFS_NPROCS] = {
176 NFSPROC_NULL,
177 NFSPROC_GETATTR,
178 NFSPROC_SETATTR,
179 NFSPROC_NOOP,
180 NFSPROC_LOOKUP,
181 NFSPROC_READLINK,
182 NFSPROC_READ,
183 NFSPROC_NOOP,
184 NFSPROC_WRITE,
185 NFSPROC_CREATE,
186 NFSPROC_REMOVE,
187 NFSPROC_RENAME,
188 NFSPROC_LINK,
189 NFSPROC_SYMLINK,
190 NFSPROC_MKDIR,
191 NFSPROC_RMDIR,
192 NFSPROC_READDIR,
193 NFSPROC_FSSTAT,
194 NFSPROC_NOOP,
195 NFSPROC_NOOP,
196 NFSPROC_NOOP,
197 NFSPROC_NOOP,
1c79356b
A
198 NFSPROC_NOOP
199};
200
201#endif /* NFS_NOSERVER */
202/*
203 * and the reverse mapping from generic to Version 2 procedure numbers
204 */
205int nfsv2_procid[NFS_NPROCS] = {
206 NFSV2PROC_NULL,
207 NFSV2PROC_GETATTR,
208 NFSV2PROC_SETATTR,
209 NFSV2PROC_LOOKUP,
210 NFSV2PROC_NOOP,
211 NFSV2PROC_READLINK,
212 NFSV2PROC_READ,
213 NFSV2PROC_WRITE,
214 NFSV2PROC_CREATE,
215 NFSV2PROC_MKDIR,
216 NFSV2PROC_SYMLINK,
217 NFSV2PROC_CREATE,
218 NFSV2PROC_REMOVE,
219 NFSV2PROC_RMDIR,
220 NFSV2PROC_RENAME,
221 NFSV2PROC_LINK,
222 NFSV2PROC_READDIR,
223 NFSV2PROC_NOOP,
224 NFSV2PROC_STATFS,
225 NFSV2PROC_NOOP,
226 NFSV2PROC_NOOP,
227 NFSV2PROC_NOOP,
91447636 228 NFSV2PROC_NOOP
1c79356b
A
229};
230
231#ifndef NFS_NOSERVER
232/*
233 * Maps errno values to nfs error numbers.
234 * Use NFSERR_IO as the catch all for ones not specifically defined in
235 * RFC 1094.
236 */
237static u_char nfsrv_v2errmap[ELAST] = {
238 NFSERR_PERM, NFSERR_NOENT, NFSERR_IO, NFSERR_IO, NFSERR_IO,
239 NFSERR_NXIO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
240 NFSERR_IO, NFSERR_IO, NFSERR_ACCES, NFSERR_IO, NFSERR_IO,
241 NFSERR_IO, NFSERR_EXIST, NFSERR_IO, NFSERR_NODEV, NFSERR_NOTDIR,
242 NFSERR_ISDIR, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
243 NFSERR_IO, NFSERR_FBIG, NFSERR_NOSPC, NFSERR_IO, NFSERR_ROFS,
244 NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
245 NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
246 NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
247 NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
248 NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
249 NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
250 NFSERR_IO, NFSERR_IO, NFSERR_NAMETOL, NFSERR_IO, NFSERR_IO,
251 NFSERR_NOTEMPTY, NFSERR_IO, NFSERR_IO, NFSERR_DQUOT, NFSERR_STALE,
252 NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
253 NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
254 NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
255};
256
257/*
258 * Maps errno values to nfs error numbers.
259 * Although it is not obvious whether or not NFS clients really care if
260 * a returned error value is in the specified list for the procedure, the
261 * safest thing to do is filter them appropriately. For Version 2, the
262 * X/Open XNFS document is the only specification that defines error values
263 * for each RPC (The RFC simply lists all possible error values for all RPCs),
264 * so I have decided to not do this for Version 2.
265 * The first entry is the default error return and the rest are the valid
266 * errors for that RPC in increasing numeric order.
267 */
268static short nfsv3err_null[] = {
269 0,
270 0,
271};
272
273static short nfsv3err_getattr[] = {
274 NFSERR_IO,
275 NFSERR_IO,
276 NFSERR_STALE,
277 NFSERR_BADHANDLE,
278 NFSERR_SERVERFAULT,
279 0,
280};
281
282static short nfsv3err_setattr[] = {
283 NFSERR_IO,
284 NFSERR_PERM,
285 NFSERR_IO,
286 NFSERR_ACCES,
287 NFSERR_INVAL,
288 NFSERR_NOSPC,
289 NFSERR_ROFS,
290 NFSERR_DQUOT,
291 NFSERR_STALE,
292 NFSERR_BADHANDLE,
293 NFSERR_NOT_SYNC,
294 NFSERR_SERVERFAULT,
295 0,
296};
297
298static short nfsv3err_lookup[] = {
299 NFSERR_IO,
300 NFSERR_NOENT,
301 NFSERR_IO,
302 NFSERR_ACCES,
303 NFSERR_NOTDIR,
304 NFSERR_NAMETOL,
305 NFSERR_STALE,
306 NFSERR_BADHANDLE,
307 NFSERR_SERVERFAULT,
308 0,
309};
310
311static short nfsv3err_access[] = {
312 NFSERR_IO,
313 NFSERR_IO,
314 NFSERR_STALE,
315 NFSERR_BADHANDLE,
316 NFSERR_SERVERFAULT,
317 0,
318};
319
320static short nfsv3err_readlink[] = {
321 NFSERR_IO,
322 NFSERR_IO,
323 NFSERR_ACCES,
324 NFSERR_INVAL,
325 NFSERR_STALE,
326 NFSERR_BADHANDLE,
327 NFSERR_NOTSUPP,
328 NFSERR_SERVERFAULT,
329 0,
330};
331
332static short nfsv3err_read[] = {
333 NFSERR_IO,
334 NFSERR_IO,
335 NFSERR_NXIO,
336 NFSERR_ACCES,
337 NFSERR_INVAL,
338 NFSERR_STALE,
339 NFSERR_BADHANDLE,
340 NFSERR_SERVERFAULT,
341 0,
342};
343
344static short nfsv3err_write[] = {
345 NFSERR_IO,
346 NFSERR_IO,
347 NFSERR_ACCES,
348 NFSERR_INVAL,
349 NFSERR_FBIG,
350 NFSERR_NOSPC,
351 NFSERR_ROFS,
352 NFSERR_DQUOT,
353 NFSERR_STALE,
354 NFSERR_BADHANDLE,
355 NFSERR_SERVERFAULT,
356 0,
357};
358
359static short nfsv3err_create[] = {
360 NFSERR_IO,
361 NFSERR_IO,
362 NFSERR_ACCES,
363 NFSERR_EXIST,
364 NFSERR_NOTDIR,
365 NFSERR_NOSPC,
366 NFSERR_ROFS,
367 NFSERR_NAMETOL,
368 NFSERR_DQUOT,
369 NFSERR_STALE,
370 NFSERR_BADHANDLE,
371 NFSERR_NOTSUPP,
372 NFSERR_SERVERFAULT,
373 0,
374};
375
376static short nfsv3err_mkdir[] = {
377 NFSERR_IO,
378 NFSERR_IO,
379 NFSERR_ACCES,
380 NFSERR_EXIST,
381 NFSERR_NOTDIR,
382 NFSERR_NOSPC,
383 NFSERR_ROFS,
384 NFSERR_NAMETOL,
385 NFSERR_DQUOT,
386 NFSERR_STALE,
387 NFSERR_BADHANDLE,
388 NFSERR_NOTSUPP,
389 NFSERR_SERVERFAULT,
390 0,
391};
392
393static short nfsv3err_symlink[] = {
394 NFSERR_IO,
395 NFSERR_IO,
396 NFSERR_ACCES,
397 NFSERR_EXIST,
398 NFSERR_NOTDIR,
399 NFSERR_NOSPC,
400 NFSERR_ROFS,
401 NFSERR_NAMETOL,
402 NFSERR_DQUOT,
403 NFSERR_STALE,
404 NFSERR_BADHANDLE,
405 NFSERR_NOTSUPP,
406 NFSERR_SERVERFAULT,
407 0,
408};
409
410static short nfsv3err_mknod[] = {
411 NFSERR_IO,
412 NFSERR_IO,
413 NFSERR_ACCES,
414 NFSERR_EXIST,
415 NFSERR_NOTDIR,
416 NFSERR_NOSPC,
417 NFSERR_ROFS,
418 NFSERR_NAMETOL,
419 NFSERR_DQUOT,
420 NFSERR_STALE,
421 NFSERR_BADHANDLE,
422 NFSERR_NOTSUPP,
423 NFSERR_SERVERFAULT,
424 NFSERR_BADTYPE,
425 0,
426};
427
428static short nfsv3err_remove[] = {
429 NFSERR_IO,
430 NFSERR_NOENT,
431 NFSERR_IO,
432 NFSERR_ACCES,
433 NFSERR_NOTDIR,
434 NFSERR_ROFS,
435 NFSERR_NAMETOL,
436 NFSERR_STALE,
437 NFSERR_BADHANDLE,
438 NFSERR_SERVERFAULT,
439 0,
440};
441
442static short nfsv3err_rmdir[] = {
443 NFSERR_IO,
444 NFSERR_NOENT,
445 NFSERR_IO,
446 NFSERR_ACCES,
447 NFSERR_EXIST,
448 NFSERR_NOTDIR,
449 NFSERR_INVAL,
450 NFSERR_ROFS,
451 NFSERR_NAMETOL,
452 NFSERR_NOTEMPTY,
453 NFSERR_STALE,
454 NFSERR_BADHANDLE,
455 NFSERR_NOTSUPP,
456 NFSERR_SERVERFAULT,
457 0,
458};
459
460static short nfsv3err_rename[] = {
461 NFSERR_IO,
462 NFSERR_NOENT,
463 NFSERR_IO,
464 NFSERR_ACCES,
465 NFSERR_EXIST,
466 NFSERR_XDEV,
467 NFSERR_NOTDIR,
468 NFSERR_ISDIR,
469 NFSERR_INVAL,
470 NFSERR_NOSPC,
471 NFSERR_ROFS,
472 NFSERR_MLINK,
473 NFSERR_NAMETOL,
474 NFSERR_NOTEMPTY,
475 NFSERR_DQUOT,
476 NFSERR_STALE,
477 NFSERR_BADHANDLE,
478 NFSERR_NOTSUPP,
479 NFSERR_SERVERFAULT,
480 0,
481};
482
483static short nfsv3err_link[] = {
484 NFSERR_IO,
485 NFSERR_IO,
486 NFSERR_ACCES,
487 NFSERR_EXIST,
488 NFSERR_XDEV,
489 NFSERR_NOTDIR,
490 NFSERR_INVAL,
491 NFSERR_NOSPC,
492 NFSERR_ROFS,
493 NFSERR_MLINK,
494 NFSERR_NAMETOL,
495 NFSERR_DQUOT,
496 NFSERR_STALE,
497 NFSERR_BADHANDLE,
498 NFSERR_NOTSUPP,
499 NFSERR_SERVERFAULT,
500 0,
501};
502
503static short nfsv3err_readdir[] = {
504 NFSERR_IO,
505 NFSERR_IO,
506 NFSERR_ACCES,
507 NFSERR_NOTDIR,
508 NFSERR_STALE,
509 NFSERR_BADHANDLE,
510 NFSERR_BAD_COOKIE,
511 NFSERR_TOOSMALL,
512 NFSERR_SERVERFAULT,
513 0,
514};
515
516static short nfsv3err_readdirplus[] = {
517 NFSERR_IO,
518 NFSERR_IO,
519 NFSERR_ACCES,
520 NFSERR_NOTDIR,
521 NFSERR_STALE,
522 NFSERR_BADHANDLE,
523 NFSERR_BAD_COOKIE,
524 NFSERR_NOTSUPP,
525 NFSERR_TOOSMALL,
526 NFSERR_SERVERFAULT,
527 0,
528};
529
530static short nfsv3err_fsstat[] = {
531 NFSERR_IO,
532 NFSERR_IO,
533 NFSERR_STALE,
534 NFSERR_BADHANDLE,
535 NFSERR_SERVERFAULT,
536 0,
537};
538
539static short nfsv3err_fsinfo[] = {
540 NFSERR_STALE,
541 NFSERR_STALE,
542 NFSERR_BADHANDLE,
543 NFSERR_SERVERFAULT,
544 0,
545};
546
547static short nfsv3err_pathconf[] = {
548 NFSERR_STALE,
549 NFSERR_STALE,
550 NFSERR_BADHANDLE,
551 NFSERR_SERVERFAULT,
552 0,
553};
554
555static short nfsv3err_commit[] = {
556 NFSERR_IO,
557 NFSERR_IO,
558 NFSERR_STALE,
559 NFSERR_BADHANDLE,
560 NFSERR_SERVERFAULT,
561 0,
562};
563
564static short *nfsrv_v3errmap[] = {
565 nfsv3err_null,
566 nfsv3err_getattr,
567 nfsv3err_setattr,
568 nfsv3err_lookup,
569 nfsv3err_access,
570 nfsv3err_readlink,
571 nfsv3err_read,
572 nfsv3err_write,
573 nfsv3err_create,
574 nfsv3err_mkdir,
575 nfsv3err_symlink,
576 nfsv3err_mknod,
577 nfsv3err_remove,
578 nfsv3err_rmdir,
579 nfsv3err_rename,
580 nfsv3err_link,
581 nfsv3err_readdir,
582 nfsv3err_readdirplus,
583 nfsv3err_fsstat,
584 nfsv3err_fsinfo,
585 nfsv3err_pathconf,
586 nfsv3err_commit,
587};
588
589#endif /* NFS_NOSERVER */
590
591extern struct nfsrtt nfsrtt;
1c79356b 592extern struct nfsstats nfsstats;
1c79356b
A
593extern nfstype nfsv2_type[9];
594extern nfstype nfsv3_type[9];
595extern struct nfsnodehashhead *nfsnodehashtbl;
596extern u_long nfsnodehash;
597
1c79356b
A
598
599LIST_HEAD(nfsnodehashhead, nfsnode);
600
1c79356b
A
601/*
602 * Create the header for an rpc request packet
603 * The hsiz is the size of the rest of the nfs request header.
604 * (just used to decide if a cluster is a good idea)
605 */
91447636
A
606int
607nfsm_reqh(int hsiz, caddr_t *bposp, mbuf_t *mbp)
1c79356b 608{
91447636 609 int error;
1c79356b 610
91447636
A
611 *mbp = NULL;
612 if (hsiz >= nfs_mbuf_minclsize)
613 error = mbuf_mclget(MBUF_WAITOK, MBUF_TYPE_DATA, mbp);
614 else
615 error = mbuf_get(MBUF_WAITOK, MBUF_TYPE_DATA, mbp);
616 if (error)
617 return (error);
618 *bposp = mbuf_data(*mbp);
619 return (0);
1c79356b
A
620}
621
622/*
623 * Build the RPC header and fill in the authorization info.
624 * The authorization string argument is only used when the credentials
625 * come from outside of the kernel.
626 * Returns the head of the mbuf list.
627 */
91447636 628int
1c79356b 629nfsm_rpchead(cr, nmflag, procid, auth_type, auth_len, auth_str, verf_len,
91447636
A
630 verf_str, mrest, mrest_len, mbp, xidp, mreqp)
631 kauth_cred_t cr;
1c79356b
A
632 int nmflag;
633 int procid;
634 int auth_type;
635 int auth_len;
636 char *auth_str;
637 int verf_len;
638 char *verf_str;
91447636 639 mbuf_t mrest;
1c79356b 640 int mrest_len;
91447636 641 mbuf_t *mbp;
1c79356b 642 u_long *xidp;
91447636 643 mbuf_t *mreqp;
1c79356b 644{
91447636
A
645 mbuf_t mb;
646 u_long *tl;
647 caddr_t bpos;
648 int i, error, len;
649 mbuf_t mreq, mb2;
650 int siz, grpsiz, authsiz, mlen;
1c79356b 651 struct timeval tv;
1c79356b
A
652
653 authsiz = nfsm_rndup(auth_len);
91447636
A
654 len = authsiz + 10 * NFSX_UNSIGNED;
655 if (len >= nfs_mbuf_minclsize) {
656 error = mbuf_getpacket(MBUF_WAITOK, &mb);
1c79356b 657 } else {
91447636
A
658 error = mbuf_gethdr(MBUF_WAITOK, MBUF_TYPE_DATA, &mb);
659 if (!error) {
660 if (len < nfs_mbuf_mhlen)
661 mbuf_align_32(mb, len);
662 else
663 mbuf_align_32(mb, 8 * NFSX_UNSIGNED);
664 }
665 }
666 if (error) {
667 /* unable to allocate packet */
668 /* XXX nfsstat? */
669 return (error);
1c79356b 670 }
1c79356b 671 mreq = mb;
91447636 672 bpos = mbuf_data(mb);
1c79356b
A
673
674 /*
675 * First the RPC header.
676 */
677 nfsm_build(tl, u_long *, 8 * NFSX_UNSIGNED);
678
679 /*
680 * derive initial xid from system time
1c79356b 681 */
4a249263
A
682 if (!nfs_xid) {
683 /*
684 * Note: it's OK if this code inits nfs_xid to 0 (for example,
685 * due to a broken clock) because we immediately increment it
686 * and we guarantee to never use xid 0. So, nfs_xid should only
687 * ever be 0 the first time this function is called.
688 */
1c79356b 689 microtime(&tv);
4a249263 690 nfs_xid = tv.tv_sec << 12;
1c79356b
A
691 }
692 /*
693 * Skip zero xid if it should ever happen.
694 */
fa4905b1
A
695 if (++nfs_xid == 0) {
696 nfs_xidwrap++;
1c79356b 697 nfs_xid++;
fa4905b1 698 }
1c79356b
A
699
700 *tl++ = *xidp = txdr_unsigned(nfs_xid);
701 *tl++ = rpc_call;
702 *tl++ = rpc_vers;
91447636
A
703 *tl++ = txdr_unsigned(NFS_PROG);
704 if (nmflag & NFSMNT_NFSV3)
705 *tl++ = txdr_unsigned(NFS_VER3);
706 else
707 *tl++ = txdr_unsigned(NFS_VER2);
1c79356b
A
708 if (nmflag & NFSMNT_NFSV3)
709 *tl++ = txdr_unsigned(procid);
710 else
711 *tl++ = txdr_unsigned(nfsv2_procid[procid]);
712
713 /*
714 * And then the authorization cred.
715 */
716 *tl++ = txdr_unsigned(auth_type);
717 *tl = txdr_unsigned(authsiz);
718 switch (auth_type) {
719 case RPCAUTH_UNIX:
720 nfsm_build(tl, u_long *, auth_len);
721 *tl++ = 0; /* stamp ?? */
722 *tl++ = 0; /* NULL hostname */
91447636 723 *tl++ = txdr_unsigned(kauth_cred_getuid(cr));
1c79356b
A
724 *tl++ = txdr_unsigned(cr->cr_groups[0]);
725 grpsiz = (auth_len >> 2) - 5;
726 *tl++ = txdr_unsigned(grpsiz);
727 for (i = 1; i <= grpsiz; i++)
728 *tl++ = txdr_unsigned(cr->cr_groups[i]);
729 break;
730 case RPCAUTH_KERB4:
731 siz = auth_len;
91447636 732 mlen = mbuf_len(mb);
1c79356b 733 while (siz > 0) {
91447636
A
734 if (mbuf_trailingspace(mb) == 0) {
735 mb2 = NULL;
736 if (siz >= nfs_mbuf_minclsize)
737 error = mbuf_mclget(MBUF_WAITOK, MBUF_TYPE_DATA, &mb2);
738 else
739 error = mbuf_get(MBUF_WAITOK, MBUF_TYPE_DATA, &mb2);
740 if (!error)
741 error = mbuf_setnext(mb, mb2);
742 if (error) {
743 mbuf_freem(mreq);
744 return (error);
745 }
1c79356b 746 mb = mb2;
91447636
A
747 mlen = 0;
748 bpos = mbuf_data(mb);
1c79356b 749 }
91447636 750 i = min(siz, mbuf_trailingspace(mb));
1c79356b 751 bcopy(auth_str, bpos, i);
91447636
A
752 mlen += i;
753 mbuf_setlen(mb, mlen);
1c79356b
A
754 auth_str += i;
755 bpos += i;
756 siz -= i;
757 }
758 if ((siz = (nfsm_rndup(auth_len) - auth_len)) > 0) {
759 for (i = 0; i < siz; i++)
760 *bpos++ = '\0';
91447636
A
761 mlen += siz;
762 mbuf_setlen(mb, mlen);
1c79356b
A
763 }
764 break;
765 };
766
767 /*
768 * And the verifier...
769 */
770 nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED);
771 if (verf_str) {
91447636 772 mlen = mbuf_len(mb);
1c79356b
A
773 *tl++ = txdr_unsigned(RPCAUTH_KERB4);
774 *tl = txdr_unsigned(verf_len);
775 siz = verf_len;
776 while (siz > 0) {
91447636
A
777 if (mbuf_trailingspace(mb) == 0) {
778 mb2 = NULL;
779 if (siz >= nfs_mbuf_minclsize)
780 error = mbuf_mclget(MBUF_WAITOK, MBUF_TYPE_DATA, &mb2);
781 else
782 error = mbuf_get(MBUF_WAITOK, MBUF_TYPE_DATA, &mb2);
783 if (!error)
784 error = mbuf_setnext(mb, mb2);
785 if (error) {
786 mbuf_freem(mreq);
787 return (error);
788 }
1c79356b 789 mb = mb2;
91447636
A
790 mlen = 0;
791 bpos = mbuf_data(mb);
1c79356b 792 }
91447636 793 i = min(siz, mbuf_trailingspace(mb));
1c79356b 794 bcopy(verf_str, bpos, i);
91447636
A
795 mlen += i;
796 mbuf_setlen(mb, mlen);
1c79356b
A
797 verf_str += i;
798 bpos += i;
799 siz -= i;
800 }
801 if ((siz = (nfsm_rndup(verf_len) - verf_len)) > 0) {
802 for (i = 0; i < siz; i++)
803 *bpos++ = '\0';
91447636
A
804 mlen += siz;
805 mbuf_setlen(mb, mlen);
1c79356b
A
806 }
807 } else {
808 *tl++ = txdr_unsigned(RPCAUTH_NULL);
809 *tl = 0;
810 }
91447636
A
811 error = mbuf_pkthdr_setrcvif(mreq, 0);
812 if (!error)
813 error = mbuf_setnext(mb, mrest);
814 if (error) {
815 mbuf_freem(mreq);
816 return (error);
817 }
818 mbuf_pkthdr_setlen(mreq, authsiz + 10 * NFSX_UNSIGNED + mrest_len);
1c79356b 819 *mbp = mb;
91447636
A
820 *mreqp = mreq;
821 return (0);
1c79356b
A
822}
823
824/*
825 * copies mbuf chain to the uio scatter/gather list
826 */
827int
828nfsm_mbuftouio(mrep, uiop, siz, dpos)
91447636
A
829 mbuf_t *mrep;
830 struct uio *uiop;
1c79356b
A
831 int siz;
832 caddr_t *dpos;
833{
91447636
A
834 char *mbufcp, *uiocp;
835 int xfer, left, len;
836 mbuf_t mp;
1c79356b
A
837 long uiosiz, rem;
838 int error = 0;
839
840 mp = *mrep;
841 mbufcp = *dpos;
91447636 842 len = (caddr_t)mbuf_data(mp) + mbuf_len(mp) - mbufcp;
1c79356b
A
843 rem = nfsm_rndup(siz)-siz;
844 while (siz > 0) {
91447636 845 if (uiop->uio_iovcnt <= 0 || uiop->uio_iovs.iov32p == NULL)
1c79356b 846 return (EFBIG);
91447636
A
847 // LP64todo - fix this!
848 left = uio_iov_len(uiop);
849 uiocp = CAST_DOWN(caddr_t, uio_iov_base(uiop));
1c79356b
A
850 if (left > siz)
851 left = siz;
852 uiosiz = left;
853 while (left > 0) {
854 while (len == 0) {
91447636 855 mp = mbuf_next(mp);
1c79356b
A
856 if (mp == NULL)
857 return (EBADRPC);
91447636
A
858 mbufcp = mbuf_data(mp);
859 len = mbuf_len(mp);
1c79356b
A
860 }
861 xfer = (left > len) ? len : left;
91447636
A
862 if (UIO_SEG_IS_USER_SPACE(uiop->uio_segflg))
863 copyout(mbufcp, CAST_USER_ADDR_T(uiocp), xfer);
1c79356b 864 else
1c79356b 865 bcopy(mbufcp, uiocp, xfer);
1c79356b
A
866 left -= xfer;
867 len -= xfer;
868 mbufcp += xfer;
869 uiocp += xfer;
870 uiop->uio_offset += xfer;
91447636 871 uio_uio_resid_add(uiop, -xfer);
1c79356b 872 }
91447636 873 if (uio_iov_len(uiop) <= (size_t)siz) {
1c79356b 874 uiop->uio_iovcnt--;
91447636 875 uio_next_iov(uiop);
1c79356b 876 } else {
91447636
A
877 uio_iov_base_add(uiop, uiosiz);
878 uio_iov_len_add(uiop, -uiosiz);
1c79356b
A
879 }
880 siz -= uiosiz;
881 }
882 *dpos = mbufcp;
883 *mrep = mp;
884 if (rem > 0) {
885 if (len < rem)
886 error = nfs_adv(mrep, dpos, rem, len);
887 else
888 *dpos += rem;
889 }
890 return (error);
891}
892
893/*
894 * copies a uio scatter/gather list to an mbuf chain.
895 * NOTE: can ony handle iovcnt == 1
896 */
897int
898nfsm_uiotombuf(uiop, mq, siz, bpos)
91447636
A
899 struct uio *uiop;
900 mbuf_t *mq;
1c79356b
A
901 int siz;
902 caddr_t *bpos;
903{
91447636
A
904 char *uiocp;
905 mbuf_t mp, mp2;
906 int xfer, left, mlen, mplen;
907 int uiosiz, clflg, rem, error;
1c79356b
A
908 char *cp;
909
910 if (uiop->uio_iovcnt != 1)
911 panic("nfsm_uiotombuf: iovcnt != 1");
912
91447636 913 if (siz > nfs_mbuf_mlen) /* or should it >= MCLBYTES ?? */
1c79356b
A
914 clflg = 1;
915 else
916 clflg = 0;
917 rem = nfsm_rndup(siz)-siz;
918 mp = mp2 = *mq;
91447636 919 mplen = mbuf_len(mp);
1c79356b 920 while (siz > 0) {
91447636
A
921 // LP64todo - fix this!
922 left = uio_iov_len(uiop);
923 uiocp = CAST_DOWN(caddr_t, uio_iov_base(uiop));
1c79356b
A
924 if (left > siz)
925 left = siz;
926 uiosiz = left;
927 while (left > 0) {
91447636 928 mlen = mbuf_trailingspace(mp);
1c79356b 929 if (mlen == 0) {
91447636 930 mp = NULL;
1c79356b 931 if (clflg)
91447636
A
932 error = mbuf_mclget(MBUF_WAITOK, MBUF_TYPE_DATA, &mp);
933 else
934 error = mbuf_get(MBUF_WAITOK, MBUF_TYPE_DATA, &mp);
935 if (!error)
936 error = mbuf_setnext(mp2, mp);
937 if (error)
938 return (error);
939 mplen = 0;
1c79356b 940 mp2 = mp;
91447636 941 mlen = mbuf_trailingspace(mp);
1c79356b
A
942 }
943 xfer = (left > mlen) ? mlen : left;
91447636
A
944 if (UIO_SEG_IS_USER_SPACE(uiop->uio_segflg))
945 copyin(CAST_USER_ADDR_T(uiocp), (caddr_t)mbuf_data(mp) + mplen, xfer);
1c79356b 946 else
91447636
A
947 bcopy(uiocp, (caddr_t)mbuf_data(mp) + mplen, xfer);
948 mplen += xfer;
949 mbuf_setlen(mp, mplen);
1c79356b
A
950 left -= xfer;
951 uiocp += xfer;
952 uiop->uio_offset += xfer;
91447636 953 uio_uio_resid_add(uiop, -xfer);
1c79356b 954 }
91447636
A
955 uio_iov_base_add(uiop, uiosiz);
956 uio_iov_len_add(uiop, -uiosiz);
1c79356b
A
957 siz -= uiosiz;
958 }
959 if (rem > 0) {
91447636
A
960 if (rem > mbuf_trailingspace(mp)) {
961 error = mbuf_get(MBUF_WAITOK, MBUF_TYPE_DATA, &mp);
962 if (!error)
963 error = mbuf_setnext(mp2, mp);
964 if (error)
965 return (error);
966 mplen = 0;
1c79356b 967 }
91447636 968 cp = (caddr_t)mbuf_data(mp) + mplen;
1c79356b
A
969 for (left = 0; left < rem; left++)
970 *cp++ = '\0';
91447636
A
971 mplen += rem;
972 mbuf_setlen(mp, mplen);
1c79356b 973 *bpos = cp;
91447636
A
974 } else {
975 *bpos = (caddr_t)mbuf_data(mp) + mplen;
976 }
1c79356b
A
977 *mq = mp;
978 return (0);
979}
980
981/*
982 * Help break down an mbuf chain by setting the first siz bytes contiguous
983 * pointed to by returned val.
984 * This is used by the macros nfsm_dissect and nfsm_dissecton for tough
985 * cases. (The macros use the vars. dpos and dpos2)
986 */
987int
988nfsm_disct(mdp, dposp, siz, left, cp2)
91447636 989 mbuf_t *mdp;
1c79356b
A
990 caddr_t *dposp;
991 int siz;
992 int left;
993 caddr_t *cp2;
994{
91447636
A
995 mbuf_t mp, mp2;
996 int siz2, xfer, error, mp2len;
997 caddr_t p, mp2data;
1c79356b
A
998
999 mp = *mdp;
1000 while (left == 0) {
91447636 1001 *mdp = mp = mbuf_next(mp);
1c79356b
A
1002 if (mp == NULL)
1003 return (EBADRPC);
91447636
A
1004 left = mbuf_len(mp);
1005 *dposp = mbuf_data(mp);
1c79356b
A
1006 }
1007 if (left >= siz) {
1008 *cp2 = *dposp;
1009 *dposp += siz;
91447636 1010 } else if (mbuf_next(mp) == NULL) {
1c79356b 1011 return (EBADRPC);
91447636 1012 } else if (siz > nfs_mbuf_mhlen) {
1c79356b
A
1013 panic("nfs S too big");
1014 } else {
91447636
A
1015 error = mbuf_get(MBUF_WAITOK, MBUF_TYPE_DATA, &mp2);
1016 if (error)
1017 return (error);
1018 error = mbuf_setnext(mp2, mbuf_next(mp));
1019 if (!error)
1020 error = mbuf_setnext(mp, mp2);
1021 if (error) {
1022 mbuf_free(mp2);
1023 return (error);
1024 }
1025 mbuf_setlen(mp, mbuf_len(mp) - left);
1c79356b 1026 mp = mp2;
91447636 1027 *cp2 = p = mbuf_data(mp);
1c79356b
A
1028 bcopy(*dposp, p, left); /* Copy what was left */
1029 siz2 = siz-left;
1030 p += left;
91447636
A
1031 mp2 = mbuf_next(mp);
1032 mp2data = mbuf_data(mp2);
1033 mp2len = mbuf_len(mp2);
1c79356b
A
1034 /* Loop around copying up the siz2 bytes */
1035 while (siz2 > 0) {
1036 if (mp2 == NULL)
1037 return (EBADRPC);
91447636 1038 xfer = (siz2 > mp2len) ? mp2len : siz2;
1c79356b 1039 if (xfer > 0) {
91447636
A
1040 bcopy(mp2data, p, xfer);
1041 mp2data += xfer;
1042 mp2len -= xfer;
1043 mbuf_setdata(mp2, mp2data, mp2len);
1c79356b
A
1044 p += xfer;
1045 siz2 -= xfer;
1046 }
91447636
A
1047 if (siz2 > 0) {
1048 mp2 = mbuf_next(mp2);
1049 mp2data = mbuf_data(mp2);
1050 mp2len = mbuf_len(mp2);
1051 }
1c79356b 1052 }
91447636 1053 mbuf_setlen(mp, siz);
1c79356b 1054 *mdp = mp2;
91447636 1055 *dposp = mp2data;
1c79356b
A
1056 }
1057 return (0);
1058}
1059
1060/*
1061 * Advance the position in the mbuf chain.
1062 */
1063int
1064nfs_adv(mdp, dposp, offs, left)
91447636 1065 mbuf_t *mdp;
1c79356b
A
1066 caddr_t *dposp;
1067 int offs;
1068 int left;
1069{
91447636
A
1070 mbuf_t m;
1071 int s;
1c79356b
A
1072
1073 m = *mdp;
1074 s = left;
1075 while (s < offs) {
1076 offs -= s;
91447636 1077 m = mbuf_next(m);
1c79356b
A
1078 if (m == NULL)
1079 return (EBADRPC);
91447636 1080 s = mbuf_len(m);
1c79356b
A
1081 }
1082 *mdp = m;
91447636 1083 *dposp = (caddr_t)mbuf_data(m) + offs;
1c79356b
A
1084 return (0);
1085}
1086
1087/*
1088 * Copy a string into mbufs for the hard cases...
1089 */
1090int
1091nfsm_strtmbuf(mb, bpos, cp, siz)
91447636 1092 mbuf_t *mb;
1c79356b
A
1093 char **bpos;
1094 char *cp;
1095 long siz;
1096{
91447636
A
1097 mbuf_t m1 = NULL, m2;
1098 long left, xfer, len, tlen, mlen;
1c79356b 1099 u_long *tl;
91447636 1100 int putsize, error;
1c79356b
A
1101
1102 putsize = 1;
1103 m2 = *mb;
91447636
A
1104 left = mbuf_trailingspace(m2);
1105 if (left >= NFSX_UNSIGNED) {
1c79356b
A
1106 tl = ((u_long *)(*bpos));
1107 *tl++ = txdr_unsigned(siz);
1108 putsize = 0;
1109 left -= NFSX_UNSIGNED;
91447636
A
1110 len = mbuf_len(m2);
1111 len += NFSX_UNSIGNED;
1112 mbuf_setlen(m2, len);
1c79356b
A
1113 if (left > 0) {
1114 bcopy(cp, (caddr_t) tl, left);
1115 siz -= left;
1116 cp += left;
91447636
A
1117 len += left;
1118 mbuf_setlen(m2, len);
1c79356b
A
1119 left = 0;
1120 }
1121 }
1122 /* Loop around adding mbufs */
1123 while (siz > 0) {
91447636
A
1124 m1 = NULL;
1125 if (siz > nfs_mbuf_mlen)
1126 error = mbuf_mclget(MBUF_WAITOK, MBUF_TYPE_DATA, &m1);
1127 else
1128 error = mbuf_get(MBUF_WAITOK, MBUF_TYPE_DATA, &m1);
1129 if (!error)
1130 error = mbuf_setnext(m2, m1);
1131 if (error)
1132 return (error);
1133 mlen = mbuf_maxlen(m1);
1134 mbuf_setlen(m1, mlen);
1c79356b 1135 m2 = m1;
91447636 1136 tl = mbuf_data(m1);
1c79356b
A
1137 tlen = 0;
1138 if (putsize) {
1139 *tl++ = txdr_unsigned(siz);
91447636
A
1140 mlen -= NFSX_UNSIGNED;
1141 mbuf_setlen(m1, mlen);
1c79356b
A
1142 tlen = NFSX_UNSIGNED;
1143 putsize = 0;
1144 }
91447636 1145 if (siz < mlen) {
1c79356b
A
1146 len = nfsm_rndup(siz);
1147 xfer = siz;
1148 if (xfer < len)
1149 *(tl+(xfer>>2)) = 0;
1150 } else {
91447636 1151 xfer = len = mlen;
1c79356b
A
1152 }
1153 bcopy(cp, (caddr_t) tl, xfer);
91447636 1154 mbuf_setlen(m1, len + tlen);
1c79356b
A
1155 siz -= xfer;
1156 cp += xfer;
1157 }
1158 *mb = m1;
91447636 1159 *bpos = (caddr_t)mbuf_data(m1) + mbuf_len(m1);
1c79356b
A
1160 return (0);
1161}
1162
1163/*
1164 * Called once to initialize data structures...
1165 */
1166int
91447636 1167nfs_init(struct vfsconf *vfsp)
1c79356b 1168{
91447636 1169 int i;
1c79356b
A
1170
1171 /*
1172 * Check to see if major data structures haven't bloated.
1173 */
1174 if (sizeof (struct nfsnode) > NFS_NODEALLOC) {
1175 printf("struct nfsnode bloated (> %dbytes)\n", NFS_NODEALLOC);
1176 printf("Try reducing NFS_SMALLFH\n");
1177 }
1178 if (sizeof (struct nfsmount) > NFS_MNTALLOC) {
1179 printf("struct nfsmount bloated (> %dbytes)\n", NFS_MNTALLOC);
1180 printf("Try reducing NFS_MUIDHASHSIZ\n");
1181 }
1182 if (sizeof (struct nfssvc_sock) > NFS_SVCALLOC) {
1183 printf("struct nfssvc_sock bloated (> %dbytes)\n",NFS_SVCALLOC);
1184 printf("Try reducing NFS_UIDHASHSIZ\n");
1185 }
1186 if (sizeof (struct nfsuid) > NFS_UIDALLOC) {
1187 printf("struct nfsuid bloated (> %dbytes)\n",NFS_UIDALLOC);
1188 printf("Try unionizing the nu_nickname and nu_flag fields\n");
1189 }
91447636 1190
1c79356b
A
1191 nfs_mount_type = vfsp->vfc_typenum;
1192 nfsrtt.pos = 0;
1193 rpc_vers = txdr_unsigned(RPC_VER2);
1194 rpc_call = txdr_unsigned(RPC_CALL);
1195 rpc_reply = txdr_unsigned(RPC_REPLY);
1196 rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED);
1197 rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED);
1198 rpc_mismatch = txdr_unsigned(RPC_MISMATCH);
1199 rpc_autherr = txdr_unsigned(RPC_AUTHERR);
1200 rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX);
1201 rpc_auth_kerb = txdr_unsigned(RPCAUTH_KERB4);
1202 nfs_prog = txdr_unsigned(NFS_PROG);
1c79356b
A
1203 nfs_true = txdr_unsigned(TRUE);
1204 nfs_false = txdr_unsigned(FALSE);
1205 nfs_xdrneg1 = txdr_unsigned(-1);
91447636 1206
1c79356b
A
1207 nfs_ticks = (hz * NFS_TICKINTVL + 500) / 1000;
1208 if (nfs_ticks < 1)
1209 nfs_ticks = 1;
1210 /* Ensure async daemons disabled */
1211 for (i = 0; i < NFS_MAXASYNCDAEMON; i++) {
91447636 1212 nfs_iodwant[i] = NULL;
1c79356b
A
1213 nfs_iodmount[i] = (struct nfsmount *)0;
1214 }
91447636
A
1215 /* init nfsiod mutex */
1216 nfs_iod_lck_grp_attr = lck_grp_attr_alloc_init();
91447636
A
1217 nfs_iod_lck_grp = lck_grp_alloc_init("nfs_iod", nfs_iod_lck_grp_attr);
1218 nfs_iod_lck_attr = lck_attr_alloc_init();
1219 nfs_iod_mutex = lck_mtx_alloc_init(nfs_iod_lck_grp, nfs_iod_lck_attr);
1220
55e303ae 1221 nfs_nbinit(); /* Init the nfsbuf table */
1c79356b 1222 nfs_nhinit(); /* Init the nfsnode table */
e5568f75 1223 nfs_lockinit(); /* Init the nfs lock state */
91447636 1224
1c79356b 1225#ifndef NFS_NOSERVER
91447636
A
1226 /* init nfsd mutex */
1227 nfsd_lck_grp_attr = lck_grp_attr_alloc_init();
91447636
A
1228 nfsd_lck_grp = lck_grp_alloc_init("nfsd", nfsd_lck_grp_attr);
1229 nfsd_lck_attr = lck_attr_alloc_init();
1230 nfsd_mutex = lck_mtx_alloc_init(nfsd_lck_grp, nfsd_lck_attr);
1231
1232 /* init slp rwlock */
1233 nfs_slp_lock_attr = lck_attr_alloc_init();
1234 nfs_slp_group_attr = lck_grp_attr_alloc_init();
1235 nfs_slp_rwlock_group = lck_grp_alloc_init("nfs-slp-rwlock", nfs_slp_group_attr);
1236 nfs_slp_mutex_group = lck_grp_alloc_init("nfs-slp-mutex", nfs_slp_group_attr);
1237
1238 /* init export data structures */
1239 nfsexphashtbl = hashinit(8, M_TEMP, &nfsexphash);
1240 LIST_INIT(&nfs_exports);
1241 nfs_export_lock_attr = lck_attr_alloc_init();
1242 nfs_export_group_attr = lck_grp_attr_alloc_init();
1243 nfs_export_rwlock_group = lck_grp_alloc_init("nfs-export-rwlock", nfs_export_group_attr);
1244 lck_rw_init(&nfs_export_rwlock, nfs_export_rwlock_group, nfs_export_lock_attr);
1245
1246 lck_mtx_lock(nfsd_mutex);
1c79356b
A
1247 nfsrv_init(0); /* Init server data structures */
1248 nfsrv_initcache(); /* Init the server request cache */
91447636 1249 lck_mtx_unlock(nfsd_mutex);
1c79356b
A
1250#endif
1251
1c79356b
A
1252 /*
1253 * Initialize reply list and start timer
1254 */
1255 TAILQ_INIT(&nfs_reqq);
1256
1257 nfs_timer(0);
1258
1c79356b 1259 vfsp->vfc_refcount++; /* make us non-unloadable */
1c79356b
A
1260 return (0);
1261}
1262
1263/*
91447636 1264 * initialize NFS's cache of mbuf constants
1c79356b 1265 */
91447636
A
1266void
1267nfs_mbuf_init(void)
1268{
1269 struct mbuf_stat ms;
1270
1271 mbuf_stats(&ms);
1272 nfs_mbuf_mlen = ms.mlen;
1273 nfs_mbuf_mhlen = ms.mhlen;
1274 nfs_mbuf_minclsize = ms.minclsize;
1275 nfs_mbuf_mclbytes = ms.mclbytes;
1276}
1c79356b
A
1277
1278/*
91447636 1279 * Parse the attributes that are in the mbuf list and store them in *nvap.
1c79356b
A
1280 */
1281int
91447636 1282nfs_parsefattr(mbuf_t *mdp, caddr_t *dposp, int v3, struct nfs_vattr *nvap)
1c79356b 1283{
91447636
A
1284 struct nfs_fattr *fp;
1285 long t1;
1c79356b
A
1286 caddr_t cp2;
1287 int error = 0, rdev;
91447636
A
1288 mbuf_t md;
1289 enum vtype vtype;
1c79356b 1290 u_short vmode;
55e303ae 1291
1c79356b 1292 md = *mdp;
91447636 1293 t1 = ((caddr_t)mbuf_data(md) + mbuf_len(md)) - *dposp;
fa4905b1 1294 if ((error = nfsm_disct(mdp, dposp, NFSX_FATTR(v3), t1, &cp2))) {
1c79356b 1295 return (error);
fa4905b1 1296 }
1c79356b
A
1297 fp = (struct nfs_fattr *)cp2;
1298 if (v3) {
91447636 1299 vtype = nfsv3tov_type(fp->fa_type);
1c79356b
A
1300 vmode = fxdr_unsigned(u_short, fp->fa_mode);
1301 rdev = makedev(fxdr_unsigned(int, fp->fa3_rdev.specdata1),
1302 fxdr_unsigned(int, fp->fa3_rdev.specdata2));
1c79356b 1303 } else {
91447636 1304 vtype = nfsv2tov_type(fp->fa_type);
1c79356b
A
1305 vmode = fxdr_unsigned(u_short, fp->fa_mode);
1306 /*
1307 * XXX
1308 *
1309 * The duplicate information returned in fa_type and fa_mode
1310 * is an ambiguity in the NFS version 2 protocol.
1311 *
1312 * VREG should be taken literally as a regular file. If a
1313 * server intents to return some type information differently
1314 * in the upper bits of the mode field (e.g. for sockets, or
1315 * FIFOs), NFSv2 mandates fa_type to be VNON. Anyway, we
1316 * leave the examination of the mode bits even in the VREG
1317 * case to avoid breakage for bogus servers, but we make sure
1318 * that there are actually type bits set in the upper part of
1319 * fa_mode (and failing that, trust the va_type field).
1320 *
1321 * NFSv3 cleared the issue, and requires fa_mode to not
1322 * contain any type information (while also introduing sockets
1323 * and FIFOs for fa_type).
1324 */
91447636
A
1325 if (vtype == VNON || (vtype == VREG && (vmode & S_IFMT) != 0))
1326 vtype = IFTOVT(vmode);
1c79356b 1327 rdev = fxdr_unsigned(long, fp->fa2_rdev);
1c79356b
A
1328 /*
1329 * Really ugly NFSv2 kludge.
1330 */
91447636
A
1331 if (vtype == VCHR && rdev == (int)0xffffffff)
1332 vtype = VFIFO;
1333 }
1334
1335 nvap->nva_type = vtype;
1336 nvap->nva_mode = (vmode & 07777);
1337 nvap->nva_rdev = (dev_t)rdev;
1338 nvap->nva_nlink = (uint64_t)fxdr_unsigned(u_long, fp->fa_nlink);
1339 nvap->nva_uid = fxdr_unsigned(uid_t, fp->fa_uid);
1340 nvap->nva_gid = fxdr_unsigned(gid_t, fp->fa_gid);
1341 if (v3) {
1342 fxdr_hyper(&fp->fa3_size, &nvap->nva_size);
1343 nvap->nva_blocksize = 16*1024;
1344 fxdr_hyper(&fp->fa3_used, &nvap->nva_bytes);
1345 fxdr_hyper(&fp->fa3_fileid, &nvap->nva_fileid);
1346 fxdr_nfsv3time(&fp->fa3_atime, &nvap->nva_atime);
1347 fxdr_nfsv3time(&fp->fa3_mtime, &nvap->nva_mtime);
1348 fxdr_nfsv3time(&fp->fa3_ctime, &nvap->nva_ctime);
1349 } else {
1350 nvap->nva_size = fxdr_unsigned(u_long, fp->fa2_size);
1351 nvap->nva_blocksize = fxdr_unsigned(long, fp->fa2_blocksize);
1352 nvap->nva_bytes = fxdr_unsigned(long, fp->fa2_blocks) * NFS_FABLKSIZE;
1353 nvap->nva_fileid = (uint64_t)fxdr_unsigned(u_long, fp->fa2_fileid);
1354 fxdr_nfsv2time(&fp->fa2_atime, &nvap->nva_atime);
1355 fxdr_nfsv2time(&fp->fa2_mtime, &nvap->nva_mtime);
1356 fxdr_nfsv2time(&fp->fa2_ctime, &nvap->nva_ctime);
1357 }
1358
1359 return (0);
1360}
1361
1362/*
1363 * Load the attribute cache (that lives in the nfsnode entry) with
1364 * the value pointed to by nvap, unless the file type in the attribute
1365 * cache doesn't match the file type in the nvap, in which case log a
1366 * warning and return ESTALE.
1367 *
1368 * If the dontshrink flag is set, then it's not safe to call ubc_setsize()
1369 * to shrink the size of the file.
1370 */
1371int
1372nfs_loadattrcache(
1373 struct nfsnode *np,
1374 struct nfs_vattr *nvap,
1375 u_int64_t *xidp,
1376 int dontshrink)
1377{
1378 mount_t mp;
1379 vnode_t vp;
1380 struct timeval now;
1381 struct nfs_vattr *npnvap;
1382
1383 if (np->n_flag & NINIT) {
1384 vp = NULL;
1385 mp = np->n_mount;
1386 } else {
1387 vp = NFSTOV(np);
1388 mp = vnode_mount(vp);
1389 }
1390
1391 FSDBG_TOP(527, vp, np, *xidp >> 32, *xidp);
1392
1393 if (!VFSTONFS(mp)) {
1394 FSDBG_BOT(527, ENXIO, 1, 0, *xidp);
1395 return (ENXIO);
1c79356b
A
1396 }
1397
55e303ae 1398 if (*xidp < np->n_xid) {
fa4905b1
A
1399 /*
1400 * We have already updated attributes with a response from
1401 * a later request. The attributes we have here are probably
1402 * stale so we drop them (just return). However, our
1403 * out-of-order receipt could be correct - if the requests were
1404 * processed out of order at the server. Given the uncertainty
1405 * we invalidate our cached attributes. *xidp is zeroed here
1406 * to indicate the attributes were dropped - only getattr
1407 * cares - it needs to retry the rpc.
1408 */
91447636 1409 NATTRINVALIDATE(np);
fa4905b1
A
1410 FSDBG_BOT(527, 0, np, np->n_xid, *xidp);
1411 *xidp = 0;
1412 return (0);
1413 }
1c79356b 1414
91447636
A
1415 if (vp && (nvap->nva_type != vnode_vtype(vp))) {
1416 /*
1417 * The filehandle has changed type on us. This can be
1418 * caused by either the server not having unique filehandles
1419 * or because another client has removed the previous
1420 * filehandle and a new object (of a different type)
1421 * has been created with the same filehandle.
1422 *
1423 * We can't simply switch the type on the vnode because
1424 * there may be type-specific fields that need to be
1425 * cleaned up or set up.
1426 *
1427 * So, what should we do with this vnode?
1428 *
1429 * About the best we can do is log a warning and return
1430 * an error. ESTALE is about the closest error, but it
1431 * is a little strange that we come up with this error
1432 * internally instead of simply passing it through from
1433 * the server. Hopefully, the vnode will be reclaimed
1434 * soon so the filehandle can be reincarnated as the new
1435 * object type.
1436 */
1437 printf("nfs loadattrcache vnode changed type, was %d now %d\n",
1438 vnode_vtype(vp), nvap->nva_type);
1439 FSDBG_BOT(527, ESTALE, 3, 0, *xidp);
1440 return (ESTALE);
1c79356b
A
1441 }
1442
55e303ae
A
1443 microuptime(&now);
1444 np->n_attrstamp = now.tv_sec;
91447636 1445 np->n_xid = *xidp;
55e303ae 1446
91447636
A
1447 npnvap = &np->n_vattr;
1448 nvap->nva_fsid = vfs_statfs(mp)->f_fsid.val[0];
1449 bcopy((caddr_t)nvap, (caddr_t)npnvap, sizeof(*nvap));
1c79356b 1450
91447636
A
1451 if (vp) {
1452 if (nvap->nva_size != np->n_size) {
1453 FSDBG(527, vp, nvap->nva_size, np->n_size,
1454 (nvap->nva_type == VREG) |
1455 (np->n_flag & NMODIFIED ? 6 : 4));
1456 if (nvap->nva_type == VREG) {
743b1565 1457 u_quad_t orig_size = np->n_size;
91447636
A
1458 if (np->n_flag & NMODIFIED) {
1459 if (nvap->nva_size < np->n_size)
1460 nvap->nva_size = np->n_size;
1461 else
1462 np->n_size = nvap->nva_size;
1463 } else
1464 np->n_size = nvap->nva_size;
1465 if (!UBCINFOEXISTS(vp) ||
1466 (dontshrink && np->n_size < (u_quad_t)ubc_getsize(vp))) {
1467 nvap->nva_size = np->n_size = orig_size;
1468 NATTRINVALIDATE(np);
1469 } else {
1470 ubc_setsize(vp, (off_t)np->n_size); /* XXX */
1471 }
1c79356b 1472 } else
91447636
A
1473 np->n_size = nvap->nva_size;
1474 }
1475 } else {
1476 np->n_size = nvap->nva_size;
1c79356b
A
1477 }
1478
91447636
A
1479 if (np->n_flag & NCHG) {
1480 if (np->n_flag & NACC)
1481 nvap->nva_atime = np->n_atim;
1482 if (np->n_flag & NUPD)
1483 nvap->nva_mtime = np->n_mtim;
1c79356b 1484 }
91447636 1485
fa4905b1 1486 FSDBG_BOT(527, 0, np, 0, *xidp);
1c79356b
A
1487 return (0);
1488}
1489
1490/*
91447636
A
1491 * Calculate the attribute timeout based on
1492 * how recently the file has been modified.
1c79356b
A
1493 */
1494int
91447636 1495nfs_attrcachetimeout(vnode_t vp)
1c79356b 1496{
91447636
A
1497 struct nfsnode *np = VTONFS(vp);
1498 struct nfsmount *nmp;
1499 struct timeval now;
1500 int isdir, timeo;
55e303ae 1501
91447636
A
1502 if (!(nmp = VFSTONFS(vnode_mount(vp))))
1503 return (0);
1504
1505 isdir = vnode_isdir(vp);
ab86ba33 1506
55e303ae 1507 if ((np)->n_flag & NMODIFIED)
91447636 1508 timeo = isdir ? nmp->nm_acdirmin : nmp->nm_acregmin;
55e303ae
A
1509 else {
1510 /* Note that if the client and server clocks are way out of sync, */
1511 /* timeout will probably get clamped to a min or max value */
1512 microtime(&now);
91447636
A
1513 timeo = (now.tv_sec - (np)->n_mtime.tv_sec) / 10;
1514 if (isdir) {
1515 if (timeo < nmp->nm_acdirmin)
1516 timeo = nmp->nm_acdirmin;
1517 else if (timeo > nmp->nm_acdirmax)
1518 timeo = nmp->nm_acdirmax;
1519 } else {
1520 if (timeo < nmp->nm_acregmin)
1521 timeo = nmp->nm_acregmin;
1522 else if (timeo > nmp->nm_acregmax)
1523 timeo = nmp->nm_acregmax;
1524 }
55e303ae 1525 }
1c79356b 1526
91447636
A
1527 return (timeo);
1528}
1529
1530/*
1531 * Check the time stamp
1532 * If the cache is valid, copy contents to *nvaper and return 0
1533 * otherwise return an error
1534 */
1535int
1536nfs_getattrcache(vp, nvaper)
1537 vnode_t vp;
1538 struct nfs_vattr *nvaper;
1539{
1540 struct nfsnode *np = VTONFS(vp);
1541 struct nfs_vattr *nvap;
1542 struct timeval nowup;
1543 int32_t timeo;
1544
1545 if (!NATTRVALID(np)) {
1546 FSDBG(528, vp, 0, 0, 0);
1547 OSAddAtomic(1, (SInt32*)&nfsstats.attrcache_misses);
1548 return (ENOENT);
1549 }
1550
1551 timeo = nfs_attrcachetimeout(vp);
1552
55e303ae
A
1553 microuptime(&nowup);
1554 if ((nowup.tv_sec - np->n_attrstamp) >= timeo) {
fa4905b1 1555 FSDBG(528, vp, 0, 0, 1);
91447636 1556 OSAddAtomic(1, (SInt32*)&nfsstats.attrcache_misses);
1c79356b
A
1557 return (ENOENT);
1558 }
fa4905b1 1559 FSDBG(528, vp, 0, 0, 2);
91447636
A
1560 OSAddAtomic(1, (SInt32*)&nfsstats.attrcache_hits);
1561 nvap = &np->n_vattr;
1c79356b 1562
91447636
A
1563 if (nvap->nva_size != np->n_size) {
1564 FSDBG(528, vp, nvap->nva_size, np->n_size,
1565 (nvap->nva_type == VREG) |
fa4905b1 1566 (np->n_flag & NMODIFIED ? 6 : 4));
91447636 1567 if (nvap->nva_type == VREG) {
1c79356b 1568 if (np->n_flag & NMODIFIED) {
91447636
A
1569 if (nvap->nva_size < np->n_size)
1570 nvap->nva_size = np->n_size;
1c79356b 1571 else
91447636 1572 np->n_size = nvap->nva_size;
1c79356b 1573 } else
91447636 1574 np->n_size = nvap->nva_size;
fa4905b1 1575 ubc_setsize(vp, (off_t)np->n_size); /* XXX */
1c79356b 1576 } else
91447636 1577 np->n_size = nvap->nva_size;
1c79356b
A
1578 }
1579
91447636 1580 bcopy((caddr_t)nvap, (caddr_t)nvaper, sizeof(struct nfs_vattr));
1c79356b
A
1581 if (np->n_flag & NCHG) {
1582 if (np->n_flag & NACC)
91447636 1583 nvaper->nva_atime = np->n_atim;
1c79356b 1584 if (np->n_flag & NUPD)
91447636 1585 nvaper->nva_mtime = np->n_mtim;
1c79356b
A
1586 }
1587 return (0);
1588}
1589
1590#ifndef NFS_NOSERVER
1591/*
91447636
A
1592 * Extract a lookup path from the given mbufs and store it in
1593 * a newly allocated buffer saved in the given nameidata structure.
1594 * exptected string length given as *lenp and final string length
1595 * (after any WebNFS processing) is returned in *lenp.
1c79356b
A
1596 */
1597int
91447636
A
1598nfsm_path_mbuftond(
1599 mbuf_t *mdp,
1600 caddr_t *dposp,
1601 __unused int v3,
1602 __unused int pubflag,
1603 int* lenp,
1604 struct nameidata *ndp)
1c79356b 1605{
91447636
A
1606 int i, len, len2, rem, error = 0;
1607 mbuf_t md;
1608 char *fromcp, *tocp;
1c79356b 1609 struct componentname *cnp = &ndp->ni_cnd;
91447636
A
1610/* XXX Revisit when enabling WebNFS */
1611#ifdef WEBNFS_ENABLED
1612 int webcnt = 0, digitcnt = 0;
1613 char hexdigits[2];
1614#endif
55e303ae 1615
91447636
A
1616 len = *lenp;
1617 if (len > (MAXPATHLEN - 1))
55e303ae
A
1618 return (ENAMETOOLONG);
1619
91447636
A
1620 /*
1621 * Get a buffer for the name to be translated, and copy the
1622 * name into the buffer.
1623 */
1624 MALLOC_ZONE(cnp->cn_pnbuf, caddr_t, MAXPATHLEN, M_NAMEI, M_WAITOK);
1625 if (!cnp->cn_pnbuf)
1626 return (ENOMEM);
55e303ae 1627 cnp->cn_pnlen = MAXPATHLEN;
91447636 1628 cnp->cn_flags |= HASBUF;
1c79356b
A
1629
1630 /*
91447636
A
1631 * Copy the name from the mbuf list to the string
1632 *
1633 * Along the way, take note of any WebNFS characters
1634 * and convert any % escapes.
1c79356b
A
1635 */
1636 fromcp = *dposp;
1637 tocp = cnp->cn_pnbuf;
1638 md = *mdp;
91447636 1639 rem = (caddr_t)mbuf_data(md) + mbuf_len(md) - fromcp;
1c79356b
A
1640 for (i = 1; i <= len; i++) {
1641 while (rem == 0) {
91447636 1642 md = mbuf_next(md);
1c79356b
A
1643 if (md == NULL) {
1644 error = EBADRPC;
1645 goto out;
1646 }
91447636
A
1647 fromcp = mbuf_data(md);
1648 rem = mbuf_len(md);
1c79356b 1649 }
91447636
A
1650/* XXX Revisit when enabling WebNFS */
1651#ifdef WEBNFS_ENABLED
1652 if (pubflag) {
1653 if ((i == 1) && ((unsigned char)*fromcp >= WEBNFS_SPECCHAR_START)) {
1654 switch ((unsigned char)*fromcp) {
1655 case WEBNFS_NATIVE_CHAR:
1656 /*
1657 * 'Native' path for us is the same
1658 * as a path according to the NFS spec,
1659 * just skip the escape char.
1660 */
1661 webcnt++;
1662 fromcp++;
1663 rem--;
1664 /* next iteration of for loop */
1665 continue;
1666 /*
1667 * More may be added in the future, range 0x80-0xff.
1668 * Don't currently support security query lookup (0x81).
1669 */
1670 default:
1671 error = EIO;
1672 goto out;
1673 }
1674 }
1675 if (digitcnt) {
1676 /* We're expecting hex digits */
1677 if (!ISHEX(*fromcp)) {
1678 error = ENOENT;
1679 goto out;
1680 }
1681 digitcnt--;
1682 hexdigits[digitcnt ? 0 : 1] = *fromcp++;
1683 if (!digitcnt)
1684 *tocp++ = HEXSTRTOI(hexdigits);
1685 rem--;
1686 /* next iteration of for loop */
1687 continue;
1688 } else if (*fromcp == WEBNFS_ESC_CHAR) {
1689 /*
1690 * We can't really look at the next couple
1691 * bytes here safely/easily, so we note that
1692 * the next two characters should be hex
1693 * digits and later save them in hexdigits[].
1694 * When we've got both, we'll convert it.
1695 */
1696 digitcnt = 2;
1697 webcnt += 2;
1698 fromcp++;
1699 rem--;
1700 /* next iteration of for loop */
1701 continue;
1702 }
1703 }
1704 if (*fromcp == '\0' || (!pubflag && *fromcp == '/'))
1c79356b 1705#else
91447636 1706 if (*fromcp == '\0' || *fromcp == '/')
1c79356b 1707#endif
91447636 1708 {
1c79356b
A
1709 error = EACCES;
1710 goto out;
1711 }
1c79356b
A
1712 *tocp++ = *fromcp++;
1713 rem--;
1714 }
1715 *tocp = '\0';
1716 *mdp = md;
1717 *dposp = fromcp;
91447636
A
1718 len2 = nfsm_rndup(len)-len;
1719 if (len2 > 0) {
1720 if (rem >= len2)
1721 *dposp += len2;
1722 else if ((error = nfs_adv(mdp, dposp, len2, rem)) != 0)
1c79356b
A
1723 goto out;
1724 }
1725
91447636
A
1726/* XXX Revisit when enabling WebNFS */
1727#ifdef WEBNFS_ENABLED
1728 if (pubflag) {
1729 if (digitcnt) {
1730 /* The string ended in the middle of an escape! */
1731 error = ENOENT;
1732 goto out;
1733 }
1734 len -= webcnt;
1735 }
1736#endif
1737
1738out:
1739 if (error) {
1740 if (cnp->cn_pnbuf)
1741 FREE_ZONE(cnp->cn_pnbuf, MAXPATHLEN, M_NAMEI);
1742 cnp->cn_flags &= ~HASBUF;
1743 } else {
1744 ndp->ni_pathlen = len;
1745 *lenp = len;
1746 }
1747 return (error);
1748}
1749
1750/*
1751 * Set up nameidata for a lookup() call and do it.
1752 *
1753 * If pubflag is set, this call is done for a lookup operation on the
1754 * public filehandle. In that case we allow crossing mountpoints and
1755 * absolute pathnames. However, the caller is expected to check that
1756 * the lookup result is within the public fs, and deny access if
1757 * it is not.
1758 */
1759int
1760nfs_namei(
1761 struct nfsrv_descript *nfsd,
1762 struct vfs_context *ctx,
1763 struct nameidata *ndp,
1764 struct nfs_filehandle *nfhp,
1765 mbuf_t nam,
1766 int pubflag,
1767 vnode_t *retdirp,
1768 struct nfs_export **nxp,
1769 struct nfs_export_options **nxop)
1770{
1771/* XXX Revisit when enabling WebNFS */
1772#ifdef WEBNFS_ENABLED
1773 char *cp;
1774 uio_t auio;
1775 char uio_buf[ UIO_SIZEOF(1) ];
1776 int linklen, olen = ndp->ni_pathlen;
1777#endif
1778 vnode_t dp;
1779 int error;
1780 struct componentname *cnp = &ndp->ni_cnd;
1781 char *tmppn;
1782
1783 *retdirp = NULL;
1784
1c79356b
A
1785 /*
1786 * Extract and set starting directory.
1787 */
91447636 1788 error = nfsrv_fhtovp(nfhp, nam, pubflag, &dp, nxp, nxop);
1c79356b
A
1789 if (error)
1790 goto out;
91447636
A
1791 error = nfsrv_credcheck(nfsd, *nxp, *nxop);
1792 if (error || (vnode_vtype(dp) != VDIR)) {
1793 vnode_put(dp);
1c79356b
A
1794 error = ENOTDIR;
1795 goto out;
1796 }
1797
91447636
A
1798 ctx->vc_ucred = nfsd->nd_cr;
1799 ndp->ni_cnd.cn_context = ctx;
1800
1801 if (*nxop && ((*nxop)->nxo_flags & NX_READONLY))
1c79356b
A
1802 cnp->cn_flags |= RDONLY;
1803
1804 *retdirp = dp;
1805
91447636
A
1806/* XXX Revisit when enabling WebNFS */
1807#ifdef WEBNFS_ENABLED
1c79356b
A
1808 if (pubflag) {
1809 ndp->ni_rootdir = rootvnode;
1810 ndp->ni_loopcnt = 0;
91447636
A
1811 if (cnp->cn_pnbuf[0] == '/') {
1812 vnode_put(dp);
1c79356b 1813 dp = rootvnode;
91447636
A
1814 error = vnode_get(dp);
1815 if (error) {
1816 *retdirp = NULL;
1817 goto out;
1818 }
1819 }
1c79356b
A
1820 } else {
1821 cnp->cn_flags |= NOCROSSMOUNT;
1822 }
1823#else
1824 cnp->cn_flags |= NOCROSSMOUNT;
1825#endif
1826
91447636 1827 ndp->ni_usedvp = dp;
1c79356b
A
1828
1829 for (;;) {
1830 cnp->cn_nameptr = cnp->cn_pnbuf;
1831 ndp->ni_startdir = dp;
1832 /*
1833 * And call lookup() to do the real work
1834 */
1835 error = lookup(ndp);
1836 if (error)
1837 break;
1838 /*
1839 * Check for encountering a symbolic link
1840 */
1841 if ((cnp->cn_flags & ISSYMLINK) == 0) {
91447636 1842 return (0);
1c79356b 1843 } else {
91447636
A
1844 if ((cnp->cn_flags & FSNODELOCKHELD)) {
1845 cnp->cn_flags &= ~FSNODELOCKHELD;
1846 unlock_fsnode(ndp->ni_dvp, NULL);
1847 }
1848/* XXX Revisit when enabling WebNFS */
1849#ifdef WEBNFS_ENABLED
1c79356b
A
1850 if (!pubflag) {
1851#endif
91447636
A
1852 if (cnp->cn_flags & (LOCKPARENT | WANTPARENT))
1853 vnode_put(ndp->ni_dvp);
1854 if (ndp->ni_vp) {
1855 vnode_put(ndp->ni_vp);
1856 ndp->ni_vp = NULL;
1857 }
1c79356b
A
1858 error = EINVAL;
1859 break;
91447636
A
1860/* XXX Revisit when enabling WebNFS */
1861#ifdef WEBNFS_ENABLED
1c79356b
A
1862 }
1863
1864 if (ndp->ni_loopcnt++ >= MAXSYMLINKS) {
91447636
A
1865 vnode_put(ndp->ni_vp);
1866 ndp->ni_vp = NULL;
1c79356b
A
1867 error = ELOOP;
1868 break;
1869 }
55e303ae 1870 /* XXX assert(olen <= MAXPATHLEN - 1); */
91447636 1871 if (ndp->ni_pathlen > 1) {
55e303ae 1872 MALLOC_ZONE(cp, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
91447636
A
1873 if (!cp) {
1874 vnode_put(ndp->ni_vp);
1875 ndp->ni_vp = NULL;
1876 error = ENOMEM;
1877 break;
1878 }
1879 } else {
1c79356b 1880 cp = cnp->cn_pnbuf;
91447636
A
1881 }
1882 auio = uio_createwithbuffer(1, 0, UIO_SYSSPACE, UIO_READ,
1883 &uio_buf[0], sizeof(uio_buf));
1884 if (!auio) {
1885 vnode_put(ndp->ni_vp);
1886 ndp->ni_vp = NULL;
1887 if (ndp->ni_pathlen > 1)
1888 FREE_ZONE(cp, MAXPATHLEN, M_NAMEI);
1889 error = ENOMEM;
1890 break;
1891 }
1892 uio_addiov(auio, CAST_USER_ADDR_T(cp), MAXPATHLEN);
1893 error = VNOP_READLINK(ndp->ni_vp, auio, cnp->cn_context);
1c79356b 1894 if (error) {
55e303ae 1895badlink:
91447636
A
1896 vnode_put(ndp->ni_vp);
1897 ndp->ni_vp = NULL;
1c79356b 1898 if (ndp->ni_pathlen > 1)
55e303ae 1899 FREE_ZONE(cp, MAXPATHLEN, M_NAMEI);
1c79356b
A
1900 break;
1901 }
91447636 1902 linklen = MAXPATHLEN - uio_resid(auio);
1c79356b
A
1903 if (linklen == 0) {
1904 error = ENOENT;
1905 goto badlink;
1906 }
1907 if (linklen + ndp->ni_pathlen >= MAXPATHLEN) {
1908 error = ENAMETOOLONG;
1909 goto badlink;
1910 }
1911 if (ndp->ni_pathlen > 1) {
55e303ae
A
1912 long len = cnp->cn_pnlen;
1913 tmppn = cnp->cn_pnbuf;
1c79356b 1914 cnp->cn_pnbuf = cp;
55e303ae
A
1915 cnp->cn_pnlen = olen + 1;
1916 bcopy(ndp->ni_next, cp + linklen, ndp->ni_pathlen);
1917 FREE_ZONE(tmppn, len, M_NAMEI);
1c79356b
A
1918 } else
1919 cnp->cn_pnbuf[linklen] = '\0';
1920 ndp->ni_pathlen += linklen;
91447636
A
1921
1922 vnode_put(ndp->ni_vp);
1c79356b 1923 dp = ndp->ni_dvp;
91447636
A
1924 ndp->ni_dvp = NULL;
1925
1c79356b
A
1926 /*
1927 * Check if root directory should replace current directory.
1928 */
1929 if (cnp->cn_pnbuf[0] == '/') {
91447636 1930 vnode_put(dp);
1c79356b 1931 dp = ndp->ni_rootdir;
91447636
A
1932 error = vnode_get(dp);
1933 if (error)
1934 break;
1c79356b
A
1935 }
1936#endif
1937 }
1938 }
1939out:
55e303ae
A
1940 tmppn = cnp->cn_pnbuf;
1941 cnp->cn_pnbuf = NULL;
1942 cnp->cn_flags &= ~HASBUF;
1943 FREE_ZONE(tmppn, cnp->cn_pnlen, M_NAMEI);
1944
1c79356b
A
1945 return (error);
1946}
1947
1948/*
1949 * A fiddled version of m_adj() that ensures null fill to a long
1950 * boundary and only trims off the back end
1951 */
1952void
1953nfsm_adj(mp, len, nul)
91447636
A
1954 mbuf_t mp;
1955 int len;
1c79356b
A
1956 int nul;
1957{
91447636
A
1958 mbuf_t m, mnext;
1959 int count, i, mlen;
1960 char *cp;
1c79356b
A
1961
1962 /*
1963 * Trim from tail. Scan the mbuf chain,
1964 * calculating its length and finding the last mbuf.
1965 * If the adjustment only affects this mbuf, then just
1966 * adjust and return. Otherwise, rescan and truncate
1967 * after the remaining size.
1968 */
1969 count = 0;
1970 m = mp;
1971 for (;;) {
91447636
A
1972 mlen = mbuf_len(m);
1973 count += mlen;
1974 mnext = mbuf_next(m);
1975 if (mnext == NULL)
1c79356b 1976 break;
91447636 1977 m = mnext;
1c79356b 1978 }
91447636
A
1979 if (mlen > len) {
1980 mlen -= len;
1981 mbuf_setlen(m, mlen);
1c79356b 1982 if (nul > 0) {
91447636 1983 cp = (caddr_t)mbuf_data(m) + mlen - nul;
1c79356b
A
1984 for (i = 0; i < nul; i++)
1985 *cp++ = '\0';
1986 }
1987 return;
1988 }
1989 count -= len;
1990 if (count < 0)
1991 count = 0;
1992 /*
1993 * Correct length for chain is "count".
1994 * Find the mbuf with last data, adjust its length,
1995 * and toss data from remaining mbufs on chain.
1996 */
91447636
A
1997 for (m = mp; m; m = mbuf_next(m)) {
1998 mlen = mbuf_len(m);
1999 if (mlen >= count) {
2000 mlen = count;
2001 mbuf_setlen(m, count);
1c79356b 2002 if (nul > 0) {
91447636 2003 cp = (caddr_t)mbuf_data(m) + mlen - nul;
1c79356b
A
2004 for (i = 0; i < nul; i++)
2005 *cp++ = '\0';
2006 }
2007 break;
2008 }
91447636 2009 count -= mlen;
1c79356b 2010 }
91447636
A
2011 for (m = mbuf_next(m); m; m = mbuf_next(m))
2012 mbuf_setlen(m, 0);
1c79356b
A
2013}
2014
2015/*
2016 * Make these functions instead of macros, so that the kernel text size
2017 * doesn't get too big...
2018 */
2019void
2020nfsm_srvwcc(nfsd, before_ret, before_vap, after_ret, after_vap, mbp, bposp)
2021 struct nfsrv_descript *nfsd;
2022 int before_ret;
91447636 2023 struct vnode_attr *before_vap;
1c79356b 2024 int after_ret;
91447636
A
2025 struct vnode_attr *after_vap;
2026 mbuf_t *mbp;
1c79356b
A
2027 char **bposp;
2028{
91447636
A
2029 mbuf_t mb = *mbp, mb2;
2030 char *bpos = *bposp;
2031 u_long *tl;
1c79356b
A
2032
2033 if (before_ret) {
2034 nfsm_build(tl, u_long *, NFSX_UNSIGNED);
2035 *tl = nfs_false;
2036 } else {
2037 nfsm_build(tl, u_long *, 7 * NFSX_UNSIGNED);
2038 *tl++ = nfs_true;
91447636 2039 txdr_hyper(&(before_vap->va_data_size), tl);
1c79356b 2040 tl += 2;
91447636 2041 txdr_nfsv3time(&(before_vap->va_modify_time), tl);
1c79356b 2042 tl += 2;
91447636 2043 txdr_nfsv3time(&(before_vap->va_change_time), tl);
1c79356b
A
2044 }
2045 *bposp = bpos;
2046 *mbp = mb;
2047 nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp);
2048}
2049
2050void
2051nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp)
2052 struct nfsrv_descript *nfsd;
2053 int after_ret;
91447636
A
2054 struct vnode_attr *after_vap;
2055 mbuf_t *mbp;
1c79356b
A
2056 char **bposp;
2057{
91447636
A
2058 mbuf_t mb = *mbp, mb2;
2059 char *bpos = *bposp;
2060 u_long *tl;
2061 struct nfs_fattr *fp;
1c79356b
A
2062
2063 if (after_ret) {
2064 nfsm_build(tl, u_long *, NFSX_UNSIGNED);
2065 *tl = nfs_false;
2066 } else {
2067 nfsm_build(tl, u_long *, NFSX_UNSIGNED + NFSX_V3FATTR);
2068 *tl++ = nfs_true;
2069 fp = (struct nfs_fattr *)tl;
2070 nfsm_srvfattr(nfsd, after_vap, fp);
2071 }
2072 *mbp = mb;
2073 *bposp = bpos;
2074}
2075
2076void
2077nfsm_srvfattr(nfsd, vap, fp)
91447636
A
2078 struct nfsrv_descript *nfsd;
2079 struct vnode_attr *vap;
2080 struct nfs_fattr *fp;
1c79356b
A
2081{
2082
91447636
A
2083 // XXX Should we assert here that all fields are supported?
2084
1c79356b
A
2085 fp->fa_nlink = txdr_unsigned(vap->va_nlink);
2086 fp->fa_uid = txdr_unsigned(vap->va_uid);
2087 fp->fa_gid = txdr_unsigned(vap->va_gid);
2088 if (nfsd->nd_flag & ND_NFSV3) {
2089 fp->fa_type = vtonfsv3_type(vap->va_type);
2090 fp->fa_mode = vtonfsv3_mode(vap->va_mode);
91447636
A
2091 txdr_hyper(&vap->va_data_size, &fp->fa3_size);
2092 txdr_hyper(&vap->va_data_alloc, &fp->fa3_used);
1c79356b
A
2093 fp->fa3_rdev.specdata1 = txdr_unsigned(major(vap->va_rdev));
2094 fp->fa3_rdev.specdata2 = txdr_unsigned(minor(vap->va_rdev));
2095 fp->fa3_fsid.nfsuquad[0] = 0;
2096 fp->fa3_fsid.nfsuquad[1] = txdr_unsigned(vap->va_fsid);
91447636
A
2097 txdr_hyper(&vap->va_fileid, &fp->fa3_fileid);
2098 txdr_nfsv3time(&vap->va_access_time, &fp->fa3_atime);
2099 txdr_nfsv3time(&vap->va_modify_time, &fp->fa3_mtime);
2100 txdr_nfsv3time(&vap->va_change_time, &fp->fa3_ctime);
1c79356b
A
2101 } else {
2102 fp->fa_type = vtonfsv2_type(vap->va_type);
2103 fp->fa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode);
91447636
A
2104 fp->fa2_size = txdr_unsigned(vap->va_data_size);
2105 fp->fa2_blocksize = txdr_unsigned(vap->va_iosize);
1c79356b
A
2106 if (vap->va_type == VFIFO)
2107 fp->fa2_rdev = 0xffffffff;
2108 else
2109 fp->fa2_rdev = txdr_unsigned(vap->va_rdev);
91447636 2110 fp->fa2_blocks = txdr_unsigned(vap->va_data_alloc / NFS_FABLKSIZE);
1c79356b
A
2111 fp->fa2_fsid = txdr_unsigned(vap->va_fsid);
2112 fp->fa2_fileid = txdr_unsigned(vap->va_fileid);
91447636
A
2113 txdr_nfsv2time(&vap->va_access_time, &fp->fa2_atime);
2114 txdr_nfsv2time(&vap->va_modify_time, &fp->fa2_mtime);
2115 txdr_nfsv2time(&vap->va_change_time, &fp->fa2_ctime);
2116 }
2117}
2118
2119/*
2120 * Build hash lists of net addresses and hang them off the NFS export.
2121 * Called by nfsrv_export() to set up the lists of export addresses.
2122 */
2123static int
2124nfsrv_hang_addrlist(struct nfs_export *nx, struct user_nfs_export_args *unxa)
2125{
2126 struct nfs_export_net_args nxna;
2127 struct nfs_netopt *no;
2128 struct radix_node_head *rnh;
2129 struct radix_node *rn;
2130 struct sockaddr *saddr, *smask;
2131 struct domain *dom;
2132 int i, error;
2133 unsigned int net;
2134 user_addr_t uaddr;
2135 kauth_cred_t cred;
2136 struct ucred temp_cred;
2137
2138 uaddr = unxa->nxa_nets;
2139 for (net = 0; net < unxa->nxa_netcount; net++, uaddr += sizeof(nxna)) {
2140 error = copyin(uaddr, &nxna, sizeof(nxna));
2141 if (error)
2142 return (error);
2143
2144 if (nxna.nxna_flags & (NX_MAPROOT|NX_MAPALL)) {
2145 bzero(&temp_cred, sizeof(temp_cred));
2146 temp_cred.cr_uid = nxna.nxna_cred.cr_uid;
2147 temp_cred.cr_ngroups = nxna.nxna_cred.cr_ngroups;
2148 for (i=0; i < nxna.nxna_cred.cr_ngroups && i < NGROUPS; i++)
2149 temp_cred.cr_groups[i] = nxna.nxna_cred.cr_groups[i];
2150
2151 cred = kauth_cred_create(&temp_cred);
2152 if (!cred)
2153 return (ENOMEM);
2154 } else {
0c530ab8 2155 cred = NOCRED;
91447636
A
2156 }
2157
2158 if (nxna.nxna_addr.ss_len == 0) {
2159 /* No address means this is a default/world export */
2160 if (nx->nx_flags & NX_DEFAULTEXPORT)
2161 return (EEXIST);
2162 nx->nx_flags |= NX_DEFAULTEXPORT;
2163 nx->nx_defopt.nxo_flags = nxna.nxna_flags;
2164 nx->nx_defopt.nxo_cred = cred;
2165 nx->nx_expcnt++;
2166 continue;
2167 }
2168
2169 i = sizeof(struct nfs_netopt);
2170 i += nxna.nxna_addr.ss_len + nxna.nxna_mask.ss_len;
2171 MALLOC(no, struct nfs_netopt *, i, M_NETADDR, M_WAITOK);
2172 if (!no)
2173 return (ENOMEM);
2174 bzero(no, sizeof(struct nfs_netopt));
2175 no->no_opt.nxo_flags = nxna.nxna_flags;
2176 no->no_opt.nxo_cred = cred;
2177
2178 saddr = (struct sockaddr *)(no + 1);
2179 bcopy(&nxna.nxna_addr, saddr, nxna.nxna_addr.ss_len);
2180 if (nxna.nxna_mask.ss_len) {
2181 smask = (struct sockaddr *)((caddr_t)saddr + nxna.nxna_addr.ss_len);
2182 bcopy(&nxna.nxna_mask, smask, nxna.nxna_mask.ss_len);
2183 } else {
2184 smask = NULL;
2185 }
2186 i = saddr->sa_family;
2187 if ((rnh = nx->nx_rtable[i]) == 0) {
2188 /*
2189 * Seems silly to initialize every AF when most are not
2190 * used, do so on demand here
2191 */
2192 for (dom = domains; dom; dom = dom->dom_next)
2193 if (dom->dom_family == i && dom->dom_rtattach) {
2194 dom->dom_rtattach((void **)&nx->nx_rtable[i],
2195 dom->dom_rtoffset);
2196 break;
2197 }
2198 if ((rnh = nx->nx_rtable[i]) == 0) {
0c530ab8
A
2199 if (IS_VALID_CRED(cred))
2200 kauth_cred_unref(&cred);
91447636
A
2201 _FREE(no, M_NETADDR);
2202 return (ENOBUFS);
2203 }
2204 }
2205 rn = (*rnh->rnh_addaddr)((caddr_t)saddr, (caddr_t)smask, rnh, no->no_rnodes);
2206 if (rn == 0) {
2207 /*
2208 * One of the reasons that rnh_addaddr may fail is that
2209 * the entry already exists. To check for this case, we
2210 * look up the entry to see if it is there. If so, we
2211 * do not need to make a new entry but do continue.
2212 */
2213 int matched = 0;
2214 rn = (*rnh->rnh_matchaddr)((caddr_t)saddr, rnh);
2215 if (rn != 0 && (rn->rn_flags & RNF_ROOT) == 0 &&
2216 (((struct nfs_netopt *)rn)->no_opt.nxo_flags == nxna.nxna_flags)) {
2217 kauth_cred_t cred2 = ((struct nfs_netopt *)rn)->no_opt.nxo_cred;
2218 if (cred && cred2 && (cred->cr_uid == cred2->cr_uid) &&
2219 (cred->cr_ngroups == cred2->cr_ngroups)) {
2220 for (i=0; i < cred2->cr_ngroups && i < NGROUPS; i++)
2221 if (cred->cr_groups[i] != cred2->cr_groups[i])
2222 break;
2223 if (i >= cred2->cr_ngroups || i >= NGROUPS)
2224 matched = 1;
2225 }
2226 }
0c530ab8
A
2227 if (IS_VALID_CRED(cred))
2228 kauth_cred_unref(&cred);
91447636
A
2229 _FREE(no, M_NETADDR);
2230 if (matched)
2231 continue;
2232 return (EPERM);
2233 }
2234 nx->nx_expcnt++;
2235 }
2236
2237 return (0);
2238}
2239
2240/*
2241 * In order to properly track an export's netopt count, we need to pass
2242 * an additional argument to nfsrv_free_netopt() so that it can decrement
2243 * the export's netopt count.
2244 */
2245struct nfsrv_free_netopt_arg {
2246 uint32_t *cnt;
2247 struct radix_node_head *rnh;
2248};
2249
2250static int
2251nfsrv_free_netopt(struct radix_node *rn, void *w)
2252{
2253 struct nfsrv_free_netopt_arg *fna = (struct nfsrv_free_netopt_arg *)w;
2254 struct radix_node_head *rnh = fna->rnh;
2255 uint32_t *cnt = fna->cnt;
2256 struct nfs_netopt *nno = (struct nfs_netopt *)rn;
2257
2258 (*rnh->rnh_deladdr)(rn->rn_key, rn->rn_mask, rnh);
0c530ab8
A
2259 if (IS_VALID_CRED(nno->no_opt.nxo_cred))
2260 kauth_cred_unref(&nno->no_opt.nxo_cred);
91447636
A
2261 _FREE((caddr_t)rn, M_NETADDR);
2262 *cnt -= 1;
2263 return (0);
2264}
2265
2266/*
2267 * Free the net address hash lists that are hanging off the mount points.
2268 */
2269static void
2270nfsrv_free_addrlist(struct nfs_export *nx)
2271{
2272 int i;
2273 struct radix_node_head *rnh;
2274 struct nfsrv_free_netopt_arg fna;
2275
2276 for (i = 0; i <= AF_MAX; i++)
2277 if ( (rnh = nx->nx_rtable[i]) ) {
2278 fna.rnh = rnh;
2279 fna.cnt = &nx->nx_expcnt;
2280 (*rnh->rnh_walktree)(rnh, nfsrv_free_netopt, (caddr_t)&fna);
2281 _FREE((caddr_t)rnh, M_RTABLE);
2282 nx->nx_rtable[i] = 0;
2283 }
2284}
2285
2286void enablequotas(struct mount *mp, vfs_context_t ctx); // XXX
2287
2288int
2289nfsrv_export(struct user_nfs_export_args *unxa, struct vfs_context *ctx)
2290{
2291 int error = 0, pathlen;
2292 struct nfs_exportfs *nxfs, *nxfs2, *nxfs3;
2293 struct nfs_export *nx, *nx2, *nx3;
2294 struct nfs_filehandle nfh;
2295 struct nameidata mnd, xnd;
2296 vnode_t mvp = NULL, xvp = NULL;
2297 mount_t mp;
2298 char path[MAXPATHLEN];
2299 int expisroot;
2300
3a60a9f5
A
2301 if (unxa->nxa_flags & NXA_DELETE_ALL) {
2302 /* delete all exports on all file systems */
2303 lck_rw_lock_exclusive(&nfs_export_rwlock);
2304 while ((nxfs = LIST_FIRST(&nfs_exports))) {
2305 mp = vfs_getvfs_by_mntonname(nxfs->nxfs_path);
2306 if (mp)
2307 mp->mnt_flag &= ~MNT_EXPORTED;
2308 /* delete all exports on this file system */
2309 while ((nx = LIST_FIRST(&nxfs->nxfs_exports))) {
2310 LIST_REMOVE(nx, nx_next);
2311 LIST_REMOVE(nx, nx_hash);
2312 /* delete all netopts for this export */
2313 nfsrv_free_addrlist(nx);
2314 nx->nx_flags &= ~NX_DEFAULTEXPORT;
0c530ab8
A
2315 if (IS_VALID_CRED(nx->nx_defopt.nxo_cred)) {
2316 kauth_cred_unref(&nx->nx_defopt.nxo_cred);
3a60a9f5
A
2317 }
2318 FREE(nx->nx_path, M_TEMP);
2319 FREE(nx, M_TEMP);
2320 }
2321 LIST_REMOVE(nxfs, nxfs_next);
2322 FREE(nxfs->nxfs_path, M_TEMP);
2323 FREE(nxfs, M_TEMP);
2324 }
2325 lck_rw_done(&nfs_export_rwlock);
2326 return (0);
2327 }
2328
91447636
A
2329 error = copyinstr(unxa->nxa_fspath, path, MAXPATHLEN, (size_t *)&pathlen);
2330 if (error)
2331 return (error);
2332
2333 lck_rw_lock_exclusive(&nfs_export_rwlock);
2334
2335 // first check if we've already got an exportfs with the given ID
2336 LIST_FOREACH(nxfs, &nfs_exports, nxfs_next) {
2337 if (nxfs->nxfs_id == unxa->nxa_fsid)
2338 break;
2339 }
2340 if (nxfs) {
2341 /* verify exported FS path matches given path */
2342 if (strcmp(path, nxfs->nxfs_path)) {
2343 error = EEXIST;
2344 goto unlock_out;
2345 }
2346 mp = vfs_getvfs_by_mntonname(nxfs->nxfs_path);
2347 /* find exported FS root vnode */
2348 NDINIT(&mnd, LOOKUP, FOLLOW | LOCKLEAF | AUDITVNPATH1,
2349 UIO_SYSSPACE, nxfs->nxfs_path, ctx);
2350 error = namei(&mnd);
2351 if (error)
2352 goto unlock_out;
2353 mvp = mnd.ni_vp;
2354 /* make sure it's (still) the root of a file system */
2355 if ((mvp->v_flag & VROOT) == 0) {
2356 error = EINVAL;
2357 goto out;
2358 }
2359 /* sanity check: this should be same mount */
2360 if (mp != vnode_mount(mvp)) {
2361 error = EINVAL;
2362 goto out;
2363 }
2364 } else {
2365 /* no current exported file system with that ID */
2366 if (!(unxa->nxa_flags & NXA_ADD)) {
2367 error = ENOENT;
2368 goto unlock_out;
2369 }
2370
2371 /* find exported FS root vnode */
2372 NDINIT(&mnd, LOOKUP, FOLLOW | LOCKLEAF | AUDITVNPATH1,
2373 UIO_SYSSPACE, path, ctx);
2374 error = namei(&mnd);
2375 if (error)
2376 goto unlock_out;
2377 mvp = mnd.ni_vp;
2378 /* make sure it's the root of a file system */
2379 if ((mvp->v_flag & VROOT) == 0) {
2380 error = EINVAL;
2381 goto out;
2382 }
2383 mp = vnode_mount(mvp);
2384
2385 /* make sure the file system is NFS-exportable */
2386 nfh.nfh_len = NFS_MAX_FID_SIZE;
2387 error = VFS_VPTOFH(mvp, &nfh.nfh_len, &nfh.nfh_fid[0], NULL);
2388 if (!error && (nfh.nfh_len > (int)NFS_MAX_FID_SIZE))
2389 error = EIO;
2390 if (error)
2391 goto out;
2392
2393 /* add an exportfs for it */
2394 MALLOC(nxfs, struct nfs_exportfs *, sizeof(struct nfs_exportfs), M_TEMP, M_WAITOK);
2395 if (!nxfs) {
2396 error = ENOMEM;
2397 goto out;
2398 }
2399 bzero(nxfs, sizeof(struct nfs_exportfs));
2400 nxfs->nxfs_id = unxa->nxa_fsid;
2401 MALLOC(nxfs->nxfs_path, char*, pathlen, M_TEMP, M_WAITOK);
2402 if (!nxfs->nxfs_path) {
2403 FREE(nxfs, M_TEMP);
2404 error = ENOMEM;
2405 goto out;
2406 }
2407 bcopy(path, nxfs->nxfs_path, pathlen);
2408 /* insert into list in reverse-sorted order */
2409 nxfs3 = NULL;
2410 LIST_FOREACH(nxfs2, &nfs_exports, nxfs_next) {
2411 if (strcmp(nxfs->nxfs_path, nxfs2->nxfs_path) > 0)
2412 break;
2413 nxfs3 = nxfs2;
2414 }
2415 if (nxfs2)
2416 LIST_INSERT_BEFORE(nxfs2, nxfs, nxfs_next);
2417 else if (nxfs3)
2418 LIST_INSERT_AFTER(nxfs3, nxfs, nxfs_next);
2419 else
2420 LIST_INSERT_HEAD(&nfs_exports, nxfs, nxfs_next);
2421
2422 /* make sure any quotas are enabled before we export the file system */
2423 enablequotas(mp, ctx);
1c79356b 2424 }
91447636
A
2425
2426 if (unxa->nxa_exppath) {
2427 error = copyinstr(unxa->nxa_exppath, path, MAXPATHLEN, (size_t *)&pathlen);
2428 if (error)
2429 goto out;
2430 LIST_FOREACH(nx, &nxfs->nxfs_exports, nx_next) {
2431 if (nx->nx_id == unxa->nxa_expid)
2432 break;
2433 }
2434 if (nx) {
2435 /* verify exported FS path matches given path */
2436 if (strcmp(path, nx->nx_path)) {
2437 error = EEXIST;
2438 goto out;
2439 }
2440 } else {
2441 /* no current export with that ID */
2442 if (!(unxa->nxa_flags & NXA_ADD)) {
2443 error = ENOENT;
2444 goto out;
2445 }
2446 /* add an export for it */
2447 MALLOC(nx, struct nfs_export *, sizeof(struct nfs_export), M_TEMP, M_WAITOK);
2448 if (!nx) {
2449 error = ENOMEM;
2450 goto out1;
2451 }
2452 bzero(nx, sizeof(struct nfs_export));
2453 nx->nx_id = unxa->nxa_expid;
2454 nx->nx_fs = nxfs;
2455 MALLOC(nx->nx_path, char*, pathlen, M_TEMP, M_WAITOK);
2456 if (!nx->nx_path) {
2457 error = ENOMEM;
2458 FREE(nx, M_TEMP);
2459 nx = NULL;
2460 goto out1;
2461 }
2462 bcopy(path, nx->nx_path, pathlen);
2463 /* insert into list in reverse-sorted order */
2464 nx3 = NULL;
2465 LIST_FOREACH(nx2, &nxfs->nxfs_exports, nx_next) {
2466 if (strcmp(nx->nx_path, nx2->nx_path) > 0)
2467 break;
2468 nx3 = nx2;
2469 }
2470 if (nx2)
2471 LIST_INSERT_BEFORE(nx2, nx, nx_next);
2472 else if (nx3)
2473 LIST_INSERT_AFTER(nx3, nx, nx_next);
2474 else
2475 LIST_INSERT_HEAD(&nxfs->nxfs_exports, nx, nx_next);
2476 /* insert into hash */
2477 LIST_INSERT_HEAD(NFSEXPHASH(nxfs->nxfs_id, nx->nx_id), nx, nx_hash);
2478
2479 /*
2480 * We don't allow nested exports. Check if the new entry
2481 * nests with the entries before and after or if there's an
2482 * entry for the file system root and subdirs.
2483 */
2484 error = 0;
2485 if ((nx3 && !strncmp(nx3->nx_path, nx->nx_path, pathlen - 1) &&
2486 (nx3->nx_path[pathlen-1] == '/')) ||
2487 (nx2 && !strncmp(nx2->nx_path, nx->nx_path, strlen(nx2->nx_path)) &&
2488 (nx->nx_path[strlen(nx2->nx_path)] == '/')))
2489 error = EINVAL;
2490 if (!error) {
2491 /* check export conflict with fs root export and vice versa */
2492 expisroot = !nx->nx_path[0] ||
2493 ((nx->nx_path[0] == '.') && !nx->nx_path[1]);
2494 LIST_FOREACH(nx2, &nxfs->nxfs_exports, nx_next) {
2495 if (expisroot) {
2496 if (nx2 != nx)
2497 break;
2498 } else if (!nx2->nx_path[0])
2499 break;
2500 else if ((nx2->nx_path[0] == '.') && !nx2->nx_path[1])
2501 break;
2502 }
2503 if (nx2)
2504 error = EINVAL;
2505 }
2506 if (error) {
2507 printf("nfsrv_export: attempt to register nested exports: %s/%s\n",
2508 nxfs->nxfs_path, nx->nx_path);
2509 goto out1;
2510 }
2511
2512 /* find export root vnode */
2513 if (!nx->nx_path[0] || ((nx->nx_path[0] == '.') && !nx->nx_path[1])) {
2514 /* exporting file system's root directory */
2515 xvp = mvp;
2516 vnode_get(xvp);
2517 } else {
2518 xnd.ni_cnd.cn_nameiop = LOOKUP;
2519 xnd.ni_cnd.cn_flags = LOCKLEAF;
2520 xnd.ni_pathlen = pathlen - 1;
2521 xnd.ni_cnd.cn_nameptr = xnd.ni_cnd.cn_pnbuf = path;
2522 xnd.ni_startdir = mvp;
2523 xnd.ni_usedvp = mvp;
2524 xnd.ni_cnd.cn_context = ctx;
2525 error = lookup(&xnd);
2526 if (error)
2527 goto out1;
2528 xvp = xnd.ni_vp;
2529 }
2530
2531 if (vnode_vtype(xvp) != VDIR) {
2532 error = EINVAL;
2533 vnode_put(xvp);
2534 goto out1;
2535 }
2536
2537 /* grab file handle */
0c530ab8
A
2538 nx->nx_fh.nfh_xh.nxh_version = htonl(NFS_FH_VERSION);
2539 nx->nx_fh.nfh_xh.nxh_fsid = htonl(nx->nx_fs->nxfs_id);
2540 nx->nx_fh.nfh_xh.nxh_expid = htonl(nx->nx_id);
91447636
A
2541 nx->nx_fh.nfh_xh.nxh_flags = 0;
2542 nx->nx_fh.nfh_xh.nxh_reserved = 0;
2543 nx->nx_fh.nfh_len = NFS_MAX_FID_SIZE;
2544 error = VFS_VPTOFH(xvp, &nx->nx_fh.nfh_len, &nx->nx_fh.nfh_fid[0], NULL);
2545 if (!error && (nx->nx_fh.nfh_len > (int)NFS_MAX_FID_SIZE)) {
2546 error = EIO;
2547 } else {
2548 nx->nx_fh.nfh_xh.nxh_fidlen = nx->nx_fh.nfh_len;
2549 nx->nx_fh.nfh_len += sizeof(nx->nx_fh.nfh_xh);
2550 }
2551
2552 vnode_put(xvp);
2553 if (error)
2554 goto out1;
2555 }
2556 } else {
2557 nx = NULL;
2558 }
2559
2560 /* perform the export changes */
2561 if (unxa->nxa_flags & NXA_DELETE) {
2562 if (!nx) {
2563 /* delete all exports on this file system */
2564 while ((nx = LIST_FIRST(&nxfs->nxfs_exports))) {
2565 LIST_REMOVE(nx, nx_next);
2566 LIST_REMOVE(nx, nx_hash);
2567 /* delete all netopts for this export */
2568 nfsrv_free_addrlist(nx);
2569 nx->nx_flags &= ~NX_DEFAULTEXPORT;
0c530ab8
A
2570 if (IS_VALID_CRED(nx->nx_defopt.nxo_cred)) {
2571 kauth_cred_unref(&nx->nx_defopt.nxo_cred);
91447636
A
2572 }
2573 FREE(nx->nx_path, M_TEMP);
2574 FREE(nx, M_TEMP);
2575 }
2576 goto out1;
2577 } else {
2578 /* delete all netopts for this export */
2579 nfsrv_free_addrlist(nx);
2580 nx->nx_flags &= ~NX_DEFAULTEXPORT;
0c530ab8
A
2581 if (IS_VALID_CRED(nx->nx_defopt.nxo_cred)) {
2582 kauth_cred_unref(&nx->nx_defopt.nxo_cred);
91447636
A
2583 }
2584 }
2585 }
2586 if (unxa->nxa_flags & NXA_ADD) {
2587 error = nfsrv_hang_addrlist(nx, unxa);
2588 if (!error)
2589 mp->mnt_flag |= MNT_EXPORTED;
2590 }
2591
2592out1:
2593 if (nx && !nx->nx_expcnt) {
2594 /* export has no export options */
2595 LIST_REMOVE(nx, nx_next);
2596 LIST_REMOVE(nx, nx_hash);
2597 FREE(nx->nx_path, M_TEMP);
2598 FREE(nx, M_TEMP);
2599 }
2600 if (LIST_EMPTY(&nxfs->nxfs_exports)) {
2601 /* exported file system has no more exports */
2602 LIST_REMOVE(nxfs, nxfs_next);
2603 FREE(nxfs->nxfs_path, M_TEMP);
2604 FREE(nxfs, M_TEMP);
2605 mp->mnt_flag &= ~MNT_EXPORTED;
2606 }
2607
2608out:
2609 if (mvp) {
2610 vnode_put(mvp);
2611 nameidone(&mnd);
2612 }
2613unlock_out:
2614 lck_rw_done(&nfs_export_rwlock);
2615 return (error);
2616}
2617
2618static struct nfs_export_options *
2619nfsrv_export_lookup(struct nfs_export *nx, mbuf_t nam)
2620{
2621 struct nfs_export_options *nxo = NULL;
2622 struct nfs_netopt *no = NULL;
2623 struct radix_node_head *rnh;
2624 struct sockaddr *saddr;
2625
2626 /* Lookup in the export list first. */
2627 if (nam != NULL) {
2628 saddr = mbuf_data(nam);
2629 rnh = nx->nx_rtable[saddr->sa_family];
2630 if (rnh != NULL) {
2631 no = (struct nfs_netopt *)
2632 (*rnh->rnh_matchaddr)((caddr_t)saddr, rnh);
2633 if (no && no->no_rnodes->rn_flags & RNF_ROOT)
2634 no = NULL;
2635 if (no)
2636 nxo = &no->no_opt;
2637 }
2638 }
2639 /* If no address match, use the default if it exists. */
2640 if ((nxo == NULL) && (nx->nx_flags & NX_DEFAULTEXPORT))
2641 nxo = &nx->nx_defopt;
2642 return (nxo);
2643}
2644
2645/* find an export for the given handle */
2646static struct nfs_export *
2647nfsrv_fhtoexport(struct nfs_filehandle *nfhp)
2648{
2649 struct nfs_export *nx;
0c530ab8
A
2650 uint32_t fsid, expid;
2651
2652 fsid = ntohl(nfhp->nfh_xh.nxh_fsid);
2653 expid = ntohl(nfhp->nfh_xh.nxh_expid);
2654 nx = NFSEXPHASH(fsid, expid)->lh_first;
91447636 2655 for (; nx; nx = LIST_NEXT(nx, nx_hash)) {
0c530ab8 2656 if (nx->nx_fs->nxfs_id != fsid)
91447636 2657 continue;
0c530ab8 2658 if (nx->nx_id != expid)
91447636
A
2659 continue;
2660 break;
2661 }
2662 return nx;
1c79356b
A
2663}
2664
2665/*
91447636 2666 * nfsrv_fhtovp() - convert FH to vnode and export info
1c79356b
A
2667 */
2668int
91447636
A
2669nfsrv_fhtovp(
2670 struct nfs_filehandle *nfhp,
2671 mbuf_t nam,
2672 __unused int pubflag,
2673 vnode_t *vpp,
2674 struct nfs_export **nxp,
2675 struct nfs_export_options **nxop)
1c79356b 2676{
91447636
A
2677 int error;
2678 struct mount *mp;
0c530ab8 2679 uint32_t v;
1c79356b 2680
91447636
A
2681 *vpp = NULL;
2682 *nxp = NULL;
2683 *nxop = NULL;
1c79356b 2684
0c530ab8
A
2685 v = ntohl(nfhp->nfh_xh.nxh_version);
2686 if (v != NFS_FH_VERSION) {
91447636
A
2687 /* file handle format not supported */
2688 return (ESTALE);
2689 }
2690 if (nfhp->nfh_len > NFS_MAX_FH_SIZE)
2691 return (EBADRPC);
2692 if (nfhp->nfh_len < (int)sizeof(nfhp->nfh_xh))
2693 return (ESTALE);
0c530ab8
A
2694 v = ntohs(nfhp->nfh_xh.nxh_flags);
2695 if (v & NXHF_INVALIDFH)
91447636
A
2696 return (ESTALE);
2697
2698/* XXX Revisit when enabling WebNFS */
2699#ifdef WEBNFS_ENABLED
2700 if (nfs_ispublicfh(nfhp)) {
1c79356b
A
2701 if (!pubflag || !nfs_pub.np_valid)
2702 return (ESTALE);
91447636 2703 nfhp = &nfs_pub.np_handle;
1c79356b
A
2704 }
2705#endif
2706
91447636
A
2707 *nxp = nfsrv_fhtoexport(nfhp);
2708 if (!*nxp)
2709 return (ESTALE);
2710
2711 /* Get the export option structure for this <export, client> tuple. */
2712 *nxop = nfsrv_export_lookup(*nxp, nam);
2713 if (nam && (*nxop == NULL))
2714 return (EACCES);
2715
2716 /* find mount structure */
2717 mp = vfs_getvfs_by_mntonname((*nxp)->nx_fs->nxfs_path);
1c79356b
A
2718 if (!mp)
2719 return (ESTALE);
91447636
A
2720
2721 error = VFS_FHTOVP(mp, nfhp->nfh_xh.nxh_fidlen, &nfhp->nfh_fid[0], vpp, NULL);
1c79356b
A
2722 if (error)
2723 return (error);
2724 /* vnode pointer should be good at this point or ... */
2725 if (*vpp == NULL)
2726 return (ESTALE);
91447636
A
2727 return (0);
2728}
1c79356b 2729
91447636
A
2730/*
2731 * nfsrv_credcheck() - check/map credentials according to given export options
2732 */
2733int
2734nfsrv_credcheck(
2735 struct nfsrv_descript *nfsd,
2736 __unused struct nfs_export *nx,
2737 struct nfs_export_options *nxo)
2738{
2739 if (nxo && nxo->nxo_cred) {
2740 if ((nxo->nxo_flags & NX_MAPALL) ||
2741 ((nxo->nxo_flags & NX_MAPROOT) && !suser(nfsd->nd_cr, NULL))) {
0c530ab8
A
2742 kauth_cred_ref(nxo->nxo_cred);
2743 kauth_cred_unref(&nfsd->nd_cr);
91447636 2744 nfsd->nd_cr = nxo->nxo_cred;
91447636
A
2745 }
2746 }
1c79356b
A
2747 return (0);
2748}
2749
2750
2751/*
2752 * WebNFS: check if a filehandle is a public filehandle. For v3, this
2753 * means a length of 0, for v2 it means all zeroes. nfsm_srvmtofh has
2754 * transformed this to all zeroes in both cases, so check for it.
2755 */
2756int
91447636 2757nfs_ispublicfh(struct nfs_filehandle *nfhp)
1c79356b 2758{
91447636
A
2759 char *cp = (char *)nfhp;
2760 unsigned int i;
2761
2762 if (nfhp->nfh_len == 0)
2763 return (TRUE);
2764 if (nfhp->nfh_len != NFSX_V2FH)
2765 return (FALSE);
2766 for (i = 0; i < NFSX_V2FH; i++)
1c79356b
A
2767 if (*cp++ != 0)
2768 return (FALSE);
2769 return (TRUE);
2770}
91447636
A
2771
2772/*
2773 * nfsrv_vptofh() - convert vnode to file handle for given export
2774 *
2775 * If the caller is passing in a vnode for a ".." directory entry,
2776 * they can pass a directory NFS file handle (dnfhp) which will be
2777 * checked against the root export file handle. If it matches, we
2778 * refuse to provide the file handle for the out-of-export directory.
2779 */
2780int
2781nfsrv_vptofh(
2782 struct nfs_export *nx,
2783 int v2,
2784 struct nfs_filehandle *dnfhp,
2785 vnode_t vp,
2786 struct vfs_context *ctx,
2787 struct nfs_filehandle *nfhp)
2788{
2789 int error;
2790
0c530ab8
A
2791 nfhp->nfh_xh.nxh_version = htonl(NFS_FH_VERSION);
2792 nfhp->nfh_xh.nxh_fsid = htonl(nx->nx_fs->nxfs_id);
2793 nfhp->nfh_xh.nxh_expid = htonl(nx->nx_id);
91447636
A
2794 nfhp->nfh_xh.nxh_flags = 0;
2795 nfhp->nfh_xh.nxh_reserved = 0;
2796
2797 if (v2)
2798 bzero(&nfhp->nfh_fid[0], NFSV2_MAX_FID_SIZE);
2799
2800 /* if directory FH matches export root, return invalid FH */
2801 if (dnfhp && nfsrv_fhmatch(dnfhp, &nx->nx_fh)) {
2802 nfhp->nfh_len = v2 ? NFSX_V2FH : sizeof(nfhp->nfh_xh);
2803 nfhp->nfh_xh.nxh_fidlen = 0;
0c530ab8 2804 nfhp->nfh_xh.nxh_flags = htons(NXHF_INVALIDFH);
91447636
A
2805 return (0);
2806 }
2807
2808 nfhp->nfh_len = v2 ? NFSV2_MAX_FID_SIZE : NFS_MAX_FID_SIZE;
2809 error = VFS_VPTOFH(vp, &nfhp->nfh_len, &nfhp->nfh_fid[0], ctx);
2810 if (error)
2811 return (error);
2812 if (nfhp->nfh_len > (int)(v2 ? NFSV2_MAX_FID_SIZE : NFS_MAX_FID_SIZE))
2813 return (EOVERFLOW);
2814 nfhp->nfh_xh.nxh_fidlen = nfhp->nfh_len;
2815 nfhp->nfh_len += sizeof(nfhp->nfh_xh);
2816 if (v2 && (nfhp->nfh_len < NFSX_V2FH))
2817 nfhp->nfh_len = NFSX_V2FH;
2818
2819 return (0);
2820}
2821
2822int
2823nfsrv_fhmatch(struct nfs_filehandle *fh1, struct nfs_filehandle *fh2)
2824{
2825 int len1, len2;
2826
2827 len1 = sizeof(fh1->nfh_xh) + fh1->nfh_xh.nxh_fidlen;
2828 len2 = sizeof(fh2->nfh_xh) + fh2->nfh_xh.nxh_fidlen;
2829 if (len1 != len2)
2830 return (0);
2831 if (bcmp(&fh1->nfh_xh, &fh2->nfh_xh, len1))
2832 return (0);
2833 return (1);
2834}
1c79356b
A
2835
2836#endif /* NFS_NOSERVER */
2837/*
2838 * This function compares two net addresses by family and returns TRUE
2839 * if they are the same host.
2840 * If there is any doubt, return FALSE.
2841 * The AF_INET family is handled as a special case so that address mbufs
2842 * don't need to be saved to store "struct in_addr", which is only 4 bytes.
2843 */
2844int
2845netaddr_match(family, haddr, nam)
2846 int family;
2847 union nethostaddr *haddr;
91447636 2848 mbuf_t nam;
1c79356b 2849{
91447636 2850 struct sockaddr_in *inetaddr;
1c79356b
A
2851
2852 switch (family) {
2853 case AF_INET:
91447636 2854 inetaddr = mbuf_data(nam);
1c79356b
A
2855 if (inetaddr->sin_family == AF_INET &&
2856 inetaddr->sin_addr.s_addr == haddr->had_inetaddr)
2857 return (1);
2858 break;
2859#if ISO
2860 case AF_ISO:
2861 {
91447636 2862 struct sockaddr_iso *isoaddr1, *isoaddr2;
1c79356b 2863
91447636
A
2864 isoaddr1 = mbuf_data(nam);
2865 isoaddr2 = mbuf_data(haddr->had_nam);
1c79356b
A
2866 if (isoaddr1->siso_family == AF_ISO &&
2867 isoaddr1->siso_nlen > 0 &&
2868 isoaddr1->siso_nlen == isoaddr2->siso_nlen &&
2869 SAME_ISOADDR(isoaddr1, isoaddr2))
2870 return (1);
2871 break;
2872 }
2873#endif /* ISO */
2874 default:
2875 break;
2876 };
2877 return (0);
2878}
2879
91447636 2880static nfsuint64 nfs_nullcookie = { { 0, 0 } };
1c79356b
A
2881/*
2882 * This function finds the directory cookie that corresponds to the
2883 * logical byte offset given.
2884 */
2885nfsuint64 *
2886nfs_getcookie(np, off, add)
91447636 2887 struct nfsnode *np;
1c79356b
A
2888 off_t off;
2889 int add;
2890{
91447636
A
2891 struct nfsdmap *dp, *dp2;
2892 int pos;
1c79356b
A
2893
2894 pos = off / NFS_DIRBLKSIZ;
2895 if (pos == 0) {
2896#if DIAGNOSTIC
2897 if (add)
2898 panic("nfs getcookie add at 0");
2899#endif
2900 return (&nfs_nullcookie);
2901 }
2902 pos--;
2903 dp = np->n_cookies.lh_first;
2904 if (!dp) {
2905 if (add) {
91447636
A
2906 MALLOC_ZONE(dp, struct nfsdmap *, sizeof(struct nfsdmap),
2907 M_NFSDIROFF, M_WAITOK);
2908 if (!dp)
2909 return ((nfsuint64 *)0);
1c79356b
A
2910 dp->ndm_eocookie = 0;
2911 LIST_INSERT_HEAD(&np->n_cookies, dp, ndm_list);
2912 } else
2913 return ((nfsuint64 *)0);
2914 }
2915 while (pos >= NFSNUMCOOKIES) {
2916 pos -= NFSNUMCOOKIES;
2917 if (dp->ndm_list.le_next) {
2918 if (!add && dp->ndm_eocookie < NFSNUMCOOKIES &&
2919 pos >= dp->ndm_eocookie)
2920 return ((nfsuint64 *)0);
2921 dp = dp->ndm_list.le_next;
2922 } else if (add) {
91447636
A
2923 MALLOC_ZONE(dp2, struct nfsdmap *, sizeof(struct nfsdmap),
2924 M_NFSDIROFF, M_WAITOK);
2925 if (!dp2)
2926 return ((nfsuint64 *)0);
1c79356b
A
2927 dp2->ndm_eocookie = 0;
2928 LIST_INSERT_AFTER(dp, dp2, ndm_list);
2929 dp = dp2;
2930 } else
2931 return ((nfsuint64 *)0);
2932 }
2933 if (pos >= dp->ndm_eocookie) {
2934 if (add)
2935 dp->ndm_eocookie = pos + 1;
2936 else
2937 return ((nfsuint64 *)0);
2938 }
2939 return (&dp->ndm_cookies[pos]);
2940}
2941
2942/*
2943 * Invalidate cached directory information, except for the actual directory
2944 * blocks (which are invalidated separately).
2945 * Done mainly to avoid the use of stale offset cookies.
2946 */
2947void
2948nfs_invaldir(vp)
91447636 2949 vnode_t vp;
1c79356b 2950{
91447636 2951 struct nfsnode *np = VTONFS(vp);
1c79356b
A
2952
2953#if DIAGNOSTIC
91447636 2954 if (vnode_vtype(vp) != VDIR)
1c79356b
A
2955 panic("nfs: invaldir not dir");
2956#endif
2957 np->n_direofoffset = 0;
2958 np->n_cookieverf.nfsuquad[0] = 0;
2959 np->n_cookieverf.nfsuquad[1] = 0;
2960 if (np->n_cookies.lh_first)
2961 np->n_cookies.lh_first->ndm_eocookie = 0;
2962}
2963
1c79356b
A
2964#ifndef NFS_NOSERVER
2965/*
2966 * Map errnos to NFS error numbers. For Version 3 also filter out error
2967 * numbers not specified for the associated procedure.
2968 */
2969int
2970nfsrv_errmap(nd, err)
2971 struct nfsrv_descript *nd;
91447636 2972 int err;
1c79356b 2973{
91447636 2974 short *defaulterrp, *errp;
1c79356b
A
2975
2976 if (nd->nd_flag & ND_NFSV3) {
2977 if (nd->nd_procnum <= NFSPROC_COMMIT) {
2978 errp = defaulterrp = nfsrv_v3errmap[nd->nd_procnum];
2979 while (*++errp) {
2980 if (*errp == err)
2981 return (err);
2982 else if (*errp > err)
2983 break;
2984 }
2985 return ((int)*defaulterrp);
2986 } else
2987 return (err & 0xffff);
2988 }
2989 if (err <= ELAST)
2990 return ((int)nfsrv_v2errmap[err - 1]);
2991 return (NFSERR_IO);
2992}
2993
1c79356b
A
2994#endif /* NFS_NOSERVER */
2995