|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * The contents of this file constitute Original Code as defined in and ! 7: * are subject to the Apple Public Source License Version 1.1 (the ! 8: * "License"). You may not use this file except in compliance with the ! 9: * License. Please obtain a copy of the License at ! 10: * http://www.apple.com/publicsource and read it before using this file. ! 11: * ! 12: * This Original Code and all software distributed under the License are ! 13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 17: * License for the specific language governing rights and limitations ! 18: * under the License. ! 19: * ! 20: * @APPLE_LICENSE_HEADER_END@ ! 21: */ ! 22: /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */ ! 23: /* ! 24: * Copyright (c) 1989, 1993 ! 25: * The Regents of the University of California. All rights reserved. ! 26: * ! 27: * This code is derived from software contributed to Berkeley by ! 28: * Rick Macklem at The University of Guelph. ! 29: * ! 30: * Redistribution and use in source and binary forms, with or without ! 31: * modification, are permitted provided that the following conditions ! 32: * are met: ! 33: * 1. Redistributions of source code must retain the above copyright ! 34: * notice, this list of conditions and the following disclaimer. ! 35: * 2. Redistributions in binary form must reproduce the above copyright ! 36: * notice, this list of conditions and the following disclaimer in the ! 37: * documentation and/or other materials provided with the distribution. ! 38: * 3. All advertising materials mentioning features or use of this software ! 39: * must display the following acknowledgement: ! 40: * This product includes software developed by the University of ! 41: * California, Berkeley and its contributors. ! 42: * 4. Neither the name of the University nor the names of its contributors ! 43: * may be used to endorse or promote products derived from this software ! 44: * without specific prior written permission. ! 45: * ! 46: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ! 47: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ! 48: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ! 49: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE ! 50: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ! 51: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ! 52: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ! 53: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ! 54: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ! 55: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ! 56: * SUCH DAMAGE. ! 57: * ! 58: * @(#)nfs_subs.c 8.8 (Berkeley) 5/22/95 ! 59: * FreeBSD-Id: nfs_subs.c,v 1.47 1997/11/07 08:53:24 phk Exp $ ! 60: */ ! 61: ! 62: /* ! 63: * These functions support the macros and help fiddle mbuf chains for ! 64: * the nfs op functions. They do things like create the rpc header and ! 65: * copy data between mbuf chains and uio lists. ! 66: */ ! 67: #include <mach_nbc.h> ! 68: #include <sys/param.h> ! 69: #include <sys/proc.h> ! 70: #include <sys/systm.h> ! 71: #include <sys/kernel.h> ! 72: #include <sys/mount.h> ! 73: #include <sys/vnode.h> ! 74: #include <sys/namei.h> ! 75: #include <sys/mbuf.h> ! 76: #include <sys/socket.h> ! 77: #include <sys/stat.h> ! 78: #include <sys/malloc.h> ! 79: #include <sys/syscall.h> ! 80: ! 81: #include <sys/vm.h> ! 82: #include <sys/vmparam.h> ! 83: #include <vm/vnode_pager.h> ! 84: #include <machine/spl.h> ! 85: ! 86: #include <sys/lock.h> ! 87: ! 88: #include <nfs/rpcv2.h> ! 89: #include <nfs/nfsproto.h> ! 90: #include <nfs/nfs.h> ! 91: #include <nfs/nfsnode.h> ! 92: #include <nfs/xdr_subs.h> ! 93: #include <nfs/nfsm_subs.h> ! 94: #include <nfs/nfsmount.h> ! 95: #include <nfs/nqnfs.h> ! 96: #include <nfs/nfsrtt.h> ! 97: ! 98: #include <miscfs/specfs/specdev.h> ! 99: ! 100: #include <netinet/in.h> ! 101: #if ISO ! 102: #include <netiso/iso.h> ! 103: #endif ! 104: ! 105: #if MACH_NBC ! 106: #include <kern/mapfs.h> ! 107: #endif /* MACH_NBC */ ! 108: ! 109: /* ! 110: * Data items converted to xdr at startup, since they are constant ! 111: * This is kinda hokey, but may save a little time doing byte swaps ! 112: */ ! 113: u_long nfs_xdrneg1; ! 114: u_long rpc_call, rpc_vers, rpc_reply, rpc_msgdenied, rpc_autherr, ! 115: rpc_mismatch, rpc_auth_unix, rpc_msgaccepted, ! 116: rpc_auth_kerb; ! 117: u_long nfs_prog, nqnfs_prog, nfs_true, nfs_false; ! 118: ! 119: /* And other global data */ ! 120: static u_long nfs_xid = 0; ! 121: static enum vtype nv2tov_type[8]= { ! 122: VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON, VNON ! 123: }; ! 124: enum vtype nv3tov_type[8]= { ! 125: VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO ! 126: }; ! 127: ! 128: int nfs_mount_type; ! 129: int nfs_ticks; ! 130: ! 131: struct nfs_reqq nfs_reqq; ! 132: struct nfssvc_sockhead nfssvc_sockhead; ! 133: int nfssvc_sockhead_flag; ! 134: struct nfsd_head nfsd_head; ! 135: int nfsd_head_flag; ! 136: struct nfs_bufq nfs_bufq; ! 137: struct nqtimerhead nqtimerhead; ! 138: struct nqfhhashhead *nqfhhashtbl; ! 139: u_long nqfhhash; ! 140: ! 141: #ifndef NFS_NOSERVER ! 142: /* ! 143: * Mapping of old NFS Version 2 RPC numbers to generic numbers. ! 144: */ ! 145: int nfsv3_procid[NFS_NPROCS] = { ! 146: NFSPROC_NULL, ! 147: NFSPROC_GETATTR, ! 148: NFSPROC_SETATTR, ! 149: NFSPROC_NOOP, ! 150: NFSPROC_LOOKUP, ! 151: NFSPROC_READLINK, ! 152: NFSPROC_READ, ! 153: NFSPROC_NOOP, ! 154: NFSPROC_WRITE, ! 155: NFSPROC_CREATE, ! 156: NFSPROC_REMOVE, ! 157: NFSPROC_RENAME, ! 158: NFSPROC_LINK, ! 159: NFSPROC_SYMLINK, ! 160: NFSPROC_MKDIR, ! 161: NFSPROC_RMDIR, ! 162: NFSPROC_READDIR, ! 163: NFSPROC_FSSTAT, ! 164: NFSPROC_NOOP, ! 165: NFSPROC_NOOP, ! 166: NFSPROC_NOOP, ! 167: NFSPROC_NOOP, ! 168: NFSPROC_NOOP, ! 169: NFSPROC_NOOP, ! 170: NFSPROC_NOOP, ! 171: NFSPROC_NOOP ! 172: }; ! 173: ! 174: #endif /* NFS_NOSERVER */ ! 175: /* ! 176: * and the reverse mapping from generic to Version 2 procedure numbers ! 177: */ ! 178: int nfsv2_procid[NFS_NPROCS] = { ! 179: NFSV2PROC_NULL, ! 180: NFSV2PROC_GETATTR, ! 181: NFSV2PROC_SETATTR, ! 182: NFSV2PROC_LOOKUP, ! 183: NFSV2PROC_NOOP, ! 184: NFSV2PROC_READLINK, ! 185: NFSV2PROC_READ, ! 186: NFSV2PROC_WRITE, ! 187: NFSV2PROC_CREATE, ! 188: NFSV2PROC_MKDIR, ! 189: NFSV2PROC_SYMLINK, ! 190: NFSV2PROC_CREATE, ! 191: NFSV2PROC_REMOVE, ! 192: NFSV2PROC_RMDIR, ! 193: NFSV2PROC_RENAME, ! 194: NFSV2PROC_LINK, ! 195: NFSV2PROC_READDIR, ! 196: NFSV2PROC_NOOP, ! 197: NFSV2PROC_STATFS, ! 198: NFSV2PROC_NOOP, ! 199: NFSV2PROC_NOOP, ! 200: NFSV2PROC_NOOP, ! 201: NFSV2PROC_NOOP, ! 202: NFSV2PROC_NOOP, ! 203: NFSV2PROC_NOOP, ! 204: NFSV2PROC_NOOP, ! 205: }; ! 206: ! 207: #ifndef NFS_NOSERVER ! 208: /* ! 209: * Maps errno values to nfs error numbers. ! 210: * Use NFSERR_IO as the catch all for ones not specifically defined in ! 211: * RFC 1094. ! 212: */ ! 213: static u_char nfsrv_v2errmap[ELAST] = { ! 214: NFSERR_PERM, NFSERR_NOENT, NFSERR_IO, NFSERR_IO, NFSERR_IO, ! 215: NFSERR_NXIO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, ! 216: NFSERR_IO, NFSERR_IO, NFSERR_ACCES, NFSERR_IO, NFSERR_IO, ! 217: NFSERR_IO, NFSERR_EXIST, NFSERR_IO, NFSERR_NODEV, NFSERR_NOTDIR, ! 218: NFSERR_ISDIR, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, ! 219: NFSERR_IO, NFSERR_FBIG, NFSERR_NOSPC, NFSERR_IO, NFSERR_ROFS, ! 220: NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, ! 221: NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, ! 222: NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, ! 223: NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, ! 224: NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, ! 225: NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, ! 226: NFSERR_IO, NFSERR_IO, NFSERR_NAMETOL, NFSERR_IO, NFSERR_IO, ! 227: NFSERR_NOTEMPTY, NFSERR_IO, NFSERR_IO, NFSERR_DQUOT, NFSERR_STALE, ! 228: NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, ! 229: NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, ! 230: NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, ! 231: }; ! 232: ! 233: /* ! 234: * Maps errno values to nfs error numbers. ! 235: * Although it is not obvious whether or not NFS clients really care if ! 236: * a returned error value is in the specified list for the procedure, the ! 237: * safest thing to do is filter them appropriately. For Version 2, the ! 238: * X/Open XNFS document is the only specification that defines error values ! 239: * for each RPC (The RFC simply lists all possible error values for all RPCs), ! 240: * so I have decided to not do this for Version 2. ! 241: * The first entry is the default error return and the rest are the valid ! 242: * errors for that RPC in increasing numeric order. ! 243: */ ! 244: static short nfsv3err_null[] = { ! 245: 0, ! 246: 0, ! 247: }; ! 248: ! 249: static short nfsv3err_getattr[] = { ! 250: NFSERR_IO, ! 251: NFSERR_IO, ! 252: NFSERR_STALE, ! 253: NFSERR_BADHANDLE, ! 254: NFSERR_SERVERFAULT, ! 255: 0, ! 256: }; ! 257: ! 258: static short nfsv3err_setattr[] = { ! 259: NFSERR_IO, ! 260: NFSERR_PERM, ! 261: NFSERR_IO, ! 262: NFSERR_ACCES, ! 263: NFSERR_INVAL, ! 264: NFSERR_NOSPC, ! 265: NFSERR_ROFS, ! 266: NFSERR_DQUOT, ! 267: NFSERR_STALE, ! 268: NFSERR_BADHANDLE, ! 269: NFSERR_NOT_SYNC, ! 270: NFSERR_SERVERFAULT, ! 271: 0, ! 272: }; ! 273: ! 274: static short nfsv3err_lookup[] = { ! 275: NFSERR_IO, ! 276: NFSERR_NOENT, ! 277: NFSERR_IO, ! 278: NFSERR_ACCES, ! 279: NFSERR_NOTDIR, ! 280: NFSERR_NAMETOL, ! 281: NFSERR_STALE, ! 282: NFSERR_BADHANDLE, ! 283: NFSERR_SERVERFAULT, ! 284: 0, ! 285: }; ! 286: ! 287: static short nfsv3err_access[] = { ! 288: NFSERR_IO, ! 289: NFSERR_IO, ! 290: NFSERR_STALE, ! 291: NFSERR_BADHANDLE, ! 292: NFSERR_SERVERFAULT, ! 293: 0, ! 294: }; ! 295: ! 296: static short nfsv3err_readlink[] = { ! 297: NFSERR_IO, ! 298: NFSERR_IO, ! 299: NFSERR_ACCES, ! 300: NFSERR_INVAL, ! 301: NFSERR_STALE, ! 302: NFSERR_BADHANDLE, ! 303: NFSERR_NOTSUPP, ! 304: NFSERR_SERVERFAULT, ! 305: 0, ! 306: }; ! 307: ! 308: static short nfsv3err_read[] = { ! 309: NFSERR_IO, ! 310: NFSERR_IO, ! 311: NFSERR_NXIO, ! 312: NFSERR_ACCES, ! 313: NFSERR_INVAL, ! 314: NFSERR_STALE, ! 315: NFSERR_BADHANDLE, ! 316: NFSERR_SERVERFAULT, ! 317: 0, ! 318: }; ! 319: ! 320: static short nfsv3err_write[] = { ! 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, ! 332: 0, ! 333: }; ! 334: ! 335: static short nfsv3err_create[] = { ! 336: NFSERR_IO, ! 337: NFSERR_IO, ! 338: NFSERR_ACCES, ! 339: NFSERR_EXIST, ! 340: NFSERR_NOTDIR, ! 341: NFSERR_NOSPC, ! 342: NFSERR_ROFS, ! 343: NFSERR_NAMETOL, ! 344: NFSERR_DQUOT, ! 345: NFSERR_STALE, ! 346: NFSERR_BADHANDLE, ! 347: NFSERR_NOTSUPP, ! 348: NFSERR_SERVERFAULT, ! 349: 0, ! 350: }; ! 351: ! 352: static short nfsv3err_mkdir[] = { ! 353: NFSERR_IO, ! 354: NFSERR_IO, ! 355: NFSERR_ACCES, ! 356: NFSERR_EXIST, ! 357: NFSERR_NOTDIR, ! 358: NFSERR_NOSPC, ! 359: NFSERR_ROFS, ! 360: NFSERR_NAMETOL, ! 361: NFSERR_DQUOT, ! 362: NFSERR_STALE, ! 363: NFSERR_BADHANDLE, ! 364: NFSERR_NOTSUPP, ! 365: NFSERR_SERVERFAULT, ! 366: 0, ! 367: }; ! 368: ! 369: static short nfsv3err_symlink[] = { ! 370: NFSERR_IO, ! 371: NFSERR_IO, ! 372: NFSERR_ACCES, ! 373: NFSERR_EXIST, ! 374: NFSERR_NOTDIR, ! 375: NFSERR_NOSPC, ! 376: NFSERR_ROFS, ! 377: NFSERR_NAMETOL, ! 378: NFSERR_DQUOT, ! 379: NFSERR_STALE, ! 380: NFSERR_BADHANDLE, ! 381: NFSERR_NOTSUPP, ! 382: NFSERR_SERVERFAULT, ! 383: 0, ! 384: }; ! 385: ! 386: static short nfsv3err_mknod[] = { ! 387: NFSERR_IO, ! 388: NFSERR_IO, ! 389: NFSERR_ACCES, ! 390: NFSERR_EXIST, ! 391: NFSERR_NOTDIR, ! 392: NFSERR_NOSPC, ! 393: NFSERR_ROFS, ! 394: NFSERR_NAMETOL, ! 395: NFSERR_DQUOT, ! 396: NFSERR_STALE, ! 397: NFSERR_BADHANDLE, ! 398: NFSERR_NOTSUPP, ! 399: NFSERR_SERVERFAULT, ! 400: NFSERR_BADTYPE, ! 401: 0, ! 402: }; ! 403: ! 404: static short nfsv3err_remove[] = { ! 405: NFSERR_IO, ! 406: NFSERR_NOENT, ! 407: NFSERR_IO, ! 408: NFSERR_ACCES, ! 409: NFSERR_NOTDIR, ! 410: NFSERR_ROFS, ! 411: NFSERR_NAMETOL, ! 412: NFSERR_STALE, ! 413: NFSERR_BADHANDLE, ! 414: NFSERR_SERVERFAULT, ! 415: 0, ! 416: }; ! 417: ! 418: static short nfsv3err_rmdir[] = { ! 419: NFSERR_IO, ! 420: NFSERR_NOENT, ! 421: NFSERR_IO, ! 422: NFSERR_ACCES, ! 423: NFSERR_EXIST, ! 424: NFSERR_NOTDIR, ! 425: NFSERR_INVAL, ! 426: NFSERR_ROFS, ! 427: NFSERR_NAMETOL, ! 428: NFSERR_NOTEMPTY, ! 429: NFSERR_STALE, ! 430: NFSERR_BADHANDLE, ! 431: NFSERR_NOTSUPP, ! 432: NFSERR_SERVERFAULT, ! 433: 0, ! 434: }; ! 435: ! 436: static short nfsv3err_rename[] = { ! 437: NFSERR_IO, ! 438: NFSERR_NOENT, ! 439: NFSERR_IO, ! 440: NFSERR_ACCES, ! 441: NFSERR_EXIST, ! 442: NFSERR_XDEV, ! 443: NFSERR_NOTDIR, ! 444: NFSERR_ISDIR, ! 445: NFSERR_INVAL, ! 446: NFSERR_NOSPC, ! 447: NFSERR_ROFS, ! 448: NFSERR_MLINK, ! 449: NFSERR_NAMETOL, ! 450: NFSERR_NOTEMPTY, ! 451: NFSERR_DQUOT, ! 452: NFSERR_STALE, ! 453: NFSERR_BADHANDLE, ! 454: NFSERR_NOTSUPP, ! 455: NFSERR_SERVERFAULT, ! 456: 0, ! 457: }; ! 458: ! 459: static short nfsv3err_link[] = { ! 460: NFSERR_IO, ! 461: NFSERR_IO, ! 462: NFSERR_ACCES, ! 463: NFSERR_EXIST, ! 464: NFSERR_XDEV, ! 465: NFSERR_NOTDIR, ! 466: NFSERR_INVAL, ! 467: NFSERR_NOSPC, ! 468: NFSERR_ROFS, ! 469: NFSERR_MLINK, ! 470: NFSERR_NAMETOL, ! 471: NFSERR_DQUOT, ! 472: NFSERR_STALE, ! 473: NFSERR_BADHANDLE, ! 474: NFSERR_NOTSUPP, ! 475: NFSERR_SERVERFAULT, ! 476: 0, ! 477: }; ! 478: ! 479: static short nfsv3err_readdir[] = { ! 480: NFSERR_IO, ! 481: NFSERR_IO, ! 482: NFSERR_ACCES, ! 483: NFSERR_NOTDIR, ! 484: NFSERR_STALE, ! 485: NFSERR_BADHANDLE, ! 486: NFSERR_BAD_COOKIE, ! 487: NFSERR_TOOSMALL, ! 488: NFSERR_SERVERFAULT, ! 489: 0, ! 490: }; ! 491: ! 492: static short nfsv3err_readdirplus[] = { ! 493: NFSERR_IO, ! 494: NFSERR_IO, ! 495: NFSERR_ACCES, ! 496: NFSERR_NOTDIR, ! 497: NFSERR_STALE, ! 498: NFSERR_BADHANDLE, ! 499: NFSERR_BAD_COOKIE, ! 500: NFSERR_NOTSUPP, ! 501: NFSERR_TOOSMALL, ! 502: NFSERR_SERVERFAULT, ! 503: 0, ! 504: }; ! 505: ! 506: static short nfsv3err_fsstat[] = { ! 507: NFSERR_IO, ! 508: NFSERR_IO, ! 509: NFSERR_STALE, ! 510: NFSERR_BADHANDLE, ! 511: NFSERR_SERVERFAULT, ! 512: 0, ! 513: }; ! 514: ! 515: static short nfsv3err_fsinfo[] = { ! 516: NFSERR_STALE, ! 517: NFSERR_STALE, ! 518: NFSERR_BADHANDLE, ! 519: NFSERR_SERVERFAULT, ! 520: 0, ! 521: }; ! 522: ! 523: static short nfsv3err_pathconf[] = { ! 524: NFSERR_STALE, ! 525: NFSERR_STALE, ! 526: NFSERR_BADHANDLE, ! 527: NFSERR_SERVERFAULT, ! 528: 0, ! 529: }; ! 530: ! 531: static short nfsv3err_commit[] = { ! 532: NFSERR_IO, ! 533: NFSERR_IO, ! 534: NFSERR_STALE, ! 535: NFSERR_BADHANDLE, ! 536: NFSERR_SERVERFAULT, ! 537: 0, ! 538: }; ! 539: ! 540: static short *nfsrv_v3errmap[] = { ! 541: nfsv3err_null, ! 542: nfsv3err_getattr, ! 543: nfsv3err_setattr, ! 544: nfsv3err_lookup, ! 545: nfsv3err_access, ! 546: nfsv3err_readlink, ! 547: nfsv3err_read, ! 548: nfsv3err_write, ! 549: nfsv3err_create, ! 550: nfsv3err_mkdir, ! 551: nfsv3err_symlink, ! 552: nfsv3err_mknod, ! 553: nfsv3err_remove, ! 554: nfsv3err_rmdir, ! 555: nfsv3err_rename, ! 556: nfsv3err_link, ! 557: nfsv3err_readdir, ! 558: nfsv3err_readdirplus, ! 559: nfsv3err_fsstat, ! 560: nfsv3err_fsinfo, ! 561: nfsv3err_pathconf, ! 562: nfsv3err_commit, ! 563: }; ! 564: ! 565: #endif /* NFS_NOSERVER */ ! 566: ! 567: extern struct nfsrtt nfsrtt; ! 568: extern time_t nqnfsstarttime; ! 569: extern int nqsrv_clockskew; ! 570: extern int nqsrv_writeslack; ! 571: extern int nqsrv_maxlease; ! 572: extern struct nfsstats nfsstats; ! 573: extern int nqnfs_piggy[NFS_NPROCS]; ! 574: extern nfstype nfsv2_type[9]; ! 575: extern nfstype nfsv3_type[9]; ! 576: extern struct nfsnodehashhead *nfsnodehashtbl; ! 577: extern u_long nfsnodehash; ! 578: ! 579: struct getfh_args; ! 580: extern int getfh(struct proc *, struct getfh_args *, int *); ! 581: struct nfssvc_args; ! 582: extern int nfssvc(struct proc *, struct nfssvc_args *, int *); ! 583: ! 584: extern void mapfs_memfree __P((struct vm_info *, boolean_t)); ! 585: ! 586: LIST_HEAD(nfsnodehashhead, nfsnode); ! 587: ! 588: int nfs_webnamei __P((struct nameidata *, struct vnode *, struct proc *)); ! 589: ! 590: /* ! 591: * Create the header for an rpc request packet ! 592: * The hsiz is the size of the rest of the nfs request header. ! 593: * (just used to decide if a cluster is a good idea) ! 594: */ ! 595: struct mbuf * ! 596: nfsm_reqh(vp, procid, hsiz, bposp) ! 597: struct vnode *vp; ! 598: u_long procid; ! 599: int hsiz; ! 600: caddr_t *bposp; ! 601: { ! 602: register struct mbuf *mb; ! 603: register u_long *tl; ! 604: register caddr_t bpos; ! 605: struct mbuf *mb2; ! 606: struct nfsmount *nmp; ! 607: int nqflag; ! 608: ! 609: MGET(mb, M_WAIT, MT_DATA); ! 610: if (hsiz >= MINCLSIZE) ! 611: MCLGET(mb, M_WAIT); ! 612: mb->m_len = 0; ! 613: bpos = mtod(mb, caddr_t); ! 614: ! 615: /* ! 616: * For NQNFS, add lease request. ! 617: */ ! 618: if (vp) { ! 619: nmp = VFSTONFS(vp->v_mount); ! 620: if (nmp->nm_flag & NFSMNT_NQNFS) { ! 621: nqflag = NQNFS_NEEDLEASE(vp, procid); ! 622: if (nqflag) { ! 623: nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED); ! 624: *tl++ = txdr_unsigned(nqflag); ! 625: *tl = txdr_unsigned(nmp->nm_leaseterm); ! 626: } else { ! 627: nfsm_build(tl, u_long *, NFSX_UNSIGNED); ! 628: *tl = 0; ! 629: } ! 630: } ! 631: } ! 632: /* Finally, return values */ ! 633: *bposp = bpos; ! 634: return (mb); ! 635: } ! 636: ! 637: /* ! 638: * Build the RPC header and fill in the authorization info. ! 639: * The authorization string argument is only used when the credentials ! 640: * come from outside of the kernel. ! 641: * Returns the head of the mbuf list. ! 642: */ ! 643: struct mbuf * ! 644: nfsm_rpchead(cr, nmflag, procid, auth_type, auth_len, auth_str, verf_len, ! 645: verf_str, mrest, mrest_len, mbp, xidp) ! 646: register struct ucred *cr; ! 647: int nmflag; ! 648: int procid; ! 649: int auth_type; ! 650: int auth_len; ! 651: char *auth_str; ! 652: int verf_len; ! 653: char *verf_str; ! 654: struct mbuf *mrest; ! 655: int mrest_len; ! 656: struct mbuf **mbp; ! 657: u_long *xidp; ! 658: { ! 659: register struct mbuf *mb; ! 660: register u_long *tl; ! 661: register caddr_t bpos; ! 662: register int i; ! 663: struct mbuf *mreq, *mb2; ! 664: int siz, grpsiz, authsiz; ! 665: struct timeval tv; ! 666: static u_long base; ! 667: ! 668: authsiz = nfsm_rndup(auth_len); ! 669: MGETHDR(mb, M_WAIT, MT_DATA); ! 670: if ((authsiz + 10 * NFSX_UNSIGNED) >= MINCLSIZE) { ! 671: MCLGET(mb, M_WAIT); ! 672: } else if ((authsiz + 10 * NFSX_UNSIGNED) < MHLEN) { ! 673: MH_ALIGN(mb, authsiz + 10 * NFSX_UNSIGNED); ! 674: } else { ! 675: MH_ALIGN(mb, 8 * NFSX_UNSIGNED); ! 676: } ! 677: mb->m_len = 0; ! 678: mreq = mb; ! 679: bpos = mtod(mb, caddr_t); ! 680: ! 681: /* ! 682: * First the RPC header. ! 683: */ ! 684: nfsm_build(tl, u_long *, 8 * NFSX_UNSIGNED); ! 685: ! 686: /* ! 687: * derive initial xid from system time ! 688: * XXX time is invalid if root not yet mounted ! 689: */ ! 690: if (!base && (rootvp)) { ! 691: microtime(&tv); ! 692: base = tv.tv_sec << 12; ! 693: nfs_xid = base; ! 694: } ! 695: /* ! 696: * Skip zero xid if it should ever happen. ! 697: */ ! 698: if (++nfs_xid == 0) ! 699: nfs_xid++; ! 700: ! 701: *tl++ = *xidp = txdr_unsigned(nfs_xid); ! 702: *tl++ = rpc_call; ! 703: *tl++ = rpc_vers; ! 704: if (nmflag & NFSMNT_NQNFS) { ! 705: *tl++ = txdr_unsigned(NQNFS_PROG); ! 706: *tl++ = txdr_unsigned(NQNFS_VER3); ! 707: } else { ! 708: *tl++ = txdr_unsigned(NFS_PROG); ! 709: if (nmflag & NFSMNT_NFSV3) ! 710: *tl++ = txdr_unsigned(NFS_VER3); ! 711: else ! 712: *tl++ = txdr_unsigned(NFS_VER2); ! 713: } ! 714: if (nmflag & NFSMNT_NFSV3) ! 715: *tl++ = txdr_unsigned(procid); ! 716: else ! 717: *tl++ = txdr_unsigned(nfsv2_procid[procid]); ! 718: ! 719: /* ! 720: * And then the authorization cred. ! 721: */ ! 722: *tl++ = txdr_unsigned(auth_type); ! 723: *tl = txdr_unsigned(authsiz); ! 724: switch (auth_type) { ! 725: case RPCAUTH_UNIX: ! 726: nfsm_build(tl, u_long *, auth_len); ! 727: *tl++ = 0; /* stamp ?? */ ! 728: *tl++ = 0; /* NULL hostname */ ! 729: *tl++ = txdr_unsigned(cr->cr_uid); ! 730: *tl++ = txdr_unsigned(cr->cr_groups[0]); ! 731: grpsiz = (auth_len >> 2) - 5; ! 732: *tl++ = txdr_unsigned(grpsiz); ! 733: for (i = 1; i <= grpsiz; i++) ! 734: *tl++ = txdr_unsigned(cr->cr_groups[i]); ! 735: break; ! 736: case RPCAUTH_KERB4: ! 737: siz = auth_len; ! 738: while (siz > 0) { ! 739: if (M_TRAILINGSPACE(mb) == 0) { ! 740: MGET(mb2, M_WAIT, MT_DATA); ! 741: if (siz >= MINCLSIZE) ! 742: MCLGET(mb2, M_WAIT); ! 743: mb->m_next = mb2; ! 744: mb = mb2; ! 745: mb->m_len = 0; ! 746: bpos = mtod(mb, caddr_t); ! 747: } ! 748: i = min(siz, M_TRAILINGSPACE(mb)); ! 749: bcopy(auth_str, bpos, i); ! 750: mb->m_len += i; ! 751: auth_str += i; ! 752: bpos += i; ! 753: siz -= i; ! 754: } ! 755: if ((siz = (nfsm_rndup(auth_len) - auth_len)) > 0) { ! 756: for (i = 0; i < siz; i++) ! 757: *bpos++ = '\0'; ! 758: mb->m_len += siz; ! 759: } ! 760: break; ! 761: }; ! 762: ! 763: /* ! 764: * And the verifier... ! 765: */ ! 766: nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED); ! 767: if (verf_str) { ! 768: *tl++ = txdr_unsigned(RPCAUTH_KERB4); ! 769: *tl = txdr_unsigned(verf_len); ! 770: siz = verf_len; ! 771: while (siz > 0) { ! 772: if (M_TRAILINGSPACE(mb) == 0) { ! 773: MGET(mb2, M_WAIT, MT_DATA); ! 774: if (siz >= MINCLSIZE) ! 775: MCLGET(mb2, M_WAIT); ! 776: mb->m_next = mb2; ! 777: mb = mb2; ! 778: mb->m_len = 0; ! 779: bpos = mtod(mb, caddr_t); ! 780: } ! 781: i = min(siz, M_TRAILINGSPACE(mb)); ! 782: bcopy(verf_str, bpos, i); ! 783: mb->m_len += i; ! 784: verf_str += i; ! 785: bpos += i; ! 786: siz -= i; ! 787: } ! 788: if ((siz = (nfsm_rndup(verf_len) - verf_len)) > 0) { ! 789: for (i = 0; i < siz; i++) ! 790: *bpos++ = '\0'; ! 791: mb->m_len += siz; ! 792: } ! 793: } else { ! 794: *tl++ = txdr_unsigned(RPCAUTH_NULL); ! 795: *tl = 0; ! 796: } ! 797: mb->m_next = mrest; ! 798: mreq->m_pkthdr.len = authsiz + 10 * NFSX_UNSIGNED + mrest_len; ! 799: mreq->m_pkthdr.rcvif = (struct ifnet *)0; ! 800: *mbp = mb; ! 801: return (mreq); ! 802: } ! 803: ! 804: /* ! 805: * copies mbuf chain to the uio scatter/gather list ! 806: */ ! 807: int ! 808: nfsm_mbuftouio(mrep, uiop, siz, dpos) ! 809: struct mbuf **mrep; ! 810: register struct uio *uiop; ! 811: int siz; ! 812: caddr_t *dpos; ! 813: { ! 814: register char *mbufcp, *uiocp; ! 815: register int xfer, left, len; ! 816: register struct mbuf *mp; ! 817: long uiosiz, rem; ! 818: int error = 0; ! 819: ! 820: mp = *mrep; ! 821: mbufcp = *dpos; ! 822: len = mtod(mp, caddr_t)+mp->m_len-mbufcp; ! 823: rem = nfsm_rndup(siz)-siz; ! 824: while (siz > 0) { ! 825: if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) ! 826: return (EFBIG); ! 827: left = uiop->uio_iov->iov_len; ! 828: uiocp = uiop->uio_iov->iov_base; ! 829: if (left > siz) ! 830: left = siz; ! 831: uiosiz = left; ! 832: while (left > 0) { ! 833: while (len == 0) { ! 834: mp = mp->m_next; ! 835: if (mp == NULL) ! 836: return (EBADRPC); ! 837: mbufcp = mtod(mp, caddr_t); ! 838: len = mp->m_len; ! 839: } ! 840: xfer = (left > len) ? len : left; ! 841: #ifdef notdef ! 842: /* Not Yet.. */ ! 843: if (uiop->uio_iov->iov_op != NULL) ! 844: (*(uiop->uio_iov->iov_op)) ! 845: (mbufcp, uiocp, xfer); ! 846: else ! 847: #endif ! 848: if (uiop->uio_segflg == UIO_SYSSPACE) ! 849: bcopy(mbufcp, uiocp, xfer); ! 850: else ! 851: copyout(mbufcp, uiocp, xfer); ! 852: left -= xfer; ! 853: len -= xfer; ! 854: mbufcp += xfer; ! 855: uiocp += xfer; ! 856: uiop->uio_offset += xfer; ! 857: uiop->uio_resid -= xfer; ! 858: } ! 859: if (uiop->uio_iov->iov_len <= siz) { ! 860: uiop->uio_iovcnt--; ! 861: uiop->uio_iov++; ! 862: } else { ! 863: uiop->uio_iov->iov_base += uiosiz; ! 864: uiop->uio_iov->iov_len -= uiosiz; ! 865: } ! 866: siz -= uiosiz; ! 867: } ! 868: *dpos = mbufcp; ! 869: *mrep = mp; ! 870: if (rem > 0) { ! 871: if (len < rem) ! 872: error = nfs_adv(mrep, dpos, rem, len); ! 873: else ! 874: *dpos += rem; ! 875: } ! 876: return (error); ! 877: } ! 878: ! 879: /* ! 880: * copies a uio scatter/gather list to an mbuf chain. ! 881: * NOTE: can ony handle iovcnt == 1 ! 882: */ ! 883: int ! 884: nfsm_uiotombuf(uiop, mq, siz, bpos) ! 885: register struct uio *uiop; ! 886: struct mbuf **mq; ! 887: int siz; ! 888: caddr_t *bpos; ! 889: { ! 890: register char *uiocp; ! 891: register struct mbuf *mp, *mp2; ! 892: register int xfer, left, mlen; ! 893: int uiosiz, clflg, rem; ! 894: char *cp; ! 895: ! 896: if (uiop->uio_iovcnt != 1) ! 897: panic("nfsm_uiotombuf: iovcnt != 1"); ! 898: ! 899: if (siz > MLEN) /* or should it >= MCLBYTES ?? */ ! 900: clflg = 1; ! 901: else ! 902: clflg = 0; ! 903: rem = nfsm_rndup(siz)-siz; ! 904: mp = mp2 = *mq; ! 905: while (siz > 0) { ! 906: left = uiop->uio_iov->iov_len; ! 907: uiocp = uiop->uio_iov->iov_base; ! 908: if (left > siz) ! 909: left = siz; ! 910: uiosiz = left; ! 911: while (left > 0) { ! 912: mlen = M_TRAILINGSPACE(mp); ! 913: if (mlen == 0) { ! 914: MGET(mp, M_WAIT, MT_DATA); ! 915: if (clflg) ! 916: MCLGET(mp, M_WAIT); ! 917: mp->m_len = 0; ! 918: mp2->m_next = mp; ! 919: mp2 = mp; ! 920: mlen = M_TRAILINGSPACE(mp); ! 921: } ! 922: xfer = (left > mlen) ? mlen : left; ! 923: #ifdef notdef ! 924: /* Not Yet.. */ ! 925: if (uiop->uio_iov->iov_op != NULL) ! 926: (*(uiop->uio_iov->iov_op)) ! 927: (uiocp, mtod(mp, caddr_t)+mp->m_len, xfer); ! 928: else ! 929: #endif ! 930: if (uiop->uio_segflg == UIO_SYSSPACE) ! 931: bcopy(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer); ! 932: else ! 933: copyin(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer); ! 934: mp->m_len += xfer; ! 935: left -= xfer; ! 936: uiocp += xfer; ! 937: uiop->uio_offset += xfer; ! 938: uiop->uio_resid -= xfer; ! 939: } ! 940: uiop->uio_iov->iov_base += uiosiz; ! 941: uiop->uio_iov->iov_len -= uiosiz; ! 942: siz -= uiosiz; ! 943: } ! 944: if (rem > 0) { ! 945: if (rem > M_TRAILINGSPACE(mp)) { ! 946: MGET(mp, M_WAIT, MT_DATA); ! 947: mp->m_len = 0; ! 948: mp2->m_next = mp; ! 949: } ! 950: cp = mtod(mp, caddr_t)+mp->m_len; ! 951: for (left = 0; left < rem; left++) ! 952: *cp++ = '\0'; ! 953: mp->m_len += rem; ! 954: *bpos = cp; ! 955: } else ! 956: *bpos = mtod(mp, caddr_t)+mp->m_len; ! 957: *mq = mp; ! 958: return (0); ! 959: } ! 960: ! 961: /* ! 962: * Help break down an mbuf chain by setting the first siz bytes contiguous ! 963: * pointed to by returned val. ! 964: * This is used by the macros nfsm_dissect and nfsm_dissecton for tough ! 965: * cases. (The macros use the vars. dpos and dpos2) ! 966: */ ! 967: int ! 968: nfsm_disct(mdp, dposp, siz, left, cp2) ! 969: struct mbuf **mdp; ! 970: caddr_t *dposp; ! 971: int siz; ! 972: int left; ! 973: caddr_t *cp2; ! 974: { ! 975: register struct mbuf *mp, *mp2; ! 976: register int siz2, xfer; ! 977: register caddr_t p; ! 978: ! 979: mp = *mdp; ! 980: while (left == 0) { ! 981: *mdp = mp = mp->m_next; ! 982: if (mp == NULL) ! 983: return (EBADRPC); ! 984: left = mp->m_len; ! 985: *dposp = mtod(mp, caddr_t); ! 986: } ! 987: if (left >= siz) { ! 988: *cp2 = *dposp; ! 989: *dposp += siz; ! 990: } else if (mp->m_next == NULL) { ! 991: return (EBADRPC); ! 992: } else if (siz > MHLEN) { ! 993: panic("nfs S too big"); ! 994: } else { ! 995: MGET(mp2, M_WAIT, MT_DATA); ! 996: mp2->m_next = mp->m_next; ! 997: mp->m_next = mp2; ! 998: mp->m_len -= left; ! 999: mp = mp2; ! 1000: *cp2 = p = mtod(mp, caddr_t); ! 1001: bcopy(*dposp, p, left); /* Copy what was left */ ! 1002: siz2 = siz-left; ! 1003: p += left; ! 1004: mp2 = mp->m_next; ! 1005: /* Loop around copying up the siz2 bytes */ ! 1006: while (siz2 > 0) { ! 1007: if (mp2 == NULL) ! 1008: return (EBADRPC); ! 1009: xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2; ! 1010: if (xfer > 0) { ! 1011: bcopy(mtod(mp2, caddr_t), p, xfer); ! 1012: NFSMADV(mp2, xfer); ! 1013: mp2->m_len -= xfer; ! 1014: p += xfer; ! 1015: siz2 -= xfer; ! 1016: } ! 1017: if (siz2 > 0) ! 1018: mp2 = mp2->m_next; ! 1019: } ! 1020: mp->m_len = siz; ! 1021: *mdp = mp2; ! 1022: *dposp = mtod(mp2, caddr_t); ! 1023: } ! 1024: return (0); ! 1025: } ! 1026: ! 1027: /* ! 1028: * Advance the position in the mbuf chain. ! 1029: */ ! 1030: int ! 1031: nfs_adv(mdp, dposp, offs, left) ! 1032: struct mbuf **mdp; ! 1033: caddr_t *dposp; ! 1034: int offs; ! 1035: int left; ! 1036: { ! 1037: register struct mbuf *m; ! 1038: register int s; ! 1039: ! 1040: m = *mdp; ! 1041: s = left; ! 1042: while (s < offs) { ! 1043: offs -= s; ! 1044: m = m->m_next; ! 1045: if (m == NULL) ! 1046: return (EBADRPC); ! 1047: s = m->m_len; ! 1048: } ! 1049: *mdp = m; ! 1050: *dposp = mtod(m, caddr_t)+offs; ! 1051: return (0); ! 1052: } ! 1053: ! 1054: /* ! 1055: * Copy a string into mbufs for the hard cases... ! 1056: */ ! 1057: int ! 1058: nfsm_strtmbuf(mb, bpos, cp, siz) ! 1059: struct mbuf **mb; ! 1060: char **bpos; ! 1061: char *cp; ! 1062: long siz; ! 1063: { ! 1064: register struct mbuf *m1 = 0, *m2; ! 1065: long left, xfer, len, tlen; ! 1066: u_long *tl; ! 1067: int putsize; ! 1068: ! 1069: putsize = 1; ! 1070: m2 = *mb; ! 1071: left = M_TRAILINGSPACE(m2); ! 1072: if (left > 0) { ! 1073: tl = ((u_long *)(*bpos)); ! 1074: *tl++ = txdr_unsigned(siz); ! 1075: putsize = 0; ! 1076: left -= NFSX_UNSIGNED; ! 1077: m2->m_len += NFSX_UNSIGNED; ! 1078: if (left > 0) { ! 1079: bcopy(cp, (caddr_t) tl, left); ! 1080: siz -= left; ! 1081: cp += left; ! 1082: m2->m_len += left; ! 1083: left = 0; ! 1084: } ! 1085: } ! 1086: /* Loop around adding mbufs */ ! 1087: while (siz > 0) { ! 1088: MGET(m1, M_WAIT, MT_DATA); ! 1089: if (siz > MLEN) ! 1090: MCLGET(m1, M_WAIT); ! 1091: m1->m_len = NFSMSIZ(m1); ! 1092: m2->m_next = m1; ! 1093: m2 = m1; ! 1094: tl = mtod(m1, u_long *); ! 1095: tlen = 0; ! 1096: if (putsize) { ! 1097: *tl++ = txdr_unsigned(siz); ! 1098: m1->m_len -= NFSX_UNSIGNED; ! 1099: tlen = NFSX_UNSIGNED; ! 1100: putsize = 0; ! 1101: } ! 1102: if (siz < m1->m_len) { ! 1103: len = nfsm_rndup(siz); ! 1104: xfer = siz; ! 1105: if (xfer < len) ! 1106: *(tl+(xfer>>2)) = 0; ! 1107: } else { ! 1108: xfer = len = m1->m_len; ! 1109: } ! 1110: bcopy(cp, (caddr_t) tl, xfer); ! 1111: m1->m_len = len+tlen; ! 1112: siz -= xfer; ! 1113: cp += xfer; ! 1114: } ! 1115: *mb = m1; ! 1116: *bpos = mtod(m1, caddr_t)+m1->m_len; ! 1117: return (0); ! 1118: } ! 1119: ! 1120: /* ! 1121: * Called once to initialize data structures... ! 1122: */ ! 1123: int ! 1124: nfs_init(vfsp) ! 1125: struct vfsconf *vfsp; ! 1126: { ! 1127: register int i; ! 1128: ! 1129: /* ! 1130: * Check to see if major data structures haven't bloated. ! 1131: */ ! 1132: if (sizeof (struct nfsnode) > NFS_NODEALLOC) { ! 1133: printf("struct nfsnode bloated (> %dbytes)\n", NFS_NODEALLOC); ! 1134: printf("Try reducing NFS_SMALLFH\n"); ! 1135: } ! 1136: if (sizeof (struct nfsmount) > NFS_MNTALLOC) { ! 1137: printf("struct nfsmount bloated (> %dbytes)\n", NFS_MNTALLOC); ! 1138: printf("Try reducing NFS_MUIDHASHSIZ\n"); ! 1139: } ! 1140: if (sizeof (struct nfssvc_sock) > NFS_SVCALLOC) { ! 1141: printf("struct nfssvc_sock bloated (> %dbytes)\n",NFS_SVCALLOC); ! 1142: printf("Try reducing NFS_UIDHASHSIZ\n"); ! 1143: } ! 1144: if (sizeof (struct nfsuid) > NFS_UIDALLOC) { ! 1145: printf("struct nfsuid bloated (> %dbytes)\n",NFS_UIDALLOC); ! 1146: printf("Try unionizing the nu_nickname and nu_flag fields\n"); ! 1147: } ! 1148: nfs_mount_type = vfsp->vfc_typenum; ! 1149: nfsrtt.pos = 0; ! 1150: rpc_vers = txdr_unsigned(RPC_VER2); ! 1151: rpc_call = txdr_unsigned(RPC_CALL); ! 1152: rpc_reply = txdr_unsigned(RPC_REPLY); ! 1153: rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED); ! 1154: rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED); ! 1155: rpc_mismatch = txdr_unsigned(RPC_MISMATCH); ! 1156: rpc_autherr = txdr_unsigned(RPC_AUTHERR); ! 1157: rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX); ! 1158: rpc_auth_kerb = txdr_unsigned(RPCAUTH_KERB4); ! 1159: nfs_prog = txdr_unsigned(NFS_PROG); ! 1160: nqnfs_prog = txdr_unsigned(NQNFS_PROG); ! 1161: nfs_true = txdr_unsigned(TRUE); ! 1162: nfs_false = txdr_unsigned(FALSE); ! 1163: nfs_xdrneg1 = txdr_unsigned(-1); ! 1164: nfs_ticks = (hz * NFS_TICKINTVL + 500) / 1000; ! 1165: if (nfs_ticks < 1) ! 1166: nfs_ticks = 1; ! 1167: /* Ensure async daemons disabled */ ! 1168: for (i = 0; i < NFS_MAXASYNCDAEMON; i++) { ! 1169: nfs_iodwant[i] = (struct proc *)0; ! 1170: nfs_iodmount[i] = (struct nfsmount *)0; ! 1171: } ! 1172: nfs_nhinit(); /* Init the nfsnode table */ ! 1173: #ifndef NFS_NOSERVER ! 1174: nfsrv_init(0); /* Init server data structures */ ! 1175: nfsrv_initcache(); /* Init the server request cache */ ! 1176: #endif ! 1177: ! 1178: /* ! 1179: * Initialize the nqnfs server stuff. ! 1180: */ ! 1181: if (nqnfsstarttime == 0) { ! 1182: nqnfsstarttime = boottime.tv_sec + nqsrv_maxlease ! 1183: + nqsrv_clockskew + nqsrv_writeslack; ! 1184: NQLOADNOVRAM(nqnfsstarttime); ! 1185: CIRCLEQ_INIT(&nqtimerhead); ! 1186: nqfhhashtbl = hashinit(NQLCHSZ, M_NQLEASE, &nqfhhash); ! 1187: } ! 1188: ! 1189: /* ! 1190: * Initialize reply list and start timer ! 1191: */ ! 1192: TAILQ_INIT(&nfs_reqq); ! 1193: ! 1194: nfs_timer(0); ! 1195: ! 1196: ! 1197: /* XXX CSM 12/4/97 Where are these declared in FreeBSD? */ ! 1198: #ifdef notyet ! 1199: /* ! 1200: * Set up lease_check and lease_updatetime so that other parts ! 1201: * of the system can call us, if we are loadable. ! 1202: */ ! 1203: #ifndef NFS_NOSERVER ! 1204: default_vnodeop_p[VOFFSET(vop_lease)] = (vop_t *)nqnfs_vop_lease_check; ! 1205: #endif ! 1206: lease_updatetime = nfs_lease_updatetime; ! 1207: #endif ! 1208: vfsp->vfc_refcount++; /* make us non-unloadable */ ! 1209: sysent[SYS_nfssvc].sy_narg = 2; ! 1210: sysent[SYS_nfssvc].sy_call = nfssvc; ! 1211: #ifndef NFS_NOSERVER ! 1212: sysent[SYS_getfh].sy_narg = 2; ! 1213: sysent[SYS_getfh].sy_call = getfh; ! 1214: #endif ! 1215: ! 1216: return (0); ! 1217: } ! 1218: ! 1219: /* ! 1220: * Attribute cache routines. ! 1221: * nfs_loadattrcache() - loads or updates the cache contents from attributes ! 1222: * that are on the mbuf list ! 1223: * nfs_getattrcache() - returns valid attributes if found in cache, returns ! 1224: * error otherwise ! 1225: */ ! 1226: ! 1227: /* ! 1228: * Load the attribute cache (that lives in the nfsnode entry) with ! 1229: * the values on the mbuf list and ! 1230: * Iff vap not NULL ! 1231: * copy the attributes to *vaper ! 1232: */ ! 1233: int ! 1234: nfs_loadattrcache(vpp, mdp, dposp, vaper) ! 1235: struct vnode **vpp; ! 1236: struct mbuf **mdp; ! 1237: caddr_t *dposp; ! 1238: struct vattr *vaper; ! 1239: { ! 1240: register struct vnode *vp = *vpp; ! 1241: register struct vattr *vap; ! 1242: register struct nfs_fattr *fp; ! 1243: register struct nfsnode *np; ! 1244: register long t1; ! 1245: caddr_t cp2; ! 1246: int error = 0, rdev; ! 1247: struct mbuf *md; ! 1248: enum vtype vtyp; ! 1249: u_short vmode; ! 1250: struct timespec mtime; ! 1251: struct vnode *nvp; ! 1252: int v3 = NFS_ISV3(vp); ! 1253: ! 1254: NFSTRACE(NFSTRC_LAC, vp); ! 1255: md = *mdp; ! 1256: t1 = (mtod(md, caddr_t) + md->m_len) - *dposp; ! 1257: if ((error = nfsm_disct(mdp, dposp, NFSX_FATTR(v3), t1, &cp2))) ! 1258: return (error); ! 1259: fp = (struct nfs_fattr *)cp2; ! 1260: if (v3) { ! 1261: vtyp = nfsv3tov_type(fp->fa_type); ! 1262: vmode = fxdr_unsigned(u_short, fp->fa_mode); ! 1263: rdev = makedev(fxdr_unsigned(int, fp->fa3_rdev.specdata1), ! 1264: fxdr_unsigned(int, fp->fa3_rdev.specdata2)); ! 1265: fxdr_nfsv3time(&fp->fa3_mtime, &mtime); ! 1266: } else { ! 1267: vtyp = nfsv2tov_type(fp->fa_type); ! 1268: vmode = fxdr_unsigned(u_short, fp->fa_mode); ! 1269: /* ! 1270: * XXX ! 1271: * ! 1272: * The duplicate information returned in fa_type and fa_mode ! 1273: * is an ambiguity in the NFS version 2 protocol. ! 1274: * ! 1275: * VREG should be taken literally as a regular file. If a ! 1276: * server intents to return some type information differently ! 1277: * in the upper bits of the mode field (e.g. for sockets, or ! 1278: * FIFOs), NFSv2 mandates fa_type to be VNON. Anyway, we ! 1279: * leave the examination of the mode bits even in the VREG ! 1280: * case to avoid breakage for bogus servers, but we make sure ! 1281: * that there are actually type bits set in the upper part of ! 1282: * fa_mode (and failing that, trust the va_type field). ! 1283: * ! 1284: * NFSv3 cleared the issue, and requires fa_mode to not ! 1285: * contain any type information (while also introduing sockets ! 1286: * and FIFOs for fa_type). ! 1287: */ ! 1288: if (vtyp == VNON || (vtyp == VREG && (vmode & S_IFMT) != 0)) ! 1289: vtyp = IFTOVT(vmode); ! 1290: rdev = fxdr_unsigned(long, fp->fa2_rdev); ! 1291: fxdr_nfsv2time(&fp->fa2_mtime, &mtime); ! 1292: ! 1293: /* ! 1294: * Really ugly NFSv2 kludge. ! 1295: */ ! 1296: if (vtyp == VCHR && rdev == 0xffffffff) ! 1297: vtyp = VFIFO; ! 1298: } ! 1299: ! 1300: /* ! 1301: * If v_type == VNON it is a new node, so fill in the v_type, ! 1302: * n_mtime fields. Check to see if it represents a special ! 1303: * device, and if so, check for a possible alias. Once the ! 1304: * correct vnode has been obtained, fill in the rest of the ! 1305: * information. ! 1306: */ ! 1307: np = VTONFS(vp); ! 1308: if (vp->v_type != vtyp) { ! 1309: vp->v_type = vtyp; ! 1310: #if MACH_NBC ! 1311: if ((vp->v_type == VREG) && !(vp->v_vm_info)){ ! 1312: vm_info_init(vp); ! 1313: } ! 1314: #endif /* MACH_NBC */ ! 1315: if (vp->v_type == VFIFO) { ! 1316: vp->v_op = fifo_nfsv2nodeop_p; ! 1317: } ! 1318: if (vp->v_type == VCHR || vp->v_type == VBLK) { ! 1319: vp->v_op = spec_nfsv2nodeop_p; ! 1320: nvp = checkalias(vp, (dev_t)rdev, vp->v_mount); ! 1321: if (nvp) { ! 1322: /* ! 1323: * Discard unneeded vnode, but save its nfsnode. ! 1324: * Since the nfsnode does not have a lock, its ! 1325: * vnode lock has to be carried over. ! 1326: */ ! 1327: nvp->v_vnlock = vp->v_vnlock; ! 1328: vp->v_vnlock = NULL; ! 1329: nvp->v_data = vp->v_data; ! 1330: vp->v_data = NULL; ! 1331: vp->v_op = spec_vnodeop_p; ! 1332: vrele(vp); ! 1333: vgone(vp); ! 1334: /* ! 1335: * Reinitialize aliased node. ! 1336: */ ! 1337: np->n_vnode = nvp; ! 1338: *vpp = vp = nvp; ! 1339: } ! 1340: } ! 1341: np->n_mtime = mtime.tv_sec; ! 1342: NFSTRACE(NFSTRC_LAC_INIT, vp); ! 1343: } ! 1344: vap = &np->n_vattr; ! 1345: vap->va_type = vtyp; ! 1346: vap->va_mode = (vmode & 07777); ! 1347: vap->va_rdev = (dev_t)rdev; ! 1348: vap->va_mtime = mtime; ! 1349: vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0]; ! 1350: if (v3) { ! 1351: vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink); ! 1352: vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid); ! 1353: vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid); ! 1354: fxdr_hyper(&fp->fa3_size, &vap->va_size); ! 1355: vap->va_blocksize = NFS_FABLKSIZE; ! 1356: fxdr_hyper(&fp->fa3_used, &vap->va_bytes); ! 1357: vap->va_fileid = fxdr_unsigned(int, fp->fa3_fileid.nfsuquad[1]); ! 1358: fxdr_nfsv3time(&fp->fa3_atime, &vap->va_atime); ! 1359: fxdr_nfsv3time(&fp->fa3_ctime, &vap->va_ctime); ! 1360: vap->va_flags = 0; ! 1361: vap->va_filerev = 0; ! 1362: } else { ! 1363: vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink); ! 1364: vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid); ! 1365: vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid); ! 1366: vap->va_size = fxdr_unsigned(u_long, fp->fa2_size); ! 1367: vap->va_blocksize = fxdr_unsigned(long, fp->fa2_blocksize); ! 1368: vap->va_bytes = fxdr_unsigned(long, fp->fa2_blocks) * NFS_FABLKSIZE; ! 1369: vap->va_fileid = fxdr_unsigned(long, fp->fa2_fileid); ! 1370: fxdr_nfsv2time(&fp->fa2_atime, &vap->va_atime); ! 1371: vap->va_flags = 0; ! 1372: vap->va_ctime.tv_sec = fxdr_unsigned(long, fp->fa2_ctime.nfsv2_sec); ! 1373: vap->va_ctime.tv_nsec = 0; ! 1374: vap->va_gen = fxdr_unsigned(u_long, fp->fa2_ctime.nfsv2_usec); ! 1375: vap->va_filerev = 0; ! 1376: } ! 1377: ! 1378: if (vap->va_size != np->n_size) { ! 1379: NFSTRACE4(NFSTRC_LAC_NP, vp, vap->va_size, np->n_size, ! 1380: (vap->va_type == VREG) | ! 1381: (np->n_flag & NMODIFIED ? 2 : 0)); ! 1382: if (vap->va_type == VREG) { ! 1383: if (np->n_flag & NMODIFIED) { ! 1384: if (vap->va_size < np->n_size) ! 1385: vap->va_size = np->n_size; ! 1386: else ! 1387: np->n_size = vap->va_size; ! 1388: } else ! 1389: np->n_size = vap->va_size; ! 1390: #if !MACH_NBC ! 1391: vnode_pager_setsize(vp, (u_long)np->n_size); ! 1392: #endif /* MACH_NBC */ ! 1393: } else ! 1394: np->n_size = vap->va_size; ! 1395: } ! 1396: ! 1397: #if MACH_NBC ! 1398: if (vap->va_type == VREG && vp->v_vm_info && vp->v_vm_info->mapped && ! 1399: vap->va_size != vp->v_vm_info->vnode_size) { ! 1400: struct vm_info *vmp = vp->v_vm_info; ! 1401: ! 1402: NFSTRACE4(NFSTRC_LAC_MAP, vp, vap->va_size, vmp->vnode_size, ! 1403: ((long)(vmp->lock.thread) > 0 ? 0x1000 : 0) | ! 1404: (vmp->lock.thread == current_thread() ? 0x2000 : 0) | ! 1405: (vmp->lock.want_write ? 0x0100 : 0) | ! 1406: (vmp->lock.want_upgrade ? 0x0200 : 0) | ! 1407: (vmp->lock.read_count ? 0x0400 : 0) | ! 1408: (vmp->nfsdirty ? 0x0010 : 0) | ! 1409: (np->n_flag & NMODIFIED ? 0x0001 : 0)); ! 1410: if (vmp->nfsdirty || np->n_flag & NMODIFIED) { ! 1411: np->n_size = vap->va_size = vmp->vnode_size; ! 1412: } else if (vmp->lock.want_write || vmp->lock.want_upgrade || ! 1413: vmp->lock.read_count) { ! 1414: vmp->invalidate = TRUE; /* vmp_put will do it */ ! 1415: #if DIAGNOSTIC ! 1416: kprintf("nfs_loadattrcache: invalidate vp %x\n", ! 1417: (unsigned)vp); ! 1418: #endif /* DIAGNOSTIC */ ! 1419: } else { /* clear the way for server's dirt */ ! 1420: mapfs_memfree(vmp, TRUE); ! 1421: vmp->vnode_size = vap->va_size; ! 1422: #if DIAGNOSTIC ! 1423: kprintf("nfs_loadattrcache: memfree vp %x\n", ! 1424: (unsigned)vp); ! 1425: #endif /* DIAGNOSTIC */ ! 1426: } ! 1427: } ! 1428: #endif /* MACH_NBC */ ! 1429: ! 1430: np->n_attrstamp = time.tv_sec; ! 1431: if (vaper != NULL) { ! 1432: bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(*vap)); ! 1433: if (np->n_flag & NCHG) { ! 1434: if (np->n_flag & NACC) ! 1435: vaper->va_atime = np->n_atim; ! 1436: if (np->n_flag & NUPD) ! 1437: vaper->va_mtime = np->n_mtim; ! 1438: } ! 1439: } ! 1440: return (0); ! 1441: } ! 1442: ! 1443: /* ! 1444: * Check the time stamp ! 1445: * If the cache is valid, copy contents to *vap and return 0 ! 1446: * otherwise return an error ! 1447: */ ! 1448: int ! 1449: nfs_getattrcache(vp, vaper) ! 1450: register struct vnode *vp; ! 1451: struct vattr *vaper; ! 1452: { ! 1453: register struct nfsnode *np = VTONFS(vp); ! 1454: register struct vattr *vap; ! 1455: ! 1456: if ((time.tv_sec - np->n_attrstamp) >= NFS_ATTRTIMEO(np)) { ! 1457: NFSTRACE(NFSTRC_GAC_MISS, vp); ! 1458: nfsstats.attrcache_misses++; ! 1459: return (ENOENT); ! 1460: } ! 1461: NFSTRACE(NFSTRC_GAC_HIT, vp); ! 1462: nfsstats.attrcache_hits++; ! 1463: vap = &np->n_vattr; ! 1464: ! 1465: if (vap->va_size != np->n_size) { ! 1466: NFSTRACE4(NFSTRC_GAC_NP, vp, vap->va_size, np->n_size, ! 1467: (vap->va_type == VREG) | ! 1468: (np->n_flag & NMODIFIED ? 2 : 0)); ! 1469: if (vap->va_type == VREG) { ! 1470: if (np->n_flag & NMODIFIED) { ! 1471: if (vap->va_size < np->n_size) ! 1472: vap->va_size = np->n_size; ! 1473: else ! 1474: np->n_size = vap->va_size; ! 1475: } else ! 1476: np->n_size = vap->va_size; ! 1477: #if !MACH_NBC ! 1478: vnode_pager_setsize(vp, (u_long)np->n_size); ! 1479: #endif /* !MACH_NBC */ ! 1480: } else ! 1481: np->n_size = vap->va_size; ! 1482: } ! 1483: ! 1484: #if MACH_NBC ! 1485: if (vap->va_type == VREG && vp->v_vm_info && vp->v_vm_info->mapped && ! 1486: vap->va_size != vp->v_vm_info->vnode_size) { ! 1487: struct vm_info *vmp = vp->v_vm_info; ! 1488: ! 1489: NFSTRACE4(NFSTRC_GAC_MAP, vp, vap->va_size, vmp->vnode_size, ! 1490: ((long)(vmp->lock.thread) > 0 ? 0x1000 : 0) | ! 1491: (vmp->lock.thread == current_thread() ? 0x2000 : 0) | ! 1492: (vmp->lock.want_write ? 0x0100 : 0) | ! 1493: (vmp->lock.want_upgrade ? 0x0200 : 0) | ! 1494: (vmp->lock.read_count ? 0x0400 : 0) | ! 1495: (vmp->nfsdirty ? 0x0010 : 0) | ! 1496: (np->n_flag & NMODIFIED ? 0x0001 : 0)); ! 1497: if (vmp->nfsdirty || np->n_flag & NMODIFIED) { ! 1498: /* keep eating our own dirt */ ! 1499: np->n_size = vap->va_size = vmp->vnode_size; ! 1500: } else if (vmp->lock.want_write || vmp->lock.want_upgrade || ! 1501: vmp->lock.read_count) { ! 1502: vmp->invalidate = TRUE; /* vmp_put will do it */ ! 1503: #if DIAGNOSTIC ! 1504: kprintf("nfs_getattrcache: invalidate vp %x\n", ! 1505: (unsigned)vp); ! 1506: #endif /* DIAGNOSTIC */ ! 1507: } else { /* clear the way for server's dirt */ ! 1508: mapfs_memfree(vmp, TRUE); ! 1509: vmp->vnode_size = vap->va_size; ! 1510: #if DIAGNOSTIC ! 1511: kprintf("nfs_getattrcache: memfree vp %x\n", ! 1512: (unsigned)vp); ! 1513: #endif /* DIAGNOSTIC */ ! 1514: } ! 1515: } ! 1516: #endif /* MACH_NBC */ ! 1517: ! 1518: bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(struct vattr)); ! 1519: if (np->n_flag & NCHG) { ! 1520: if (np->n_flag & NACC) ! 1521: vaper->va_atime = np->n_atim; ! 1522: if (np->n_flag & NUPD) ! 1523: vaper->va_mtime = np->n_mtim; ! 1524: } ! 1525: return (0); ! 1526: } ! 1527: ! 1528: #ifndef NFS_NOSERVER ! 1529: /* ! 1530: * Set up nameidata for a lookup() call and do it. ! 1531: * ! 1532: * If pubflag is set, this call is done for a lookup operation on the ! 1533: * public filehandle. In that case we allow crossing mountpoints and ! 1534: * absolute pathnames. However, the caller is expected to check that ! 1535: * the lookup result is within the public fs, and deny access if ! 1536: * it is not. ! 1537: */ ! 1538: int ! 1539: nfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, retdirp, p, kerbflag, pubflag) ! 1540: register struct nameidata *ndp; ! 1541: fhandle_t *fhp; ! 1542: int len; ! 1543: struct nfssvc_sock *slp; ! 1544: struct mbuf *nam; ! 1545: struct mbuf **mdp; ! 1546: caddr_t *dposp; ! 1547: struct vnode **retdirp; ! 1548: struct proc *p; ! 1549: int kerbflag, pubflag; ! 1550: { ! 1551: register int i, rem; ! 1552: register struct mbuf *md; ! 1553: register char *fromcp, *tocp, *cp; ! 1554: struct iovec aiov; ! 1555: struct uio auio; ! 1556: struct vnode *dp; ! 1557: int error, rdonly, linklen; ! 1558: struct componentname *cnp = &ndp->ni_cnd; ! 1559: int olen = len; ! 1560: ! 1561: *retdirp = (struct vnode *)0; ! 1562: MALLOC_ZONE(cnp->cn_pnbuf, char *, len + 1, M_NAMEI, M_WAITOK); ! 1563: cnp->cn_pnlen = len + 1; ! 1564: ! 1565: /* ! 1566: * Copy the name from the mbuf list to ndp->ni_pnbuf ! 1567: * and set the various ndp fields appropriately. ! 1568: */ ! 1569: fromcp = *dposp; ! 1570: tocp = cnp->cn_pnbuf; ! 1571: md = *mdp; ! 1572: rem = mtod(md, caddr_t) + md->m_len - fromcp; ! 1573: cnp->cn_hash = 0; ! 1574: for (i = 1; i <= len; i++) { ! 1575: while (rem == 0) { ! 1576: md = md->m_next; ! 1577: if (md == NULL) { ! 1578: error = EBADRPC; ! 1579: goto out; ! 1580: } ! 1581: fromcp = mtod(md, caddr_t); ! 1582: rem = md->m_len; ! 1583: } ! 1584: /* XXX CSM 12/4/97 Revisit when enabling WebNFS */ ! 1585: #ifdef notdef ! 1586: if (*fromcp == '\0' || (!pubflag && *fromcp == '/')) { ! 1587: #else ! 1588: if (*fromcp == '\0' || *fromcp == '/') { ! 1589: #endif ! 1590: error = EACCES; ! 1591: goto out; ! 1592: } ! 1593: cnp->cn_hash += (unsigned char)*fromcp * i; ! 1594: *tocp++ = *fromcp++; ! 1595: rem--; ! 1596: } ! 1597: *tocp = '\0'; ! 1598: *mdp = md; ! 1599: *dposp = fromcp; ! 1600: len = nfsm_rndup(len)-len; ! 1601: if (len > 0) { ! 1602: if (rem >= len) ! 1603: *dposp += len; ! 1604: else if ((error = nfs_adv(mdp, dposp, len, rem)) != 0) ! 1605: goto out; ! 1606: } ! 1607: ! 1608: /* ! 1609: * Extract and set starting directory. ! 1610: */ ! 1611: error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cnd.cn_cred, slp, ! 1612: nam, &rdonly, kerbflag, pubflag); ! 1613: if (error) ! 1614: goto out; ! 1615: if (dp->v_type != VDIR) { ! 1616: vrele(dp); ! 1617: error = ENOTDIR; ! 1618: goto out; ! 1619: } ! 1620: ! 1621: if (rdonly) ! 1622: cnp->cn_flags |= RDONLY; ! 1623: ! 1624: *retdirp = dp; ! 1625: ! 1626: /* XXX CSM 12/4/97 Revisit when enabling WebNFS */ ! 1627: /* XXX debo 12/15/97 Need to fix M_NAMEI allocations to use zone protocol */ ! 1628: #ifdef notyet ! 1629: if (pubflag) { ! 1630: /* ! 1631: * Oh joy. For WebNFS, handle those pesky '%' escapes, ! 1632: * and the 'native path' indicator. ! 1633: */ ! 1634: MALLOC(cp, char *, olen + 1, M_NAMEI, M_WAITOK); ! 1635: fromcp = cnp->cn_pnbuf; ! 1636: tocp = cp; ! 1637: if ((unsigned char)*fromcp >= WEBNFS_SPECCHAR_START) { ! 1638: switch ((unsigned char)*fromcp) { ! 1639: case WEBNFS_NATIVE_CHAR: ! 1640: /* ! 1641: * 'Native' path for us is the same ! 1642: * as a path according to the NFS spec, ! 1643: * just skip the escape char. ! 1644: */ ! 1645: fromcp++; ! 1646: break; ! 1647: /* ! 1648: * More may be added in the future, range 0x80-0xff ! 1649: */ ! 1650: default: ! 1651: error = EIO; ! 1652: FREE(cp, M_NAMEI); ! 1653: goto out; ! 1654: } ! 1655: } ! 1656: /* ! 1657: * Translate the '%' escapes, URL-style. ! 1658: */ ! 1659: while (*fromcp != '\0') { ! 1660: if (*fromcp == WEBNFS_ESC_CHAR) { ! 1661: if (fromcp[1] != '\0' && fromcp[2] != '\0') { ! 1662: fromcp++; ! 1663: *tocp++ = HEXSTRTOI(fromcp); ! 1664: fromcp += 2; ! 1665: continue; ! 1666: } else { ! 1667: error = ENOENT; ! 1668: FREE(cp, M_NAMEI); ! 1669: goto out; ! 1670: } ! 1671: } else ! 1672: *tocp++ = *fromcp++; ! 1673: } ! 1674: *tocp = '\0'; ! 1675: FREE(cnp->cn_pnbuf, M_NAMEI); ! 1676: cnp->cn_pnbuf = cp; ! 1677: } ! 1678: #endif ! 1679: ! 1680: ndp->ni_pathlen = (tocp - cnp->cn_pnbuf) + 1; ! 1681: ndp->ni_segflg = UIO_SYSSPACE; ! 1682: ! 1683: /* XXX CSM 12/4/97 Revisit when enabling WebNFS */ ! 1684: #ifdef notyet ! 1685: if (pubflag) { ! 1686: ndp->ni_rootdir = rootvnode; ! 1687: ndp->ni_loopcnt = 0; ! 1688: if (cnp->cn_pnbuf[0] == '/') ! 1689: dp = rootvnode; ! 1690: } else { ! 1691: cnp->cn_flags |= NOCROSSMOUNT; ! 1692: } ! 1693: #else ! 1694: cnp->cn_flags |= NOCROSSMOUNT; ! 1695: #endif ! 1696: ! 1697: cnp->cn_proc = p; ! 1698: VREF(dp); ! 1699: ! 1700: for (;;) { ! 1701: cnp->cn_nameptr = cnp->cn_pnbuf; ! 1702: ndp->ni_startdir = dp; ! 1703: /* ! 1704: * And call lookup() to do the real work ! 1705: */ ! 1706: error = lookup(ndp); ! 1707: if (error) ! 1708: break; ! 1709: /* ! 1710: * Check for encountering a symbolic link ! 1711: */ ! 1712: if ((cnp->cn_flags & ISSYMLINK) == 0) { ! 1713: nfsrv_object_create(ndp->ni_vp); ! 1714: if (cnp->cn_flags & (SAVENAME | SAVESTART)) { ! 1715: cnp->cn_flags |= HASBUF; ! 1716: return (0); ! 1717: } ! 1718: break; ! 1719: } else { ! 1720: if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1) ! 1721: VOP_UNLOCK(ndp->ni_dvp, 0, p); ! 1722: /* XXX CSM 12/4/97 Revisit when enabling WebNFS */ ! 1723: #ifdef notyet ! 1724: if (!pubflag) { ! 1725: #endif ! 1726: vrele(ndp->ni_dvp); ! 1727: vput(ndp->ni_vp); ! 1728: ndp->ni_vp = NULL; ! 1729: error = EINVAL; ! 1730: break; ! 1731: /* XXX CSM 12/4/97 Revisit when enabling WebNFS */ ! 1732: /* XXX debo 12/15/97 Need to fix M_NAMEI allocations to use zone protocol */ ! 1733: #ifdef notyet ! 1734: } ! 1735: ! 1736: if (ndp->ni_loopcnt++ >= MAXSYMLINKS) { ! 1737: error = ELOOP; ! 1738: break; ! 1739: } ! 1740: if (ndp->ni_pathlen > 1) ! 1741: MALLOC(cp, char *, olen + 1, M_NAMEI, M_WAITOK); ! 1742: else ! 1743: cp = cnp->cn_pnbuf; ! 1744: aiov.iov_base = cp; ! 1745: aiov.iov_len = MAXPATHLEN; ! 1746: auio.uio_iov = &aiov; ! 1747: auio.uio_iovcnt = 1; ! 1748: auio.uio_offset = 0; ! 1749: auio.uio_rw = UIO_READ; ! 1750: auio.uio_segflg = UIO_SYSSPACE; ! 1751: auio.uio_procp = (struct proc *)0; ! 1752: auio.uio_resid = MAXPATHLEN; ! 1753: error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred); ! 1754: if (error) { ! 1755: badlink: ! 1756: if (ndp->ni_pathlen > 1) ! 1757: FREE(cp, M_NAMEI); ! 1758: break; ! 1759: } ! 1760: linklen = MAXPATHLEN - auio.uio_resid; ! 1761: if (linklen == 0) { ! 1762: error = ENOENT; ! 1763: goto badlink; ! 1764: } ! 1765: if (linklen + ndp->ni_pathlen >= MAXPATHLEN) { ! 1766: error = ENAMETOOLONG; ! 1767: goto badlink; ! 1768: } ! 1769: if (ndp->ni_pathlen > 1) { ! 1770: bcopy(ndp->ni_next, cp + linklen, ndp->ni_pathlen); ! 1771: FREE(cnp->cn_pnbuf, M_NAMEI); ! 1772: cnp->cn_pnbuf = cp; ! 1773: } else ! 1774: cnp->cn_pnbuf[linklen] = '\0'; ! 1775: ndp->ni_pathlen += linklen; ! 1776: vput(ndp->ni_vp); ! 1777: dp = ndp->ni_dvp; ! 1778: /* ! 1779: * Check if root directory should replace current directory. ! 1780: */ ! 1781: if (cnp->cn_pnbuf[0] == '/') { ! 1782: vrele(dp); ! 1783: dp = ndp->ni_rootdir; ! 1784: VREF(dp); ! 1785: } ! 1786: #endif ! 1787: } ! 1788: } ! 1789: out: ! 1790: FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI); ! 1791: return (error); ! 1792: } ! 1793: ! 1794: /* ! 1795: * A fiddled version of m_adj() that ensures null fill to a long ! 1796: * boundary and only trims off the back end ! 1797: */ ! 1798: void ! 1799: nfsm_adj(mp, len, nul) ! 1800: struct mbuf *mp; ! 1801: register int len; ! 1802: int nul; ! 1803: { ! 1804: register struct mbuf *m; ! 1805: register int count, i; ! 1806: register char *cp; ! 1807: ! 1808: /* ! 1809: * Trim from tail. Scan the mbuf chain, ! 1810: * calculating its length and finding the last mbuf. ! 1811: * If the adjustment only affects this mbuf, then just ! 1812: * adjust and return. Otherwise, rescan and truncate ! 1813: * after the remaining size. ! 1814: */ ! 1815: count = 0; ! 1816: m = mp; ! 1817: for (;;) { ! 1818: count += m->m_len; ! 1819: if (m->m_next == (struct mbuf *)0) ! 1820: break; ! 1821: m = m->m_next; ! 1822: } ! 1823: if (m->m_len > len) { ! 1824: m->m_len -= len; ! 1825: if (nul > 0) { ! 1826: cp = mtod(m, caddr_t)+m->m_len-nul; ! 1827: for (i = 0; i < nul; i++) ! 1828: *cp++ = '\0'; ! 1829: } ! 1830: return; ! 1831: } ! 1832: count -= len; ! 1833: if (count < 0) ! 1834: count = 0; ! 1835: /* ! 1836: * Correct length for chain is "count". ! 1837: * Find the mbuf with last data, adjust its length, ! 1838: * and toss data from remaining mbufs on chain. ! 1839: */ ! 1840: for (m = mp; m; m = m->m_next) { ! 1841: if (m->m_len >= count) { ! 1842: m->m_len = count; ! 1843: if (nul > 0) { ! 1844: cp = mtod(m, caddr_t)+m->m_len-nul; ! 1845: for (i = 0; i < nul; i++) ! 1846: *cp++ = '\0'; ! 1847: } ! 1848: break; ! 1849: } ! 1850: count -= m->m_len; ! 1851: } ! 1852: for (m = m->m_next;m;m = m->m_next) ! 1853: m->m_len = 0; ! 1854: } ! 1855: ! 1856: /* ! 1857: * Make these functions instead of macros, so that the kernel text size ! 1858: * doesn't get too big... ! 1859: */ ! 1860: void ! 1861: nfsm_srvwcc(nfsd, before_ret, before_vap, after_ret, after_vap, mbp, bposp) ! 1862: struct nfsrv_descript *nfsd; ! 1863: int before_ret; ! 1864: register struct vattr *before_vap; ! 1865: int after_ret; ! 1866: struct vattr *after_vap; ! 1867: struct mbuf **mbp; ! 1868: char **bposp; ! 1869: { ! 1870: register struct mbuf *mb = *mbp, *mb2; ! 1871: register char *bpos = *bposp; ! 1872: register u_long *tl; ! 1873: ! 1874: if (before_ret) { ! 1875: nfsm_build(tl, u_long *, NFSX_UNSIGNED); ! 1876: *tl = nfs_false; ! 1877: } else { ! 1878: nfsm_build(tl, u_long *, 7 * NFSX_UNSIGNED); ! 1879: *tl++ = nfs_true; ! 1880: txdr_hyper(&(before_vap->va_size), tl); ! 1881: tl += 2; ! 1882: txdr_nfsv3time(&(before_vap->va_mtime), tl); ! 1883: tl += 2; ! 1884: txdr_nfsv3time(&(before_vap->va_ctime), tl); ! 1885: } ! 1886: *bposp = bpos; ! 1887: *mbp = mb; ! 1888: nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp); ! 1889: } ! 1890: ! 1891: void ! 1892: nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp) ! 1893: struct nfsrv_descript *nfsd; ! 1894: int after_ret; ! 1895: struct vattr *after_vap; ! 1896: struct mbuf **mbp; ! 1897: char **bposp; ! 1898: { ! 1899: register struct mbuf *mb = *mbp, *mb2; ! 1900: register char *bpos = *bposp; ! 1901: register u_long *tl; ! 1902: register struct nfs_fattr *fp; ! 1903: ! 1904: if (after_ret) { ! 1905: nfsm_build(tl, u_long *, NFSX_UNSIGNED); ! 1906: *tl = nfs_false; ! 1907: } else { ! 1908: nfsm_build(tl, u_long *, NFSX_UNSIGNED + NFSX_V3FATTR); ! 1909: *tl++ = nfs_true; ! 1910: fp = (struct nfs_fattr *)tl; ! 1911: nfsm_srvfattr(nfsd, after_vap, fp); ! 1912: } ! 1913: *mbp = mb; ! 1914: *bposp = bpos; ! 1915: } ! 1916: ! 1917: void ! 1918: nfsm_srvfattr(nfsd, vap, fp) ! 1919: register struct nfsrv_descript *nfsd; ! 1920: register struct vattr *vap; ! 1921: register struct nfs_fattr *fp; ! 1922: { ! 1923: ! 1924: fp->fa_nlink = txdr_unsigned(vap->va_nlink); ! 1925: fp->fa_uid = txdr_unsigned(vap->va_uid); ! 1926: fp->fa_gid = txdr_unsigned(vap->va_gid); ! 1927: if (nfsd->nd_flag & ND_NFSV3) { ! 1928: fp->fa_type = vtonfsv3_type(vap->va_type); ! 1929: fp->fa_mode = vtonfsv3_mode(vap->va_mode); ! 1930: txdr_hyper(&vap->va_size, &fp->fa3_size); ! 1931: txdr_hyper(&vap->va_bytes, &fp->fa3_used); ! 1932: fp->fa3_rdev.specdata1 = txdr_unsigned(major(vap->va_rdev)); ! 1933: fp->fa3_rdev.specdata2 = txdr_unsigned(minor(vap->va_rdev)); ! 1934: fp->fa3_fsid.nfsuquad[0] = 0; ! 1935: fp->fa3_fsid.nfsuquad[1] = txdr_unsigned(vap->va_fsid); ! 1936: fp->fa3_fileid.nfsuquad[0] = 0; ! 1937: fp->fa3_fileid.nfsuquad[1] = txdr_unsigned(vap->va_fileid); ! 1938: txdr_nfsv3time(&vap->va_atime, &fp->fa3_atime); ! 1939: txdr_nfsv3time(&vap->va_mtime, &fp->fa3_mtime); ! 1940: txdr_nfsv3time(&vap->va_ctime, &fp->fa3_ctime); ! 1941: } else { ! 1942: fp->fa_type = vtonfsv2_type(vap->va_type); ! 1943: fp->fa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode); ! 1944: fp->fa2_size = txdr_unsigned(vap->va_size); ! 1945: fp->fa2_blocksize = txdr_unsigned(vap->va_blocksize); ! 1946: if (vap->va_type == VFIFO) ! 1947: fp->fa2_rdev = 0xffffffff; ! 1948: else ! 1949: fp->fa2_rdev = txdr_unsigned(vap->va_rdev); ! 1950: fp->fa2_blocks = txdr_unsigned(vap->va_bytes / NFS_FABLKSIZE); ! 1951: fp->fa2_fsid = txdr_unsigned(vap->va_fsid); ! 1952: fp->fa2_fileid = txdr_unsigned(vap->va_fileid); ! 1953: txdr_nfsv2time(&vap->va_atime, &fp->fa2_atime); ! 1954: txdr_nfsv2time(&vap->va_mtime, &fp->fa2_mtime); ! 1955: txdr_nfsv2time(&vap->va_ctime, &fp->fa2_ctime); ! 1956: } ! 1957: } ! 1958: ! 1959: /* ! 1960: * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked) ! 1961: * - look up fsid in mount list (if not found ret error) ! 1962: * - get vp and export rights by calling VFS_FHTOVP() ! 1963: * - if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon ! 1964: * - if not lockflag unlock it with VOP_UNLOCK() ! 1965: */ ! 1966: int ! 1967: nfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp, kerbflag, pubflag) ! 1968: fhandle_t *fhp; ! 1969: int lockflag; ! 1970: struct vnode **vpp; ! 1971: struct ucred *cred; ! 1972: struct nfssvc_sock *slp; ! 1973: struct mbuf *nam; ! 1974: int *rdonlyp; ! 1975: int kerbflag; ! 1976: int pubflag; ! 1977: { ! 1978: struct proc *p = current_proc(); /* XXX */ ! 1979: register struct mount *mp; ! 1980: register int i; ! 1981: struct ucred *credanon; ! 1982: int error, exflags; ! 1983: ! 1984: *vpp = (struct vnode *)0; ! 1985: ! 1986: /* XXX CSM 12/4/97 Revisit when enabling WebNFS */ ! 1987: #ifdef notyet ! 1988: if (nfs_ispublicfh(fhp)) { ! 1989: if (!pubflag || !nfs_pub.np_valid) ! 1990: return (ESTALE); ! 1991: fhp = &nfs_pub.np_handle; ! 1992: } ! 1993: #endif ! 1994: ! 1995: mp = vfs_getvfs(&fhp->fh_fsid); ! 1996: if (!mp) ! 1997: return (ESTALE); ! 1998: error = VFS_FHTOVP(mp, &fhp->fh_fid, nam, vpp, &exflags, &credanon); ! 1999: if (error) ! 2000: return (error); ! 2001: /* ! 2002: * Check/setup credentials. ! 2003: */ ! 2004: if (exflags & MNT_EXKERB) { ! 2005: if (!kerbflag) { ! 2006: vput(*vpp); ! 2007: return (NFSERR_AUTHERR | AUTH_TOOWEAK); ! 2008: } ! 2009: } else if (kerbflag) { ! 2010: vput(*vpp); ! 2011: return (NFSERR_AUTHERR | AUTH_TOOWEAK); ! 2012: } else if (cred->cr_uid == 0 || (exflags & MNT_EXPORTANON)) { ! 2013: cred->cr_uid = credanon->cr_uid; ! 2014: for (i = 0; i < credanon->cr_ngroups && i < NGROUPS; i++) ! 2015: cred->cr_groups[i] = credanon->cr_groups[i]; ! 2016: cred->cr_ngroups = i; ! 2017: } ! 2018: if (exflags & MNT_EXRDONLY) ! 2019: *rdonlyp = 1; ! 2020: else ! 2021: *rdonlyp = 0; ! 2022: ! 2023: nfsrv_object_create(*vpp); ! 2024: ! 2025: if (!lockflag) ! 2026: VOP_UNLOCK(*vpp, 0, p); ! 2027: return (0); ! 2028: } ! 2029: ! 2030: ! 2031: /* ! 2032: * WebNFS: check if a filehandle is a public filehandle. For v3, this ! 2033: * means a length of 0, for v2 it means all zeroes. nfsm_srvmtofh has ! 2034: * transformed this to all zeroes in both cases, so check for it. ! 2035: */ ! 2036: int ! 2037: nfs_ispublicfh(fhp) ! 2038: fhandle_t *fhp; ! 2039: { ! 2040: char *cp = (char *)fhp; ! 2041: int i; ! 2042: ! 2043: for (i = 0; i < NFSX_V3FH; i++) ! 2044: if (*cp++ != 0) ! 2045: return (FALSE); ! 2046: return (TRUE); ! 2047: } ! 2048: ! 2049: #endif /* NFS_NOSERVER */ ! 2050: /* ! 2051: * This function compares two net addresses by family and returns TRUE ! 2052: * if they are the same host. ! 2053: * If there is any doubt, return FALSE. ! 2054: * The AF_INET family is handled as a special case so that address mbufs ! 2055: * don't need to be saved to store "struct in_addr", which is only 4 bytes. ! 2056: */ ! 2057: int ! 2058: netaddr_match(family, haddr, nam) ! 2059: int family; ! 2060: union nethostaddr *haddr; ! 2061: struct mbuf *nam; ! 2062: { ! 2063: register struct sockaddr_in *inetaddr; ! 2064: ! 2065: switch (family) { ! 2066: case AF_INET: ! 2067: inetaddr = mtod(nam, struct sockaddr_in *); ! 2068: if (inetaddr->sin_family == AF_INET && ! 2069: inetaddr->sin_addr.s_addr == haddr->had_inetaddr) ! 2070: return (1); ! 2071: break; ! 2072: #if ISO ! 2073: case AF_ISO: ! 2074: { ! 2075: register struct sockaddr_iso *isoaddr1, *isoaddr2; ! 2076: ! 2077: isoaddr1 = mtod(nam, struct sockaddr_iso *); ! 2078: isoaddr2 = mtod(haddr->had_nam, struct sockaddr_iso *); ! 2079: if (isoaddr1->siso_family == AF_ISO && ! 2080: isoaddr1->siso_nlen > 0 && ! 2081: isoaddr1->siso_nlen == isoaddr2->siso_nlen && ! 2082: SAME_ISOADDR(isoaddr1, isoaddr2)) ! 2083: return (1); ! 2084: break; ! 2085: } ! 2086: #endif /* ISO */ ! 2087: default: ! 2088: break; ! 2089: }; ! 2090: return (0); ! 2091: } ! 2092: ! 2093: static nfsuint64 nfs_nullcookie = { 0, 0 }; ! 2094: /* ! 2095: * This function finds the directory cookie that corresponds to the ! 2096: * logical byte offset given. ! 2097: */ ! 2098: nfsuint64 * ! 2099: nfs_getcookie(np, off, add) ! 2100: register struct nfsnode *np; ! 2101: off_t off; ! 2102: int add; ! 2103: { ! 2104: register struct nfsdmap *dp, *dp2; ! 2105: register int pos; ! 2106: ! 2107: pos = off / NFS_DIRBLKSIZ; ! 2108: if (pos == 0) { ! 2109: #if DIAGNOSTIC ! 2110: if (add) ! 2111: panic("nfs getcookie add at 0"); ! 2112: #endif ! 2113: return (&nfs_nullcookie); ! 2114: } ! 2115: pos--; ! 2116: dp = np->n_cookies.lh_first; ! 2117: if (!dp) { ! 2118: if (add) { ! 2119: MALLOC_ZONE(dp, struct nfsdmap *, ! 2120: sizeof (struct nfsdmap), ! 2121: M_NFSDIROFF, M_WAITOK); ! 2122: dp->ndm_eocookie = 0; ! 2123: LIST_INSERT_HEAD(&np->n_cookies, dp, ndm_list); ! 2124: } else ! 2125: return ((nfsuint64 *)0); ! 2126: } ! 2127: while (pos >= NFSNUMCOOKIES) { ! 2128: pos -= NFSNUMCOOKIES; ! 2129: if (dp->ndm_list.le_next) { ! 2130: if (!add && dp->ndm_eocookie < NFSNUMCOOKIES && ! 2131: pos >= dp->ndm_eocookie) ! 2132: return ((nfsuint64 *)0); ! 2133: dp = dp->ndm_list.le_next; ! 2134: } else if (add) { ! 2135: MALLOC_ZONE(dp2, struct nfsdmap *, ! 2136: sizeof (struct nfsdmap), ! 2137: M_NFSDIROFF, M_WAITOK); ! 2138: dp2->ndm_eocookie = 0; ! 2139: LIST_INSERT_AFTER(dp, dp2, ndm_list); ! 2140: dp = dp2; ! 2141: } else ! 2142: return ((nfsuint64 *)0); ! 2143: } ! 2144: if (pos >= dp->ndm_eocookie) { ! 2145: if (add) ! 2146: dp->ndm_eocookie = pos + 1; ! 2147: else ! 2148: return ((nfsuint64 *)0); ! 2149: } ! 2150: return (&dp->ndm_cookies[pos]); ! 2151: } ! 2152: ! 2153: /* ! 2154: * Invalidate cached directory information, except for the actual directory ! 2155: * blocks (which are invalidated separately). ! 2156: * Done mainly to avoid the use of stale offset cookies. ! 2157: */ ! 2158: void ! 2159: nfs_invaldir(vp) ! 2160: register struct vnode *vp; ! 2161: { ! 2162: register struct nfsnode *np = VTONFS(vp); ! 2163: ! 2164: #if DIAGNOSTIC ! 2165: if (vp->v_type != VDIR) ! 2166: panic("nfs: invaldir not dir"); ! 2167: #endif ! 2168: np->n_direofoffset = 0; ! 2169: np->n_cookieverf.nfsuquad[0] = 0; ! 2170: np->n_cookieverf.nfsuquad[1] = 0; ! 2171: if (np->n_cookies.lh_first) ! 2172: np->n_cookies.lh_first->ndm_eocookie = 0; ! 2173: } ! 2174: ! 2175: /* ! 2176: * The write verifier has changed (probably due to a server reboot), so all ! 2177: * B_NEEDCOMMIT blocks will have to be written again. Since they are on the ! 2178: * dirty block list as B_DELWRI, all this takes is clearing the B_NEEDCOMMIT ! 2179: * flag. Once done the new write verifier can be set for the mount point. ! 2180: */ ! 2181: void ! 2182: nfs_clearcommit(mp) ! 2183: struct mount *mp; ! 2184: { ! 2185: register struct vnode *vp, *nvp; ! 2186: register struct buf *bp, *nbp; ! 2187: int s; ! 2188: ! 2189: s = splbio(); ! 2190: loop: ! 2191: for (vp = mp->mnt_vnodelist.lh_first; vp; vp = nvp) { ! 2192: if (vp->v_mount != mp) /* Paranoia */ ! 2193: goto loop; ! 2194: nvp = vp->v_mntvnodes.le_next; ! 2195: for (bp = vp->v_dirtyblkhd.lh_first; bp; bp = nbp) { ! 2196: nbp = bp->b_vnbufs.le_next; ! 2197: if ((bp->b_flags & (B_BUSY | B_DELWRI | B_NEEDCOMMIT)) ! 2198: == (B_DELWRI | B_NEEDCOMMIT)) ! 2199: bp->b_flags &= ~B_NEEDCOMMIT; ! 2200: } ! 2201: } ! 2202: splx(s); ! 2203: } ! 2204: ! 2205: #ifndef NFS_NOSERVER ! 2206: /* ! 2207: * Map errnos to NFS error numbers. For Version 3 also filter out error ! 2208: * numbers not specified for the associated procedure. ! 2209: */ ! 2210: int ! 2211: nfsrv_errmap(nd, err) ! 2212: struct nfsrv_descript *nd; ! 2213: register int err; ! 2214: { ! 2215: register short *defaulterrp, *errp; ! 2216: ! 2217: if (nd->nd_flag & ND_NFSV3) { ! 2218: if (nd->nd_procnum <= NFSPROC_COMMIT) { ! 2219: errp = defaulterrp = nfsrv_v3errmap[nd->nd_procnum]; ! 2220: while (*++errp) { ! 2221: if (*errp == err) ! 2222: return (err); ! 2223: else if (*errp > err) ! 2224: break; ! 2225: } ! 2226: return ((int)*defaulterrp); ! 2227: } else ! 2228: return (err & 0xffff); ! 2229: } ! 2230: if (err <= ELAST) ! 2231: return ((int)nfsrv_v2errmap[err - 1]); ! 2232: return (NFSERR_IO); ! 2233: } ! 2234: ! 2235: /* XXX CSM 11/25/97 Revisit when Ramesh merges vm with buffer cache */ ! 2236: #define vfs_object_create(v, p, c, l) (0) ! 2237: ! 2238: int ! 2239: nfsrv_object_create(struct vnode *vp) { ! 2240: struct proc *curproc = current_proc(); ! 2241: ! 2242: if ((vp == NULL) || (vp->v_type != VREG)) ! 2243: return 1; ! 2244: return vfs_object_create(vp, curproc, curproc?curproc->p_ucred:NULL, 1); ! 2245: } ! 2246: #endif /* NFS_NOSERVER */ ! 2247:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.