[BACK]Return to nfs_subs.c CVS log [TXT][DIR] Up to [local] / sys / nfs

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