[BACK]Return to nfs_subs.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / nfs

Annotation of src/sys/nfs/nfs_subs.c, Revision 1.201.4.5

1.201.4.5! yamt        1: /*     $NetBSD: nfs_subs.c,v 1.201.4.4 2009/05/16 10:41:51 yamt Exp $  */
1.14      cgd         2:
1.1       cgd         3: /*
1.12      mycroft     4:  * Copyright (c) 1989, 1993
                      5:  *     The Regents of the University of California.  All rights reserved.
1.1       cgd         6:  *
                      7:  * This code is derived from software contributed to Berkeley by
                      8:  * Rick Macklem at The University of Guelph.
                      9:  *
                     10:  * Redistribution and use in source and binary forms, with or without
                     11:  * modification, are permitted provided that the following conditions
                     12:  * are met:
                     13:  * 1. Redistributions of source code must retain the above copyright
                     14:  *    notice, this list of conditions and the following disclaimer.
                     15:  * 2. Redistributions in binary form must reproduce the above copyright
                     16:  *    notice, this list of conditions and the following disclaimer in the
                     17:  *    documentation and/or other materials provided with the distribution.
1.127     agc        18:  * 3. Neither the name of the University nor the names of its contributors
1.1       cgd        19:  *    may be used to endorse or promote products derived from this software
                     20:  *    without specific prior written permission.
                     21:  *
                     22:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     23:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     24:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     25:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     26:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     27:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     28:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     29:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     30:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     31:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     32:  * SUCH DAMAGE.
                     33:  *
1.25      fvdl       34:  *     @(#)nfs_subs.c  8.8 (Berkeley) 5/22/95
1.1       cgd        35:  */
                     36:
1.83      fvdl       37: /*
                     38:  * Copyright 2000 Wasabi Systems, Inc.
                     39:  * All rights reserved.
                     40:  *
                     41:  * Written by Frank van der Linden for Wasabi Systems, Inc.
                     42:  *
                     43:  * Redistribution and use in source and binary forms, with or without
                     44:  * modification, are permitted provided that the following conditions
                     45:  * are met:
                     46:  * 1. Redistributions of source code must retain the above copyright
                     47:  *    notice, this list of conditions and the following disclaimer.
                     48:  * 2. Redistributions in binary form must reproduce the above copyright
                     49:  *    notice, this list of conditions and the following disclaimer in the
                     50:  *    documentation and/or other materials provided with the distribution.
                     51:  * 3. All advertising materials mentioning features or use of this software
                     52:  *    must display the following acknowledgement:
                     53:  *      This product includes software developed for the NetBSD Project by
                     54:  *      Wasabi Systems, Inc.
                     55:  * 4. The name of Wasabi Systems, Inc. may not be used to endorse
                     56:  *    or promote products derived from this software without specific prior
                     57:  *    written permission.
                     58:  *
                     59:  * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
                     60:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
                     61:  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
                     62:  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL WASABI SYSTEMS, INC
                     63:  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
                     64:  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
                     65:  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
                     66:  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
                     67:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
                     68:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
                     69:  * POSSIBILITY OF SUCH DAMAGE.
                     70:  */
1.99      lukem      71:
                     72: #include <sys/cdefs.h>
1.201.4.5! yamt       73: __KERNEL_RCSID(0, "$NetBSD: nfs_subs.c,v 1.201.4.4 2009/05/16 10:41:51 yamt Exp $");
1.83      fvdl       74:
1.201.4.3  yamt       75: #ifdef _KERNEL_OPT
1.82      bjh21      76: #include "opt_nfs.h"
1.201.4.3  yamt       77: #endif
1.25      fvdl       78:
1.1       cgd        79: /*
                     80:  * These functions support the macros and help fiddle mbuf chains for
                     81:  * the nfs op functions. They do things like create the rpc header and
                     82:  * copy data between mbuf chains and uio lists.
                     83:  */
1.9       mycroft    84: #include <sys/param.h>
                     85: #include <sys/proc.h>
                     86: #include <sys/systm.h>
                     87: #include <sys/kernel.h>
1.196     yamt       88: #include <sys/kmem.h>
1.9       mycroft    89: #include <sys/mount.h>
                     90: #include <sys/vnode.h>
                     91: #include <sys/namei.h>
                     92: #include <sys/mbuf.h>
1.12      mycroft    93: #include <sys/socket.h>
                     94: #include <sys/stat.h>
1.98      fvdl       95: #include <sys/filedesc.h>
1.30      fvdl       96: #include <sys/time.h>
1.43      fvdl       97: #include <sys/dirent.h>
1.155     thorpej    98: #include <sys/once.h>
1.162     elad       99: #include <sys/kauth.h>
1.201.4.3  yamt      100: #include <sys/atomic.h>
1.1       cgd       101:
1.51      mrg       102: #include <uvm/uvm_extern.h>
                    103:
1.9       mycroft   104: #include <nfs/rpcv2.h>
1.25      fvdl      105: #include <nfs/nfsproto.h>
1.9       mycroft   106: #include <nfs/nfsnode.h>
                    107: #include <nfs/nfs.h>
                    108: #include <nfs/xdr_subs.h>
                    109: #include <nfs/nfsm_subs.h>
1.12      mycroft   110: #include <nfs/nfsmount.h>
                    111: #include <nfs/nfsrtt.h>
1.24      christos  112: #include <nfs/nfs_var.h>
1.12      mycroft   113:
                    114: #include <miscfs/specfs/specdev.h>
1.24      christos  115:
1.12      mycroft   116: #include <netinet/in.h>
1.201.4.3  yamt      117:
                    118: static u_int32_t nfs_xid;
1.1       cgd       119:
1.201.4.5! yamt      120: int nuidhash_max = NFS_MAXUIDHASH;
1.1       cgd       121: /*
                    122:  * Data items converted to xdr at startup, since they are constant
                    123:  * This is kinda hokey, but may save a little time doing byte swaps
                    124:  */
1.22      cgd       125: u_int32_t nfs_xdrneg1;
                    126: u_int32_t rpc_call, rpc_vers, rpc_reply, rpc_msgdenied, rpc_autherr,
1.25      fvdl      127:        rpc_mismatch, rpc_auth_unix, rpc_msgaccepted,
1.12      mycroft   128:        rpc_auth_kerb;
1.179     yamt      129: u_int32_t nfs_prog, nfs_true, nfs_false;
1.12      mycroft   130:
1.1       cgd       131: /* And other global data */
1.90      jdolecek  132: const nfstype nfsv2_type[9] =
                    133:        { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFNON, NFCHR, NFNON };
                    134: const nfstype nfsv3_type[9] =
                    135:        { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFSOCK, NFFIFO, NFNON };
                    136: const enum vtype nv2tov_type[8] =
                    137:        { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON, VNON };
                    138: const enum vtype nv3tov_type[8] =
                    139:        { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO };
1.25      fvdl      140: int nfs_ticks;
1.108     christos  141:
1.35      thorpej   142: /* NFS client/server stats. */
                    143: struct nfsstats nfsstats;
                    144:
1.25      fvdl      145: /*
                    146:  * Mapping of old NFS Version 2 RPC numbers to generic numbers.
                    147:  */
1.90      jdolecek  148: const int nfsv3_procid[NFS_NPROCS] = {
1.25      fvdl      149:        NFSPROC_NULL,
                    150:        NFSPROC_GETATTR,
                    151:        NFSPROC_SETATTR,
                    152:        NFSPROC_NOOP,
                    153:        NFSPROC_LOOKUP,
                    154:        NFSPROC_READLINK,
                    155:        NFSPROC_READ,
                    156:        NFSPROC_NOOP,
                    157:        NFSPROC_WRITE,
                    158:        NFSPROC_CREATE,
                    159:        NFSPROC_REMOVE,
                    160:        NFSPROC_RENAME,
                    161:        NFSPROC_LINK,
                    162:        NFSPROC_SYMLINK,
                    163:        NFSPROC_MKDIR,
                    164:        NFSPROC_RMDIR,
                    165:        NFSPROC_READDIR,
                    166:        NFSPROC_FSSTAT,
                    167:        NFSPROC_NOOP,
                    168:        NFSPROC_NOOP,
                    169:        NFSPROC_NOOP,
                    170:        NFSPROC_NOOP,
                    171:        NFSPROC_NOOP
                    172: };
                    173:
                    174: /*
                    175:  * and the reverse mapping from generic to Version 2 procedure numbers
                    176:  */
1.90      jdolecek  177: const int nfsv2_procid[NFS_NPROCS] = {
1.25      fvdl      178:        NFSV2PROC_NULL,
                    179:        NFSV2PROC_GETATTR,
                    180:        NFSV2PROC_SETATTR,
                    181:        NFSV2PROC_LOOKUP,
                    182:        NFSV2PROC_NOOP,
                    183:        NFSV2PROC_READLINK,
                    184:        NFSV2PROC_READ,
                    185:        NFSV2PROC_WRITE,
                    186:        NFSV2PROC_CREATE,
                    187:        NFSV2PROC_MKDIR,
                    188:        NFSV2PROC_SYMLINK,
                    189:        NFSV2PROC_CREATE,
                    190:        NFSV2PROC_REMOVE,
                    191:        NFSV2PROC_RMDIR,
                    192:        NFSV2PROC_RENAME,
                    193:        NFSV2PROC_LINK,
                    194:        NFSV2PROC_READDIR,
                    195:        NFSV2PROC_NOOP,
                    196:        NFSV2PROC_STATFS,
                    197:        NFSV2PROC_NOOP,
                    198:        NFSV2PROC_NOOP,
                    199:        NFSV2PROC_NOOP,
                    200:        NFSV2PROC_NOOP,
                    201: };
                    202:
                    203: /*
                    204:  * Maps errno values to nfs error numbers.
                    205:  * Use NFSERR_IO as the catch all for ones not specifically defined in
                    206:  * RFC 1094.
                    207:  */
1.90      jdolecek  208: static const u_char nfsrv_v2errmap[ELAST] = {
1.25      fvdl      209:   NFSERR_PERM, NFSERR_NOENT,   NFSERR_IO,      NFSERR_IO,      NFSERR_IO,
                    210:   NFSERR_NXIO, NFSERR_IO,      NFSERR_IO,      NFSERR_IO,      NFSERR_IO,
                    211:   NFSERR_IO,   NFSERR_IO,      NFSERR_ACCES,   NFSERR_IO,      NFSERR_IO,
                    212:   NFSERR_IO,   NFSERR_EXIST,   NFSERR_IO,      NFSERR_NODEV,   NFSERR_NOTDIR,
                    213:   NFSERR_ISDIR,        NFSERR_IO,      NFSERR_IO,      NFSERR_IO,      NFSERR_IO,
                    214:   NFSERR_IO,   NFSERR_FBIG,    NFSERR_NOSPC,   NFSERR_IO,      NFSERR_ROFS,
                    215:   NFSERR_IO,   NFSERR_IO,      NFSERR_IO,      NFSERR_IO,      NFSERR_IO,
                    216:   NFSERR_IO,   NFSERR_IO,      NFSERR_IO,      NFSERR_IO,      NFSERR_IO,
                    217:   NFSERR_IO,   NFSERR_IO,      NFSERR_IO,      NFSERR_IO,      NFSERR_IO,
                    218:   NFSERR_IO,   NFSERR_IO,      NFSERR_IO,      NFSERR_IO,      NFSERR_IO,
                    219:   NFSERR_IO,   NFSERR_IO,      NFSERR_IO,      NFSERR_IO,      NFSERR_IO,
                    220:   NFSERR_IO,   NFSERR_IO,      NFSERR_IO,      NFSERR_IO,      NFSERR_IO,
                    221:   NFSERR_IO,   NFSERR_IO,      NFSERR_NAMETOL, NFSERR_IO,      NFSERR_IO,
                    222:   NFSERR_NOTEMPTY, NFSERR_IO,  NFSERR_IO,      NFSERR_DQUOT,   NFSERR_STALE,
                    223:   NFSERR_IO,   NFSERR_IO,      NFSERR_IO,      NFSERR_IO,      NFSERR_IO,
                    224:   NFSERR_IO,   NFSERR_IO,      NFSERR_IO,      NFSERR_IO,      NFSERR_IO,
1.52      mikel     225:   NFSERR_IO,   NFSERR_IO,
1.25      fvdl      226: };
                    227:
                    228: /*
                    229:  * Maps errno values to nfs error numbers.
                    230:  * Although it is not obvious whether or not NFS clients really care if
                    231:  * a returned error value is in the specified list for the procedure, the
                    232:  * safest thing to do is filter them appropriately. For Version 2, the
                    233:  * X/Open XNFS document is the only specification that defines error values
                    234:  * for each RPC (The RFC simply lists all possible error values for all RPCs),
                    235:  * so I have decided to not do this for Version 2.
                    236:  * The first entry is the default error return and the rest are the valid
                    237:  * errors for that RPC in increasing numeric order.
                    238:  */
