]> git.saurik.com Git - apple/xnu.git/blame - bsd/nfs/nfs_subs.c
xnu-344.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 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22/* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
23/*
24 * Copyright (c) 1989, 1993
25 * The Regents of the University of California. All rights reserved.
26 *
27 * This code is derived from software contributed to Berkeley by
28 * Rick Macklem at The University of Guelph.
29 *
30 * Redistribution and use in source and binary forms, with or without
31 * modification, are permitted provided that the following conditions
32 * are met:
33 * 1. Redistributions of source code must retain the above copyright
34 * notice, this list of conditions and the following disclaimer.
35 * 2. Redistributions in binary form must reproduce the above copyright
36 * notice, this list of conditions and the following disclaimer in the
37 * documentation and/or other materials provided with the distribution.
38 * 3. All advertising materials mentioning features or use of this software
39 * must display the following acknowledgement:
40 * This product includes software developed by the University of
41 * California, Berkeley and its contributors.
42 * 4. Neither the name of the University nor the names of its contributors
43 * may be used to endorse or promote products derived from this software
44 * without specific prior written permission.
45 *
46 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
47 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
48 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
49 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
50 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
51 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
52 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
53 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
54 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
55 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
56 * SUCH DAMAGE.
57 *
58 * @(#)nfs_subs.c 8.8 (Berkeley) 5/22/95
59 * FreeBSD-Id: nfs_subs.c,v 1.47 1997/11/07 08:53:24 phk Exp $
60 */
61
62/*
63 * These functions support the macros and help fiddle mbuf chains for
64 * the nfs op functions. They do things like create the rpc header and
65 * copy data between mbuf chains and uio lists.
66 */
67#include <sys/param.h>
68#include <sys/proc.h>
69#include <sys/systm.h>
70#include <sys/kernel.h>
71#include <sys/mount.h>
72#include <sys/vnode.h>
73#include <sys/namei.h>
74#include <sys/mbuf.h>
75#include <sys/socket.h>
76#include <sys/stat.h>
77#include <sys/malloc.h>
78#include <sys/syscall.h>
79#include <sys/ubc.h>
80
81#include <sys/vm.h>
82#include <sys/vmparam.h>
83#include <machine/spl.h>
84
85#include <sys/lock.h>
86
87#include <sys/time.h>
88#include <kern/clock.h>
89
90#include <nfs/rpcv2.h>
91#include <nfs/nfsproto.h>
92#include <nfs/nfs.h>
93#include <nfs/nfsnode.h>
94#include <nfs/xdr_subs.h>
95#include <nfs/nfsm_subs.h>
96#include <nfs/nfsmount.h>
97#include <nfs/nqnfs.h>
98#include <nfs/nfsrtt.h>
99
100#include <miscfs/specfs/specdev.h>
101
102#include <netinet/in.h>
103#if ISO
104#include <netiso/iso.h>
105#endif
106
fa4905b1
A
107#include <sys/kdebug.h>
108
109#define FSDBG(A, B, C, D, E) \
110 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, (A))) | DBG_FUNC_NONE, \
111 (int)(B), (int)(C), (int)(D), (int)(E), 0)
112#define FSDBG_TOP(A, B, C, D, E) \
113 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, (A))) | DBG_FUNC_START, \
114 (int)(B), (int)(C), (int)(D), (int)(E), 0)
115#define FSDBG_BOT(A, B, C, D, E) \
116 KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, (A))) | DBG_FUNC_END, \
117 (int)(B), (int)(C), (int)(D), (int)(E), 0)
1c79356b
A
118/*
119 * Data items converted to xdr at startup, since they are constant
120 * This is kinda hokey, but may save a little time doing byte swaps
121 */
122u_long nfs_xdrneg1;
123u_long rpc_call, rpc_vers, rpc_reply, rpc_msgdenied, rpc_autherr,
124 rpc_mismatch, rpc_auth_unix, rpc_msgaccepted,
125 rpc_auth_kerb;
126u_long nfs_prog, nqnfs_prog, nfs_true, nfs_false;
127
128/* And other global data */
129static u_long nfs_xid = 0;
fa4905b1 130u_long nfs_xidwrap = 0; /* to build a (non-wwrapping) 64 bit xid */
1c79356b
A
131static enum vtype nv2tov_type[8]= {
132 VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON, VNON
133};
134enum vtype nv3tov_type[8]= {
135 VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO
136};
137
138int nfs_mount_type;
139int nfs_ticks;
140
141struct nfs_reqq nfs_reqq;
142struct nfssvc_sockhead nfssvc_sockhead;
143int nfssvc_sockhead_flag;
144struct nfsd_head nfsd_head;
145int nfsd_head_flag;
146struct nfs_bufq nfs_bufq;
147struct nqtimerhead nqtimerhead;
148struct nqfhhashhead *nqfhhashtbl;
149u_long nqfhhash;
150
151#ifndef NFS_NOSERVER
152/*
153 * Mapping of old NFS Version 2 RPC numbers to generic numbers.
154 */
155int nfsv3_procid[NFS_NPROCS] = {
156 NFSPROC_NULL,
157 NFSPROC_GETATTR,
158 NFSPROC_SETATTR,
159 NFSPROC_NOOP,
160 NFSPROC_LOOKUP,
161 NFSPROC_READLINK,
162 NFSPROC_READ,
163 NFSPROC_NOOP,
164 NFSPROC_WRITE,
165 NFSPROC_CREATE,
166 NFSPROC_REMOVE,
167 NFSPROC_RENAME,
168 NFSPROC_LINK,
169 NFSPROC_SYMLINK,
170 NFSPROC_MKDIR,
171 NFSPROC_RMDIR,
172 NFSPROC_READDIR,
173 NFSPROC_FSSTAT,
174 NFSPROC_NOOP,
175 NFSPROC_NOOP,
176 NFSPROC_NOOP,
177 NFSPROC_NOOP,
178 NFSPROC_NOOP,
179 NFSPROC_NOOP,
180 NFSPROC_NOOP,
181 NFSPROC_NOOP
182};
183
184#endif /* NFS_NOSERVER */
185/*
186 * and the reverse mapping from generic to Version 2 procedure numbers
187 */
188int nfsv2_procid[NFS_NPROCS] = {
189 NFSV2PROC_NULL,
190 NFSV2PROC_GETATTR,
191 NFSV2PROC_SETATTR,
192 NFSV2PROC_LOOKUP,
193 NFSV2PROC_NOOP,
194 NFSV2PROC_READLINK,
195 NFSV2PROC_READ,
196 NFSV2PROC_WRITE,
197 NFSV2PROC_CREATE,
198 NFSV2PROC_MKDIR,
199 NFSV2PROC_SYMLINK,
200 NFSV2PROC_CREATE,
201 NFSV2PROC_REMOVE,
202 NFSV2PROC_RMDIR,
203 NFSV2PROC_RENAME,
204 NFSV2PROC_LINK,
205 NFSV2PROC_READDIR,
206 NFSV2PROC_NOOP,
207 NFSV2PROC_STATFS,
208 NFSV2PROC_NOOP,
209 NFSV2PROC_NOOP,
210 NFSV2PROC_NOOP,
211 NFSV2PROC_NOOP,
212 NFSV2PROC_NOOP,
213 NFSV2PROC_NOOP,
214 NFSV2PROC_NOOP,
215};
216
217#ifndef NFS_NOSERVER
218/*
219 * Maps errno values to nfs error numbers.
220 * Use NFSERR_IO as the catch all for ones not specifically defined in
221 * RFC 1094.
222 */
223static u_char nfsrv_v2errmap[ELAST] = {
224 NFSERR_PERM, NFSERR_NOENT, NFSERR_IO, NFSERR_IO, NFSERR_IO,
225 NFSERR_NXIO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
226 NFSERR_IO, NFSERR_IO, NFSERR_ACCES, NFSERR_IO, NFSERR_IO,
227 NFSERR_IO, NFSERR_EXIST, NFSERR_IO, NFSERR_NODEV, NFSERR_NOTDIR,
228 NFSERR_ISDIR, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
229 NFSERR_IO, NFSERR_FBIG, NFSERR_NOSPC, NFSERR_IO, NFSERR_ROFS,
230 NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
231 NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
232 NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
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_NAMETOL, NFSERR_IO, NFSERR_IO,
237 NFSERR_NOTEMPTY, NFSERR_IO, NFSERR_IO, NFSERR_DQUOT, NFSERR_STALE,
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,
241};
242
243/*
244 * Maps errno values to nfs error numbers.
245 * Although it is not obvious whether or not NFS clients really care if
246 * a returned error value is in the specified list for the procedure, the
247 * safest thing to do is filter them appropriately. For Version 2, the
248 * X/Open XNFS document is the only specification that defines error values
249 * for each RPC (The RFC simply lists all possible error values for all RPCs),
250 * so I have decided to not do this for Version 2.
251 * The first entry is the default error return and the rest are the valid
252 * errors for that RPC in increasing numeric order.
253 */
254static short nfsv3err_null[] = {
255 0,
256 0,
257};
258
259static short nfsv3err_getattr[] = {
260 NFSERR_IO,
261 NFSERR_IO,
262 NFSERR_STALE,
263 NFSERR_BADHANDLE,
264 NFSERR_SERVERFAULT,
265 0,
266};
267
268static short nfsv3err_setattr[] = {
269 NFSERR_IO,
270 NFSERR_PERM,
271 NFSERR_IO,
272 NFSERR_ACCES,
273 NFSERR_INVAL,
274 NFSERR_NOSPC,
275 NFSERR_ROFS,
276 NFSERR_DQUOT,
277 NFSERR_STALE,
278 NFSERR_BADHANDLE,
279 NFSERR_NOT_SYNC,
280 NFSERR_SERVERFAULT,
281 0,
282};
283
284static short nfsv3err_lookup[] = {
285 NFSERR_IO,
286 NFSERR_NOENT,
287 NFSERR_IO,
288 NFSERR_ACCES,
289 NFSERR_NOTDIR,
290 NFSERR_NAMETOL,
291 NFSERR_STALE,
292 NFSERR_BADHANDLE,
293 NFSERR_SERVERFAULT,
294 0,
295};
296
297static short nfsv3err_access[] = {
298 NFSERR_IO,
299 NFSERR_IO,
300 NFSERR_STALE,
301 NFSERR_BADHANDLE,
302 NFSERR_SERVERFAULT,
303 0,
304};
305
306static short nfsv3err_readlink[] = {
307 NFSERR_IO,
308 NFSERR_IO,
309 NFSERR_ACCES,
310 NFSERR_INVAL,
311 NFSERR_STALE,
312 NFSERR_BADHANDLE,
313 NFSERR_NOTSUPP,
314 NFSERR_SERVERFAULT,
315 0,
316};
317
318static short nfsv3err_read[] = {
319 NFSERR_IO,
320 NFSERR_IO,
321 NFSERR_NXIO,
322 NFSERR_ACCES,
323 NFSERR_INVAL,
324 NFSERR_STALE,
325 NFSERR_BADHANDLE,
326 NFSERR_SERVERFAULT,
327 0,
328};
329
330static short nfsv3err_write[] = {
331 NFSERR_IO,
332 NFSERR_IO,
333 NFSERR_ACCES,
334 NFSERR_INVAL,
335 NFSERR_FBIG,
336 NFSERR_NOSPC,
337 NFSERR_ROFS,
338 NFSERR_DQUOT,
339 NFSERR_STALE,
340 NFSERR_BADHANDLE,
341 NFSERR_SERVERFAULT,
342 0,
343};
344
345static short nfsv3err_create[] = {
346 NFSERR_IO,
347 NFSERR_IO,
348 NFSERR_ACCES,
349 NFSERR_EXIST,
350 NFSERR_NOTDIR,
351 NFSERR_NOSPC,
352 NFSERR_ROFS,
353 NFSERR_NAMETOL,
354 NFSERR_DQUOT,
355 NFSERR_STALE,
356 NFSERR_BADHANDLE,
357 NFSERR_NOTSUPP,
358 NFSERR_SERVERFAULT,
359 0,
360};
361
362static short nfsv3err_mkdir[] = {
363 NFSERR_IO,
364 NFSERR_IO,
365 NFSERR_ACCES,
366 NFSERR_EXIST,
367 NFSERR_NOTDIR,
368 NFSERR_NOSPC,
369 NFSERR_ROFS,
370 NFSERR_NAMETOL,
371 NFSERR_DQUOT,
372 NFSERR_STALE,
373 NFSERR_BADHANDLE,
374 NFSERR_NOTSUPP,
375 NFSERR_SERVERFAULT,
376 0,
377};
378
379static short nfsv3err_symlink[] = {
380 NFSERR_IO,
381 NFSERR_IO,
382 NFSERR_ACCES,
383 NFSERR_EXIST,
384 NFSERR_NOTDIR,
385 NFSERR_NOSPC,
386 NFSERR_ROFS,
387 NFSERR_NAMETOL,
388 NFSERR_DQUOT,
389 NFSERR_STALE,
390 NFSERR_BADHANDLE,
391 NFSERR_NOTSUPP,
392 NFSERR_SERVERFAULT,
393 0,
394};
395
396static short nfsv3err_mknod[] = {
397 NFSERR_IO,
398 NFSERR_IO,
399 NFSERR_ACCES,
400 NFSERR_EXIST,
401 NFSERR_NOTDIR,
402 NFSERR_NOSPC,
403 NFSERR_ROFS,
404 NFSERR_NAMETOL,
405 NFSERR_DQUOT,
406 NFSERR_STALE,
407 NFSERR_BADHANDLE,
408 NFSERR_NOTSUPP,
409 NFSERR_SERVERFAULT,
410 NFSERR_BADTYPE,
411 0,
412};
413
414static short nfsv3err_remove[] = {
415 NFSERR_IO,
416 NFSERR_NOENT,
417 NFSERR_IO,
418 NFSERR_ACCES,
419 NFSERR_NOTDIR,
420 NFSERR_ROFS,
421 NFSERR_NAMETOL,
422 NFSERR_STALE,
423 NFSERR_BADHANDLE,
424 NFSERR_SERVERFAULT,
425 0,
426};
427
428static short nfsv3err_rmdir[] = {
429 NFSERR_IO,
430 NFSERR_NOENT,
431 NFSERR_IO,
432 NFSERR_ACCES,
433 NFSERR_EXIST,
434 NFSERR_NOTDIR,
435 NFSERR_INVAL,
436 NFSERR_ROFS,
437 NFSERR_NAMETOL,
438 NFSERR_NOTEMPTY,
439 NFSERR_STALE,
440 NFSERR_BADHANDLE,
441 NFSERR_NOTSUPP,
442 NFSERR_SERVERFAULT,
443 0,
444};
445
446static short nfsv3err_rename[] = {
447 NFSERR_IO,
448 NFSERR_NOENT,
449 NFSERR_IO,
450 NFSERR_ACCES,
451 NFSERR_EXIST,
452 NFSERR_XDEV,
453 NFSERR_NOTDIR,
454 NFSERR_ISDIR,
455 NFSERR_INVAL,
456 NFSERR_NOSPC,
457 NFSERR_ROFS,
458 NFSERR_MLINK,
459 NFSERR_NAMETOL,
460 NFSERR_NOTEMPTY,
461 NFSERR_DQUOT,
462 NFSERR_STALE,
463 NFSERR_BADHANDLE,
464 NFSERR_NOTSUPP,
465 NFSERR_SERVERFAULT,
466 0,
467};
468
469static short nfsv3err_link[] = {
470 NFSERR_IO,
471 NFSERR_IO,
472 NFSERR_ACCES,
473 NFSERR_EXIST,
474 NFSERR_XDEV,
475 NFSERR_NOTDIR,
476 NFSERR_INVAL,
477 NFSERR_NOSPC,
478 NFSERR_ROFS,
479 NFSERR_MLINK,
480 NFSERR_NAMETOL,
481 NFSERR_DQUOT,
482 NFSERR_STALE,
483 NFSERR_BADHANDLE,
484 NFSERR_NOTSUPP,
485 NFSERR_SERVERFAULT,
486 0,
487};
488
489static short nfsv3err_readdir[] = {
490 NFSERR_IO,
491 NFSERR_IO,
492 NFSERR_ACCES,
493 NFSERR_NOTDIR,
494 NFSERR_STALE,
495 NFSERR_BADHANDLE,
496 NFSERR_BAD_COOKIE,
497 NFSERR_TOOSMALL,
498 NFSERR_SERVERFAULT,
499 0,
500};
501
502static short nfsv3err_readdirplus[] = {
503 NFSERR_IO,
504 NFSERR_IO,
505 NFSERR_ACCES,
506 NFSERR_NOTDIR,
507 NFSERR_STALE,
508 NFSERR_BADHANDLE,
509 NFSERR_BAD_COOKIE,
510 NFSERR_NOTSUPP,
511 NFSERR_TOOSMALL,
512 NFSERR_SERVERFAULT,
513 0,
514};
515
516static short nfsv3err_fsstat[] = {
517 NFSERR_IO,
518 NFSERR_IO,
519 NFSERR_STALE,
520 NFSERR_BADHANDLE,
521 NFSERR_SERVERFAULT,
522 0,
523};
524
525static short nfsv3err_fsinfo[] = {
526 NFSERR_STALE,
527 NFSERR_STALE,
528 NFSERR_BADHANDLE,
529 NFSERR_SERVERFAULT,
530 0,
531};
532
533static short nfsv3err_pathconf[] = {
534 NFSERR_STALE,
535 NFSERR_STALE,
536 NFSERR_BADHANDLE,
537 NFSERR_SERVERFAULT,
538 0,
539};
540
541static short nfsv3err_commit[] = {
542 NFSERR_IO,
543 NFSERR_IO,
544 NFSERR_STALE,
545 NFSERR_BADHANDLE,
546 NFSERR_SERVERFAULT,
547 0,
548};
549
550static short *nfsrv_v3errmap[] = {
551 nfsv3err_null,
552 nfsv3err_getattr,
553 nfsv3err_setattr,
554 nfsv3err_lookup,
555 nfsv3err_access,
556 nfsv3err_readlink,
557 nfsv3err_read,
558 nfsv3err_write,
559 nfsv3err_create,
560 nfsv3err_mkdir,
561 nfsv3err_symlink,
562 nfsv3err_mknod,
563 nfsv3err_remove,
564 nfsv3err_rmdir,
565 nfsv3err_rename,
566 nfsv3err_link,
567 nfsv3err_readdir,
568 nfsv3err_readdirplus,
569 nfsv3err_fsstat,
570 nfsv3err_fsinfo,
571 nfsv3err_pathconf,
572 nfsv3err_commit,
573};
574
575#endif /* NFS_NOSERVER */
576
577extern struct nfsrtt nfsrtt;
578extern time_t nqnfsstarttime;
579extern int nqsrv_clockskew;
580extern int nqsrv_writeslack;
581extern int nqsrv_maxlease;
582extern struct nfsstats nfsstats;
583extern int nqnfs_piggy[NFS_NPROCS];
584extern nfstype nfsv2_type[9];
585extern nfstype nfsv3_type[9];
586extern struct nfsnodehashhead *nfsnodehashtbl;
587extern u_long nfsnodehash;
588
589struct getfh_args;
590extern int getfh(struct proc *, struct getfh_args *, int *);
591struct nfssvc_args;
592extern int nfssvc(struct proc *, struct nfssvc_args *, int *);
593
594LIST_HEAD(nfsnodehashhead, nfsnode);
595
596int nfs_webnamei __P((struct nameidata *, struct vnode *, struct proc *));
597
598/*
599 * Create the header for an rpc request packet
600 * The hsiz is the size of the rest of the nfs request header.
601 * (just used to decide if a cluster is a good idea)
602 */
603struct mbuf *
604nfsm_reqh(vp, procid, hsiz, bposp)
605 struct vnode *vp;
606 u_long procid;
607 int hsiz;
608 caddr_t *bposp;
609{
610 register struct mbuf *mb;
611 register u_long *tl;
612 register caddr_t bpos;
613 struct mbuf *mb2;
614 struct nfsmount *nmp;
615 int nqflag;
616
617 MGET(mb, M_WAIT, MT_DATA);
618 if (hsiz >= MINCLSIZE)
619 MCLGET(mb, M_WAIT);
620 mb->m_len = 0;
621 bpos = mtod(mb, caddr_t);
622
623 /*
624 * For NQNFS, add lease request.
625 */
626 if (vp) {
627 nmp = VFSTONFS(vp->v_mount);
628 if (nmp->nm_flag & NFSMNT_NQNFS) {
629 nqflag = NQNFS_NEEDLEASE(vp, procid);
630 if (nqflag) {
631 nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED);
632 *tl++ = txdr_unsigned(nqflag);
633 *tl = txdr_unsigned(nmp->nm_leaseterm);
634 } else {
635 nfsm_build(tl, u_long *, NFSX_UNSIGNED);
636 *tl = 0;
637 }
638 }
639 }
640 /* Finally, return values */
641 *bposp = bpos;
642 return (mb);
643}
644
645/*
646 * Build the RPC header and fill in the authorization info.
647 * The authorization string argument is only used when the credentials
648 * come from outside of the kernel.
649 * Returns the head of the mbuf list.
650 */
651struct mbuf *
652nfsm_rpchead(cr, nmflag, procid, auth_type, auth_len, auth_str, verf_len,
653 verf_str, mrest, mrest_len, mbp, xidp)
654 register struct ucred *cr;
655 int nmflag;
656 int procid;
657 int auth_type;
658 int auth_len;
659 char *auth_str;
660 int verf_len;
661 char *verf_str;
662 struct mbuf *mrest;
663 int mrest_len;
664 struct mbuf **mbp;
665 u_long *xidp;
666{
667 register struct mbuf *mb;
668 register u_long *tl;
669 register caddr_t bpos;
670 register int i;
671 struct mbuf *mreq, *mb2;
672 int siz, grpsiz, authsiz;
673 struct timeval tv;
674 static u_long base;
675
676 authsiz = nfsm_rndup(auth_len);
677 MGETHDR(mb, M_WAIT, MT_DATA);
678 if ((authsiz + 10 * NFSX_UNSIGNED) >= MINCLSIZE) {
679 MCLGET(mb, M_WAIT);
680 } else if ((authsiz + 10 * NFSX_UNSIGNED) < MHLEN) {
681 MH_ALIGN(mb, authsiz + 10 * NFSX_UNSIGNED);
682 } else {
683 MH_ALIGN(mb, 8 * NFSX_UNSIGNED);
684 }
685 mb->m_len = 0;
686 mreq = mb;
687 bpos = mtod(mb, caddr_t);
688
689 /*
690 * First the RPC header.
691 */
692 nfsm_build(tl, u_long *, 8 * NFSX_UNSIGNED);
693
694 /*
695 * derive initial xid from system time
696 * XXX time is invalid if root not yet mounted
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 */
fa4905b1
A
706 if (++nfs_xid == 0) {
707 nfs_xidwrap++;
1c79356b 708 nfs_xid++;
fa4905b1 709 }
1c79356b
A
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 */
817int
818nfsm_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 */
893int
894nfsm_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 */
977int
978nfsm_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 */
1040int
1041nfs_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 */
1067int
1068nfsm_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 */
1133int
1134nfs_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_nhinit(); /* Init the nfsnode table */
1183#ifndef NFS_NOSERVER
1184 nfsrv_init(0); /* Init server data structures */
1185 nfsrv_initcache(); /* Init the server request cache */
1186#endif
1187
1188 /*
1189 * Initialize the nqnfs server stuff.
1190 */
1191 if (nqnfsstarttime == 0) {
1192 nqnfsstarttime = boottime.tv_sec + nqsrv_maxlease
1193 + nqsrv_clockskew + nqsrv_writeslack;
1194 NQLOADNOVRAM(nqnfsstarttime);
1195 CIRCLEQ_INIT(&nqtimerhead);
1196 nqfhhashtbl = hashinit(NQLCHSZ, M_NQLEASE, &nqfhhash);
1197 }
1198
1199 /*
1200 * Initialize reply list and start timer
1201 */
1202 TAILQ_INIT(&nfs_reqq);
1203
1204 nfs_timer(0);
1205
1206
1207/* XXX CSM 12/4/97 Where are these declared in FreeBSD? */
1208#ifdef notyet
1209 /*
1210 * Set up lease_check and lease_updatetime so that other parts
1211 * of the system can call us, if we are loadable.
1212 */
1213#ifndef NFS_NOSERVER
1214 default_vnodeop_p[VOFFSET(vop_lease)] = (vop_t *)nqnfs_vop_lease_check;
1215#endif
1216 lease_updatetime = nfs_lease_updatetime;
1217#endif
1218 vfsp->vfc_refcount++; /* make us non-unloadable */
1219 sysent[SYS_nfssvc].sy_narg = 2;
1220 sysent[SYS_nfssvc].sy_call = nfssvc;
1221#ifndef NFS_NOSERVER
1222 sysent[SYS_getfh].sy_narg = 2;
1223 sysent[SYS_getfh].sy_call = getfh;
1224#endif
1225
1226 return (0);
1227}
1228
1229/*
1230 * Attribute cache routines.
1231 * nfs_loadattrcache() - loads or updates the cache contents from attributes
1232 * that are on the mbuf list
1233 * nfs_getattrcache() - returns valid attributes if found in cache, returns
1234 * error otherwise
1235 */
1236
1237/*
1238 * Load the attribute cache (that lives in the nfsnode entry) with
1239 * the values on the mbuf list and
1240 * Iff vap not NULL
1241 * copy the attributes to *vaper
1242 */
1243int
fa4905b1 1244nfs_loadattrcache(vpp, mdp, dposp, vaper, dontshrink, xidp)
1c79356b
A
1245 struct vnode **vpp;
1246 struct mbuf **mdp;
1247 caddr_t *dposp;
1248 struct vattr *vaper;
fa4905b1
A
1249 int dontshrink;
1250 u_int64_t *xidp;
1c79356b
A
1251{
1252 register struct vnode *vp = *vpp;
1253 register struct vattr *vap;
1254 register struct nfs_fattr *fp;
1255 register struct nfsnode *np;
1256 register long t1;
1257 caddr_t cp2;
1258 int error = 0, rdev;
1259 struct mbuf *md;
1260 enum vtype vtyp;
1261 u_short vmode;
1262 struct timespec mtime;
1263 struct vnode *nvp;
1264 int v3;
1265
fa4905b1
A
1266 FSDBG_TOP(527, vp, 0, *xidp >> 32, *xidp);
1267 /*
1268 * this routine is a good place to check for VBAD again. We caught
1269 * most of them in nfsm_request, but postprocessing may indirectly get
1270 * here, so check again.
1271 */
1272 if (vp->v_type == VBAD) {
1273 FSDBG_BOT(527, EINVAL, 1, 0, *xidp);
1274 return (EINVAL);
1275 }
1276
1277 v3 = NFS_ISV3(vp);
1c79356b
A
1278 md = *mdp;
1279 t1 = (mtod(md, caddr_t) + md->m_len) - *dposp;
fa4905b1
A
1280 if ((error = nfsm_disct(mdp, dposp, NFSX_FATTR(v3), t1, &cp2))) {
1281 FSDBG_BOT(527, error, 2, 0, *xidp);
1c79356b 1282 return (error);
fa4905b1 1283 }
1c79356b
A
1284 fp = (struct nfs_fattr *)cp2;
1285 if (v3) {
1286 vtyp = nfsv3tov_type(fp->fa_type);
1287 vmode = fxdr_unsigned(u_short, fp->fa_mode);
1288 rdev = makedev(fxdr_unsigned(int, fp->fa3_rdev.specdata1),
1289 fxdr_unsigned(int, fp->fa3_rdev.specdata2));
1290 fxdr_nfsv3time(&fp->fa3_mtime, &mtime);
1291 } else {
1292 vtyp = nfsv2tov_type(fp->fa_type);
1293 vmode = fxdr_unsigned(u_short, fp->fa_mode);
1294 /*
1295 * XXX
1296 *
1297 * The duplicate information returned in fa_type and fa_mode
1298 * is an ambiguity in the NFS version 2 protocol.
1299 *
1300 * VREG should be taken literally as a regular file. If a
1301 * server intents to return some type information differently
1302 * in the upper bits of the mode field (e.g. for sockets, or
1303 * FIFOs), NFSv2 mandates fa_type to be VNON. Anyway, we
1304 * leave the examination of the mode bits even in the VREG
1305 * case to avoid breakage for bogus servers, but we make sure
1306 * that there are actually type bits set in the upper part of
1307 * fa_mode (and failing that, trust the va_type field).
1308 *
1309 * NFSv3 cleared the issue, and requires fa_mode to not
1310 * contain any type information (while also introduing sockets
1311 * and FIFOs for fa_type).
1312 */
1313 if (vtyp == VNON || (vtyp == VREG && (vmode & S_IFMT) != 0))
1314 vtyp = IFTOVT(vmode);
1315 rdev = fxdr_unsigned(long, fp->fa2_rdev);
1316 fxdr_nfsv2time(&fp->fa2_mtime, &mtime);
1317
1318 /*
1319 * Really ugly NFSv2 kludge.
1320 */
1321 if (vtyp == VCHR && rdev == 0xffffffff)
1322 vtyp = VFIFO;
1323 }
1324
1325 /*
1326 * If v_type == VNON it is a new node, so fill in the v_type,
1327 * n_mtime fields. Check to see if it represents a special
1328 * device, and if so, check for a possible alias. Once the
1329 * correct vnode has been obtained, fill in the rest of the
1330 * information.
1331 */
1332 np = VTONFS(vp);
9bccf70c 1333if (*xidp < np->n_xid) {
fa4905b1
A
1334 /*
1335 * We have already updated attributes with a response from
1336 * a later request. The attributes we have here are probably
1337 * stale so we drop them (just return). However, our
1338 * out-of-order receipt could be correct - if the requests were
1339 * processed out of order at the server. Given the uncertainty
1340 * we invalidate our cached attributes. *xidp is zeroed here
1341 * to indicate the attributes were dropped - only getattr
1342 * cares - it needs to retry the rpc.
1343 */
1344 np->n_attrstamp = 0;
1345 FSDBG_BOT(527, 0, np, np->n_xid, *xidp);
1346 *xidp = 0;
1347 return (0);
1348 }
1c79356b
A
1349 if (vp->v_type != vtyp) {
1350 vp->v_type = vtyp;
1351
1352 if (UBCINFOMISSING(vp) || UBCINFORECLAIMED(vp))
fa4905b1
A
1353 if ((error = ubc_info_init(vp))) { /* VREG */
1354 FSDBG_BOT(527, error, 3, 0, *xidp);
1c79356b 1355 return(error);
fa4905b1 1356 }
1c79356b
A
1357
1358 if (vp->v_type == VFIFO) {
1359 vp->v_op = fifo_nfsv2nodeop_p;
1360 }
1361 if (vp->v_type == VCHR || vp->v_type == VBLK) {
1362 vp->v_op = spec_nfsv2nodeop_p;
1363 nvp = checkalias(vp, (dev_t)rdev, vp->v_mount);
1364 if (nvp) {
1365 /*
1366 * Discard unneeded vnode, but save its nfsnode.
1367 * Since the nfsnode does not have a lock, its
1368 * vnode lock has to be carried over.
1369 */
1370 nvp->v_vnlock = vp->v_vnlock;
1371 vp->v_vnlock = NULL;
1372 nvp->v_data = vp->v_data;
1373 vp->v_data = NULL;
1374 vp->v_op = spec_vnodeop_p;
1375 vrele(vp);
1376 vgone(vp);
1377 /*
1378 * Reinitialize aliased node.
1379 */
1380 np->n_vnode = nvp;
1381 *vpp = vp = nvp;
1382 }
1383 }
1384 np->n_mtime = mtime.tv_sec;
fa4905b1 1385 FSDBG(527, vp, np->n_mtime, 0, 0);
1c79356b 1386 }
fa4905b1 1387 np->n_xid = *xidp;
1c79356b
A
1388 vap = &np->n_vattr;
1389 vap->va_type = vtyp;
1390 vap->va_mode = (vmode & 07777);
1391 vap->va_rdev = (dev_t)rdev;
1392 vap->va_mtime = mtime;
1393 vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0];
1394 if (v3) {
1395 vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink);
1396 vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid);
1397 vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid);
1398 fxdr_hyper(&fp->fa3_size, &vap->va_size);
1399 vap->va_blocksize = NFS_FABLKSIZE;
1400 fxdr_hyper(&fp->fa3_used, &vap->va_bytes);
1401 vap->va_fileid = fxdr_unsigned(int, fp->fa3_fileid.nfsuquad[1]);
1402 fxdr_nfsv3time(&fp->fa3_atime, &vap->va_atime);
1403 fxdr_nfsv3time(&fp->fa3_ctime, &vap->va_ctime);
1404 vap->va_flags = 0;
1405 vap->va_filerev = 0;
1406 } else {
1407 vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink);
1408 vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid);
1409 vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid);
1410 vap->va_size = fxdr_unsigned(u_long, fp->fa2_size);
1411 vap->va_blocksize = fxdr_unsigned(long, fp->fa2_blocksize);
1412 vap->va_bytes = fxdr_unsigned(long, fp->fa2_blocks) * NFS_FABLKSIZE;
1413 vap->va_fileid = fxdr_unsigned(long, fp->fa2_fileid);
1414 fxdr_nfsv2time(&fp->fa2_atime, &vap->va_atime);
1415 vap->va_flags = 0;
1416 vap->va_ctime.tv_sec = fxdr_unsigned(long, fp->fa2_ctime.nfsv2_sec);
1417 vap->va_ctime.tv_nsec = 0;
1418 vap->va_gen = fxdr_unsigned(u_long, fp->fa2_ctime.nfsv2_usec);
1419 vap->va_filerev = 0;
1420 }
1421
fa4905b1 1422 np->n_attrstamp = time.tv_sec;
1c79356b 1423 if (vap->va_size != np->n_size) {
fa4905b1
A
1424 FSDBG(527, vp, vap->va_size, np->n_size,
1425 (vap->va_type == VREG) |
1426 (np->n_flag & NMODIFIED ? 6 : 4));
1c79356b 1427 if (vap->va_type == VREG) {
fa4905b1 1428 int orig_size;
1c79356b
A
1429
1430 orig_size = np->n_size;
1c79356b
A
1431 if (np->n_flag & NMODIFIED) {
1432 if (vap->va_size < np->n_size)
1433 vap->va_size = np->n_size;
1434 else
1435 np->n_size = vap->va_size;
1436 } else
1437 np->n_size = vap->va_size;
d52fe63f
A
1438 if (!UBCINFOEXISTS(vp) ||
1439 dontshrink && np->n_size < ubc_getsize(vp)) {
fa4905b1
A
1440 vap->va_size = np->n_size = orig_size;
1441 np->n_attrstamp = 0;
1442 } else
1443 ubc_setsize(vp, (off_t)np->n_size); /* XXX */
1c79356b
A
1444 } else
1445 np->n_size = vap->va_size;
1446 }
1447
1c79356b
A
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 }
fa4905b1 1457 FSDBG_BOT(527, 0, np, 0, *xidp);
1c79356b
A
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 */
1466int
1467nfs_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
1474 if ((time.tv_sec - np->n_attrstamp) >= NFS_ATTRTIMEO(np)) {
fa4905b1 1475 FSDBG(528, vp, 0, 0, 1);
1c79356b
A
1476 nfsstats.attrcache_misses++;
1477 return (ENOENT);
1478 }
fa4905b1 1479 FSDBG(528, vp, 0, 0, 2);
1c79356b
A
1480 nfsstats.attrcache_hits++;
1481 vap = &np->n_vattr;
1482
1483 if (vap->va_size != np->n_size) {
fa4905b1
A
1484 FSDBG(528, vp, vap->va_size, np->n_size,
1485 (vap->va_type == VREG) |
1486 (np->n_flag & NMODIFIED ? 6 : 4));
1c79356b 1487 if (vap->va_type == VREG) {
1c79356b
A
1488 if (np->n_flag & NMODIFIED) {
1489 if (vap->va_size < np->n_size)
1490 vap->va_size = np->n_size;
1491 else
1492 np->n_size = vap->va_size;
1493 } else
1494 np->n_size = vap->va_size;
fa4905b1 1495 ubc_setsize(vp, (off_t)np->n_size); /* XXX */
1c79356b
A
1496 } else
1497 np->n_size = vap->va_size;
1498 }
1499
1500 bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(struct vattr));
1501 if (np->n_flag & NCHG) {
1502 if (np->n_flag & NACC)
1503 vaper->va_atime = np->n_atim;
1504 if (np->n_flag & NUPD)
1505 vaper->va_mtime = np->n_mtim;
1506 }
1507 return (0);
1508}
1509
1510#ifndef NFS_NOSERVER
1511/*
1512 * Set up nameidata for a lookup() call and do it.
1513 *
1514 * If pubflag is set, this call is done for a lookup operation on the
1515 * public filehandle. In that case we allow crossing mountpoints and
1516 * absolute pathnames. However, the caller is expected to check that
1517 * the lookup result is within the public fs, and deny access if
1518 * it is not.
1519 */
1520int
1521nfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, retdirp, p, kerbflag, pubflag)
1522 register struct nameidata *ndp;
1523 fhandle_t *fhp;
1524 int len;
1525 struct nfssvc_sock *slp;
1526 struct mbuf *nam;
1527 struct mbuf **mdp;
1528 caddr_t *dposp;
1529 struct vnode **retdirp;
1530 struct proc *p;
1531 int kerbflag, pubflag;
1532{
1533 register int i, rem;
1534 register struct mbuf *md;
1535 register char *fromcp, *tocp, *cp;
1536 struct iovec aiov;
1537 struct uio auio;
1538 struct vnode *dp;
1539 int error, rdonly, linklen;
1540 struct componentname *cnp = &ndp->ni_cnd;
1541 int olen = len;
1542
1543 *retdirp = (struct vnode *)0;
1544 MALLOC_ZONE(cnp->cn_pnbuf, char *, len + 1, M_NAMEI, M_WAITOK);
1545 cnp->cn_pnlen = len + 1;
1546
1547 /*
1548 * Copy the name from the mbuf list to ndp->ni_pnbuf
1549 * and set the various ndp fields appropriately.
1550 */
1551 fromcp = *dposp;
1552 tocp = cnp->cn_pnbuf;
1553 md = *mdp;
1554 rem = mtod(md, caddr_t) + md->m_len - fromcp;
1555 cnp->cn_hash = 0;
1556 for (i = 1; i <= len; i++) {
1557 while (rem == 0) {
1558 md = md->m_next;
1559 if (md == NULL) {
1560 error = EBADRPC;
1561 goto out;
1562 }
1563 fromcp = mtod(md, caddr_t);
1564 rem = md->m_len;
1565 }
1566/* XXX CSM 12/4/97 Revisit when enabling WebNFS */
1567#ifdef notdef
1568 if (*fromcp == '\0' || (!pubflag && *fromcp == '/')) {
1569#else
1570 if (*fromcp == '\0' || *fromcp == '/') {
1571#endif
1572 error = EACCES;
1573 goto out;
1574 }
1575 cnp->cn_hash += (unsigned char)*fromcp * i;
1576 *tocp++ = *fromcp++;
1577 rem--;
1578 }
1579 *tocp = '\0';
1580 *mdp = md;
1581 *dposp = fromcp;
1582 len = nfsm_rndup(len)-len;
1583 if (len > 0) {
1584 if (rem >= len)
1585 *dposp += len;
1586 else if ((error = nfs_adv(mdp, dposp, len, rem)) != 0)
1587 goto out;
1588 }
1589
1590 /*
1591 * Extract and set starting directory.
1592 */
1593 error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cnd.cn_cred, slp,
1594 nam, &rdonly, kerbflag, pubflag);
1595 if (error)
1596 goto out;
1597 if (dp->v_type != VDIR) {
1598 vrele(dp);
1599 error = ENOTDIR;
1600 goto out;
1601 }
1602
1603 if (rdonly)
1604 cnp->cn_flags |= RDONLY;
1605
1606 *retdirp = dp;
1607
1608/* XXX CSM 12/4/97 Revisit when enabling WebNFS */
1609/* XXX debo 12/15/97 Need to fix M_NAMEI allocations to use zone protocol */
1610#ifdef notyet
1611 if (pubflag) {
1612 /*
1613 * Oh joy. For WebNFS, handle those pesky '%' escapes,
1614 * and the 'native path' indicator.
1615 */
1616 MALLOC(cp, char *, olen + 1, M_NAMEI, M_WAITOK);
1617 fromcp = cnp->cn_pnbuf;
1618 tocp = cp;
1619 if ((unsigned char)*fromcp >= WEBNFS_SPECCHAR_START) {
1620 switch ((unsigned char)*fromcp) {
1621 case WEBNFS_NATIVE_CHAR:
1622 /*
1623 * 'Native' path for us is the same
1624 * as a path according to the NFS spec,
1625 * just skip the escape char.
1626 */
1627 fromcp++;
1628 break;
1629 /*
1630 * More may be added in the future, range 0x80-0xff
1631 */
1632 default:
1633 error = EIO;
1634 FREE(cp, M_NAMEI);
1635 goto out;
1636 }
1637 }
1638 /*
1639 * Translate the '%' escapes, URL-style.
1640 */
1641 while (*fromcp != '\0') {
1642 if (*fromcp == WEBNFS_ESC_CHAR) {
1643 if (fromcp[1] != '\0' && fromcp[2] != '\0') {
1644 fromcp++;
1645 *tocp++ = HEXSTRTOI(fromcp);
1646 fromcp += 2;
1647 continue;
1648 } else {
1649 error = ENOENT;
1650 FREE(cp, M_NAMEI);
1651 goto out;
1652 }
1653 } else
1654 *tocp++ = *fromcp++;
1655 }
1656 *tocp = '\0';
1657 FREE(cnp->cn_pnbuf, M_NAMEI);
1658 cnp->cn_pnbuf = cp;
1659 }
1660#endif
1661
1662 ndp->ni_pathlen = (tocp - cnp->cn_pnbuf) + 1;
1663 ndp->ni_segflg = UIO_SYSSPACE;
1664
1665/* XXX CSM 12/4/97 Revisit when enabling WebNFS */
1666#ifdef notyet
1667 if (pubflag) {
1668 ndp->ni_rootdir = rootvnode;
1669 ndp->ni_loopcnt = 0;
1670 if (cnp->cn_pnbuf[0] == '/')
1671 dp = rootvnode;
1672 } else {
1673 cnp->cn_flags |= NOCROSSMOUNT;
1674 }
1675#else
1676 cnp->cn_flags |= NOCROSSMOUNT;
1677#endif
1678
1679 cnp->cn_proc = p;
1680 VREF(dp);
1681
1682 for (;;) {
1683 cnp->cn_nameptr = cnp->cn_pnbuf;
1684 ndp->ni_startdir = dp;
1685 /*
1686 * And call lookup() to do the real work
1687 */
1688 error = lookup(ndp);
1689 if (error)
1690 break;
1691 /*
1692 * Check for encountering a symbolic link
1693 */
1694 if ((cnp->cn_flags & ISSYMLINK) == 0) {
1695 nfsrv_object_create(ndp->ni_vp);
1696 if (cnp->cn_flags & (SAVENAME | SAVESTART)) {
1697 cnp->cn_flags |= HASBUF;
1698 return (0);
1699 }
1700 break;
1701 } else {
1702 if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1)
1703 VOP_UNLOCK(ndp->ni_dvp, 0, p);
1704/* XXX CSM 12/4/97 Revisit when enabling WebNFS */
1705#ifdef notyet
1706 if (!pubflag) {
1707#endif
1708 vrele(ndp->ni_dvp);
1709 vput(ndp->ni_vp);
1710 ndp->ni_vp = NULL;
1711 error = EINVAL;
1712 break;
1713/* XXX CSM 12/4/97 Revisit when enabling WebNFS */
1714/* XXX debo 12/15/97 Need to fix M_NAMEI allocations to use zone protocol */
1715#ifdef notyet
1716 }
1717
1718 if (ndp->ni_loopcnt++ >= MAXSYMLINKS) {
1719 error = ELOOP;
1720 break;
1721 }
1722 if (ndp->ni_pathlen > 1)
1723 MALLOC(cp, char *, olen + 1, M_NAMEI, M_WAITOK);
1724 else
1725 cp = cnp->cn_pnbuf;
1726 aiov.iov_base = cp;
1727 aiov.iov_len = MAXPATHLEN;
1728 auio.uio_iov = &aiov;
1729 auio.uio_iovcnt = 1;
1730 auio.uio_offset = 0;
1731 auio.uio_rw = UIO_READ;
1732 auio.uio_segflg = UIO_SYSSPACE;
1733 auio.uio_procp = (struct proc *)0;
1734 auio.uio_resid = MAXPATHLEN;
1735 error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred);
1736 if (error) {
1737 badlink:
1738 if (ndp->ni_pathlen > 1)
1739 FREE(cp, M_NAMEI);
1740 break;
1741 }
1742 linklen = MAXPATHLEN - auio.uio_resid;
1743 if (linklen == 0) {
1744 error = ENOENT;
1745 goto badlink;
1746 }
1747 if (linklen + ndp->ni_pathlen >= MAXPATHLEN) {
1748 error = ENAMETOOLONG;
1749 goto badlink;
1750 }
1751 if (ndp->ni_pathlen > 1) {
1752 bcopy(ndp->ni_next, cp + linklen, ndp->ni_pathlen);
1753 FREE(cnp->cn_pnbuf, M_NAMEI);
1754 cnp->cn_pnbuf = cp;
1755 } else
1756 cnp->cn_pnbuf[linklen] = '\0';
1757 ndp->ni_pathlen += linklen;
1758 vput(ndp->ni_vp);
1759 dp = ndp->ni_dvp;
1760 /*
1761 * Check if root directory should replace current directory.
1762 */
1763 if (cnp->cn_pnbuf[0] == '/') {
1764 vrele(dp);
1765 dp = ndp->ni_rootdir;
1766 VREF(dp);
1767 }
1768#endif
1769 }
1770 }
1771out:
1772 FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI);
1773 return (error);
1774}
1775
1776/*
1777 * A fiddled version of m_adj() that ensures null fill to a long
1778 * boundary and only trims off the back end
1779 */
1780void
1781nfsm_adj(mp, len, nul)
1782 struct mbuf *mp;
1783 register int len;
1784 int nul;
1785{
1786 register struct mbuf *m;
1787 register int count, i;
1788 register char *cp;
1789
1790 /*
1791 * Trim from tail. Scan the mbuf chain,
1792 * calculating its length and finding the last mbuf.
1793 * If the adjustment only affects this mbuf, then just
1794 * adjust and return. Otherwise, rescan and truncate
1795 * after the remaining size.
1796 */
1797 count = 0;
1798 m = mp;
1799 for (;;) {
1800 count += m->m_len;
1801 if (m->m_next == (struct mbuf *)0)
1802 break;
1803 m = m->m_next;
1804 }
1805 if (m->m_len > len) {
1806 m->m_len -= len;
1807 if (nul > 0) {
1808 cp = mtod(m, caddr_t)+m->m_len-nul;
1809 for (i = 0; i < nul; i++)
1810 *cp++ = '\0';
1811 }
1812 return;
1813 }
1814 count -= len;
1815 if (count < 0)
1816 count = 0;
1817 /*
1818 * Correct length for chain is "count".
1819 * Find the mbuf with last data, adjust its length,
1820 * and toss data from remaining mbufs on chain.
1821 */
1822 for (m = mp; m; m = m->m_next) {
1823 if (m->m_len >= count) {
1824 m->m_len = count;
1825 if (nul > 0) {
1826 cp = mtod(m, caddr_t)+m->m_len-nul;
1827 for (i = 0; i < nul; i++)
1828 *cp++ = '\0';
1829 }
1830 break;
1831 }
1832 count -= m->m_len;
1833 }
1834 for (m = m->m_next;m;m = m->m_next)
1835 m->m_len = 0;
1836}
1837
1838/*
1839 * Make these functions instead of macros, so that the kernel text size
1840 * doesn't get too big...
1841 */
1842void
1843nfsm_srvwcc(nfsd, before_ret, before_vap, after_ret, after_vap, mbp, bposp)
1844 struct nfsrv_descript *nfsd;
1845 int before_ret;
1846 register struct vattr *before_vap;
1847 int after_ret;
1848 struct vattr *after_vap;
1849 struct mbuf **mbp;
1850 char **bposp;
1851{
1852 register struct mbuf *mb = *mbp, *mb2;
1853 register char *bpos = *bposp;
1854 register u_long *tl;
1855
1856 if (before_ret) {
1857 nfsm_build(tl, u_long *, NFSX_UNSIGNED);
1858 *tl = nfs_false;
1859 } else {
1860 nfsm_build(tl, u_long *, 7 * NFSX_UNSIGNED);
1861 *tl++ = nfs_true;
1862 txdr_hyper(&(before_vap->va_size), tl);
1863 tl += 2;
1864 txdr_nfsv3time(&(before_vap->va_mtime), tl);
1865 tl += 2;
1866 txdr_nfsv3time(&(before_vap->va_ctime), tl);
1867 }
1868 *bposp = bpos;
1869 *mbp = mb;
1870 nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp);
1871}
1872
1873void
1874nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp)
1875 struct nfsrv_descript *nfsd;
1876 int after_ret;
1877 struct vattr *after_vap;
1878 struct mbuf **mbp;
1879 char **bposp;
1880{
1881 register struct mbuf *mb = *mbp, *mb2;
1882 register char *bpos = *bposp;
1883 register u_long *tl;
1884 register struct nfs_fattr *fp;
1885
1886 if (after_ret) {
1887 nfsm_build(tl, u_long *, NFSX_UNSIGNED);
1888 *tl = nfs_false;
1889 } else {
1890 nfsm_build(tl, u_long *, NFSX_UNSIGNED + NFSX_V3FATTR);
1891 *tl++ = nfs_true;
1892 fp = (struct nfs_fattr *)tl;
1893 nfsm_srvfattr(nfsd, after_vap, fp);
1894 }
1895 *mbp = mb;
1896 *bposp = bpos;
1897}
1898
1899void
1900nfsm_srvfattr(nfsd, vap, fp)
1901 register struct nfsrv_descript *nfsd;
1902 register struct vattr *vap;
1903 register struct nfs_fattr *fp;
1904{
1905
1906 fp->fa_nlink = txdr_unsigned(vap->va_nlink);
1907 fp->fa_uid = txdr_unsigned(vap->va_uid);
1908 fp->fa_gid = txdr_unsigned(vap->va_gid);
1909 if (nfsd->nd_flag & ND_NFSV3) {
1910 fp->fa_type = vtonfsv3_type(vap->va_type);
1911 fp->fa_mode = vtonfsv3_mode(vap->va_mode);
1912 txdr_hyper(&vap->va_size, &fp->fa3_size);
1913 txdr_hyper(&vap->va_bytes, &fp->fa3_used);
1914 fp->fa3_rdev.specdata1 = txdr_unsigned(major(vap->va_rdev));
1915 fp->fa3_rdev.specdata2 = txdr_unsigned(minor(vap->va_rdev));
1916 fp->fa3_fsid.nfsuquad[0] = 0;
1917 fp->fa3_fsid.nfsuquad[1] = txdr_unsigned(vap->va_fsid);
1918 fp->fa3_fileid.nfsuquad[0] = 0;
1919 fp->fa3_fileid.nfsuquad[1] = txdr_unsigned(vap->va_fileid);
1920 txdr_nfsv3time(&vap->va_atime, &fp->fa3_atime);
1921 txdr_nfsv3time(&vap->va_mtime, &fp->fa3_mtime);
1922 txdr_nfsv3time(&vap->va_ctime, &fp->fa3_ctime);
1923 } else {
1924 fp->fa_type = vtonfsv2_type(vap->va_type);
1925 fp->fa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode);
1926 fp->fa2_size = txdr_unsigned(vap->va_size);
1927 fp->fa2_blocksize = txdr_unsigned(vap->va_blocksize);
1928 if (vap->va_type == VFIFO)
1929 fp->fa2_rdev = 0xffffffff;
1930 else
1931 fp->fa2_rdev = txdr_unsigned(vap->va_rdev);
1932 fp->fa2_blocks = txdr_unsigned(vap->va_bytes / NFS_FABLKSIZE);
1933 fp->fa2_fsid = txdr_unsigned(vap->va_fsid);
1934 fp->fa2_fileid = txdr_unsigned(vap->va_fileid);
1935 txdr_nfsv2time(&vap->va_atime, &fp->fa2_atime);
1936 txdr_nfsv2time(&vap->va_mtime, &fp->fa2_mtime);
1937 txdr_nfsv2time(&vap->va_ctime, &fp->fa2_ctime);
1938 }
1939}
1940
1941/*
1942 * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked)
1943 * - look up fsid in mount list (if not found ret error)
1944 * - get vp and export rights by calling VFS_FHTOVP()
1945 * - if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon
1946 * - if not lockflag unlock it with VOP_UNLOCK()
1947 */
1948int
1949nfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp, kerbflag, pubflag)
1950 fhandle_t *fhp;
1951 int lockflag;
1952 struct vnode **vpp;
1953 struct ucred *cred;
1954 struct nfssvc_sock *slp;
1955 struct mbuf *nam;
1956 int *rdonlyp;
1957 int kerbflag;
1958 int pubflag;
1959{
1960 struct proc *p = current_proc(); /* XXX */
1961 register struct mount *mp;
1962 register int i;
1963 struct ucred *credanon;
1964 int error, exflags;
1965
1966 *vpp = (struct vnode *)0;
1967
1968/* XXX CSM 12/4/97 Revisit when enabling WebNFS */
1969#ifdef notyet
1970 if (nfs_ispublicfh(fhp)) {
1971 if (!pubflag || !nfs_pub.np_valid)
1972 return (ESTALE);
1973 fhp = &nfs_pub.np_handle;
1974 }
1975#endif
1976
1977 mp = vfs_getvfs(&fhp->fh_fsid);
1978 if (!mp)
1979 return (ESTALE);
1980 error = VFS_FHTOVP(mp, &fhp->fh_fid, nam, vpp, &exflags, &credanon);
1981 if (error)
1982 return (error);
1983 /* vnode pointer should be good at this point or ... */
1984 if (*vpp == NULL)
1985 return (ESTALE);
1986 /*
1987 * Check/setup credentials.
1988 */
1989 if (exflags & MNT_EXKERB) {
1990 if (!kerbflag) {
1991 vput(*vpp);
1992 return (NFSERR_AUTHERR | AUTH_TOOWEAK);
1993 }
1994 } else if (kerbflag) {
1995 vput(*vpp);
1996 return (NFSERR_AUTHERR | AUTH_TOOWEAK);
1997 } else if (cred->cr_uid == 0 || (exflags & MNT_EXPORTANON)) {
1998 cred->cr_uid = credanon->cr_uid;
1999 for (i = 0; i < credanon->cr_ngroups && i < NGROUPS; i++)
2000 cred->cr_groups[i] = credanon->cr_groups[i];
2001 cred->cr_ngroups = i;
2002 }
2003 if (exflags & MNT_EXRDONLY)
2004 *rdonlyp = 1;
2005 else
2006 *rdonlyp = 0;
2007
2008 nfsrv_object_create(*vpp);
2009
2010 if (!lockflag)
2011 VOP_UNLOCK(*vpp, 0, p);
2012 return (0);
2013}
2014
2015
2016/*
2017 * WebNFS: check if a filehandle is a public filehandle. For v3, this
2018 * means a length of 0, for v2 it means all zeroes. nfsm_srvmtofh has
2019 * transformed this to all zeroes in both cases, so check for it.
2020 */
2021int
2022nfs_ispublicfh(fhp)
2023 fhandle_t *fhp;
2024{
2025 char *cp = (char *)fhp;
2026 int i;
2027
2028 for (i = 0; i < NFSX_V3FH; i++)
2029 if (*cp++ != 0)
2030 return (FALSE);
2031 return (TRUE);
2032}
2033
2034#endif /* NFS_NOSERVER */
2035/*
2036 * This function compares two net addresses by family and returns TRUE
2037 * if they are the same host.
2038 * If there is any doubt, return FALSE.
2039 * The AF_INET family is handled as a special case so that address mbufs
2040 * don't need to be saved to store "struct in_addr", which is only 4 bytes.
2041 */
2042int
2043netaddr_match(family, haddr, nam)
2044 int family;
2045 union nethostaddr *haddr;
2046 struct mbuf *nam;
2047{
2048 register struct sockaddr_in *inetaddr;
2049
2050 switch (family) {
2051 case AF_INET:
2052 inetaddr = mtod(nam, struct sockaddr_in *);
2053 if (inetaddr->sin_family == AF_INET &&
2054 inetaddr->sin_addr.s_addr == haddr->had_inetaddr)
2055 return (1);
2056 break;
2057#if ISO
2058 case AF_ISO:
2059 {
2060 register struct sockaddr_iso *isoaddr1, *isoaddr2;
2061
2062 isoaddr1 = mtod(nam, struct sockaddr_iso *);
2063 isoaddr2 = mtod(haddr->had_nam, struct sockaddr_iso *);
2064 if (isoaddr1->siso_family == AF_ISO &&
2065 isoaddr1->siso_nlen > 0 &&
2066 isoaddr1->siso_nlen == isoaddr2->siso_nlen &&
2067 SAME_ISOADDR(isoaddr1, isoaddr2))
2068 return (1);
2069 break;
2070 }
2071#endif /* ISO */
2072 default:
2073 break;
2074 };
2075 return (0);
2076}
2077
2078static nfsuint64 nfs_nullcookie = { 0, 0 };
2079/*
2080 * This function finds the directory cookie that corresponds to the
2081 * logical byte offset given.
2082 */
2083nfsuint64 *
2084nfs_getcookie(np, off, add)
2085 register struct nfsnode *np;
2086 off_t off;
2087 int add;
2088{
2089 register struct nfsdmap *dp, *dp2;
2090 register int pos;
2091
2092 pos = off / NFS_DIRBLKSIZ;
2093 if (pos == 0) {
2094#if DIAGNOSTIC
2095 if (add)
2096 panic("nfs getcookie add at 0");
2097#endif
2098 return (&nfs_nullcookie);
2099 }
2100 pos--;
2101 dp = np->n_cookies.lh_first;
2102 if (!dp) {
2103 if (add) {
2104 MALLOC_ZONE(dp, struct nfsdmap *,
2105 sizeof (struct nfsdmap),
2106 M_NFSDIROFF, M_WAITOK);
2107 dp->ndm_eocookie = 0;
2108 LIST_INSERT_HEAD(&np->n_cookies, dp, ndm_list);
2109 } else
2110 return ((nfsuint64 *)0);
2111 }
2112 while (pos >= NFSNUMCOOKIES) {
2113 pos -= NFSNUMCOOKIES;
2114 if (dp->ndm_list.le_next) {
2115 if (!add && dp->ndm_eocookie < NFSNUMCOOKIES &&
2116 pos >= dp->ndm_eocookie)
2117 return ((nfsuint64 *)0);
2118 dp = dp->ndm_list.le_next;
2119 } else if (add) {
2120 MALLOC_ZONE(dp2, struct nfsdmap *,
2121 sizeof (struct nfsdmap),
2122 M_NFSDIROFF, M_WAITOK);
2123 dp2->ndm_eocookie = 0;
2124 LIST_INSERT_AFTER(dp, dp2, ndm_list);
2125 dp = dp2;
2126 } else
2127 return ((nfsuint64 *)0);
2128 }
2129 if (pos >= dp->ndm_eocookie) {
2130 if (add)
2131 dp->ndm_eocookie = pos + 1;
2132 else
2133 return ((nfsuint64 *)0);
2134 }
2135 return (&dp->ndm_cookies[pos]);
2136}
2137
2138/*
2139 * Invalidate cached directory information, except for the actual directory
2140 * blocks (which are invalidated separately).
2141 * Done mainly to avoid the use of stale offset cookies.
2142 */
2143void
2144nfs_invaldir(vp)
2145 register struct vnode *vp;
2146{
2147 register struct nfsnode *np = VTONFS(vp);
2148
2149#if DIAGNOSTIC
2150 if (vp->v_type != VDIR)
2151 panic("nfs: invaldir not dir");
2152#endif
2153 np->n_direofoffset = 0;
2154 np->n_cookieverf.nfsuquad[0] = 0;
2155 np->n_cookieverf.nfsuquad[1] = 0;
2156 if (np->n_cookies.lh_first)
2157 np->n_cookies.lh_first->ndm_eocookie = 0;
2158}
2159
2160/*
2161 * The write verifier has changed (probably due to a server reboot), so all
2162 * B_NEEDCOMMIT blocks will have to be written again. Since they are on the
2163 * dirty block list as B_DELWRI, all this takes is clearing the B_NEEDCOMMIT
2164 * flag. Once done the new write verifier can be set for the mount point.
2165 */
2166void
2167nfs_clearcommit(mp)
2168 struct mount *mp;
2169{
2170 register struct vnode *vp, *nvp;
2171 register struct buf *bp, *nbp;
2172 int s;
2173
2174 s = splbio();
2175loop:
2176 for (vp = mp->mnt_vnodelist.lh_first; vp; vp = nvp) {
2177 if (vp->v_mount != mp) /* Paranoia */
2178 goto loop;
2179 nvp = vp->v_mntvnodes.le_next;
2180 for (bp = vp->v_dirtyblkhd.lh_first; bp; bp = nbp) {
2181 nbp = bp->b_vnbufs.le_next;
2182 if ((bp->b_flags & (B_BUSY | B_DELWRI | B_NEEDCOMMIT))
2183 == (B_DELWRI | B_NEEDCOMMIT))
2184 bp->b_flags &= ~B_NEEDCOMMIT;
2185 }
2186 }
2187 splx(s);
2188}
2189
2190#ifndef NFS_NOSERVER
2191/*
2192 * Map errnos to NFS error numbers. For Version 3 also filter out error
2193 * numbers not specified for the associated procedure.
2194 */
2195int
2196nfsrv_errmap(nd, err)
2197 struct nfsrv_descript *nd;
2198 register int err;
2199{
2200 register short *defaulterrp, *errp;
2201
2202 if (nd->nd_flag & ND_NFSV3) {
2203 if (nd->nd_procnum <= NFSPROC_COMMIT) {
2204 errp = defaulterrp = nfsrv_v3errmap[nd->nd_procnum];
2205 while (*++errp) {
2206 if (*errp == err)
2207 return (err);
2208 else if (*errp > err)
2209 break;
2210 }
2211 return ((int)*defaulterrp);
2212 } else
2213 return (err & 0xffff);
2214 }
2215 if (err <= ELAST)
2216 return ((int)nfsrv_v2errmap[err - 1]);
2217 return (NFSERR_IO);
2218}
2219
2220/* XXX CSM 11/25/97 Revisit when Ramesh merges vm with buffer cache */
2221#define vfs_object_create(v, p, c, l) (0)
2222
2223int
2224nfsrv_object_create(struct vnode *vp) {
2225 struct proc *curproc = current_proc();
2226
2227 if ((vp == NULL) || (vp->v_type != VREG))
2228 return 1;
2229 return vfs_object_create(vp, curproc, curproc?curproc->p_ucred:NULL, 1);
2230}
2231#endif /* NFS_NOSERVER */
2232