Annotation of src/sys/nfs/nfs_subs.c, Revision 1.202.2.1
1.202.2.1! wrstuden 1: /* $NetBSD: nfs_subs.c,v 1.202 2008/05/05 17:11:17 ad 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.202.2.1! wrstuden 73: __KERNEL_RCSID(0, "$NetBSD: nfs_subs.c,v 1.202 2008/05/05 17:11:17 ad 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.196 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.98 fvdl 97: #include <sys/filedesc.h>
1.30 fvdl 98: #include <sys/time.h>
1.43 fvdl 99: #include <sys/dirent.h>
1.155 thorpej 100: #include <sys/once.h>
1.162 elad 101: #include <sys/kauth.h>
1.1 cgd 102:
1.51 mrg 103: #include <uvm/uvm_extern.h>
104:
1.9 mycroft 105: #include <nfs/rpcv2.h>
1.25 fvdl 106: #include <nfs/nfsproto.h>
1.9 mycroft 107: #include <nfs/nfsnode.h>
108: #include <nfs/nfs.h>
109: #include <nfs/xdr_subs.h>
110: #include <nfs/nfsm_subs.h>
1.12 mycroft 111: #include <nfs/nfsmount.h>
112: #include <nfs/nfsrtt.h>
1.24 christos 113: #include <nfs/nfs_var.h>
1.12 mycroft 114:
115: #include <miscfs/specfs/specdev.h>
1.24 christos 116:
1.12 mycroft 117: #include <netinet/in.h>
118: #ifdef ISO
119: #include <netiso/iso.h>
120: #endif
1.1 cgd 121:
122: /*
123: * Data items converted to xdr at startup, since they are constant
124: * This is kinda hokey, but may save a little time doing byte swaps
125: */
1.22 cgd 126: u_int32_t nfs_xdrneg1;
127: u_int32_t rpc_call, rpc_vers, rpc_reply, rpc_msgdenied, rpc_autherr,
1.25 fvdl 128: rpc_mismatch, rpc_auth_unix, rpc_msgaccepted,
1.12 mycroft 129: rpc_auth_kerb;
1.179 yamt 130: u_int32_t nfs_prog, nfs_true, nfs_false;
1.12 mycroft 131:
1.1 cgd 132: /* And other global data */
1.90 jdolecek 133: const nfstype nfsv2_type[9] =
134: { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFNON, NFCHR, NFNON };
135: const nfstype nfsv3_type[9] =
136: { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFSOCK, NFFIFO, NFNON };
137: const enum vtype nv2tov_type[8] =
138: { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON, VNON };
139: const enum vtype nv3tov_type[8] =
140: { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO };
1.25 fvdl 141: int nfs_ticks;
1.100 chs 142: int nfs_commitsize;
1.108 christos 143:
144: MALLOC_DEFINE(M_NFSDIROFF, "NFS diroff", "NFS directory cookies");
1.25 fvdl 145:
1.35 thorpej 146: /* NFS client/server stats. */
147: struct nfsstats nfsstats;
148:
1.25 fvdl 149: /*
150: * Mapping of old NFS Version 2 RPC numbers to generic numbers.
151: */
1.90 jdolecek 152: const int nfsv3_procid[NFS_NPROCS] = {
1.25 fvdl 153: NFSPROC_NULL,
154: NFSPROC_GETATTR,
155: NFSPROC_SETATTR,
156: NFSPROC_NOOP,
157: NFSPROC_LOOKUP,
158: NFSPROC_READLINK,
159: NFSPROC_READ,
160: NFSPROC_NOOP,
161: NFSPROC_WRITE,
162: NFSPROC_CREATE,
163: NFSPROC_REMOVE,
164: NFSPROC_RENAME,
165: NFSPROC_LINK,
166: NFSPROC_SYMLINK,
167: NFSPROC_MKDIR,
168: NFSPROC_RMDIR,
169: NFSPROC_READDIR,
170: NFSPROC_FSSTAT,
171: NFSPROC_NOOP,
172: NFSPROC_NOOP,
173: NFSPROC_NOOP,
174: NFSPROC_NOOP,
175: NFSPROC_NOOP
176: };
177:
178: /*
179: * and the reverse mapping from generic to Version 2 procedure numbers
180: */
1.90 jdolecek 181: const int nfsv2_procid[NFS_NPROCS] = {
1.25 fvdl 182: NFSV2PROC_NULL,
183: NFSV2PROC_GETATTR,
184: NFSV2PROC_SETATTR,
185: NFSV2PROC_LOOKUP,
186: NFSV2PROC_NOOP,
187: NFSV2PROC_READLINK,
188: NFSV2PROC_READ,
189: NFSV2PROC_WRITE,
190: NFSV2PROC_CREATE,
191: NFSV2PROC_MKDIR,
192: NFSV2PROC_SYMLINK,
193: NFSV2PROC_CREATE,
194: NFSV2PROC_REMOVE,
195: NFSV2PROC_RMDIR,
196: NFSV2PROC_RENAME,
197: NFSV2PROC_LINK,
198: NFSV2PROC_READDIR,
199: NFSV2PROC_NOOP,
200: NFSV2PROC_STATFS,
201: NFSV2PROC_NOOP,
202: NFSV2PROC_NOOP,
203: NFSV2PROC_NOOP,
204: NFSV2PROC_NOOP,
205: };
206:
207: /*
208: * Maps errno values to nfs error numbers.
209: * Use NFSERR_IO as the catch all for ones not specifically defined in
210: * RFC 1094.
211: */
1.90 jdolecek 212: static const u_char nfsrv_v2errmap[ELAST] = {
1.25 fvdl 213: NFSERR_PERM, NFSERR_NOENT, NFSERR_IO, NFSERR_IO, NFSERR_IO,
214: NFSERR_NXIO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
215: NFSERR_IO, NFSERR_IO, NFSERR_ACCES, NFSERR_IO, NFSERR_IO,
216: NFSERR_IO, NFSERR_EXIST, NFSERR_IO, NFSERR_NODEV, NFSERR_NOTDIR,
217: NFSERR_ISDIR, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
218: NFSERR_IO, NFSERR_FBIG, NFSERR_NOSPC, NFSERR_IO, NFSERR_ROFS,
219: NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
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_NAMETOL, NFSERR_IO, NFSERR_IO,
226: NFSERR_NOTEMPTY, NFSERR_IO, NFSERR_IO, NFSERR_DQUOT, NFSERR_STALE,
227: NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
228: NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
1.52 mikel 229: NFSERR_IO, NFSERR_IO,
1.25 fvdl 230: };
231:
232: /*
233: * Maps errno values to nfs error numbers.
234: * Although it is not obvious whether or not NFS clients really care if
235: * a returned error value is in the specified list for the procedure, the
236: * safest thing to do is filter them appropriately. For Version 2, the
237: * X/Open XNFS document is the only specification that defines error values
238: * for each RPC (The RFC simply lists all possible error values for all RPCs),
239: * so I have decided to not do this for Version 2.
240: * The first entry is the default error return and the rest are the valid
241: * errors for that RPC in increasing numeric order.
242: */
1.90 jdolecek 243: static const short nfsv3err_null[] = {
1.25 fvdl 244: 0,
245: 0,
246: };
247:
1.90 jdolecek 248: static const short nfsv3err_getattr[] = {
1.25 fvdl 249: NFSERR_IO,
250: NFSERR_IO,
251: NFSERR_STALE,
252: NFSERR_BADHANDLE,
253: NFSERR_SERVERFAULT,
254: 0,
255: };
256:
1.90 jdolecek 257: static const short nfsv3err_setattr[] = {
1.25 fvdl 258: NFSERR_IO,
259: NFSERR_PERM,
260: NFSERR_IO,
261: NFSERR_ACCES,
262: NFSERR_INVAL,
263: NFSERR_NOSPC,
264: NFSERR_ROFS,
265: NFSERR_DQUOT,
266: NFSERR_STALE,
267: NFSERR_BADHANDLE,
268: NFSERR_NOT_SYNC,
269: NFSERR_SERVERFAULT,
270: 0,
271: };
272:
1.90 jdolecek 273: static const short nfsv3err_lookup[] = {
1.25 fvdl 274: NFSERR_IO,
275: NFSERR_NOENT,
276: NFSERR_IO,
277: NFSERR_ACCES,
278: NFSERR_NOTDIR,
279: NFSERR_NAMETOL,
280: NFSERR_STALE,
281: NFSERR_BADHANDLE,
282: NFSERR_SERVERFAULT,
283: 0,
284: };
285:
1.90 jdolecek 286: static const short nfsv3err_access[] = {
1.25 fvdl 287: NFSERR_IO,
288: NFSERR_IO,
289: NFSERR_STALE,
290: NFSERR_BADHANDLE,
291: NFSERR_SERVERFAULT,
292: 0,
293: };
294:
1.90 jdolecek 295: static const short nfsv3err_readlink[] = {
1.25 fvdl 296: NFSERR_IO,
297: NFSERR_IO,
298: NFSERR_ACCES,
299: NFSERR_INVAL,
300: NFSERR_STALE,
301: NFSERR_BADHANDLE,
302: NFSERR_NOTSUPP,
303: NFSERR_SERVERFAULT,
304: 0,
305: };
306:
1.90 jdolecek 307: static const short nfsv3err_read[] = {
1.25 fvdl 308: NFSERR_IO,
309: NFSERR_IO,
310: NFSERR_NXIO,
311: NFSERR_ACCES,
312: NFSERR_INVAL,
313: NFSERR_STALE,
314: NFSERR_BADHANDLE,
315: NFSERR_SERVERFAULT,
1.67 fvdl 316: NFSERR_JUKEBOX,
1.25 fvdl 317: 0,
318: };
319:
1.90 jdolecek 320: static const short nfsv3err_write[] = {
1.25 fvdl 321: NFSERR_IO,
322: NFSERR_IO,
323: NFSERR_ACCES,
324: NFSERR_INVAL,
325: NFSERR_FBIG,
326: NFSERR_NOSPC,
327: NFSERR_ROFS,
328: NFSERR_DQUOT,
329: NFSERR_STALE,
330: NFSERR_BADHANDLE,
331: NFSERR_SERVERFAULT,
1.68 fvdl 332: NFSERR_JUKEBOX,
1.25 fvdl 333: 0,
334: };
335:
1.90 jdolecek 336: static const short nfsv3err_create[] = {
1.25 fvdl 337: NFSERR_IO,
338: NFSERR_IO,
339: NFSERR_ACCES,
340: NFSERR_EXIST,
341: NFSERR_NOTDIR,
342: NFSERR_NOSPC,
343: NFSERR_ROFS,
344: NFSERR_NAMETOL,
345: NFSERR_DQUOT,
346: NFSERR_STALE,
347: NFSERR_BADHANDLE,
348: NFSERR_NOTSUPP,
349: NFSERR_SERVERFAULT,
350: 0,
351: };
352:
1.90 jdolecek 353: static const short nfsv3err_mkdir[] = {
1.25 fvdl 354: NFSERR_IO,
355: NFSERR_IO,
356: NFSERR_ACCES,
357: NFSERR_EXIST,
358: NFSERR_NOTDIR,
359: NFSERR_NOSPC,
360: NFSERR_ROFS,
361: NFSERR_NAMETOL,
362: NFSERR_DQUOT,
363: NFSERR_STALE,
364: NFSERR_BADHANDLE,
365: NFSERR_NOTSUPP,
366: NFSERR_SERVERFAULT,
367: 0,
368: };
369:
1.90 jdolecek 370: static const short nfsv3err_symlink[] = {
1.25 fvdl 371: NFSERR_IO,
372: NFSERR_IO,
373: NFSERR_ACCES,
374: NFSERR_EXIST,
375: NFSERR_NOTDIR,
376: NFSERR_NOSPC,
377: NFSERR_ROFS,
378: NFSERR_NAMETOL,
379: NFSERR_DQUOT,
380: NFSERR_STALE,
381: NFSERR_BADHANDLE,
382: NFSERR_NOTSUPP,
383: NFSERR_SERVERFAULT,
384: 0,
385: };
386:
1.90 jdolecek 387: static const short nfsv3err_mknod[] = {
1.25 fvdl 388: NFSERR_IO,
389: NFSERR_IO,
390: NFSERR_ACCES,
391: NFSERR_EXIST,
392: NFSERR_NOTDIR,
393: NFSERR_NOSPC,
394: NFSERR_ROFS,
395: NFSERR_NAMETOL,
396: NFSERR_DQUOT,
397: NFSERR_STALE,
398: NFSERR_BADHANDLE,
399: NFSERR_NOTSUPP,
400: NFSERR_SERVERFAULT,
401: NFSERR_BADTYPE,
402: 0,
403: };
404:
1.90 jdolecek 405: static const short nfsv3err_remove[] = {
1.25 fvdl 406: NFSERR_IO,
407: NFSERR_NOENT,
408: NFSERR_IO,
409: NFSERR_ACCES,
410: NFSERR_NOTDIR,
411: NFSERR_ROFS,
412: NFSERR_NAMETOL,
413: NFSERR_STALE,
414: NFSERR_BADHANDLE,
415: NFSERR_SERVERFAULT,
416: 0,
417: };
418:
1.90 jdolecek 419: static const short nfsv3err_rmdir[] = {
1.25 fvdl 420: NFSERR_IO,
421: NFSERR_NOENT,
422: NFSERR_IO,
423: NFSERR_ACCES,
424: NFSERR_EXIST,
425: NFSERR_NOTDIR,
426: NFSERR_INVAL,
427: NFSERR_ROFS,
428: NFSERR_NAMETOL,
429: NFSERR_NOTEMPTY,
430: NFSERR_STALE,
431: NFSERR_BADHANDLE,
432: NFSERR_NOTSUPP,
433: NFSERR_SERVERFAULT,
434: 0,
435: };
436:
1.90 jdolecek 437: static const short nfsv3err_rename[] = {
1.25 fvdl 438: NFSERR_IO,
439: NFSERR_NOENT,
440: NFSERR_IO,
441: NFSERR_ACCES,
442: NFSERR_EXIST,
443: NFSERR_XDEV,
444: NFSERR_NOTDIR,
445: NFSERR_ISDIR,
446: NFSERR_INVAL,
447: NFSERR_NOSPC,
448: NFSERR_ROFS,
449: NFSERR_MLINK,
450: NFSERR_NAMETOL,
451: NFSERR_NOTEMPTY,
452: NFSERR_DQUOT,
453: NFSERR_STALE,
454: NFSERR_BADHANDLE,
455: NFSERR_NOTSUPP,
456: NFSERR_SERVERFAULT,
457: 0,
458: };
459:
1.90 jdolecek 460: static const short nfsv3err_link[] = {
1.25 fvdl 461: NFSERR_IO,
462: NFSERR_IO,
463: NFSERR_ACCES,
464: NFSERR_EXIST,
465: NFSERR_XDEV,
466: NFSERR_NOTDIR,
467: NFSERR_INVAL,
468: NFSERR_NOSPC,
469: NFSERR_ROFS,
470: NFSERR_MLINK,
471: NFSERR_NAMETOL,
472: NFSERR_DQUOT,
473: NFSERR_STALE,
474: NFSERR_BADHANDLE,
475: NFSERR_NOTSUPP,
476: NFSERR_SERVERFAULT,
477: 0,
478: };
479:
1.90 jdolecek 480: static const short nfsv3err_readdir[] = {
1.25 fvdl 481: NFSERR_IO,
482: NFSERR_IO,
483: NFSERR_ACCES,
484: NFSERR_NOTDIR,
485: NFSERR_STALE,
486: NFSERR_BADHANDLE,
487: NFSERR_BAD_COOKIE,
488: NFSERR_TOOSMALL,
489: NFSERR_SERVERFAULT,
490: 0,
491: };
492:
1.90 jdolecek 493: static const short nfsv3err_readdirplus[] = {
1.25 fvdl 494: NFSERR_IO,
495: NFSERR_IO,
496: NFSERR_ACCES,
497: NFSERR_NOTDIR,
498: NFSERR_STALE,
499: NFSERR_BADHANDLE,
500: NFSERR_BAD_COOKIE,
501: NFSERR_NOTSUPP,
502: NFSERR_TOOSMALL,
503: NFSERR_SERVERFAULT,
504: 0,
505: };
506:
1.90 jdolecek 507: static const short nfsv3err_fsstat[] = {
1.25 fvdl 508: NFSERR_IO,
509: NFSERR_IO,
510: NFSERR_STALE,
511: NFSERR_BADHANDLE,
512: NFSERR_SERVERFAULT,
513: 0,
514: };
515:
1.90 jdolecek 516: static const short nfsv3err_fsinfo[] = {
1.25 fvdl 517: NFSERR_STALE,
518: NFSERR_STALE,
519: NFSERR_BADHANDLE,
520: NFSERR_SERVERFAULT,
521: 0,
522: };
523:
1.90 jdolecek 524: static const short nfsv3err_pathconf[] = {
1.25 fvdl 525: NFSERR_STALE,
526: NFSERR_STALE,
527: NFSERR_BADHANDLE,
528: NFSERR_SERVERFAULT,
529: 0,
530: };
531:
1.90 jdolecek 532: static const short nfsv3err_commit[] = {
1.25 fvdl 533: NFSERR_IO,
534: NFSERR_IO,
535: NFSERR_STALE,
536: NFSERR_BADHANDLE,
537: NFSERR_SERVERFAULT,
538: 0,
539: };
540:
1.90 jdolecek 541: static const short * const nfsrv_v3errmap[] = {
1.25 fvdl 542: nfsv3err_null,
543: nfsv3err_getattr,
544: nfsv3err_setattr,
545: nfsv3err_lookup,
546: nfsv3err_access,
547: nfsv3err_readlink,
548: nfsv3err_read,
549: nfsv3err_write,
550: nfsv3err_create,
551: nfsv3err_mkdir,
552: nfsv3err_symlink,
553: nfsv3err_mknod,
554: nfsv3err_remove,
555: nfsv3err_rmdir,
556: nfsv3err_rename,
557: nfsv3err_link,
558: nfsv3err_readdir,
559: nfsv3err_readdirplus,
560: nfsv3err_fsstat,
561: nfsv3err_fsinfo,
562: nfsv3err_pathconf,
563: nfsv3err_commit,
564: };
565:
1.202.2.1! wrstuden 566: extern struct vfs_hooks nfs_export_hooks;
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.183 christos 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.183 christos 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.183 christos 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.162 elad 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.183 christos 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.183 christos 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.179 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.162 elad 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.162 elad 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.183 christos 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.183 christos 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.183 christos 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.183 christos 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.183 christos 781: mbufcp = mtod(mp, void *);
1.1 cgd 782: len = mp->m_len;
783: }
784: xfer = (left > len) ? len : left;
1.158 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.183 christos 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.183 christos 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.158 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.183 christos 866: cp = mtod(mp, char *) + mp->m_len;
1.158 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.183 christos 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.183 christos 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.183 christos 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.183 christos 912: char **dposp;
1.1 cgd 913: int siz;
914: int left;
1.183 christos 915: char **cp2;
1.1 cgd 916: {
1.75 augustss 917: struct mbuf *m1, *m2;
1.39 fvdl 918: struct mbuf *havebuf = NULL;
1.183 christos 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.183 christos 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.201 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.201 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.201 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.201 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.201 yamt 1020: MRESETDATA(m1);
1021: dst = mtod(m1, char *);
1022: if (dst != src) {
1.63 perry 1023: memmove(dst, src, left);
1.201 yamt 1024: }
1.39 fvdl 1025: m1->m_len = left;
1026: m2 = m1->m_next;
1.201 yamt 1027: *cp2 = m1->m_data;
1.1 cgd 1028: }
1.201 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.201 yamt 1035: dst = mtod(m1, char *) + m1->m_len;
1.129 itojun 1036: while ((len = M_TRAILINGSPACE(m1)) != 0 && m2) {
1.201 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.183 christos 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.183 christos 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.183 christos 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.183 christos 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.183 christos 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.195 ad 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.202 ad 1206: dircache = hashinit(NFS_DIRHASHSIZ, HASH_LIST, true,
1207: &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)
1.202 ad 1218: hashdone(dircache, HASH_LIST, nfsdirhashmask);
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.196 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.196 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.196 yamt 1282: kmem_free(ndp, sizeof(*ndp));
1.49 fvdl 1283: }
1284:
1.135 yamt 1285: static void
1.177 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.196 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.171 christos 1370: nfs_enterdircache(struct vnode *vp, off_t off, off_t blkoff, int en,
1.177 yamt 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.161 christos 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.196 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.160 christos 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.181 thorpej 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.196 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.157 yamt 1521: static int
1.155 thorpej 1522: nfs_init0(void)
1.1 cgd 1523: {
1.189 ad 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.182 thorpej 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.202.2.1! wrstuden 1543: vfs_hooks_attach(&nfs_export_hooks);
1.12 mycroft 1544: nfsrv_init(0); /* Init server data structures */
1.1 cgd 1545: nfsrv_initcache(); /* Init the server request cache */
1.190 ad 1546: {
1547: extern krwlock_t netexport_lock; /* XXX */
1548: rw_init(&netexport_lock);
1549: }
1.36 fvdl 1550: #endif /* NFSSERVER */
1.12 mycroft 1551:
1.164 yamt 1552: #if defined(NFSSERVER) || (defined(NFS) && !defined(NFS_V2_ONLY))
1553: nfsdreq_init();
1554: #endif /* defined(NFSSERVER) || (defined(NFS) && !defined(NFS_V2_ONLY)) */
1555:
1.1 cgd 1556: /*
1557: * Initialize reply list and start timer
1558: */
1.16 mycroft 1559: TAILQ_INIT(&nfs_reqq);
1.191 yamt 1560: nfs_timer_init();
1.109 matt 1561: MOWNER_ATTACH(&nfs_mowner);
1.106 jdolecek 1562:
1563: #ifdef NFS
1564: /* Initialize the kqueue structures */
1565: nfs_kqinit();
1.119 yamt 1566: /* Initialize the iod structures */
1567: nfs_iodinit();
1.106 jdolecek 1568: #endif
1.157 yamt 1569: return 0;
1.1 cgd 1570: }
1571:
1.155 thorpej 1572: void
1573: nfs_init(void)
1574: {
1575: static ONCE_DECL(nfs_init_once);
1576:
1577: RUN_ONCE(&nfs_init_once, nfs_init0);
1578: }
1579:
1.38 thorpej 1580: #ifdef NFS
1.35 thorpej 1581: /*
1582: * Called once at VFS init to initialize client-specific data structures.
1583: */
1584: void
1585: nfs_vfs_init()
1586: {
1.155 thorpej 1587: /* Initialize NFS server / client shared data. */
1588: nfs_init();
1589:
1.96 chs 1590: nfs_nhinit(); /* Init the nfsnode table */
1.100 chs 1591: nfs_commitsize = uvmexp.npages << (PAGE_SHIFT - 4);
1.96 chs 1592: }
1.35 thorpej 1593:
1.96 chs 1594: void
1595: nfs_vfs_reinit()
1596: {
1597: nfs_nhreinit();
1.73 jdolecek 1598: }
1599:
1600: void
1601: nfs_vfs_done()
1602: {
1603: nfs_nhdone();
1.35 thorpej 1604: }
1605:
1.1 cgd 1606: /*
1.12 mycroft 1607: * Attribute cache routines.
1608: * nfs_loadattrcache() - loads or updates the cache contents from attributes
1609: * that are on the mbuf list
1610: * nfs_getattrcache() - returns valid attributes if found in cache, returns
1611: * error otherwise
1.1 cgd 1612: */
1.12 mycroft 1613:
1614: /*
1615: * Load the attribute cache (that lives in the nfsnode entry) with
1616: * the values on the mbuf list and
1617: * Iff vap not NULL
1618: * copy the attributes to *vaper
1619: */
1.24 christos 1620: int
1.105 yamt 1621: nfsm_loadattrcache(vpp, mdp, dposp, vaper, flags)
1.12 mycroft 1622: struct vnode **vpp;
1623: struct mbuf **mdp;
1.183 christos 1624: char **dposp;
1.12 mycroft 1625: struct vattr *vaper;
1.105 yamt 1626: int flags;
1.1 cgd 1627: {
1.75 augustss 1628: int32_t t1;
1.183 christos 1629: char *cp2;
1.25 fvdl 1630: int error = 0;
1.12 mycroft 1631: struct mbuf *md;
1.45 fvdl 1632: int v3 = NFS_ISV3(*vpp);
1.1 cgd 1633:
1.12 mycroft 1634: md = *mdp;
1.183 christos 1635: t1 = (mtod(md, char *) + md->m_len) - *dposp;
1.25 fvdl 1636: error = nfsm_disct(mdp, dposp, NFSX_FATTR(v3), t1, &cp2);
1.24 christos 1637: if (error)
1.12 mycroft 1638: return (error);
1.105 yamt 1639: return nfs_loadattrcache(vpp, (struct nfs_fattr *)cp2, vaper, flags);
1.45 fvdl 1640: }
1641:
1642: int
1.105 yamt 1643: nfs_loadattrcache(vpp, fp, vaper, flags)
1.45 fvdl 1644: struct vnode **vpp;
1645: struct nfs_fattr *fp;
1646: struct vattr *vaper;
1.105 yamt 1647: int flags;
1.45 fvdl 1648: {
1.75 augustss 1649: struct vnode *vp = *vpp;
1650: struct vattr *vap;
1.45 fvdl 1651: int v3 = NFS_ISV3(vp);
1652: enum vtype vtyp;
1653: u_short vmode;
1654: struct timespec mtime;
1.139 yamt 1655: struct timespec ctime;
1.45 fvdl 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.180 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.197 ad 1706: spec_node_init(vp, (dev_t)rdev);
1.12 mycroft 1707: }
1.128 yamt 1708: np->n_mtime = mtime;
1.12 mycroft 1709: }
1.101 fvdl 1710: uid = fxdr_unsigned(uid_t, fp->fa_uid);
1711: gid = fxdr_unsigned(gid_t, fp->fa_gid);
1.49 fvdl 1712: vap = np->n_vattr;
1.101 fvdl 1713:
1714: /*
1.139 yamt 1715: * Invalidate access cache if uid, gid, mode or ctime changed.
1.101 fvdl 1716: */
1717: if (np->n_accstamp != -1 &&
1.139 yamt 1718: (gid != vap->va_gid || uid != vap->va_uid || vmode != vap->va_mode
1719: || timespeccmp(&ctime, &vap->va_ctime, !=)))
1.101 fvdl 1720: np->n_accstamp = -1;
1721:
1.12 mycroft 1722: vap->va_type = vtyp;
1.101 fvdl 1723: vap->va_mode = vmode;
1.12 mycroft 1724: vap->va_rdev = (dev_t)rdev;
1725: vap->va_mtime = mtime;
1.139 yamt 1726: vap->va_ctime = ctime;
1.133 christos 1727: vap->va_fsid = vp->v_mount->mnt_stat.f_fsidx.__fsid_val[0];
1.72 fvdl 1728: switch (vtyp) {
1729: case VDIR:
1730: vap->va_blocksize = NFS_DIRFRAGSIZ;
1731: break;
1732: case VBLK:
1733: vap->va_blocksize = BLKDEV_IOSIZE;
1734: break;
1735: case VCHR:
1736: vap->va_blocksize = MAXBSIZE;
1737: break;
1738: default:
1739: vap->va_blocksize = v3 ? vp->v_mount->mnt_stat.f_iosize :
1740: fxdr_unsigned(int32_t, fp->fa2_blocksize);
1741: break;
1742: }
1.25 fvdl 1743: if (v3) {
1744: vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink);
1.101 fvdl 1745: vap->va_uid = uid;
1746: vap->va_gid = gid;
1.66 fair 1747: vap->va_size = fxdr_hyper(&fp->fa3_size);
1748: vap->va_bytes = fxdr_hyper(&fp->fa3_used);
1.151 yamt 1749: vap->va_fileid = fxdr_hyper(&fp->fa3_fileid);
1.25 fvdl 1750: fxdr_nfsv3time(&fp->fa3_atime, &vap->va_atime);
1751: vap->va_flags = 0;
1752: vap->va_filerev = 0;
1.12 mycroft 1753: } else {
1.25 fvdl 1754: vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink);
1.101 fvdl 1755: vap->va_uid = uid;
1756: vap->va_gid = gid;
1.25 fvdl 1757: vap->va_size = fxdr_unsigned(u_int32_t, fp->fa2_size);
1758: vap->va_bytes = fxdr_unsigned(int32_t, fp->fa2_blocks)
1759: * NFS_FABLKSIZE;
1760: vap->va_fileid = fxdr_unsigned(int32_t, fp->fa2_fileid);
1761: fxdr_nfsv2time(&fp->fa2_atime, &vap->va_atime);
1.12 mycroft 1762: vap->va_flags = 0;
1.25 fvdl 1763: vap->va_gen = fxdr_unsigned(u_int32_t,fp->fa2_ctime.nfsv2_usec);
1.12 mycroft 1764: vap->va_filerev = 0;
1765: }
1.199 yamt 1766: if (vap->va_size > VFSTONFS(vp->v_mount)->nm_maxfilesize) {
1767: return EFBIG;
1768: }
1.12 mycroft 1769: if (vap->va_size != np->n_size) {
1.89 chs 1770: if ((np->n_flag & NMODIFIED) && vap->va_size < np->n_size) {
1771: vap->va_size = np->n_size;
1772: } else {
1.12 mycroft 1773: np->n_size = vap->va_size;
1.89 chs 1774: if (vap->va_type == VREG) {
1.140 yamt 1775: /*
1776: * we can't free pages if NAC_NOTRUNC because
1777: * the pages can be owned by ourselves.
1778: */
1779: if (flags & NAC_NOTRUNC) {
1.105 yamt 1780: np->n_flag |= NTRUNCDELAYED;
1.140 yamt 1781: } else {
1.174 yamt 1782: genfs_node_wrlock(vp);
1.195 ad 1783: mutex_enter(&vp->v_interlock);
1.140 yamt 1784: (void)VOP_PUTPAGES(vp, 0,
1785: 0, PGO_SYNCIO | PGO_CLEANIT |
1786: PGO_FREE | PGO_ALLPAGES);
1.105 yamt 1787: uvm_vnp_setsize(vp, np->n_size);
1.174 yamt 1788: genfs_node_unlock(vp);
1.105 yamt 1789: }
1.89 chs 1790: }
1791: }
1.12 mycroft 1792: }
1.165 kardel 1793: np->n_attrstamp = time_second;
1.12 mycroft 1794: if (vaper != NULL) {
1.183 christos 1795: memcpy((void *)vaper, (void *)vap, sizeof(*vap));
1.12 mycroft 1796: if (np->n_flag & NCHG) {
1.25 fvdl 1797: if (np->n_flag & NACC)
1798: vaper->va_atime = np->n_atim;
1799: if (np->n_flag & NUPD)
1800: vaper->va_mtime = np->n_mtim;
1.12 mycroft 1801: }
1802: }
1803: return (0);
1804: }
1805:
1806: /*
1807: * Check the time stamp
1808: * If the cache is valid, copy contents to *vap and return 0
1809: * otherwise return an error
1810: */
1.24 christos 1811: int
1.12 mycroft 1812: nfs_getattrcache(vp, vaper)
1.75 augustss 1813: struct vnode *vp;
1.12 mycroft 1814: struct vattr *vaper;
1815: {
1.75 augustss 1816: struct nfsnode *np = VTONFS(vp);
1.152 christos 1817: struct nfsmount *nmp = VFSTONFS(vp->v_mount);
1.75 augustss 1818: struct vattr *vap;
1.12 mycroft 1819:
1.132 yamt 1820: if (np->n_attrstamp == 0 ||
1.192 yamt 1821: (time_second - np->n_attrstamp) >= nfs_attrtimeo(nmp, np)) {
1.12 mycroft 1822: nfsstats.attrcache_misses++;
1823: return (ENOENT);
1824: }
1825: nfsstats.attrcache_hits++;
1.49 fvdl 1826: vap = np->n_vattr;
1.12 mycroft 1827: if (vap->va_size != np->n_size) {
1828: if (vap->va_type == VREG) {
1.188 yamt 1829: if ((np->n_flag & NMODIFIED) != 0 &&
1830: vap->va_size < np->n_size) {
1831: vap->va_size = np->n_size;
1832: } else {
1.12 mycroft 1833: np->n_size = vap->va_size;
1.188 yamt 1834: }
1.174 yamt 1835: genfs_node_wrlock(vp);
1.51 mrg 1836: uvm_vnp_setsize(vp, np->n_size);
1.174 yamt 1837: genfs_node_unlock(vp);
1.12 mycroft 1838: } else
1839: np->n_size = vap->va_size;
1840: }
1.183 christos 1841: memcpy((void *)vaper, (void *)vap, sizeof(struct vattr));
1.12 mycroft 1842: if (np->n_flag & NCHG) {
1.25 fvdl 1843: if (np->n_flag & NACC)
1844: vaper->va_atime = np->n_atim;
1845: if (np->n_flag & NUPD)
1846: vaper->va_mtime = np->n_mtim;
1.1 cgd 1847: }
1.12 mycroft 1848: return (0);
1.105 yamt 1849: }
1850:
1851: void
1852: nfs_delayedtruncate(vp)
1853: struct vnode *vp;
1854: {
1855: struct nfsnode *np = VTONFS(vp);
1856:
1857: if (np->n_flag & NTRUNCDELAYED) {
1858: np->n_flag &= ~NTRUNCDELAYED;
1.174 yamt 1859: genfs_node_wrlock(vp);
1.195 ad 1860: mutex_enter(&vp->v_interlock);
1.140 yamt 1861: (void)VOP_PUTPAGES(vp, 0,
1862: 0, PGO_SYNCIO | PGO_CLEANIT | PGO_FREE | PGO_ALLPAGES);
1.105 yamt 1863: uvm_vnp_setsize(vp, np->n_size);
1.174 yamt 1864: genfs_node_unlock(vp);
1.105 yamt 1865: }
1.1 cgd 1866: }
1.48 fvdl 1867:
1.141 yamt 1868: #define NFS_WCCKLUDGE_TIMEOUT (24 * 60 * 60) /* 1 day */
1869: #define NFS_WCCKLUDGE(nmp, now) \
1870: (((nmp)->nm_iflag & NFSMNT_WCCKLUDGE) && \
1871: ((now) - (nmp)->nm_wcckludgetime - NFS_WCCKLUDGE_TIMEOUT) < 0)
1872:
1873: /*
1874: * nfs_check_wccdata: check inaccurate wcc_data
1875: *
1876: * => return non-zero if we shouldn't trust the wcc_data.
1877: * => NFS_WCCKLUDGE_TIMEOUT is for the case that the server is "fixed".
1878: */
1879:
1880: int
1.177 yamt 1881: nfs_check_wccdata(struct nfsnode *np, const struct timespec *ctime,
1.181 thorpej 1882: struct timespec *mtime, bool docheck)
1.141 yamt 1883: {
1884: int error = 0;
1885:
1886: #if !defined(NFS_V2_ONLY)
1887:
1888: if (docheck) {
1889: struct vnode *vp = NFSTOV(np);
1890: struct nfsmount *nmp;
1.165 kardel 1891: long now = time_second;
1.184 yamt 1892: const struct timespec *omtime = &np->n_vattr->va_mtime;
1893: const struct timespec *octime = &np->n_vattr->va_ctime;
1.141 yamt 1894: const char *reason = NULL; /* XXX: gcc */
1895:
1.184 yamt 1896: if (timespeccmp(omtime, mtime, <=)) {
1.141 yamt 1897: reason = "mtime";
1898: error = EINVAL;
1899: }
1900:
1.184 yamt 1901: if (vp->v_type == VDIR && timespeccmp(octime, ctime, <=)) {
1.141 yamt 1902: reason = "ctime";
1903: error = EINVAL;
1904: }
1905:
1906: nmp = VFSTONFS(vp->v_mount);
1907: if (error) {
1.143 yamt 1908:
1909: /*
1910: * despite of the fact that we've updated the file,
1911: * timestamps of the file were not updated as we
1912: * expected.
1913: * it means that the server has incompatible
1914: * semantics of timestamps or (more likely)
1915: * the server time is not precise enough to
1916: * track each modifications.
1917: * in that case, we disable wcc processing.
1918: *
1919: * yes, strictly speaking, we should disable all
1920: * caching. it's a compromise.
1921: */
1922:
1.186 yamt 1923: mutex_enter(&nmp->nm_lock);
1.141 yamt 1924: if (!NFS_WCCKLUDGE(nmp, now)) {
1925: printf("%s: inaccurate wcc data (%s) detected,"
1.184 yamt 1926: " disabling wcc"
1927: " (ctime %u.%09u %u.%09u,"
1928: " mtime %u.%09u %u.%09u)\n",
1.141 yamt 1929: vp->v_mount->mnt_stat.f_mntfromname,
1.184 yamt 1930: reason,
1931: (unsigned int)octime->tv_sec,
1932: (unsigned int)octime->tv_nsec,
1933: (unsigned int)ctime->tv_sec,
1934: (unsigned int)ctime->tv_nsec,
1935: (unsigned int)omtime->tv_sec,
1936: (unsigned int)omtime->tv_nsec,
1937: (unsigned int)mtime->tv_sec,
1938: (unsigned int)mtime->tv_nsec);
1.141 yamt 1939: }
1940: nmp->nm_iflag |= NFSMNT_WCCKLUDGE;
1941: nmp->nm_wcckludgetime = now;
1.186 yamt 1942: mutex_exit(&nmp->nm_lock);
1.141 yamt 1943: } else if (NFS_WCCKLUDGE(nmp, now)) {
1944: error = EPERM; /* XXX */
1945: } else if (nmp->nm_iflag & NFSMNT_WCCKLUDGE) {
1.186 yamt 1946: mutex_enter(&nmp->nm_lock);
1.141 yamt 1947: if (nmp->nm_iflag & NFSMNT_WCCKLUDGE) {
1948: printf("%s: re-enabling wcc\n",
1949: vp->v_mount->mnt_stat.f_mntfromname);
1950: nmp->nm_iflag &= ~NFSMNT_WCCKLUDGE;
1951: }
1.186 yamt 1952: mutex_exit(&nmp->nm_lock);
1.141 yamt 1953: }
1954: }
1955:
1956: #endif /* !defined(NFS_V2_ONLY) */
1957:
1958: return error;
1959: }
1960:
1.48 fvdl 1961: /*
1962: * Heuristic to see if the server XDR encodes directory cookies or not.
1963: * it is not supposed to, but a lot of servers may do this. Also, since
1964: * most/all servers will implement V2 as well, it is expected that they
1965: * may return just 32 bits worth of cookie information, so we need to
1966: * find out in which 32 bits this information is available. We do this
1967: * to avoid trouble with emulated binaries that can't handle 64 bit
1968: * directory offsets.
1969: */
1970:
1971: void
1.156 christos 1972: nfs_cookieheuristic(vp, flagp, l, cred)
1.48 fvdl 1973: struct vnode *vp;
1974: int *flagp;
1.156 christos 1975: struct lwp *l;
1.162 elad 1976: kauth_cred_t cred;
1.48 fvdl 1977: {
1978: struct uio auio;
1979: struct iovec aiov;
1.183 christos 1980: char *tbuf, *cp;
1.48 fvdl 1981: struct dirent *dp;
1.57 fvdl 1982: off_t *cookies = NULL, *cop;
1.48 fvdl 1983: int error, eof, nc, len;
1984:
1.183 christos 1985: MALLOC(tbuf, void *, NFS_DIRFRAGSIZ, M_TEMP, M_WAITOK);
1.48 fvdl 1986:
1.149 christos 1987: aiov.iov_base = tbuf;
1.48 fvdl 1988: aiov.iov_len = NFS_DIRFRAGSIZ;
1989: auio.uio_iov = &aiov;
1990: auio.uio_iovcnt = 1;
1991: auio.uio_rw = UIO_READ;
1992: auio.uio_resid = NFS_DIRFRAGSIZ;
1993: auio.uio_offset = 0;
1.158 yamt 1994: UIO_SETUP_SYSSPACE(&auio);
1.48 fvdl 1995:
1.56 fvdl 1996: error = VOP_READDIR(vp, &auio, cred, &eof, &cookies, &nc);
1.48 fvdl 1997:
1998: len = NFS_DIRFRAGSIZ - auio.uio_resid;
1999: if (error || len == 0) {
1.149 christos 2000: FREE(tbuf, M_TEMP);
1.57 fvdl 2001: if (cookies)
1.80 thorpej 2002: free(cookies, M_TEMP);
1.48 fvdl 2003: return;
2004: }
2005:
2006: /*
2007: * Find the first valid entry and look at its offset cookie.
2008: */
2009:
1.149 christos 2010: cp = tbuf;
1.48 fvdl 2011: for (cop = cookies; len > 0; len -= dp->d_reclen) {
2012: dp = (struct dirent *)cp;
2013: if (dp->d_fileno != 0 && len >= dp->d_reclen) {
2014: if ((*cop >> 32) != 0 && (*cop & 0xffffffffLL) == 0) {
2015: *flagp |= NFSMNT_SWAPCOOKIE;
1.49 fvdl 2016: nfs_invaldircache(vp, 0);
1.156 christos 2017: nfs_vinvalbuf(vp, 0, cred, l, 1);
1.48 fvdl 2018: }
2019: break;
2020: }
2021: cop++;
2022: cp += dp->d_reclen;
2023: }
2024:
1.149 christos 2025: FREE(tbuf, M_TEMP);
1.80 thorpej 2026: free(cookies, M_TEMP);
1.48 fvdl 2027: }
1.38 thorpej 2028: #endif /* NFS */
1.1 cgd 2029:
1.153 jmmv 2030: #ifdef NFSSERVER
1.1 cgd 2031: /*
1.43 fvdl 2032: * Set up nameidata for a lookup() call and do it.
2033: *
2034: * If pubflag is set, this call is done for a lookup operation on the
2035: * public filehandle. In that case we allow crossing mountpoints and
2036: * absolute pathnames. However, the caller is expected to check that
2037: * the lookup result is within the public fs, and deny access if
2038: * it is not.
1.1 cgd 2039: */
1.24 christos 2040: int
1.168 yamt 2041: nfs_namei(ndp, nsfh, len, slp, nam, mdp, dposp, retdirp, l, kerbflag, pubflag)
1.75 augustss 2042: struct nameidata *ndp;
1.168 yamt 2043: nfsrvfh_t *nsfh;
1.110 yamt 2044: uint32_t len;
1.12 mycroft 2045: struct nfssvc_sock *slp;
2046: struct mbuf *nam;
1.1 cgd 2047: struct mbuf **mdp;
1.183 christos 2048: char **dposp;
1.25 fvdl 2049: struct vnode **retdirp;
1.156 christos 2050: struct lwp *l;
1.43 fvdl 2051: int kerbflag, pubflag;
1.1 cgd 2052: {
1.75 augustss 2053: int i, rem;
2054: struct mbuf *md;
2055: char *fromcp, *tocp, *cp;
1.43 fvdl 2056: struct iovec aiov;
2057: struct uio auio;
1.1 cgd 2058: struct vnode *dp;
1.43 fvdl 2059: int error, rdonly, linklen;
1.12 mycroft 2060: struct componentname *cnp = &ndp->ni_cnd;
1.1 cgd 2061:
1.178 chs 2062: *retdirp = NULL;
1.81 thorpej 2063:
2064: if ((len + 1) > MAXPATHLEN)
2065: return (ENAMETOOLONG);
1.147 yamt 2066: if (len == 0)
2067: return (EACCES);
1.81 thorpej 2068: cnp->cn_pnbuf = PNBUF_GET();
2069:
1.1 cgd 2070: /*
2071: * Copy the name from the mbuf list to ndp->ni_pnbuf
2072: * and set the various ndp fields appropriately.
2073: */
2074: fromcp = *dposp;
1.12 mycroft 2075: tocp = cnp->cn_pnbuf;
1.1 cgd 2076: md = *mdp;
1.183 christos 2077: rem = mtod(md, char *) + md->m_len - fromcp;
1.1 cgd 2078: for (i = 0; i < len; i++) {
2079: while (rem == 0) {
2080: md = md->m_next;
2081: if (md == NULL) {
2082: error = EBADRPC;
2083: goto out;
2084: }
1.183 christos 2085: fromcp = mtod(md, void *);
1.1 cgd 2086: rem = md->m_len;
2087: }
1.43 fvdl 2088: if (*fromcp == '\0' || (!pubflag && *fromcp == '/')) {
1.25 fvdl 2089: error = EACCES;
1.1 cgd 2090: goto out;
2091: }
2092: *tocp++ = *fromcp++;
2093: rem--;
2094: }
2095: *tocp = '\0';
2096: *mdp = md;
2097: *dposp = fromcp;
2098: len = nfsm_rndup(len)-len;
2099: if (len > 0) {
2100: if (rem >= len)
2101: *dposp += len;
1.24 christos 2102: else if ((error = nfs_adv(mdp, dposp, len, rem)) != 0)
1.1 cgd 2103: goto out;
2104: }
1.43 fvdl 2105:
1.1 cgd 2106: /*
2107: * Extract and set starting directory.
2108: */
1.182 thorpej 2109: error = nfsrv_fhtovp(nsfh, false, &dp, ndp->ni_cnd.cn_cred, slp,
1.124 thorpej 2110: nam, &rdonly, kerbflag, pubflag);
1.24 christos 2111: if (error)
1.1 cgd 2112: goto out;
2113: if (dp->v_type != VDIR) {
2114: vrele(dp);
2115: error = ENOTDIR;
2116: goto out;
2117: }
1.43 fvdl 2118:
2119: if (rdonly)
2120: cnp->cn_flags |= RDONLY;
2121:
2122: *retdirp = dp;
2123:
2124: if (pubflag) {
2125: /*
2126: * Oh joy. For WebNFS, handle those pesky '%' escapes,
2127: * and the 'native path' indicator.
2128: */
1.81 thorpej 2129: cp = PNBUF_GET();
1.43 fvdl 2130: fromcp = cnp->cn_pnbuf;
2131: tocp = cp;
2132: if ((unsigned char)*fromcp >= WEBNFS_SPECCHAR_START) {
2133: switch ((unsigned char)*fromcp) {
2134: case WEBNFS_NATIVE_CHAR:
2135: /*
2136: * 'Native' path for us is the same
2137: * as a path according to the NFS spec,
2138: * just skip the escape char.
2139: */
2140: fromcp++;
2141: break;
2142: /*
2143: * More may be added in the future, range 0x80-0xff
2144: */
2145: default:
2146: error = EIO;
1.178 chs 2147: vrele(dp);
1.104 enami 2148: PNBUF_PUT(cp);
1.43 fvdl 2149: goto out;
2150: }
2151: }
2152: /*
2153: * Translate the '%' escapes, URL-style.
2154: */
2155: while (*fromcp != '\0') {
2156: if (*fromcp == WEBNFS_ESC_CHAR) {
2157: if (fromcp[1] != '\0' && fromcp[2] != '\0') {
2158: fromcp++;
2159: *tocp++ = HEXSTRTOI(fromcp);
2160: fromcp += 2;
2161: continue;
2162: } else {
2163: error = ENOENT;
1.178 chs 2164: vrele(dp);
1.104 enami 2165: PNBUF_PUT(cp);
1.43 fvdl 2166: goto out;
2167: }
2168: } else
2169: *tocp++ = *fromcp++;
2170: }
2171: *tocp = '\0';
1.81 thorpej 2172: PNBUF_PUT(cnp->cn_pnbuf);
1.43 fvdl 2173: cnp->cn_pnbuf = cp;
2174: }
2175:
2176: ndp->ni_pathlen = (tocp - cnp->cn_pnbuf) + 1;
2177: ndp->ni_segflg = UIO_SYSSPACE;
1.98 fvdl 2178: ndp->ni_rootdir = rootvnode;
1.185 dsl 2179: ndp->ni_erootdir = NULL;
1.43 fvdl 2180:
2181: if (pubflag) {
2182: ndp->ni_loopcnt = 0;
2183: if (cnp->cn_pnbuf[0] == '/')
2184: dp = rootvnode;
2185: } else {
2186: cnp->cn_flags |= NOCROSSMOUNT;
2187: }
2188:
1.25 fvdl 2189: VREF(dp);
1.178 chs 2190: vn_lock(dp, LK_EXCLUSIVE | LK_RETRY);
1.43 fvdl 2191:
2192: for (;;) {
2193: cnp->cn_nameptr = cnp->cn_pnbuf;
1.1 cgd 2194: ndp->ni_startdir = dp;
1.178 chs 2195:
1.1 cgd 2196: /*
2197: * And call lookup() to do the real work
2198: */
1.25 fvdl 2199: error = lookup(ndp);
1.91 fvdl 2200: if (error) {
1.178 chs 2201: if (ndp->ni_dvp) {
2202: vput(ndp->ni_dvp);
2203: }
1.91 fvdl 2204: PNBUF_PUT(cnp->cn_pnbuf);
2205: return (error);
2206: }
1.178 chs 2207:
1.1 cgd 2208: /*
2209: * Check for encountering a symbolic link
2210: */
1.43 fvdl 2211: if ((cnp->cn_flags & ISSYMLINK) == 0) {
1.178 chs 2212: if ((cnp->cn_flags & LOCKPARENT) == 0 && ndp->ni_dvp) {
2213: if (ndp->ni_dvp == ndp->ni_vp) {
2214: vrele(ndp->ni_dvp);
2215: } else {
2216: vput(ndp->ni_dvp);
2217: }
2218: }
1.91 fvdl 2219: if (cnp->cn_flags & (SAVENAME | SAVESTART))
1.43 fvdl 2220: cnp->cn_flags |= HASBUF;
1.91 fvdl 2221: else
2222: PNBUF_PUT(cnp->cn_pnbuf);
2223: return (0);
1.43 fvdl 2224: } else {
2225: if (!pubflag) {
2226: error = EINVAL;
2227: break;
2228: }
2229: if (ndp->ni_loopcnt++ >= MAXSYMLINKS) {
2230: error = ELOOP;
2231: break;
2232: }
1.91 fvdl 2233: if (ndp->ni_vp->v_mount->mnt_flag & MNT_SYMPERM) {
1.193 pooka 2234: error = VOP_ACCESS(ndp->ni_vp, VEXEC, cnp->cn_cred);
1.91 fvdl 2235: if (error != 0)
2236: break;
2237: }
1.43 fvdl 2238: if (ndp->ni_pathlen > 1)
1.81 thorpej 2239: cp = PNBUF_GET();
1.1 cgd 2240: else
1.43 fvdl 2241: cp = cnp->cn_pnbuf;
2242: aiov.iov_base = cp;
2243: aiov.iov_len = MAXPATHLEN;
2244: auio.uio_iov = &aiov;
2245: auio.uio_iovcnt = 1;
2246: auio.uio_offset = 0;
2247: auio.uio_rw = UIO_READ;
2248: auio.uio_resid = MAXPATHLEN;
1.158 yamt 2249: UIO_SETUP_SYSSPACE(&auio);
1.43 fvdl 2250: error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred);
2251: if (error) {
1.178 chs 2252: badlink:
1.43 fvdl 2253: if (ndp->ni_pathlen > 1)
1.81 thorpej 2254: PNBUF_PUT(cp);
1.43 fvdl 2255: break;
2256: }
2257: linklen = MAXPATHLEN - auio.uio_resid;
2258: if (linklen == 0) {
2259: error = ENOENT;
2260: goto badlink;
2261: }
2262: if (linklen + ndp->ni_pathlen >= MAXPATHLEN) {
2263: error = ENAMETOOLONG;
2264: goto badlink;
2265: }
2266: if (ndp->ni_pathlen > 1) {
1.63 perry 2267: memcpy(cp + linklen, ndp->ni_next, ndp->ni_pathlen);
1.81 thorpej 2268: PNBUF_PUT(cnp->cn_pnbuf);
1.43 fvdl 2269: cnp->cn_pnbuf = cp;
2270: } else
2271: cnp->cn_pnbuf[linklen] = '\0';
2272: ndp->ni_pathlen += linklen;
1.1 cgd 2273: vput(ndp->ni_vp);
1.43 fvdl 2274: dp = ndp->ni_dvp;
1.178 chs 2275:
1.43 fvdl 2276: /*
2277: * Check if root directory should replace current directory.
2278: */
2279: if (cnp->cn_pnbuf[0] == '/') {
1.178 chs 2280: vput(dp);
1.43 fvdl 2281: dp = ndp->ni_rootdir;
2282: VREF(dp);
1.178 chs 2283: vn_lock(dp, LK_EXCLUSIVE | LK_RETRY);
1.43 fvdl 2284: }
1.1 cgd 2285: }
1.43 fvdl 2286: }
1.178 chs 2287: vput(ndp->ni_dvp);
1.91 fvdl 2288: vput(ndp->ni_vp);
2289: ndp->ni_vp = NULL;
1.1 cgd 2290: out:
1.81 thorpej 2291: PNBUF_PUT(cnp->cn_pnbuf);
1.1 cgd 2292: return (error);
2293: }
1.153 jmmv 2294: #endif /* NFSSERVER */
1.1 cgd 2295:
2296: /*
1.118 yamt 2297: * A fiddled version of m_adj() that ensures null fill to a 32-bit
1.1 cgd 2298: * boundary and only trims off the back end
1.122 yamt 2299: *
2300: * 1. trim off 'len' bytes as m_adj(mp, -len).
2301: * 2. add zero-padding 'nul' bytes at the end of the mbuf chain.
1.1 cgd 2302: */
1.12 mycroft 2303: void
1.122 yamt 2304: nfs_zeropad(mp, len, nul)
1.1 cgd 2305: struct mbuf *mp;
1.75 augustss 2306: int len;
1.1 cgd 2307: int nul;
2308: {
1.75 augustss 2309: struct mbuf *m;
1.130 yamt 2310: int count;
1.1 cgd 2311:
2312: /*
2313: * Trim from tail. Scan the mbuf chain,
2314: * calculating its length and finding the last mbuf.
2315: * If the adjustment only affects this mbuf, then just
2316: * adjust and return. Otherwise, rescan and truncate
2317: * after the remaining size.
2318: */
2319: count = 0;
2320: m = mp;
2321: for (;;) {
2322: count += m->m_len;
1.122 yamt 2323: if (m->m_next == NULL)
1.1 cgd 2324: break;
2325: m = m->m_next;
2326: }
1.122 yamt 2327:
2328: KDASSERT(count >= len);
2329:
2330: if (m->m_len >= len) {
1.1 cgd 2331: m->m_len -= len;
1.122 yamt 2332: } else {
2333: count -= len;
2334: /*
2335: * Correct length for chain is "count".
2336: * Find the mbuf with last data, adjust its length,
2337: * and toss data from remaining mbufs on chain.
2338: */
2339: for (m = mp; m; m = m->m_next) {
2340: if (m->m_len >= count) {
2341: m->m_len = count;
2342: break;
1.118 yamt 2343: }
1.122 yamt 2344: count -= m->m_len;
1.1 cgd 2345: }
1.159 christos 2346: KASSERT(m && m->m_next);
1.122 yamt 2347: m_freem(m->m_next);
2348: m->m_next = NULL;
1.1 cgd 2349: }
1.122 yamt 2350:
1.130 yamt 2351: KDASSERT(m->m_next == NULL);
2352:
1.122 yamt 2353: /*
2354: * zero-padding.
2355: */
2356: if (nul > 0) {
1.130 yamt 2357: char *cp;
2358: int i;
2359:
1.122 yamt 2360: if (M_ROMAP(m) || M_TRAILINGSPACE(m) < nul) {
2361: struct mbuf *n;
2362:
2363: KDASSERT(MLEN >= nul);
2364: n = m_get(M_WAIT, MT_DATA);
2365: MCLAIM(n, &nfs_mowner);
2366: n->m_len = nul;
1.130 yamt 2367: n->m_next = NULL;
1.122 yamt 2368: m->m_next = n;
1.183 christos 2369: cp = mtod(n, void *);
1.122 yamt 2370: } else {
1.183 christos 2371: cp = mtod(m, char *) + m->m_len;
1.122 yamt 2372: m->m_len += nul;
1.1 cgd 2373: }
1.122 yamt 2374: for (i = 0; i < nul; i++)
2375: *cp++ = '\0';
1.1 cgd 2376: }
1.122 yamt 2377: return;
1.1 cgd 2378: }
2379:
2380: /*
1.25 fvdl 2381: * Make these functions instead of macros, so that the kernel text size
2382: * doesn't get too big...
2383: */
2384: void
2385: nfsm_srvwcc(nfsd, before_ret, before_vap, after_ret, after_vap, mbp, bposp)
2386: struct nfsrv_descript *nfsd;
2387: int before_ret;
1.75 augustss 2388: struct vattr *before_vap;
1.25 fvdl 2389: int after_ret;
2390: struct vattr *after_vap;
2391: struct mbuf **mbp;
2392: char **bposp;
2393: {
1.109 matt 2394: struct mbuf *mb = *mbp;
1.75 augustss 2395: char *bpos = *bposp;
2396: u_int32_t *tl;
1.25 fvdl 2397:
2398: if (before_ret) {
2399: nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED);
2400: *tl = nfs_false;
2401: } else {
2402: nfsm_build(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
2403: *tl++ = nfs_true;
1.66 fair 2404: txdr_hyper(before_vap->va_size, tl);
1.25 fvdl 2405: tl += 2;
2406: txdr_nfsv3time(&(before_vap->va_mtime), tl);
2407: tl += 2;
2408: txdr_nfsv3time(&(before_vap->va_ctime), tl);
2409: }
2410: *bposp = bpos;
2411: *mbp = mb;
2412: nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp);
2413: }
2414:
2415: void
2416: nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp)
2417: struct nfsrv_descript *nfsd;
2418: int after_ret;
2419: struct vattr *after_vap;
2420: struct mbuf **mbp;
2421: char **bposp;
2422: {
1.109 matt 2423: struct mbuf *mb = *mbp;
1.75 augustss 2424: char *bpos = *bposp;
2425: u_int32_t *tl;
2426: struct nfs_fattr *fp;
1.25 fvdl 2427:
2428: if (after_ret) {
2429: nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED);
2430: *tl = nfs_false;
2431: } else {
2432: nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_V3FATTR);
2433: *tl++ = nfs_true;
2434: fp = (struct nfs_fattr *)tl;
2435: nfsm_srvfattr(nfsd, after_vap, fp);
2436: }
2437: *mbp = mb;
2438: *bposp = bpos;
2439: }
2440:
2441: void
2442: nfsm_srvfattr(nfsd, vap, fp)
1.75 augustss 2443: struct nfsrv_descript *nfsd;
2444: struct vattr *vap;
2445: struct nfs_fattr *fp;
1.25 fvdl 2446: {
2447:
2448: fp->fa_nlink = txdr_unsigned(vap->va_nlink);
2449: fp->fa_uid = txdr_unsigned(vap->va_uid);
2450: fp->fa_gid = txdr_unsigned(vap->va_gid);
2451: if (nfsd->nd_flag & ND_NFSV3) {
2452: fp->fa_type = vtonfsv3_type(vap->va_type);
2453: fp->fa_mode = vtonfsv3_mode(vap->va_mode);
1.66 fair 2454: txdr_hyper(vap->va_size, &fp->fa3_size);
2455: txdr_hyper(vap->va_bytes, &fp->fa3_used);
1.25 fvdl 2456: fp->fa3_rdev.specdata1 = txdr_unsigned(major(vap->va_rdev));
2457: fp->fa3_rdev.specdata2 = txdr_unsigned(minor(vap->va_rdev));
2458: fp->fa3_fsid.nfsuquad[0] = 0;
2459: fp->fa3_fsid.nfsuquad[1] = txdr_unsigned(vap->va_fsid);
1.151 yamt 2460: txdr_hyper(vap->va_fileid, &fp->fa3_fileid);
1.25 fvdl 2461: txdr_nfsv3time(&vap->va_atime, &fp->fa3_atime);
2462: txdr_nfsv3time(&vap->va_mtime, &fp->fa3_mtime);
2463: txdr_nfsv3time(&vap->va_ctime, &fp->fa3_ctime);
2464: } else {
2465: fp->fa_type = vtonfsv2_type(vap->va_type);
2466: fp->fa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode);
2467: fp->fa2_size = txdr_unsigned(vap->va_size);
2468: fp->fa2_blocksize = txdr_unsigned(vap->va_blocksize);
2469: if (vap->va_type == VFIFO)
2470: fp->fa2_rdev = 0xffffffff;
2471: else
2472: fp->fa2_rdev = txdr_unsigned(vap->va_rdev);
2473: fp->fa2_blocks = txdr_unsigned(vap->va_bytes / NFS_FABLKSIZE);
2474: fp->fa2_fsid = txdr_unsigned(vap->va_fsid);
2475: fp->fa2_fileid = txdr_unsigned(vap->va_fileid);
2476: txdr_nfsv2time(&vap->va_atime, &fp->fa2_atime);
2477: txdr_nfsv2time(&vap->va_mtime, &fp->fa2_mtime);
2478: txdr_nfsv2time(&vap->va_ctime, &fp->fa2_ctime);
2479: }
2480: }
2481:
1.153 jmmv 2482: #ifdef NFSSERVER
1.25 fvdl 2483: /*
1.1 cgd 2484: * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked)
2485: * - look up fsid in mount list (if not found ret error)
1.12 mycroft 2486: * - get vp and export rights by calling VFS_FHTOVP()
2487: * - if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon
1.1 cgd 2488: * - if not lockflag unlock it with VOP_UNLOCK()
2489: */
1.24 christos 2490: int
1.177 yamt 2491: nfsrv_fhtovp(nfsrvfh_t *nsfh, int lockflag, struct vnode **vpp,
2492: kauth_cred_t cred, struct nfssvc_sock *slp, struct mbuf *nam, int *rdonlyp,
2493: int kerbflag, int pubflag)
1.1 cgd 2494: {
1.75 augustss 2495: struct mount *mp;
1.162 elad 2496: kauth_cred_t credanon;
1.12 mycroft 2497: int error, exflags;
1.40 fvdl 2498: struct sockaddr_in *saddr;
1.168 yamt 2499: fhandle_t *fhp;
1.1 cgd 2500:
1.168 yamt 2501: fhp = NFSRVFH_FHANDLE(nsfh);
1.12 mycroft 2502: *vpp = (struct vnode *)0;
1.43 fvdl 2503:
1.168 yamt 2504: if (nfs_ispublicfh(nsfh)) {
1.43 fvdl 2505: if (!pubflag || !nfs_pub.np_valid)
2506: return (ESTALE);
1.166 martin 2507: fhp = nfs_pub.np_handle;
1.43 fvdl 2508: }
2509:
1.154 yamt 2510: error = netexport_check(&fhp->fh_fsid, nam, &mp, &exflags, &credanon);
2511: if (error) {
2512: return error;
2513: }
2514:
1.124 thorpej 2515: error = VFS_FHTOVP(mp, &fhp->fh_fid, vpp);
1.24 christos 2516: if (error)
1.12 mycroft 2517: return (error);
1.40 fvdl 2518:
1.43 fvdl 2519: if (!(exflags & (MNT_EXNORESPORT|MNT_EXPUBLIC))) {
1.40 fvdl 2520: saddr = mtod(nam, struct sockaddr_in *);
1.76 fvdl 2521: if ((saddr->sin_family == AF_INET) &&
1.40 fvdl 2522: ntohs(saddr->sin_port) >= IPPORT_RESERVED) {
2523: vput(*vpp);
2524: return (NFSERR_AUTHERR | AUTH_TOOWEAK);
2525: }
1.76 fvdl 2526: #ifdef INET6
2527: if ((saddr->sin_family == AF_INET6) &&
2528: ntohs(saddr->sin_port) >= IPV6PORT_RESERVED) {
2529: vput(*vpp);
2530: return (NFSERR_AUTHERR | AUTH_TOOWEAK);
2531: }
2532: #endif
1.40 fvdl 2533: }
1.12 mycroft 2534: /*
2535: * Check/setup credentials.
2536: */
2537: if (exflags & MNT_EXKERB) {
1.25 fvdl 2538: if (!kerbflag) {
1.12 mycroft 2539: vput(*vpp);
1.25 fvdl 2540: return (NFSERR_AUTHERR | AUTH_TOOWEAK);
1.12 mycroft 2541: }
1.25 fvdl 2542: } else if (kerbflag) {
2543: vput(*vpp);
2544: return (NFSERR_AUTHERR | AUTH_TOOWEAK);
1.200 elad 2545: } else if (kauth_cred_geteuid(cred) == 0 || /* NFS maproot, see below */
2546: (exflags & MNT_EXPORTANON)) {
2547: /*
2548: * This is used by the NFS maproot option. While we can change
2549: * the secmodel on our own host, we can't change it on the
2550: * clients. As means of least surprise, we're doing the
2551: * traditional thing here.
2552: * Should look into adding a "mapprivileged" or similar where
2553: * the users can be explicitly specified...
2554: * [elad, yamt 2008-03-05]
2555: */
1.162 elad 2556: kauth_cred_clone(credanon, cred);
1.12 mycroft 2557: }
2558: if (exflags & MNT_EXRDONLY)
2559: *rdonlyp = 1;
2560: else
2561: *rdonlyp = 0;
1.1 cgd 2562: if (!lockflag)
1.56 fvdl 2563: VOP_UNLOCK(*vpp, 0);
1.1 cgd 2564: return (0);
1.43 fvdl 2565: }
2566:
2567: /*
2568: * WebNFS: check if a filehandle is a public filehandle. For v3, this
1.168 yamt 2569: * means a length of 0, for v2 it means all zeroes.
1.43 fvdl 2570: */
2571: int
1.168 yamt 2572: nfs_ispublicfh(const nfsrvfh_t *nsfh)
1.43 fvdl 2573: {
1.170 yamt 2574: const char *cp = (const void *)(NFSRVFH_DATA(nsfh));
1.43 fvdl 2575: int i;
2576:
1.168 yamt 2577: if (NFSRVFH_SIZE(nsfh) == 0) {
1.182 thorpej 2578: return true;
1.168 yamt 2579: }
2580: if (NFSRVFH_SIZE(nsfh) != NFSX_V2FH) {
1.182 thorpej 2581: return false;
1.168 yamt 2582: }
2583: for (i = 0; i < NFSX_V2FH; i++)
1.43 fvdl 2584: if (*cp++ != 0)
1.182 thorpej 2585: return false;
2586: return true;
1.1 cgd 2587: }
1.153 jmmv 2588: #endif /* NFSSERVER */
1.1 cgd 2589:
2590: /*
1.182 thorpej 2591: * This function compares two net addresses by family and returns true
1.12 mycroft 2592: * if they are the same host.
1.182 thorpej 2593: * If there is any doubt, return false.
1.12 mycroft 2594: * The AF_INET family is handled as a special case so that address mbufs
2595: * don't need to be saved to store "struct in_addr", which is only 4 bytes.
1.1 cgd 2596: */
1.24 christos 2597: int
1.12 mycroft 2598: netaddr_match(family, haddr, nam)
2599: int family;
2600: union nethostaddr *haddr;
2601: struct mbuf *nam;
1.1 cgd 2602: {
1.75 augustss 2603: struct sockaddr_in *inetaddr;
1.1 cgd 2604:
1.12 mycroft 2605: switch (family) {
2606: case AF_INET:
2607: inetaddr = mtod(nam, struct sockaddr_in *);
2608: if (inetaddr->sin_family == AF_INET &&
2609: inetaddr->sin_addr.s_addr == haddr->had_inetaddr)
2610: return (1);
2611: break;
1.76 fvdl 2612: #ifdef INET6
2613: case AF_INET6:
2614: {
2615: struct sockaddr_in6 *sin6_1, *sin6_2;
2616:
2617: sin6_1 = mtod(nam, struct sockaddr_in6 *);
2618: sin6_2 = mtod(haddr->had_nam, struct sockaddr_in6 *);
2619: if (sin6_1->sin6_family == AF_INET6 &&
2620: IN6_ARE_ADDR_EQUAL(&sin6_1->sin6_addr, &sin6_2->sin6_addr))
2621: return 1;
2622: }
2623: #endif
1.12 mycroft 2624: #ifdef ISO
2625: case AF_ISO:
2626: {
1.75 augustss 2627: struct sockaddr_iso *isoaddr1, *isoaddr2;
1.12 mycroft 2628:
2629: isoaddr1 = mtod(nam, struct sockaddr_iso *);
2630: isoaddr2 = mtod(haddr->had_nam, struct sockaddr_iso *);
2631: if (isoaddr1->siso_family == AF_ISO &&
2632: isoaddr1->siso_nlen > 0 &&
2633: isoaddr1->siso_nlen == isoaddr2->siso_nlen &&
2634: SAME_ISOADDR(isoaddr1, isoaddr2))
2635: return (1);
2636: break;
2637: }
2638: #endif /* ISO */
2639: default:
2640: break;
2641: };
2642: return (0);
1.25 fvdl 2643: }
2644:
2645: /*
2646: * The write verifier has changed (probably due to a server reboot), so all
1.114 yamt 2647: * PG_NEEDCOMMIT pages will have to be written again. Since they are marked
1.117 yamt 2648: * as dirty or are being written out just now, all this takes is clearing
2649: * the PG_NEEDCOMMIT flag. Once done the new write verifier can be set for
2650: * the mount point.
1.25 fvdl 2651: */
2652: void
2653: nfs_clearcommit(mp)
2654: struct mount *mp;
2655: {
1.89 chs 2656: struct vnode *vp;
1.83 fvdl 2657: struct nfsnode *np;
1.89 chs 2658: struct vm_page *pg;
1.116 yamt 2659: struct nfsmount *nmp = VFSTONFS(mp);
2660:
1.180 yamt 2661: rw_enter(&nmp->nm_writeverflock, RW_WRITER);
1.195 ad 2662: mutex_enter(&mntvnode_lock);
1.176 reinoud 2663: TAILQ_FOREACH(vp, &mp->mnt_vnodelist, v_mntvnodes) {
1.89 chs 2664: KASSERT(vp->v_mount == mp);
1.146 yamt 2665: if (vp->v_type != VREG)
1.85 enami 2666: continue;
1.83 fvdl 2667: np = VTONFS(vp);
2668: np->n_pushlo = np->n_pushhi = np->n_pushedlo =
2669: np->n_pushedhi = 0;
2670: np->n_commitflags &=
2671: ~(NFS_COMMIT_PUSH_VALID | NFS_COMMIT_PUSHED_VALID);
1.195 ad 2672: mutex_enter(&vp->v_uobj.vmobjlock);
1.202.2.1! wrstuden 2673: TAILQ_FOREACH(pg, &vp->v_uobj.memq, listq.queue) {
1.89 chs 2674: pg->flags &= ~PG_NEEDCOMMIT;
1.25 fvdl 2675: }
1.195 ad 2676: mutex_exit(&vp->v_uobj.vmobjlock);
1.25 fvdl 2677: }
1.195 ad 2678: mutex_exit(&mntvnode_lock);
1.186 yamt 2679: mutex_enter(&nmp->nm_lock);
1.116 yamt 2680: nmp->nm_iflag &= ~NFSMNT_STALEWRITEVERF;
1.186 yamt 2681: mutex_exit(&nmp->nm_lock);
1.180 yamt 2682: rw_exit(&nmp->nm_writeverflock);
1.83 fvdl 2683: }
2684:
2685: void
2686: nfs_merge_commit_ranges(vp)
2687: struct vnode *vp;
2688: {
2689: struct nfsnode *np = VTONFS(vp);
1.112 yamt 2690:
2691: KASSERT(np->n_commitflags & NFS_COMMIT_PUSH_VALID);
1.83 fvdl 2692:
2693: if (!(np->n_commitflags & NFS_COMMIT_PUSHED_VALID)) {
2694: np->n_pushedlo = np->n_pushlo;
2695: np->n_pushedhi = np->n_pushhi;
2696: np->n_commitflags |= NFS_COMMIT_PUSHED_VALID;
2697: } else {
2698: if (np->n_pushlo < np->n_pushedlo)
2699: np->n_pushedlo = np->n_pushlo;
2700: if (np->n_pushhi > np->n_pushedhi)
2701: np->n_pushedhi = np->n_pushhi;
2702: }
2703:
2704: np->n_pushlo = np->n_pushhi = 0;
2705: np->n_commitflags &= ~NFS_COMMIT_PUSH_VALID;
2706:
1.111 yamt 2707: #ifdef NFS_DEBUG_COMMIT
1.83 fvdl 2708: printf("merge: committed: %u - %u\n", (unsigned)np->n_pushedlo,
2709: (unsigned)np->n_pushedhi);
2710: #endif
2711: }
2712:
2713: int
1.89 chs 2714: nfs_in_committed_range(vp, off, len)
1.83 fvdl 2715: struct vnode *vp;
1.89 chs 2716: off_t off, len;
1.83 fvdl 2717: {
2718: struct nfsnode *np = VTONFS(vp);
2719: off_t lo, hi;
2720:
2721: if (!(np->n_commitflags & NFS_COMMIT_PUSHED_VALID))
2722: return 0;
1.89 chs 2723: lo = off;
2724: hi = lo + len;
1.83 fvdl 2725:
2726: return (lo >= np->n_pushedlo && hi <= np->n_pushedhi);
2727: }
2728:
2729: int
1.89 chs 2730: nfs_in_tobecommitted_range(vp, off, len)
1.83 fvdl 2731: struct vnode *vp;
1.89 chs 2732: off_t off, len;
1.83 fvdl 2733: {
2734: struct nfsnode *np = VTONFS(vp);
2735: off_t lo, hi;
2736:
2737: if (!(np->n_commitflags & NFS_COMMIT_PUSH_VALID))
2738: return 0;
1.89 chs 2739: lo = off;
2740: hi = lo + len;
1.83 fvdl 2741:
2742: return (lo >= np->n_pushlo && hi <= np->n_pushhi);
2743: }
2744:
2745: void
1.89 chs 2746: nfs_add_committed_range(vp, off, len)
1.83 fvdl 2747: struct vnode *vp;
1.89 chs 2748: off_t off, len;
1.83 fvdl 2749: {
2750: struct nfsnode *np = VTONFS(vp);
2751: off_t lo, hi;
2752:
1.89 chs 2753: lo = off;
2754: hi = lo + len;
1.83 fvdl 2755:
2756: if (!(np->n_commitflags & NFS_COMMIT_PUSHED_VALID)) {
2757: np->n_pushedlo = lo;
2758: np->n_pushedhi = hi;
2759: np->n_commitflags |= NFS_COMMIT_PUSHED_VALID;
2760: } else {
2761: if (hi > np->n_pushedhi)
2762: np->n_pushedhi = hi;
2763: if (lo < np->n_pushedlo)
2764: np->n_pushedlo = lo;
2765: }
1.111 yamt 2766: #ifdef NFS_DEBUG_COMMIT
1.83 fvdl 2767: printf("add: committed: %u - %u\n", (unsigned)np->n_pushedlo,
2768: (unsigned)np->n_pushedhi);
2769: #endif
2770: }
2771:
2772: void
1.89 chs 2773: nfs_del_committed_range(vp, off, len)
1.83 fvdl 2774: struct vnode *vp;
1.89 chs 2775: off_t off, len;
1.83 fvdl 2776: {
2777: struct nfsnode *np = VTONFS(vp);
2778: off_t lo, hi;
2779:
2780: if (!(np->n_commitflags & NFS_COMMIT_PUSHED_VALID))
2781: return;
2782:
1.89 chs 2783: lo = off;
2784: hi = lo + len;
1.83 fvdl 2785:
2786: if (lo > np->n_pushedhi || hi < np->n_pushedlo)
2787: return;
2788: if (lo <= np->n_pushedlo)
2789: np->n_pushedlo = hi;
2790: else if (hi >= np->n_pushedhi)
2791: np->n_pushedhi = lo;
2792: else {
2793: /*
2794: * XXX There's only one range. If the deleted range
2795: * is in the middle, pick the largest of the
2796: * contiguous ranges that it leaves.
2797: */
2798: if ((np->n_pushedlo - lo) > (hi - np->n_pushedhi))
2799: np->n_pushedhi = lo;
2800: else
2801: np->n_pushedlo = hi;
2802: }
1.111 yamt 2803: #ifdef NFS_DEBUG_COMMIT
1.83 fvdl 2804: printf("del: committed: %u - %u\n", (unsigned)np->n_pushedlo,
2805: (unsigned)np->n_pushedhi);
2806: #endif
2807: }
2808:
2809: void
1.89 chs 2810: nfs_add_tobecommitted_range(vp, off, len)
1.83 fvdl 2811: struct vnode *vp;
1.89 chs 2812: off_t off, len;
1.83 fvdl 2813: {
2814: struct nfsnode *np = VTONFS(vp);
2815: off_t lo, hi;
2816:
1.89 chs 2817: lo = off;
2818: hi = lo + len;
1.83 fvdl 2819:
2820: if (!(np->n_commitflags & NFS_COMMIT_PUSH_VALID)) {
2821: np->n_pushlo = lo;
2822: np->n_pushhi = hi;
2823: np->n_commitflags |= NFS_COMMIT_PUSH_VALID;
2824: } else {
2825: if (lo < np->n_pushlo)
2826: np->n_pushlo = lo;
2827: if (hi > np->n_pushhi)
2828: np->n_pushhi = hi;
2829: }
1.111 yamt 2830: #ifdef NFS_DEBUG_COMMIT
1.83 fvdl 2831: printf("add: tobecommitted: %u - %u\n", (unsigned)np->n_pushlo,
2832: (unsigned)np->n_pushhi);
2833: #endif
2834: }
2835:
2836: void
1.89 chs 2837: nfs_del_tobecommitted_range(vp, off, len)
1.83 fvdl 2838: struct vnode *vp;
1.89 chs 2839: off_t off, len;
1.83 fvdl 2840: {
2841: struct nfsnode *np = VTONFS(vp);
2842: off_t lo, hi;
2843:
2844: if (!(np->n_commitflags & NFS_COMMIT_PUSH_VALID))
2845: return;
2846:
1.89 chs 2847: lo = off;
2848: hi = lo + len;
1.83 fvdl 2849:
2850: if (lo > np->n_pushhi || hi < np->n_pushlo)
2851: return;
2852:
2853: if (lo <= np->n_pushlo)
2854: np->n_pushlo = hi;
2855: else if (hi >= np->n_pushhi)
2856: np->n_pushhi = lo;
2857: else {
2858: /*
2859: * XXX There's only one range. If the deleted range
2860: * is in the middle, pick the largest of the
2861: * contiguous ranges that it leaves.
2862: */
2863: if ((np->n_pushlo - lo) > (hi - np->n_pushhi))
2864: np->n_pushhi = lo;
2865: else
2866: np->n_pushlo = hi;
2867: }
1.111 yamt 2868: #ifdef NFS_DEBUG_COMMIT
1.83 fvdl 2869: printf("del: tobecommitted: %u - %u\n", (unsigned)np->n_pushlo,
2870: (unsigned)np->n_pushhi);
2871: #endif
1.25 fvdl 2872: }
2873:
2874: /*
2875: * Map errnos to NFS error numbers. For Version 3 also filter out error
2876: * numbers not specified for the associated procedure.
2877: */
2878: int
2879: nfsrv_errmap(nd, err)
2880: struct nfsrv_descript *nd;
1.75 augustss 2881: int err;
1.25 fvdl 2882: {
1.90 jdolecek 2883: const short *defaulterrp, *errp;
1.25 fvdl 2884:
2885: if (nd->nd_flag & ND_NFSV3) {
2886: if (nd->nd_procnum <= NFSPROC_COMMIT) {
2887: errp = defaulterrp = nfsrv_v3errmap[nd->nd_procnum];
2888: while (*++errp) {
2889: if (*errp == err)
2890: return (err);
2891: else if (*errp > err)
2892: break;
2893: }
2894: return ((int)*defaulterrp);
2895: } else
2896: return (err & 0xffff);
2897: }
2898: if (err <= ELAST)
2899: return ((int)nfsrv_v2errmap[err - 1]);
2900: return (NFSERR_IO);
2901: }
2902:
1.126 yamt 2903: u_int32_t
2904: nfs_getxid()
2905: {
2906: static u_int32_t base;
2907: static u_int32_t nfs_xid = 0;
2908: static struct simplelock nfs_xidlock = SIMPLELOCK_INITIALIZER;
2909: u_int32_t newxid;
2910:
2911: simple_lock(&nfs_xidlock);
2912: /*
2913: * derive initial xid from system time
2914: * XXX time is invalid if root not yet mounted
2915: */
2916: if (__predict_false(!base && (rootvp))) {
2917: struct timeval tv;
2918:
2919: microtime(&tv);
2920: base = tv.tv_sec << 12;
2921: nfs_xid = base;
2922: }
2923:
2924: /*
2925: * Skip zero xid if it should ever happen.
2926: */
2927: if (__predict_false(++nfs_xid == 0))
2928: nfs_xid++;
2929: newxid = nfs_xid;
2930: simple_unlock(&nfs_xidlock);
2931:
2932: return txdr_unsigned(newxid);
2933: }
2934:
2935: /*
2936: * assign a new xid for existing request.
2937: * used for NFSERR_JUKEBOX handling.
2938: */
2939: void
2940: nfs_renewxid(struct nfsreq *req)
2941: {
2942: u_int32_t xid;
2943: int off;
2944:
2945: xid = nfs_getxid();
2946: if (req->r_nmp->nm_sotype == SOCK_STREAM)
2947: off = sizeof(u_int32_t); /* RPC record mark */
2948: else
2949: off = 0;
2950:
2951: m_copyback(req->r_mreq, off, sizeof(xid), (void *)&xid);
2952: req->r_xid = xid;
1.1 cgd 2953: }
1.168 yamt 2954:
2955: #if defined(NFSSERVER)
2956: int
1.181 thorpej 2957: nfsrv_composefh(struct vnode *vp, nfsrvfh_t *nsfh, bool v3)
1.168 yamt 2958: {
2959: int error;
2960: size_t fhsize;
2961:
2962: fhsize = NFSD_MAXFHSIZE;
1.169 yamt 2963: error = vfs_composefh(vp, (void *)NFSRVFH_DATA(nsfh), &fhsize);
1.168 yamt 2964: if (NFSX_FHTOOBIG_P(fhsize, v3)) {
2965: error = EOPNOTSUPP;
2966: }
2967: if (error != 0) {
2968: return error;
2969: }
2970: if (!v3 && fhsize < NFSX_V2FH) {
2971: memset((char *)NFSRVFH_DATA(nsfh) + fhsize, 0,
2972: NFSX_V2FH - fhsize);
2973: fhsize = NFSX_V2FH;
2974: }
2975: if ((fhsize % NFSX_UNSIGNED) != 0) {
2976: return EOPNOTSUPP;
2977: }
2978: nsfh->nsfh_size = fhsize;
2979: return 0;
2980: }
2981:
2982: int
2983: nfsrv_comparefh(const nfsrvfh_t *fh1, const nfsrvfh_t *fh2)
2984: {
2985:
2986: if (NFSRVFH_SIZE(fh1) != NFSRVFH_SIZE(fh2)) {
2987: return NFSRVFH_SIZE(fh2) - NFSRVFH_SIZE(fh1);
2988: }
2989: return memcmp(NFSRVFH_DATA(fh1), NFSRVFH_DATA(fh2), NFSRVFH_SIZE(fh1));
2990: }
2991:
2992: void
2993: nfsrv_copyfh(nfsrvfh_t *fh1, const nfsrvfh_t *fh2)
2994: {
2995: size_t size;
2996:
2997: fh1->nsfh_size = size = NFSRVFH_SIZE(fh2);
2998: memcpy(NFSRVFH_DATA(fh1), NFSRVFH_DATA(fh2), size);
2999: }
3000: #endif /* defined(NFSSERVER) */
1.192 yamt 3001:
3002: #if defined(NFS)
3003: /*
3004: * Set the attribute timeout based on how recently the file has been modified.
3005: */
3006:
3007: time_t
3008: nfs_attrtimeo(struct nfsmount *nmp, struct nfsnode *np)
3009: {
3010: time_t timeo;
3011:
3012: if ((nmp->nm_flag & NFSMNT_NOAC) != 0)
3013: return 0;
3014:
3015: if (((np)->n_flag & NMODIFIED) != 0)
3016: return NFS_MINATTRTIMO;
3017:
3018: timeo = (time_second - np->n_mtime.tv_sec) / 10;
3019: timeo = max(timeo, NFS_MINATTRTIMO);
3020: timeo = min(timeo, NFS_MAXATTRTIMO);
3021: return timeo;
3022: }
3023: #endif /* defined(NFS) */
CVSweb <webmaster@jp.NetBSD.org>