1.90      jdolecek  239: static const short nfsv3err_null[] = {
1.25      fvdl      240:        0,
                    241:        0,
                    242: };
                    243:
1.90      jdolecek  244: static const short nfsv3err_getattr[] = {
1.25      fvdl      245:        NFSERR_IO,
                    246:        NFSERR_IO,
                    247:        NFSERR_STALE,
                    248:        NFSERR_BADHANDLE,
                    249:        NFSERR_SERVERFAULT,
                    250:        0,
                    251: };
                    252:
1.90      jdolecek  253: static const short nfsv3err_setattr[] = {
1.25      fvdl      254:        NFSERR_IO,
                    255:        NFSERR_PERM,
                    256:        NFSERR_IO,
                    257:        NFSERR_ACCES,
                    258:        NFSERR_INVAL,
                    259:        NFSERR_NOSPC,
                    260:        NFSERR_ROFS,
                    261:        NFSERR_DQUOT,
                    262:        NFSERR_STALE,
                    263:        NFSERR_BADHANDLE,
                    264:        NFSERR_NOT_SYNC,
                    265:        NFSERR_SERVERFAULT,
                    266:        0,
                    267: };
                    268:
1.90      jdolecek  269: static const short nfsv3err_lookup[] = {
1.25      fvdl      270:        NFSERR_IO,
                    271:        NFSERR_NOENT,
                    272:        NFSERR_IO,
                    273:        NFSERR_ACCES,
                    274:        NFSERR_NOTDIR,
                    275:        NFSERR_NAMETOL,
                    276:        NFSERR_STALE,
                    277:        NFSERR_BADHANDLE,
                    278:        NFSERR_SERVERFAULT,
                    279:        0,
                    280: };
                    281:
1.90      jdolecek  282: static const short nfsv3err_access[] = {
1.25      fvdl      283:        NFSERR_IO,
                    284:        NFSERR_IO,
                    285:        NFSERR_STALE,
                    286:        NFSERR_BADHANDLE,
                    287:        NFSERR_SERVERFAULT,
                    288:        0,
                    289: };
                    290:
1.90      jdolecek  291: static const short nfsv3err_readlink[] = {
1.25      fvdl      292:        NFSERR_IO,
                    293:        NFSERR_IO,
                    294:        NFSERR_ACCES,
                    295:        NFSERR_INVAL,
                    296:        NFSERR_STALE,
                    297:        NFSERR_BADHANDLE,
                    298:        NFSERR_NOTSUPP,
                    299:        NFSERR_SERVERFAULT,
                    300:        0,
                    301: };
                    302:
1.90      jdolecek  303: static const short nfsv3err_read[] = {
1.25      fvdl      304:        NFSERR_IO,
                    305:        NFSERR_IO,
                    306:        NFSERR_NXIO,
                    307:        NFSERR_ACCES,
                    308:        NFSERR_INVAL,
                    309:        NFSERR_STALE,
                    310:        NFSERR_BADHANDLE,
                    311:        NFSERR_SERVERFAULT,
1.67      fvdl      312:        NFSERR_JUKEBOX,
1.25      fvdl      313:        0,
                    314: };
                    315:
1.90      jdolecek  316: static const short nfsv3err_write[] = {
1.25      fvdl      317:        NFSERR_IO,
                    318:        NFSERR_IO,
                    319:        NFSERR_ACCES,
                    320:        NFSERR_INVAL,
                    321:        NFSERR_FBIG,
                    322:        NFSERR_NOSPC,
                    323:        NFSERR_ROFS,
                    324:        NFSERR_DQUOT,
                    325:        NFSERR_STALE,
                    326:        NFSERR_BADHANDLE,
                    327:        NFSERR_SERVERFAULT,
1.68      fvdl      328:        NFSERR_JUKEBOX,
1.25      fvdl      329:        0,
                    330: };
                    331:
