Annotation of sys/nfs/nfs_subs.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: nfs_subs.c,v 1.61 2007/04/19 14:46:44 thib Exp $ */
! 2: /* $NetBSD: nfs_subs.c,v 1.27.4.3 1996/07/08 20:34:24 jtc Exp $ */
! 3:
! 4: /*
! 5: * Copyright (c) 1989, 1993
! 6: * The Regents of the University of California. All rights reserved.
! 7: *
! 8: * This code is derived from software contributed to Berkeley by
! 9: * Rick Macklem at The University of Guelph.
! 10: *
! 11: * Redistribution and use in source and binary forms, with or without
! 12: * modification, are permitted provided that the following conditions
! 13: * are met:
! 14: * 1. Redistributions of source code must retain the above copyright
! 15: * notice, this list of conditions and the following disclaimer.
! 16: * 2. Redistributions in binary form must reproduce the above copyright
! 17: * notice, this list of conditions and the following disclaimer in the
! 18: * documentation and/or other materials provided with the distribution.
! 19: * 3. Neither the name of the University nor the names of its contributors
! 20: * may be used to endorse or promote products derived from this software
! 21: * without specific prior written permission.
! 22: *
! 23: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
! 24: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 25: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 26: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
! 27: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 28: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 29: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 30: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 31: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 32: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 33: * SUCH DAMAGE.
! 34: *
! 35: * @(#)nfs_subs.c 8.8 (Berkeley) 5/22/95
! 36: */
! 37:
! 38:
! 39: /*
! 40: * These functions support the macros and help fiddle mbuf chains for
! 41: * the nfs op functions. They do things like create the rpc header and
! 42: * copy data between mbuf chains and uio lists.
! 43: */
! 44: #include <sys/param.h>
! 45: #include <sys/proc.h>
! 46: #include <sys/systm.h>
! 47: #include <sys/kernel.h>
! 48: #include <sys/mount.h>
! 49: #include <sys/vnode.h>
! 50: #include <sys/namei.h>
! 51: #include <sys/mbuf.h>
! 52: #include <sys/socket.h>
! 53: #include <sys/socketvar.h>
! 54: #include <sys/stat.h>
! 55: #include <sys/malloc.h>
! 56: #include <sys/pool.h>
! 57: #include <sys/time.h>
! 58:
! 59: #include <uvm/uvm_extern.h>
! 60:
! 61: #include <nfs/rpcv2.h>
! 62: #include <nfs/nfsproto.h>
! 63: #include <nfs/nfsnode.h>
! 64: #include <nfs/nfs.h>
! 65: #include <nfs/xdr_subs.h>
! 66: #include <nfs/nfsm_subs.h>
! 67: #include <nfs/nfsmount.h>
! 68: #include <nfs/nfsrtt.h>
! 69: #include <nfs/nfs_var.h>
! 70:
! 71: #include <miscfs/specfs/specdev.h>
! 72:
! 73: #include <netinet/in.h>
! 74:
! 75: #include <dev/rndvar.h>
! 76:
! 77: #ifdef __GNUC__
! 78: #define INLINE __inline
! 79: #else
! 80: #define INLINE
! 81: #endif
! 82:
! 83: int nfs_attrtimeo(struct nfsnode *np);
! 84:
! 85: /*
! 86: * Data items converted to xdr at startup, since they are constant
! 87: * This is kinda hokey, but may save a little time doing byte swaps
! 88: */
! 89: u_int32_t nfs_xdrneg1;
! 90: u_int32_t rpc_call, rpc_vers, rpc_reply, rpc_msgdenied, rpc_autherr,
! 91: rpc_mismatch, rpc_auth_unix, rpc_msgaccepted,
! 92: rpc_auth_kerb;
! 93: u_int32_t nfs_prog, nfs_true, nfs_false;
! 94:
! 95: /* And other global data */
! 96: static u_int32_t nfs_xid = 0;
! 97: static u_int32_t nfs_xid_touched = 0;
! 98: nfstype nfsv2_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFNON,
! 99: NFCHR, NFNON };
! 100: nfstype nfsv3_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFSOCK,
! 101: NFFIFO, NFNON };
! 102: enum vtype nv2tov_type[8] = { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON, VNON };
! 103: enum vtype nv3tov_type[8]={ VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO };
! 104: int nfs_ticks;
! 105: struct nfsstats nfsstats;
! 106:
! 107: /*
! 108: * Mapping of old NFS Version 2 RPC numbers to generic numbers.
! 109: */
! 110: int nfsv3_procid[NFS_NPROCS] = {
! 111: NFSPROC_NULL,
! 112: NFSPROC_GETATTR,
! 113: NFSPROC_SETATTR,
! 114: NFSPROC_NOOP,
! 115: NFSPROC_LOOKUP,
! 116: NFSPROC_READLINK,
! 117: NFSPROC_READ,
! 118: NFSPROC_NOOP,
! 119: NFSPROC_WRITE,
! 120: NFSPROC_CREATE,
! 121: NFSPROC_REMOVE,
! 122: NFSPROC_RENAME,
! 123: NFSPROC_LINK,
! 124: NFSPROC_SYMLINK,
! 125: NFSPROC_MKDIR,
! 126: NFSPROC_RMDIR,
! 127: NFSPROC_READDIR,
! 128: NFSPROC_FSSTAT,
! 129: NFSPROC_NOOP,
! 130: NFSPROC_NOOP,
! 131: NFSPROC_NOOP,
! 132: NFSPROC_NOOP,
! 133: NFSPROC_NOOP,
! 134: NFSPROC_NOOP,
! 135: NFSPROC_NOOP,
! 136: NFSPROC_NOOP
! 137: };
! 138:
! 139: /*
! 140: * and the reverse mapping from generic to Version 2 procedure numbers
! 141: */
! 142: int nfsv2_procid[NFS_NPROCS] = {
! 143: NFSV2PROC_NULL,
! 144: NFSV2PROC_GETATTR,
! 145: NFSV2PROC_SETATTR,
! 146: NFSV2PROC_LOOKUP,
! 147: NFSV2PROC_NOOP,
! 148: NFSV2PROC_READLINK,
! 149: NFSV2PROC_READ,
! 150: NFSV2PROC_WRITE,
! 151: NFSV2PROC_CREATE,
! 152: NFSV2PROC_MKDIR,
! 153: NFSV2PROC_SYMLINK,
! 154: NFSV2PROC_CREATE,
! 155: NFSV2PROC_REMOVE,
! 156: NFSV2PROC_RMDIR,
! 157: NFSV2PROC_RENAME,
! 158: NFSV2PROC_LINK,
! 159: NFSV2PROC_READDIR,
! 160: NFSV2PROC_NOOP,
! 161: NFSV2PROC_STATFS,
! 162: NFSV2PROC_NOOP,
! 163: NFSV2PROC_NOOP,
! 164: NFSV2PROC_NOOP,
! 165: NFSV2PROC_NOOP,
! 166: NFSV2PROC_NOOP,
! 167: NFSV2PROC_NOOP,
! 168: NFSV2PROC_NOOP,
! 169: };
! 170:
! 171: /*
! 172: * Maps errno values to nfs error numbers.
! 173: * Use NFSERR_IO as the catch all for ones not specifically defined in
! 174: * RFC 1094.
! 175: */
! 176: static u_char nfsrv_v2errmap[ELAST] = {
! 177: NFSERR_PERM, NFSERR_NOENT, NFSERR_IO, NFSERR_IO, NFSERR_IO,
! 178: NFSERR_NXIO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
! 179: NFSERR_IO, NFSERR_IO, NFSERR_ACCES, NFSERR_IO, NFSERR_IO,
! 180: NFSERR_IO, NFSERR_EXIST, NFSERR_IO, NFSERR_NODEV, NFSERR_NOTDIR,
! 181: NFSERR_ISDIR, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
! 182: NFSERR_IO, NFSERR_FBIG, NFSERR_NOSPC, NFSERR_IO, NFSERR_ROFS,
! 183: NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
! 184: NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
! 185: NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
! 186: NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
! 187: NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
! 188: NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
! 189: NFSERR_IO, NFSERR_IO, NFSERR_NAMETOL, NFSERR_IO, NFSERR_IO,
! 190: NFSERR_NOTEMPTY, NFSERR_IO, NFSERR_IO, NFSERR_DQUOT, NFSERR_STALE,
! 191: NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
! 192: NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
! 193: NFSERR_IO,
! 194: };
! 195:
! 196: /*
! 197: * Maps errno values to nfs error numbers.
! 198: * Although it is not obvious whether or not NFS clients really care if
! 199: * a returned error value is in the specified list for the procedure, the
! 200: * safest thing to do is filter them appropriately. For Version 2, the
! 201: * X/Open XNFS document is the only specification that defines error values
! 202: * for each RPC (The RFC simply lists all possible error values for all RPCs),
! 203: * so I have decided to not do this for Version 2.
! 204: * The first entry is the default error return and the rest are the valid
! 205: * errors for that RPC in increasing numeric order.
! 206: */
! 207: static short nfsv3err_null[] = {
! 208: 0,
! 209: 0,
! 210: };
! 211:
! 212: static short nfsv3err_getattr[] = {
! 213: NFSERR_IO,
! 214: NFSERR_IO,
! 215: NFSERR_STALE,
! 216: NFSERR_BADHANDLE,
! 217: NFSERR_SERVERFAULT,
! 218: 0,
! 219: };
! 220:
! 221: static short nfsv3err_setattr[] = {
! 222: NFSERR_IO,
! 223: NFSERR_PERM,
! 224: NFSERR_IO,
! 225: NFSERR_ACCES,
! 226: NFSERR_INVAL,
! 227: NFSERR_NOSPC,
! 228: NFSERR_ROFS,
! 229: NFSERR_DQUOT,
! 230: NFSERR_STALE,
! 231: NFSERR_BADHANDLE,
! 232: NFSERR_NOT_SYNC,
! 233: NFSERR_SERVERFAULT,
! 234: 0,
! 235: };
! 236:
! 237: static short nfsv3err_lookup[] = {
! 238: NFSERR_IO,
! 239: NFSERR_NOENT,
! 240: NFSERR_IO,
! 241: NFSERR_ACCES,
! 242: NFSERR_NOTDIR,
! 243: NFSERR_NAMETOL,
! 244: NFSERR_STALE,
! 245: NFSERR_BADHANDLE,
! 246: NFSERR_SERVERFAULT,
! 247: 0,
! 248: };
! 249:
! 250: static short nfsv3err_access[] = {
! 251: NFSERR_IO,
! 252: NFSERR_IO,
! 253: NFSERR_STALE,
! 254: NFSERR_BADHANDLE,
! 255: NFSERR_SERVERFAULT,
! 256: 0,
! 257: };
! 258:
! 259: static short nfsv3err_readlink[] = {
! 260: NFSERR_IO,
! 261: NFSERR_IO,
! 262: NFSERR_ACCES,
! 263: NFSERR_INVAL,
! 264: NFSERR_STALE,
! 265: NFSERR_BADHANDLE,
! 266: NFSERR_NOTSUPP,
! 267: NFSERR_SERVERFAULT,
! 268: 0,
! 269: };
! 270:
! 271: static short nfsv3err_read[] = {
! 272: NFSERR_IO,
! 273: NFSERR_IO,
! 274: NFSERR_NXIO,
! 275: NFSERR_ACCES,
! 276: NFSERR_INVAL,
! 277: NFSERR_STALE,
! 278: NFSERR_BADHANDLE,
! 279: NFSERR_SERVERFAULT,
! 280: 0,
! 281: };
! 282:
! 283: static short nfsv3err_write[] = {
! 284: NFSERR_IO,
! 285: NFSERR_IO,
! 286: NFSERR_ACCES,
! 287: NFSERR_INVAL,
! 288: NFSERR_FBIG,
! 289: NFSERR_NOSPC,
! 290: NFSERR_ROFS,
! 291: NFSERR_DQUOT,
! 292: NFSERR_STALE,
! 293: NFSERR_BADHANDLE,
! 294: NFSERR_SERVERFAULT,
! 295: 0,
! 296: };
! 297:
! 298: static short nfsv3err_create[] = {
! 299: NFSERR_IO,
! 300: NFSERR_IO,
! 301: NFSERR_ACCES,
! 302: NFSERR_EXIST,
! 303: NFSERR_NOTDIR,
! 304: NFSERR_NOSPC,
! 305: NFSERR_ROFS,
! 306: NFSERR_NAMETOL,
! 307: NFSERR_DQUOT,
! 308: NFSERR_STALE,
! 309: NFSERR_BADHANDLE,
! 310: NFSERR_NOTSUPP,
! 311: NFSERR_SERVERFAULT,
! 312: 0,
! 313: };
! 314:
! 315: static short nfsv3err_mkdir[] = {
! 316: NFSERR_IO,
! 317: NFSERR_IO,
! 318: NFSERR_ACCES,
! 319: NFSERR_EXIST,
! 320: NFSERR_NOTDIR,
! 321: NFSERR_NOSPC,
! 322: NFSERR_ROFS,
! 323: NFSERR_NAMETOL,
! 324: NFSERR_DQUOT,
! 325: NFSERR_STALE,
! 326: NFSERR_BADHANDLE,
! 327: NFSERR_NOTSUPP,
! 328: NFSERR_SERVERFAULT,
! 329: 0,
! 330: };
! 331:
! 332: static short nfsv3err_symlink[] = {
! 333: NFSERR_IO,
! 334: NFSERR_IO,
! 335: NFSERR_ACCES,
! 336: NFSERR_EXIST,
! 337: NFSERR_NOTDIR,
! 338: NFSERR_NOSPC,
! 339: NFSERR_ROFS,
! 340: NFSERR_NAMETOL,
! 341: NFSERR_DQUOT,
! 342: NFSERR_STALE,
! 343: NFSERR_BADHANDLE,
! 344: NFSERR_NOTSUPP,
! 345: NFSERR_SERVERFAULT,
! 346: 0,
! 347: };
! 348:
! 349: static short nfsv3err_mknod[] = {
! 350: NFSERR_IO,
! 351: NFSERR_IO,
! 352: NFSERR_ACCES,
! 353: NFSERR_EXIST,
! 354: NFSERR_NOTDIR,
! 355: NFSERR_NOSPC,
! 356: NFSERR_ROFS,
! 357: NFSERR_NAMETOL,
! 358: NFSERR_DQUOT,
! 359: NFSERR_STALE,
! 360: NFSERR_BADHANDLE,
! 361: NFSERR_NOTSUPP,
! 362: NFSERR_SERVERFAULT,
! 363: NFSERR_BADTYPE,
! 364: 0,
! 365: };
! 366:
! 367: static short nfsv3err_remove[] = {
! 368: NFSERR_IO,
! 369: NFSERR_NOENT,
! 370: NFSERR_IO,
! 371: NFSERR_ACCES,
! 372: NFSERR_NOTDIR,
! 373: NFSERR_ROFS,
! 374: NFSERR_NAMETOL,
! 375: NFSERR_STALE,
! 376: NFSERR_BADHANDLE,
! 377: NFSERR_SERVERFAULT,
! 378: 0,
! 379: };
! 380:
! 381: static short nfsv3err_rmdir[] = {
! 382: NFSERR_IO,
! 383: NFSERR_NOENT,
! 384: NFSERR_IO,
! 385: NFSERR_ACCES,
! 386: NFSERR_EXIST,
! 387: NFSERR_NOTDIR,
! 388: NFSERR_INVAL,
! 389: NFSERR_ROFS,
! 390: NFSERR_NAMETOL,
! 391: NFSERR_NOTEMPTY,
! 392: NFSERR_STALE,
! 393: NFSERR_BADHANDLE,
! 394: NFSERR_NOTSUPP,
! 395: NFSERR_SERVERFAULT,
! 396: 0,
! 397: };
! 398:
! 399: static short nfsv3err_rename[] = {
! 400: NFSERR_IO,
! 401: NFSERR_NOENT,
! 402: NFSERR_IO,
! 403: NFSERR_ACCES,
! 404: NFSERR_EXIST,
! 405: NFSERR_XDEV,
! 406: NFSERR_NOTDIR,
! 407: NFSERR_ISDIR,
! 408: NFSERR_INVAL,
! 409: NFSERR_NOSPC,
! 410: NFSERR_ROFS,
! 411: NFSERR_MLINK,
! 412: NFSERR_NAMETOL,
! 413: NFSERR_NOTEMPTY,
! 414: NFSERR_DQUOT,
! 415: NFSERR_STALE,
! 416: NFSERR_BADHANDLE,
! 417: NFSERR_NOTSUPP,
! 418: NFSERR_SERVERFAULT,
! 419: 0,
! 420: };
! 421:
! 422: static short nfsv3err_link[] = {
! 423: NFSERR_IO,
! 424: NFSERR_IO,
! 425: NFSERR_ACCES,
! 426: NFSERR_EXIST,
! 427: NFSERR_XDEV,
! 428: NFSERR_NOTDIR,
! 429: NFSERR_INVAL,
! 430: NFSERR_NOSPC,
! 431: NFSERR_ROFS,
! 432: NFSERR_MLINK,
! 433: NFSERR_NAMETOL,
! 434: NFSERR_DQUOT,
! 435: NFSERR_STALE,
! 436: NFSERR_BADHANDLE,
! 437: NFSERR_NOTSUPP,
! 438: NFSERR_SERVERFAULT,
! 439: 0,
! 440: };
! 441:
! 442: static short nfsv3err_readdir[] = {
! 443: NFSERR_IO,
! 444: NFSERR_IO,
! 445: NFSERR_ACCES,
! 446: NFSERR_NOTDIR,
! 447: NFSERR_STALE,
! 448: NFSERR_BADHANDLE,
! 449: NFSERR_BAD_COOKIE,
! 450: NFSERR_TOOSMALL,
! 451: NFSERR_SERVERFAULT,
! 452: 0,
! 453: };
! 454:
! 455: static short nfsv3err_readdirplus[] = {
! 456: NFSERR_IO,
! 457: NFSERR_IO,
! 458: NFSERR_ACCES,
! 459: NFSERR_NOTDIR,
! 460: NFSERR_STALE,
! 461: NFSERR_BADHANDLE,
! 462: NFSERR_BAD_COOKIE,
! 463: NFSERR_NOTSUPP,
! 464: NFSERR_TOOSMALL,
! 465: NFSERR_SERVERFAULT,
! 466: 0,
! 467: };
! 468:
! 469: static short nfsv3err_fsstat[] = {
! 470: NFSERR_IO,
! 471: NFSERR_IO,
! 472: NFSERR_STALE,
! 473: NFSERR_BADHANDLE,
! 474: NFSERR_SERVERFAULT,
! 475: 0,
! 476: };
! 477:
! 478: static short nfsv3err_fsinfo[] = {
! 479: NFSERR_STALE,
! 480: NFSERR_STALE,
! 481: NFSERR_BADHANDLE,
! 482: NFSERR_SERVERFAULT,
! 483: 0,
! 484: };
! 485:
! 486: static short nfsv3err_pathconf[] = {
! 487: NFSERR_STALE,
! 488: NFSERR_STALE,
! 489: NFSERR_BADHANDLE,
! 490: NFSERR_SERVERFAULT,
! 491: 0,
! 492: };
! 493:
! 494: static short nfsv3err_commit[] = {
! 495: NFSERR_IO,
! 496: NFSERR_IO,
! 497: NFSERR_STALE,
! 498: NFSERR_BADHANDLE,
! 499: NFSERR_SERVERFAULT,
! 500: 0,
! 501: };
! 502:
! 503: static short *nfsrv_v3errmap[] = {
! 504: nfsv3err_null,
! 505: nfsv3err_getattr,
! 506: nfsv3err_setattr,
! 507: nfsv3err_lookup,
! 508: nfsv3err_access,
! 509: nfsv3err_readlink,
! 510: nfsv3err_read,
! 511: nfsv3err_write,
! 512: nfsv3err_create,
! 513: nfsv3err_mkdir,
! 514: nfsv3err_symlink,
! 515: nfsv3err_mknod,
! 516: nfsv3err_remove,
! 517: nfsv3err_rmdir,
! 518: nfsv3err_rename,
! 519: nfsv3err_link,
! 520: nfsv3err_readdir,
! 521: nfsv3err_readdirplus,
! 522: nfsv3err_fsstat,
! 523: nfsv3err_fsinfo,
! 524: nfsv3err_pathconf,
! 525: nfsv3err_commit,
! 526: };
! 527:
! 528: extern struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON];
! 529: extern struct nfsrtt nfsrtt;
! 530:
! 531: struct pool nfsreqpl;
! 532:
! 533: /*
! 534: * Create the header for an rpc request packet
! 535: * The hsiz is the size of the rest of the nfs request header.
! 536: * (just used to decide if a cluster is a good idea)
! 537: */
! 538: struct mbuf *
! 539: nfsm_reqh(vp, procid, hsiz, bposp)
! 540: struct vnode *vp;
! 541: u_long procid;
! 542: int hsiz;
! 543: caddr_t *bposp;
! 544: {
! 545: struct mbuf *mb;
! 546: caddr_t bpos;
! 547:
! 548: MGET(mb, M_WAIT, MT_DATA);
! 549: if (hsiz >= MINCLSIZE)
! 550: MCLGET(mb, M_WAIT);
! 551: mb->m_len = 0;
! 552: bpos = mtod(mb, caddr_t);
! 553:
! 554: /* Finally, return values */
! 555: *bposp = bpos;
! 556: return (mb);
! 557: }
! 558:
! 559: /*
! 560: * Build the RPC header and fill in the authorization info.
! 561: * The authorization string argument is only used when the credentials
! 562: * come from outside of the kernel.
! 563: * Returns the head of the mbuf list.
! 564: */
! 565: struct mbuf *
! 566: nfsm_rpchead(cr, nmflag, procid, auth_type, auth_len, auth_str, verf_len,
! 567: verf_str, mrest, mrest_len, mbp, xidp)
! 568: struct ucred *cr;
! 569: int nmflag;
! 570: int procid;
! 571: int auth_type;
! 572: int auth_len;
! 573: char *auth_str;
! 574: int verf_len;
! 575: char *verf_str;
! 576: struct mbuf *mrest;
! 577: int mrest_len;
! 578: struct mbuf **mbp;
! 579: u_int32_t *xidp;
! 580: {
! 581: struct mbuf *mb;
! 582: u_int32_t *tl;
! 583: caddr_t bpos;
! 584: int i;
! 585: struct mbuf *mreq, *mb2;
! 586: int siz, grpsiz, authsiz;
! 587:
! 588: authsiz = nfsm_rndup(auth_len);
! 589: MGETHDR(mb, M_WAIT, MT_DATA);
! 590: if ((authsiz + 10 * NFSX_UNSIGNED) >= MINCLSIZE) {
! 591: MCLGET(mb, M_WAIT);
! 592: } else if ((authsiz + 10 * NFSX_UNSIGNED) < MHLEN) {
! 593: MH_ALIGN(mb, authsiz + 10 * NFSX_UNSIGNED);
! 594: } else {
! 595: MH_ALIGN(mb, 8 * NFSX_UNSIGNED);
! 596: }
! 597: mb->m_len = 0;
! 598: mreq = mb;
! 599: bpos = mtod(mb, caddr_t);
! 600:
! 601: /*
! 602: * First the RPC header.
! 603: */
! 604: nfsm_build(tl, u_int32_t *, 8 * NFSX_UNSIGNED);
! 605:
! 606: /* Get a new (non-zero) xid */
! 607:
! 608: if ((nfs_xid == 0) && (nfs_xid_touched == 0)) {
! 609: nfs_xid = arc4random();
! 610: nfs_xid_touched = 1;
! 611: } else {
! 612: while ((*xidp = arc4random() % 256) == 0)
! 613: ;
! 614: nfs_xid += *xidp;
! 615: }
! 616:
! 617: *tl++ = *xidp = txdr_unsigned(nfs_xid);
! 618: *tl++ = rpc_call;
! 619: *tl++ = rpc_vers;
! 620: *tl++ = txdr_unsigned(NFS_PROG);
! 621: if (nmflag & NFSMNT_NFSV3)
! 622: *tl++ = txdr_unsigned(NFS_VER3);
! 623: else
! 624: *tl++ = txdr_unsigned(NFS_VER2);
! 625: if (nmflag & NFSMNT_NFSV3)
! 626: *tl++ = txdr_unsigned(procid);
! 627: else
! 628: *tl++ = txdr_unsigned(nfsv2_procid[procid]);
! 629:
! 630: /*
! 631: * And then the authorization cred.
! 632: */
! 633: *tl++ = txdr_unsigned(auth_type);
! 634: *tl = txdr_unsigned(authsiz);
! 635: switch (auth_type) {
! 636: case RPCAUTH_UNIX:
! 637: nfsm_build(tl, u_int32_t *, auth_len);
! 638: *tl++ = 0; /* stamp ?? */
! 639: *tl++ = 0; /* NULL hostname */
! 640: *tl++ = txdr_unsigned(cr->cr_uid);
! 641: *tl++ = txdr_unsigned(cr->cr_gid);
! 642: grpsiz = (auth_len >> 2) - 5;
! 643: *tl++ = txdr_unsigned(grpsiz);
! 644: for (i = 0; i < grpsiz; i++)
! 645: *tl++ = txdr_unsigned(cr->cr_groups[i]);
! 646: break;
! 647: case RPCAUTH_KERB4:
! 648: siz = auth_len;
! 649: while (siz > 0) {
! 650: if (M_TRAILINGSPACE(mb) == 0) {
! 651: MGET(mb2, M_WAIT, MT_DATA);
! 652: if (siz >= MINCLSIZE)
! 653: MCLGET(mb2, M_WAIT);
! 654: mb->m_next = mb2;
! 655: mb = mb2;
! 656: mb->m_len = 0;
! 657: bpos = mtod(mb, caddr_t);
! 658: }
! 659: i = min(siz, M_TRAILINGSPACE(mb));
! 660: bcopy(auth_str, bpos, i);
! 661: mb->m_len += i;
! 662: auth_str += i;
! 663: bpos += i;
! 664: siz -= i;
! 665: }
! 666: if ((siz = (nfsm_rndup(auth_len) - auth_len)) > 0) {
! 667: for (i = 0; i < siz; i++)
! 668: *bpos++ = '\0';
! 669: mb->m_len += siz;
! 670: }
! 671: break;
! 672: };
! 673:
! 674: /*
! 675: * And the verifier...
! 676: */
! 677: nfsm_build(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
! 678: if (verf_str) {
! 679: *tl++ = txdr_unsigned(RPCAUTH_KERB4);
! 680: *tl = txdr_unsigned(verf_len);
! 681: siz = verf_len;
! 682: while (siz > 0) {
! 683: if (M_TRAILINGSPACE(mb) == 0) {
! 684: MGET(mb2, M_WAIT, MT_DATA);
! 685: if (siz >= MINCLSIZE)
! 686: MCLGET(mb2, M_WAIT);
! 687: mb->m_next = mb2;
! 688: mb = mb2;
! 689: mb->m_len = 0;
! 690: bpos = mtod(mb, caddr_t);
! 691: }
! 692: i = min(siz, M_TRAILINGSPACE(mb));
! 693: bcopy(verf_str, bpos, i);
! 694: mb->m_len += i;
! 695: verf_str += i;
! 696: bpos += i;
! 697: siz -= i;
! 698: }
! 699: if ((siz = (nfsm_rndup(verf_len) - verf_len)) > 0) {
! 700: for (i = 0; i < siz; i++)
! 701: *bpos++ = '\0';
! 702: mb->m_len += siz;
! 703: }
! 704: } else {
! 705: *tl++ = txdr_unsigned(RPCAUTH_NULL);
! 706: *tl = 0;
! 707: }
! 708: mb->m_next = mrest;
! 709: mreq->m_pkthdr.len = authsiz + 10 * NFSX_UNSIGNED + mrest_len;
! 710: mreq->m_pkthdr.rcvif = (struct ifnet *)0;
! 711: *mbp = mb;
! 712: return (mreq);
! 713: }
! 714:
! 715: /*
! 716: * copies mbuf chain to the uio scatter/gather list
! 717: */
! 718: int
! 719: nfsm_mbuftouio(mrep, uiop, siz, dpos)
! 720: struct mbuf **mrep;
! 721: struct uio *uiop;
! 722: int siz;
! 723: caddr_t *dpos;
! 724: {
! 725: char *mbufcp, *uiocp;
! 726: int xfer, left, len;
! 727: struct mbuf *mp;
! 728: long uiosiz, rem;
! 729: int error = 0;
! 730:
! 731: mp = *mrep;
! 732: mbufcp = *dpos;
! 733: len = mtod(mp, caddr_t)+mp->m_len-mbufcp;
! 734: rem = nfsm_rndup(siz)-siz;
! 735: while (siz > 0) {
! 736: if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL)
! 737: return (EFBIG);
! 738: left = uiop->uio_iov->iov_len;
! 739: uiocp = uiop->uio_iov->iov_base;
! 740: if (left > siz)
! 741: left = siz;
! 742: uiosiz = left;
! 743: while (left > 0) {
! 744: while (len == 0) {
! 745: mp = mp->m_next;
! 746: if (mp == NULL)
! 747: return (EBADRPC);
! 748: mbufcp = mtod(mp, caddr_t);
! 749: len = mp->m_len;
! 750: }
! 751: xfer = (left > len) ? len : left;
! 752: #ifdef notdef
! 753: /* Not Yet.. */
! 754: if (uiop->uio_iov->iov_op != NULL)
! 755: (*(uiop->uio_iov->iov_op))
! 756: (mbufcp, uiocp, xfer);
! 757: else
! 758: #endif
! 759: if (uiop->uio_segflg == UIO_SYSSPACE)
! 760: bcopy(mbufcp, uiocp, xfer);
! 761: else
! 762: copyout(mbufcp, uiocp, xfer);
! 763: left -= xfer;
! 764: len -= xfer;
! 765: mbufcp += xfer;
! 766: uiocp += xfer;
! 767: uiop->uio_offset += xfer;
! 768: uiop->uio_resid -= xfer;
! 769: }
! 770: if (uiop->uio_iov->iov_len <= siz) {
! 771: uiop->uio_iovcnt--;
! 772: uiop->uio_iov++;
! 773: } else {
! 774: (char *)uiop->uio_iov->iov_base += uiosiz;
! 775: uiop->uio_iov->iov_len -= uiosiz;
! 776: }
! 777: siz -= uiosiz;
! 778: }
! 779: *dpos = mbufcp;
! 780: *mrep = mp;
! 781: if (rem > 0) {
! 782: if (len < rem)
! 783: error = nfs_adv(mrep, dpos, rem, len);
! 784: else
! 785: *dpos += rem;
! 786: }
! 787: return (error);
! 788: }
! 789:
! 790: /*
! 791: * copies a uio scatter/gather list to an mbuf chain.
! 792: * NOTE: can ony handle iovcnt == 1
! 793: */
! 794: int
! 795: nfsm_uiotombuf(uiop, mq, siz, bpos)
! 796: struct uio *uiop;
! 797: struct mbuf **mq;
! 798: int siz;
! 799: caddr_t *bpos;
! 800: {
! 801: char *uiocp;
! 802: struct mbuf *mp, *mp2;
! 803: int xfer, left, mlen;
! 804: int uiosiz, clflg, rem;
! 805: char *cp;
! 806:
! 807: #ifdef DIAGNOSTIC
! 808: if (uiop->uio_iovcnt != 1)
! 809: panic("nfsm_uiotombuf: iovcnt != 1");
! 810: #endif
! 811:
! 812: if (siz > MLEN) /* or should it >= MCLBYTES ?? */
! 813: clflg = 1;
! 814: else
! 815: clflg = 0;
! 816: rem = nfsm_rndup(siz)-siz;
! 817: mp = mp2 = *mq;
! 818: while (siz > 0) {
! 819: left = uiop->uio_iov->iov_len;
! 820: uiocp = uiop->uio_iov->iov_base;
! 821: if (left > siz)
! 822: left = siz;
! 823: uiosiz = left;
! 824: while (left > 0) {
! 825: mlen = M_TRAILINGSPACE(mp);
! 826: if (mlen == 0) {
! 827: MGET(mp, M_WAIT, MT_DATA);
! 828: if (clflg)
! 829: MCLGET(mp, M_WAIT);
! 830: mp->m_len = 0;
! 831: mp2->m_next = mp;
! 832: mp2 = mp;
! 833: mlen = M_TRAILINGSPACE(mp);
! 834: }
! 835: xfer = (left > mlen) ? mlen : left;
! 836: #ifdef notdef
! 837: /* Not Yet.. */
! 838: if (uiop->uio_iov->iov_op != NULL)
! 839: (*(uiop->uio_iov->iov_op))
! 840: (uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
! 841: else
! 842: #endif
! 843: if (uiop->uio_segflg == UIO_SYSSPACE)
! 844: bcopy(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
! 845: else
! 846: copyin(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
! 847: mp->m_len += xfer;
! 848: left -= xfer;
! 849: uiocp += xfer;
! 850: uiop->uio_offset += xfer;
! 851: uiop->uio_resid -= xfer;
! 852: }
! 853: (char *)uiop->uio_iov->iov_base += uiosiz;
! 854: uiop->uio_iov->iov_len -= uiosiz;
! 855: siz -= uiosiz;
! 856: }
! 857: if (rem > 0) {
! 858: if (rem > M_TRAILINGSPACE(mp)) {
! 859: MGET(mp, M_WAIT, MT_DATA);
! 860: mp->m_len = 0;
! 861: mp2->m_next = mp;
! 862: }
! 863: cp = mtod(mp, caddr_t)+mp->m_len;
! 864: for (left = 0; left < rem; left++)
! 865: *cp++ = '\0';
! 866: mp->m_len += rem;
! 867: *bpos = cp;
! 868: } else
! 869: *bpos = mtod(mp, caddr_t)+mp->m_len;
! 870: *mq = mp;
! 871: return (0);
! 872: }
! 873:
! 874: /*
! 875: * Help break down an mbuf chain by setting the first siz bytes contiguous
! 876: * pointed to by returned val.
! 877: * This is used by the macros nfsm_dissect and nfsm_dissecton for tough
! 878: * cases. (The macros use the vars. dpos and dpos2)
! 879: */
! 880: int
! 881: nfsm_disct(mdp, dposp, siz, left, cp2)
! 882: struct mbuf **mdp;
! 883: caddr_t *dposp;
! 884: int siz;
! 885: int left;
! 886: caddr_t *cp2;
! 887: {
! 888: struct mbuf *mp, *mp2;
! 889: int siz2, xfer;
! 890: caddr_t p;
! 891:
! 892: mp = *mdp;
! 893: while (left == 0) {
! 894: *mdp = mp = mp->m_next;
! 895: if (mp == NULL)
! 896: return (EBADRPC);
! 897: left = mp->m_len;
! 898: *dposp = mtod(mp, caddr_t);
! 899: }
! 900: if (left >= siz) {
! 901: *cp2 = *dposp;
! 902: *dposp += siz;
! 903: } else if (mp->m_next == NULL) {
! 904: return (EBADRPC);
! 905: } else if (siz > MHLEN) {
! 906: panic("nfs S too big");
! 907: } else {
! 908: MGET(mp2, M_WAIT, MT_DATA);
! 909: mp2->m_next = mp->m_next;
! 910: mp->m_next = mp2;
! 911: mp->m_len -= left;
! 912: mp = mp2;
! 913: *cp2 = p = mtod(mp, caddr_t);
! 914: bcopy(*dposp, p, left); /* Copy what was left */
! 915: siz2 = siz-left;
! 916: p += left;
! 917: mp2 = mp->m_next;
! 918: /* Loop around copying up the siz2 bytes */
! 919: while (siz2 > 0) {
! 920: if (mp2 == NULL)
! 921: return (EBADRPC);
! 922: xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2;
! 923: if (xfer > 0) {
! 924: bcopy(mtod(mp2, caddr_t), p, xfer);
! 925: NFSMADV(mp2, xfer);
! 926: mp2->m_len -= xfer;
! 927: p += xfer;
! 928: siz2 -= xfer;
! 929: }
! 930: if (siz2 > 0)
! 931: mp2 = mp2->m_next;
! 932: }
! 933: mp->m_len = siz;
! 934: *mdp = mp2;
! 935: *dposp = mtod(mp2, caddr_t);
! 936: }
! 937: return (0);
! 938: }
! 939:
! 940: /*
! 941: * Advance the position in the mbuf chain.
! 942: */
! 943: int
! 944: nfs_adv(mdp, dposp, offs, left)
! 945: struct mbuf **mdp;
! 946: caddr_t *dposp;
! 947: int offs;
! 948: int left;
! 949: {
! 950: struct mbuf *m;
! 951: int s;
! 952:
! 953: m = *mdp;
! 954: s = left;
! 955: while (s < offs) {
! 956: offs -= s;
! 957: m = m->m_next;
! 958: if (m == NULL)
! 959: return (EBADRPC);
! 960: s = m->m_len;
! 961: }
! 962: *mdp = m;
! 963: *dposp = mtod(m, caddr_t)+offs;
! 964: return (0);
! 965: }
! 966:
! 967: /*
! 968: * Copy a string into mbufs for the hard cases...
! 969: */
! 970: int
! 971: nfsm_strtmbuf(mb, bpos, cp, siz)
! 972: struct mbuf **mb;
! 973: char **bpos;
! 974: char *cp;
! 975: long siz;
! 976: {
! 977: struct mbuf *m1 = NULL, *m2;
! 978: long left, xfer, len, tlen;
! 979: u_int32_t *tl;
! 980: int putsize;
! 981:
! 982: putsize = 1;
! 983: m2 = *mb;
! 984: left = M_TRAILINGSPACE(m2);
! 985: if (left > 0) {
! 986: tl = ((u_int32_t *)(*bpos));
! 987: *tl++ = txdr_unsigned(siz);
! 988: putsize = 0;
! 989: left -= NFSX_UNSIGNED;
! 990: m2->m_len += NFSX_UNSIGNED;
! 991: if (left > 0) {
! 992: bcopy(cp, (caddr_t) tl, left);
! 993: siz -= left;
! 994: cp += left;
! 995: m2->m_len += left;
! 996: left = 0;
! 997: }
! 998: }
! 999: /* Loop around adding mbufs */
! 1000: while (siz > 0) {
! 1001: MGET(m1, M_WAIT, MT_DATA);
! 1002: if (siz > MLEN)
! 1003: MCLGET(m1, M_WAIT);
! 1004: m1->m_len = NFSMSIZ(m1);
! 1005: m2->m_next = m1;
! 1006: m2 = m1;
! 1007: tl = mtod(m1, u_int32_t *);
! 1008: tlen = 0;
! 1009: if (putsize) {
! 1010: *tl++ = txdr_unsigned(siz);
! 1011: m1->m_len -= NFSX_UNSIGNED;
! 1012: tlen = NFSX_UNSIGNED;
! 1013: putsize = 0;
! 1014: }
! 1015: if (siz < m1->m_len) {
! 1016: len = nfsm_rndup(siz);
! 1017: xfer = siz;
! 1018: if (xfer < len)
! 1019: *(tl+(xfer>>2)) = 0;
! 1020: } else {
! 1021: xfer = len = m1->m_len;
! 1022: }
! 1023: bcopy(cp, (caddr_t) tl, xfer);
! 1024: m1->m_len = len+tlen;
! 1025: siz -= xfer;
! 1026: cp += xfer;
! 1027: }
! 1028: *mb = m1;
! 1029: *bpos = mtod(m1, caddr_t)+m1->m_len;
! 1030: return (0);
! 1031: }
! 1032:
! 1033: /*
! 1034: * Called once to initialize data structures...
! 1035: */
! 1036: void
! 1037: nfs_init()
! 1038: {
! 1039: static struct timeout nfs_timer_to;
! 1040:
! 1041: nfsrtt.pos = 0;
! 1042: rpc_vers = txdr_unsigned(RPC_VER2);
! 1043: rpc_call = txdr_unsigned(RPC_CALL);
! 1044: rpc_reply = txdr_unsigned(RPC_REPLY);
! 1045: rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED);
! 1046: rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED);
! 1047: rpc_mismatch = txdr_unsigned(RPC_MISMATCH);
! 1048: rpc_autherr = txdr_unsigned(RPC_AUTHERR);
! 1049: rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX);
! 1050: rpc_auth_kerb = txdr_unsigned(RPCAUTH_KERB4);
! 1051: nfs_prog = txdr_unsigned(NFS_PROG);
! 1052: nfs_true = txdr_unsigned(TRUE);
! 1053: nfs_false = txdr_unsigned(FALSE);
! 1054: nfs_xdrneg1 = txdr_unsigned(-1);
! 1055: nfs_ticks = (hz * NFS_TICKINTVL + 500) / 1000;
! 1056: if (nfs_ticks < 1)
! 1057: nfs_ticks = 1;
! 1058: #ifdef NFSSERVER
! 1059: nfsrv_init(0); /* Init server data structures */
! 1060: nfsrv_initcache(); /* Init the server request cache */
! 1061: #endif /* NFSSERVER */
! 1062:
! 1063: pool_init(&nfsreqpl, sizeof(struct nfsreq), 0, 0, 0, "nfsreqpl",
! 1064: &pool_allocator_nointr);
! 1065:
! 1066: /*
! 1067: * Initialize reply list and start timer
! 1068: */
! 1069: TAILQ_INIT(&nfs_reqq);
! 1070:
! 1071: timeout_set(&nfs_timer_to, nfs_timer, &nfs_timer_to);
! 1072: nfs_timer(&nfs_timer_to);
! 1073: }
! 1074:
! 1075: #ifdef NFSCLIENT
! 1076: int
! 1077: nfs_vfs_init(vfsp)
! 1078: struct vfsconf *vfsp;
! 1079: {
! 1080: int i;
! 1081:
! 1082: /* Ensure async daemons disabled */
! 1083: for (i = 0; i < NFS_MAXASYNCDAEMON; i++)
! 1084: nfs_iodwant[i] = (struct proc *)0;
! 1085: TAILQ_INIT(&nfs_bufq);
! 1086: nfs_nhinit(); /* Init the nfsnode table */
! 1087:
! 1088: return (0);
! 1089: }
! 1090:
! 1091: /*
! 1092: * Attribute cache routines.
! 1093: * nfs_loadattrcache() - loads or updates the cache contents from attributes
! 1094: * that are on the mbuf list
! 1095: * nfs_getattrcache() - returns valid attributes if found in cache, returns
! 1096: * error otherwise
! 1097: */
! 1098:
! 1099: /*
! 1100: * Load the attribute cache (that lives in the nfsnode entry) with
! 1101: * the values on the mbuf list and
! 1102: * Iff vap not NULL
! 1103: * copy the attributes to *vaper
! 1104: */
! 1105: int
! 1106: nfs_loadattrcache(vpp, mdp, dposp, vaper)
! 1107: struct vnode **vpp;
! 1108: struct mbuf **mdp;
! 1109: caddr_t *dposp;
! 1110: struct vattr *vaper;
! 1111: {
! 1112: struct vnode *vp = *vpp;
! 1113: struct vattr *vap;
! 1114: struct nfs_fattr *fp;
! 1115: extern int (**spec_nfsv2nodeop_p)(void *);
! 1116: struct nfsnode *np;
! 1117: int32_t t1;
! 1118: caddr_t cp2;
! 1119: int error = 0;
! 1120: int32_t rdev;
! 1121: struct mbuf *md;
! 1122: enum vtype vtyp;
! 1123: mode_t vmode;
! 1124: struct timespec mtime;
! 1125: struct vnode *nvp;
! 1126: int v3 = NFS_ISV3(vp);
! 1127:
! 1128: md = *mdp;
! 1129: t1 = (mtod(md, caddr_t) + md->m_len) - *dposp;
! 1130: error = nfsm_disct(mdp, dposp, NFSX_FATTR(v3), t1, &cp2);
! 1131: if (error)
! 1132: return (error);
! 1133: fp = (struct nfs_fattr *)cp2;
! 1134: if (v3) {
! 1135: vtyp = nfsv3tov_type(fp->fa_type);
! 1136: vmode = fxdr_unsigned(mode_t, fp->fa_mode);
! 1137: rdev = makedev(fxdr_unsigned(u_int32_t, fp->fa3_rdev.specdata1),
! 1138: fxdr_unsigned(u_int32_t, fp->fa3_rdev.specdata2));
! 1139: fxdr_nfsv3time(&fp->fa3_mtime, &mtime);
! 1140: } else {
! 1141: vtyp = nfsv2tov_type(fp->fa_type);
! 1142: vmode = fxdr_unsigned(mode_t, fp->fa_mode);
! 1143: if (vtyp == VNON || vtyp == VREG)
! 1144: vtyp = IFTOVT(vmode);
! 1145: rdev = fxdr_unsigned(int32_t, fp->fa2_rdev);
! 1146: fxdr_nfsv2time(&fp->fa2_mtime, &mtime);
! 1147:
! 1148: /*
! 1149: * Really ugly NFSv2 kludge.
! 1150: */
! 1151: if (vtyp == VCHR && rdev == 0xffffffff)
! 1152: vtyp = VFIFO;
! 1153: }
! 1154:
! 1155: /*
! 1156: * If v_type == VNON it is a new node, so fill in the v_type,
! 1157: * n_mtime fields. Check to see if it represents a special
! 1158: * device, and if so, check for a possible alias. Once the
! 1159: * correct vnode has been obtained, fill in the rest of the
! 1160: * information.
! 1161: */
! 1162: np = VTONFS(vp);
! 1163: if (vp->v_type != vtyp) {
! 1164: vp->v_type = vtyp;
! 1165: if (vp->v_type == VFIFO) {
! 1166: #ifndef FIFO
! 1167: return (EOPNOTSUPP);
! 1168: #else
! 1169: extern int (**fifo_nfsv2nodeop_p)(void *);
! 1170: vp->v_op = fifo_nfsv2nodeop_p;
! 1171: #endif /* FIFO */
! 1172: }
! 1173: if (vp->v_type == VCHR || vp->v_type == VBLK) {
! 1174: vp->v_op = spec_nfsv2nodeop_p;
! 1175: nvp = checkalias(vp, (dev_t)rdev, vp->v_mount);
! 1176: if (nvp) {
! 1177: /*
! 1178: * Discard unneeded vnode, but save its nfsnode.
! 1179: * Since the nfsnode does not have a lock, its
! 1180: * vnode lock has to be carried over.
! 1181: */
! 1182:
! 1183: nvp->v_data = vp->v_data;
! 1184: vp->v_data = NULL;
! 1185: vp->v_op = spec_vnodeop_p;
! 1186: vrele(vp);
! 1187: vgone(vp);
! 1188: /*
! 1189: * Reinitialize aliased node.
! 1190: */
! 1191: np->n_vnode = nvp;
! 1192: *vpp = vp = nvp;
! 1193: }
! 1194: }
! 1195: np->n_mtime = mtime.tv_sec;
! 1196: }
! 1197: vap = &np->n_vattr;
! 1198: vap->va_type = vtyp;
! 1199: vap->va_mode = (vmode & 07777);
! 1200: vap->va_rdev = (dev_t)rdev;
! 1201: vap->va_mtime = mtime;
! 1202: vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0];
! 1203: if (v3) {
! 1204: vap->va_nlink = fxdr_unsigned(nlink_t, fp->fa_nlink);
! 1205: vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid);
! 1206: vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid);
! 1207: vap->va_size = fxdr_hyper(&fp->fa3_size);
! 1208: vap->va_blocksize = NFS_FABLKSIZE;
! 1209: vap->va_bytes = fxdr_hyper(&fp->fa3_used);
! 1210: vap->va_fileid = fxdr_unsigned(int32_t,
! 1211: fp->fa3_fileid.nfsuquad[1]);
! 1212: fxdr_nfsv3time(&fp->fa3_atime, &vap->va_atime);
! 1213: fxdr_nfsv3time(&fp->fa3_ctime, &vap->va_ctime);
! 1214: vap->va_flags = 0;
! 1215: vap->va_filerev = 0;
! 1216: } else {
! 1217: vap->va_nlink = fxdr_unsigned(nlink_t, fp->fa_nlink);
! 1218: vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid);
! 1219: vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid);
! 1220: vap->va_size = fxdr_unsigned(u_int32_t, fp->fa2_size);
! 1221: vap->va_blocksize = fxdr_unsigned(int32_t, fp->fa2_blocksize);
! 1222: vap->va_bytes =
! 1223: (u_quad_t)fxdr_unsigned(int32_t, fp->fa2_blocks) *
! 1224: NFS_FABLKSIZE;
! 1225: vap->va_fileid = fxdr_unsigned(int32_t, fp->fa2_fileid);
! 1226: fxdr_nfsv2time(&fp->fa2_atime, &vap->va_atime);
! 1227: vap->va_flags = 0;
! 1228: vap->va_ctime.tv_sec = fxdr_unsigned(u_int32_t,
! 1229: fp->fa2_ctime.nfsv2_sec);
! 1230: vap->va_ctime.tv_nsec = 0;
! 1231: vap->va_gen = fxdr_unsigned(u_int32_t,fp->fa2_ctime.nfsv2_usec);
! 1232: vap->va_filerev = 0;
! 1233: }
! 1234: if (vap->va_size != np->n_size) {
! 1235: if (vap->va_type == VREG) {
! 1236: if (np->n_flag & NMODIFIED) {
! 1237: if (vap->va_size < np->n_size)
! 1238: vap->va_size = np->n_size;
! 1239: else
! 1240: np->n_size = vap->va_size;
! 1241: } else
! 1242: np->n_size = vap->va_size;
! 1243: uvm_vnp_setsize(vp, np->n_size);
! 1244: } else
! 1245: np->n_size = vap->va_size;
! 1246: }
! 1247: np->n_attrstamp = time_second;
! 1248: if (vaper != NULL) {
! 1249: bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(*vap));
! 1250: if (np->n_flag & NCHG) {
! 1251: if (np->n_flag & NACC)
! 1252: vaper->va_atime = np->n_atim;
! 1253: if (np->n_flag & NUPD)
! 1254: vaper->va_mtime = np->n_mtim;
! 1255: }
! 1256: }
! 1257: return (0);
! 1258: }
! 1259:
! 1260: INLINE int
! 1261: nfs_attrtimeo (np)
! 1262: struct nfsnode *np;
! 1263: {
! 1264: struct vnode *vp = np->n_vnode;
! 1265: struct nfsmount *nmp = VFSTONFS(vp->v_mount);
! 1266: int tenthage = (time_second - np->n_mtime) / 10;
! 1267: int minto, maxto;
! 1268:
! 1269: if (vp->v_type == VDIR) {
! 1270: maxto = nmp->nm_acdirmax;
! 1271: minto = nmp->nm_acdirmin;
! 1272: }
! 1273: else {
! 1274: maxto = nmp->nm_acregmax;
! 1275: minto = nmp->nm_acregmin;
! 1276: }
! 1277:
! 1278: if (np->n_flag & NMODIFIED || tenthage < minto)
! 1279: return minto;
! 1280: else if (tenthage < maxto)
! 1281: return tenthage;
! 1282: else
! 1283: return maxto;
! 1284: }
! 1285:
! 1286: /*
! 1287: * Check the time stamp
! 1288: * If the cache is valid, copy contents to *vap and return 0
! 1289: * otherwise return an error
! 1290: */
! 1291: int
! 1292: nfs_getattrcache(vp, vaper)
! 1293: struct vnode *vp;
! 1294: struct vattr *vaper;
! 1295: {
! 1296: struct nfsnode *np = VTONFS(vp);
! 1297: struct vattr *vap;
! 1298:
! 1299: if (np->n_attrstamp == 0 ||
! 1300: (time_second - np->n_attrstamp) >= nfs_attrtimeo(np)) {
! 1301: nfsstats.attrcache_misses++;
! 1302: return (ENOENT);
! 1303: }
! 1304: nfsstats.attrcache_hits++;
! 1305: vap = &np->n_vattr;
! 1306: if (vap->va_size != np->n_size) {
! 1307: if (vap->va_type == VREG) {
! 1308: if (np->n_flag & NMODIFIED) {
! 1309: if (vap->va_size < np->n_size)
! 1310: vap->va_size = np->n_size;
! 1311: else
! 1312: np->n_size = vap->va_size;
! 1313: } else
! 1314: np->n_size = vap->va_size;
! 1315: uvm_vnp_setsize(vp, np->n_size);
! 1316: } else
! 1317: np->n_size = vap->va_size;
! 1318: }
! 1319: bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(struct vattr));
! 1320: if (np->n_flag & NCHG) {
! 1321: if (np->n_flag & NACC)
! 1322: vaper->va_atime = np->n_atim;
! 1323: if (np->n_flag & NUPD)
! 1324: vaper->va_mtime = np->n_mtim;
! 1325: }
! 1326: return (0);
! 1327: }
! 1328: #endif /* NFSCLIENT */
! 1329:
! 1330: /*
! 1331: * Set up nameidata for a lookup() call and do it
! 1332: */
! 1333: int
! 1334: nfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, retdirp, p, kerbflag)
! 1335: struct nameidata *ndp;
! 1336: fhandle_t *fhp;
! 1337: int len;
! 1338: struct nfssvc_sock *slp;
! 1339: struct mbuf *nam;
! 1340: struct mbuf **mdp;
! 1341: caddr_t *dposp;
! 1342: struct vnode **retdirp;
! 1343: struct proc *p;
! 1344: int kerbflag;
! 1345: {
! 1346: int i, rem;
! 1347: struct mbuf *md;
! 1348: char *fromcp, *tocp;
! 1349: struct vnode *dp;
! 1350: int error, rdonly;
! 1351: struct componentname *cnp = &ndp->ni_cnd;
! 1352:
! 1353: *retdirp = (struct vnode *)0;
! 1354: cnp->cn_pnbuf = pool_get(&namei_pool, PR_WAITOK);
! 1355: /*
! 1356: * Copy the name from the mbuf list to ndp->ni_pnbuf
! 1357: * and set the various ndp fields appropriately.
! 1358: */
! 1359: fromcp = *dposp;
! 1360: tocp = cnp->cn_pnbuf;
! 1361: md = *mdp;
! 1362: rem = mtod(md, caddr_t) + md->m_len - fromcp;
! 1363: cnp->cn_hash = 0;
! 1364: for (i = 0; i < len; i++) {
! 1365: while (rem == 0) {
! 1366: md = md->m_next;
! 1367: if (md == NULL) {
! 1368: error = EBADRPC;
! 1369: goto out;
! 1370: }
! 1371: fromcp = mtod(md, caddr_t);
! 1372: rem = md->m_len;
! 1373: }
! 1374: if (*fromcp == '\0' || *fromcp == '/') {
! 1375: error = EACCES;
! 1376: goto out;
! 1377: }
! 1378: cnp->cn_hash += (u_char)*fromcp;
! 1379: *tocp++ = *fromcp++;
! 1380: rem--;
! 1381: }
! 1382: *tocp = '\0';
! 1383: *mdp = md;
! 1384: *dposp = fromcp;
! 1385: len = nfsm_rndup(len)-len;
! 1386: if (len > 0) {
! 1387: if (rem >= len)
! 1388: *dposp += len;
! 1389: else if ((error = nfs_adv(mdp, dposp, len, rem)) != 0)
! 1390: goto out;
! 1391: }
! 1392: ndp->ni_pathlen = tocp - cnp->cn_pnbuf;
! 1393: cnp->cn_nameptr = cnp->cn_pnbuf;
! 1394: /*
! 1395: * Extract and set starting directory.
! 1396: */
! 1397: error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cnd.cn_cred, slp,
! 1398: nam, &rdonly, kerbflag);
! 1399: if (error)
! 1400: goto out;
! 1401: if (dp->v_type != VDIR) {
! 1402: vrele(dp);
! 1403: error = ENOTDIR;
! 1404: goto out;
! 1405: }
! 1406: VREF(dp);
! 1407: *retdirp = dp;
! 1408: ndp->ni_startdir = dp;
! 1409: if (rdonly)
! 1410: cnp->cn_flags |= (NOCROSSMOUNT | RDONLY);
! 1411: else
! 1412: cnp->cn_flags |= NOCROSSMOUNT;
! 1413: /*
! 1414: * And call lookup() to do the real work
! 1415: */
! 1416: cnp->cn_proc = p;
! 1417: error = lookup(ndp);
! 1418: if (error)
! 1419: goto out;
! 1420: /*
! 1421: * Check for encountering a symbolic link
! 1422: */
! 1423: if (cnp->cn_flags & ISSYMLINK) {
! 1424: if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1)
! 1425: vput(ndp->ni_dvp);
! 1426: else
! 1427: vrele(ndp->ni_dvp);
! 1428: vput(ndp->ni_vp);
! 1429: ndp->ni_vp = NULL;
! 1430: error = EINVAL;
! 1431: goto out;
! 1432: }
! 1433: /*
! 1434: * Check for saved name request
! 1435: */
! 1436: if (cnp->cn_flags & (SAVENAME | SAVESTART)) {
! 1437: cnp->cn_flags |= HASBUF;
! 1438: return (0);
! 1439: }
! 1440: out:
! 1441: pool_put(&namei_pool, cnp->cn_pnbuf);
! 1442: return (error);
! 1443: }
! 1444:
! 1445: /*
! 1446: * A fiddled version of m_adj() that ensures null fill to a long
! 1447: * boundary and only trims off the back end
! 1448: */
! 1449: void
! 1450: nfsm_adj(mp, len, nul)
! 1451: struct mbuf *mp;
! 1452: int len;
! 1453: int nul;
! 1454: {
! 1455: struct mbuf *m;
! 1456: int count, i;
! 1457: char *cp;
! 1458:
! 1459: /*
! 1460: * Trim from tail. Scan the mbuf chain,
! 1461: * calculating its length and finding the last mbuf.
! 1462: * If the adjustment only affects this mbuf, then just
! 1463: * adjust and return. Otherwise, rescan and truncate
! 1464: * after the remaining size.
! 1465: */
! 1466: count = 0;
! 1467: m = mp;
! 1468: for (;;) {
! 1469: count += m->m_len;
! 1470: if (m->m_next == (struct mbuf *)0)
! 1471: break;
! 1472: m = m->m_next;
! 1473: }
! 1474: if (m->m_len > len) {
! 1475: m->m_len -= len;
! 1476: if (nul > 0) {
! 1477: cp = mtod(m, caddr_t)+m->m_len-nul;
! 1478: for (i = 0; i < nul; i++)
! 1479: *cp++ = '\0';
! 1480: }
! 1481: return;
! 1482: }
! 1483: count -= len;
! 1484: if (count < 0)
! 1485: count = 0;
! 1486: /*
! 1487: * Correct length for chain is "count".
! 1488: * Find the mbuf with last data, adjust its length,
! 1489: * and toss data from remaining mbufs on chain.
! 1490: */
! 1491: for (m = mp; m; m = m->m_next) {
! 1492: if (m->m_len >= count) {
! 1493: m->m_len = count;
! 1494: if (nul > 0) {
! 1495: cp = mtod(m, caddr_t)+m->m_len-nul;
! 1496: for (i = 0; i < nul; i++)
! 1497: *cp++ = '\0';
! 1498: }
! 1499: break;
! 1500: }
! 1501: count -= m->m_len;
! 1502: }
! 1503: for (m = m->m_next;m;m = m->m_next)
! 1504: m->m_len = 0;
! 1505: }
! 1506:
! 1507: /*
! 1508: * Make these functions instead of macros, so that the kernel text size
! 1509: * doesn't get too big...
! 1510: */
! 1511: void
! 1512: nfsm_srvwcc(nfsd, before_ret, before_vap, after_ret, after_vap, mbp, bposp)
! 1513: struct nfsrv_descript *nfsd;
! 1514: int before_ret;
! 1515: struct vattr *before_vap;
! 1516: int after_ret;
! 1517: struct vattr *after_vap;
! 1518: struct mbuf **mbp;
! 1519: char **bposp;
! 1520: {
! 1521: struct mbuf *mb = *mbp, *mb2;
! 1522: char *bpos = *bposp;
! 1523: u_int32_t *tl;
! 1524:
! 1525: if (before_ret) {
! 1526: nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED);
! 1527: *tl = nfs_false;
! 1528: } else {
! 1529: nfsm_build(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
! 1530: *tl++ = nfs_true;
! 1531: txdr_hyper(before_vap->va_size, tl);
! 1532: tl += 2;
! 1533: txdr_nfsv3time(&(before_vap->va_mtime), tl);
! 1534: tl += 2;
! 1535: txdr_nfsv3time(&(before_vap->va_ctime), tl);
! 1536: }
! 1537: *bposp = bpos;
! 1538: *mbp = mb;
! 1539: nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp);
! 1540: }
! 1541:
! 1542: void
! 1543: nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp)
! 1544: struct nfsrv_descript *nfsd;
! 1545: int after_ret;
! 1546: struct vattr *after_vap;
! 1547: struct mbuf **mbp;
! 1548: char **bposp;
! 1549: {
! 1550: struct mbuf *mb = *mbp, *mb2;
! 1551: char *bpos = *bposp;
! 1552: u_int32_t *tl;
! 1553: struct nfs_fattr *fp;
! 1554:
! 1555: if (after_ret) {
! 1556: nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED);
! 1557: *tl = nfs_false;
! 1558: } else {
! 1559: nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_V3FATTR);
! 1560: *tl++ = nfs_true;
! 1561: fp = (struct nfs_fattr *)tl;
! 1562: nfsm_srvfattr(nfsd, after_vap, fp);
! 1563: }
! 1564: *mbp = mb;
! 1565: *bposp = bpos;
! 1566: }
! 1567:
! 1568: void
! 1569: nfsm_srvfattr(nfsd, vap, fp)
! 1570: struct nfsrv_descript *nfsd;
! 1571: struct vattr *vap;
! 1572: struct nfs_fattr *fp;
! 1573: {
! 1574:
! 1575: fp->fa_nlink = txdr_unsigned(vap->va_nlink);
! 1576: fp->fa_uid = txdr_unsigned(vap->va_uid);
! 1577: fp->fa_gid = txdr_unsigned(vap->va_gid);
! 1578: if (nfsd->nd_flag & ND_NFSV3) {
! 1579: fp->fa_type = vtonfsv3_type(vap->va_type);
! 1580: fp->fa_mode = vtonfsv3_mode(vap->va_mode);
! 1581: txdr_hyper(vap->va_size, &fp->fa3_size);
! 1582: txdr_hyper(vap->va_bytes, &fp->fa3_used);
! 1583: fp->fa3_rdev.specdata1 = txdr_unsigned(major(vap->va_rdev));
! 1584: fp->fa3_rdev.specdata2 = txdr_unsigned(minor(vap->va_rdev));
! 1585: fp->fa3_fsid.nfsuquad[0] = 0;
! 1586: fp->fa3_fsid.nfsuquad[1] = txdr_unsigned(vap->va_fsid);
! 1587: fp->fa3_fileid.nfsuquad[0] = 0;
! 1588: fp->fa3_fileid.nfsuquad[1] = txdr_unsigned(vap->va_fileid);
! 1589: txdr_nfsv3time(&vap->va_atime, &fp->fa3_atime);
! 1590: txdr_nfsv3time(&vap->va_mtime, &fp->fa3_mtime);
! 1591: txdr_nfsv3time(&vap->va_ctime, &fp->fa3_ctime);
! 1592: } else {
! 1593: fp->fa_type = vtonfsv2_type(vap->va_type);
! 1594: fp->fa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode);
! 1595: fp->fa2_size = txdr_unsigned(vap->va_size);
! 1596: fp->fa2_blocksize = txdr_unsigned(vap->va_blocksize);
! 1597: if (vap->va_type == VFIFO)
! 1598: fp->fa2_rdev = 0xffffffff;
! 1599: else
! 1600: fp->fa2_rdev = txdr_unsigned(vap->va_rdev);
! 1601: fp->fa2_blocks = txdr_unsigned(vap->va_bytes / NFS_FABLKSIZE);
! 1602: fp->fa2_fsid = txdr_unsigned(vap->va_fsid);
! 1603: fp->fa2_fileid = txdr_unsigned(vap->va_fileid);
! 1604: txdr_nfsv2time(&vap->va_atime, &fp->fa2_atime);
! 1605: txdr_nfsv2time(&vap->va_mtime, &fp->fa2_mtime);
! 1606: txdr_nfsv2time(&vap->va_ctime, &fp->fa2_ctime);
! 1607: }
! 1608: }
! 1609:
! 1610: /*
! 1611: * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked)
! 1612: * - look up fsid in mount list (if not found ret error)
! 1613: * - get vp and export rights by calling VFS_FHTOVP() and VFS_CHECKEXP()
! 1614: * - if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon
! 1615: * - if not lockflag unlock it with VOP_UNLOCK()
! 1616: */
! 1617: int
! 1618: nfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp, kerbflag)
! 1619: fhandle_t *fhp;
! 1620: int lockflag;
! 1621: struct vnode **vpp;
! 1622: struct ucred *cred;
! 1623: struct nfssvc_sock *slp;
! 1624: struct mbuf *nam;
! 1625: int *rdonlyp;
! 1626: int kerbflag;
! 1627: {
! 1628: struct proc *p = curproc; /* XXX */
! 1629: struct mount *mp;
! 1630: int i;
! 1631: struct ucred *credanon;
! 1632: int error, exflags;
! 1633: struct sockaddr_in *saddr;
! 1634:
! 1635: *vpp = (struct vnode *)0;
! 1636: mp = vfs_getvfs(&fhp->fh_fsid);
! 1637:
! 1638: if (!mp)
! 1639: return (ESTALE);
! 1640: error = VFS_CHECKEXP(mp, nam, &exflags, &credanon);
! 1641: if (error)
! 1642: return (error);
! 1643: error = VFS_FHTOVP(mp, &fhp->fh_fid, vpp);
! 1644: if (error)
! 1645: return (error);
! 1646:
! 1647: saddr = mtod(nam, struct sockaddr_in *);
! 1648: if (saddr->sin_family == AF_INET &&
! 1649: (ntohs(saddr->sin_port) >= IPPORT_RESERVED ||
! 1650: (slp->ns_so->so_type == SOCK_STREAM && ntohs(saddr->sin_port) == 20))) {
! 1651: vput(*vpp);
! 1652: return (NFSERR_AUTHERR | AUTH_TOOWEAK);
! 1653: }
! 1654:
! 1655: /*
! 1656: * Check/setup credentials.
! 1657: */
! 1658: if (exflags & MNT_EXKERB) {
! 1659: if (!kerbflag) {
! 1660: vput(*vpp);
! 1661: return (NFSERR_AUTHERR | AUTH_TOOWEAK);
! 1662: }
! 1663: } else if (kerbflag) {
! 1664: vput(*vpp);
! 1665: return (NFSERR_AUTHERR | AUTH_TOOWEAK);
! 1666: } else if (cred->cr_uid == 0 || (exflags & MNT_EXPORTANON)) {
! 1667: cred->cr_uid = credanon->cr_uid;
! 1668: cred->cr_gid = credanon->cr_gid;
! 1669: for (i = 0; i < credanon->cr_ngroups && i < NGROUPS; i++)
! 1670: cred->cr_groups[i] = credanon->cr_groups[i];
! 1671: cred->cr_ngroups = i;
! 1672: }
! 1673: if (exflags & MNT_EXRDONLY)
! 1674: *rdonlyp = 1;
! 1675: else
! 1676: *rdonlyp = 0;
! 1677: if (!lockflag)
! 1678: VOP_UNLOCK(*vpp, 0, p);
! 1679:
! 1680: return (0);
! 1681: }
! 1682:
! 1683: /*
! 1684: * This function compares two net addresses by family and returns TRUE
! 1685: * if they are the same host.
! 1686: * If there is any doubt, return FALSE.
! 1687: * The AF_INET family is handled as a special case so that address mbufs
! 1688: * don't need to be saved to store "struct in_addr", which is only 4 bytes.
! 1689: */
! 1690: int
! 1691: netaddr_match(family, haddr, nam)
! 1692: int family;
! 1693: union nethostaddr *haddr;
! 1694: struct mbuf *nam;
! 1695: {
! 1696: struct sockaddr_in *inetaddr;
! 1697:
! 1698: switch (family) {
! 1699: case AF_INET:
! 1700: inetaddr = mtod(nam, struct sockaddr_in *);
! 1701: if (inetaddr->sin_family == AF_INET &&
! 1702: inetaddr->sin_addr.s_addr == haddr->had_inetaddr)
! 1703: return (1);
! 1704: break;
! 1705: default:
! 1706: break;
! 1707: };
! 1708: return (0);
! 1709: }
! 1710:
! 1711: /*
! 1712: * The write verifier has changed (probably due to a server reboot), so all
! 1713: * B_NEEDCOMMIT blocks will have to be written again. Since they are on the
! 1714: * dirty block list as B_DELWRI, all this takes is clearing the B_NEEDCOMMIT
! 1715: * flag. Once done the new write verifier can be set for the mount point.
! 1716: */
! 1717: void
! 1718: nfs_clearcommit(mp)
! 1719: struct mount *mp;
! 1720: {
! 1721: struct vnode *vp, *nvp;
! 1722: struct buf *bp, *nbp;
! 1723: int s;
! 1724:
! 1725: s = splbio();
! 1726: loop:
! 1727: for (vp = LIST_FIRST(&mp->mnt_vnodelist); vp != NULL; vp = nvp) {
! 1728: if (vp->v_mount != mp) /* Paranoia */
! 1729: goto loop;
! 1730: nvp = LIST_NEXT(vp, v_mntvnodes);
! 1731: for (bp = LIST_FIRST(&vp->v_dirtyblkhd); bp != NULL; bp = nbp) {
! 1732: nbp = LIST_NEXT(bp, b_vnbufs);
! 1733: if ((bp->b_flags & (B_BUSY | B_DELWRI | B_NEEDCOMMIT))
! 1734: == (B_DELWRI | B_NEEDCOMMIT))
! 1735: bp->b_flags &= ~B_NEEDCOMMIT;
! 1736: }
! 1737: }
! 1738: splx(s);
! 1739: }
! 1740:
! 1741: void
! 1742: nfs_merge_commit_ranges(vp)
! 1743: struct vnode *vp;
! 1744: {
! 1745: struct nfsnode *np = VTONFS(vp);
! 1746:
! 1747: if (!(np->n_commitflags & NFS_COMMIT_PUSHED_VALID)) {
! 1748: np->n_pushedlo = np->n_pushlo;
! 1749: np->n_pushedhi = np->n_pushhi;
! 1750: np->n_commitflags |= NFS_COMMIT_PUSHED_VALID;
! 1751: } else {
! 1752: if (np->n_pushlo < np->n_pushedlo)
! 1753: np->n_pushedlo = np->n_pushlo;
! 1754: if (np->n_pushhi > np->n_pushedhi)
! 1755: np->n_pushedhi = np->n_pushhi;
! 1756: }
! 1757:
! 1758: np->n_pushlo = np->n_pushhi = 0;
! 1759: np->n_commitflags &= ~NFS_COMMIT_PUSH_VALID;
! 1760: }
! 1761:
! 1762: int
! 1763: nfs_in_committed_range(vp, bp)
! 1764: struct vnode *vp;
! 1765: struct buf *bp;
! 1766: {
! 1767: struct nfsnode *np = VTONFS(vp);
! 1768: off_t lo, hi;
! 1769:
! 1770: if (!(np->n_commitflags & NFS_COMMIT_PUSHED_VALID))
! 1771: return 0;
! 1772: lo = (off_t)bp->b_blkno * DEV_BSIZE;
! 1773: hi = lo + bp->b_dirtyend;
! 1774:
! 1775: return (lo >= np->n_pushedlo && hi <= np->n_pushedhi);
! 1776: }
! 1777:
! 1778: int
! 1779: nfs_in_tobecommitted_range(vp, bp)
! 1780: struct vnode *vp;
! 1781: struct buf *bp;
! 1782: {
! 1783: struct nfsnode *np = VTONFS(vp);
! 1784: off_t lo, hi;
! 1785:
! 1786: if (!(np->n_commitflags & NFS_COMMIT_PUSH_VALID))
! 1787: return 0;
! 1788: lo = (off_t)bp->b_blkno * DEV_BSIZE;
! 1789: hi = lo + bp->b_dirtyend;
! 1790:
! 1791: return (lo >= np->n_pushlo && hi <= np->n_pushhi);
! 1792: }
! 1793:
! 1794: void
! 1795: nfs_add_committed_range(vp, bp)
! 1796: struct vnode *vp;
! 1797: struct buf *bp;
! 1798: {
! 1799: struct nfsnode *np = VTONFS(vp);
! 1800: off_t lo, hi;
! 1801:
! 1802: lo = (off_t)bp->b_blkno * DEV_BSIZE;
! 1803: hi = lo + bp->b_dirtyend;
! 1804:
! 1805: if (!(np->n_commitflags & NFS_COMMIT_PUSHED_VALID)) {
! 1806: np->n_pushedlo = lo;
! 1807: np->n_pushedhi = hi;
! 1808: np->n_commitflags |= NFS_COMMIT_PUSHED_VALID;
! 1809: } else {
! 1810: if (hi > np->n_pushedhi)
! 1811: np->n_pushedhi = hi;
! 1812: if (lo < np->n_pushedlo)
! 1813: np->n_pushedlo = lo;
! 1814: }
! 1815: }
! 1816:
! 1817: void
! 1818: nfs_del_committed_range(vp, bp)
! 1819: struct vnode *vp;
! 1820: struct buf *bp;
! 1821: {
! 1822: struct nfsnode *np = VTONFS(vp);
! 1823: off_t lo, hi;
! 1824:
! 1825: if (!(np->n_commitflags & NFS_COMMIT_PUSHED_VALID))
! 1826: return;
! 1827:
! 1828: lo = (off_t)bp->b_blkno * DEV_BSIZE;
! 1829: hi = lo + bp->b_dirtyend;
! 1830:
! 1831: if (lo > np->n_pushedhi || hi < np->n_pushedlo)
! 1832: return;
! 1833: if (lo <= np->n_pushedlo)
! 1834: np->n_pushedlo = hi;
! 1835: else if (hi >= np->n_pushedhi)
! 1836: np->n_pushedhi = lo;
! 1837: else {
! 1838: /*
! 1839: * XXX There's only one range. If the deleted range
! 1840: * is in the middle, pick the largest of the
! 1841: * contiguous ranges that it leaves.
! 1842: */
! 1843: if ((np->n_pushedlo - lo) > (hi - np->n_pushedhi))
! 1844: np->n_pushedhi = lo;
! 1845: else
! 1846: np->n_pushedlo = hi;
! 1847: }
! 1848: }
! 1849:
! 1850: void
! 1851: nfs_add_tobecommitted_range(vp, bp)
! 1852: struct vnode *vp;
! 1853: struct buf *bp;
! 1854: {
! 1855: struct nfsnode *np = VTONFS(vp);
! 1856: off_t lo, hi;
! 1857:
! 1858: lo = (off_t)bp->b_blkno * DEV_BSIZE;
! 1859: hi = lo + bp->b_dirtyend;
! 1860:
! 1861: if (!(np->n_commitflags & NFS_COMMIT_PUSH_VALID)) {
! 1862: np->n_pushlo = lo;
! 1863: np->n_pushhi = hi;
! 1864: np->n_commitflags |= NFS_COMMIT_PUSH_VALID;
! 1865: } else {
! 1866: if (lo < np->n_pushlo)
! 1867: np->n_pushlo = lo;
! 1868: if (hi > np->n_pushhi)
! 1869: np->n_pushhi = hi;
! 1870: }
! 1871: }
! 1872:
! 1873: void
! 1874: nfs_del_tobecommitted_range(vp, bp)
! 1875: struct vnode *vp;
! 1876: struct buf *bp;
! 1877: {
! 1878: struct nfsnode *np = VTONFS(vp);
! 1879: off_t lo, hi;
! 1880:
! 1881: if (!(np->n_commitflags & NFS_COMMIT_PUSH_VALID))
! 1882: return;
! 1883:
! 1884: lo = (off_t)bp->b_blkno * DEV_BSIZE;
! 1885: hi = lo + bp->b_dirtyend;
! 1886:
! 1887: if (lo > np->n_pushhi || hi < np->n_pushlo)
! 1888: return;
! 1889:
! 1890: if (lo <= np->n_pushlo)
! 1891: np->n_pushlo = hi;
! 1892: else if (hi >= np->n_pushhi)
! 1893: np->n_pushhi = lo;
! 1894: else {
! 1895: /*
! 1896: * XXX There's only one range. If the deleted range
! 1897: * is in the middle, pick the largest of the
! 1898: * contiguous ranges that it leaves.
! 1899: */
! 1900: if ((np->n_pushlo - lo) > (hi - np->n_pushhi))
! 1901: np->n_pushhi = lo;
! 1902: else
! 1903: np->n_pushlo = hi;
! 1904: }
! 1905: }
! 1906:
! 1907: /*
! 1908: * Map errnos to NFS error numbers. For Version 3 also filter out error
! 1909: * numbers not specified for the associated procedure.
! 1910: */
! 1911: int
! 1912: nfsrv_errmap(nd, err)
! 1913: struct nfsrv_descript *nd;
! 1914: int err;
! 1915: {
! 1916: short *defaulterrp, *errp;
! 1917:
! 1918: if (nd->nd_flag & ND_NFSV3) {
! 1919: if (nd->nd_procnum <= NFSPROC_COMMIT) {
! 1920: errp = defaulterrp = nfsrv_v3errmap[nd->nd_procnum];
! 1921: while (*++errp) {
! 1922: if (*errp == err)
! 1923: return (err);
! 1924: else if (*errp > err)
! 1925: break;
! 1926: }
! 1927: return ((int)*defaulterrp);
! 1928: } else
! 1929: return (err & 0xffff);
! 1930: }
! 1931: if (err <= ELAST)
! 1932: return ((int)nfsrv_v2errmap[err - 1]);
! 1933: return (NFSERR_IO);
! 1934: }
! 1935:
! 1936: /*
! 1937: * Sort the group list in increasing numerical order.
! 1938: * (Insertion sort by Chris Torek, who was grossed out by the bubble sort
! 1939: * that used to be here.)
! 1940: */
! 1941: void
! 1942: nfsrvw_sort(list, num)
! 1943: gid_t *list;
! 1944: int num;
! 1945: {
! 1946: int i, j;
! 1947: gid_t v;
! 1948:
! 1949: /* Insertion sort. */
! 1950: for (i = 1; i < num; i++) {
! 1951: v = list[i];
! 1952: /* find correct slot for value v, moving others up */
! 1953: for (j = i; --j >= 0 && v < list[j];)
! 1954: list[j + 1] = list[j];
! 1955: list[j + 1] = v;
! 1956: }
! 1957: }
! 1958:
! 1959: /*
! 1960: * copy credentials making sure that the result can be compared with bcmp().
! 1961: */
! 1962: void
! 1963: nfsrv_setcred(incred, outcred)
! 1964: struct ucred *incred, *outcred;
! 1965: {
! 1966: int i;
! 1967:
! 1968: bzero((caddr_t)outcred, sizeof (struct ucred));
! 1969: outcred->cr_ref = 1;
! 1970: outcred->cr_uid = incred->cr_uid;
! 1971: outcred->cr_gid = incred->cr_gid;
! 1972: outcred->cr_ngroups = incred->cr_ngroups;
! 1973: for (i = 0; i < incred->cr_ngroups; i++)
! 1974: outcred->cr_groups[i] = incred->cr_groups[i];
! 1975: nfsrvw_sort(outcred->cr_groups, outcred->cr_ngroups);
! 1976: }
CVSweb