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