1.90      jdolecek  332: static const short nfsv3err_create[] = {
1.25      fvdl      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:
1.90      jdolecek  349: static const short nfsv3err_mkdir[] = {
1.25      fvdl      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:        0,
                    364: };
                    365:
1.90      jdolecek  366: static const short nfsv3err_symlink[] = {
1.25      fvdl      367:        NFSERR_IO,
                    368:        NFSERR_IO,
                    369:        NFSERR_ACCES,
                    370:        NFSERR_EXIST,
                    371:        NFSERR_NOTDIR,
                    372:        NFSERR_NOSPC,
                    373:        NFSERR_ROFS,
                    374:        NFSERR_NAMETOL,
                    375:        NFSERR_DQUOT,
                    376:        NFSERR_STALE,
                    377:        NFSERR_BADHANDLE,
                    378:        NFSERR_NOTSUPP,
                    379:        NFSERR_SERVERFAULT,
                    380:        0,
                    381: };
                    382:
1.90      jdolecek  383: static const short nfsv3err_mknod[] = {
1.25      fvdl      384:        NFSERR_IO,
                    385:        NFSERR_IO,
                    386:        NFSERR_ACCES,
                    387:        NFSERR_EXIST,
                    388:        NFSERR_NOTDIR,
                    389:        NFSERR_NOSPC,
                    390:        NFSERR_ROFS,
                    391:        NFSERR_NAMETOL,
                    392:        NFSERR_DQUOT,
                    393:        NFSERR_STALE,
                    394:        NFSERR_BADHANDLE,
                    395:        NFSERR_NOTSUPP,
                    396:        NFSERR_SERVERFAULT,
                    397:        NFSERR_BADTYPE,
                    398:        0,
                    399: };
                    400:
1.90      jdolecek  401: static const short nfsv3err_remove[] = {
1.25      fvdl      402:        NFSERR_IO,
                    403:        NFSERR_NOENT,
                    404:        NFSERR_IO,
                    405:        NFSERR_ACCES,
                    406:        NFSERR_NOTDIR,
                    407:        NFSERR_ROFS,
                    408:        NFSERR_NAMETOL,
                    409:        NFSERR_STALE,
                    410:        NFSERR_BADHANDLE,
                    411:        NFSERR_SERVERFAULT,
                    412:        0,
                    413: };
                    414:
1.90      jdolecek  415: static const short nfsv3err_rmdir[] = {
1.25      fvdl      416:        NFSERR_IO,
                    417:        NFSERR_NOENT,
                    418:        NFSERR_IO,
                    419:        NFSERR_ACCES,
                    420:        NFSERR_EXIST,
                    421:        NFSERR_NOTDIR,
                    422:        NFSERR_INVAL,
                    423:        NFSERR_ROFS,
                    424:        NFSERR_NAMETOL,
                    425:        NFSERR_NOTEMPTY,
                    426:        NFSERR_STALE,
                    427:        NFSERR_BADHANDLE,
                    428:        NFSERR_NOTSUPP,
                    429:        NFSERR_SERVERFAULT,
                    430:        0,
                    431: };
                    432:
1.90      jdolecek  433: static const short nfsv3err_rename[] = {
1.25      fvdl      434:        NFSERR_IO,
                    435:        NFSERR_NOENT,
                    436:        NFSERR_IO,
                    437:        NFSERR_ACCES,
                    438:        NFSERR_EXIST,
                    439:        NFSERR_XDEV,
                    440:        NFSERR_NOTDIR,
                    441:        NFSERR_ISDIR,
                    442:        NFSERR_INVAL,
                    443:        NFSERR_NOSPC,
                    444:        NFSERR_ROFS,
                    445:        NFSERR_MLINK,
                    446:        NFSERR_NAMETOL,
                    447:        NFSERR_NOTEMPTY,
                    448:        NFSERR_DQUOT,
                    449:        NFSERR_STALE,
                    450:        NFSERR_BADHANDLE,
                    451:        NFSERR_NOTSUPP,
                    452:        NFSERR_SERVERFAULT,
                    453:        0,
                    454: };
                    455:
1.90      jdolecek  456: static const short nfsv3err_link[] = {
1.25      fvdl      457:        NFSERR_IO,
                    458:        NFSERR_IO,
                    459:        NFSERR_ACCES,
                    460:        NFSERR_EXIST,
                    461:        NFSERR_XDEV,
                    462:        NFSERR_NOTDIR,
                    463:        NFSERR_INVAL,
                    464:        NFSERR_NOSPC,
                    465:        NFSERR_ROFS,
                    466:        NFSERR_MLINK,
                    467:        NFSERR_NAMETOL,
                    468:        NFSERR_DQUOT,
                    469:        NFSERR_STALE,
                    470:        NFSERR_BADHANDLE,
                    471:        NFSERR_NOTSUPP,
                    472:        NFSERR_SERVERFAULT,
                    473:        0,
                    474: };
                    475:
1.90      jdolecek  476: static const short nfsv3err_readdir[] = {
1.25      fvdl      477:        NFSERR_IO,
                    478:        NFSERR_IO,
                    479:        NFSERR_ACCES,
                    480:        NFSERR_NOTDIR,
                    481:        NFSERR_STALE,
                    482:        NFSERR_BADHANDLE,
                    483:        NFSERR_BAD_COOKIE,
                    484:        NFSERR_TOOSMALL,
                    485:        NFSERR_SERVERFAULT,
                    486:        0,
                    487: };
                    488:
1.90      jdolecek  489: static const short nfsv3err_readdirplus[] = {
1.25      fvdl      490:        NFSERR_IO,
                    491:        NFSERR_IO,
                    492:        NFSERR_ACCES,
                    493:        NFSERR_NOTDIR,
                    494:        NFSERR_STALE,
                    495:        NFSERR_BADHANDLE,
                    496:        NFSERR_BAD_COOKIE,
                    497:        NFSERR_NOTSUPP,
                    498:        NFSERR_TOOSMALL,
                    499:        NFSERR_SERVERFAULT,
                    500:        0,
                    501: };
                    502:
1.90      jdolecek  503: static const short nfsv3err_fsstat[] = {
1.25      fvdl      504:        NFSERR_IO,
                    505:        NFSERR_IO,
                    506:        NFSERR_STALE,
                    507:        NFSERR_BADHANDLE,
                    508:        NFSERR_SERVERFAULT,
                    509:        0,
                    510: };
                    511:
1.90      jdolecek  512: static const short nfsv3err_fsinfo[] = {
1.25      fvdl      513:        NFSERR_STALE,
                    514:        NFSERR_STALE,
                    515:        NFSERR_BADHANDLE,
                    516:        NFSERR_SERVERFAULT,
                    517:        0,
                    518: };
                    519:
1.90      jdolecek  520: static const short nfsv3err_pathconf[] = {
1.25      fvdl      521:        NFSERR_STALE,
                    522:        NFSERR_STALE,
                    523:        NFSERR_BADHANDLE,
                    524:        NFSERR_SERVERFAULT,
                    525:        0,
                    526: };
                    527:
1.90      jdolecek  528: static const short nfsv3err_commit[] = {
1.25      fvdl      529:        NFSERR_IO,
                    530:        NFSERR_IO,
                    531:        NFSERR_STALE,
                    532:        NFSERR_BADHANDLE,
                    533:        NFSERR_SERVERFAULT,
                    534:        0,
                    535: };
                    536:
1.90      jdolecek  537: static const short * const nfsrv_v3errmap[] = {
1.25      fvdl      538:        nfsv3err_null,
                    539:        nfsv3err_getattr,
                    540:        nfsv3err_setattr,
                    541:        nfsv3err_lookup,
                    542:        nfsv3err_access,
                    543:        nfsv3err_readlink,
                    544:        nfsv3err_read,
                    545:        nfsv3err_write,
                    546:        nfsv3err_create,
                    547:        nfsv3err_mkdir,
                    548:        nfsv3err_symlink,
                    549:        nfsv3err_mknod,
                    550:        nfsv3err_remove,
                    551:        nfsv3err_rmdir,
                    552:        nfsv3err_rename,
                    553:        nfsv3err_link,
                    554:        nfsv3err_readdir,
                    555:        nfsv3err_readdirplus,
                    556:        nfsv3err_fsstat,
                    557:        nfsv3err_fsinfo,
                    558:        nfsv3err_pathconf,
                    559:        nfsv3err_commit,
                    560: };
                    561:
1.12      mycroft   562: extern struct nfsrtt nfsrtt;
1.1       cgd       563:
1.46      fvdl      564: u_long nfsdirhashmask;
1.18      mycroft   565:
1.201.4.3  yamt      566: int nfs_webnamei(struct nameidata *, struct vnode *, struct proc *);
1.43      fvdl      567:
1.1       cgd       568: /*
                    569:  * Create the header for an rpc request packet
                    570:  * The hsiz is the size of the rest of the nfs request header.
                    571:  * (just used to decide if a cluster is a good idea)
                    572:  */
1.12      mycroft   573: struct mbuf *
1.183     christos  574: nfsm_reqh(struct nfsnode *np, u_long procid, int hsiz, char **bposp)
1.12      mycroft   575: {
1.75      augustss  576:        struct mbuf *mb;
1.183     christos  577:        char *bpos;
1.12      mycroft   578:
1.109     matt      579:        mb = m_get(M_WAIT, MT_DATA);
                    580:        MCLAIM(mb, &nfs_mowner);
1.12      mycroft   581:        if (hsiz >= MINCLSIZE)
1.109     matt      582:                m_clget(mb, M_WAIT);
1.12      mycroft   583:        mb->m_len = 0;
1.183     christos  584:        bpos = mtod(mb, void *);
1.148     perry     585:
1.12      mycroft   586:        /* Finally, return values */
                    587:        *bposp = bpos;
                    588:        return (mb);
                    589: }
                    590:
                    591: /*
                    592:  * Build the RPC header and fill in the authorization info.
                    593:  * The authorization string argument is only used when the credentials
                    594:  * come from outside of the kernel.
                    595:  * Returns the head of the mbuf list.
                    596:  */
                    597: struct mbuf *
1.201.4.3  yamt      598: nfsm_rpchead(kauth_cred_t cr, int nmflag, int procid,
                    599:        int auth_type, int auth_len, char *auth_str, int verf_len,
                    600:        char *verf_str, struct mbuf *mrest, int mrest_len,
                    601:        struct mbuf **mbp, uint32_t *xidp)
1.1       cgd       602: {
1.75      augustss  603:        struct mbuf *mb;
                    604:        u_int32_t *tl;
1.183     christos  605:        char *bpos;
1.75      augustss  606:        int i;
1.109     matt      607:        struct mbuf *mreq;
1.12      mycroft   608:        int siz, grpsiz, authsiz;
1.1       cgd       609:
1.12      mycroft   610:        authsiz = nfsm_rndup(auth_len);
1.109     matt      611:        mb = m_gethdr(M_WAIT, MT_DATA);
                    612:        MCLAIM(mb, &nfs_mowner);
1.25      fvdl      613:        if ((authsiz + 10 * NFSX_UNSIGNED) >= MINCLSIZE) {
1.109     matt      614:                m_clget(mb, M_WAIT);
1.25      fvdl      615:        } else if ((authsiz + 10 * NFSX_UNSIGNED) < MHLEN) {
                    616:                MH_ALIGN(mb, authsiz + 10 * NFSX_UNSIGNED);
1.12      mycroft   617:        } else {
1.25      fvdl      618:                MH_ALIGN(mb, 8 * NFSX_UNSIGNED);
1.1       cgd       619:        }
1.12      mycroft   620:        mb->m_len = 0;
                    621:        mreq = mb;
1.183     christos  622:        bpos = mtod(mb, void *);
1.12      mycroft   623:
                    624:        /*
                    625:         * First the RPC header.
                    626:         */
1.25      fvdl      627:        nfsm_build(tl, u_int32_t *, 8 * NFSX_UNSIGNED);
1.30      fvdl      628:
1.126     yamt      629:        *tl++ = *xidp = nfs_getxid();
1.1       cgd       630:        *tl++ = rpc_call;
                    631:        *tl++ = rpc_vers;
1.179     yamt      632:        *tl++ = txdr_unsigned(NFS_PROG);
                    633:        if (nmflag & NFSMNT_NFSV3)
                    634:                *tl++ = txdr_unsigned(NFS_VER3);
                    635:        else
                    636:                *tl++ = txdr_unsigned(NFS_VER2);
1.25      fvdl      637:        if (nmflag & NFSMNT_NFSV3)
                    638:                *tl++ = txdr_unsigned(procid);
                    639:        else
                    640:                *tl++ = txdr_unsigned(nfsv2_procid[procid]);
1.12      mycroft   641:
                    642:        /*
                    643:         * And then the authorization cred.
                    644:         */
                    645:        *tl++ = txdr_unsigned(auth_type);
                    646:        *tl = txdr_unsigned(authsiz);
                    647:        switch (auth_type) {
                    648:        case RPCAUTH_UNIX:
1.22      cgd       649:                nfsm_build(tl, u_int32_t *, auth_len);
1.12      mycroft   650:                *tl++ = 0;              /* stamp ?? */
                    651:                *tl++ = 0;              /* NULL hostname */
1.162     elad      652:                *tl++ = txdr_unsigned(kauth_cred_geteuid(cr));
                    653:                *tl++ = txdr_unsigned(kauth_cred_getegid(cr));
1.12      mycroft   654:                grpsiz = (auth_len >> 2) - 5;
                    655:                *tl++ = txdr_unsigned(grpsiz);
1.20      mycroft   656:                for (i = 0; i < grpsiz; i++)
1.162     elad      657:                        *tl++ = txdr_unsigned(kauth_cred_group(cr, i)); /* XXX elad review */
1.12      mycroft   658:                break;
1.25      fvdl      659:        case RPCAUTH_KERB4:
1.12      mycroft   660:                siz = auth_len;
                    661:                while (siz > 0) {
                    662:                        if (M_TRAILINGSPACE(mb) == 0) {
1.109     matt      663:                                struct mbuf *mb2;
                    664:                                mb2 = m_get(M_WAIT, MT_DATA);
                    665:                                MCLAIM(mb2, &nfs_mowner);
1.12      mycroft   666:                                if (siz >= MINCLSIZE)
1.109     matt      667:                                        m_clget(mb2, M_WAIT);
1.12      mycroft   668:                                mb->m_next = mb2;
                    669:                                mb = mb2;
                    670:                                mb->m_len = 0;
1.183     christos  671:                                bpos = mtod(mb, void *);
1.12      mycroft   672:                        }
                    673:                        i = min(siz, M_TRAILINGSPACE(mb));
1.63      perry     674:                        memcpy(bpos, auth_str, i);
1.12      mycroft   675:                        mb->m_len += i;
                    676:                        auth_str += i;
                    677:                        bpos += i;
                    678:                        siz -= i;
                    679:                }
                    680:                if ((siz = (nfsm_rndup(auth_len) - auth_len)) > 0) {
                    681:                        for (i = 0; i < siz; i++)
                    682:                                *bpos++ = '\0';
                    683:                        mb->m_len += siz;
                    684:                }
                    685:                break;
                    686:        };
1.25      fvdl      687:
                    688:        /*
                    689:         * And the verifier...
                    690:         */
                    691:        nfsm_build(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
                    692:        if (verf_str) {
                    693:                *tl++ = txdr_unsigned(RPCAUTH_KERB4);
                    694:                *tl = txdr_unsigned(verf_len);
                    695:                siz = verf_len;
                    696:                while (siz > 0) {
                    697:                        if (M_TRAILINGSPACE(mb) == 0) {
1.109     matt      698:                                struct mbuf *mb2;
                    699:                                mb2 = m_get(M_WAIT, MT_DATA);
                    700:                                MCLAIM(mb2, &nfs_mowner);
1.25      fvdl      701:                                if (siz >= MINCLSIZE)
1.109     matt      702:                                        m_clget(mb2, M_WAIT);
1.25      fvdl      703:                                mb->m_next = mb2;
                    704:                                mb = mb2;
                    705:                                mb->m_len = 0;
1.183     christos  706:                                bpos = mtod(mb, void *);
1.25      fvdl      707:                        }
                    708:                        i = min(siz, M_TRAILINGSPACE(mb));
1.63      perry     709:                        memcpy(bpos, verf_str, i);
1.25      fvdl      710:                        mb->m_len += i;
                    711:                        verf_str += i;
                    712:                        bpos += i;
                    713:                        siz -= i;
                    714:                }
                    715:                if ((siz = (nfsm_rndup(verf_len) - verf_len)) > 0) {
                    716:                        for (i = 0; i < siz; i++)
                    717:                                *bpos++ = '\0';
                    718:                        mb->m_len += siz;
                    719:                }
                    720:        } else {
                    721:                *tl++ = txdr_unsigned(RPCAUTH_NULL);
                    722:                *tl = 0;
                    723:        }
1.12      mycroft   724:        mb->m_next = mrest;
1.25      fvdl      725:        mreq->m_pkthdr.len = authsiz + 10 * NFSX_UNSIGNED + mrest_len;
1.12      mycroft   726:        mreq->m_pkthdr.rcvif = (struct ifnet *)0;
                    727:        *mbp = mb;
1.1       cgd       728:        return (mreq);
                    729: }
                    730:
                    731: /*
                    732:  * copies mbuf chain to the uio scatter/gather list
                    733:  */
1.24      christos  734: int
1.201.4.3  yamt      735: nfsm_mbuftouio(struct mbuf **mrep, struct uio *uiop, int siz, char **dpos)
1.1       cgd       736: {
1.75      augustss  737:        char *mbufcp, *uiocp;
                    738:        int xfer, left, len;
                    739:        struct mbuf *mp;
1.1       cgd       740:        long uiosiz, rem;
                    741:        int error = 0;
                    742:
                    743:        mp = *mrep;
                    744:        mbufcp = *dpos;
1.183     christos  745:        len = mtod(mp, char *) + mp->m_len - mbufcp;
1.1       cgd       746:        rem = nfsm_rndup(siz)-siz;
                    747:        while (siz > 0) {
                    748:                if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL)
                    749:                        return (EFBIG);
                    750:                left = uiop->uio_iov->iov_len;
                    751:                uiocp = uiop->uio_iov->iov_base;
                    752:                if (left > siz)
                    753:                        left = siz;
                    754:                uiosiz = left;
                    755:                while (left > 0) {
                    756:                        while (len == 0) {
                    757:                                mp = mp->m_next;
                    758:                                if (mp == NULL)
                    759:                                        return (EBADRPC);
1.183     christos  760:                                mbufcp = mtod(mp, void *);
1.1       cgd       761:                                len = mp->m_len;
                    762:                        }
                    763:                        xfer = (left > len) ? len : left;
1.158     yamt      764:                        error = copyout_vmspace(uiop->uio_vmspace, mbufcp,
                    765:                            uiocp, xfer);
                    766:                        if (error) {
                    767:                                return error;
                    768:                        }
1.1       cgd       769:                        left -= xfer;
                    770:                        len -= xfer;
                    771:                        mbufcp += xfer;
                    772:                        uiocp += xfer;
                    773:                        uiop->uio_offset += xfer;
                    774:                        uiop->uio_resid -= xfer;
                    775:                }
                    776:                if (uiop->uio_iov->iov_len <= siz) {
                    777:                        uiop->uio_iovcnt--;
                    778:                        uiop->uio_iov++;
                    779:                } else {
1.95      lukem     780:                        uiop->uio_iov->iov_base =
1.183     christos  781:                            (char *)uiop->uio_iov->iov_base + uiosiz;
1.1       cgd       782:                        uiop->uio_iov->iov_len -= uiosiz;
                    783:                }
                    784:                siz -= uiosiz;
                    785:        }
                    786:        *dpos = mbufcp;
                    787:        *mrep = mp;
                    788:        if (rem > 0) {
                    789:                if (len < rem)
                    790:                        error = nfs_adv(mrep, dpos, rem, len);
                    791:                else
                    792:                        *dpos += rem;
                    793:        }
                    794:        return (error);
                    795: }
                    796:
                    797: /*
1.29      fvdl      798:  * copies a uio scatter/gather list to an mbuf chain.
                    799:  * NOTE: can ony handle iovcnt == 1
1.1       cgd       800:  */
1.24      christos  801: int
1.201.4.3  yamt      802: nfsm_uiotombuf(struct uio *uiop, struct mbuf **mq, int siz, char **bpos)
1.1       cgd       803: {
1.75      augustss  804:        char *uiocp;
                    805:        struct mbuf *mp, *mp2;
                    806:        int xfer, left, mlen;
1.1       cgd       807:        int uiosiz, clflg, rem;
                    808:        char *cp;
1.158     yamt      809:        int error;
1.1       cgd       810:
1.29      fvdl      811: #ifdef DIAGNOSTIC
                    812:        if (uiop->uio_iovcnt != 1)
                    813:                panic("nfsm_uiotombuf: iovcnt != 1");
                    814: #endif
                    815:
1.1       cgd       816:        if (siz > MLEN)         /* or should it >= MCLBYTES ?? */
                    817:                clflg = 1;
                    818:        else
                    819:                clflg = 0;
                    820:        rem = nfsm_rndup(siz)-siz;
1.12      mycroft   821:        mp = mp2 = *mq;
1.1       cgd       822:        while (siz > 0) {
                    823:                left = uiop->uio_iov->iov_len;
                    824:                uiocp = uiop->uio_iov->iov_base;
                    825:                if (left > siz)
                    826:                        left = siz;
                    827:                uiosiz = left;
                    828:                while (left > 0) {
1.12      mycroft   829:                        mlen = M_TRAILINGSPACE(mp);
                    830:                        if (mlen == 0) {
1.109     matt      831:                                mp = m_get(M_WAIT, MT_DATA);
                    832:                                MCLAIM(mp, &nfs_mowner);
1.12      mycroft   833:                                if (clflg)
1.109     matt      834:                                        m_clget(mp, M_WAIT);
1.12      mycroft   835:                                mp->m_len = 0;
                    836:                                mp2->m_next = mp;
                    837:                                mp2 = mp;
                    838:                                mlen = M_TRAILINGSPACE(mp);
                    839:                        }
                    840:                        xfer = (left > mlen) ? mlen : left;
1.183     christos  841:                        cp = mtod(mp, char *) + mp->m_len;
1.158     yamt      842:                        error = copyin_vmspace(uiop->uio_vmspace, uiocp, cp,
                    843:                            xfer);
                    844:                        if (error) {
                    845:                                /* XXX */
                    846:                        }
1.12      mycroft   847:                        mp->m_len += xfer;
1.1       cgd       848:                        left -= xfer;
                    849:                        uiocp += xfer;
                    850:                        uiop->uio_offset += xfer;
                    851:                        uiop->uio_resid -= xfer;
                    852:                }
1.183     christos  853:                uiop->uio_iov->iov_base = (char *)uiop->uio_iov->iov_base +
1.95      lukem     854:                    uiosiz;
1.29      fvdl      855:                uiop->uio_iov->iov_len -= uiosiz;
1.1       cgd       856:                siz -= uiosiz;
                    857:        }
                    858:        if (rem > 0) {
1.12      mycroft   859:                if (rem > M_TRAILINGSPACE(mp)) {
1.109     matt      860:                        mp = m_get(M_WAIT, MT_DATA);
                    861:                        MCLAIM(mp, &nfs_mowner);
1.1       cgd       862:                        mp->m_len = 0;
                    863:                        mp2->m_next = mp;
                    864:                }
1.183     christos  865:                cp = mtod(mp, char *) + mp->m_len;
1.1       cgd       866:                for (left = 0; left < rem; left++)
                    867:                        *cp++ = '\0';
                    868:                mp->m_len += rem;
                    869:                *bpos = cp;
                    870:        } else
1.183     christos  871:                *bpos = mtod(mp, char *) + mp->m_len;
1.1       cgd       872:        *mq = mp;
                    873:        return (0);
                    874: }
                    875:
                    876: /*
1.39      fvdl      877:  * Get at least "siz" bytes of correctly aligned data.
                    878:  * When called the mbuf pointers are not necessarily correct,
                    879:  * dsosp points to what ought to be in m_data and left contains
1.148     perry     880:  * what ought to be in m_len.
1.12      mycroft   881:  * This is used by the macros nfsm_dissect and nfsm_dissecton for tough
1.1       cgd       882:  * cases. (The macros use the vars. dpos and dpos2)
                    883:  */
1.24      christos  884: int
1.201.4.3  yamt      885: nfsm_disct(struct mbuf **mdp, char **dposp, int siz, int left, char **cp2)
1.1       cgd       886: {
1.75      augustss  887:        struct mbuf *m1, *m2;
1.39      fvdl      888:        struct mbuf *havebuf = NULL;
1.183     christos  889:        char *src = *dposp;
                    890:        char *dst;
1.39      fvdl      891:        int len;
                    892:
                    893: #ifdef DEBUG
                    894:        if (left < 0)
1.148     perry     895:                panic("nfsm_disct: left < 0");
1.39      fvdl      896: #endif
                    897:        m1 = *mdp;
                    898:        /*
                    899:         * Skip through the mbuf chain looking for an mbuf with
                    900:         * some data. If the first mbuf found has enough data
                    901:         * and it is correctly aligned return it.
                    902:         */
1.1       cgd       903:        while (left == 0) {
1.39      fvdl      904:                havebuf = m1;
                    905:                *mdp = m1 = m1->m_next;
                    906:                if (m1 == NULL)
1.1       cgd       907:                        return (EBADRPC);
1.183     christos  908:                src = mtod(m1, void *);
1.39      fvdl      909:                left = m1->m_len;
                    910:                /*
                    911:                 * If we start a new mbuf and it is big enough
                    912:                 * and correctly aligned just return it, don't
                    913:                 * do any pull up.
                    914:                 */
                    915:                if (left >= siz && nfsm_aligned(src)) {
                    916:                        *cp2 = src;
                    917:                        *dposp = src + siz;
                    918:                        return (0);
                    919:                }
1.1       cgd       920:        }
1.201     yamt      921:        if ((m1->m_flags & M_EXT) != 0) {
                    922:                if (havebuf && M_TRAILINGSPACE(havebuf) >= siz &&
                    923:                    nfsm_aligned(mtod(havebuf, char *) + havebuf->m_len)) {
                    924:                        /*
                    925:                         * If the first mbuf with data has external data
                    926:                         * and there is a previous mbuf with some trailing
                    927:                         * space, use it to move the data into.
1.39      fvdl      928:                         */
                    929:                        m2 = m1;
                    930:                        *mdp = m1 = havebuf;
1.201     yamt      931:                        *cp2 = mtod(m1, char *) + m1->m_len;
                    932:                } else if (havebuf) {
1.39      fvdl      933:                        /*
                    934:                         * If the first mbuf has a external data
                    935:                         * and there is no previous empty mbuf
                    936:                         * allocate a new mbuf and move the external
1.148     perry     937:                         * data to the new mbuf. Also make the first
1.39      fvdl      938:                         * mbuf look empty.
                    939:                         */
1.201     yamt      940:                        m2 = m1;
                    941:                        *mdp = m1 = m_get(M_WAIT, MT_DATA);
                    942:                        MCLAIM(m1, m2->m_owner);
                    943:                        if ((m2->m_flags & M_PKTHDR) != 0) {
                    944:                                /* XXX MOVE */
                    945:                                M_COPY_PKTHDR(m1, m2);
                    946:                                m_tag_delete_chain(m2, NULL);
                    947:                                m2->m_flags &= ~M_PKTHDR;
                    948:                        }
                    949:                        if (havebuf) {
                    950:                                havebuf->m_next = m1;
                    951:                        }
                    952:                        m1->m_next = m2;
                    953:                        MRESETDATA(m1);
                    954:                        m1->m_len = 0;
1.39      fvdl      955:                        m2->m_data = src;
                    956:                        m2->m_len = left;
1.201     yamt      957:                        *cp2 = mtod(m1, char *);
                    958:                } else {
                    959:                        struct mbuf **nextp = &m1->m_next;
                    960:
                    961:                        m1->m_len -= left;
                    962:                        do {
                    963:                                m2 = m_get(M_WAIT, MT_DATA);
                    964:                                MCLAIM(m2, m1->m_owner);
                    965:                                if (left >= MINCLSIZE) {
                    966:                                        MCLGET(m2, M_WAIT);
                    967:                                }
                    968:                                m2->m_next = *nextp;
                    969:                                *nextp = m2;
                    970:                                nextp = &m2->m_next;
                    971:                                len = (m2->m_flags & M_EXT) != 0 ?
                    972:                                    MCLBYTES : MLEN;
                    973:                                if (len > left) {
                    974:                                        len = left;
                    975:                                }
                    976:                                memcpy(mtod(m2, char *), src, len);
                    977:                                m2->m_len = len;
                    978:                                src += len;
                    979:                                left -= len;
                    980:                        } while (left > 0);
                    981:                        *mdp = m1 = m1->m_next;
                    982:                        m2 = m1->m_next;
                    983:                        *cp2 = mtod(m1, char *);
1.1       cgd       984:                }
1.39      fvdl      985:        } else {
                    986:                /*
                    987:                 * If the first mbuf has no external data
                    988:                 * move the data to the front of the mbuf.
                    989:                 */
1.201     yamt      990:                MRESETDATA(m1);
                    991:                dst = mtod(m1, char *);
                    992:                if (dst != src) {
1.63      perry     993:                        memmove(dst, src, left);
1.201     yamt      994:                }
1.39      fvdl      995:                m1->m_len = left;
                    996:                m2 = m1->m_next;
1.201     yamt      997:                *cp2 = m1->m_data;
1.1       cgd       998:        }
1.201     yamt      999:        *dposp = *cp2 + siz;
1.39      fvdl     1000:        /*
                   1001:         * Loop through mbufs pulling data up into first mbuf until
                   1002:         * the first mbuf is full or there is no more data to
                   1003:         * pullup.
                   1004:         */
1.201     yamt     1005:        dst = mtod(m1, char *) + m1->m_len;
1.129     itojun   1006:        while ((len = M_TRAILINGSPACE(m1)) != 0 && m2) {
1.201     yamt     1007:                if ((len = min(len, m2->m_len)) != 0) {
                   1008:                        memcpy(dst, mtod(m2, char *), len);
                   1009:                }
1.39      fvdl     1010:                m1->m_len += len;
                   1011:                dst += len;
                   1012:                m2->m_data += len;
                   1013:                m2->m_len -= len;
                   1014:                m2 = m2->m_next;
                   1015:        }
                   1016:        if (m1->m_len < siz)
                   1017:                return (EBADRPC);
1.1       cgd      1018:        return (0);
                   1019: }
                   1020:
                   1021: /*
                   1022:  * Advance the position in the mbuf chain.
                   1023:  */
1.24      christos 1024: int
1.201.4.3  yamt     1025: nfs_adv(struct mbuf **mdp, char **dposp, int offs, int left)
1.1       cgd      1026: {
1.75      augustss 1027:        struct mbuf *m;
                   1028:        int s;
1.1       cgd      1029:
                   1030:        m = *mdp;
                   1031:        s = left;
                   1032:        while (s < offs) {
                   1033:                offs -= s;
                   1034:                m = m->m_next;
                   1035:                if (m == NULL)
                   1036:                        return (EBADRPC);
                   1037:                s = m->m_len;
                   1038:        }
                   1039:        *mdp = m;
1.183     christos 1040:        *dposp = mtod(m, char *) + offs;
1.1       cgd      1041:        return (0);
                   1042: }
                   1043:
                   1044: /*
                   1045:  * Copy a string into mbufs for the hard cases...
                   1046:  */
1.24      christos 1047: int
1.201.4.3  yamt     1048: nfsm_strtmbuf(struct mbuf **mb, char **bpos, const char *cp, long siz)
1.1       cgd      1049: {
1.75      augustss 1050:        struct mbuf *m1 = NULL, *m2;
1.1       cgd      1051:        long left, xfer, len, tlen;
1.22      cgd      1052:        u_int32_t *tl;
1.1       cgd      1053:        int putsize;
                   1054:
                   1055:        putsize = 1;
                   1056:        m2 = *mb;
1.12      mycroft  1057:        left = M_TRAILINGSPACE(m2);
1.1       cgd      1058:        if (left > 0) {
1.22      cgd      1059:                tl = ((u_int32_t *)(*bpos));
1.1       cgd      1060:                *tl++ = txdr_unsigned(siz);
                   1061:                putsize = 0;
                   1062:                left -= NFSX_UNSIGNED;
                   1063:                m2->m_len += NFSX_UNSIGNED;
                   1064:                if (left > 0) {
1.183     christos 1065:                        memcpy((void *) tl, cp, left);
1.1       cgd      1066:                        siz -= left;
                   1067:                        cp += left;
                   1068:                        m2->m_len += left;
                   1069:                        left = 0;
                   1070:                }
                   1071:        }
1.12      mycroft  1072:        /* Loop around adding mbufs */
1.1       cgd      1073:        while (siz > 0) {
1.109     matt     1074:                m1 = m_get(M_WAIT, MT_DATA);
                   1075:                MCLAIM(m1, &nfs_mowner);
1.1       cgd      1076:                if (siz > MLEN)
1.109     matt     1077:                        m_clget(m1, M_WAIT);
1.1       cgd      1078:                m1->m_len = NFSMSIZ(m1);
                   1079:                m2->m_next = m1;
                   1080:                m2 = m1;
1.22      cgd      1081:                tl = mtod(m1, u_int32_t *);
1.1       cgd      1082:                tlen = 0;
                   1083:                if (putsize) {
                   1084:                        *tl++ = txdr_unsigned(siz);
                   1085:                        m1->m_len -= NFSX_UNSIGNED;
                   1086:                        tlen = NFSX_UNSIGNED;
                   1087:                        putsize = 0;
                   1088:                }
                   1089:                if (siz < m1->m_len) {
                   1090:                        len = nfsm_rndup(siz);
                   1091:                        xfer = siz;
                   1092:                        if (xfer < len)
                   1093:                                *(tl+(xfer>>2)) = 0;
                   1094:                } else {
                   1095:                        xfer = len = m1->m_len;
                   1096:                }
1.183     christos 1097:                memcpy((void *) tl, cp, xfer);
1.1       cgd      1098:                m1->m_len = len+tlen;
                   1099:                siz -= xfer;
                   1100:                cp += xfer;
                   1101:        }
                   1102:        *mb = m1;
1.183     christos 1103:        *bpos = mtod(m1, char *) + m1->m_len;
1.1       cgd      1104:        return (0);
                   1105: }
                   1106:
1.49      fvdl     1107: /*
                   1108:  * Directory caching routines. They work as follows:
                   1109:  * - a cache is maintained per VDIR nfsnode.
                   1110:  * - for each offset cookie that is exported to userspace, and can
                   1111:  *   thus be thrown back at us as an offset to VOP_READDIR, store
                   1112:  *   information in the cache.
                   1113:  * - cached are:
                   1114:  *   - cookie itself
                   1115:  *   - blocknumber (essentially just a search key in the buffer cache)
                   1116:  *   - entry number in block.
                   1117:  *   - offset cookie of block in which this entry is stored
                   1118:  *   - 32 bit cookie if NFSMNT_XLATECOOKIE is used.
                   1119:  * - entries are looked up in a hash table
                   1120:  * - also maintained is an LRU list of entries, used to determine
                   1121:  *   which ones to delete if the cache grows too large.
                   1122:  * - if 32 <-> 64 translation mode is requested for a filesystem,
                   1123:  *   the cache also functions as a translation table
                   1124:  * - in the translation case, invalidating the cache does not mean
                   1125:  *   flushing it, but just marking entries as invalid, except for
                   1126:  *   the <64bit cookie, 32bitcookie> pair which is still valid, to
                   1127:  *   still be able to use the cache as a translation table.
                   1128:  * - 32 bit cookies are uniquely created by combining the hash table
                   1129:  *   entry value, and one generation count per hash table entry,
                   1130:  *   incremented each time an entry is appended to the chain.
                   1131:  * - the cache is invalidated each time a direcory is modified
                   1132:  * - sanity checks are also done; if an entry in a block turns
                   1133:  *   out not to have a matching cookie, the cache is invalidated
                   1134:  *   and a new block starting from the wanted offset is fetched from
                   1135:  *   the server.
                   1136:  * - directory entries as read from the server are extended to contain
                   1137:  *   the 64bit and, optionally, the 32bit cookies, for sanity checking
                   1138:  *   the cache and exporting them to userspace through the cookie
                   1139:  *   argument to VOP_READDIR.
                   1140:  */
                   1141:
1.46      fvdl     1142: u_long
1.201.4.3  yamt     1143: nfs_dirhash(off_t off)
1.46      fvdl     1144: {
                   1145:        int i;
                   1146:        char *cp = (char *)&off;
                   1147:        u_long sum = 0L;
                   1148:
                   1149:        for (i = 0 ; i < sizeof (off); i++)
                   1150:                sum += *cp++;
                   1151:
                   1152:        return sum;
                   1153: }
                   1154:
1.135     yamt     1155: #define        _NFSDC_MTX(np)          (&NFSTOV(np)->v_interlock)
1.195     ad       1156: #define        NFSDC_LOCK(np)          mutex_enter(_NFSDC_MTX(np))
                   1157: #define        NFSDC_UNLOCK(np)        mutex_exit(_NFSDC_MTX(np))
                   1158: #define        NFSDC_ASSERT_LOCKED(np) KASSERT(mutex_owned(_NFSDC_MTX(np)))
1.135     yamt     1159:
1.49      fvdl     1160: void
1.201.4.3  yamt     1161: nfs_initdircache(struct vnode *vp)
1.49      fvdl     1162: {
                   1163:        struct nfsnode *np = VTONFS(vp);
1.135     yamt     1164:        struct nfsdirhashhead *dircache;
1.120     yamt     1165:
1.201.4.2  yamt     1166:        dircache = hashinit(NFS_DIRHASHSIZ, HASH_LIST, true,
                   1167:            &nfsdirhashmask);
1.49      fvdl     1168:
1.135     yamt     1169:        NFSDC_LOCK(np);
                   1170:        if (np->n_dircache == NULL) {
                   1171:                np->n_dircachesize = 0;
                   1172:                np->n_dircache = dircache;
                   1173:                dircache = NULL;
                   1174:                TAILQ_INIT(&np->n_dirchain);
                   1175:        }
                   1176:        NFSDC_UNLOCK(np);
                   1177:        if (dircache)
1.201.4.2  yamt     1178:                hashdone(dircache, HASH_LIST, nfsdirhashmask);
1.120     yamt     1179: }
                   1180:
                   1181: void
1.201.4.3  yamt     1182: nfs_initdirxlatecookie(struct vnode *vp)
1.120     yamt     1183: {
                   1184:        struct nfsnode *np = VTONFS(vp);
1.135     yamt     1185:        unsigned *dirgens;
1.120     yamt     1186:
                   1187:        KASSERT(VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_XLATECOOKIE);
                   1188:
1.196     yamt     1189:        dirgens = kmem_zalloc(NFS_DIRHASHSIZ * sizeof(unsigned), KM_SLEEP);
1.135     yamt     1190:        NFSDC_LOCK(np);
                   1191:        if (np->n_dirgens == NULL) {
                   1192:                np->n_dirgens = dirgens;
                   1193:                dirgens = NULL;
                   1194:        }
                   1195:        NFSDC_UNLOCK(np);
                   1196:        if (dirgens)
1.196     yamt     1197:                kmem_free(dirgens, NFS_DIRHASHSIZ * sizeof(unsigned));
1.135     yamt     1198: }
                   1199:
                   1200: static const struct nfsdircache dzero;
                   1201:
1.201.4.3  yamt     1202: static void nfs_unlinkdircache(struct nfsnode *np, struct nfsdircache *);
                   1203: static void nfs_putdircache_unlocked(struct nfsnode *,
                   1204:     struct nfsdircache *);
1.135     yamt     1205:
                   1206: static void
1.201.4.3  yamt     1207: nfs_unlinkdircache(struct nfsnode *np, struct nfsdircache *ndp)
1.135     yamt     1208: {
                   1209:
                   1210:        NFSDC_ASSERT_LOCKED(np);
                   1211:        KASSERT(ndp != &dzero);
                   1212:
                   1213:        if (LIST_NEXT(ndp, dc_hash) == (void *)-1)
                   1214:                return;
                   1215:
                   1216:        TAILQ_REMOVE(&np->n_dirchain, ndp, dc_chain);
                   1217:        LIST_REMOVE(ndp, dc_hash);
                   1218:        LIST_NEXT(ndp, dc_hash) = (void *)-1; /* mark as unlinked */
                   1219:
                   1220:        nfs_putdircache_unlocked(np, ndp);
                   1221: }
                   1222:
                   1223: void
1.201.4.3  yamt     1224: nfs_putdircache(struct nfsnode *np, struct nfsdircache *ndp)
1.135     yamt     1225: {
                   1226:        int ref;
                   1227:
                   1228:        if (ndp == &dzero)
                   1229:                return;
                   1230:
                   1231:        KASSERT(ndp->dc_refcnt > 0);
                   1232:        NFSDC_LOCK(np);
                   1233:        ref = --ndp->dc_refcnt;
                   1234:        NFSDC_UNLOCK(np);
                   1235:
                   1236:        if (ref == 0)
1.196     yamt     1237:                kmem_free(ndp, sizeof(*ndp));
1.49      fvdl     1238: }
                   1239:
1.135     yamt     1240: static void
1.177     yamt     1241: nfs_putdircache_unlocked(struct nfsnode *np, struct nfsdircache *ndp)
1.135     yamt     1242: {
                   1243:        int ref;
                   1244:
                   1245:        NFSDC_ASSERT_LOCKED(np);
                   1246:
                   1247:        if (ndp == &dzero)
                   1248:                return;
                   1249:
                   1250:        KASSERT(ndp->dc_refcnt > 0);
                   1251:        ref = --ndp->dc_refcnt;
                   1252:        if (ref == 0)
1.196     yamt     1253:                kmem_free(ndp, sizeof(*ndp));
1.135     yamt     1254: }
1.46      fvdl     1255:
                   1256: struct nfsdircache *
1.201.4.3  yamt     1257: nfs_searchdircache(struct vnode *vp, off_t off, int do32, int *hashent)
1.49      fvdl     1258: {
                   1259:        struct nfsdirhashhead *ndhp;
                   1260:        struct nfsdircache *ndp = NULL;
                   1261:        struct nfsnode *np = VTONFS(vp);
                   1262:        unsigned ent;
                   1263:
                   1264:        /*
                   1265:         * Zero is always a valid cookie.
                   1266:         */
                   1267:        if (off == 0)
1.149     christos 1268:                /* XXXUNCONST */
                   1269:                return (struct nfsdircache *)__UNCONST(&dzero);
1.49      fvdl     1270:
1.134     yamt     1271:        if (!np->n_dircache)
                   1272:                return NULL;
                   1273:
1.49      fvdl     1274:        /*
                   1275:         * We use a 32bit cookie as search key, directly reconstruct
                   1276:         * the hashentry. Else use the hashfunction.
                   1277:         */
                   1278:        if (do32) {
                   1279:                ent = (u_int32_t)off >> 24;
                   1280:                if (ent >= NFS_DIRHASHSIZ)
                   1281:                        return NULL;
                   1282:                ndhp = &np->n_dircache[ent];
                   1283:        } else {
                   1284:                ndhp = NFSDIRHASH(np, off);
                   1285:        }
                   1286:
                   1287:        if (hashent)
                   1288:                *hashent = (int)(ndhp - np->n_dircache);
1.135     yamt     1289:
                   1290:        NFSDC_LOCK(np);
1.49      fvdl     1291:        if (do32) {
1.113     yamt     1292:                LIST_FOREACH(ndp, ndhp, dc_hash) {
1.49      fvdl     1293:                        if (ndp->dc_cookie32 == (u_int32_t)off) {
                   1294:                                /*
                   1295:                                 * An invalidated entry will become the
                   1296:                                 * start of a new block fetched from
                   1297:                                 * the server.
                   1298:                                 */
1.135     yamt     1299:                                if (ndp->dc_flags & NFSDC_INVALID) {
1.49      fvdl     1300:                                        ndp->dc_blkcookie = ndp->dc_cookie;
                   1301:                                        ndp->dc_entry = 0;
1.135     yamt     1302:                                        ndp->dc_flags &= ~NFSDC_INVALID;
1.49      fvdl     1303:                                }
                   1304:                                break;
                   1305:                        }
                   1306:                }
                   1307:        } else {
1.113     yamt     1308:                LIST_FOREACH(ndp, ndhp, dc_hash) {
1.49      fvdl     1309:                        if (ndp->dc_cookie == off)
                   1310:                                break;
1.113     yamt     1311:                }
1.49      fvdl     1312:        }
1.135     yamt     1313:        if (ndp != NULL)
                   1314:                ndp->dc_refcnt++;
                   1315:        NFSDC_UNLOCK(np);
1.49      fvdl     1316:        return ndp;
                   1317: }
                   1318:
                   1319:
                   1320: struct nfsdircache *
1.171     christos 1321: nfs_enterdircache(struct vnode *vp, off_t off, off_t blkoff, int en,
1.177     yamt     1322:     daddr_t blkno)
1.46      fvdl     1323: {
                   1324:        struct nfsnode *np = VTONFS(vp);
                   1325:        struct nfsdirhashhead *ndhp;
1.135     yamt     1326:        struct nfsdircache *ndp = NULL;
                   1327:        struct nfsdircache *newndp = NULL;
1.49      fvdl     1328:        struct nfsmount *nmp = VFSTONFS(vp->v_mount);
1.161     christos 1329:        int hashent = 0, gen, overwrite;        /* XXX: GCC */
1.46      fvdl     1330:
1.135     yamt     1331:        /*
                   1332:         * XXX refuse entries for offset 0. amd(8) erroneously sets
                   1333:         * cookie 0 for the '.' entry, making this necessary. This
                   1334:         * isn't so bad, as 0 is a special case anyway.
                   1335:         */
                   1336:        if (off == 0)
1.149     christos 1337:                /* XXXUNCONST */
                   1338:                return (struct nfsdircache *)__UNCONST(&dzero);
1.135     yamt     1339:
1.49      fvdl     1340:        if (!np->n_dircache)
                   1341:                /*
                   1342:                 * XXX would like to do this in nfs_nget but vtype
                   1343:                 * isn't known at that time.
                   1344:                 */
                   1345:                nfs_initdircache(vp);
1.50      fvdl     1346:
1.120     yamt     1347:        if ((nmp->nm_flag & NFSMNT_XLATECOOKIE) && !np->n_dirgens)
                   1348:                nfs_initdirxlatecookie(vp);
                   1349:
1.135     yamt     1350: retry:
1.49      fvdl     1351:        ndp = nfs_searchdircache(vp, off, 0, &hashent);
                   1352:
1.135     yamt     1353:        NFSDC_LOCK(np);
                   1354:        if (ndp && (ndp->dc_flags & NFSDC_INVALID) == 0) {
1.49      fvdl     1355:                /*
                   1356:                 * Overwriting an old entry. Check if it's the same.
                   1357:                 * If so, just return. If not, remove the old entry.
                   1358:                 */
                   1359:                if (ndp->dc_blkcookie == blkoff && ndp->dc_entry == en)
1.135     yamt     1360:                        goto done;
                   1361:                nfs_unlinkdircache(np, ndp);
                   1362:                nfs_putdircache_unlocked(np, ndp);
                   1363:                ndp = NULL;
1.46      fvdl     1364:        }
                   1365:
1.49      fvdl     1366:        ndhp = &np->n_dircache[hashent];
1.46      fvdl     1367:
1.49      fvdl     1368:        if (!ndp) {
1.135     yamt     1369:                if (newndp == NULL) {
                   1370:                        NFSDC_UNLOCK(np);
1.196     yamt     1371:                        newndp = kmem_alloc(sizeof(*newndp), KM_SLEEP);
1.135     yamt     1372:                        newndp->dc_refcnt = 1;
                   1373:                        LIST_NEXT(newndp, dc_hash) = (void *)-1;
                   1374:                        goto retry;
                   1375:                }
                   1376:                ndp = newndp;
                   1377:                newndp = NULL;
1.49      fvdl     1378:                overwrite = 0;
                   1379:                if (nmp->nm_flag & NFSMNT_XLATECOOKIE) {
                   1380:                        /*
                   1381:                         * We're allocating a new entry, so bump the
                   1382:                         * generation number.
                   1383:                         */
1.160     christos 1384:                        KASSERT(np->n_dirgens);
1.49      fvdl     1385:                        gen = ++np->n_dirgens[hashent];
                   1386:                        if (gen == 0) {
                   1387:                                np->n_dirgens[hashent]++;
                   1388:                                gen++;
                   1389:                        }
                   1390:                        ndp->dc_cookie32 = (hashent << 24) | (gen & 0xffffff);
                   1391:                }
                   1392:        } else
                   1393:                overwrite = 1;
1.46      fvdl     1394:
1.49      fvdl     1395:        ndp->dc_cookie = off;
                   1396:        ndp->dc_blkcookie = blkoff;
1.46      fvdl     1397:        ndp->dc_entry = en;
1.137     yamt     1398:        ndp->dc_flags = 0;
1.46      fvdl     1399:
1.49      fvdl     1400:        if (overwrite)
1.135     yamt     1401:                goto done;
1.49      fvdl     1402:
1.46      fvdl     1403:        /*
                   1404:         * If the maximum directory cookie cache size has been reached
                   1405:         * for this node, take one off the front. The idea is that
                   1406:         * directories are typically read front-to-back once, so that
                   1407:         * the oldest entries can be thrown away without much performance
                   1408:         * loss.
                   1409:         */
                   1410:        if (np->n_dircachesize == NFS_MAXDIRCACHE) {
1.135     yamt     1411:                nfs_unlinkdircache(np, TAILQ_FIRST(&np->n_dirchain));
1.46      fvdl     1412:        } else
                   1413:                np->n_dircachesize++;
1.148     perry    1414:
1.135     yamt     1415:        KASSERT(ndp->dc_refcnt == 1);
1.46      fvdl     1416:        LIST_INSERT_HEAD(ndhp, ndp, dc_hash);
                   1417:        TAILQ_INSERT_TAIL(&np->n_dirchain, ndp, dc_chain);
1.135     yamt     1418:        ndp->dc_refcnt++;
                   1419: done:
                   1420:        KASSERT(ndp->dc_refcnt > 0);
                   1421:        NFSDC_UNLOCK(np);
                   1422:        if (newndp)
                   1423:                nfs_putdircache(np, newndp);
1.46      fvdl     1424:        return ndp;
                   1425: }
                   1426:
                   1427: void
1.201.4.3  yamt     1428: nfs_invaldircache(struct vnode *vp, int flags)
1.46      fvdl     1429: {
                   1430:        struct nfsnode *np = VTONFS(vp);
                   1431:        struct nfsdircache *ndp = NULL;
1.49      fvdl     1432:        struct nfsmount *nmp = VFSTONFS(vp->v_mount);
1.181     thorpej  1433:        const bool forcefree = flags & NFS_INVALDIRCACHE_FORCE;
1.46      fvdl     1434:
                   1435: #ifdef DIAGNOSTIC
                   1436:        if (vp->v_type != VDIR)
                   1437:                panic("nfs: invaldircache: not dir");
                   1438: #endif
                   1439:
1.145     yamt     1440:        if ((flags & NFS_INVALDIRCACHE_KEEPEOF) == 0)
                   1441:                np->n_flag &= ~NEOFVALID;
1.144     yamt     1442:
1.46      fvdl     1443:        if (!np->n_dircache)
                   1444:                return;
                   1445:
1.135     yamt     1446:        NFSDC_LOCK(np);
1.49      fvdl     1447:        if (!(nmp->nm_flag & NFSMNT_XLATECOOKIE) || forcefree) {
1.135     yamt     1448:                while ((ndp = TAILQ_FIRST(&np->n_dirchain)) != NULL) {
                   1449:                        KASSERT(!forcefree || ndp->dc_refcnt == 1);
                   1450:                        nfs_unlinkdircache(np, ndp);
1.49      fvdl     1451:                }
                   1452:                np->n_dircachesize = 0;
                   1453:                if (forcefree && np->n_dirgens) {
1.196     yamt     1454:                        kmem_free(np->n_dirgens,
                   1455:                            NFS_DIRHASHSIZ * sizeof(unsigned));
1.120     yamt     1456:                        np->n_dirgens = NULL;
1.49      fvdl     1457:                }
                   1458:        } else {
1.135     yamt     1459:                TAILQ_FOREACH(ndp, &np->n_dirchain, dc_chain)
                   1460:                        ndp->dc_flags |= NFSDC_INVALID;
1.46      fvdl     1461:        }
                   1462:
1.135     yamt     1463:        NFSDC_UNLOCK(np);
1.46      fvdl     1464: }
                   1465:
1.1       cgd      1466: /*
1.35      thorpej  1467:  * Called once before VFS init to initialize shared and
                   1468:  * server-specific data structures.
1.1       cgd      1469:  */
1.157     yamt     1470: static int
1.155     thorpej  1471: nfs_init0(void)
1.1       cgd      1472: {
1.189     ad       1473:
1.12      mycroft  1474:        nfsrtt.pos = 0;
1.1       cgd      1475:        rpc_vers = txdr_unsigned(RPC_VER2);
                   1476:        rpc_call = txdr_unsigned(RPC_CALL);
                   1477:        rpc_reply = txdr_unsigned(RPC_REPLY);
                   1478:        rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED);
                   1479:        rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED);
                   1480:        rpc_mismatch = txdr_unsigned(RPC_MISMATCH);
