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