1 /* $OpenBSD: nfs_subs.c,v 1.54 2005/04/02 01:00:38 mickey Exp $ */
2 /* $NetBSD: nfs_subs.c,v 1.27.4.3 1996/07/08 20:34:24 jtc Exp $ */
3
4 /*
5 * Copyright (c) 1989, 1993
6 * The Regents of the University of California. All rights reserved.
7 *
8 * This code is derived from software contributed to Berkeley by
9 * Rick Macklem at The University of Guelph.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 *
35 * @(#)nfs_subs.c 8.8 (Berkeley) 5/22/95
36 */
37
38
39 /*
40 * These functions support the macros and help fiddle mbuf chains for
41 * the nfs op functions. They do things like create the rpc header and
42 * copy data between mbuf chains and uio lists.
43 */
44 #include <sys/param.h>
45 #include <sys/proc.h>
46 #include <sys/systm.h>
47 #include <sys/kernel.h>
48 #include <sys/mount.h>
49 #include <sys/vnode.h>
50 #include <sys/namei.h>
51 #include <sys/mbuf.h>
52 #include <sys/socket.h>
53 #include <sys/socketvar.h>
54 #include <sys/stat.h>
55 #include <sys/malloc.h>
56 #include <sys/pool.h>
57 #include <sys/time.h>
58
59 #include <uvm/uvm_extern.h>
60
61 #include <nfs/rpcv2.h>
62 #include <nfs/nfsproto.h>
63 #include <nfs/nfsnode.h>
64 #include <nfs/nfs.h>
65 #include <nfs/xdr_subs.h>
66 #include <nfs/nfsm_subs.h>
67 #include <nfs/nfsmount.h>
68 #include <nfs/nfsrtt.h>
69 #include <nfs/nfs_var.h>
70
71 #include <miscfs/specfs/specdev.h>
72
73 #include <netinet/in.h>
74
75 #include <dev/rndvar.h>
76
77 #ifdef __GNUC__
78 #define INLINE __inline
79 #else
80 #define INLINE
81 #endif
82
83 int nfs_attrtimeo(struct nfsnode *np);
84
85 /*
86 * Data items converted to xdr at startup, since they are constant
87 * This is kinda hokey, but may save a little time doing byte swaps
88 */
89 u_int32_t nfs_xdrneg1;
90 u_int32_t rpc_call, rpc_vers, rpc_reply, rpc_msgdenied, rpc_autherr,
91 rpc_mismatch, rpc_auth_unix, rpc_msgaccepted,
92 rpc_auth_kerb;
93 u_int32_t nfs_prog, nfs_true, nfs_false;
94
95 /* And other global data */
96 static u_int32_t nfs_xid = 0;
97 static u_int32_t nfs_xid_touched = 0;
98 nfstype nfsv2_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFNON,
99 NFCHR, NFNON };
100 nfstype nfsv3_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFSOCK,
101 NFFIFO, NFNON };
102 enum vtype nv2tov_type[8] = { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON, VNON };
103 enum vtype nv3tov_type[8]={ VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO };
104 int nfs_ticks;
105
106 /*
107 * Mapping of old NFS Version 2 RPC numbers to generic numbers.
108 */
109 int nfsv3_procid[NFS_NPROCS] = {
110 NFSPROC_NULL,
111 NFSPROC_GETATTR,
112 NFSPROC_SETATTR,
113 NFSPROC_NOOP,
114 NFSPROC_LOOKUP,
115 NFSPROC_READLINK,
116 NFSPROC_READ,
117 NFSPROC_NOOP,
118 NFSPROC_WRITE,
119 NFSPROC_CREATE,
120 NFSPROC_REMOVE,
121 NFSPROC_RENAME,
122 NFSPROC_LINK,
123 NFSPROC_SYMLINK,
124 NFSPROC_MKDIR,
125 NFSPROC_RMDIR,
126 NFSPROC_READDIR,
127 NFSPROC_FSSTAT,
128 NFSPROC_NOOP,
129 NFSPROC_NOOP,
130 NFSPROC_NOOP,
131 NFSPROC_NOOP,
132 NFSPROC_NOOP,
133 NFSPROC_NOOP,
134 NFSPROC_NOOP,
135 NFSPROC_NOOP
136 };
137
138 /*
139 * and the reverse mapping from generic to Version 2 procedure numbers
140 */
141 int nfsv2_procid[NFS_NPROCS] = {
142 NFSV2PROC_NULL,
143 NFSV2PROC_GETATTR,
144 NFSV2PROC_SETATTR,
145 NFSV2PROC_LOOKUP,
146 NFSV2PROC_NOOP,
147 NFSV2PROC_READLINK,
148 NFSV2PROC_READ,
149 NFSV2PROC_WRITE,
150 NFSV2PROC_CREATE,
151 NFSV2PROC_MKDIR,
152 NFSV2PROC_SYMLINK,
153 NFSV2PROC_CREATE,
154 NFSV2PROC_REMOVE,
155 NFSV2PROC_RMDIR,
156 NFSV2PROC_RENAME,
157 NFSV2PROC_LINK,
158 NFSV2PROC_READDIR,
159 NFSV2PROC_NOOP,
160 NFSV2PROC_STATFS,
161 NFSV2PROC_NOOP,
162 NFSV2PROC_NOOP,
163 NFSV2PROC_NOOP,
164 NFSV2PROC_NOOP,
165 NFSV2PROC_NOOP,
166 NFSV2PROC_NOOP,
167 NFSV2PROC_NOOP,
168 };
169
170 /*
171 * Maps errno values to nfs error numbers.
172 * Use NFSERR_IO as the catch all for ones not specifically defined in
173 * RFC 1094.
174 */
175 static u_char nfsrv_v2errmap[ELAST] = {
176 NFSERR_PERM, NFSERR_NOENT, NFSERR_IO, NFSERR_IO, NFSERR_IO,
177 NFSERR_NXIO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
178 NFSERR_IO, NFSERR_IO, NFSERR_ACCES, NFSERR_IO, NFSERR_IO,
179 NFSERR_IO, NFSERR_EXIST, NFSERR_IO, NFSERR_NODEV, NFSERR_NOTDIR,
180 NFSERR_ISDIR, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
181 NFSERR_IO, NFSERR_FBIG, NFSERR_NOSPC, NFSERR_IO, NFSERR_ROFS,
182 NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
183 NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
184 NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
185 NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
186 NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
187 NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
188 NFSERR_IO, NFSERR_IO, NFSERR_NAMETOL, NFSERR_IO, NFSERR_IO,
189 NFSERR_NOTEMPTY, NFSERR_IO, NFSERR_IO, NFSERR_DQUOT, NFSERR_STALE,
190 NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
191 NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
192 NFSERR_IO,
193 };
194
195 /*
196 * Maps errno values to nfs error numbers.
197 * Although it is not obvious whether or not NFS clients really care if
198 * a returned error value is in the specified list for the procedure, the
199 * safest thing to do is filter them appropriately. For Version 2, the
200 * X/Open XNFS document is the only specification that defines error values
201 * for each RPC (The RFC simply lists all possible error values for all RPCs),
202 * so I have decided to not do this for Version 2.
203 * The first entry is the default error return and the rest are the valid
204 * errors for that RPC in increasing numeric order.
205 */
206 static short nfsv3err_null[] = {
207 0,
208 0,
209 };
210
211 static short nfsv3err_getattr[] = {
212 NFSERR_IO,
213 NFSERR_IO,
214 NFSERR_STALE,
215 NFSERR_BADHANDLE,
216 NFSERR_SERVERFAULT,
217 0,
218 };
219
220 static short nfsv3err_setattr[] = {
221 NFSERR_IO,
222 NFSERR_PERM,
223 NFSERR_IO,
224 NFSERR_ACCES,
225 NFSERR_INVAL,
226 NFSERR_NOSPC,
227 NFSERR_ROFS,
228 NFSERR_DQUOT,
229 NFSERR_STALE,
230 NFSERR_BADHANDLE,
231 NFSERR_NOT_SYNC,
232 NFSERR_SERVERFAULT,
233 0,
234 };
235
236 static short nfsv3err_lookup[] = {
237 NFSERR_IO,
238 NFSERR_NOENT,
239 NFSERR_IO,
240 NFSERR_ACCES,
241 NFSERR_NOTDIR,
242 NFSERR_NAMETOL,
243 NFSERR_STALE,
244 NFSERR_BADHANDLE,
245 NFSERR_SERVERFAULT,
246 0,
247 };
248
249 static short nfsv3err_access[] = {
250 NFSERR_IO,
251 NFSERR_IO,
252 NFSERR_STALE,
253 NFSERR_BADHANDLE,
254 NFSERR_SERVERFAULT,
255 0,
256 };
257
258 static short nfsv3err_readlink[] = {
259 NFSERR_IO,
260 NFSERR_IO,
261 NFSERR_ACCES,
262 NFSERR_INVAL,
263 NFSERR_STALE,
264 NFSERR_BADHANDLE,
265 NFSERR_NOTSUPP,
266 NFSERR_SERVERFAULT,
267 0,
268 };
269
270 static short nfsv3err_read[] = {
271 NFSERR_IO,
272 NFSERR_IO,
273 NFSERR_NXIO,
274 NFSERR_ACCES,
275 NFSERR_INVAL,
276 NFSERR_STALE,
277 NFSERR_BADHANDLE,
278 NFSERR_SERVERFAULT,
279 0,
280 };
281
282 static short nfsv3err_write[] = {
283 NFSERR_IO,
284 NFSERR_IO,
285 NFSERR_ACCES,
286 NFSERR_INVAL,
287 NFSERR_FBIG,
288 NFSERR_NOSPC,
289 NFSERR_ROFS,
290 NFSERR_DQUOT,
291 NFSERR_STALE,
292 NFSERR_BADHANDLE,
293 NFSERR_SERVERFAULT,
294 0,
295 };
296
297 static short nfsv3err_create[] = {
298 NFSERR_IO,
299 NFSERR_IO,
300 NFSERR_ACCES,
301 NFSERR_EXIST,
302 NFSERR_NOTDIR,
303 NFSERR_NOSPC,
304 NFSERR_ROFS,
305 NFSERR_NAMETOL,
306 NFSERR_DQUOT,
307 NFSERR_STALE,
308 NFSERR_BADHANDLE,
309 NFSERR_NOTSUPP,
310 NFSERR_SERVERFAULT,
311 0,
312 };
313
314 static short nfsv3err_mkdir[] = {
315 NFSERR_IO,
316 NFSERR_IO,
317 NFSERR_ACCES,
318 NFSERR_EXIST,
319 NFSERR_NOTDIR,
320 NFSERR_NOSPC,
321 NFSERR_ROFS,
322 NFSERR_NAMETOL,
323 NFSERR_DQUOT,
324 NFSERR_STALE,
325 NFSERR_BADHANDLE,
326 NFSERR_NOTSUPP,
327 NFSERR_SERVERFAULT,
328 0,
329 };
330
331 static short nfsv3err_symlink[] = {
332 NFSERR_IO,
333 NFSERR_IO,
334 NFSERR_ACCES,
335 NFSERR_EXIST,
336 NFSERR_NOTDIR,
337 NFSERR_NOSPC,
338 NFSERR_ROFS,
339 NFSERR_NAMETOL,
340 NFSERR_DQUOT,
341 NFSERR_STALE,
342 NFSERR_BADHANDLE,
343 NFSERR_NOTSUPP,
344 NFSERR_SERVERFAULT,
345 0,
346 };
347
348 static short nfsv3err_mknod[] = {
349 NFSERR_IO,
350 NFSERR_IO,
351 NFSERR_ACCES,
352 NFSERR_EXIST,
353 NFSERR_NOTDIR,
354 NFSERR_NOSPC,
355 NFSERR_ROFS,
356 NFSERR_NAMETOL,
357 NFSERR_DQUOT,
358 NFSERR_STALE,
359 NFSERR_BADHANDLE,
360 NFSERR_NOTSUPP,
361 NFSERR_SERVERFAULT,
362 NFSERR_BADTYPE,
363 0,
364 };
365
366 static short nfsv3err_remove[] = {
367 NFSERR_IO,
368 NFSERR_NOENT,
369 NFSERR_IO,
370 NFSERR_ACCES,
371 NFSERR_NOTDIR,
372 NFSERR_ROFS,
373 NFSERR_NAMETOL,
374 NFSERR_STALE,
375 NFSERR_BADHANDLE,
376 NFSERR_SERVERFAULT,
377 0,
378 };
379
380 static short nfsv3err_rmdir[] = {
381 NFSERR_IO,
382 NFSERR_NOENT,
383 NFSERR_IO,
384 NFSERR_ACCES,
385 NFSERR_EXIST,
386 NFSERR_NOTDIR,
387 NFSERR_INVAL,
388 NFSERR_ROFS,
389 NFSERR_NAMETOL,
390 NFSERR_NOTEMPTY,
391 NFSERR_STALE,
392 NFSERR_BADHANDLE,
393 NFSERR_NOTSUPP,
394 NFSERR_SERVERFAULT,
395 0,
396 };
397
398 static short nfsv3err_rename[] = {
399 NFSERR_IO,
400 NFSERR_NOENT,
401 NFSERR_IO,
402 NFSERR_ACCES,
403 NFSERR_EXIST,
404 NFSERR_XDEV,
405 NFSERR_NOTDIR,
406 NFSERR_ISDIR,
407 NFSERR_INVAL,
408 NFSERR_NOSPC,
409 NFSERR_ROFS,
410 NFSERR_MLINK,
411 NFSERR_NAMETOL,
412 NFSERR_NOTEMPTY,
413 NFSERR_DQUOT,
414 NFSERR_STALE,
415 NFSERR_BADHANDLE,
416 NFSERR_NOTSUPP,
417 NFSERR_SERVERFAULT,
418 0,
419 };
420
421 static short nfsv3err_link[] = {
422 NFSERR_IO,
423 NFSERR_IO,
424 NFSERR_ACCES,
425 NFSERR_EXIST,
426 NFSERR_XDEV,
427 NFSERR_NOTDIR,
428 NFSERR_INVAL,
429 NFSERR_NOSPC,
430 NFSERR_ROFS,
431 NFSERR_MLINK,
432 NFSERR_NAMETOL,
433 NFSERR_DQUOT,
434 NFSERR_STALE,
435 NFSERR_BADHANDLE,
436 NFSERR_NOTSUPP,
437 NFSERR_SERVERFAULT,
438 0,
439 };
440
441 static short nfsv3err_readdir[] = {
442 NFSERR_IO,
443 NFSERR_IO,
444 NFSERR_ACCES,
445 NFSERR_NOTDIR,
446 NFSERR_STALE,
447 NFSERR_BADHANDLE,
448 NFSERR_BAD_COOKIE,
449 NFSERR_TOOSMALL,
450 NFSERR_SERVERFAULT,
451 0,
452 };
453
454 static short nfsv3err_readdirplus[] = {
455 NFSERR_IO,
456 NFSERR_IO,
457 NFSERR_ACCES,
458 NFSERR_NOTDIR,
459 NFSERR_STALE,
460 NFSERR_BADHANDLE,
461 NFSERR_BAD_COOKIE,
462 NFSERR_NOTSUPP,
463 NFSERR_TOOSMALL,
464 NFSERR_SERVERFAULT,
465 0,
466 };
467
468 static short nfsv3err_fsstat[] = {
469 NFSERR_IO,
470 NFSERR_IO,
471 NFSERR_STALE,
472 NFSERR_BADHANDLE,
473 NFSERR_SERVERFAULT,
474 0,
475 };
476
477 static short nfsv3err_fsinfo[] = {
478 NFSERR_STALE,
479 NFSERR_STALE,
480 NFSERR_BADHANDLE,
481 NFSERR_SERVERFAULT,
482 0,
483 };
484
485 static short nfsv3err_pathconf[] = {
486 NFSERR_STALE,
487 NFSERR_STALE,
488 NFSERR_BADHANDLE,
489 NFSERR_SERVERFAULT,
490 0,
491 };
492
493 static short nfsv3err_commit[] = {
494 NFSERR_IO,
495 NFSERR_IO,
496 NFSERR_STALE,
497 NFSERR_BADHANDLE,
498 NFSERR_SERVERFAULT,
499 0,
500 };
501
502 static short *nfsrv_v3errmap[] = {
503 nfsv3err_null,
504 nfsv3err_getattr,
505 nfsv3err_setattr,
506 nfsv3err_lookup,
507 nfsv3err_access,
508 nfsv3err_readlink,
509 nfsv3err_read,
510 nfsv3err_write,
511 nfsv3err_create,
512 nfsv3err_mkdir,
513 nfsv3err_symlink,
514 nfsv3err_mknod,
515 nfsv3err_remove,
516 nfsv3err_rmdir,
517 nfsv3err_rename,
518 nfsv3err_link,
519 nfsv3err_readdir,
520 nfsv3err_readdirplus,
521 nfsv3err_fsstat,
522 nfsv3err_fsinfo,
523 nfsv3err_pathconf,
524 nfsv3err_commit,
525 };
526
527 extern struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON];
528 extern struct nfsrtt nfsrtt;
529 extern struct nfsstats nfsstats;
530 extern nfstype nfsv2_type[9];
531 extern nfstype nfsv3_type[9];
532 extern struct nfsnodehashhead *nfsnodehashtbl;
533 extern u_long nfsnodehash;
534
535 LIST_HEAD(nfsnodehashhead, nfsnode);
536
537 struct pool nfsreqpl;
538
539 /*
540 * Create the header for an rpc request packet
541 * The hsiz is the size of the rest of the nfs request header.
542 * (just used to decide if a cluster is a good idea)
543 */
544 struct mbuf *
nfsm_reqh(vp,procid,hsiz,bposp)545 nfsm_reqh(vp, procid, hsiz, bposp)
546 struct vnode *vp;
547 u_long procid;
548 int hsiz;
549 caddr_t *bposp;
550 {
551 struct mbuf *mb;
552 caddr_t bpos;
553
554 MGET(mb, M_WAIT, MT_DATA);
555 if (hsiz >= MINCLSIZE)
556 MCLGET(mb, M_WAIT);
557 mb->m_len = 0;
558 bpos = mtod(mb, caddr_t);
559
560 /* Finally, return values */
561 *bposp = bpos;
562 return (mb);
563 }
564
565 /*
566 * Build the RPC header and fill in the authorization info.
567 * The authorization string argument is only used when the credentials
568 * come from outside of the kernel.
569 * Returns the head of the mbuf list.
570 */
571 struct mbuf *
nfsm_rpchead(cr,nmflag,procid,auth_type,auth_len,auth_str,verf_len,verf_str,mrest,mrest_len,mbp,xidp)572 nfsm_rpchead(cr, nmflag, procid, auth_type, auth_len, auth_str, verf_len,
573 verf_str, mrest, mrest_len, mbp, xidp)
574 struct ucred *cr;
575 int nmflag;
576 int procid;
577 int auth_type;
578 int auth_len;
579 char *auth_str;
580 int verf_len;
581 char *verf_str;
582 struct mbuf *mrest;
583 int mrest_len;
584 struct mbuf **mbp;
585 u_int32_t *xidp;
586 {
587 struct mbuf *mb;
588 u_int32_t *tl;
589 caddr_t bpos;
590 int i;
591 struct mbuf *mreq, *mb2;
592 int siz, grpsiz, authsiz;
593
594 authsiz = nfsm_rndup(auth_len);
595 MGETHDR(mb, M_WAIT, MT_DATA);
596 if ((authsiz + 10 * NFSX_UNSIGNED) >= MINCLSIZE) {
597 MCLGET(mb, M_WAIT);
598 } else if ((authsiz + 10 * NFSX_UNSIGNED) < MHLEN) {
599 MH_ALIGN(mb, authsiz + 10 * NFSX_UNSIGNED);
600 } else {
601 MH_ALIGN(mb, 8 * NFSX_UNSIGNED);
602 }
603 mb->m_len = 0;
604 mreq = mb;
605 bpos = mtod(mb, caddr_t);
606
607 /*
608 * First the RPC header.
609 */
610 nfsm_build(tl, u_int32_t *, 8 * NFSX_UNSIGNED);
611
612 /* Get a new (non-zero) xid */
613
614 if ((nfs_xid == 0) && (nfs_xid_touched == 0)) {
615 nfs_xid = arc4random();
616 nfs_xid_touched = 1;
617 } else {
618 while ((*xidp = arc4random() % 256) == 0)
619 ;
620 nfs_xid += *xidp;
621 }
622
623 *tl++ = *xidp = txdr_unsigned(nfs_xid);
624 *tl++ = rpc_call;
625 *tl++ = rpc_vers;
626 *tl++ = txdr_unsigned(NFS_PROG);
627 if (nmflag & NFSMNT_NFSV3)
628 *tl++ = txdr_unsigned(NFS_VER3);
629 else
630 *tl++ = txdr_unsigned(NFS_VER2);
631 if (nmflag & NFSMNT_NFSV3)
632 *tl++ = txdr_unsigned(procid);
633 else
634 *tl++ = txdr_unsigned(nfsv2_procid[procid]);
635
636 /*
637 * And then the authorization cred.
638 */
639 *tl++ = txdr_unsigned(auth_type);
640 *tl = txdr_unsigned(authsiz);
641 switch (auth_type) {
642 case RPCAUTH_UNIX:
643 nfsm_build(tl, u_int32_t *, auth_len);
644 *tl++ = 0; /* stamp ?? */
645 *tl++ = 0; /* NULL hostname */
646 *tl++ = txdr_unsigned(cr->cr_uid);
647 *tl++ = txdr_unsigned(cr->cr_gid);
648 grpsiz = (auth_len >> 2) - 5;
649 *tl++ = txdr_unsigned(grpsiz);
650 for (i = 0; i < grpsiz; i++)
651 *tl++ = txdr_unsigned(cr->cr_groups[i]);
652 break;
653 case RPCAUTH_KERB4:
654 siz = auth_len;
655 while (siz > 0) {
656 if (M_TRAILINGSPACE(mb) == 0) {
657 MGET(mb2, M_WAIT, MT_DATA);
658 if (siz >= MINCLSIZE)
659 MCLGET(mb2, M_WAIT);
660 mb->m_next = mb2;
661 mb = mb2;
662 mb->m_len = 0;
663 bpos = mtod(mb, caddr_t);
664 }
665 i = min(siz, M_TRAILINGSPACE(mb));
666 bcopy(auth_str, bpos, i);
667 mb->m_len += i;
668 auth_str += i;
669 bpos += i;
670 siz -= i;
671 }
672 if ((siz = (nfsm_rndup(auth_len) - auth_len)) > 0) {
673 for (i = 0; i < siz; i++)
674 *bpos++ = '\0';
675 mb->m_len += siz;
676 }
677 break;
678 };
679
680 /*
681 * And the verifier...
682 */
683 nfsm_build(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
684 if (verf_str) {
685 *tl++ = txdr_unsigned(RPCAUTH_KERB4);
686 *tl = txdr_unsigned(verf_len);
687 siz = verf_len;
688 while (siz > 0) {
689 if (M_TRAILINGSPACE(mb) == 0) {
690 MGET(mb2, M_WAIT, MT_DATA);
691 if (siz >= MINCLSIZE)
692 MCLGET(mb2, M_WAIT);
693 mb->m_next = mb2;
694 mb = mb2;
695 mb->m_len = 0;
696 bpos = mtod(mb, caddr_t);
697 }
698 i = min(siz, M_TRAILINGSPACE(mb));
699 bcopy(verf_str, bpos, i);
700 mb->m_len += i;
701 verf_str += i;
702 bpos += i;
703 siz -= i;
704 }
705 if ((siz = (nfsm_rndup(verf_len) - verf_len)) > 0) {
706 for (i = 0; i < siz; i++)
707 *bpos++ = '\0';
708 mb->m_len += siz;
709 }
710 } else {
711 *tl++ = txdr_unsigned(RPCAUTH_NULL);
712 *tl = 0;
713 }
714 mb->m_next = mrest;
715 mreq->m_pkthdr.len = authsiz + 10 * NFSX_UNSIGNED + mrest_len;
716 mreq->m_pkthdr.rcvif = (struct ifnet *)0;
717 *mbp = mb;
718 return (mreq);
719 }
720
721 /*
722 * copies mbuf chain to the uio scatter/gather list
723 */
724 int
nfsm_mbuftouio(mrep,uiop,siz,dpos)725 nfsm_mbuftouio(mrep, uiop, siz, dpos)
726 struct mbuf **mrep;
727 struct uio *uiop;
728 int siz;
729 caddr_t *dpos;
730 {
731 char *mbufcp, *uiocp;
732 int xfer, left, len;
733 struct mbuf *mp;
734 long uiosiz, rem;
735 int error = 0;
736
737 mp = *mrep;
738 mbufcp = *dpos;
739 len = mtod(mp, caddr_t)+mp->m_len-mbufcp;
740 rem = nfsm_rndup(siz)-siz;
741 while (siz > 0) {
742 if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL)
743 return (EFBIG);
744 left = uiop->uio_iov->iov_len;
745 uiocp = uiop->uio_iov->iov_base;
746 if (left > siz)
747 left = siz;
748 uiosiz = left;
749 while (left > 0) {
750 while (len == 0) {
751 mp = mp->m_next;
752 if (mp == NULL)
753 return (EBADRPC);
754 mbufcp = mtod(mp, caddr_t);
755 len = mp->m_len;
756 }
757 xfer = (left > len) ? len : left;
758 #ifdef notdef
759 /* Not Yet.. */
760 if (uiop->uio_iov->iov_op != NULL)
761 (*(uiop->uio_iov->iov_op))
762 (mbufcp, uiocp, xfer);
763 else
764 #endif
765 if (uiop->uio_segflg == UIO_SYSSPACE)
766 bcopy(mbufcp, uiocp, xfer);
767 else
768 copyout(mbufcp, uiocp, xfer);
769 left -= xfer;
770 len -= xfer;
771 mbufcp += xfer;
772 uiocp += xfer;
773 uiop->uio_offset += xfer;
774 uiop->uio_resid -= xfer;
775 }
776 if (uiop->uio_iov->iov_len <= siz) {
777 uiop->uio_iovcnt--;
778 uiop->uio_iov++;
779 } else {
780 uiop->uio_iov->iov_base += uiosiz;
781 uiop->uio_iov->iov_len -= uiosiz;
782 }
783 siz -= uiosiz;
784 }
785 *dpos = mbufcp;
786 *mrep = mp;
787 if (rem > 0) {
788 if (len < rem)
789 error = nfs_adv(mrep, dpos, rem, len);
790 else
791 *dpos += rem;
792 }
793 return (error);
794 }
795
796 /*
797 * copies a uio scatter/gather list to an mbuf chain.
798 * NOTE: can ony handle iovcnt == 1
799 */
800 int
nfsm_uiotombuf(uiop,mq,siz,bpos)801 nfsm_uiotombuf(uiop, mq, siz, bpos)
802 struct uio *uiop;
803 struct mbuf **mq;
804 int siz;
805 caddr_t *bpos;
806 {
807 char *uiocp;
808 struct mbuf *mp, *mp2;
809 int xfer, left, mlen;
810 int uiosiz, clflg, rem;
811 char *cp;
812
813 #ifdef DIAGNOSTIC
814 if (uiop->uio_iovcnt != 1)
815 panic("nfsm_uiotombuf: iovcnt != 1");
816 #endif
817
818 if (siz > MLEN) /* or should it >= MCLBYTES ?? */
819 clflg = 1;
820 else
821 clflg = 0;
822 rem = nfsm_rndup(siz)-siz;
823 mp = mp2 = *mq;
824 while (siz > 0) {
825 left = uiop->uio_iov->iov_len;
826 uiocp = uiop->uio_iov->iov_base;
827 if (left > siz)
828 left = siz;
829 uiosiz = left;
830 while (left > 0) {
831 mlen = M_TRAILINGSPACE(mp);
832 if (mlen == 0) {
833 MGET(mp, M_WAIT, MT_DATA);
834 if (clflg)
835 MCLGET(mp, M_WAIT);
836 mp->m_len = 0;
837 mp2->m_next = mp;
838 mp2 = mp;
839 mlen = M_TRAILINGSPACE(mp);
840 }
841 xfer = (left > mlen) ? mlen : left;
842 #ifdef notdef
843 /* Not Yet.. */
844 if (uiop->uio_iov->iov_op != NULL)
845 (*(uiop->uio_iov->iov_op))
846 (uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
847 else
848 #endif
849 if (uiop->uio_segflg == UIO_SYSSPACE)
850 bcopy(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
851 else
852 copyin(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
853 mp->m_len += xfer;
854 left -= xfer;
855 uiocp += xfer;
856 uiop->uio_offset += xfer;
857 uiop->uio_resid -= xfer;
858 }
859 uiop->uio_iov->iov_base += uiosiz;
860 uiop->uio_iov->iov_len -= uiosiz;
861 siz -= uiosiz;
862 }
863 if (rem > 0) {
864 if (rem > M_TRAILINGSPACE(mp)) {
865 MGET(mp, M_WAIT, MT_DATA);
866 mp->m_len = 0;
867 mp2->m_next = mp;
868 }
869 cp = mtod(mp, caddr_t)+mp->m_len;
870 for (left = 0; left < rem; left++)
871 *cp++ = '\0';
872 mp->m_len += rem;
873 *bpos = cp;
874 } else
875 *bpos = mtod(mp, caddr_t)+mp->m_len;
876 *mq = mp;
877 return (0);
878 }
879
880 /*
881 * Help break down an mbuf chain by setting the first siz bytes contiguous
882 * pointed to by returned val.
883 * This is used by the macros nfsm_dissect and nfsm_dissecton for tough
884 * cases. (The macros use the vars. dpos and dpos2)
885 */
886 int
nfsm_disct(mdp,dposp,siz,left,cp2)887 nfsm_disct(mdp, dposp, siz, left, cp2)
888 struct mbuf **mdp;
889 caddr_t *dposp;
890 int siz;
891 int left;
892 caddr_t *cp2;
893 {
894 struct mbuf *mp, *mp2;
895 int siz2, xfer;
896 caddr_t p;
897
898 mp = *mdp;
899 while (left == 0) {
900 *mdp = mp = mp->m_next;
901 if (mp == NULL)
902 return (EBADRPC);
903 left = mp->m_len;
904 *dposp = mtod(mp, caddr_t);
905 }
906 if (left >= siz) {
907 *cp2 = *dposp;
908 *dposp += siz;
909 } else if (mp->m_next == NULL) {
910 return (EBADRPC);
911 } else if (siz > MHLEN) {
912 panic("nfs S too big");
913 } else {
914 MGET(mp2, M_WAIT, MT_DATA);
915 mp2->m_next = mp->m_next;
916 mp->m_next = mp2;
917 mp->m_len -= left;
918 mp = mp2;
919 *cp2 = p = mtod(mp, caddr_t);
920 bcopy(*dposp, p, left); /* Copy what was left */
921 siz2 = siz-left;
922 p += left;
923 mp2 = mp->m_next;
924 /* Loop around copying up the siz2 bytes */
925 while (siz2 > 0) {
926 if (mp2 == NULL)
927 return (EBADRPC);
928 xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2;
929 if (xfer > 0) {
930 bcopy(mtod(mp2, caddr_t), p, xfer);
931 NFSMADV(mp2, xfer);
932 mp2->m_len -= xfer;
933 p += xfer;
934 siz2 -= xfer;
935 }
936 if (siz2 > 0)
937 mp2 = mp2->m_next;
938 }
939 mp->m_len = siz;
940 *mdp = mp2;
941 *dposp = mtod(mp2, caddr_t);
942 }
943 return (0);
944 }
945
946 /*
947 * Advance the position in the mbuf chain.
948 */
949 int
nfs_adv(mdp,dposp,offs,left)950 nfs_adv(mdp, dposp, offs, left)
951 struct mbuf **mdp;
952 caddr_t *dposp;
953 int offs;
954 int left;
955 {
956 struct mbuf *m;
957 int s;
958
959 m = *mdp;
960 s = left;
961 while (s < offs) {
962 offs -= s;
963 m = m->m_next;
964 if (m == NULL)
965 return (EBADRPC);
966 s = m->m_len;
967 }
968 *mdp = m;
969 *dposp = mtod(m, caddr_t)+offs;
970 return (0);
971 }
972
973 /*
974 * Copy a string into mbufs for the hard cases...
975 */
976 int
nfsm_strtmbuf(mb,bpos,cp,siz)977 nfsm_strtmbuf(mb, bpos, cp, siz)
978 struct mbuf **mb;
979 char **bpos;
980 char *cp;
981 long siz;
982 {
983 struct mbuf *m1 = NULL, *m2;
984 long left, xfer, len, tlen;
985 u_int32_t *tl;
986 int putsize;
987
988 putsize = 1;
989 m2 = *mb;
990 left = M_TRAILINGSPACE(m2);
991 if (left > 0) {
992 tl = ((u_int32_t *)(*bpos));
993 *tl++ = txdr_unsigned(siz);
994 putsize = 0;
995 left -= NFSX_UNSIGNED;
996 m2->m_len += NFSX_UNSIGNED;
997 if (left > 0) {
998 bcopy(cp, (caddr_t) tl, left);
999 siz -= left;
1000 cp += left;
1001 m2->m_len += left;
1002 left = 0;
1003 }
1004 }
1005 /* Loop around adding mbufs */
1006 while (siz > 0) {
1007 MGET(m1, M_WAIT, MT_DATA);
1008 if (siz > MLEN)
1009 MCLGET(m1, M_WAIT);
1010 m1->m_len = NFSMSIZ(m1);
1011 m2->m_next = m1;
1012 m2 = m1;
1013 tl = mtod(m1, u_int32_t *);
1014 tlen = 0;
1015 if (putsize) {
1016 *tl++ = txdr_unsigned(siz);
1017 m1->m_len -= NFSX_UNSIGNED;
1018 tlen = NFSX_UNSIGNED;
1019 putsize = 0;
1020 }
1021 if (siz < m1->m_len) {
1022 len = nfsm_rndup(siz);
1023 xfer = siz;
1024 if (xfer < len)
1025 *(tl+(xfer>>2)) = 0;
1026 } else {
1027 xfer = len = m1->m_len;
1028 }
1029 bcopy(cp, (caddr_t) tl, xfer);
1030 m1->m_len = len+tlen;
1031 siz -= xfer;
1032 cp += xfer;
1033 }
1034 *mb = m1;
1035 *bpos = mtod(m1, caddr_t)+m1->m_len;
1036 return (0);
1037 }
1038
1039 /*
1040 * Called once to initialize data structures...
1041 */
1042 void
nfs_init()1043 nfs_init()
1044 {
1045 static struct timeout nfs_timer_to;
1046
1047 nfsrtt.pos = 0;
1048 rpc_vers = txdr_unsigned(RPC_VER2);
1049 rpc_call = txdr_unsigned(RPC_CALL);
1050 rpc_reply = txdr_unsigned(RPC_REPLY);
1051 rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED);
1052 rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED);
1053 rpc_mismatch = txdr_unsigned(RPC_MISMATCH);
1054 rpc_autherr = txdr_unsigned(RPC_AUTHERR);
1055 rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX);
1056 rpc_auth_kerb = txdr_unsigned(RPCAUTH_KERB4);
1057 nfs_prog = txdr_unsigned(NFS_PROG);
1058 nfs_true = txdr_unsigned(TRUE);
1059 nfs_false = txdr_unsigned(FALSE);
1060 nfs_xdrneg1 = txdr_unsigned(-1);
1061 nfs_ticks = (hz * NFS_TICKINTVL + 500) / 1000;
1062 if (nfs_ticks < 1)
1063 nfs_ticks = 1;
1064 #ifdef NFSSERVER
1065 nfsrv_init(0); /* Init server data structures */
1066 nfsrv_initcache(); /* Init the server request cache */
1067 #endif /* NFSSERVER */
1068
1069 pool_init(&nfsreqpl, sizeof(struct nfsreq), 0, 0, 0, "nfsreqpl",
1070 &pool_allocator_nointr);
1071
1072 /*
1073 * Initialize reply list and start timer
1074 */
1075 TAILQ_INIT(&nfs_reqq);
1076
1077 timeout_set(&nfs_timer_to, nfs_timer, &nfs_timer_to);
1078 nfs_timer(&nfs_timer_to);
1079
1080 #ifdef NFSCLIENT
1081 nfs_kqinit();
1082 #endif
1083 }
1084
1085 #ifdef NFSCLIENT
1086 int
nfs_vfs_init(vfsp)1087 nfs_vfs_init(vfsp)
1088 struct vfsconf *vfsp;
1089 {
1090 int i;
1091
1092 /* Ensure async daemons disabled */
1093 for (i = 0; i < NFS_MAXASYNCDAEMON; i++)
1094 nfs_iodwant[i] = (struct proc *)0;
1095 TAILQ_INIT(&nfs_bufq);
1096 nfs_nhinit(); /* Init the nfsnode table */
1097
1098 return (0);
1099 }
1100
1101 /*
1102 * Attribute cache routines.
1103 * nfs_loadattrcache() - loads or updates the cache contents from attributes
1104 * that are on the mbuf list
1105 * nfs_getattrcache() - returns valid attributes if found in cache, returns
1106 * error otherwise
1107 */
1108
1109 /*
1110 * Load the attribute cache (that lives in the nfsnode entry) with
1111 * the values on the mbuf list and
1112 * Iff vap not NULL
1113 * copy the attributes to *vaper
1114 */
1115 int
nfs_loadattrcache(vpp,mdp,dposp,vaper)1116 nfs_loadattrcache(vpp, mdp, dposp, vaper)
1117 struct vnode **vpp;
1118 struct mbuf **mdp;
1119 caddr_t *dposp;
1120 struct vattr *vaper;
1121 {
1122 struct vnode *vp = *vpp;
1123 struct vattr *vap;
1124 struct nfs_fattr *fp;
1125 extern int (**spec_nfsv2nodeop_p)(void *);
1126 struct nfsnode *np;
1127 int32_t t1;
1128 caddr_t cp2;
1129 int error = 0;
1130 int32_t rdev;
1131 struct mbuf *md;
1132 enum vtype vtyp;
1133 mode_t vmode;
1134 struct timespec mtime;
1135 struct vnode *nvp;
1136 int v3 = NFS_ISV3(vp);
1137
1138 md = *mdp;
1139 t1 = (mtod(md, caddr_t) + md->m_len) - *dposp;
1140 error = nfsm_disct(mdp, dposp, NFSX_FATTR(v3), t1, &cp2);
1141 if (error)
1142 return (error);
1143 fp = (struct nfs_fattr *)cp2;
1144 if (v3) {
1145 vtyp = nfsv3tov_type(fp->fa_type);
1146 vmode = fxdr_unsigned(mode_t, fp->fa_mode);
1147 rdev = makedev(fxdr_unsigned(u_int32_t, fp->fa3_rdev.specdata1),
1148 fxdr_unsigned(u_int32_t, fp->fa3_rdev.specdata2));
1149 fxdr_nfsv3time(&fp->fa3_mtime, &mtime);
1150 } else {
1151 vtyp = nfsv2tov_type(fp->fa_type);
1152 vmode = fxdr_unsigned(mode_t, fp->fa_mode);
1153 if (vtyp == VNON || vtyp == VREG)
1154 vtyp = IFTOVT(vmode);
1155 rdev = fxdr_unsigned(int32_t, fp->fa2_rdev);
1156 fxdr_nfsv2time(&fp->fa2_mtime, &mtime);
1157
1158 /*
1159 * Really ugly NFSv2 kludge.
1160 */
1161 if (vtyp == VCHR && rdev == 0xffffffff)
1162 vtyp = VFIFO;
1163 }
1164
1165 /*
1166 * If v_type == VNON it is a new node, so fill in the v_type,
1167 * n_mtime fields. Check to see if it represents a special
1168 * device, and if so, check for a possible alias. Once the
1169 * correct vnode has been obtained, fill in the rest of the
1170 * information.
1171 */
1172 np = VTONFS(vp);
1173 if (vp->v_type != vtyp) {
1174 vp->v_type = vtyp;
1175 if (vp->v_type == VFIFO) {
1176 #ifndef FIFO
1177 return (EOPNOTSUPP);
1178 #else
1179 extern int (**fifo_nfsv2nodeop_p)(void *);
1180 vp->v_op = fifo_nfsv2nodeop_p;
1181 #endif /* FIFO */
1182 }
1183 if (vp->v_type == VCHR || vp->v_type == VBLK) {
1184 vp->v_op = spec_nfsv2nodeop_p;
1185 nvp = checkalias(vp, (dev_t)rdev, vp->v_mount);
1186 if (nvp) {
1187 /*
1188 * Discard unneeded vnode, but save its nfsnode.
1189 * Since the nfsnode does not have a lock, its
1190 * vnode lock has to be carried over.
1191 */
1192
1193 nvp->v_vnlock = vp->v_vnlock;
1194 vp->v_vnlock = NULL;
1195 nvp->v_data = vp->v_data;
1196 vp->v_data = NULL;
1197 vp->v_op = spec_vnodeop_p;
1198 vrele(vp);
1199 vgone(vp);
1200 /*
1201 * Reinitialize aliased node.
1202 */
1203 np->n_vnode = nvp;
1204 *vpp = vp = nvp;
1205 }
1206 }
1207 np->n_mtime = mtime.tv_sec;
1208 }
1209 vap = &np->n_vattr;
1210 vap->va_type = vtyp;
1211 vap->va_mode = (vmode & 07777);
1212 vap->va_rdev = (dev_t)rdev;
1213 vap->va_mtime = mtime;
1214 vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0];
1215 if (v3) {
1216 vap->va_nlink = fxdr_unsigned(nlink_t, fp->fa_nlink);
1217 vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid);
1218 vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid);
1219 vap->va_size = fxdr_hyper(&fp->fa3_size);
1220 vap->va_blocksize = NFS_FABLKSIZE;
1221 vap->va_bytes = fxdr_hyper(&fp->fa3_used);
1222 vap->va_fileid = fxdr_unsigned(int32_t,
1223 fp->fa3_fileid.nfsuquad[1]);
1224 fxdr_nfsv3time(&fp->fa3_atime, &vap->va_atime);
1225 fxdr_nfsv3time(&fp->fa3_ctime, &vap->va_ctime);
1226 vap->va_flags = 0;
1227 vap->va_filerev = 0;
1228 } else {
1229 vap->va_nlink = fxdr_unsigned(nlink_t, fp->fa_nlink);
1230 vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid);
1231 vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid);
1232 vap->va_size = fxdr_unsigned(u_int32_t, fp->fa2_size);
1233 vap->va_blocksize = fxdr_unsigned(int32_t, fp->fa2_blocksize);
1234 vap->va_bytes =
1235 (u_quad_t)fxdr_unsigned(int32_t, fp->fa2_blocks) *
1236 NFS_FABLKSIZE;
1237 vap->va_fileid = fxdr_unsigned(int32_t, fp->fa2_fileid);
1238 fxdr_nfsv2time(&fp->fa2_atime, &vap->va_atime);
1239 vap->va_flags = 0;
1240 vap->va_ctime.tv_sec = fxdr_unsigned(u_int32_t,
1241 fp->fa2_ctime.nfsv2_sec);
1242 vap->va_ctime.tv_nsec = 0;
1243 vap->va_gen = fxdr_unsigned(u_int32_t,fp->fa2_ctime.nfsv2_usec);
1244 vap->va_filerev = 0;
1245 }
1246 if (vap->va_size != np->n_size) {
1247 if (vap->va_type == VREG) {
1248 if (np->n_flag & NMODIFIED) {
1249 if (vap->va_size < np->n_size)
1250 vap->va_size = np->n_size;
1251 else
1252 np->n_size = vap->va_size;
1253 } else
1254 np->n_size = vap->va_size;
1255 uvm_vnp_setsize(vp, np->n_size);
1256 } else
1257 np->n_size = vap->va_size;
1258 }
1259 np->n_attrstamp = time.tv_sec;
1260 if (vaper != NULL) {
1261 bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(*vap));
1262 if (np->n_flag & NCHG) {
1263 if (np->n_flag & NACC)
1264 vaper->va_atime = np->n_atim;
1265 if (np->n_flag & NUPD)
1266 vaper->va_mtime = np->n_mtim;
1267 }
1268 }
1269 return (0);
1270 }
1271
1272 INLINE int
nfs_attrtimeo(np)1273 nfs_attrtimeo (np)
1274 struct nfsnode *np;
1275 {
1276 struct vnode *vp = np->n_vnode;
1277 struct nfsmount *nmp = VFSTONFS(vp->v_mount);
1278 int tenthage = (time.tv_sec - np->n_mtime) / 10;
1279 int minto, maxto;
1280
1281 if (vp->v_type == VDIR) {
1282 maxto = nmp->nm_acdirmax;
1283 minto = nmp->nm_acdirmin;
1284 }
1285 else {
1286 maxto = nmp->nm_acregmax;
1287 minto = nmp->nm_acregmin;
1288 }
1289
1290 if (np->n_flag & NMODIFIED || tenthage < minto)
1291 return minto;
1292 else if (tenthage < maxto)
1293 return tenthage;
1294 else
1295 return maxto;
1296 }
1297
1298 /*
1299 * Check the time stamp
1300 * If the cache is valid, copy contents to *vap and return 0
1301 * otherwise return an error
1302 */
1303 int
nfs_getattrcache(vp,vaper)1304 nfs_getattrcache(vp, vaper)
1305 struct vnode *vp;
1306 struct vattr *vaper;
1307 {
1308 struct nfsnode *np = VTONFS(vp);
1309 struct vattr *vap;
1310
1311 if (np->n_attrstamp == 0 ||
1312 (time.tv_sec - np->n_attrstamp) >= nfs_attrtimeo(np)) {
1313 nfsstats.attrcache_misses++;
1314 return (ENOENT);
1315 }
1316 nfsstats.attrcache_hits++;
1317 vap = &np->n_vattr;
1318 if (vap->va_size != np->n_size) {
1319 if (vap->va_type == VREG) {
1320 if (np->n_flag & NMODIFIED) {
1321 if (vap->va_size < np->n_size)
1322 vap->va_size = np->n_size;
1323 else
1324 np->n_size = vap->va_size;
1325 } else
1326 np->n_size = vap->va_size;
1327 uvm_vnp_setsize(vp, np->n_size);
1328 } else
1329 np->n_size = vap->va_size;
1330 }
1331 bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(struct vattr));
1332 if (np->n_flag & NCHG) {
1333 if (np->n_flag & NACC)
1334 vaper->va_atime = np->n_atim;
1335 if (np->n_flag & NUPD)
1336 vaper->va_mtime = np->n_mtim;
1337 }
1338 return (0);
1339 }
1340 #endif /* NFSCLIENT */
1341
1342 /*
1343 * Set up nameidata for a lookup() call and do it
1344 */
1345 int
nfs_namei(ndp,fhp,len,slp,nam,mdp,dposp,retdirp,p,kerbflag)1346 nfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, retdirp, p, kerbflag)
1347 struct nameidata *ndp;
1348 fhandle_t *fhp;
1349 int len;
1350 struct nfssvc_sock *slp;
1351 struct mbuf *nam;
1352 struct mbuf **mdp;
1353 caddr_t *dposp;
1354 struct vnode **retdirp;
1355 struct proc *p;
1356 int kerbflag;
1357 {
1358 int i, rem;
1359 struct mbuf *md;
1360 char *fromcp, *tocp;
1361 struct vnode *dp;
1362 int error, rdonly;
1363 struct componentname *cnp = &ndp->ni_cnd;
1364
1365 *retdirp = (struct vnode *)0;
1366 cnp->cn_pnbuf = pool_get(&namei_pool, PR_WAITOK);
1367 /*
1368 * Copy the name from the mbuf list to ndp->ni_pnbuf
1369 * and set the various ndp fields appropriately.
1370 */
1371 fromcp = *dposp;
1372 tocp = cnp->cn_pnbuf;
1373 md = *mdp;
1374 rem = mtod(md, caddr_t) + md->m_len - fromcp;
1375 cnp->cn_hash = 0;
1376 for (i = 0; i < len; i++) {
1377 while (rem == 0) {
1378 md = md->m_next;
1379 if (md == NULL) {
1380 error = EBADRPC;
1381 goto out;
1382 }
1383 fromcp = mtod(md, caddr_t);
1384 rem = md->m_len;
1385 }
1386 if (*fromcp == '\0' || *fromcp == '/') {
1387 error = EACCES;
1388 goto out;
1389 }
1390 cnp->cn_hash += (u_char)*fromcp;
1391 *tocp++ = *fromcp++;
1392 rem--;
1393 }
1394 *tocp = '\0';
1395 *mdp = md;
1396 *dposp = fromcp;
1397 len = nfsm_rndup(len)-len;
1398 if (len > 0) {
1399 if (rem >= len)
1400 *dposp += len;
1401 else if ((error = nfs_adv(mdp, dposp, len, rem)) != 0)
1402 goto out;
1403 }
1404 ndp->ni_pathlen = tocp - cnp->cn_pnbuf;
1405 cnp->cn_nameptr = cnp->cn_pnbuf;
1406 /*
1407 * Extract and set starting directory.
1408 */
1409 error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cnd.cn_cred, slp,
1410 nam, &rdonly, kerbflag);
1411 if (error)
1412 goto out;
1413 if (dp->v_type != VDIR) {
1414 vrele(dp);
1415 error = ENOTDIR;
1416 goto out;
1417 }
1418 VREF(dp);
1419 *retdirp = dp;
1420 ndp->ni_startdir = dp;
1421 if (rdonly)
1422 cnp->cn_flags |= (NOCROSSMOUNT | RDONLY);
1423 else
1424 cnp->cn_flags |= NOCROSSMOUNT;
1425 /*
1426 * And call lookup() to do the real work
1427 */
1428 cnp->cn_proc = p;
1429 error = lookup(ndp);
1430 if (error)
1431 goto out;
1432 /*
1433 * Check for encountering a symbolic link
1434 */
1435 if (cnp->cn_flags & ISSYMLINK) {
1436 if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1)
1437 vput(ndp->ni_dvp);
1438 else
1439 vrele(ndp->ni_dvp);
1440 vput(ndp->ni_vp);
1441 ndp->ni_vp = NULL;
1442 error = EINVAL;
1443 goto out;
1444 }
1445 /*
1446 * Check for saved name request
1447 */
1448 if (cnp->cn_flags & (SAVENAME | SAVESTART)) {
1449 cnp->cn_flags |= HASBUF;
1450 return (0);
1451 }
1452 out:
1453 pool_put(&namei_pool, cnp->cn_pnbuf);
1454 return (error);
1455 }
1456
1457 /*
1458 * A fiddled version of m_adj() that ensures null fill to a long
1459 * boundary and only trims off the back end
1460 */
1461 void
nfsm_adj(mp,len,nul)1462 nfsm_adj(mp, len, nul)
1463 struct mbuf *mp;
1464 int len;
1465 int nul;
1466 {
1467 struct mbuf *m;
1468 int count, i;
1469 char *cp;
1470
1471 /*
1472 * Trim from tail. Scan the mbuf chain,
1473 * calculating its length and finding the last mbuf.
1474 * If the adjustment only affects this mbuf, then just
1475 * adjust and return. Otherwise, rescan and truncate
1476 * after the remaining size.
1477 */
1478 count = 0;
1479 m = mp;
1480 for (;;) {
1481 count += m->m_len;
1482 if (m->m_next == (struct mbuf *)0)
1483 break;
1484 m = m->m_next;
1485 }
1486 if (m->m_len > len) {
1487 m->m_len -= len;
1488 if (nul > 0) {
1489 cp = mtod(m, caddr_t)+m->m_len-nul;
1490 for (i = 0; i < nul; i++)
1491 *cp++ = '\0';
1492 }
1493 return;
1494 }
1495 count -= len;
1496 if (count < 0)
1497 count = 0;
1498 /*
1499 * Correct length for chain is "count".
1500 * Find the mbuf with last data, adjust its length,
1501 * and toss data from remaining mbufs on chain.
1502 */
1503 for (m = mp; m; m = m->m_next) {
1504 if (m->m_len >= count) {
1505 m->m_len = count;
1506 if (nul > 0) {
1507 cp = mtod(m, caddr_t)+m->m_len-nul;
1508 for (i = 0; i < nul; i++)
1509 *cp++ = '\0';
1510 }
1511 break;
1512 }
1513 count -= m->m_len;
1514 }
1515 for (m = m->m_next;m;m = m->m_next)
1516 m->m_len = 0;
1517 }
1518
1519 /*
1520 * Make these functions instead of macros, so that the kernel text size
1521 * doesn't get too big...
1522 */
1523 void
nfsm_srvwcc(nfsd,before_ret,before_vap,after_ret,after_vap,mbp,bposp)1524 nfsm_srvwcc(nfsd, before_ret, before_vap, after_ret, after_vap, mbp, bposp)
1525 struct nfsrv_descript *nfsd;
1526 int before_ret;
1527 struct vattr *before_vap;
1528 int after_ret;
1529 struct vattr *after_vap;
1530 struct mbuf **mbp;
1531 char **bposp;
1532 {
1533 struct mbuf *mb = *mbp, *mb2;
1534 char *bpos = *bposp;
1535 u_int32_t *tl;
1536
1537 if (before_ret) {
1538 nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED);
1539 *tl = nfs_false;
1540 } else {
1541 nfsm_build(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
1542 *tl++ = nfs_true;
1543 txdr_hyper(before_vap->va_size, tl);
1544 tl += 2;
1545 txdr_nfsv3time(&(before_vap->va_mtime), tl);
1546 tl += 2;
1547 txdr_nfsv3time(&(before_vap->va_ctime), tl);
1548 }
1549 *bposp = bpos;
1550 *mbp = mb;
1551 nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp);
1552 }
1553
1554 void
nfsm_srvpostopattr(nfsd,after_ret,after_vap,mbp,bposp)1555 nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp)
1556 struct nfsrv_descript *nfsd;
1557 int after_ret;
1558 struct vattr *after_vap;
1559 struct mbuf **mbp;
1560 char **bposp;
1561 {
1562 struct mbuf *mb = *mbp, *mb2;
1563 char *bpos = *bposp;
1564 u_int32_t *tl;
1565 struct nfs_fattr *fp;
1566
1567 if (after_ret) {
1568 nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED);
1569 *tl = nfs_false;
1570 } else {
1571 nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_V3FATTR);
1572 *tl++ = nfs_true;
1573 fp = (struct nfs_fattr *)tl;
1574 nfsm_srvfattr(nfsd, after_vap, fp);
1575 }
1576 *mbp = mb;
1577 *bposp = bpos;
1578 }
1579
1580 void
nfsm_srvfattr(nfsd,vap,fp)1581 nfsm_srvfattr(nfsd, vap, fp)
1582 struct nfsrv_descript *nfsd;
1583 struct vattr *vap;
1584 struct nfs_fattr *fp;
1585 {
1586
1587 fp->fa_nlink = txdr_unsigned(vap->va_nlink);
1588 fp->fa_uid = txdr_unsigned(vap->va_uid);
1589 fp->fa_gid = txdr_unsigned(vap->va_gid);
1590 if (nfsd->nd_flag & ND_NFSV3) {
1591 fp->fa_type = vtonfsv3_type(vap->va_type);
1592 fp->fa_mode = vtonfsv3_mode(vap->va_mode);
1593 txdr_hyper(vap->va_size, &fp->fa3_size);
1594 txdr_hyper(vap->va_bytes, &fp->fa3_used);
1595 fp->fa3_rdev.specdata1 = txdr_unsigned(major(vap->va_rdev));
1596 fp->fa3_rdev.specdata2 = txdr_unsigned(minor(vap->va_rdev));
1597 fp->fa3_fsid.nfsuquad[0] = 0;
1598 fp->fa3_fsid.nfsuquad[1] = txdr_unsigned(vap->va_fsid);
1599 fp->fa3_fileid.nfsuquad[0] = 0;
1600 fp->fa3_fileid.nfsuquad[1] = txdr_unsigned(vap->va_fileid);
1601 txdr_nfsv3time(&vap->va_atime, &fp->fa3_atime);
1602 txdr_nfsv3time(&vap->va_mtime, &fp->fa3_mtime);
1603 txdr_nfsv3time(&vap->va_ctime, &fp->fa3_ctime);
1604 } else {
1605 fp->fa_type = vtonfsv2_type(vap->va_type);
1606 fp->fa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode);
1607 fp->fa2_size = txdr_unsigned(vap->va_size);
1608 fp->fa2_blocksize = txdr_unsigned(vap->va_blocksize);
1609 if (vap->va_type == VFIFO)
1610 fp->fa2_rdev = 0xffffffff;
1611 else
1612 fp->fa2_rdev = txdr_unsigned(vap->va_rdev);
1613 fp->fa2_blocks = txdr_unsigned(vap->va_bytes / NFS_FABLKSIZE);
1614 fp->fa2_fsid = txdr_unsigned(vap->va_fsid);
1615 fp->fa2_fileid = txdr_unsigned(vap->va_fileid);
1616 txdr_nfsv2time(&vap->va_atime, &fp->fa2_atime);
1617 txdr_nfsv2time(&vap->va_mtime, &fp->fa2_mtime);
1618 txdr_nfsv2time(&vap->va_ctime, &fp->fa2_ctime);
1619 }
1620 }
1621
1622 /*
1623 * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked)
1624 * - look up fsid in mount list (if not found ret error)
1625 * - get vp and export rights by calling VFS_FHTOVP() and VFS_CHECKEXP()
1626 * - if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon
1627 * - if not lockflag unlock it with VOP_UNLOCK()
1628 */
1629 int
nfsrv_fhtovp(fhp,lockflag,vpp,cred,slp,nam,rdonlyp,kerbflag)1630 nfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp, kerbflag)
1631 fhandle_t *fhp;
1632 int lockflag;
1633 struct vnode **vpp;
1634 struct ucred *cred;
1635 struct nfssvc_sock *slp;
1636 struct mbuf *nam;
1637 int *rdonlyp;
1638 int kerbflag;
1639 {
1640 struct proc *p = curproc; /* XXX */
1641 struct mount *mp;
1642 int i;
1643 struct ucred *credanon;
1644 int error, exflags;
1645 struct sockaddr_in *saddr;
1646
1647 *vpp = (struct vnode *)0;
1648 mp = vfs_getvfs(&fhp->fh_fsid);
1649
1650 if (!mp)
1651 return (ESTALE);
1652 error = VFS_CHECKEXP(mp, nam, &exflags, &credanon);
1653 if (error)
1654 return (error);
1655 error = VFS_FHTOVP(mp, &fhp->fh_fid, vpp);
1656 if (error)
1657 return (error);
1658
1659 saddr = mtod(nam, struct sockaddr_in *);
1660 if (saddr->sin_family == AF_INET &&
1661 (ntohs(saddr->sin_port) >= IPPORT_RESERVED ||
1662 (slp->ns_so->so_type == SOCK_STREAM && ntohs(saddr->sin_port) == 20))) {
1663 vput(*vpp);
1664 return (NFSERR_AUTHERR | AUTH_TOOWEAK);
1665 }
1666
1667 /*
1668 * Check/setup credentials.
1669 */
1670 if (exflags & MNT_EXKERB) {
1671 if (!kerbflag) {
1672 vput(*vpp);
1673 return (NFSERR_AUTHERR | AUTH_TOOWEAK);
1674 }
1675 } else if (kerbflag) {
1676 vput(*vpp);
1677 return (NFSERR_AUTHERR | AUTH_TOOWEAK);
1678 } else if (cred->cr_uid == 0 || (exflags & MNT_EXPORTANON)) {
1679 cred->cr_uid = credanon->cr_uid;
1680 cred->cr_gid = credanon->cr_gid;
1681 for (i = 0; i < credanon->cr_ngroups && i < NGROUPS; i++)
1682 cred->cr_groups[i] = credanon->cr_groups[i];
1683 cred->cr_ngroups = i;
1684 }
1685 if (exflags & MNT_EXRDONLY)
1686 *rdonlyp = 1;
1687 else
1688 *rdonlyp = 0;
1689 if (!lockflag)
1690 VOP_UNLOCK(*vpp, 0, p);
1691
1692 return (0);
1693 }
1694
1695 /*
1696 * This function compares two net addresses by family and returns TRUE
1697 * if they are the same host.
1698 * If there is any doubt, return FALSE.
1699 * The AF_INET family is handled as a special case so that address mbufs
1700 * don't need to be saved to store "struct in_addr", which is only 4 bytes.
1701 */
1702 int
netaddr_match(family,haddr,nam)1703 netaddr_match(family, haddr, nam)
1704 int family;
1705 union nethostaddr *haddr;
1706 struct mbuf *nam;
1707 {
1708 struct sockaddr_in *inetaddr;
1709
1710 switch (family) {
1711 case AF_INET:
1712 inetaddr = mtod(nam, struct sockaddr_in *);
1713 if (inetaddr->sin_family == AF_INET &&
1714 inetaddr->sin_addr.s_addr == haddr->had_inetaddr)
1715 return (1);
1716 break;
1717 default:
1718 break;
1719 };
1720 return (0);
1721 }
1722
1723 /*
1724 * The write verifier has changed (probably due to a server reboot), so all
1725 * B_NEEDCOMMIT blocks will have to be written again. Since they are on the
1726 * dirty block list as B_DELWRI, all this takes is clearing the B_NEEDCOMMIT
1727 * flag. Once done the new write verifier can be set for the mount point.
1728 */
1729 void
nfs_clearcommit(mp)1730 nfs_clearcommit(mp)
1731 struct mount *mp;
1732 {
1733 struct vnode *vp, *nvp;
1734 struct buf *bp, *nbp;
1735 int s;
1736
1737 s = splbio();
1738 loop:
1739 for (vp = LIST_FIRST(&mp->mnt_vnodelist); vp != NULL; vp = nvp) {
1740 if (vp->v_mount != mp) /* Paranoia */
1741 goto loop;
1742 nvp = LIST_NEXT(vp, v_mntvnodes);
1743 for (bp = LIST_FIRST(&vp->v_dirtyblkhd); bp != NULL; bp = nbp) {
1744 nbp = LIST_NEXT(bp, b_vnbufs);
1745 if ((bp->b_flags & (B_BUSY | B_DELWRI | B_NEEDCOMMIT))
1746 == (B_DELWRI | B_NEEDCOMMIT))
1747 bp->b_flags &= ~B_NEEDCOMMIT;
1748 }
1749 }
1750 splx(s);
1751 }
1752
1753 void
nfs_merge_commit_ranges(vp)1754 nfs_merge_commit_ranges(vp)
1755 struct vnode *vp;
1756 {
1757 struct nfsnode *np = VTONFS(vp);
1758
1759 if (!(np->n_commitflags & NFS_COMMIT_PUSHED_VALID)) {
1760 np->n_pushedlo = np->n_pushlo;
1761 np->n_pushedhi = np->n_pushhi;
1762 np->n_commitflags |= NFS_COMMIT_PUSHED_VALID;
1763 } else {
1764 if (np->n_pushlo < np->n_pushedlo)
1765 np->n_pushedlo = np->n_pushlo;
1766 if (np->n_pushhi > np->n_pushedhi)
1767 np->n_pushedhi = np->n_pushhi;
1768 }
1769
1770 np->n_pushlo = np->n_pushhi = 0;
1771 np->n_commitflags &= ~NFS_COMMIT_PUSH_VALID;
1772 }
1773
1774 int
nfs_in_committed_range(vp,bp)1775 nfs_in_committed_range(vp, bp)
1776 struct vnode *vp;
1777 struct buf *bp;
1778 {
1779 struct nfsnode *np = VTONFS(vp);
1780 off_t lo, hi;
1781
1782 if (!(np->n_commitflags & NFS_COMMIT_PUSHED_VALID))
1783 return 0;
1784 lo = (off_t)bp->b_blkno * DEV_BSIZE;
1785 hi = lo + bp->b_dirtyend;
1786
1787 return (lo >= np->n_pushedlo && hi <= np->n_pushedhi);
1788 }
1789
1790 int
nfs_in_tobecommitted_range(vp,bp)1791 nfs_in_tobecommitted_range(vp, bp)
1792 struct vnode *vp;
1793 struct buf *bp;
1794 {
1795 struct nfsnode *np = VTONFS(vp);
1796 off_t lo, hi;
1797
1798 if (!(np->n_commitflags & NFS_COMMIT_PUSH_VALID))
1799 return 0;
1800 lo = (off_t)bp->b_blkno * DEV_BSIZE;
1801 hi = lo + bp->b_dirtyend;
1802
1803 return (lo >= np->n_pushlo && hi <= np->n_pushhi);
1804 }
1805
1806 void
nfs_add_committed_range(vp,bp)1807 nfs_add_committed_range(vp, bp)
1808 struct vnode *vp;
1809 struct buf *bp;
1810 {
1811 struct nfsnode *np = VTONFS(vp);
1812 off_t lo, hi;
1813
1814 lo = (off_t)bp->b_blkno * DEV_BSIZE;
1815 hi = lo + bp->b_dirtyend;
1816
1817 if (!(np->n_commitflags & NFS_COMMIT_PUSHED_VALID)) {
1818 np->n_pushedlo = lo;
1819 np->n_pushedhi = hi;
1820 np->n_commitflags |= NFS_COMMIT_PUSHED_VALID;
1821 } else {
1822 if (hi > np->n_pushedhi)
1823 np->n_pushedhi = hi;
1824 if (lo < np->n_pushedlo)
1825 np->n_pushedlo = lo;
1826 }
1827 }
1828
1829 void
nfs_del_committed_range(vp,bp)1830 nfs_del_committed_range(vp, bp)
1831 struct vnode *vp;
1832 struct buf *bp;
1833 {
1834 struct nfsnode *np = VTONFS(vp);
1835 off_t lo, hi;
1836
1837 if (!(np->n_commitflags & NFS_COMMIT_PUSHED_VALID))
1838 return;
1839
1840 lo = (off_t)bp->b_blkno * DEV_BSIZE;
1841 hi = lo + bp->b_dirtyend;
1842
1843 if (lo > np->n_pushedhi || hi < np->n_pushedlo)
1844 return;
1845 if (lo <= np->n_pushedlo)
1846 np->n_pushedlo = hi;
1847 else if (hi >= np->n_pushedhi)
1848 np->n_pushedhi = lo;
1849 else {
1850 /*
1851 * XXX There's only one range. If the deleted range
1852 * is in the middle, pick the largest of the
1853 * contiguous ranges that it leaves.
1854 */
1855 if ((np->n_pushedlo - lo) > (hi - np->n_pushedhi))
1856 np->n_pushedhi = lo;
1857 else
1858 np->n_pushedlo = hi;
1859 }
1860 }
1861
1862 void
nfs_add_tobecommitted_range(vp,bp)1863 nfs_add_tobecommitted_range(vp, bp)
1864 struct vnode *vp;
1865 struct buf *bp;
1866 {
1867 struct nfsnode *np = VTONFS(vp);
1868 off_t lo, hi;
1869
1870 lo = (off_t)bp->b_blkno * DEV_BSIZE;
1871 hi = lo + bp->b_dirtyend;
1872
1873 if (!(np->n_commitflags & NFS_COMMIT_PUSH_VALID)) {
1874 np->n_pushlo = lo;
1875 np->n_pushhi = hi;
1876 np->n_commitflags |= NFS_COMMIT_PUSH_VALID;
1877 } else {
1878 if (lo < np->n_pushlo)
1879 np->n_pushlo = lo;
1880 if (hi > np->n_pushhi)
1881 np->n_pushhi = hi;
1882 }
1883 }
1884
1885 void
nfs_del_tobecommitted_range(vp,bp)1886 nfs_del_tobecommitted_range(vp, bp)
1887 struct vnode *vp;
1888 struct buf *bp;
1889 {
1890 struct nfsnode *np = VTONFS(vp);
1891 off_t lo, hi;
1892
1893 if (!(np->n_commitflags & NFS_COMMIT_PUSH_VALID))
1894 return;
1895
1896 lo = (off_t)bp->b_blkno * DEV_BSIZE;
1897 hi = lo + bp->b_dirtyend;
1898
1899 if (lo > np->n_pushhi || hi < np->n_pushlo)
1900 return;
1901
1902 if (lo <= np->n_pushlo)
1903 np->n_pushlo = hi;
1904 else if (hi >= np->n_pushhi)
1905 np->n_pushhi = lo;
1906 else {
1907 /*
1908 * XXX There's only one range. If the deleted range
1909 * is in the middle, pick the largest of the
1910 * contiguous ranges that it leaves.
1911 */
1912 if ((np->n_pushlo - lo) > (hi - np->n_pushhi))
1913 np->n_pushhi = lo;
1914 else
1915 np->n_pushlo = hi;
1916 }
1917 }
1918
1919 /*
1920 * Map errnos to NFS error numbers. For Version 3 also filter out error
1921 * numbers not specified for the associated procedure.
1922 */
1923 int
nfsrv_errmap(nd,err)1924 nfsrv_errmap(nd, err)
1925 struct nfsrv_descript *nd;
1926 int err;
1927 {
1928 short *defaulterrp, *errp;
1929
1930 if (nd->nd_flag & ND_NFSV3) {
1931 if (nd->nd_procnum <= NFSPROC_COMMIT) {
1932 errp = defaulterrp = nfsrv_v3errmap[nd->nd_procnum];
1933 while (*++errp) {
1934 if (*errp == err)
1935 return (err);
1936 else if (*errp > err)
1937 break;
1938 }
1939 return ((int)*defaulterrp);
1940 } else
1941 return (err & 0xffff);
1942 }
1943 if (err <= ELAST)
1944 return ((int)nfsrv_v2errmap[err - 1]);
1945 return (NFSERR_IO);
1946 }
1947
1948 /*
1949 * Sort the group list in increasing numerical order.
1950 * (Insertion sort by Chris Torek, who was grossed out by the bubble sort
1951 * that used to be here.)
1952 */
1953 void
nfsrvw_sort(list,num)1954 nfsrvw_sort(list, num)
1955 gid_t *list;
1956 int num;
1957 {
1958 int i, j;
1959 gid_t v;
1960
1961 /* Insertion sort. */
1962 for (i = 1; i < num; i++) {
1963 v = list[i];
1964 /* find correct slot for value v, moving others up */
1965 for (j = i; --j >= 0 && v < list[j];)
1966 list[j + 1] = list[j];
1967 list[j + 1] = v;
1968 }
1969 }
1970
1971 /*
1972 * copy credentials making sure that the result can be compared with bcmp().
1973 */
1974 void
nfsrv_setcred(incred,outcred)1975 nfsrv_setcred(incred, outcred)
1976 struct ucred *incred, *outcred;
1977 {
1978 int i;
1979
1980 bzero((caddr_t)outcred, sizeof (struct ucred));
1981 outcred->cr_ref = 1;
1982 outcred->cr_uid = incred->cr_uid;
1983 outcred->cr_gid = incred->cr_gid;
1984 outcred->cr_ngroups = incred->cr_ngroups;
1985 for (i = 0; i < incred->cr_ngroups; i++)
1986 outcred->cr_groups[i] = incred->cr_groups[i];
1987 nfsrvw_sort(outcred->cr_groups, outcred->cr_ngroups);
1988 }
1989