1.12      mycroft  1481:        rpc_autherr = txdr_unsigned(RPC_AUTHERR);
1.1       cgd      1482:        rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX);
1.25      fvdl     1483:        rpc_auth_kerb = txdr_unsigned(RPCAUTH_KERB4);
1.1       cgd      1484:        nfs_prog = txdr_unsigned(NFS_PROG);
1.182     thorpej  1485:        nfs_true = txdr_unsigned(true);
                   1486:        nfs_false = txdr_unsigned(false);
1.12      mycroft  1487:        nfs_xdrneg1 = txdr_unsigned(-1);
1.25      fvdl     1488:        nfs_ticks = (hz * NFS_TICKINTVL + 500) / 1000;
                   1489:        if (nfs_ticks < 1)
                   1490:                nfs_ticks = 1;
1.201.4.3  yamt     1491:        nfs_xid = arc4random();
1.164     yamt     1492:        nfsdreq_init();
                   1493:
1.1       cgd      1494:        /*
                   1495:         * Initialize reply list and start timer
                   1496:         */
1.201.4.1  yamt     1497:        mutex_init(&nfs_reqq_lock, MUTEX_DEFAULT, IPL_SOFTCLOCK);
1.16      mycroft  1498:        TAILQ_INIT(&nfs_reqq);
1.191     yamt     1499:        nfs_timer_init();
1.109     matt     1500:        MOWNER_ATTACH(&nfs_mowner);
1.106     jdolecek 1501:
1.157     yamt     1502:        return 0;
1.1       cgd      1503: }
                   1504:
