Annotation of src/sys/nfs/nfs_subs.c, Revision 1.149.2.8
1.149.2.8! yamt 1: /* $NetBSD: nfs_subs.c,v 1.149.2.7 2007/12/07 17:34:44 yamt Exp $ */
1.14 cgd 2:
1.1 cgd 3: /*
1.12 mycroft 4: * Copyright (c) 1989, 1993
5: * The Regents of the University of California. All rights reserved.
1.1 cgd 6: *
7: * This code is derived from software contributed to Berkeley by
8: * Rick Macklem at The University of Guelph.
9: *
10: * Redistribution and use in source and binary forms, with or without
11: * modification, are permitted provided that the following conditions
12: * are met:
13: * 1. Redistributions of source code must retain the above copyright
14: * notice, this list of conditions and the following disclaimer.
15: * 2. Redistributions in binary form must reproduce the above copyright
16: * notice, this list of conditions and the following disclaimer in the
17: * documentation and/or other materials provided with the distribution.
1.127 agc 18: * 3. Neither the name of the University nor the names of its contributors
1.1 cgd 19: * may be used to endorse or promote products derived from this software
20: * without specific prior written permission.
21: *
22: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32: * SUCH DAMAGE.
33: *
1.25 fvdl 34: * @(#)nfs_subs.c 8.8 (Berkeley) 5/22/95
1.1 cgd 35: */
36:
1.83 fvdl 37: /*
38: * Copyright 2000 Wasabi Systems, Inc.
39: * All rights reserved.
40: *
41: * Written by Frank van der Linden for Wasabi Systems, Inc.
42: *
43: * Redistribution and use in source and binary forms, with or without
44: * modification, are permitted provided that the following conditions
45: * are met:
46: * 1. Redistributions of source code must retain the above copyright
47: * notice, this list of conditions and the following disclaimer.
48: * 2. Redistributions in binary form must reproduce the above copyright
49: * notice, this list of conditions and the following disclaimer in the
50: * documentation and/or other materials provided with the distribution.
51: * 3. All advertising materials mentioning features or use of this software
52: * must display the following acknowledgement:
53: * This product includes software developed for the NetBSD Project by
54: * Wasabi Systems, Inc.
55: * 4. The name of Wasabi Systems, Inc. may not be used to endorse
56: * or promote products derived from this software without specific prior
57: * written permission.
58: *
59: * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
60: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
61: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
62: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
63: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
64: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
65: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
66: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
67: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
68: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
69: * POSSIBILITY OF SUCH DAMAGE.
70: */
1.99 lukem 71:
72: #include <sys/cdefs.h>
1.149.2.8! yamt 73: __KERNEL_RCSID(0, "$NetBSD: nfs_subs.c,v 1.149.2.7 2007/12/07 17:34:44 yamt Exp $");
1.83 fvdl 74:
1.55 thorpej 75: #include "fs_nfs.h"
1.82 bjh21 76: #include "opt_nfs.h"
1.61 thorpej 77: #include "opt_nfsserver.h"
1.62 jonathan 78: #include "opt_iso.h"
1.76 fvdl 79: #include "opt_inet.h"
1.25 fvdl 80:
1.1 cgd 81: /*
82: * These functions support the macros and help fiddle mbuf chains for
83: * the nfs op functions. They do things like create the rpc header and
84: * copy data between mbuf chains and uio lists.
85: */
1.9 mycroft 86: #include <sys/param.h>
87: #include <sys/proc.h>
88: #include <sys/systm.h>
89: #include <sys/kernel.h>
1.149.2.8! yamt 90: #include <sys/kmem.h>
1.9 mycroft 91: #include <sys/mount.h>
92: #include <sys/vnode.h>
93: #include <sys/namei.h>
94: #include <sys/mbuf.h>
1.12 mycroft 95: #include <sys/socket.h>
96: #include <sys/stat.h>
1.25 fvdl 97: #include <sys/malloc.h>
1.98 fvdl 98: #include <sys/filedesc.h>
1.30 fvdl 99: #include <sys/time.h>
1.43 fvdl 100: #include <sys/dirent.h>
1.149.2.2 yamt 101: #include <sys/once.h>
102: #include <sys/kauth.h>
1.1 cgd 103:
1.51 mrg 104: #include <uvm/uvm_extern.h>
105:
1.9 mycroft 106: #include <nfs/rpcv2.h>
1.25 fvdl 107: #include <nfs/nfsproto.h>
1.9 mycroft 108: #include <nfs/nfsnode.h>
109: #include <nfs/nfs.h>
110: #include <nfs/xdr_subs.h>
111: #include <nfs/nfsm_subs.h>
1.12 mycroft 112: #include <nfs/nfsmount.h>
113: #include <nfs/nfsrtt.h>
1.24 christos 114: #include <nfs/nfs_var.h>
1.12 mycroft 115:
116: #include <miscfs/specfs/specdev.h>
1.24 christos 117:
1.12 mycroft 118: #include <netinet/in.h>
119: #ifdef ISO
120: #include <netiso/iso.h>
121: #endif
1.1 cgd 122:
123: /*
124: * Data items converted to xdr at startup, since they are constant
125: * This is kinda hokey, but may save a little time doing byte swaps
126: */
1.22 cgd 127: u_int32_t nfs_xdrneg1;
128: u_int32_t rpc_call, rpc_vers, rpc_reply, rpc_msgdenied, rpc_autherr,
1.25 fvdl 129: rpc_mismatch, rpc_auth_unix, rpc_msgaccepted,
1.12 mycroft 130: rpc_auth_kerb;
1.149.2.3 yamt 131: u_int32_t nfs_prog, nfs_true, nfs_false;
1.12 mycroft 132:
1.1 cgd 133: /* And other global data */
1.90 jdolecek 134: const nfstype nfsv2_type[9] =
135: { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFNON, NFCHR, NFNON };
136: const nfstype nfsv3_type[9] =
137: { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFSOCK, NFFIFO, NFNON };
138: const enum vtype nv2tov_type[8] =
139: { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON, VNON };
140: const enum vtype nv3tov_type[8] =
141: { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO };
1.25 fvdl 142: int nfs_ticks;
1.100 chs 143: int nfs_commitsize;
1.108 christos 144:
145: MALLOC_DEFINE(M_NFSDIROFF, "NFS diroff", "NFS directory cookies");
1.25 fvdl 146:
1.35 thorpej 147: /* NFS client/server stats. */
148: struct nfsstats nfsstats;
149:
1.25 fvdl 150: /*
151: * Mapping of old NFS Version 2 RPC numbers to generic numbers.
152: */
1.90 jdolecek 153: const int nfsv3_procid[NFS_NPROCS] = {
1.25 fvdl 154: NFSPROC_NULL,
155: NFSPROC_GETATTR,
156: NFSPROC_SETATTR,
157: NFSPROC_NOOP,
158: NFSPROC_LOOKUP,
159: NFSPROC_READLINK,
160: NFSPROC_READ,
161: NFSPROC_NOOP,
162: NFSPROC_WRITE,
163: NFSPROC_CREATE,
164: NFSPROC_REMOVE,
165: NFSPROC_RENAME,
166: NFSPROC_LINK,
167: NFSPROC_SYMLINK,
168: NFSPROC_MKDIR,
169: NFSPROC_RMDIR,
170: NFSPROC_READDIR,
171: NFSPROC_FSSTAT,
172: NFSPROC_NOOP,
173: NFSPROC_NOOP,
174: NFSPROC_NOOP,
175: NFSPROC_NOOP,
176: NFSPROC_NOOP
177: };
178:
179: /*
180: * and the reverse mapping from generic to Version 2 procedure numbers
181: */
1.90 jdolecek 182: const int nfsv2_procid[NFS_NPROCS] = {
1.25 fvdl 183: NFSV2PROC_NULL,
184: NFSV2PROC_GETATTR,
185: NFSV2PROC_SETATTR,
186: NFSV2PROC_LOOKUP,
187: NFSV2PROC_NOOP,
188: NFSV2PROC_READLINK,
189: NFSV2PROC_READ,
190: NFSV2PROC_WRITE,
191: NFSV2PROC_CREATE,
192: NFSV2PROC_MKDIR,
193: NFSV2PROC_SYMLINK,
194: NFSV2PROC_CREATE,
195: NFSV2PROC_REMOVE,
196: NFSV2PROC_RMDIR,
197: NFSV2PROC_RENAME,
198: NFSV2PROC_LINK,
199: NFSV2PROC_READDIR,
200: NFSV2PROC_NOOP,
201: NFSV2PROC_STATFS,
202: NFSV2PROC_NOOP,
203: NFSV2PROC_NOOP,
204: NFSV2PROC_NOOP,
205: NFSV2PROC_NOOP,
206: };
207:
208: /*
209: * Maps errno values to nfs error numbers.
210: * Use NFSERR_IO as the catch all for ones not specifically defined in
211: * RFC 1094.
212: */
1.90 jdolecek 213: static const u_char nfsrv_v2errmap[ELAST] = {
1.25 fvdl 214: NFSERR_PERM, NFSERR_NOENT, NFSERR_IO, NFSERR_IO, NFSERR_IO,
215: NFSERR_NXIO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
216: NFSERR_IO, NFSERR_IO, NFSERR_ACCES, NFSERR_IO, NFSERR_IO,
217: NFSERR_IO, NFSERR_EXIST, NFSERR_IO, NFSERR_NODEV, NFSERR_NOTDIR,
218: NFSERR_ISDIR, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
219: NFSERR_IO, NFSERR_FBIG, NFSERR_NOSPC, NFSERR_IO, NFSERR_ROFS,
220: NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
221: NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
222: NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
223: NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
224: NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
225: NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
226: NFSERR_IO, NFSERR_IO, NFSERR_NAMETOL, NFSERR_IO, NFSERR_IO,
227: NFSERR_NOTEMPTY, NFSERR_IO, NFSERR_IO, NFSERR_DQUOT, NFSERR_STALE,
228: NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
229: NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
1.52 mikel 230: NFSERR_IO, NFSERR_IO,
1.25 fvdl 231: };
232:
233: /*
234: * Maps errno values to nfs error numbers.
235: * Although it is not obvious whether or not NFS clients really care if
236: * a returned error value is in the specified list for the procedure, the
237: * safest thing to do is filter them appropriately. For Version 2, the
238: * X/Open XNFS document is the only specification that defines error values
239: * for each RPC (The RFC simply lists all possible error values for all RPCs),
240: * so I have decided to not do this for Version 2.
241: * The first entry is the default error return and the rest are the valid
242: * errors for that RPC in increasing numeric order.
243: */
1.90 jdolecek 244: static const short nfsv3err_null[] = {
1.25 fvdl 245: 0,
246: 0,
247: };
248:
1.90 jdolecek 249: static const short nfsv3err_getattr[] = {
1.25 fvdl 250: NFSERR_IO,
251: NFSERR_IO,
252: NFSERR_STALE,
253: NFSERR_BADHANDLE,
254: NFSERR_SERVERFAULT,
255: 0,
256: };
257:
1.90 jdolecek 258: static const short nfsv3err_setattr[] = {
1.25 fvdl 259: NFSERR_IO,
260: NFSERR_PERM,
261: NFSERR_IO,
262: NFSERR_ACCES,
263: NFSERR_INVAL,
264: NFSERR_NOSPC,
265: NFSERR_ROFS,
266: NFSERR_DQUOT,
267: NFSERR_STALE,
268: NFSERR_BADHANDLE,
269: NFSERR_NOT_SYNC,
270: NFSERR_SERVERFAULT,
271: 0,
272: };
273:
1.90 jdolecek 274: static const short nfsv3err_lookup[] = {
1.25 fvdl 275: NFSERR_IO,
276: NFSERR_NOENT,
277: NFSERR_IO,
278: NFSERR_ACCES,
279: NFSERR_NOTDIR,
280: NFSERR_NAMETOL,
281: NFSERR_STALE,
282: NFSERR_BADHANDLE,
283: NFSERR_SERVERFAULT,
284: 0,
285: };
286:
1.90 jdolecek 287: static const short nfsv3err_access[] = {
1.25 fvdl 288: NFSERR_IO,
289: NFSERR_IO,
290: NFSERR_STALE,
291: NFSERR_BADHANDLE,
292: NFSERR_SERVERFAULT,
293: 0,
294: };
295:
1.90 jdolecek 296: static const short nfsv3err_readlink[] = {
1.25 fvdl 297: NFSERR_IO,
298: NFSERR_IO,
299: NFSERR_ACCES,
300: NFSERR_INVAL,
301: NFSERR_STALE,
302: NFSERR_BADHANDLE,
303: NFSERR_NOTSUPP,
304: NFSERR_SERVERFAULT,
305: 0,
306: };
307:
1.90 jdolecek 308: static const short nfsv3err_read[] = {
1.25 fvdl 309: NFSERR_IO,
310: NFSERR_IO,
311: NFSERR_NXIO,
312: NFSERR_ACCES,
313: NFSERR_INVAL,
314: NFSERR_STALE,
315: NFSERR_BADHANDLE,
316: NFSERR_SERVERFAULT,
1.67 fvdl 317: NFSERR_JUKEBOX,
1.25 fvdl 318: 0,
319: };
320:
1.90 jdolecek 321: static const short nfsv3err_write[] = {
1.25 fvdl 322: NFSERR_IO,
323: NFSERR_IO,
324: NFSERR_ACCES,
325: NFSERR_INVAL,
326: NFSERR_FBIG,
327: NFSERR_NOSPC,
328: NFSERR_ROFS,
329: NFSERR_DQUOT,
330: NFSERR_STALE,
331: NFSERR_BADHANDLE,
332: NFSERR_SERVERFAULT,
1.68 fvdl 333: NFSERR_JUKEBOX,
1.25 fvdl 334: 0,
335: };
336:
1.90 jdolecek 337: static const short nfsv3err_create[] = {
1.25 fvdl 338: NFSERR_IO,
339: NFSERR_IO,
340: NFSERR_ACCES,
341: NFSERR_EXIST,
342: NFSERR_NOTDIR,
343: NFSERR_NOSPC,
344: NFSERR_ROFS,
345: NFSERR_NAMETOL,
346: NFSERR_DQUOT,
347: NFSERR_STALE,
348: NFSERR_BADHANDLE,
349: NFSERR_NOTSUPP,
350: NFSERR_SERVERFAULT,
351: 0,
352: };
353:
1.90 jdolecek 354: static const short nfsv3err_mkdir[] = {
1.25 fvdl 355: NFSERR_IO,
356: NFSERR_IO,
357: NFSERR_ACCES,
358: NFSERR_EXIST,
359: NFSERR_NOTDIR,
360: NFSERR_NOSPC,
361: NFSERR_ROFS,
362: NFSERR_NAMETOL,
363: NFSERR_DQUOT,
364: NFSERR_STALE,
365: NFSERR_BADHANDLE,
366: NFSERR_NOTSUPP,
367: NFSERR_SERVERFAULT,
368: 0,
369: };
370:
1.90 jdolecek 371: static const short nfsv3err_symlink[] = {
1.25 fvdl 372: NFSERR_IO,
373: NFSERR_IO,
374: NFSERR_ACCES,
375: NFSERR_EXIST,
376: NFSERR_NOTDIR,
377: NFSERR_NOSPC,
378: NFSERR_ROFS,
379: NFSERR_NAMETOL,
380: NFSERR_DQUOT,
381: NFSERR_STALE,
382: NFSERR_BADHANDLE,
383: NFSERR_NOTSUPP,
384: NFSERR_SERVERFAULT,
385: 0,
386: };
387:
1.90 jdolecek 388: static const short nfsv3err_mknod[] = {
1.25 fvdl 389: NFSERR_IO,
390: NFSERR_IO,
391: NFSERR_ACCES,
392: NFSERR_EXIST,
393: NFSERR_NOTDIR,
394: NFSERR_NOSPC,
395: NFSERR_ROFS,
396: NFSERR_NAMETOL,
397: NFSERR_DQUOT,
398: NFSERR_STALE,
399: NFSERR_BADHANDLE,
400: NFSERR_NOTSUPP,
401: NFSERR_SERVERFAULT,
402: NFSERR_BADTYPE,
403: 0,
404: };
405:
1.90 jdolecek 406: static const short nfsv3err_remove[] = {
1.25 fvdl 407: NFSERR_IO,
408: NFSERR_NOENT,
409: NFSERR_IO,
410: NFSERR_ACCES,
411: NFSERR_NOTDIR,
412: NFSERR_ROFS,
413: NFSERR_NAMETOL,
414: NFSERR_STALE,
415: NFSERR_BADHANDLE,
416: NFSERR_SERVERFAULT,
417: 0,
418: };
419:
1.90 jdolecek 420: static const short nfsv3err_rmdir[] = {
1.25 fvdl 421: NFSERR_IO,
422: NFSERR_NOENT,
423: NFSERR_IO,
424: NFSERR_ACCES,
425: NFSERR_EXIST,
426: NFSERR_NOTDIR,
427: NFSERR_INVAL,
428: NFSERR_ROFS,
429: NFSERR_NAMETOL,
430: NFSERR_NOTEMPTY,
431: NFSERR_STALE,
432: NFSERR_BADHANDLE,
433: NFSERR_NOTSUPP,
434: NFSERR_SERVERFAULT,
435: 0,
436: };
437:
1.90 jdolecek 438: static const short nfsv3err_rename[] = {
1.25 fvdl 439: NFSERR_IO,
440: NFSERR_NOENT,
441: NFSERR_IO,
442: NFSERR_ACCES,
443: NFSERR_EXIST,
444: NFSERR_XDEV,
445: NFSERR_NOTDIR,
446: NFSERR_ISDIR,
447: NFSERR_INVAL,
448: NFSERR_NOSPC,
449: NFSERR_ROFS,
450: NFSERR_MLINK,
451: NFSERR_NAMETOL,
452: NFSERR_NOTEMPTY,
453: NFSERR_DQUOT,
454: NFSERR_STALE,
455: NFSERR_BADHANDLE,
456: NFSERR_NOTSUPP,
457: NFSERR_SERVERFAULT,
458: 0,
459: };
460:
1.90 jdolecek 461: static const short nfsv3err_link[] = {
1.25 fvdl 462: NFSERR_IO,
463: NFSERR_IO,
464: NFSERR_ACCES,
465: NFSERR_EXIST,
466: NFSERR_XDEV,
467: NFSERR_NOTDIR,
468: NFSERR_INVAL,
469: NFSERR_NOSPC,
470: NFSERR_ROFS,
471: NFSERR_MLINK,
472: NFSERR_NAMETOL,
473: NFSERR_DQUOT,
474: NFSERR_STALE,
475: NFSERR_BADHANDLE,
476: NFSERR_NOTSUPP,
477: NFSERR_SERVERFAULT,
478: 0,
479: };
480:
1.90 jdolecek 481: static const short nfsv3err_readdir[] = {
1.25 fvdl 482: NFSERR_IO,
483: NFSERR_IO,
484: NFSERR_ACCES,
485: NFSERR_NOTDIR,
486: NFSERR_STALE,
487: NFSERR_BADHANDLE,
488: NFSERR_BAD_COOKIE,
489: NFSERR_TOOSMALL,
490: NFSERR_SERVERFAULT,
491: 0,
492: };
493:
1.90 jdolecek 494: static const short nfsv3err_readdirplus[] = {
1.25 fvdl 495: NFSERR_IO,
496: NFSERR_IO,
497: NFSERR_ACCES,
498: NFSERR_NOTDIR,
499: NFSERR_STALE,
500: NFSERR_BADHANDLE,
501: NFSERR_BAD_COOKIE,
502: NFSERR_NOTSUPP,
503: NFSERR_TOOSMALL,
504: NFSERR_SERVERFAULT,
505: 0,
506: };
507:
1.90 jdolecek 508: static const short nfsv3err_fsstat[] = {
1.25 fvdl 509: NFSERR_IO,
510: NFSERR_IO,
511: NFSERR_STALE,
512: NFSERR_BADHANDLE,
513: NFSERR_SERVERFAULT,
514: 0,
515: };
516:
1.90 jdolecek 517: static const short nfsv3err_fsinfo[] = {
1.25 fvdl 518: NFSERR_STALE,
519: NFSERR_STALE,
520: NFSERR_BADHANDLE,
521: NFSERR_SERVERFAULT,
522: 0,
523: };
524:
1.90 jdolecek 525: static const short nfsv3err_pathconf[] = {
1.25 fvdl 526: NFSERR_STALE,
527: NFSERR_STALE,
528: NFSERR_BADHANDLE,
529: NFSERR_SERVERFAULT,
530: 0,
531: };
532:
1.90 jdolecek 533: static const short nfsv3err_commit[] = {
1.25 fvdl 534: NFSERR_IO,
535: NFSERR_IO,
536: NFSERR_STALE,
537: NFSERR_BADHANDLE,
538: NFSERR_SERVERFAULT,
539: 0,
540: };
541:
1.90 jdolecek 542: static const short * const nfsrv_v3errmap[] = {
1.25 fvdl 543: nfsv3err_null,
544: nfsv3err_getattr,
545: nfsv3err_setattr,
546: nfsv3err_lookup,
547: nfsv3err_access,
548: nfsv3err_readlink,
549: nfsv3err_read,
550: nfsv3err_write,
551: nfsv3err_create,
552: nfsv3err_mkdir,
553: nfsv3err_symlink,
554: nfsv3err_mknod,
555: nfsv3err_remove,
556: nfsv3err_rmdir,
557: nfsv3err_rename,
558: nfsv3err_link,
559: nfsv3err_readdir,
560: nfsv3err_readdirplus,
561: nfsv3err_fsstat,
562: nfsv3err_fsinfo,
563: nfsv3err_pathconf,
564: nfsv3err_commit,
565: };
566:
1.12 mycroft 567: extern struct nfsrtt nfsrtt;
1.25 fvdl 568: extern struct nfsnodehashhead *nfsnodehashtbl;
569: extern u_long nfsnodehash;
1.1 cgd 570:
1.46 fvdl 571: u_long nfsdirhashmask;
1.18 mycroft 572:
1.43 fvdl 573: int nfs_webnamei __P((struct nameidata *, struct vnode *, struct proc *));
574:
1.1 cgd 575: /*
576: * Create the header for an rpc request packet
577: * The hsiz is the size of the rest of the nfs request header.
578: * (just used to decide if a cluster is a good idea)
579: */
1.12 mycroft 580: struct mbuf *
1.149.2.5 yamt 581: nfsm_reqh(struct nfsnode *np, u_long procid, int hsiz, char **bposp)
1.12 mycroft 582: {
1.75 augustss 583: struct mbuf *mb;
1.149.2.5 yamt 584: char *bpos;
1.12 mycroft 585:
1.109 matt 586: mb = m_get(M_WAIT, MT_DATA);
587: MCLAIM(mb, &nfs_mowner);
1.12 mycroft 588: if (hsiz >= MINCLSIZE)
1.109 matt 589: m_clget(mb, M_WAIT);
1.12 mycroft 590: mb->m_len = 0;
1.149.2.5 yamt 591: bpos = mtod(mb, void *);
1.148 perry 592:
1.12 mycroft 593: /* Finally, return values */
594: *bposp = bpos;
595: return (mb);
596: }
597:
598: /*
599: * Build the RPC header and fill in the authorization info.
600: * The authorization string argument is only used when the credentials
601: * come from outside of the kernel.
602: * Returns the head of the mbuf list.
603: */
604: struct mbuf *
1.25 fvdl 605: nfsm_rpchead(cr, nmflag, procid, auth_type, auth_len, auth_str, verf_len,
606: verf_str, mrest, mrest_len, mbp, xidp)
1.149.2.2 yamt 607: kauth_cred_t cr;
1.25 fvdl 608: int nmflag;
1.12 mycroft 609: int procid;
610: int auth_type;
611: int auth_len;
612: char *auth_str;
1.25 fvdl 613: int verf_len;
614: char *verf_str;
1.12 mycroft 615: struct mbuf *mrest;
616: int mrest_len;
617: struct mbuf **mbp;
1.22 cgd 618: u_int32_t *xidp;
1.1 cgd 619: {
1.75 augustss 620: struct mbuf *mb;
621: u_int32_t *tl;
1.149.2.5 yamt 622: char *bpos;
1.75 augustss 623: int i;
1.109 matt 624: struct mbuf *mreq;
1.12 mycroft 625: int siz, grpsiz, authsiz;
1.1 cgd 626:
1.12 mycroft 627: authsiz = nfsm_rndup(auth_len);
1.109 matt 628: mb = m_gethdr(M_WAIT, MT_DATA);
629: MCLAIM(mb, &nfs_mowner);
1.25 fvdl 630: if ((authsiz + 10 * NFSX_UNSIGNED) >= MINCLSIZE) {
1.109 matt 631: m_clget(mb, M_WAIT);
1.25 fvdl 632: } else if ((authsiz + 10 * NFSX_UNSIGNED) < MHLEN) {
633: MH_ALIGN(mb, authsiz + 10 * NFSX_UNSIGNED);
1.12 mycroft 634: } else {
1.25 fvdl 635: MH_ALIGN(mb, 8 * NFSX_UNSIGNED);
1.1 cgd 636: }
1.12 mycroft 637: mb->m_len = 0;
638: mreq = mb;
1.149.2.5 yamt 639: bpos = mtod(mb, void *);
1.12 mycroft 640:
641: /*
642: * First the RPC header.
643: */
1.25 fvdl 644: nfsm_build(tl, u_int32_t *, 8 * NFSX_UNSIGNED);
1.30 fvdl 645:
1.126 yamt 646: *tl++ = *xidp = nfs_getxid();
1.1 cgd 647: *tl++ = rpc_call;
648: *tl++ = rpc_vers;
1.149.2.3 yamt 649: *tl++ = txdr_unsigned(NFS_PROG);
650: if (nmflag & NFSMNT_NFSV3)
651: *tl++ = txdr_unsigned(NFS_VER3);
652: else
653: *tl++ = txdr_unsigned(NFS_VER2);
1.25 fvdl 654: if (nmflag & NFSMNT_NFSV3)
655: *tl++ = txdr_unsigned(procid);
656: else
657: *tl++ = txdr_unsigned(nfsv2_procid[procid]);
1.12 mycroft 658:
659: /*
660: * And then the authorization cred.
661: */
662: *tl++ = txdr_unsigned(auth_type);
663: *tl = txdr_unsigned(authsiz);
664: switch (auth_type) {
665: case RPCAUTH_UNIX:
1.22 cgd 666: nfsm_build(tl, u_int32_t *, auth_len);
1.12 mycroft 667: *tl++ = 0; /* stamp ?? */
668: *tl++ = 0; /* NULL hostname */
1.149.2.2 yamt 669: *tl++ = txdr_unsigned(kauth_cred_geteuid(cr));
670: *tl++ = txdr_unsigned(kauth_cred_getegid(cr));
1.12 mycroft 671: grpsiz = (auth_len >> 2) - 5;
672: *tl++ = txdr_unsigned(grpsiz);
1.20 mycroft 673: for (i = 0; i < grpsiz; i++)
1.149.2.2 yamt 674: *tl++ = txdr_unsigned(kauth_cred_group(cr, i)); /* XXX elad review */
1.12 mycroft 675: break;
1.25 fvdl 676: case RPCAUTH_KERB4:
1.12 mycroft 677: siz = auth_len;
678: while (siz > 0) {
679: if (M_TRAILINGSPACE(mb) == 0) {
1.109 matt 680: struct mbuf *mb2;
681: mb2 = m_get(M_WAIT, MT_DATA);
682: MCLAIM(mb2, &nfs_mowner);
1.12 mycroft 683: if (siz >= MINCLSIZE)
1.109 matt 684: m_clget(mb2, M_WAIT);
1.12 mycroft 685: mb->m_next = mb2;
686: mb = mb2;
687: mb->m_len = 0;
1.149.2.5 yamt 688: bpos = mtod(mb, void *);
1.12 mycroft 689: }
690: i = min(siz, M_TRAILINGSPACE(mb));
1.63 perry 691: memcpy(bpos, auth_str, i);
1.12 mycroft 692: mb->m_len += i;
693: auth_str += i;
694: bpos += i;
695: siz -= i;
696: }
697: if ((siz = (nfsm_rndup(auth_len) - auth_len)) > 0) {
698: for (i = 0; i < siz; i++)
699: *bpos++ = '\0';
700: mb->m_len += siz;
701: }
702: break;
703: };
1.25 fvdl 704:
705: /*
706: * And the verifier...
707: */
708: nfsm_build(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
709: if (verf_str) {
710: *tl++ = txdr_unsigned(RPCAUTH_KERB4);
711: *tl = txdr_unsigned(verf_len);
712: siz = verf_len;
713: while (siz > 0) {
714: if (M_TRAILINGSPACE(mb) == 0) {
1.109 matt 715: struct mbuf *mb2;
716: mb2 = m_get(M_WAIT, MT_DATA);
717: MCLAIM(mb2, &nfs_mowner);
1.25 fvdl 718: if (siz >= MINCLSIZE)
1.109 matt 719: m_clget(mb2, M_WAIT);
1.25 fvdl 720: mb->m_next = mb2;
721: mb = mb2;
722: mb->m_len = 0;
1.149.2.5 yamt 723: bpos = mtod(mb, void *);
1.25 fvdl 724: }
725: i = min(siz, M_TRAILINGSPACE(mb));
1.63 perry 726: memcpy(bpos, verf_str, i);
1.25 fvdl 727: mb->m_len += i;
728: verf_str += i;
729: bpos += i;
730: siz -= i;
731: }
732: if ((siz = (nfsm_rndup(verf_len) - verf_len)) > 0) {
733: for (i = 0; i < siz; i++)
734: *bpos++ = '\0';
735: mb->m_len += siz;
736: }
737: } else {
738: *tl++ = txdr_unsigned(RPCAUTH_NULL);
739: *tl = 0;
740: }
1.12 mycroft 741: mb->m_next = mrest;
1.25 fvdl 742: mreq->m_pkthdr.len = authsiz + 10 * NFSX_UNSIGNED + mrest_len;
1.12 mycroft 743: mreq->m_pkthdr.rcvif = (struct ifnet *)0;
744: *mbp = mb;
1.1 cgd 745: return (mreq);
746: }
747:
748: /*
749: * copies mbuf chain to the uio scatter/gather list
750: */
1.24 christos 751: int
1.1 cgd 752: nfsm_mbuftouio(mrep, uiop, siz, dpos)
753: struct mbuf **mrep;
1.75 augustss 754: struct uio *uiop;
1.1 cgd 755: int siz;
1.149.2.5 yamt 756: char **dpos;
1.1 cgd 757: {
1.75 augustss 758: char *mbufcp, *uiocp;
759: int xfer, left, len;
760: struct mbuf *mp;
1.1 cgd 761: long uiosiz, rem;
762: int error = 0;
763:
764: mp = *mrep;
765: mbufcp = *dpos;
1.149.2.5 yamt 766: len = mtod(mp, char *) + mp->m_len - mbufcp;
1.1 cgd 767: rem = nfsm_rndup(siz)-siz;
768: while (siz > 0) {
769: if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL)
770: return (EFBIG);
771: left = uiop->uio_iov->iov_len;
772: uiocp = uiop->uio_iov->iov_base;
773: if (left > siz)
774: left = siz;
775: uiosiz = left;
776: while (left > 0) {
777: while (len == 0) {
778: mp = mp->m_next;
779: if (mp == NULL)
780: return (EBADRPC);
1.149.2.5 yamt 781: mbufcp = mtod(mp, void *);
1.1 cgd 782: len = mp->m_len;
783: }
784: xfer = (left > len) ? len : left;
1.149.2.2 yamt 785: error = copyout_vmspace(uiop->uio_vmspace, mbufcp,
786: uiocp, xfer);
787: if (error) {
788: return error;
789: }
1.1 cgd 790: left -= xfer;
791: len -= xfer;
792: mbufcp += xfer;
793: uiocp += xfer;
794: uiop->uio_offset += xfer;
795: uiop->uio_resid -= xfer;
796: }
797: if (uiop->uio_iov->iov_len <= siz) {
798: uiop->uio_iovcnt--;
799: uiop->uio_iov++;
800: } else {
1.95 lukem 801: uiop->uio_iov->iov_base =
1.149.2.5 yamt 802: (char *)uiop->uio_iov->iov_base + uiosiz;
1.1 cgd 803: uiop->uio_iov->iov_len -= uiosiz;
804: }
805: siz -= uiosiz;
806: }
807: *dpos = mbufcp;
808: *mrep = mp;
809: if (rem > 0) {
810: if (len < rem)
811: error = nfs_adv(mrep, dpos, rem, len);
812: else
813: *dpos += rem;
814: }
815: return (error);
816: }
817:
818: /*
1.29 fvdl 819: * copies a uio scatter/gather list to an mbuf chain.
820: * NOTE: can ony handle iovcnt == 1
1.1 cgd 821: */
1.24 christos 822: int
1.1 cgd 823: nfsm_uiotombuf(uiop, mq, siz, bpos)
1.75 augustss 824: struct uio *uiop;
1.1 cgd 825: struct mbuf **mq;
826: int siz;
1.149.2.5 yamt 827: char **bpos;
1.1 cgd 828: {
1.75 augustss 829: char *uiocp;
830: struct mbuf *mp, *mp2;
831: int xfer, left, mlen;
1.1 cgd 832: int uiosiz, clflg, rem;
833: char *cp;
1.149.2.2 yamt 834: int error;
1.1 cgd 835:
1.29 fvdl 836: #ifdef DIAGNOSTIC
837: if (uiop->uio_iovcnt != 1)
838: panic("nfsm_uiotombuf: iovcnt != 1");
839: #endif
840:
1.1 cgd 841: if (siz > MLEN) /* or should it >= MCLBYTES ?? */
842: clflg = 1;
843: else
844: clflg = 0;
845: rem = nfsm_rndup(siz)-siz;
1.12 mycroft 846: mp = mp2 = *mq;
1.1 cgd 847: while (siz > 0) {
848: left = uiop->uio_iov->iov_len;
849: uiocp = uiop->uio_iov->iov_base;
850: if (left > siz)
851: left = siz;
852: uiosiz = left;
853: while (left > 0) {
1.12 mycroft 854: mlen = M_TRAILINGSPACE(mp);
855: if (mlen == 0) {
1.109 matt 856: mp = m_get(M_WAIT, MT_DATA);
857: MCLAIM(mp, &nfs_mowner);
1.12 mycroft 858: if (clflg)
1.109 matt 859: m_clget(mp, M_WAIT);
1.12 mycroft 860: mp->m_len = 0;
861: mp2->m_next = mp;
862: mp2 = mp;
863: mlen = M_TRAILINGSPACE(mp);
864: }
865: xfer = (left > mlen) ? mlen : left;
1.149.2.5 yamt 866: cp = mtod(mp, char *) + mp->m_len;
1.149.2.2 yamt 867: error = copyin_vmspace(uiop->uio_vmspace, uiocp, cp,
868: xfer);
869: if (error) {
870: /* XXX */
871: }
1.12 mycroft 872: mp->m_len += xfer;
1.1 cgd 873: left -= xfer;
874: uiocp += xfer;
875: uiop->uio_offset += xfer;
876: uiop->uio_resid -= xfer;
877: }
1.149.2.5 yamt 878: uiop->uio_iov->iov_base = (char *)uiop->uio_iov->iov_base +
1.95 lukem 879: uiosiz;
1.29 fvdl 880: uiop->uio_iov->iov_len -= uiosiz;
1.1 cgd 881: siz -= uiosiz;
882: }
883: if (rem > 0) {
1.12 mycroft 884: if (rem > M_TRAILINGSPACE(mp)) {
1.109 matt 885: mp = m_get(M_WAIT, MT_DATA);
886: MCLAIM(mp, &nfs_mowner);
1.1 cgd 887: mp->m_len = 0;
888: mp2->m_next = mp;
889: }
1.149.2.5 yamt 890: cp = mtod(mp, char *) + mp->m_len;
1.1 cgd 891: for (left = 0; left < rem; left++)
892: *cp++ = '\0';
893: mp->m_len += rem;
894: *bpos = cp;
895: } else
1.149.2.5 yamt 896: *bpos = mtod(mp, char *) + mp->m_len;
1.1 cgd 897: *mq = mp;
898: return (0);
899: }
900:
901: /*
1.39 fvdl 902: * Get at least "siz" bytes of correctly aligned data.
903: * When called the mbuf pointers are not necessarily correct,
904: * dsosp points to what ought to be in m_data and left contains
1.148 perry 905: * what ought to be in m_len.
1.12 mycroft 906: * This is used by the macros nfsm_dissect and nfsm_dissecton for tough
1.1 cgd 907: * cases. (The macros use the vars. dpos and dpos2)
908: */
1.24 christos 909: int
1.12 mycroft 910: nfsm_disct(mdp, dposp, siz, left, cp2)
1.1 cgd 911: struct mbuf **mdp;
1.149.2.5 yamt 912: char **dposp;
1.1 cgd 913: int siz;
914: int left;
1.149.2.5 yamt 915: char **cp2;
1.1 cgd 916: {
1.75 augustss 917: struct mbuf *m1, *m2;
1.39 fvdl 918: struct mbuf *havebuf = NULL;
1.149.2.5 yamt 919: char *src = *dposp;
920: char *dst;
1.39 fvdl 921: int len;
922:
923: #ifdef DEBUG
924: if (left < 0)
1.148 perry 925: panic("nfsm_disct: left < 0");
1.39 fvdl 926: #endif
927: m1 = *mdp;
928: /*
929: * Skip through the mbuf chain looking for an mbuf with
930: * some data. If the first mbuf found has enough data
931: * and it is correctly aligned return it.
932: */
1.1 cgd 933: while (left == 0) {
1.39 fvdl 934: havebuf = m1;
935: *mdp = m1 = m1->m_next;
936: if (m1 == NULL)
1.1 cgd 937: return (EBADRPC);
1.149.2.5 yamt 938: src = mtod(m1, void *);
1.39 fvdl 939: left = m1->m_len;
940: /*
941: * If we start a new mbuf and it is big enough
942: * and correctly aligned just return it, don't
943: * do any pull up.
944: */
945: if (left >= siz && nfsm_aligned(src)) {
946: *cp2 = src;
947: *dposp = src + siz;
948: return (0);
949: }
1.1 cgd 950: }
1.149.2.1 yamt 951: if ((m1->m_flags & M_EXT) != 0) {
952: if (havebuf && M_TRAILINGSPACE(havebuf) >= siz &&
953: nfsm_aligned(mtod(havebuf, char *) + havebuf->m_len)) {
954: /*
955: * If the first mbuf with data has external data
956: * and there is a previous mbuf with some trailing
957: * space, use it to move the data into.
1.39 fvdl 958: */
959: m2 = m1;
960: *mdp = m1 = havebuf;
1.149.2.1 yamt 961: *cp2 = mtod(m1, char *) + m1->m_len;
962: } else if (havebuf) {
1.39 fvdl 963: /*
964: * If the first mbuf has a external data
965: * and there is no previous empty mbuf
966: * allocate a new mbuf and move the external
1.148 perry 967: * data to the new mbuf. Also make the first
1.39 fvdl 968: * mbuf look empty.
969: */
1.149.2.1 yamt 970: m2 = m1;
971: *mdp = m1 = m_get(M_WAIT, MT_DATA);
972: MCLAIM(m1, m2->m_owner);
973: if ((m2->m_flags & M_PKTHDR) != 0) {
974: /* XXX MOVE */
975: M_COPY_PKTHDR(m1, m2);
976: m_tag_delete_chain(m2, NULL);
977: m2->m_flags &= ~M_PKTHDR;
978: }
979: if (havebuf) {
980: havebuf->m_next = m1;
981: }
982: m1->m_next = m2;
983: MRESETDATA(m1);
984: m1->m_len = 0;
1.39 fvdl 985: m2->m_data = src;
986: m2->m_len = left;
1.149.2.1 yamt 987: *cp2 = mtod(m1, char *);
988: } else {
989: struct mbuf **nextp = &m1->m_next;
990:
991: m1->m_len -= left;
992: do {
993: m2 = m_get(M_WAIT, MT_DATA);
994: MCLAIM(m2, m1->m_owner);
995: if (left >= MINCLSIZE) {
996: MCLGET(m2, M_WAIT);
997: }
998: m2->m_next = *nextp;
999: *nextp = m2;
1000: nextp = &m2->m_next;
1001: len = (m2->m_flags & M_EXT) != 0 ?
1002: MCLBYTES : MLEN;
1003: if (len > left) {
1004: len = left;
1005: }
1006: memcpy(mtod(m2, char *), src, len);
1007: m2->m_len = len;
1008: src += len;
1009: left -= len;
1010: } while (left > 0);
1011: *mdp = m1 = m1->m_next;
1012: m2 = m1->m_next;
1013: *cp2 = mtod(m1, char *);
1.1 cgd 1014: }
1.39 fvdl 1015: } else {
1016: /*
1017: * If the first mbuf has no external data
1018: * move the data to the front of the mbuf.
1019: */
1.149.2.1 yamt 1020: MRESETDATA(m1);
1021: dst = mtod(m1, char *);
1022: if (dst != src) {
1.63 perry 1023: memmove(dst, src, left);
1.149.2.1 yamt 1024: }
1.39 fvdl 1025: m1->m_len = left;
1026: m2 = m1->m_next;
1.149.2.1 yamt 1027: *cp2 = m1->m_data;
1.1 cgd 1028: }
1.149.2.1 yamt 1029: *dposp = *cp2 + siz;
1.39 fvdl 1030: /*
1031: * Loop through mbufs pulling data up into first mbuf until
1032: * the first mbuf is full or there is no more data to
1033: * pullup.
1034: */
1.149.2.1 yamt 1035: dst = mtod(m1, char *) + m1->m_len;
1.129 itojun 1036: while ((len = M_TRAILINGSPACE(m1)) != 0 && m2) {
1.149.2.1 yamt 1037: if ((len = min(len, m2->m_len)) != 0) {
1038: memcpy(dst, mtod(m2, char *), len);
1039: }
1.39 fvdl 1040: m1->m_len += len;
1041: dst += len;
1042: m2->m_data += len;
1043: m2->m_len -= len;
1044: m2 = m2->m_next;
1045: }
1046: if (m1->m_len < siz)
1047: return (EBADRPC);
1.1 cgd 1048: return (0);
1049: }
1050:
1051: /*
1052: * Advance the position in the mbuf chain.
1053: */
1.24 christos 1054: int
1.1 cgd 1055: nfs_adv(mdp, dposp, offs, left)
1056: struct mbuf **mdp;
1.149.2.5 yamt 1057: char **dposp;
1.1 cgd 1058: int offs;
1059: int left;
1060: {
1.75 augustss 1061: struct mbuf *m;
1062: int s;
1.1 cgd 1063:
1064: m = *mdp;
1065: s = left;
1066: while (s < offs) {
1067: offs -= s;
1068: m = m->m_next;
1069: if (m == NULL)
1070: return (EBADRPC);
1071: s = m->m_len;
1072: }
1073: *mdp = m;
1.149.2.5 yamt 1074: *dposp = mtod(m, char *) + offs;
1.1 cgd 1075: return (0);
1076: }
1077:
1078: /*
1079: * Copy a string into mbufs for the hard cases...
1080: */
1.24 christos 1081: int
1.1 cgd 1082: nfsm_strtmbuf(mb, bpos, cp, siz)
1083: struct mbuf **mb;
1084: char **bpos;
1.33 cgd 1085: const char *cp;
1.1 cgd 1086: long siz;
1087: {
1.75 augustss 1088: struct mbuf *m1 = NULL, *m2;
1.1 cgd 1089: long left, xfer, len, tlen;
1.22 cgd 1090: u_int32_t *tl;
1.1 cgd 1091: int putsize;
1092:
1093: putsize = 1;
1094: m2 = *mb;
1.12 mycroft 1095: left = M_TRAILINGSPACE(m2);
1.1 cgd 1096: if (left > 0) {
1.22 cgd 1097: tl = ((u_int32_t *)(*bpos));
1.1 cgd 1098: *tl++ = txdr_unsigned(siz);
1099: putsize = 0;
1100: left -= NFSX_UNSIGNED;
1101: m2->m_len += NFSX_UNSIGNED;
1102: if (left > 0) {
1.149.2.5 yamt 1103: memcpy((void *) tl, cp, left);
1.1 cgd 1104: siz -= left;
1105: cp += left;
1106: m2->m_len += left;
1107: left = 0;
1108: }
1109: }
1.12 mycroft 1110: /* Loop around adding mbufs */
1.1 cgd 1111: while (siz > 0) {
1.109 matt 1112: m1 = m_get(M_WAIT, MT_DATA);
1113: MCLAIM(m1, &nfs_mowner);
1.1 cgd 1114: if (siz > MLEN)
1.109 matt 1115: m_clget(m1, M_WAIT);
1.1 cgd 1116: m1->m_len = NFSMSIZ(m1);
1117: m2->m_next = m1;
1118: m2 = m1;
1.22 cgd 1119: tl = mtod(m1, u_int32_t *);
1.1 cgd 1120: tlen = 0;
1121: if (putsize) {
1122: *tl++ = txdr_unsigned(siz);
1123: m1->m_len -= NFSX_UNSIGNED;
1124: tlen = NFSX_UNSIGNED;
1125: putsize = 0;
1126: }
1127: if (siz < m1->m_len) {
1128: len = nfsm_rndup(siz);
1129: xfer = siz;
1130: if (xfer < len)
1131: *(tl+(xfer>>2)) = 0;
1132: } else {
1133: xfer = len = m1->m_len;
1134: }
1.149.2.5 yamt 1135: memcpy((void *) tl, cp, xfer);
1.1 cgd 1136: m1->m_len = len+tlen;
1137: siz -= xfer;
1138: cp += xfer;
1139: }
1140: *mb = m1;
1.149.2.5 yamt 1141: *bpos = mtod(m1, char *) + m1->m_len;
1.1 cgd 1142: return (0);
1143: }
1144:
1.49 fvdl 1145: /*
1146: * Directory caching routines. They work as follows:
1147: * - a cache is maintained per VDIR nfsnode.
1148: * - for each offset cookie that is exported to userspace, and can
1149: * thus be thrown back at us as an offset to VOP_READDIR, store
1150: * information in the cache.
1151: * - cached are:
1152: * - cookie itself
1153: * - blocknumber (essentially just a search key in the buffer cache)
1154: * - entry number in block.
1155: * - offset cookie of block in which this entry is stored
1156: * - 32 bit cookie if NFSMNT_XLATECOOKIE is used.
1157: * - entries are looked up in a hash table
1158: * - also maintained is an LRU list of entries, used to determine
1159: * which ones to delete if the cache grows too large.
1160: * - if 32 <-> 64 translation mode is requested for a filesystem,
1161: * the cache also functions as a translation table
1162: * - in the translation case, invalidating the cache does not mean
1163: * flushing it, but just marking entries as invalid, except for
1164: * the <64bit cookie, 32bitcookie> pair which is still valid, to
1165: * still be able to use the cache as a translation table.
1166: * - 32 bit cookies are uniquely created by combining the hash table
1167: * entry value, and one generation count per hash table entry,
1168: * incremented each time an entry is appended to the chain.
1169: * - the cache is invalidated each time a direcory is modified
1170: * - sanity checks are also done; if an entry in a block turns
1171: * out not to have a matching cookie, the cache is invalidated
1172: * and a new block starting from the wanted offset is fetched from
1173: * the server.
1174: * - directory entries as read from the server are extended to contain
1175: * the 64bit and, optionally, the 32bit cookies, for sanity checking
1176: * the cache and exporting them to userspace through the cookie
1177: * argument to VOP_READDIR.
1178: */
1179:
1.46 fvdl 1180: u_long
1181: nfs_dirhash(off)
1182: off_t off;
1183: {
1184: int i;
1185: char *cp = (char *)&off;
1186: u_long sum = 0L;
1187:
1188: for (i = 0 ; i < sizeof (off); i++)
1189: sum += *cp++;
1190:
1191: return sum;
1192: }
1193:
1.135 yamt 1194: #define _NFSDC_MTX(np) (&NFSTOV(np)->v_interlock)
1.149.2.8! yamt 1195: #define NFSDC_LOCK(np) mutex_enter(_NFSDC_MTX(np))
! 1196: #define NFSDC_UNLOCK(np) mutex_exit(_NFSDC_MTX(np))
! 1197: #define NFSDC_ASSERT_LOCKED(np) KASSERT(mutex_owned(_NFSDC_MTX(np)))
1.135 yamt 1198:
1.49 fvdl 1199: void
1200: nfs_initdircache(vp)
1201: struct vnode *vp;
1202: {
1203: struct nfsnode *np = VTONFS(vp);
1.135 yamt 1204: struct nfsdirhashhead *dircache;
1.120 yamt 1205:
1.135 yamt 1206: dircache = hashinit(NFS_DIRHASHSIZ, HASH_LIST, M_NFSDIROFF,
1207: M_WAITOK, &nfsdirhashmask);
1.49 fvdl 1208:
1.135 yamt 1209: NFSDC_LOCK(np);
1210: if (np->n_dircache == NULL) {
1211: np->n_dircachesize = 0;
1212: np->n_dircache = dircache;
1213: dircache = NULL;
1214: TAILQ_INIT(&np->n_dirchain);
1215: }
1216: NFSDC_UNLOCK(np);
1217: if (dircache)
1218: hashdone(dircache, M_NFSDIROFF);
1.120 yamt 1219: }
1220:
1221: void
1222: nfs_initdirxlatecookie(vp)
1223: struct vnode *vp;
1224: {
1225: struct nfsnode *np = VTONFS(vp);
1.135 yamt 1226: unsigned *dirgens;
1.120 yamt 1227:
1228: KASSERT(VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_XLATECOOKIE);
1229:
1.149.2.8! yamt 1230: dirgens = kmem_zalloc(NFS_DIRHASHSIZ * sizeof(unsigned), KM_SLEEP);
1.135 yamt 1231: NFSDC_LOCK(np);
1232: if (np->n_dirgens == NULL) {
1233: np->n_dirgens = dirgens;
1234: dirgens = NULL;
1235: }
1236: NFSDC_UNLOCK(np);
1237: if (dirgens)
1.149.2.8! yamt 1238: kmem_free(dirgens, NFS_DIRHASHSIZ * sizeof(unsigned));
1.135 yamt 1239: }
1240:
1241: static const struct nfsdircache dzero;
1242:
1243: static void nfs_unlinkdircache __P((struct nfsnode *np, struct nfsdircache *));
1244: static void nfs_putdircache_unlocked __P((struct nfsnode *,
1245: struct nfsdircache *));
1246:
1247: static void
1248: nfs_unlinkdircache(np, ndp)
1249: struct nfsnode *np;
1250: struct nfsdircache *ndp;
1251: {
1252:
1253: NFSDC_ASSERT_LOCKED(np);
1254: KASSERT(ndp != &dzero);
1255:
1256: if (LIST_NEXT(ndp, dc_hash) == (void *)-1)
1257: return;
1258:
1259: TAILQ_REMOVE(&np->n_dirchain, ndp, dc_chain);
1260: LIST_REMOVE(ndp, dc_hash);
1261: LIST_NEXT(ndp, dc_hash) = (void *)-1; /* mark as unlinked */
1262:
1263: nfs_putdircache_unlocked(np, ndp);
1264: }
1265:
1266: void
1267: nfs_putdircache(np, ndp)
1268: struct nfsnode *np;
1269: struct nfsdircache *ndp;
1270: {
1271: int ref;
1272:
1273: if (ndp == &dzero)
1274: return;
1275:
1276: KASSERT(ndp->dc_refcnt > 0);
1277: NFSDC_LOCK(np);
1278: ref = --ndp->dc_refcnt;
1279: NFSDC_UNLOCK(np);
1280:
1281: if (ref == 0)
1.149.2.8! yamt 1282: kmem_free(ndp, sizeof(*ndp));
1.49 fvdl 1283: }
1284:
1.135 yamt 1285: static void
1.149.2.3 yamt 1286: nfs_putdircache_unlocked(struct nfsnode *np, struct nfsdircache *ndp)
1.135 yamt 1287: {
1288: int ref;
1289:
1290: NFSDC_ASSERT_LOCKED(np);
1291:
1292: if (ndp == &dzero)
1293: return;
1294:
1295: KASSERT(ndp->dc_refcnt > 0);
1296: ref = --ndp->dc_refcnt;
1297: if (ref == 0)
1.149.2.8! yamt 1298: kmem_free(ndp, sizeof(*ndp));
1.135 yamt 1299: }
1.46 fvdl 1300:
1301: struct nfsdircache *
1.49 fvdl 1302: nfs_searchdircache(vp, off, do32, hashent)
1.46 fvdl 1303: struct vnode *vp;
1304: off_t off;
1.49 fvdl 1305: int do32;
1306: int *hashent;
1307: {
1308: struct nfsdirhashhead *ndhp;
1309: struct nfsdircache *ndp = NULL;
1310: struct nfsnode *np = VTONFS(vp);
1311: unsigned ent;
1312:
1313: /*
1314: * Zero is always a valid cookie.
1315: */
1316: if (off == 0)
1.149 christos 1317: /* XXXUNCONST */
1318: return (struct nfsdircache *)__UNCONST(&dzero);
1.49 fvdl 1319:
1.134 yamt 1320: if (!np->n_dircache)
1321: return NULL;
1322:
1.49 fvdl 1323: /*
1324: * We use a 32bit cookie as search key, directly reconstruct
1325: * the hashentry. Else use the hashfunction.
1326: */
1327: if (do32) {
1328: ent = (u_int32_t)off >> 24;
1329: if (ent >= NFS_DIRHASHSIZ)
1330: return NULL;
1331: ndhp = &np->n_dircache[ent];
1332: } else {
1333: ndhp = NFSDIRHASH(np, off);
1334: }
1335:
1336: if (hashent)
1337: *hashent = (int)(ndhp - np->n_dircache);
1.135 yamt 1338:
1339: NFSDC_LOCK(np);
1.49 fvdl 1340: if (do32) {
1.113 yamt 1341: LIST_FOREACH(ndp, ndhp, dc_hash) {
1.49 fvdl 1342: if (ndp->dc_cookie32 == (u_int32_t)off) {
1343: /*
1344: * An invalidated entry will become the
1345: * start of a new block fetched from
1346: * the server.
1347: */
1.135 yamt 1348: if (ndp->dc_flags & NFSDC_INVALID) {
1.49 fvdl 1349: ndp->dc_blkcookie = ndp->dc_cookie;
1350: ndp->dc_entry = 0;
1.135 yamt 1351: ndp->dc_flags &= ~NFSDC_INVALID;
1.49 fvdl 1352: }
1353: break;
1354: }
1355: }
1356: } else {
1.113 yamt 1357: LIST_FOREACH(ndp, ndhp, dc_hash) {
1.49 fvdl 1358: if (ndp->dc_cookie == off)
1359: break;
1.113 yamt 1360: }
1.49 fvdl 1361: }
1.135 yamt 1362: if (ndp != NULL)
1363: ndp->dc_refcnt++;
1364: NFSDC_UNLOCK(np);
1.49 fvdl 1365: return ndp;
1366: }
1367:
1368:
1369: struct nfsdircache *
1.149.2.3 yamt 1370: nfs_enterdircache(struct vnode *vp, off_t off, off_t blkoff, int en,
1371: daddr_t blkno)
1.46 fvdl 1372: {
1373: struct nfsnode *np = VTONFS(vp);
1374: struct nfsdirhashhead *ndhp;
1.135 yamt 1375: struct nfsdircache *ndp = NULL;
1376: struct nfsdircache *newndp = NULL;
1.49 fvdl 1377: struct nfsmount *nmp = VFSTONFS(vp->v_mount);
1.149.2.2 yamt 1378: int hashent = 0, gen, overwrite; /* XXX: GCC */
1.46 fvdl 1379:
1.135 yamt 1380: /*
1381: * XXX refuse entries for offset 0. amd(8) erroneously sets
1382: * cookie 0 for the '.' entry, making this necessary. This
1383: * isn't so bad, as 0 is a special case anyway.
1384: */
1385: if (off == 0)
1.149 christos 1386: /* XXXUNCONST */
1387: return (struct nfsdircache *)__UNCONST(&dzero);
1.135 yamt 1388:
1.49 fvdl 1389: if (!np->n_dircache)
1390: /*
1391: * XXX would like to do this in nfs_nget but vtype
1392: * isn't known at that time.
1393: */
1394: nfs_initdircache(vp);
1.50 fvdl 1395:
1.120 yamt 1396: if ((nmp->nm_flag & NFSMNT_XLATECOOKIE) && !np->n_dirgens)
1397: nfs_initdirxlatecookie(vp);
1398:
1.135 yamt 1399: retry:
1.49 fvdl 1400: ndp = nfs_searchdircache(vp, off, 0, &hashent);
1401:
1.135 yamt 1402: NFSDC_LOCK(np);
1403: if (ndp && (ndp->dc_flags & NFSDC_INVALID) == 0) {
1.49 fvdl 1404: /*
1405: * Overwriting an old entry. Check if it's the same.
1406: * If so, just return. If not, remove the old entry.
1407: */
1408: if (ndp->dc_blkcookie == blkoff && ndp->dc_entry == en)
1.135 yamt 1409: goto done;
1410: nfs_unlinkdircache(np, ndp);
1411: nfs_putdircache_unlocked(np, ndp);
1412: ndp = NULL;
1.46 fvdl 1413: }
1414:
1.49 fvdl 1415: ndhp = &np->n_dircache[hashent];
1.46 fvdl 1416:
1.49 fvdl 1417: if (!ndp) {
1.135 yamt 1418: if (newndp == NULL) {
1419: NFSDC_UNLOCK(np);
1.149.2.8! yamt 1420: newndp = kmem_alloc(sizeof(*newndp), KM_SLEEP);
1.135 yamt 1421: newndp->dc_refcnt = 1;
1422: LIST_NEXT(newndp, dc_hash) = (void *)-1;
1423: goto retry;
1424: }
1425: ndp = newndp;
1426: newndp = NULL;
1.49 fvdl 1427: overwrite = 0;
1428: if (nmp->nm_flag & NFSMNT_XLATECOOKIE) {
1429: /*
1430: * We're allocating a new entry, so bump the
1431: * generation number.
1432: */
1.149.2.2 yamt 1433: KASSERT(np->n_dirgens);
1.49 fvdl 1434: gen = ++np->n_dirgens[hashent];
1435: if (gen == 0) {
1436: np->n_dirgens[hashent]++;
1437: gen++;
1438: }
1439: ndp->dc_cookie32 = (hashent << 24) | (gen & 0xffffff);
1440: }
1441: } else
1442: overwrite = 1;
1.46 fvdl 1443:
1.49 fvdl 1444: ndp->dc_cookie = off;
1445: ndp->dc_blkcookie = blkoff;
1.46 fvdl 1446: ndp->dc_entry = en;
1.137 yamt 1447: ndp->dc_flags = 0;
1.46 fvdl 1448:
1.49 fvdl 1449: if (overwrite)
1.135 yamt 1450: goto done;
1.49 fvdl 1451:
1.46 fvdl 1452: /*
1453: * If the maximum directory cookie cache size has been reached
1454: * for this node, take one off the front. The idea is that
1455: * directories are typically read front-to-back once, so that
1456: * the oldest entries can be thrown away without much performance
1457: * loss.
1458: */
1459: if (np->n_dircachesize == NFS_MAXDIRCACHE) {
1.135 yamt 1460: nfs_unlinkdircache(np, TAILQ_FIRST(&np->n_dirchain));
1.46 fvdl 1461: } else
1462: np->n_dircachesize++;
1.148 perry 1463:
1.135 yamt 1464: KASSERT(ndp->dc_refcnt == 1);
1.46 fvdl 1465: LIST_INSERT_HEAD(ndhp, ndp, dc_hash);
1466: TAILQ_INSERT_TAIL(&np->n_dirchain, ndp, dc_chain);
1.135 yamt 1467: ndp->dc_refcnt++;
1468: done:
1469: KASSERT(ndp->dc_refcnt > 0);
1470: NFSDC_UNLOCK(np);
1471: if (newndp)
1472: nfs_putdircache(np, newndp);
1.46 fvdl 1473: return ndp;
1474: }
1475:
1476: void
1.145 yamt 1477: nfs_invaldircache(vp, flags)
1.46 fvdl 1478: struct vnode *vp;
1.145 yamt 1479: int flags;
1.46 fvdl 1480: {
1481: struct nfsnode *np = VTONFS(vp);
1482: struct nfsdircache *ndp = NULL;
1.49 fvdl 1483: struct nfsmount *nmp = VFSTONFS(vp->v_mount);
1.149.2.4 yamt 1484: const bool forcefree = flags & NFS_INVALDIRCACHE_FORCE;
1.46 fvdl 1485:
1486: #ifdef DIAGNOSTIC
1487: if (vp->v_type != VDIR)
1488: panic("nfs: invaldircache: not dir");
1489: #endif
1490:
1.145 yamt 1491: if ((flags & NFS_INVALDIRCACHE_KEEPEOF) == 0)
1492: np->n_flag &= ~NEOFVALID;
1.144 yamt 1493:
1.46 fvdl 1494: if (!np->n_dircache)
1495: return;
1496:
1.135 yamt 1497: NFSDC_LOCK(np);
1.49 fvdl 1498: if (!(nmp->nm_flag & NFSMNT_XLATECOOKIE) || forcefree) {
1.135 yamt 1499: while ((ndp = TAILQ_FIRST(&np->n_dirchain)) != NULL) {
1500: KASSERT(!forcefree || ndp->dc_refcnt == 1);
1501: nfs_unlinkdircache(np, ndp);
1.49 fvdl 1502: }
1503: np->n_dircachesize = 0;
1504: if (forcefree && np->n_dirgens) {
1.149.2.8! yamt 1505: kmem_free(np->n_dirgens,
! 1506: NFS_DIRHASHSIZ * sizeof(unsigned));
1.120 yamt 1507: np->n_dirgens = NULL;
1.49 fvdl 1508: }
1509: } else {
1.135 yamt 1510: TAILQ_FOREACH(ndp, &np->n_dirchain, dc_chain)
1511: ndp->dc_flags |= NFSDC_INVALID;
1.46 fvdl 1512: }
1513:
1.135 yamt 1514: NFSDC_UNLOCK(np);
1.46 fvdl 1515: }
1516:
1.1 cgd 1517: /*
1.35 thorpej 1518: * Called once before VFS init to initialize shared and
1519: * server-specific data structures.
1.1 cgd 1520: */
1.149.2.2 yamt 1521: static int
1522: nfs_init0(void)
1.1 cgd 1523: {
1.149.2.5 yamt 1524:
1.12 mycroft 1525: nfsrtt.pos = 0;
1.1 cgd 1526: rpc_vers = txdr_unsigned(RPC_VER2);
1527: rpc_call = txdr_unsigned(RPC_CALL);
1528: rpc_reply = txdr_unsigned(RPC_REPLY);
1529: rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED);
1530: rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED);
1531: rpc_mismatch = txdr_unsigned(RPC_MISMATCH);
1.12 mycroft 1532: rpc_autherr = txdr_unsigned(RPC_AUTHERR);
1.1 cgd 1533: rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX);
1.25 fvdl 1534: rpc_auth_kerb = txdr_unsigned(RPCAUTH_KERB4);
1.1 cgd 1535: nfs_prog = txdr_unsigned(NFS_PROG);
1.149.2.4 yamt 1536: nfs_true = txdr_unsigned(true);
1537: nfs_false = txdr_unsigned(false);
1.12 mycroft 1538: nfs_xdrneg1 = txdr_unsigned(-1);
1.25 fvdl 1539: nfs_ticks = (hz * NFS_TICKINTVL + 500) / 1000;
1540: if (nfs_ticks < 1)
1541: nfs_ticks = 1;
1.2 glass 1542: #ifdef NFSSERVER
1.12 mycroft 1543: nfsrv_init(0); /* Init server data structures */
1.1 cgd 1544: nfsrv_initcache(); /* Init the server request cache */
1.149.2.5 yamt 1545: {
1546: extern krwlock_t netexport_lock; /* XXX */
1547: rw_init(&netexport_lock);
1548: }
1.36 fvdl 1549: #endif /* NFSSERVER */
1.12 mycroft 1550:
1.149.2.2 yamt 1551: #if defined(NFSSERVER) || (defined(NFS) && !defined(NFS_V2_ONLY))
1552: nfsdreq_init();
1553: #endif /* defined(NFSSERVER) || (defined(NFS) && !defined(NFS_V2_ONLY)) */
1554:
1.1 cgd 1555: /*
1556: * Initialize reply list and start timer
1557: */
1.16 mycroft 1558: TAILQ_INIT(&nfs_reqq);
1.149.2.5 yamt 1559: nfs_timer_init();
1.109 matt 1560: MOWNER_ATTACH(&nfs_mowner);
1.106 jdolecek 1561:
1562: #ifdef NFS
1563: /* Initialize the kqueue structures */
1564: nfs_kqinit();
1.119 yamt 1565: /* Initialize the iod structures */
1566: nfs_iodinit();
1.106 jdolecek 1567: #endif
1.149.2.2 yamt 1568: return 0;
1569: }
1570:
1571: void
1572: nfs_init(void)
1573: {
1574: static ONCE_DECL(nfs_init_once);
1575:
1576: RUN_ONCE(&nfs_init_once, nfs_init0);
1.1 cgd 1577: }
1578:
1.38 thorpej 1579: #ifdef NFS
1.35 thorpej 1580: /*
1581: * Called once at VFS init to initialize client-specific data structures.
1582: */
1583: void
1584: nfs_vfs_init()
1585: {
1.149.2.2 yamt 1586: /* Initialize NFS server / client shared data. */
1587: nfs_init();
1588:
1.96 chs 1589: nfs_nhinit(); /* Init the nfsnode table */
1.100 chs 1590: nfs_commitsize = uvmexp.npages << (PAGE_SHIFT - 4);
1.96 chs 1591: }
1.35 thorpej 1592:
1.96 chs 1593: void
1594: nfs_vfs_reinit()
1595: {
1596: nfs_nhreinit();
1.73 jdolecek 1597: }
1598:
1599: void
1600: nfs_vfs_done()
1601: {
1602: nfs_nhdone();
1.35 thorpej 1603: }
1604:
1.1 cgd 1605: /*
1.12 mycroft 1606: * Attribute cache routines.
1607: * nfs_loadattrcache() - loads or updates the cache contents from attributes
1608: * that are on the mbuf list
1609: * nfs_getattrcache() - returns valid attributes if found in cache, returns
1610: * error otherwise
1.1 cgd 1611: */
1.12 mycroft 1612:
1613: /*
1614: * Load the attribute cache (that lives in the nfsnode entry) with
1615: * the values on the mbuf list and
1616: * Iff vap not NULL
1617: * copy the attributes to *vaper
1618: */
1.24 christos 1619: int
1.105 yamt 1620: nfsm_loadattrcache(vpp, mdp, dposp, vaper, flags)
1.12 mycroft 1621: struct vnode **vpp;
1622: struct mbuf **mdp;
1.149.2.5 yamt 1623: char **dposp;
1.12 mycroft 1624: struct vattr *vaper;
1.105 yamt 1625: int flags;
1.1 cgd 1626: {
1.75 augustss 1627: int32_t t1;
1.149.2.5 yamt 1628: char *cp2;
1.25 fvdl 1629: int error = 0;
1.12 mycroft 1630: struct mbuf *md;
1.45 fvdl 1631: int v3 = NFS_ISV3(*vpp);
1.1 cgd 1632:
1.12 mycroft 1633: md = *mdp;
1.149.2.5 yamt 1634: t1 = (mtod(md, char *) + md->m_len) - *dposp;
1.25 fvdl 1635: error = nfsm_disct(mdp, dposp, NFSX_FATTR(v3), t1, &cp2);
1.24 christos 1636: if (error)
1.12 mycroft 1637: return (error);
1.105 yamt 1638: return nfs_loadattrcache(vpp, (struct nfs_fattr *)cp2, vaper, flags);
1.45 fvdl 1639: }
1640:
1641: int
1.105 yamt 1642: nfs_loadattrcache(vpp, fp, vaper, flags)
1.45 fvdl 1643: struct vnode **vpp;
1644: struct nfs_fattr *fp;
1645: struct vattr *vaper;
1.105 yamt 1646: int flags;
1.45 fvdl 1647: {
1.75 augustss 1648: struct vnode *vp = *vpp;
1649: struct vattr *vap;
1.45 fvdl 1650: int v3 = NFS_ISV3(vp);
1651: enum vtype vtyp;
1652: u_short vmode;
1653: struct timespec mtime;
1.139 yamt 1654: struct timespec ctime;
1.45 fvdl 1655: struct vnode *nvp;
1656: int32_t rdev;
1.75 augustss 1657: struct nfsnode *np;
1.45 fvdl 1658: extern int (**spec_nfsv2nodeop_p) __P((void *));
1.101 fvdl 1659: uid_t uid;
1660: gid_t gid;
1.45 fvdl 1661:
1.25 fvdl 1662: if (v3) {
1663: vtyp = nfsv3tov_type(fp->fa_type);
1664: vmode = fxdr_unsigned(u_short, fp->fa_mode);
1.71 is 1665: rdev = makedev(fxdr_unsigned(u_int32_t, fp->fa3_rdev.specdata1),
1666: fxdr_unsigned(u_int32_t, fp->fa3_rdev.specdata2));
1.25 fvdl 1667: fxdr_nfsv3time(&fp->fa3_mtime, &mtime);
1.139 yamt 1668: fxdr_nfsv3time(&fp->fa3_ctime, &ctime);
1.12 mycroft 1669: } else {
1.25 fvdl 1670: vtyp = nfsv2tov_type(fp->fa_type);
1671: vmode = fxdr_unsigned(u_short, fp->fa_mode);
1672: if (vtyp == VNON || vtyp == VREG)
1673: vtyp = IFTOVT(vmode);
1674: rdev = fxdr_unsigned(int32_t, fp->fa2_rdev);
1675: fxdr_nfsv2time(&fp->fa2_mtime, &mtime);
1.139 yamt 1676: ctime.tv_sec = fxdr_unsigned(u_int32_t,
1677: fp->fa2_ctime.nfsv2_sec);
1678: ctime.tv_nsec = 0;
1.25 fvdl 1679:
1680: /*
1681: * Really ugly NFSv2 kludge.
1682: */
1683: if (vtyp == VCHR && rdev == 0xffffffff)
1684: vtyp = VFIFO;
1.12 mycroft 1685: }
1.25 fvdl 1686:
1.101 fvdl 1687: vmode &= ALLPERMS;
1688:
1.12 mycroft 1689: /*
1690: * If v_type == VNON it is a new node, so fill in the v_type,
1.148 perry 1691: * n_mtime fields. Check to see if it represents a special
1.12 mycroft 1692: * device, and if so, check for a possible alias. Once the
1693: * correct vnode has been obtained, fill in the rest of the
1694: * information.
1695: */
1696: np = VTONFS(vp);
1.87 fvdl 1697: if (vp->v_type == VNON) {
1.25 fvdl 1698: vp->v_type = vtyp;
1.12 mycroft 1699: if (vp->v_type == VFIFO) {
1.24 christos 1700: extern int (**fifo_nfsv2nodeop_p) __P((void *));
1.12 mycroft 1701: vp->v_op = fifo_nfsv2nodeop_p;
1.131 yamt 1702: } else if (vp->v_type == VREG) {
1.149.2.4 yamt 1703: mutex_init(&np->n_commitlock, MUTEX_DEFAULT, IPL_NONE);
1.131 yamt 1704: } else if (vp->v_type == VCHR || vp->v_type == VBLK) {
1.12 mycroft 1705: vp->v_op = spec_nfsv2nodeop_p;
1.24 christos 1706: nvp = checkalias(vp, (dev_t)rdev, vp->v_mount);
1707: if (nvp) {
1.12 mycroft 1708: /*
1709: * Discard unneeded vnode, but save its nfsnode.
1.25 fvdl 1710: * Since the nfsnode does not have a lock, its
1711: * vnode lock has to be carried over.
1.12 mycroft 1712: */
1.94 bjh21 1713: /*
1714: * XXX is the old node sure to be locked here?
1715: */
1716: KASSERT(lockstatus(&vp->v_lock) ==
1717: LK_EXCLUSIVE);
1.12 mycroft 1718: nvp->v_data = vp->v_data;
1719: vp->v_data = NULL;
1.93 fvdl 1720: VOP_UNLOCK(vp, 0);
1.12 mycroft 1721: vp->v_op = spec_vnodeop_p;
1722: vgone(vp);
1.94 bjh21 1723: lockmgr(&nvp->v_lock, LK_EXCLUSIVE,
1724: &nvp->v_interlock);
1.12 mycroft 1725: /*
1726: * Reinitialize aliased node.
1727: */
1728: np->n_vnode = nvp;
1729: *vpp = vp = nvp;
1730: }
1731: }
1.128 yamt 1732: np->n_mtime = mtime;
1.12 mycroft 1733: }
1.101 fvdl 1734: uid = fxdr_unsigned(uid_t, fp->fa_uid);
1735: gid = fxdr_unsigned(gid_t, fp->fa_gid);
1.49 fvdl 1736: vap = np->n_vattr;
1.101 fvdl 1737:
1738: /*
1.139 yamt 1739: * Invalidate access cache if uid, gid, mode or ctime changed.
1.101 fvdl 1740: */
1741: if (np->n_accstamp != -1 &&
1.139 yamt 1742: (gid != vap->va_gid || uid != vap->va_uid || vmode != vap->va_mode
1743: || timespeccmp(&ctime, &vap->va_ctime, !=)))
1.101 fvdl 1744: np->n_accstamp = -1;
1745:
1.12 mycroft 1746: vap->va_type = vtyp;
1.101 fvdl 1747: vap->va_mode = vmode;
1.12 mycroft 1748: vap->va_rdev = (dev_t)rdev;
1749: vap->va_mtime = mtime;
1.139 yamt 1750: vap->va_ctime = ctime;
1.133 christos 1751: vap->va_fsid = vp->v_mount->mnt_stat.f_fsidx.__fsid_val[0];
1.72 fvdl 1752: switch (vtyp) {
1753: case VDIR:
1754: vap->va_blocksize = NFS_DIRFRAGSIZ;
1755: break;
1756: case VBLK:
1757: vap->va_blocksize = BLKDEV_IOSIZE;
1758: break;
1759: case VCHR:
1760: vap->va_blocksize = MAXBSIZE;
1761: break;
1762: default:
1763: vap->va_blocksize = v3 ? vp->v_mount->mnt_stat.f_iosize :
1764: fxdr_unsigned(int32_t, fp->fa2_blocksize);
1765: break;
1766: }
1.25 fvdl 1767: if (v3) {
1768: vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink);
1.101 fvdl 1769: vap->va_uid = uid;
1770: vap->va_gid = gid;
1.66 fair 1771: vap->va_size = fxdr_hyper(&fp->fa3_size);
1772: vap->va_bytes = fxdr_hyper(&fp->fa3_used);
1.149.2.2 yamt 1773: vap->va_fileid = fxdr_hyper(&fp->fa3_fileid);
1.25 fvdl 1774: fxdr_nfsv3time(&fp->fa3_atime, &vap->va_atime);
1775: vap->va_flags = 0;
1776: vap->va_filerev = 0;
1.12 mycroft 1777: } else {
1.25 fvdl 1778: vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink);
1.101 fvdl 1779: vap->va_uid = uid;
1780: vap->va_gid = gid;
1.25 fvdl 1781: vap->va_size = fxdr_unsigned(u_int32_t, fp->fa2_size);
1782: vap->va_bytes = fxdr_unsigned(int32_t, fp->fa2_blocks)
1783: * NFS_FABLKSIZE;
1784: vap->va_fileid = fxdr_unsigned(int32_t, fp->fa2_fileid);
1785: fxdr_nfsv2time(&fp->fa2_atime, &vap->va_atime);
1.12 mycroft 1786: vap->va_flags = 0;
1.25 fvdl 1787: vap->va_gen = fxdr_unsigned(u_int32_t,fp->fa2_ctime.nfsv2_usec);
1.12 mycroft 1788: vap->va_filerev = 0;
1789: }
1790: if (vap->va_size != np->n_size) {
1.89 chs 1791: if ((np->n_flag & NMODIFIED) && vap->va_size < np->n_size) {
1792: vap->va_size = np->n_size;
1793: } else {
1.12 mycroft 1794: np->n_size = vap->va_size;
1.89 chs 1795: if (vap->va_type == VREG) {
1.140 yamt 1796: /*
1797: * we can't free pages if NAC_NOTRUNC because
1798: * the pages can be owned by ourselves.
1799: */
1800: if (flags & NAC_NOTRUNC) {
1.105 yamt 1801: np->n_flag |= NTRUNCDELAYED;
1.140 yamt 1802: } else {
1.149.2.3 yamt 1803: genfs_node_wrlock(vp);
1.149.2.8! yamt 1804: mutex_enter(&vp->v_interlock);
1.140 yamt 1805: (void)VOP_PUTPAGES(vp, 0,
1806: 0, PGO_SYNCIO | PGO_CLEANIT |
1807: PGO_FREE | PGO_ALLPAGES);
1.105 yamt 1808: uvm_vnp_setsize(vp, np->n_size);
1.149.2.3 yamt 1809: genfs_node_unlock(vp);
1.105 yamt 1810: }
1.89 chs 1811: }
1812: }
1.12 mycroft 1813: }
1.149.2.2 yamt 1814: np->n_attrstamp = time_second;
1.12 mycroft 1815: if (vaper != NULL) {
1.149.2.5 yamt 1816: memcpy((void *)vaper, (void *)vap, sizeof(*vap));
1.12 mycroft 1817: if (np->n_flag & NCHG) {
1.25 fvdl 1818: if (np->n_flag & NACC)
1819: vaper->va_atime = np->n_atim;
1820: if (np->n_flag & NUPD)
1821: vaper->va_mtime = np->n_mtim;
1.12 mycroft 1822: }
1823: }
1824: return (0);
1825: }
1826:
1827: /*
1828: * Check the time stamp
1829: * If the cache is valid, copy contents to *vap and return 0
1830: * otherwise return an error
1831: */
1.24 christos 1832: int
1.12 mycroft 1833: nfs_getattrcache(vp, vaper)
1.75 augustss 1834: struct vnode *vp;
1.12 mycroft 1835: struct vattr *vaper;
1836: {
1.75 augustss 1837: struct nfsnode *np = VTONFS(vp);
1.149.2.2 yamt 1838: struct nfsmount *nmp = VFSTONFS(vp->v_mount);
1.75 augustss 1839: struct vattr *vap;
1.12 mycroft 1840:
1.132 yamt 1841: if (np->n_attrstamp == 0 ||
1.149.2.6 yamt 1842: (time_second - np->n_attrstamp) >= nfs_attrtimeo(nmp, np)) {
1.12 mycroft 1843: nfsstats.attrcache_misses++;
1844: return (ENOENT);
1845: }
1846: nfsstats.attrcache_hits++;
1.49 fvdl 1847: vap = np->n_vattr;
1.12 mycroft 1848: if (vap->va_size != np->n_size) {
1849: if (vap->va_type == VREG) {
1.149.2.5 yamt 1850: if ((np->n_flag & NMODIFIED) != 0 &&
1851: vap->va_size < np->n_size) {
1852: vap->va_size = np->n_size;
1853: } else {
1.12 mycroft 1854: np->n_size = vap->va_size;
1.149.2.5 yamt 1855: }
1.149.2.3 yamt 1856: genfs_node_wrlock(vp);
1.51 mrg 1857: uvm_vnp_setsize(vp, np->n_size);
1.149.2.3 yamt 1858: genfs_node_unlock(vp);
1.12 mycroft 1859: } else
1860: np->n_size = vap->va_size;
1861: }
1.149.2.5 yamt 1862: memcpy((void *)vaper, (void *)vap, sizeof(struct vattr));
1.12 mycroft 1863: if (np->n_flag & NCHG) {
1.25 fvdl 1864: if (np->n_flag & NACC)
1865: vaper->va_atime = np->n_atim;
1866: if (np->n_flag & NUPD)
1867: vaper->va_mtime = np->n_mtim;
1.1 cgd 1868: }
1.12 mycroft 1869: return (0);
1.105 yamt 1870: }
1871:
1872: void
1873: nfs_delayedtruncate(vp)
1874: struct vnode *vp;
1875: {
1876: struct nfsnode *np = VTONFS(vp);
1877:
1878: if (np->n_flag & NTRUNCDELAYED) {
1879: np->n_flag &= ~NTRUNCDELAYED;
1.149.2.3 yamt 1880: genfs_node_wrlock(vp);
1.149.2.8! yamt 1881: mutex_enter(&vp->v_interlock);
1.140 yamt 1882: (void)VOP_PUTPAGES(vp, 0,
1883: 0, PGO_SYNCIO | PGO_CLEANIT | PGO_FREE | PGO_ALLPAGES);
1.105 yamt 1884: uvm_vnp_setsize(vp, np->n_size);
1.149.2.3 yamt 1885: genfs_node_unlock(vp);
1.105 yamt 1886: }
1.1 cgd 1887: }
1.48 fvdl 1888:
1.141 yamt 1889: #define NFS_WCCKLUDGE_TIMEOUT (24 * 60 * 60) /* 1 day */
1890: #define NFS_WCCKLUDGE(nmp, now) \
1891: (((nmp)->nm_iflag & NFSMNT_WCCKLUDGE) && \
1892: ((now) - (nmp)->nm_wcckludgetime - NFS_WCCKLUDGE_TIMEOUT) < 0)
1893:
1894: /*
1895: * nfs_check_wccdata: check inaccurate wcc_data
1896: *
1897: * => return non-zero if we shouldn't trust the wcc_data.
1898: * => NFS_WCCKLUDGE_TIMEOUT is for the case that the server is "fixed".
1899: */
1900:
1901: int
1902: nfs_check_wccdata(struct nfsnode *np, const struct timespec *ctime,
1.149.2.4 yamt 1903: struct timespec *mtime, bool docheck)
1.141 yamt 1904: {
1905: int error = 0;
1906:
1907: #if !defined(NFS_V2_ONLY)
1908:
1909: if (docheck) {
1910: struct vnode *vp = NFSTOV(np);
1911: struct nfsmount *nmp;
1.149.2.2 yamt 1912: long now = time_second;
1.149.2.5 yamt 1913: const struct timespec *omtime = &np->n_vattr->va_mtime;
1914: const struct timespec *octime = &np->n_vattr->va_ctime;
1.141 yamt 1915: #if defined(DEBUG)
1916: const char *reason = NULL; /* XXX: gcc */
1917: #endif
1918:
1.149.2.5 yamt 1919: if (timespeccmp(omtime, mtime, <=)) {
1.141 yamt 1920: #if defined(DEBUG)
1921: reason = "mtime";
1922: #endif
1923: error = EINVAL;
1924: }
1925:
1.149.2.5 yamt 1926: if (vp->v_type == VDIR && timespeccmp(octime, ctime, <=)) {
1.141 yamt 1927: #if defined(DEBUG)
1928: reason = "ctime";
1929: #endif
1930: error = EINVAL;
1931: }
1932:
1933: nmp = VFSTONFS(vp->v_mount);
1934: if (error) {
1.143 yamt 1935:
1936: /*
1937: * despite of the fact that we've updated the file,
1938: * timestamps of the file were not updated as we
1939: * expected.
1940: * it means that the server has incompatible
1941: * semantics of timestamps or (more likely)
1942: * the server time is not precise enough to
1943: * track each modifications.
1944: * in that case, we disable wcc processing.
1945: *
1946: * yes, strictly speaking, we should disable all
1947: * caching. it's a compromise.
1948: */
1949:
1.149.2.5 yamt 1950: mutex_enter(&nmp->nm_lock);
1.141 yamt 1951: #if defined(DEBUG)
1952: if (!NFS_WCCKLUDGE(nmp, now)) {
1953: printf("%s: inaccurate wcc data (%s) detected,"
1.149.2.5 yamt 1954: " disabling wcc"
1955: " (ctime %u.%09u %u.%09u,"
1956: " mtime %u.%09u %u.%09u)\n",
1.141 yamt 1957: vp->v_mount->mnt_stat.f_mntfromname,
1.149.2.5 yamt 1958: reason,
1959: (unsigned int)octime->tv_sec,
1960: (unsigned int)octime->tv_nsec,
1961: (unsigned int)ctime->tv_sec,
1962: (unsigned int)ctime->tv_nsec,
1963: (unsigned int)omtime->tv_sec,
1964: (unsigned int)omtime->tv_nsec,
1965: (unsigned int)mtime->tv_sec,
1966: (unsigned int)mtime->tv_nsec);
1.141 yamt 1967: }
1968: #endif
1969: nmp->nm_iflag |= NFSMNT_WCCKLUDGE;
1970: nmp->nm_wcckludgetime = now;
1.149.2.5 yamt 1971: mutex_exit(&nmp->nm_lock);
1.141 yamt 1972: } else if (NFS_WCCKLUDGE(nmp, now)) {
1973: error = EPERM; /* XXX */
1974: } else if (nmp->nm_iflag & NFSMNT_WCCKLUDGE) {
1.149.2.5 yamt 1975: mutex_enter(&nmp->nm_lock);
1.141 yamt 1976: if (nmp->nm_iflag & NFSMNT_WCCKLUDGE) {
1977: #if defined(DEBUG)
1978: printf("%s: re-enabling wcc\n",
1979: vp->v_mount->mnt_stat.f_mntfromname);
1980: #endif
1981: nmp->nm_iflag &= ~NFSMNT_WCCKLUDGE;
1982: }
1.149.2.5 yamt 1983: mutex_exit(&nmp->nm_lock);
1.141 yamt 1984: }
1985: }
1986:
1987: #endif /* !defined(NFS_V2_ONLY) */
1988:
1989: return error;
1990: }
1991:
1.48 fvdl 1992: /*
1993: * Heuristic to see if the server XDR encodes directory cookies or not.
1994: * it is not supposed to, but a lot of servers may do this. Also, since
1995: * most/all servers will implement V2 as well, it is expected that they
1996: * may return just 32 bits worth of cookie information, so we need to
1997: * find out in which 32 bits this information is available. We do this
1998: * to avoid trouble with emulated binaries that can't handle 64 bit
1999: * directory offsets.
2000: */
2001:
2002: void
1.149.2.2 yamt 2003: nfs_cookieheuristic(vp, flagp, l, cred)
1.48 fvdl 2004: struct vnode *vp;
2005: int *flagp;
1.149.2.2 yamt 2006: struct lwp *l;
2007: kauth_cred_t cred;
1.48 fvdl 2008: {
2009: struct uio auio;
2010: struct iovec aiov;
1.149.2.5 yamt 2011: char *tbuf, *cp;
1.48 fvdl 2012: struct dirent *dp;
1.57 fvdl 2013: off_t *cookies = NULL, *cop;
1.48 fvdl 2014: int error, eof, nc, len;
2015:
1.149.2.5 yamt 2016: MALLOC(tbuf, void *, NFS_DIRFRAGSIZ, M_TEMP, M_WAITOK);
1.48 fvdl 2017:
1.149 christos 2018: aiov.iov_base = tbuf;
1.48 fvdl 2019: aiov.iov_len = NFS_DIRFRAGSIZ;
2020: auio.uio_iov = &aiov;
2021: auio.uio_iovcnt = 1;
2022: auio.uio_rw = UIO_READ;
2023: auio.uio_resid = NFS_DIRFRAGSIZ;
2024: auio.uio_offset = 0;
1.149.2.2 yamt 2025: UIO_SETUP_SYSSPACE(&auio);
1.48 fvdl 2026:
1.56 fvdl 2027: error = VOP_READDIR(vp, &auio, cred, &eof, &cookies, &nc);
1.48 fvdl 2028:
2029: len = NFS_DIRFRAGSIZ - auio.uio_resid;
2030: if (error || len == 0) {
1.149 christos 2031: FREE(tbuf, M_TEMP);
1.57 fvdl 2032: if (cookies)
1.80 thorpej 2033: free(cookies, M_TEMP);
1.48 fvdl 2034: return;
2035: }
2036:
2037: /*
2038: * Find the first valid entry and look at its offset cookie.
2039: */
2040:
1.149 christos 2041: cp = tbuf;
1.48 fvdl 2042: for (cop = cookies; len > 0; len -= dp->d_reclen) {
2043: dp = (struct dirent *)cp;
2044: if (dp->d_fileno != 0 && len >= dp->d_reclen) {
2045: if ((*cop >> 32) != 0 && (*cop & 0xffffffffLL) == 0) {
2046: *flagp |= NFSMNT_SWAPCOOKIE;
1.49 fvdl 2047: nfs_invaldircache(vp, 0);
1.149.2.2 yamt 2048: nfs_vinvalbuf(vp, 0, cred, l, 1);
1.48 fvdl 2049: }
2050: break;
2051: }
2052: cop++;
2053: cp += dp->d_reclen;
2054: }
2055:
1.149 christos 2056: FREE(tbuf, M_TEMP);
1.80 thorpej 2057: free(cookies, M_TEMP);
1.48 fvdl 2058: }
1.38 thorpej 2059: #endif /* NFS */
1.1 cgd 2060:
1.149.2.2 yamt 2061: #ifdef NFSSERVER
1.1 cgd 2062: /*
1.43 fvdl 2063: * Set up nameidata for a lookup() call and do it.
2064: *
2065: * If pubflag is set, this call is done for a lookup operation on the
2066: * public filehandle. In that case we allow crossing mountpoints and
2067: * absolute pathnames. However, the caller is expected to check that
2068: * the lookup result is within the public fs, and deny access if
2069: * it is not.
1.1 cgd 2070: */
1.24 christos 2071: int
1.149.2.3 yamt 2072: nfs_namei(ndp, nsfh, len, slp, nam, mdp, dposp, retdirp, l, kerbflag, pubflag)
1.75 augustss 2073: struct nameidata *ndp;
1.149.2.3 yamt 2074: nfsrvfh_t *nsfh;
1.110 yamt 2075: uint32_t len;
1.12 mycroft 2076: struct nfssvc_sock *slp;
2077: struct mbuf *nam;
1.1 cgd 2078: struct mbuf **mdp;
1.149.2.5 yamt 2079: char **dposp;
1.25 fvdl 2080: struct vnode **retdirp;
1.149.2.2 yamt 2081: struct lwp *l;
1.43 fvdl 2082: int kerbflag, pubflag;
1.1 cgd 2083: {
1.75 augustss 2084: int i, rem;
2085: struct mbuf *md;
2086: char *fromcp, *tocp, *cp;
1.43 fvdl 2087: struct iovec aiov;
2088: struct uio auio;
1.1 cgd 2089: struct vnode *dp;
1.43 fvdl 2090: int error, rdonly, linklen;
1.12 mycroft 2091: struct componentname *cnp = &ndp->ni_cnd;
1.1 cgd 2092:
1.149.2.3 yamt 2093: *retdirp = NULL;
1.81 thorpej 2094:
2095: if ((len + 1) > MAXPATHLEN)
2096: return (ENAMETOOLONG);
1.147 yamt 2097: if (len == 0)
2098: return (EACCES);
1.81 thorpej 2099: cnp->cn_pnbuf = PNBUF_GET();
2100:
1.1 cgd 2101: /*
2102: * Copy the name from the mbuf list to ndp->ni_pnbuf
2103: * and set the various ndp fields appropriately.
2104: */
2105: fromcp = *dposp;
1.12 mycroft 2106: tocp = cnp->cn_pnbuf;
1.1 cgd 2107: md = *mdp;
1.149.2.5 yamt 2108: rem = mtod(md, char *) + md->m_len - fromcp;
1.1 cgd 2109: for (i = 0; i < len; i++) {
2110: while (rem == 0) {
2111: md = md->m_next;
2112: if (md == NULL) {
2113: error = EBADRPC;
2114: goto out;
2115: }
1.149.2.5 yamt 2116: fromcp = mtod(md, void *);
1.1 cgd 2117: rem = md->m_len;
2118: }
1.43 fvdl 2119: if (*fromcp == '\0' || (!pubflag && *fromcp == '/')) {
1.25 fvdl 2120: error = EACCES;
1.1 cgd 2121: goto out;
2122: }
2123: *tocp++ = *fromcp++;
2124: rem--;
2125: }
2126: *tocp = '\0';
2127: *mdp = md;
2128: *dposp = fromcp;
2129: len = nfsm_rndup(len)-len;
2130: if (len > 0) {
2131: if (rem >= len)
2132: *dposp += len;
1.24 christos 2133: else if ((error = nfs_adv(mdp, dposp, len, rem)) != 0)
1.1 cgd 2134: goto out;
2135: }
1.43 fvdl 2136:
1.1 cgd 2137: /*
2138: * Extract and set starting directory.
2139: */
1.149.2.4 yamt 2140: error = nfsrv_fhtovp(nsfh, false, &dp, ndp->ni_cnd.cn_cred, slp,
1.124 thorpej 2141: nam, &rdonly, kerbflag, pubflag);
1.24 christos 2142: if (error)
1.1 cgd 2143: goto out;
2144: if (dp->v_type != VDIR) {
2145: vrele(dp);
2146: error = ENOTDIR;
2147: goto out;
2148: }
1.43 fvdl 2149:
2150: if (rdonly)
2151: cnp->cn_flags |= RDONLY;
2152:
2153: *retdirp = dp;
2154:
2155: if (pubflag) {
2156: /*
2157: * Oh joy. For WebNFS, handle those pesky '%' escapes,
2158: * and the 'native path' indicator.
2159: */
1.81 thorpej 2160: cp = PNBUF_GET();
1.43 fvdl 2161: fromcp = cnp->cn_pnbuf;
2162: tocp = cp;
2163: if ((unsigned char)*fromcp >= WEBNFS_SPECCHAR_START) {
2164: switch ((unsigned char)*fromcp) {
2165: case WEBNFS_NATIVE_CHAR:
2166: /*
2167: * 'Native' path for us is the same
2168: * as a path according to the NFS spec,
2169: * just skip the escape char.
2170: */
2171: fromcp++;
2172: break;
2173: /*
2174: * More may be added in the future, range 0x80-0xff
2175: */
2176: default:
2177: error = EIO;
1.149.2.3 yamt 2178: vrele(dp);
1.104 enami 2179: PNBUF_PUT(cp);
1.43 fvdl 2180: goto out;
2181: }
2182: }
2183: /*
2184: * Translate the '%' escapes, URL-style.
2185: */
2186: while (*fromcp != '\0') {
2187: if (*fromcp == WEBNFS_ESC_CHAR) {
2188: if (fromcp[1] != '\0' && fromcp[2] != '\0') {
2189: fromcp++;
2190: *tocp++ = HEXSTRTOI(fromcp);
2191: fromcp += 2;
2192: continue;
2193: } else {
2194: error = ENOENT;
1.149.2.3 yamt 2195: vrele(dp);
1.104 enami 2196: PNBUF_PUT(cp);
1.43 fvdl 2197: goto out;
2198: }
2199: } else
2200: *tocp++ = *fromcp++;
2201: }
2202: *tocp = '\0';
1.81 thorpej 2203: PNBUF_PUT(cnp->cn_pnbuf);
1.43 fvdl 2204: cnp->cn_pnbuf = cp;
2205: }
2206:
2207: ndp->ni_pathlen = (tocp - cnp->cn_pnbuf) + 1;
2208: ndp->ni_segflg = UIO_SYSSPACE;
1.98 fvdl 2209: ndp->ni_rootdir = rootvnode;
1.149.2.5 yamt 2210: ndp->ni_erootdir = NULL;
1.43 fvdl 2211:
2212: if (pubflag) {
2213: ndp->ni_loopcnt = 0;
2214: if (cnp->cn_pnbuf[0] == '/')
2215: dp = rootvnode;
2216: } else {
2217: cnp->cn_flags |= NOCROSSMOUNT;
2218: }
2219:
1.25 fvdl 2220: VREF(dp);
1.149.2.3 yamt 2221: vn_lock(dp, LK_EXCLUSIVE | LK_RETRY);
1.43 fvdl 2222:
2223: for (;;) {
2224: cnp->cn_nameptr = cnp->cn_pnbuf;
1.1 cgd 2225: ndp->ni_startdir = dp;
1.149.2.3 yamt 2226:
1.1 cgd 2227: /*
2228: * And call lookup() to do the real work
2229: */
1.25 fvdl 2230: error = lookup(ndp);
1.91 fvdl 2231: if (error) {
1.149.2.3 yamt 2232: if (ndp->ni_dvp) {
2233: vput(ndp->ni_dvp);
2234: }
1.91 fvdl 2235: PNBUF_PUT(cnp->cn_pnbuf);
2236: return (error);
2237: }
1.149.2.3 yamt 2238:
1.1 cgd 2239: /*
2240: * Check for encountering a symbolic link
2241: */
1.43 fvdl 2242: if ((cnp->cn_flags & ISSYMLINK) == 0) {
1.149.2.3 yamt 2243: if ((cnp->cn_flags & LOCKPARENT) == 0 && ndp->ni_dvp) {
2244: if (ndp->ni_dvp == ndp->ni_vp) {
2245: vrele(ndp->ni_dvp);
2246: } else {
2247: vput(ndp->ni_dvp);
2248: }
2249: }
1.91 fvdl 2250: if (cnp->cn_flags & (SAVENAME | SAVESTART))
1.43 fvdl 2251: cnp->cn_flags |= HASBUF;
1.91 fvdl 2252: else
2253: PNBUF_PUT(cnp->cn_pnbuf);
2254: return (0);
1.43 fvdl 2255: } else {
2256: if (!pubflag) {
2257: error = EINVAL;
2258: break;
2259: }
2260: if (ndp->ni_loopcnt++ >= MAXSYMLINKS) {
2261: error = ELOOP;
2262: break;
2263: }
1.91 fvdl 2264: if (ndp->ni_vp->v_mount->mnt_flag & MNT_SYMPERM) {
1.149.2.7 yamt 2265: error = VOP_ACCESS(ndp->ni_vp, VEXEC, cnp->cn_cred);
1.91 fvdl 2266: if (error != 0)
2267: break;
2268: }
1.43 fvdl 2269: if (ndp->ni_pathlen > 1)
1.81 thorpej 2270: cp = PNBUF_GET();
1.1 cgd 2271: else
1.43 fvdl 2272: cp = cnp->cn_pnbuf;
2273: aiov.iov_base = cp;
2274: aiov.iov_len = MAXPATHLEN;
2275: auio.uio_iov = &aiov;
2276: auio.uio_iovcnt = 1;
2277: auio.uio_offset = 0;
2278: auio.uio_rw = UIO_READ;
2279: auio.uio_resid = MAXPATHLEN;
1.149.2.2 yamt 2280: UIO_SETUP_SYSSPACE(&auio);
1.43 fvdl 2281: error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred);
2282: if (error) {
1.149.2.3 yamt 2283: badlink:
1.43 fvdl 2284: if (ndp->ni_pathlen > 1)
1.81 thorpej 2285: PNBUF_PUT(cp);
1.43 fvdl 2286: break;
2287: }
2288: linklen = MAXPATHLEN - auio.uio_resid;
2289: if (linklen == 0) {
2290: error = ENOENT;
2291: goto badlink;
2292: }
2293: if (linklen + ndp->ni_pathlen >= MAXPATHLEN) {
2294: error = ENAMETOOLONG;
2295: goto badlink;
2296: }
2297: if (ndp->ni_pathlen > 1) {
1.63 perry 2298: memcpy(cp + linklen, ndp->ni_next, ndp->ni_pathlen);
1.81 thorpej 2299: PNBUF_PUT(cnp->cn_pnbuf);
1.43 fvdl 2300: cnp->cn_pnbuf = cp;
2301: } else
2302: cnp->cn_pnbuf[linklen] = '\0';
2303: ndp->ni_pathlen += linklen;
1.1 cgd 2304: vput(ndp->ni_vp);
1.43 fvdl 2305: dp = ndp->ni_dvp;
1.149.2.3 yamt 2306:
1.43 fvdl 2307: /*
2308: * Check if root directory should replace current directory.
2309: */
2310: if (cnp->cn_pnbuf[0] == '/') {
1.149.2.3 yamt 2311: vput(dp);
1.43 fvdl 2312: dp = ndp->ni_rootdir;
2313: VREF(dp);
1.149.2.3 yamt 2314: vn_lock(dp, LK_EXCLUSIVE | LK_RETRY);
1.43 fvdl 2315: }
1.1 cgd 2316: }
1.43 fvdl 2317: }
1.149.2.3 yamt 2318: vput(ndp->ni_dvp);
1.91 fvdl 2319: vput(ndp->ni_vp);
2320: ndp->ni_vp = NULL;
1.1 cgd 2321: out:
1.81 thorpej 2322: PNBUF_PUT(cnp->cn_pnbuf);
1.1 cgd 2323: return (error);
2324: }
1.149.2.2 yamt 2325: #endif /* NFSSERVER */
1.1 cgd 2326:
2327: /*
1.118 yamt 2328: * A fiddled version of m_adj() that ensures null fill to a 32-bit
1.1 cgd 2329: * boundary and only trims off the back end
1.122 yamt 2330: *
2331: * 1. trim off 'len' bytes as m_adj(mp, -len).
2332: * 2. add zero-padding 'nul' bytes at the end of the mbuf chain.
1.1 cgd 2333: */
1.12 mycroft 2334: void
1.122 yamt 2335: nfs_zeropad(mp, len, nul)
1.1 cgd 2336: struct mbuf *mp;
1.75 augustss 2337: int len;
1.1 cgd 2338: int nul;
2339: {
1.75 augustss 2340: struct mbuf *m;
1.130 yamt 2341: int count;
1.1 cgd 2342:
2343: /*
2344: * Trim from tail. Scan the mbuf chain,
2345: * calculating its length and finding the last mbuf.
2346: * If the adjustment only affects this mbuf, then just
2347: * adjust and return. Otherwise, rescan and truncate
2348: * after the remaining size.
2349: */
2350: count = 0;
2351: m = mp;
2352: for (;;) {
2353: count += m->m_len;
1.122 yamt 2354: if (m->m_next == NULL)
1.1 cgd 2355: break;
2356: m = m->m_next;
2357: }
1.122 yamt 2358:
2359: KDASSERT(count >= len);
2360:
2361: if (m->m_len >= len) {
1.1 cgd 2362: m->m_len -= len;
1.122 yamt 2363: } else {
2364: count -= len;
2365: /*
2366: * Correct length for chain is "count".
2367: * Find the mbuf with last data, adjust its length,
2368: * and toss data from remaining mbufs on chain.
2369: */
2370: for (m = mp; m; m = m->m_next) {
2371: if (m->m_len >= count) {
2372: m->m_len = count;
2373: break;
1.118 yamt 2374: }
1.122 yamt 2375: count -= m->m_len;
1.1 cgd 2376: }
1.149.2.2 yamt 2377: KASSERT(m && m->m_next);
1.122 yamt 2378: m_freem(m->m_next);
2379: m->m_next = NULL;
1.1 cgd 2380: }
1.122 yamt 2381:
1.130 yamt 2382: KDASSERT(m->m_next == NULL);
2383:
1.122 yamt 2384: /*
2385: * zero-padding.
2386: */
2387: if (nul > 0) {
1.130 yamt 2388: char *cp;
2389: int i;
2390:
1.122 yamt 2391: if (M_ROMAP(m) || M_TRAILINGSPACE(m) < nul) {
2392: struct mbuf *n;
2393:
2394: KDASSERT(MLEN >= nul);
2395: n = m_get(M_WAIT, MT_DATA);
2396: MCLAIM(n, &nfs_mowner);
2397: n->m_len = nul;
1.130 yamt 2398: n->m_next = NULL;
1.122 yamt 2399: m->m_next = n;
1.149.2.5 yamt 2400: cp = mtod(n, void *);
1.122 yamt 2401: } else {
1.149.2.5 yamt 2402: cp = mtod(m, char *) + m->m_len;
1.122 yamt 2403: m->m_len += nul;
1.1 cgd 2404: }
1.122 yamt 2405: for (i = 0; i < nul; i++)
2406: *cp++ = '\0';
1.1 cgd 2407: }
1.122 yamt 2408: return;
1.1 cgd 2409: }
2410:
2411: /*
1.25 fvdl 2412: * Make these functions instead of macros, so that the kernel text size
2413: * doesn't get too big...
2414: */
2415: void
2416: nfsm_srvwcc(nfsd, before_ret, before_vap, after_ret, after_vap, mbp, bposp)
2417: struct nfsrv_descript *nfsd;
2418: int before_ret;
1.75 augustss 2419: struct vattr *before_vap;
1.25 fvdl 2420: int after_ret;
2421: struct vattr *after_vap;
2422: struct mbuf **mbp;
2423: char **bposp;
2424: {
1.109 matt 2425: struct mbuf *mb = *mbp;
1.75 augustss 2426: char *bpos = *bposp;
2427: u_int32_t *tl;
1.25 fvdl 2428:
2429: if (before_ret) {
2430: nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED);
2431: *tl = nfs_false;
2432: } else {
2433: nfsm_build(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
2434: *tl++ = nfs_true;
1.66 fair 2435: txdr_hyper(before_vap->va_size, tl);
1.25 fvdl 2436: tl += 2;
2437: txdr_nfsv3time(&(before_vap->va_mtime), tl);
2438: tl += 2;
2439: txdr_nfsv3time(&(before_vap->va_ctime), tl);
2440: }
2441: *bposp = bpos;
2442: *mbp = mb;
2443: nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp);
2444: }
2445:
2446: void
2447: nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp)
2448: struct nfsrv_descript *nfsd;
2449: int after_ret;
2450: struct vattr *after_vap;
2451: struct mbuf **mbp;
2452: char **bposp;
2453: {
1.109 matt 2454: struct mbuf *mb = *mbp;
1.75 augustss 2455: char *bpos = *bposp;
2456: u_int32_t *tl;
2457: struct nfs_fattr *fp;
1.25 fvdl 2458:
2459: if (after_ret) {
2460: nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED);
2461: *tl = nfs_false;
2462: } else {
2463: nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_V3FATTR);
2464: *tl++ = nfs_true;
2465: fp = (struct nfs_fattr *)tl;
2466: nfsm_srvfattr(nfsd, after_vap, fp);
2467: }
2468: *mbp = mb;
2469: *bposp = bpos;
2470: }
2471:
2472: void
2473: nfsm_srvfattr(nfsd, vap, fp)
1.75 augustss 2474: struct nfsrv_descript *nfsd;
2475: struct vattr *vap;
2476: struct nfs_fattr *fp;
1.25 fvdl 2477: {
2478:
2479: fp->fa_nlink = txdr_unsigned(vap->va_nlink);
2480: fp->fa_uid = txdr_unsigned(vap->va_uid);
2481: fp->fa_gid = txdr_unsigned(vap->va_gid);
2482: if (nfsd->nd_flag & ND_NFSV3) {
2483: fp->fa_type = vtonfsv3_type(vap->va_type);
2484: fp->fa_mode = vtonfsv3_mode(vap->va_mode);
1.66 fair 2485: txdr_hyper(vap->va_size, &fp->fa3_size);
2486: txdr_hyper(vap->va_bytes, &fp->fa3_used);
1.25 fvdl 2487: fp->fa3_rdev.specdata1 = txdr_unsigned(major(vap->va_rdev));
2488: fp->fa3_rdev.specdata2 = txdr_unsigned(minor(vap->va_rdev));
2489: fp->fa3_fsid.nfsuquad[0] = 0;
2490: fp->fa3_fsid.nfsuquad[1] = txdr_unsigned(vap->va_fsid);
1.149.2.2 yamt 2491: txdr_hyper(vap->va_fileid, &fp->fa3_fileid);
1.25 fvdl 2492: txdr_nfsv3time(&vap->va_atime, &fp->fa3_atime);
2493: txdr_nfsv3time(&vap->va_mtime, &fp->fa3_mtime);
2494: txdr_nfsv3time(&vap->va_ctime, &fp->fa3_ctime);
2495: } else {
2496: fp->fa_type = vtonfsv2_type(vap->va_type);
2497: fp->fa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode);
2498: fp->fa2_size = txdr_unsigned(vap->va_size);
2499: fp->fa2_blocksize = txdr_unsigned(vap->va_blocksize);
2500: if (vap->va_type == VFIFO)
2501: fp->fa2_rdev = 0xffffffff;
2502: else
2503: fp->fa2_rdev = txdr_unsigned(vap->va_rdev);
2504: fp->fa2_blocks = txdr_unsigned(vap->va_bytes / NFS_FABLKSIZE);
2505: fp->fa2_fsid = txdr_unsigned(vap->va_fsid);
2506: fp->fa2_fileid = txdr_unsigned(vap->va_fileid);
2507: txdr_nfsv2time(&vap->va_atime, &fp->fa2_atime);
2508: txdr_nfsv2time(&vap->va_mtime, &fp->fa2_mtime);
2509: txdr_nfsv2time(&vap->va_ctime, &fp->fa2_ctime);
2510: }
2511: }
2512:
1.149.2.2 yamt 2513: #ifdef NFSSERVER
1.25 fvdl 2514: /*
1.1 cgd 2515: * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked)
2516: * - look up fsid in mount list (if not found ret error)
1.12 mycroft 2517: * - get vp and export rights by calling VFS_FHTOVP()
2518: * - if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon
1.1 cgd 2519: * - if not lockflag unlock it with VOP_UNLOCK()
2520: */
1.24 christos 2521: int
1.149.2.3 yamt 2522: nfsrv_fhtovp(nfsrvfh_t *nsfh, int lockflag, struct vnode **vpp,
2523: kauth_cred_t cred, struct nfssvc_sock *slp, struct mbuf *nam, int *rdonlyp,
2524: int kerbflag, int pubflag)
1.1 cgd 2525: {
1.75 augustss 2526: struct mount *mp;
1.149.2.2 yamt 2527: kauth_cred_t credanon;
1.12 mycroft 2528: int error, exflags;
1.40 fvdl 2529: struct sockaddr_in *saddr;
1.149.2.3 yamt 2530: fhandle_t *fhp;
1.1 cgd 2531:
1.149.2.3 yamt 2532: fhp = NFSRVFH_FHANDLE(nsfh);
1.12 mycroft 2533: *vpp = (struct vnode *)0;
1.43 fvdl 2534:
1.149.2.3 yamt 2535: if (nfs_ispublicfh(nsfh)) {
1.43 fvdl 2536: if (!pubflag || !nfs_pub.np_valid)
2537: return (ESTALE);
1.149.2.3 yamt 2538: fhp = nfs_pub.np_handle;
1.43 fvdl 2539: }
2540:
1.149.2.2 yamt 2541: error = netexport_check(&fhp->fh_fsid, nam, &mp, &exflags, &credanon);
2542: if (error) {
2543: return error;
2544: }
2545:
1.124 thorpej 2546: error = VFS_FHTOVP(mp, &fhp->fh_fid, vpp);
1.24 christos 2547: if (error)
1.12 mycroft 2548: return (error);
1.40 fvdl 2549:
1.43 fvdl 2550: if (!(exflags & (MNT_EXNORESPORT|MNT_EXPUBLIC))) {
1.40 fvdl 2551: saddr = mtod(nam, struct sockaddr_in *);
1.76 fvdl 2552: if ((saddr->sin_family == AF_INET) &&
1.40 fvdl 2553: ntohs(saddr->sin_port) >= IPPORT_RESERVED) {
2554: vput(*vpp);
2555: return (NFSERR_AUTHERR | AUTH_TOOWEAK);
2556: }
1.76 fvdl 2557: #ifdef INET6
2558: if ((saddr->sin_family == AF_INET6) &&
2559: ntohs(saddr->sin_port) >= IPV6PORT_RESERVED) {
2560: vput(*vpp);
2561: return (NFSERR_AUTHERR | AUTH_TOOWEAK);
2562: }
2563: #endif
1.40 fvdl 2564: }
1.12 mycroft 2565: /*
2566: * Check/setup credentials.
2567: */
2568: if (exflags & MNT_EXKERB) {
1.25 fvdl 2569: if (!kerbflag) {
1.12 mycroft 2570: vput(*vpp);
1.25 fvdl 2571: return (NFSERR_AUTHERR | AUTH_TOOWEAK);
1.12 mycroft 2572: }
1.25 fvdl 2573: } else if (kerbflag) {
2574: vput(*vpp);
2575: return (NFSERR_AUTHERR | AUTH_TOOWEAK);
1.149.2.2 yamt 2576: } else if (kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER,
2577: NULL) == 0 || (exflags & MNT_EXPORTANON)) {
2578: kauth_cred_clone(credanon, cred);
1.12 mycroft 2579: }
2580: if (exflags & MNT_EXRDONLY)
2581: *rdonlyp = 1;
2582: else
2583: *rdonlyp = 0;
1.1 cgd 2584: if (!lockflag)
1.56 fvdl 2585: VOP_UNLOCK(*vpp, 0);
1.1 cgd 2586: return (0);
1.43 fvdl 2587: }
2588:
2589: /*
2590: * WebNFS: check if a filehandle is a public filehandle. For v3, this
1.149.2.3 yamt 2591: * means a length of 0, for v2 it means all zeroes.
1.43 fvdl 2592: */
2593: int
1.149.2.3 yamt 2594: nfs_ispublicfh(const nfsrvfh_t *nsfh)
1.43 fvdl 2595: {
1.149.2.3 yamt 2596: const char *cp = (const void *)(NFSRVFH_DATA(nsfh));
1.43 fvdl 2597: int i;
2598:
1.149.2.3 yamt 2599: if (NFSRVFH_SIZE(nsfh) == 0) {
1.149.2.4 yamt 2600: return true;
1.149.2.3 yamt 2601: }
2602: if (NFSRVFH_SIZE(nsfh) != NFSX_V2FH) {
1.149.2.4 yamt 2603: return false;
1.149.2.3 yamt 2604: }
2605: for (i = 0; i < NFSX_V2FH; i++)
1.43 fvdl 2606: if (*cp++ != 0)
1.149.2.4 yamt 2607: return false;
2608: return true;
1.1 cgd 2609: }
1.149.2.2 yamt 2610: #endif /* NFSSERVER */
1.1 cgd 2611:
2612: /*
1.149.2.4 yamt 2613: * This function compares two net addresses by family and returns true
1.12 mycroft 2614: * if they are the same host.
1.149.2.4 yamt 2615: * If there is any doubt, return false.
1.12 mycroft 2616: * The AF_INET family is handled as a special case so that address mbufs
2617: * don't need to be saved to store "struct in_addr", which is only 4 bytes.
1.1 cgd 2618: */
1.24 christos 2619: int
1.12 mycroft 2620: netaddr_match(family, haddr, nam)
2621: int family;
2622: union nethostaddr *haddr;
2623: struct mbuf *nam;
1.1 cgd 2624: {
1.75 augustss 2625: struct sockaddr_in *inetaddr;
1.1 cgd 2626:
1.12 mycroft 2627: switch (family) {
2628: case AF_INET:
2629: inetaddr = mtod(nam, struct sockaddr_in *);
2630: if (inetaddr->sin_family == AF_INET &&
2631: inetaddr->sin_addr.s_addr == haddr->had_inetaddr)
2632: return (1);
2633: break;
1.76 fvdl 2634: #ifdef INET6
2635: case AF_INET6:
2636: {
2637: struct sockaddr_in6 *sin6_1, *sin6_2;
2638:
2639: sin6_1 = mtod(nam, struct sockaddr_in6 *);
2640: sin6_2 = mtod(haddr->had_nam, struct sockaddr_in6 *);
2641: if (sin6_1->sin6_family == AF_INET6 &&
2642: IN6_ARE_ADDR_EQUAL(&sin6_1->sin6_addr, &sin6_2->sin6_addr))
2643: return 1;
2644: }
2645: #endif
1.12 mycroft 2646: #ifdef ISO
2647: case AF_ISO:
2648: {
1.75 augustss 2649: struct sockaddr_iso *isoaddr1, *isoaddr2;
1.12 mycroft 2650:
2651: isoaddr1 = mtod(nam, struct sockaddr_iso *);
2652: isoaddr2 = mtod(haddr->had_nam, struct sockaddr_iso *);
2653: if (isoaddr1->siso_family == AF_ISO &&
2654: isoaddr1->siso_nlen > 0 &&
2655: isoaddr1->siso_nlen == isoaddr2->siso_nlen &&
2656: SAME_ISOADDR(isoaddr1, isoaddr2))
2657: return (1);
2658: break;
2659: }
2660: #endif /* ISO */
2661: default:
2662: break;
2663: };
2664: return (0);
1.25 fvdl 2665: }
2666:
2667: /*
2668: * The write verifier has changed (probably due to a server reboot), so all
1.114 yamt 2669: * PG_NEEDCOMMIT pages will have to be written again. Since they are marked
1.117 yamt 2670: * as dirty or are being written out just now, all this takes is clearing
2671: * the PG_NEEDCOMMIT flag. Once done the new write verifier can be set for
2672: * the mount point.
1.25 fvdl 2673: */
2674: void
2675: nfs_clearcommit(mp)
2676: struct mount *mp;
2677: {
1.89 chs 2678: struct vnode *vp;
1.83 fvdl 2679: struct nfsnode *np;
1.89 chs 2680: struct vm_page *pg;
1.116 yamt 2681: struct nfsmount *nmp = VFSTONFS(mp);
2682:
1.149.2.4 yamt 2683: rw_enter(&nmp->nm_writeverflock, RW_WRITER);
1.149.2.8! yamt 2684: mutex_enter(&mntvnode_lock);
1.149.2.3 yamt 2685: TAILQ_FOREACH(vp, &mp->mnt_vnodelist, v_mntvnodes) {
1.89 chs 2686: KASSERT(vp->v_mount == mp);
1.146 yamt 2687: if (vp->v_type != VREG)
1.85 enami 2688: continue;
1.83 fvdl 2689: np = VTONFS(vp);
2690: np->n_pushlo = np->n_pushhi = np->n_pushedlo =
2691: np->n_pushedhi = 0;
2692: np->n_commitflags &=
2693: ~(NFS_COMMIT_PUSH_VALID | NFS_COMMIT_PUSHED_VALID);
1.149.2.8! yamt 2694: mutex_enter(&vp->v_uobj.vmobjlock);
1.97 chs 2695: TAILQ_FOREACH(pg, &vp->v_uobj.memq, listq) {
1.89 chs 2696: pg->flags &= ~PG_NEEDCOMMIT;
1.25 fvdl 2697: }
1.149.2.8! yamt 2698: mutex_exit(&vp->v_uobj.vmobjlock);
1.25 fvdl 2699: }
1.149.2.8! yamt 2700: mutex_exit(&mntvnode_lock);
1.149.2.5 yamt 2701: mutex_enter(&nmp->nm_lock);
1.116 yamt 2702: nmp->nm_iflag &= ~NFSMNT_STALEWRITEVERF;
1.149.2.5 yamt 2703: mutex_exit(&nmp->nm_lock);
1.149.2.4 yamt 2704: rw_exit(&nmp->nm_writeverflock);
1.83 fvdl 2705: }
2706:
2707: void
2708: nfs_merge_commit_ranges(vp)
2709: struct vnode *vp;
2710: {
2711: struct nfsnode *np = VTONFS(vp);
1.112 yamt 2712:
2713: KASSERT(np->n_commitflags & NFS_COMMIT_PUSH_VALID);
1.83 fvdl 2714:
2715: if (!(np->n_commitflags & NFS_COMMIT_PUSHED_VALID)) {
2716: np->n_pushedlo = np->n_pushlo;
2717: np->n_pushedhi = np->n_pushhi;
2718: np->n_commitflags |= NFS_COMMIT_PUSHED_VALID;
2719: } else {
2720: if (np->n_pushlo < np->n_pushedlo)
2721: np->n_pushedlo = np->n_pushlo;
2722: if (np->n_pushhi > np->n_pushedhi)
2723: np->n_pushedhi = np->n_pushhi;
2724: }
2725:
2726: np->n_pushlo = np->n_pushhi = 0;
2727: np->n_commitflags &= ~NFS_COMMIT_PUSH_VALID;
2728:
1.111 yamt 2729: #ifdef NFS_DEBUG_COMMIT
1.83 fvdl 2730: printf("merge: committed: %u - %u\n", (unsigned)np->n_pushedlo,
2731: (unsigned)np->n_pushedhi);
2732: #endif
2733: }
2734:
2735: int
1.89 chs 2736: nfs_in_committed_range(vp, off, len)
1.83 fvdl 2737: struct vnode *vp;
1.89 chs 2738: off_t off, len;
1.83 fvdl 2739: {
2740: struct nfsnode *np = VTONFS(vp);
2741: off_t lo, hi;
2742:
2743: if (!(np->n_commitflags & NFS_COMMIT_PUSHED_VALID))
2744: return 0;
1.89 chs 2745: lo = off;
2746: hi = lo + len;
1.83 fvdl 2747:
2748: return (lo >= np->n_pushedlo && hi <= np->n_pushedhi);
2749: }
2750:
2751: int
1.89 chs 2752: nfs_in_tobecommitted_range(vp, off, len)
1.83 fvdl 2753: struct vnode *vp;
1.89 chs 2754: off_t off, len;
1.83 fvdl 2755: {
2756: struct nfsnode *np = VTONFS(vp);
2757: off_t lo, hi;
2758:
2759: if (!(np->n_commitflags & NFS_COMMIT_PUSH_VALID))
2760: return 0;
1.89 chs 2761: lo = off;
2762: hi = lo + len;
1.83 fvdl 2763:
2764: return (lo >= np->n_pushlo && hi <= np->n_pushhi);
2765: }
2766:
2767: void
1.89 chs 2768: nfs_add_committed_range(vp, off, len)
1.83 fvdl 2769: struct vnode *vp;
1.89 chs 2770: off_t off, len;
1.83 fvdl 2771: {
2772: struct nfsnode *np = VTONFS(vp);
2773: off_t lo, hi;
2774:
1.89 chs 2775: lo = off;
2776: hi = lo + len;
1.83 fvdl 2777:
2778: if (!(np->n_commitflags & NFS_COMMIT_PUSHED_VALID)) {
2779: np->n_pushedlo = lo;
2780: np->n_pushedhi = hi;
2781: np->n_commitflags |= NFS_COMMIT_PUSHED_VALID;
2782: } else {
2783: if (hi > np->n_pushedhi)
2784: np->n_pushedhi = hi;
2785: if (lo < np->n_pushedlo)
2786: np->n_pushedlo = lo;
2787: }
1.111 yamt 2788: #ifdef NFS_DEBUG_COMMIT
1.83 fvdl 2789: printf("add: committed: %u - %u\n", (unsigned)np->n_pushedlo,
2790: (unsigned)np->n_pushedhi);
2791: #endif
2792: }
2793:
2794: void
1.89 chs 2795: nfs_del_committed_range(vp, off, len)
1.83 fvdl 2796: struct vnode *vp;
1.89 chs 2797: off_t off, len;
1.83 fvdl 2798: {
2799: struct nfsnode *np = VTONFS(vp);
2800: off_t lo, hi;
2801:
2802: if (!(np->n_commitflags & NFS_COMMIT_PUSHED_VALID))
2803: return;
2804:
1.89 chs 2805: lo = off;
2806: hi = lo + len;
1.83 fvdl 2807:
2808: if (lo > np->n_pushedhi || hi < np->n_pushedlo)
2809: return;
2810: if (lo <= np->n_pushedlo)
2811: np->n_pushedlo = hi;
2812: else if (hi >= np->n_pushedhi)
2813: np->n_pushedhi = lo;
2814: else {
2815: /*
2816: * XXX There's only one range. If the deleted range
2817: * is in the middle, pick the largest of the
2818: * contiguous ranges that it leaves.
2819: */
2820: if ((np->n_pushedlo - lo) > (hi - np->n_pushedhi))
2821: np->n_pushedhi = lo;
2822: else
2823: np->n_pushedlo = hi;
2824: }
1.111 yamt 2825: #ifdef NFS_DEBUG_COMMIT
1.83 fvdl 2826: printf("del: committed: %u - %u\n", (unsigned)np->n_pushedlo,
2827: (unsigned)np->n_pushedhi);
2828: #endif
2829: }
2830:
2831: void
1.89 chs 2832: nfs_add_tobecommitted_range(vp, off, len)
1.83 fvdl 2833: struct vnode *vp;
1.89 chs 2834: off_t off, len;
1.83 fvdl 2835: {
2836: struct nfsnode *np = VTONFS(vp);
2837: off_t lo, hi;
2838:
1.89 chs 2839: lo = off;
2840: hi = lo + len;
1.83 fvdl 2841:
2842: if (!(np->n_commitflags & NFS_COMMIT_PUSH_VALID)) {
2843: np->n_pushlo = lo;
2844: np->n_pushhi = hi;
2845: np->n_commitflags |= NFS_COMMIT_PUSH_VALID;
2846: } else {
2847: if (lo < np->n_pushlo)
2848: np->n_pushlo = lo;
2849: if (hi > np->n_pushhi)
2850: np->n_pushhi = hi;
2851: }
1.111 yamt 2852: #ifdef NFS_DEBUG_COMMIT
1.83 fvdl 2853: printf("add: tobecommitted: %u - %u\n", (unsigned)np->n_pushlo,
2854: (unsigned)np->n_pushhi);
2855: #endif
2856: }
2857:
2858: void
1.89 chs 2859: nfs_del_tobecommitted_range(vp, off, len)
1.83 fvdl 2860: struct vnode *vp;
1.89 chs 2861: off_t off, len;
1.83 fvdl 2862: {
2863: struct nfsnode *np = VTONFS(vp);
2864: off_t lo, hi;
2865:
2866: if (!(np->n_commitflags & NFS_COMMIT_PUSH_VALID))
2867: return;
2868:
1.89 chs 2869: lo = off;
2870: hi = lo + len;
1.83 fvdl 2871:
2872: if (lo > np->n_pushhi || hi < np->n_pushlo)
2873: return;
2874:
2875: if (lo <= np->n_pushlo)
2876: np->n_pushlo = hi;
2877: else if (hi >= np->n_pushhi)
2878: np->n_pushhi = lo;
2879: else {
2880: /*
2881: * XXX There's only one range. If the deleted range
2882: * is in the middle, pick the largest of the
2883: * contiguous ranges that it leaves.
2884: */
2885: if ((np->n_pushlo - lo) > (hi - np->n_pushhi))
2886: np->n_pushhi = lo;
2887: else
2888: np->n_pushlo = hi;
2889: }
1.111 yamt 2890: #ifdef NFS_DEBUG_COMMIT
1.83 fvdl 2891: printf("del: tobecommitted: %u - %u\n", (unsigned)np->n_pushlo,
2892: (unsigned)np->n_pushhi);
2893: #endif
1.25 fvdl 2894: }
2895:
2896: /*
2897: * Map errnos to NFS error numbers. For Version 3 also filter out error
2898: * numbers not specified for the associated procedure.
2899: */
2900: int
2901: nfsrv_errmap(nd, err)
2902: struct nfsrv_descript *nd;
1.75 augustss 2903: int err;
1.25 fvdl 2904: {
1.90 jdolecek 2905: const short *defaulterrp, *errp;
1.25 fvdl 2906:
2907: if (nd->nd_flag & ND_NFSV3) {
2908: if (nd->nd_procnum <= NFSPROC_COMMIT) {
2909: errp = defaulterrp = nfsrv_v3errmap[nd->nd_procnum];
2910: while (*++errp) {
2911: if (*errp == err)
2912: return (err);
2913: else if (*errp > err)
2914: break;
2915: }
2916: return ((int)*defaulterrp);
2917: } else
2918: return (err & 0xffff);
2919: }
2920: if (err <= ELAST)
2921: return ((int)nfsrv_v2errmap[err - 1]);
2922: return (NFSERR_IO);
2923: }
2924:
1.126 yamt 2925: u_int32_t
2926: nfs_getxid()
2927: {
2928: static u_int32_t base;
2929: static u_int32_t nfs_xid = 0;
2930: static struct simplelock nfs_xidlock = SIMPLELOCK_INITIALIZER;
2931: u_int32_t newxid;
2932:
2933: simple_lock(&nfs_xidlock);
2934: /*
2935: * derive initial xid from system time
2936: * XXX time is invalid if root not yet mounted
2937: */
2938: if (__predict_false(!base && (rootvp))) {
2939: struct timeval tv;
2940:
2941: microtime(&tv);
2942: base = tv.tv_sec << 12;
2943: nfs_xid = base;
2944: }
2945:
2946: /*
2947: * Skip zero xid if it should ever happen.
2948: */
2949: if (__predict_false(++nfs_xid == 0))
2950: nfs_xid++;
2951: newxid = nfs_xid;
2952: simple_unlock(&nfs_xidlock);
2953:
2954: return txdr_unsigned(newxid);
2955: }
2956:
2957: /*
2958: * assign a new xid for existing request.
2959: * used for NFSERR_JUKEBOX handling.
2960: */
2961: void
2962: nfs_renewxid(struct nfsreq *req)
2963: {
2964: u_int32_t xid;
2965: int off;
2966:
2967: xid = nfs_getxid();
2968: if (req->r_nmp->nm_sotype == SOCK_STREAM)
2969: off = sizeof(u_int32_t); /* RPC record mark */
2970: else
2971: off = 0;
2972:
2973: m_copyback(req->r_mreq, off, sizeof(xid), (void *)&xid);
2974: req->r_xid = xid;
1.1 cgd 2975: }
1.149.2.3 yamt 2976:
2977: #if defined(NFSSERVER)
2978: int
1.149.2.4 yamt 2979: nfsrv_composefh(struct vnode *vp, nfsrvfh_t *nsfh, bool v3)
1.149.2.3 yamt 2980: {
2981: int error;
2982: size_t fhsize;
2983:
2984: fhsize = NFSD_MAXFHSIZE;
2985: error = vfs_composefh(vp, (void *)NFSRVFH_DATA(nsfh), &fhsize);
2986: if (NFSX_FHTOOBIG_P(fhsize, v3)) {
2987: error = EOPNOTSUPP;
2988: }
2989: if (error != 0) {
2990: return error;
2991: }
2992: if (!v3 && fhsize < NFSX_V2FH) {
2993: memset((char *)NFSRVFH_DATA(nsfh) + fhsize, 0,
2994: NFSX_V2FH - fhsize);
2995: fhsize = NFSX_V2FH;
2996: }
2997: if ((fhsize % NFSX_UNSIGNED) != 0) {
2998: return EOPNOTSUPP;
2999: }
3000: nsfh->nsfh_size = fhsize;
3001: return 0;
3002: }
3003:
3004: int
3005: nfsrv_comparefh(const nfsrvfh_t *fh1, const nfsrvfh_t *fh2)
3006: {
3007:
3008: if (NFSRVFH_SIZE(fh1) != NFSRVFH_SIZE(fh2)) {
3009: return NFSRVFH_SIZE(fh2) - NFSRVFH_SIZE(fh1);
3010: }
3011: return memcmp(NFSRVFH_DATA(fh1), NFSRVFH_DATA(fh2), NFSRVFH_SIZE(fh1));
3012: }
3013:
3014: void
3015: nfsrv_copyfh(nfsrvfh_t *fh1, const nfsrvfh_t *fh2)
3016: {
3017: size_t size;
3018:
3019: fh1->nsfh_size = size = NFSRVFH_SIZE(fh2);
3020: memcpy(NFSRVFH_DATA(fh1), NFSRVFH_DATA(fh2), size);
3021: }
3022: #endif /* defined(NFSSERVER) */
1.149.2.6 yamt 3023:
3024: #if defined(NFS)
3025: /*
3026: * Set the attribute timeout based on how recently the file has been modified.
3027: */
3028:
3029: time_t
3030: nfs_attrtimeo(struct nfsmount *nmp, struct nfsnode *np)
3031: {
3032: time_t timeo;
3033:
3034: if ((nmp->nm_flag & NFSMNT_NOAC) != 0)
3035: return 0;
3036:
3037: if (((np)->n_flag & NMODIFIED) != 0)
3038: return NFS_MINATTRTIMO;
3039:
3040: timeo = (time_second - np->n_mtime.tv_sec) / 10;
3041: timeo = max(timeo, NFS_MINATTRTIMO);
3042: timeo = min(timeo, NFS_MAXATTRTIMO);
3043: return timeo;
3044: }
3045: #endif /* defined(NFS) */
CVSweb <webmaster@jp.NetBSD.org>