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