1.201.4.3  yamt     1505: /*
                   1506:  * This is disgusting, but it must support both modular and monolothic
                   1507:  * configurations.  For monolithic builds NFSSERVER may not imply NFS.
                   1508:  *
                   1509:  * Yuck.
                   1510:  */
1.155     thorpej  1511: void
                   1512: nfs_init(void)
                   1513: {
                   1514:        static ONCE_DECL(nfs_init_once);
                   1515:
                   1516:        RUN_ONCE(&nfs_init_once, nfs_init0);
                   1517: }
                   1518:
1.201.4.3  yamt     1519: void
                   1520: nfs_fini(void)
                   1521: {
                   1522:
                   1523:        nfsdreq_fini();
                   1524:        nfs_timer_fini();
                   1525:        MOWNER_DETACH(&nfs_mowner);
                   1526: }
                   1527:
1.1       cgd      1528: /*
1.118     yamt     1529:  * A fiddled version of m_adj() that ensures null fill to a 32-bit
1.1       cgd      1530:  * boundary and only trims off the back end
1.122     yamt     1531:  *
                   1532:  * 1. trim off 'len' bytes as m_adj(mp, -len).
                   1533:  * 2. add zero-padding 'nul' bytes at the end of the mbuf chain.
1.1       cgd      1534:  */
1.12      mycroft  1535: void
1.201.4.3  yamt     1536: nfs_zeropad(struct mbuf *mp, int len, int nul)
1.1       cgd      1537: {
1.75      augustss 1538:        struct mbuf *m;
1.130     yamt     1539:        int count;
1.1       cgd      1540:
                   1541:        /*
                   1542:         * Trim from tail.  Scan the mbuf chain,
                   1543:         * calculating its length and finding the last mbuf.
                   1544:         * If the adjustment only affects this mbuf, then just
                   1545:         * adjust and return.  Otherwise, rescan and truncate
                   1546:         * after the remaining size.
                   1547:         */
                   1548:        count = 0;
                   1549:        m = mp;
                   1550:        for (;;) {
                   1551:                count += m->m_len;
1.122     yamt     1552:                if (m->m_next == NULL)
1.1       cgd      1553:                        break;
                   1554:                m = m->m_next;
                   1555:        }
1.122     yamt     1556:
                   1557:        KDASSERT(count >= len);
                   1558:
                   1559:        if (m->m_len >= len) {
1.1       cgd      1560:                m->m_len -= len;
1.122     yamt     1561:        } else {
                   1562:                count -= len;
                   1563:                /*
                   1564:                 * Correct length for chain is "count".
                   1565:                 * Find the mbuf with last data, adjust its length,
                   1566:                 * and toss data from remaining mbufs on chain.
                   1567:                 */
                   1568:                for (m = mp; m; m = m->m_next) {
                   1569:                        if (m->m_len >= count) {
                   1570:                                m->m_len = count;
                   1571:                                break;
1.118     yamt     1572:                        }
1.122     yamt     1573:                        count -= m->m_len;
1.1       cgd      1574:                }
1.159     christos 1575:                KASSERT(m && m->m_next);
1.122     yamt     1576:                m_freem(m->m_next);
                   1577:                m->m_next = NULL;
1.1       cgd      1578:        }
1.122     yamt     1579:
1.130     yamt     1580:        KDASSERT(m->m_next == NULL);
                   1581:
1.122     yamt     1582:        /*
                   1583:         * zero-padding.
                   1584:         */
                   1585:        if (nul > 0) {
1.130     yamt     1586:                char *cp;
                   1587:                int i;
                   1588:
1.122     yamt     1589:                if (M_ROMAP(m) || M_TRAILINGSPACE(m) < nul) {
                   1590:                        struct mbuf *n;
                   1591:
                   1592:                        KDASSERT(MLEN >= nul);
                   1593:                        n = m_get(M_WAIT, MT_DATA);
                   1594:                        MCLAIM(n, &nfs_mowner);
                   1595:                        n->m_len = nul;
1.130     yamt     1596:                        n->m_next = NULL;
1.122     yamt     1597:                        m->m_next = n;
1.183     christos 1598:                        cp = mtod(n, void *);
1.122     yamt     1599:                } else {
1.183     christos 1600:                        cp = mtod(m, char *) + m->m_len;
1.122     yamt     1601:                        m->m_len += nul;
1.1       cgd      1602:                }
1.122     yamt     1603:                for (i = 0; i < nul; i++)
                   1604:                        *cp++ = '\0';
1.1       cgd      1605:        }
1.122     yamt     1606:        return;
1.1       cgd      1607: }
                   1608:
                   1609: /*
1.25      fvdl     1610:  * Make these functions instead of macros, so that the kernel text size
                   1611:  * doesn't get too big...
                   1612:  */
                   1613: void
