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