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