1.201.4.3  yamt     1614: nfsm_srvwcc(struct nfsrv_descript *nfsd, int before_ret, struct vattr *before_vap, int after_ret, struct vattr *after_vap, struct mbuf **mbp, char **bposp)
1.25      fvdl     1615: {
1.109     matt     1616:        struct mbuf *mb = *mbp;
1.75      augustss 1617:        char *bpos = *bposp;
                   1618:        u_int32_t *tl;
1.25      fvdl     1619:
                   1620:        if (before_ret) {
                   1621:                nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED);
                   1622:                *tl = nfs_false;
                   1623:        } else {
                   1624:                nfsm_build(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
                   1625:                *tl++ = nfs_true;
1.66      fair     1626:                txdr_hyper(before_vap->va_size, tl);
1.25      fvdl     1627:                tl += 2;
                   1628:                txdr_nfsv3time(&(before_vap->va_mtime), tl);
                   1629:                tl += 2;
                   1630:                txdr_nfsv3time(&(before_vap->va_ctime), tl);
                   1631:        }
                   1632:        *bposp = bpos;
                   1633:        *mbp = mb;
                   1634:        nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp);
                   1635: }
                   1636:
                   1637: void
1.201.4.3  yamt     1638: nfsm_srvpostopattr(struct nfsrv_descript *nfsd, int after_ret, struct vattr *after_vap, struct mbuf **mbp, char **bposp)
1.25      fvdl     1639: {
1.109     matt     1640:        struct mbuf *mb = *mbp;
1.75      augustss 1641:        char *bpos = *bposp;
                   1642:        u_int32_t *tl;
                   1643:        struct nfs_fattr *fp;
1.25      fvdl     1644:
                   1645:        if (after_ret) {
                   1646:                nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED);
                   1647:                *tl = nfs_false;
                   1648:        } else {
                   1649:                nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_V3FATTR);
                   1650:                *tl++ = nfs_true;
                   1651:                fp = (struct nfs_fattr *)tl;
                   1652:                nfsm_srvfattr(nfsd, after_vap, fp);
                   1653:        }
                   1654:        *mbp = mb;
                   1655:        *bposp = bpos;
                   1656: }
                   1657:
                   1658: void
