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