1.201.4.3  yamt     1659: nfsm_srvfattr(struct nfsrv_descript *nfsd, struct vattr *vap, struct nfs_fattr *fp)
1.25      fvdl     1660: {
                   1661:
                   1662:        fp->fa_nlink = txdr_unsigned(vap->va_nlink);
                   1663:        fp->fa_uid = txdr_unsigned(vap->va_uid);
                   1664:        fp->fa_gid = txdr_unsigned(vap->va_gid);
                   1665:        if (nfsd->nd_flag & ND_NFSV3) {
                   1666:                fp->fa_type = vtonfsv3_type(vap->va_type);
                   1667:                fp->fa_mode = vtonfsv3_mode(vap->va_mode);
1.66      fair     1668:                txdr_hyper(vap->va_size, &fp->fa3_size);
                   1669:                txdr_hyper(vap->va_bytes, &fp->fa3_used);
1.25      fvdl     1670:                fp->fa3_rdev.specdata1 = txdr_unsigned(major(vap->va_rdev));
                   1671:                fp->fa3_rdev.specdata2 = txdr_unsigned(minor(vap->va_rdev));
                   1672:                fp->fa3_fsid.nfsuquad[0] = 0;
                   1673:                fp->fa3_fsid.nfsuquad[1] = txdr_unsigned(vap->va_fsid);
1.151     yamt     1674:                txdr_hyper(vap->va_fileid, &fp->fa3_fileid);
1.25      fvdl     1675:                txdr_nfsv3time(&vap->va_atime, &fp->fa3_atime);
                   1676:                txdr_nfsv3time(&vap->va_mtime, &fp->fa3_mtime);
                   1677:                txdr_nfsv3time(&vap->va_ctime, &fp->fa3_ctime);
                   1678:        } else {
                   1679:                fp->fa_type = vtonfsv2_type(vap->va_type);
                   1680:                fp->fa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode);
                   1681:                fp->fa2_size = txdr_unsigned(vap->va_size);
                   1682:                fp->fa2_blocksize = txdr_unsigned(vap->va_blocksize);
                   1683:                if (vap->va_type == VFIFO)
                   1684:                        fp->fa2_rdev = 0xffffffff;
                   1685:                else
                   1686:                        fp->fa2_rdev = txdr_unsigned(vap->va_rdev);
                   1687:                fp->fa2_blocks = txdr_unsigned(vap->va_bytes / NFS_FABLKSIZE);
                   1688:                fp->fa2_fsid = txdr_unsigned(vap->va_fsid);
                   1689:                fp->fa2_fileid = txdr_unsigned(vap->va_fileid);
                   1690:                txdr_nfsv2time(&vap->va_atime, &fp->fa2_atime);
                   1691:                txdr_nfsv2time(&vap->va_mtime, &fp->fa2_mtime);
                   1692:                txdr_nfsv2time(&vap->va_ctime, &fp->fa2_ctime);
                   1693:        }
                   1694: }
                   1695:
1.1       cgd      1696: /*
1.182     thorpej  1697:  * This function compares two net addresses by family and returns true
1.12      mycroft  1698:  * if they are the same host.
1.182     thorpej  1699:  * If there is any doubt, return false.
1.12      mycroft  1700:  * The AF_INET family is handled as a special case so that address mbufs
                   1701:  * don't need to be saved to store "struct in_addr", which is only 4 bytes.
1.1       cgd      1702:  */
1.24      christos 1703: int
1.201.4.3  yamt     1704: netaddr_match(int family, union nethostaddr *haddr, struct mbuf *nam)
1.1       cgd      1705: {
1.75      augustss 1706:        struct sockaddr_in *inetaddr;
1.1       cgd      1707:
1.12      mycroft  1708:        switch (family) {
                   1709:        case AF_INET:
                   1710:                inetaddr = mtod(nam, struct sockaddr_in *);
                   1711:                if (inetaddr->sin_family == AF_INET &&
                   1712:                    inetaddr->sin_addr.s_addr == haddr->had_inetaddr)
                   1713:                        return (1);
                   1714:                break;
1.76      fvdl     1715:        case AF_INET6:
                   1716:            {
                   1717:                struct sockaddr_in6 *sin6_1, *sin6_2;
                   1718:
                   1719:                sin6_1 = mtod(nam, struct sockaddr_in6 *);
                   1720:                sin6_2 = mtod(haddr->had_nam, struct sockaddr_in6 *);
                   1721:                if (sin6_1->sin6_family == AF_INET6 &&
                   1722:                    IN6_ARE_ADDR_EQUAL(&sin6_1->sin6_addr, &sin6_2->sin6_addr))
                   1723:                        return 1;
                   1724:            }
1.12      mycroft  1725:        default:
                   1726:                break;
                   1727:        };
                   1728:        return (0);
1.25      fvdl     1729: }
                   1730:
                   1731: /*
                   1732:  * The write verifier has changed (probably due to a server reboot), so all
1.114     yamt     1733:  * PG_NEEDCOMMIT pages will have to be written again. Since they are marked
1.117     yamt     1734:  * as dirty or are being written out just now, all this takes is clearing
                   1735:  * the PG_NEEDCOMMIT flag. Once done the new write verifier can be set for
                   1736:  * the mount point.
1.25      fvdl     1737:  */
                   1738: void
1.201.4.3  yamt     1739: nfs_clearcommit(struct mount *mp)
1.25      fvdl     1740: {
1.89      chs      1741:        struct vnode *vp;
1.83      fvdl     1742:        struct nfsnode *np;
1.89      chs      1743:        struct vm_page *pg;
1.116     yamt     1744:        struct nfsmount *nmp = VFSTONFS(mp);
                   1745:
1.180     yamt     1746:        rw_enter(&nmp->nm_writeverflock, RW_WRITER);
1.195     ad       1747:        mutex_enter(&mntvnode_lock);
1.176     reinoud  1748:        TAILQ_FOREACH(vp, &mp->mnt_vnodelist, v_mntvnodes) {
1.89      chs      1749:                KASSERT(vp->v_mount == mp);
1.146     yamt     1750:                if (vp->v_type != VREG)
1.85      enami    1751:                        continue;
1.201.4.4  yamt     1752:                mutex_enter(&vp->v_interlock);
                   1753:                if (vp->v_iflag & (VI_XLOCK | VI_CLEAN)) {
                   1754:                        mutex_exit(&vp->v_interlock);
                   1755:                        continue;
                   1756:                }
1.83      fvdl     1757:                np = VTONFS(vp);
                   1758:                np->n_pushlo = np->n_pushhi = np->n_pushedlo =
                   1759:                    np->n_pushedhi = 0;
                   1760:                np->n_commitflags &=
                   1761:                    ~(NFS_COMMIT_PUSH_VALID | NFS_COMMIT_PUSHED_VALID);
1.201.4.3  yamt     1762:                TAILQ_FOREACH(pg, &vp->v_uobj.memq, listq.queue) {
1.89      chs      1763:                        pg->flags &= ~PG_NEEDCOMMIT;
1.25      fvdl     1764:                }
1.201.4.4  yamt     1765:                mutex_exit(&vp->v_interlock);
1.25      fvdl     1766:        }
1.195     ad       1767:        mutex_exit(&mntvnode_lock);
1.186     yamt     1768:        mutex_enter(&nmp->nm_lock);
1.116     yamt     1769:        nmp->nm_iflag &= ~NFSMNT_STALEWRITEVERF;
1.186     yamt     1770:        mutex_exit(&nmp->nm_lock);
1.180     yamt     1771:        rw_exit(&nmp->nm_writeverflock);
1.83      fvdl     1772: }
                   1773:
                   1774: void
1.201.4.3  yamt     1775: nfs_merge_commit_ranges(struct vnode *vp)
1.83      fvdl     1776: {
                   1777:        struct nfsnode *np = VTONFS(vp);
1.112     yamt     1778:
                   1779:        KASSERT(np->n_commitflags & NFS_COMMIT_PUSH_VALID);
1.83      fvdl     1780:
                   1781:        if (!(np->n_commitflags & NFS_COMMIT_PUSHED_VALID)) {
                   1782:                np->n_pushedlo = np->n_pushlo;
                   1783:                np->n_pushedhi = np->n_pushhi;
                   1784:                np->n_commitflags |= NFS_COMMIT_PUSHED_VALID;
                   1785:        } else {
                   1786:                if (np->n_pushlo < np->n_pushedlo)
                   1787:                        np->n_pushedlo = np->n_pushlo;
                   1788:                if (np->n_pushhi > np->n_pushedhi)
                   1789:                        np->n_pushedhi = np->n_pushhi;
                   1790:        }
                   1791:
                   1792:        np->n_pushlo = np->n_pushhi = 0;
                   1793:        np->n_commitflags &= ~NFS_COMMIT_PUSH_VALID;
                   1794:
1.111     yamt     1795: #ifdef NFS_DEBUG_COMMIT
1.83      fvdl     1796:        printf("merge: committed: %u - %u\n", (unsigned)np->n_pushedlo,
                   1797:            (unsigned)np->n_pushedhi);
                   1798: #endif
                   1799: }
                   1800:
                   1801: int
1.201.4.3  yamt     1802: nfs_in_committed_range(struct vnode *vp, off_t off, off_t len)
1.83      fvdl     1803: {
                   1804:        struct nfsnode *np = VTONFS(vp);
                   1805:        off_t lo, hi;
                   1806:
                   1807:        if (!(np->n_commitflags & NFS_COMMIT_PUSHED_VALID))
                   1808:                return 0;
1.89      chs      1809:        lo = off;
                   1810:        hi = lo + len;
1.83      fvdl     1811:
                   1812:        return (lo >= np->n_pushedlo && hi <= np->n_pushedhi);
                   1813: }
                   1814:
                   1815: int
1.201.4.3  yamt     1816: nfs_in_tobecommitted_range(struct vnode *vp, off_t off, off_t len)
1.83      fvdl     1817: {
                   1818:        struct nfsnode *np = VTONFS(vp);
                   1819:        off_t lo, hi;
                   1820:
                   1821:        if (!(np->n_commitflags & NFS_COMMIT_PUSH_VALID))
                   1822:                return 0;
1.89      chs      1823:        lo = off;
                   1824:        hi = lo + len;
1.83      fvdl     1825:
                   1826:        return (lo >= np->n_pushlo && hi <= np->n_pushhi);
                   1827: }
                   1828:
                   1829: void
1.201.4.3  yamt     1830: nfs_add_committed_range(struct vnode *vp, off_t off, off_t len)
1.83      fvdl     1831: {
                   1832:        struct nfsnode *np = VTONFS(vp);
                   1833:        off_t lo, hi;
                   1834:
1.89      chs      1835:        lo = off;
                   1836:        hi = lo + len;
1.83      fvdl     1837:
                   1838:        if (!(np->n_commitflags & NFS_COMMIT_PUSHED_VALID)) {
                   1839:                np->n_pushedlo = lo;
                   1840:                np->n_pushedhi = hi;
                   1841:                np->n_commitflags |= NFS_COMMIT_PUSHED_VALID;
                   1842:        } else {
                   1843:                if (hi > np->n_pushedhi)
                   1844:                        np->n_pushedhi = hi;
                   1845:                if (lo < np->n_pushedlo)
                   1846:                        np->n_pushedlo = lo;
                   1847:        }
1.111     yamt     1848: #ifdef NFS_DEBUG_COMMIT
1.83      fvdl     1849:        printf("add: committed: %u - %u\n", (unsigned)np->n_pushedlo,
                   1850:            (unsigned)np->n_pushedhi);
                   1851: #endif
                   1852: }
                   1853:
                   1854: void
1.201.4.3  yamt     1855: nfs_del_committed_range(struct vnode *vp, off_t off, off_t len)
1.83      fvdl     1856: {
                   1857:        struct nfsnode *np = VTONFS(vp);
                   1858:        off_t lo, hi;
                   1859:
                   1860:        if (!(np->n_commitflags & NFS_COMMIT_PUSHED_VALID))
                   1861:                return;
                   1862:
1.89      chs      1863:        lo = off;
                   1864:        hi = lo + len;
1.83      fvdl     1865:
                   1866:        if (lo > np->n_pushedhi || hi < np->n_pushedlo)
                   1867:                return;
                   1868:        if (lo <= np->n_pushedlo)
                   1869:                np->n_pushedlo = hi;
                   1870:        else if (hi >= np->n_pushedhi)
                   1871:                np->n_pushedhi = lo;
                   1872:        else {
                   1873:                /*
                   1874:                 * XXX There's only one range. If the deleted range
                   1875:                 * is in the middle, pick the largest of the
                   1876:                 * contiguous ranges that it leaves.
                   1877:                 */
                   1878:                if ((np->n_pushedlo - lo) > (hi - np->n_pushedhi))
                   1879:                        np->n_pushedhi = lo;
                   1880:                else
                   1881:                        np->n_pushedlo = hi;
                   1882:        }
1.111     yamt     1883: #ifdef NFS_DEBUG_COMMIT
1.83      fvdl     1884:        printf("del: committed: %u - %u\n", (unsigned)np->n_pushedlo,
                   1885:            (unsigned)np->n_pushedhi);
                   1886: #endif
                   1887: }
                   1888:
                   1889: void
1.201.4.3  yamt     1890: nfs_add_tobecommitted_range(struct vnode *vp, off_t off, off_t len)
1.83      fvdl     1891: {
                   1892:        struct nfsnode *np = VTONFS(vp);
                   1893:        off_t lo, hi;
                   1894:
1.89      chs      1895:        lo = off;
                   1896:        hi = lo + len;
1.83      fvdl     1897:
                   1898:        if (!(np->n_commitflags & NFS_COMMIT_PUSH_VALID)) {
                   1899:                np->n_pushlo = lo;
                   1900:                np->n_pushhi = hi;
                   1901:                np->n_commitflags |= NFS_COMMIT_PUSH_VALID;
                   1902:        } else {
                   1903:                if (lo < np->n_pushlo)
                   1904:                        np->n_pushlo = lo;
                   1905:                if (hi > np->n_pushhi)
                   1906:                        np->n_pushhi = hi;
                   1907:        }
1.111     yamt     1908: #ifdef NFS_DEBUG_COMMIT
1.83      fvdl     1909:        printf("add: tobecommitted: %u - %u\n", (unsigned)np->n_pushlo,
                   1910:            (unsigned)np->n_pushhi);
                   1911: #endif
                   1912: }
                   1913:
                   1914: void
1.201.4.3  yamt     1915: nfs_del_tobecommitted_range(struct vnode *vp, off_t off, off_t len)
1.83      fvdl     1916: {
                   1917:        struct nfsnode *np = VTONFS(vp);
                   1918:        off_t lo, hi;
                   1919:
                   1920:        if (!(np->n_commitflags & NFS_COMMIT_PUSH_VALID))
                   1921:                return;
                   1922:
1.89      chs      1923:        lo = off;
                   1924:        hi = lo + len;
1.83      fvdl     1925:
                   1926:        if (lo > np->n_pushhi || hi < np->n_pushlo)
                   1927:                return;
                   1928:
                   1929:        if (lo <= np->n_pushlo)
                   1930:                np->n_pushlo = hi;
                   1931:        else if (hi >= np->n_pushhi)
                   1932:                np->n_pushhi = lo;
                   1933:        else {
                   1934:                /*
                   1935:                 * XXX There's only one range. If the deleted range
                   1936:                 * is in the middle, pick the largest of the
                   1937:                 * contiguous ranges that it leaves.
                   1938:                 */
                   1939:                if ((np->n_pushlo - lo) > (hi - np->n_pushhi))
                   1940:                        np->n_pushhi = lo;
                   1941:                else
                   1942:                        np->n_pushlo = hi;
                   1943:        }
1.111     yamt     1944: #ifdef NFS_DEBUG_COMMIT
1.83      fvdl     1945:        printf("del: tobecommitted: %u - %u\n", (unsigned)np->n_pushlo,
                   1946:            (unsigned)np->n_pushhi);
                   1947: #endif
1.25      fvdl     1948: }
                   1949:
                   1950: /*
                   1951:  * Map errnos to NFS error numbers. For Version 3 also filter out error
                   1952:  * numbers not specified for the associated procedure.
                   1953:  */
                   1954: int
1.201.4.3  yamt     1955: nfsrv_errmap(struct nfsrv_descript *nd, int err)
1.25      fvdl     1956: {
1.90      jdolecek 1957:        const short *defaulterrp, *errp;
1.25      fvdl     1958:
                   1959:        if (nd->nd_flag & ND_NFSV3) {
                   1960:            if (nd->nd_procnum <= NFSPROC_COMMIT) {
                   1961:                errp = defaulterrp = nfsrv_v3errmap[nd->nd_procnum];
                   1962:                while (*++errp) {
                   1963:                        if (*errp == err)
                   1964:                                return (err);
                   1965:                        else if (*errp > err)
                   1966:                                break;
                   1967:                }
                   1968:                return ((int)*defaulterrp);
                   1969:            } else
                   1970:                return (err & 0xffff);
                   1971:        }
                   1972:        if (err <= ELAST)
                   1973:                return ((int)nfsrv_v2errmap[err - 1]);
                   1974:        return (NFSERR_IO);
                   1975: }
                   1976:
1.126     yamt     1977: u_int32_t
1.201.4.3  yamt     1978: nfs_getxid(void)
1.126     yamt     1979: {
                   1980:        u_int32_t newxid;
                   1981:
1.201.4.3  yamt     1982:        /* get next xid.  skip 0 */
                   1983:        do {
                   1984:                newxid = atomic_inc_32_nv(&nfs_xid);
                   1985:        } while (__predict_false(newxid == 0));
1.126     yamt     1986:
                   1987:        return txdr_unsigned(newxid);
                   1988: }
                   1989:
                   1990: /*
                   1991:  * assign a new xid for existing request.
                   1992:  * used for NFSERR_JUKEBOX handling.
                   1993:  */
                   1994: void
                   1995: nfs_renewxid(struct nfsreq *req)
                   1996: {
                   1997:        u_int32_t xid;
                   1998:        int off;
                   1999:
                   2000:        xid = nfs_getxid();
                   2001:        if (req->r_nmp->nm_sotype == SOCK_STREAM)
                   2002:                off = sizeof(u_int32_t); /* RPC record mark */
                   2003:        else
                   2004:                off = 0;
                   2005:
                   2006:        m_copyback(req->r_mreq, off, sizeof(xid), (void *)&xid);
                   2007:        req->r_xid = xid;
1.1       cgd      2008: }

CVSweb <webmaster@jp.NetBSD.org>