[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.149.2.8

1.149.2.8! yamt        1: /*     $NetBSD: nfs_subs.c,v 1.149.2.7 2007/12/07 17:34:44 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.149.2.8! yamt       73: __KERNEL_RCSID(0, "$NetBSD: nfs_subs.c,v 1.149.2.7 2007/12/07 17:34:44 yamt Exp $");
1.83      fvdl       74:
1.55      thorpej    75: #include "fs_nfs.h"
1.82      bjh21      76: #include "opt_nfs.h"
1.61      thorpej    77: #include "opt_nfsserver.h"
1.62      jonathan   78: #include "opt_iso.h"
1.76      fvdl       79: #include "opt_inet.h"
1.25      fvdl       80:
1.1       cgd        81: /*
                     82:  * These functions support the macros and help fiddle mbuf chains for
                     83:  * the nfs op functions. They do things like create the rpc header and
                     84:  * copy data between mbuf chains and uio lists.
                     85:  */
1.9       mycroft    86: #include <sys/param.h>
                     87: #include <sys/proc.h>
                     88: #include <sys/systm.h>
                     89: #include <sys/kernel.h>
1.149.2.8! yamt       90: #include <sys/kmem.h>
1.9       mycroft    91: #include <sys/mount.h>
                     92: #include <sys/vnode.h>
                     93: #include <sys/namei.h>
                     94: #include <sys/mbuf.h>
1.12      mycroft    95: #include <sys/socket.h>
                     96: #include <sys/stat.h>
1.25      fvdl       97: #include <sys/malloc.h>
1.98      fvdl       98: #include <sys/filedesc.h>
1.30      fvdl       99: #include <sys/time.h>
1.43      fvdl      100: #include <sys/dirent.h>
1.149.2.2  yamt      101: #include <sys/once.h>
                    102: #include <sys/kauth.h>
1.1       cgd       103:
1.51      mrg       104: #include <uvm/uvm_extern.h>
                    105:
1.9       mycroft   106: #include <nfs/rpcv2.h>
1.25      fvdl      107: #include <nfs/nfsproto.h>
1.9       mycroft   108: #include <nfs/nfsnode.h>
                    109: #include <nfs/nfs.h>
                    110: #include <nfs/xdr_subs.h>
                    111: #include <nfs/nfsm_subs.h>
1.12      mycroft   112: #include <nfs/nfsmount.h>
                    113: #include <nfs/nfsrtt.h>
1.24      christos  114: #include <nfs/nfs_var.h>
1.12      mycroft   115:
                    116: #include <miscfs/specfs/specdev.h>
1.24      christos  117:
1.12      mycroft   118: #include <netinet/in.h>
                    119: #ifdef ISO
                    120: #include <netiso/iso.h>
                    121: #endif
1.1       cgd       122:
                    123: /*
                    124:  * Data items converted to xdr at startup, since they are constant
                    125:  * This is kinda hokey, but may save a little time doing byte swaps
                    126:  */
1.22      cgd       127: u_int32_t nfs_xdrneg1;
                    128: u_int32_t rpc_call, rpc_vers, rpc_reply, rpc_msgdenied, rpc_autherr,
1.25      fvdl      129:        rpc_mismatch, rpc_auth_unix, rpc_msgaccepted,
1.12      mycroft   130:        rpc_auth_kerb;
1.149.2.3  yamt      131: u_int32_t nfs_prog, nfs_true, nfs_false;
1.12      mycroft   132:
1.1       cgd       133: /* And other global data */
1.90      jdolecek  134: const nfstype nfsv2_type[9] =
                    135:        { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFNON, NFCHR, NFNON };
                    136: const nfstype nfsv3_type[9] =
                    137:        { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFSOCK, NFFIFO, NFNON };
                    138: const enum vtype nv2tov_type[8] =
                    139:        { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON, VNON };
                    140: const enum vtype nv3tov_type[8] =
                    141:        { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO };
1.25      fvdl      142: int nfs_ticks;
1.100     chs       143: int nfs_commitsize;
1.108     christos  144:
                    145: MALLOC_DEFINE(M_NFSDIROFF, "NFS diroff", "NFS directory cookies");
1.25      fvdl      146:
1.35      thorpej   147: /* NFS client/server stats. */
                    148: struct nfsstats nfsstats;
                    149:
1.25      fvdl      150: /*
                    151:  * Mapping of old NFS Version 2 RPC numbers to generic numbers.
                    152:  */
1.90      jdolecek  153: const int nfsv3_procid[NFS_NPROCS] = {
1.25      fvdl      154:        NFSPROC_NULL,
                    155:        NFSPROC_GETATTR,
                    156:        NFSPROC_SETATTR,
                    157:        NFSPROC_NOOP,
                    158:        NFSPROC_LOOKUP,
                    159:        NFSPROC_READLINK,
                    160:        NFSPROC_READ,
                    161:        NFSPROC_NOOP,
                    162:        NFSPROC_WRITE,
                    163:        NFSPROC_CREATE,
                    164:        NFSPROC_REMOVE,
                    165:        NFSPROC_RENAME,
                    166:        NFSPROC_LINK,
                    167:        NFSPROC_SYMLINK,
                    168:        NFSPROC_MKDIR,
                    169:        NFSPROC_RMDIR,
                    170:        NFSPROC_READDIR,
                    171:        NFSPROC_FSSTAT,
                    172:        NFSPROC_NOOP,
                    173:        NFSPROC_NOOP,
                    174:        NFSPROC_NOOP,
                    175:        NFSPROC_NOOP,
                    176:        NFSPROC_NOOP
                    177: };
                    178:
                    179: /*
                    180:  * and the reverse mapping from generic to Version 2 procedure numbers
                    181:  */
1.90      jdolecek  182: const int nfsv2_procid[NFS_NPROCS] = {
1.25      fvdl      183:        NFSV2PROC_NULL,
                    184:        NFSV2PROC_GETATTR,
                    185:        NFSV2PROC_SETATTR,
                    186:        NFSV2PROC_LOOKUP,
                    187:        NFSV2PROC_NOOP,
                    188:        NFSV2PROC_READLINK,
                    189:        NFSV2PROC_READ,
                    190:        NFSV2PROC_WRITE,
                    191:        NFSV2PROC_CREATE,
                    192:        NFSV2PROC_MKDIR,
                    193:        NFSV2PROC_SYMLINK,
                    194:        NFSV2PROC_CREATE,
                    195:        NFSV2PROC_REMOVE,
                    196:        NFSV2PROC_RMDIR,
                    197:        NFSV2PROC_RENAME,
                    198:        NFSV2PROC_LINK,
                    199:        NFSV2PROC_READDIR,
                    200:        NFSV2PROC_NOOP,
                    201:        NFSV2PROC_STATFS,
                    202:        NFSV2PROC_NOOP,
                    203:        NFSV2PROC_NOOP,
                    204:        NFSV2PROC_NOOP,
                    205:        NFSV2PROC_NOOP,
                    206: };
                    207:
                    208: /*
                    209:  * Maps errno values to nfs error numbers.
                    210:  * Use NFSERR_IO as the catch all for ones not specifically defined in
                    211:  * RFC 1094.
                    212:  */
1.90      jdolecek  213: static const u_char nfsrv_v2errmap[ELAST] = {
1.25      fvdl      214:   NFSERR_PERM, NFSERR_NOENT,   NFSERR_IO,      NFSERR_IO,      NFSERR_IO,
                    215:   NFSERR_NXIO, NFSERR_IO,      NFSERR_IO,      NFSERR_IO,      NFSERR_IO,
                    216:   NFSERR_IO,   NFSERR_IO,      NFSERR_ACCES,   NFSERR_IO,      NFSERR_IO,
                    217:   NFSERR_IO,   NFSERR_EXIST,   NFSERR_IO,      NFSERR_NODEV,   NFSERR_NOTDIR,
                    218:   NFSERR_ISDIR,        NFSERR_IO,      NFSERR_IO,      NFSERR_IO,      NFSERR_IO,
                    219:   NFSERR_IO,   NFSERR_FBIG,    NFSERR_NOSPC,   NFSERR_IO,      NFSERR_ROFS,
                    220:   NFSERR_IO,   NFSERR_IO,      NFSERR_IO,      NFSERR_IO,      NFSERR_IO,
                    221:   NFSERR_IO,   NFSERR_IO,      NFSERR_IO,      NFSERR_IO,      NFSERR_IO,
                    222:   NFSERR_IO,   NFSERR_IO,      NFSERR_IO,      NFSERR_IO,      NFSERR_IO,
                    223:   NFSERR_IO,   NFSERR_IO,      NFSERR_IO,      NFSERR_IO,      NFSERR_IO,
                    224:   NFSERR_IO,   NFSERR_IO,      NFSERR_IO,      NFSERR_IO,      NFSERR_IO,
                    225:   NFSERR_IO,   NFSERR_IO,      NFSERR_IO,      NFSERR_IO,      NFSERR_IO,
                    226:   NFSERR_IO,   NFSERR_IO,      NFSERR_NAMETOL, NFSERR_IO,      NFSERR_IO,
                    227:   NFSERR_NOTEMPTY, NFSERR_IO,  NFSERR_IO,      NFSERR_DQUOT,   NFSERR_STALE,
                    228:   NFSERR_IO,   NFSERR_IO,      NFSERR_IO,      NFSERR_IO,      NFSERR_IO,
                    229:   NFSERR_IO,   NFSERR_IO,      NFSERR_IO,      NFSERR_IO,      NFSERR_IO,
1.52      mikel     230:   NFSERR_IO,   NFSERR_IO,
1.25      fvdl      231: };
                    232:
                    233: /*
                    234:  * Maps errno values to nfs error numbers.
                    235:  * Although it is not obvious whether or not NFS clients really care if
                    236:  * a returned error value is in the specified list for the procedure, the
                    237:  * safest thing to do is filter them appropriately. For Version 2, the
                    238:  * X/Open XNFS document is the only specification that defines error values
                    239:  * for each RPC (The RFC simply lists all possible error values for all RPCs),
                    240:  * so I have decided to not do this for Version 2.
                    241:  * The first entry is the default error return and the rest are the valid
                    242:  * errors for that RPC in increasing numeric order.
                    243:  */
1.90      jdolecek  244: static const short nfsv3err_null[] = {
1.25      fvdl      245:        0,
                    246:        0,
                    247: };
                    248:
1.90      jdolecek  249: static const short nfsv3err_getattr[] = {
1.25      fvdl      250:        NFSERR_IO,
                    251:        NFSERR_IO,
                    252:        NFSERR_STALE,
                    253:        NFSERR_BADHANDLE,
                    254:        NFSERR_SERVERFAULT,
                    255:        0,
                    256: };
                    257:
1.90      jdolecek  258: static const short nfsv3err_setattr[] = {
1.25      fvdl      259:        NFSERR_IO,
                    260:        NFSERR_PERM,
                    261:        NFSERR_IO,
                    262:        NFSERR_ACCES,
                    263:        NFSERR_INVAL,
                    264:        NFSERR_NOSPC,
                    265:        NFSERR_ROFS,
                    266:        NFSERR_DQUOT,
                    267:        NFSERR_STALE,
                    268:        NFSERR_BADHANDLE,
                    269:        NFSERR_NOT_SYNC,
                    270:        NFSERR_SERVERFAULT,
                    271:        0,
                    272: };
                    273:
1.90      jdolecek  274: static const short nfsv3err_lookup[] = {
1.25      fvdl      275:        NFSERR_IO,
                    276:        NFSERR_NOENT,
                    277:        NFSERR_IO,
                    278:        NFSERR_ACCES,
                    279:        NFSERR_NOTDIR,
                    280:        NFSERR_NAMETOL,
                    281:        NFSERR_STALE,
                    282:        NFSERR_BADHANDLE,
                    283:        NFSERR_SERVERFAULT,
                    284:        0,
                    285: };
                    286:
1.90      jdolecek  287: static const short nfsv3err_access[] = {
1.25      fvdl      288:        NFSERR_IO,
                    289:        NFSERR_IO,
                    290:        NFSERR_STALE,
                    291:        NFSERR_BADHANDLE,
                    292:        NFSERR_SERVERFAULT,
                    293:        0,
                    294: };
                    295:
1.90      jdolecek  296: static const short nfsv3err_readlink[] = {
1.25      fvdl      297:        NFSERR_IO,
                    298:        NFSERR_IO,
                    299:        NFSERR_ACCES,
                    300:        NFSERR_INVAL,
                    301:        NFSERR_STALE,
                    302:        NFSERR_BADHANDLE,
                    303:        NFSERR_NOTSUPP,
                    304:        NFSERR_SERVERFAULT,
                    305:        0,
                    306: };
                    307:
1.90      jdolecek  308: static const short nfsv3err_read[] = {
1.25      fvdl      309:        NFSERR_IO,
                    310:        NFSERR_IO,
                    311:        NFSERR_NXIO,
                    312:        NFSERR_ACCES,
                    313:        NFSERR_INVAL,
                    314:        NFSERR_STALE,
                    315:        NFSERR_BADHANDLE,
                    316:        NFSERR_SERVERFAULT,
1.67      fvdl      317:        NFSERR_JUKEBOX,
1.25      fvdl      318:        0,
                    319: };
                    320:
1.90      jdolecek  321: static const short nfsv3err_write[] = {
1.25      fvdl      322:        NFSERR_IO,
                    323:        NFSERR_IO,
                    324:        NFSERR_ACCES,
                    325:        NFSERR_INVAL,
                    326:        NFSERR_FBIG,
                    327:        NFSERR_NOSPC,
                    328:        NFSERR_ROFS,
                    329:        NFSERR_DQUOT,
                    330:        NFSERR_STALE,
                    331:        NFSERR_BADHANDLE,
                    332:        NFSERR_SERVERFAULT,
1.68      fvdl      333:        NFSERR_JUKEBOX,
1.25      fvdl      334:        0,
                    335: };
                    336:
1.90      jdolecek  337: static const short nfsv3err_create[] = {
1.25      fvdl      338:        NFSERR_IO,
                    339:        NFSERR_IO,
                    340:        NFSERR_ACCES,
                    341:        NFSERR_EXIST,
                    342:        NFSERR_NOTDIR,
                    343:        NFSERR_NOSPC,
                    344:        NFSERR_ROFS,
                    345:        NFSERR_NAMETOL,
                    346:        NFSERR_DQUOT,
                    347:        NFSERR_STALE,
                    348:        NFSERR_BADHANDLE,
                    349:        NFSERR_NOTSUPP,
                    350:        NFSERR_SERVERFAULT,
                    351:        0,
                    352: };
                    353:
1.90      jdolecek  354: static const short nfsv3err_mkdir[] = {
1.25      fvdl      355:        NFSERR_IO,
                    356:        NFSERR_IO,
                    357:        NFSERR_ACCES,
                    358:        NFSERR_EXIST,
                    359:        NFSERR_NOTDIR,
                    360:        NFSERR_NOSPC,
                    361:        NFSERR_ROFS,
                    362:        NFSERR_NAMETOL,
                    363:        NFSERR_DQUOT,
                    364:        NFSERR_STALE,
                    365:        NFSERR_BADHANDLE,
                    366:        NFSERR_NOTSUPP,
                    367:        NFSERR_SERVERFAULT,
                    368:        0,
                    369: };
                    370:
1.90      jdolecek  371: static const short nfsv3err_symlink[] = {
1.25      fvdl      372:        NFSERR_IO,
                    373:        NFSERR_IO,
                    374:        NFSERR_ACCES,
                    375:        NFSERR_EXIST,
                    376:        NFSERR_NOTDIR,
                    377:        NFSERR_NOSPC,
                    378:        NFSERR_ROFS,
                    379:        NFSERR_NAMETOL,
                    380:        NFSERR_DQUOT,
                    381:        NFSERR_STALE,
                    382:        NFSERR_BADHANDLE,
                    383:        NFSERR_NOTSUPP,
                    384:        NFSERR_SERVERFAULT,
                    385:        0,
                    386: };
                    387:
1.90      jdolecek  388: static const short nfsv3err_mknod[] = {
1.25      fvdl      389:        NFSERR_IO,
                    390:        NFSERR_IO,
                    391:        NFSERR_ACCES,
                    392:        NFSERR_EXIST,
                    393:        NFSERR_NOTDIR,
                    394:        NFSERR_NOSPC,
                    395:        NFSERR_ROFS,
                    396:        NFSERR_NAMETOL,
                    397:        NFSERR_DQUOT,
                    398:        NFSERR_STALE,
                    399:        NFSERR_BADHANDLE,
                    400:        NFSERR_NOTSUPP,
                    401:        NFSERR_SERVERFAULT,
                    402:        NFSERR_BADTYPE,
                    403:        0,
                    404: };
                    405:
1.90      jdolecek  406: static const short nfsv3err_remove[] = {
1.25      fvdl      407:        NFSERR_IO,
                    408:        NFSERR_NOENT,
                    409:        NFSERR_IO,
                    410:        NFSERR_ACCES,
                    411:        NFSERR_NOTDIR,
                    412:        NFSERR_ROFS,
                    413:        NFSERR_NAMETOL,
                    414:        NFSERR_STALE,
                    415:        NFSERR_BADHANDLE,
                    416:        NFSERR_SERVERFAULT,
                    417:        0,
                    418: };
                    419:
1.90      jdolecek  420: static const short nfsv3err_rmdir[] = {
1.25      fvdl      421:        NFSERR_IO,
                    422:        NFSERR_NOENT,
                    423:        NFSERR_IO,
                    424:        NFSERR_ACCES,
                    425:        NFSERR_EXIST,
                    426:        NFSERR_NOTDIR,
                    427:        NFSERR_INVAL,
                    428:        NFSERR_ROFS,
                    429:        NFSERR_NAMETOL,
                    430:        NFSERR_NOTEMPTY,
                    431:        NFSERR_STALE,
                    432:        NFSERR_BADHANDLE,
                    433:        NFSERR_NOTSUPP,
                    434:        NFSERR_SERVERFAULT,
                    435:        0,
                    436: };
                    437:
1.90      jdolecek  438: static const short nfsv3err_rename[] = {
1.25      fvdl      439:        NFSERR_IO,
                    440:        NFSERR_NOENT,
                    441:        NFSERR_IO,
                    442:        NFSERR_ACCES,
                    443:        NFSERR_EXIST,
                    444:        NFSERR_XDEV,
                    445:        NFSERR_NOTDIR,
                    446:        NFSERR_ISDIR,
                    447:        NFSERR_INVAL,
                    448:        NFSERR_NOSPC,
                    449:        NFSERR_ROFS,
                    450:        NFSERR_MLINK,
                    451:        NFSERR_NAMETOL,
                    452:        NFSERR_NOTEMPTY,
                    453:        NFSERR_DQUOT,
                    454:        NFSERR_STALE,
                    455:        NFSERR_BADHANDLE,
                    456:        NFSERR_NOTSUPP,
                    457:        NFSERR_SERVERFAULT,
                    458:        0,
                    459: };
                    460:
1.90      jdolecek  461: static const short nfsv3err_link[] = {
1.25      fvdl      462:        NFSERR_IO,
                    463:        NFSERR_IO,
                    464:        NFSERR_ACCES,
                    465:        NFSERR_EXIST,
                    466:        NFSERR_XDEV,
                    467:        NFSERR_NOTDIR,
                    468:        NFSERR_INVAL,
                    469:        NFSERR_NOSPC,
                    470:        NFSERR_ROFS,
                    471:        NFSERR_MLINK,
                    472:        NFSERR_NAMETOL,
                    473:        NFSERR_DQUOT,
                    474:        NFSERR_STALE,
                    475:        NFSERR_BADHANDLE,
                    476:        NFSERR_NOTSUPP,
                    477:        NFSERR_SERVERFAULT,
                    478:        0,
                    479: };
                    480:
1.90      jdolecek  481: static const short nfsv3err_readdir[] = {
1.25      fvdl      482:        NFSERR_IO,
                    483:        NFSERR_IO,
                    484:        NFSERR_ACCES,
                    485:        NFSERR_NOTDIR,
                    486:        NFSERR_STALE,
                    487:        NFSERR_BADHANDLE,
                    488:        NFSERR_BAD_COOKIE,
                    489:        NFSERR_TOOSMALL,
                    490:        NFSERR_SERVERFAULT,
                    491:        0,
                    492: };
                    493:
1.90      jdolecek  494: static const short nfsv3err_readdirplus[] = {
1.25      fvdl      495:        NFSERR_IO,
                    496:        NFSERR_IO,
                    497:        NFSERR_ACCES,
                    498:        NFSERR_NOTDIR,
                    499:        NFSERR_STALE,
                    500:        NFSERR_BADHANDLE,
                    501:        NFSERR_BAD_COOKIE,
                    502:        NFSERR_NOTSUPP,
                    503:        NFSERR_TOOSMALL,
                    504:        NFSERR_SERVERFAULT,
                    505:        0,
                    506: };
                    507:
1.90      jdolecek  508: static const short nfsv3err_fsstat[] = {
1.25      fvdl      509:        NFSERR_IO,
                    510:        NFSERR_IO,
                    511:        NFSERR_STALE,
                    512:        NFSERR_BADHANDLE,
                    513:        NFSERR_SERVERFAULT,
                    514:        0,
                    515: };
                    516:
1.90      jdolecek  517: static const short nfsv3err_fsinfo[] = {
1.25      fvdl      518:        NFSERR_STALE,
                    519:        NFSERR_STALE,
                    520:        NFSERR_BADHANDLE,
                    521:        NFSERR_SERVERFAULT,
                    522:        0,
                    523: };
                    524:
1.90      jdolecek  525: static const short nfsv3err_pathconf[] = {
1.25      fvdl      526:        NFSERR_STALE,
                    527:        NFSERR_STALE,
                    528:        NFSERR_BADHANDLE,
                    529:        NFSERR_SERVERFAULT,
                    530:        0,
                    531: };
                    532:
1.90      jdolecek  533: static const short nfsv3err_commit[] = {
1.25      fvdl      534:        NFSERR_IO,
                    535:        NFSERR_IO,
                    536:        NFSERR_STALE,
                    537:        NFSERR_BADHANDLE,
                    538:        NFSERR_SERVERFAULT,
                    539:        0,
                    540: };
                    541:
1.90      jdolecek  542: static const short * const nfsrv_v3errmap[] = {
1.25      fvdl      543:        nfsv3err_null,
                    544:        nfsv3err_getattr,
                    545:        nfsv3err_setattr,
                    546:        nfsv3err_lookup,
                    547:        nfsv3err_access,
                    548:        nfsv3err_readlink,
                    549:        nfsv3err_read,
                    550:        nfsv3err_write,
                    551:        nfsv3err_create,
                    552:        nfsv3err_mkdir,
                    553:        nfsv3err_symlink,
                    554:        nfsv3err_mknod,
                    555:        nfsv3err_remove,
                    556:        nfsv3err_rmdir,
                    557:        nfsv3err_rename,
                    558:        nfsv3err_link,
                    559:        nfsv3err_readdir,
                    560:        nfsv3err_readdirplus,
                    561:        nfsv3err_fsstat,
                    562:        nfsv3err_fsinfo,
                    563:        nfsv3err_pathconf,
                    564:        nfsv3err_commit,
                    565: };
                    566:
1.12      mycroft   567: extern struct nfsrtt nfsrtt;
1.25      fvdl      568: extern struct nfsnodehashhead *nfsnodehashtbl;
                    569: extern u_long nfsnodehash;
1.1       cgd       570:
1.46      fvdl      571: u_long nfsdirhashmask;
1.18      mycroft   572:
1.43      fvdl      573: int nfs_webnamei __P((struct nameidata *, struct vnode *, struct proc *));
                    574:
1.1       cgd       575: /*
                    576:  * Create the header for an rpc request packet
                    577:  * The hsiz is the size of the rest of the nfs request header.
                    578:  * (just used to decide if a cluster is a good idea)
                    579:  */
1.12      mycroft   580: struct mbuf *
1.149.2.5  yamt      581: nfsm_reqh(struct nfsnode *np, u_long procid, int hsiz, char **bposp)
1.12      mycroft   582: {
1.75      augustss  583:        struct mbuf *mb;
1.149.2.5  yamt      584:        char *bpos;
1.12      mycroft   585:
1.109     matt      586:        mb = m_get(M_WAIT, MT_DATA);
                    587:        MCLAIM(mb, &nfs_mowner);
1.12      mycroft   588:        if (hsiz >= MINCLSIZE)
1.109     matt      589:                m_clget(mb, M_WAIT);
1.12      mycroft   590:        mb->m_len = 0;
1.149.2.5  yamt      591:        bpos = mtod(mb, void *);
1.148     perry     592:
1.12      mycroft   593:        /* Finally, return values */
                    594:        *bposp = bpos;
                    595:        return (mb);
                    596: }
                    597:
                    598: /*
                    599:  * Build the RPC header and fill in the authorization info.
                    600:  * The authorization string argument is only used when the credentials
                    601:  * come from outside of the kernel.
                    602:  * Returns the head of the mbuf list.
                    603:  */
                    604: struct mbuf *
1.25      fvdl      605: nfsm_rpchead(cr, nmflag, procid, auth_type, auth_len, auth_str, verf_len,
                    606:        verf_str, mrest, mrest_len, mbp, xidp)
1.149.2.2  yamt      607:        kauth_cred_t cr;
1.25      fvdl      608:        int nmflag;
1.12      mycroft   609:        int procid;
                    610:        int auth_type;
                    611:        int auth_len;
                    612:        char *auth_str;
1.25      fvdl      613:        int verf_len;
                    614:        char *verf_str;
1.12      mycroft   615:        struct mbuf *mrest;
                    616:        int mrest_len;
                    617:        struct mbuf **mbp;
1.22      cgd       618:        u_int32_t *xidp;
1.1       cgd       619: {
1.75      augustss  620:        struct mbuf *mb;
                    621:        u_int32_t *tl;
1.149.2.5  yamt      622:        char *bpos;
1.75      augustss  623:        int i;
1.109     matt      624:        struct mbuf *mreq;
1.12      mycroft   625:        int siz, grpsiz, authsiz;
1.1       cgd       626:
1.12      mycroft   627:        authsiz = nfsm_rndup(auth_len);
1.109     matt      628:        mb = m_gethdr(M_WAIT, MT_DATA);
                    629:        MCLAIM(mb, &nfs_mowner);
1.25      fvdl      630:        if ((authsiz + 10 * NFSX_UNSIGNED) >= MINCLSIZE) {
1.109     matt      631:                m_clget(mb, M_WAIT);
1.25      fvdl      632:        } else if ((authsiz + 10 * NFSX_UNSIGNED) < MHLEN) {
                    633:                MH_ALIGN(mb, authsiz + 10 * NFSX_UNSIGNED);
1.12      mycroft   634:        } else {
1.25      fvdl      635:                MH_ALIGN(mb, 8 * NFSX_UNSIGNED);
1.1       cgd       636:        }
1.12      mycroft   637:        mb->m_len = 0;
                    638:        mreq = mb;
1.149.2.5  yamt      639:        bpos = mtod(mb, void *);
1.12      mycroft   640:
                    641:        /*
                    642:         * First the RPC header.
                    643:         */
1.25      fvdl      644:        nfsm_build(tl, u_int32_t *, 8 * NFSX_UNSIGNED);
1.30      fvdl      645:
1.126     yamt      646:        *tl++ = *xidp = nfs_getxid();
1.1       cgd       647:        *tl++ = rpc_call;
                    648:        *tl++ = rpc_vers;
1.149.2.3  yamt      649:        *tl++ = txdr_unsigned(NFS_PROG);
                    650:        if (nmflag & NFSMNT_NFSV3)
                    651:                *tl++ = txdr_unsigned(NFS_VER3);
                    652:        else
                    653:                *tl++ = txdr_unsigned(NFS_VER2);
1.25      fvdl      654:        if (nmflag & NFSMNT_NFSV3)
                    655:                *tl++ = txdr_unsigned(procid);
                    656:        else
                    657:                *tl++ = txdr_unsigned(nfsv2_procid[procid]);
1.12      mycroft   658:
                    659:        /*
                    660:         * And then the authorization cred.
                    661:         */
                    662:        *tl++ = txdr_unsigned(auth_type);
                    663:        *tl = txdr_unsigned(authsiz);
                    664:        switch (auth_type) {
                    665:        case RPCAUTH_UNIX:
1.22      cgd       666:                nfsm_build(tl, u_int32_t *, auth_len);
1.12      mycroft   667:                *tl++ = 0;              /* stamp ?? */
                    668:                *tl++ = 0;              /* NULL hostname */
1.149.2.2  yamt      669:                *tl++ = txdr_unsigned(kauth_cred_geteuid(cr));
                    670:                *tl++ = txdr_unsigned(kauth_cred_getegid(cr));
1.12      mycroft   671:                grpsiz = (auth_len >> 2) - 5;
                    672:                *tl++ = txdr_unsigned(grpsiz);
1.20      mycroft   673:                for (i = 0; i < grpsiz; i++)
1.149.2.2  yamt      674:                        *tl++ = txdr_unsigned(kauth_cred_group(cr, i)); /* XXX elad review */
1.12      mycroft   675:                break;
1.25      fvdl      676:        case RPCAUTH_KERB4:
1.12      mycroft   677:                siz = auth_len;
                    678:                while (siz > 0) {
                    679:                        if (M_TRAILINGSPACE(mb) == 0) {
1.109     matt      680:                                struct mbuf *mb2;
                    681:                                mb2 = m_get(M_WAIT, MT_DATA);
                    682:                                MCLAIM(mb2, &nfs_mowner);
1.12      mycroft   683:                                if (siz >= MINCLSIZE)
1.109     matt      684:                                        m_clget(mb2, M_WAIT);
1.12      mycroft   685:                                mb->m_next = mb2;
                    686:                                mb = mb2;
                    687:                                mb->m_len = 0;
1.149.2.5  yamt      688:                                bpos = mtod(mb, void *);
1.12      mycroft   689:                        }
                    690:                        i = min(siz, M_TRAILINGSPACE(mb));
1.63      perry     691:                        memcpy(bpos, auth_str, i);
1.12      mycroft   692:                        mb->m_len += i;
                    693:                        auth_str += i;
                    694:                        bpos += i;
                    695:                        siz -= i;
                    696:                }
                    697:                if ((siz = (nfsm_rndup(auth_len) - auth_len)) > 0) {
                    698:                        for (i = 0; i < siz; i++)
                    699:                                *bpos++ = '\0';
                    700:                        mb->m_len += siz;
                    701:                }
                    702:                break;
                    703:        };
1.25      fvdl      704:
                    705:        /*
                    706:         * And the verifier...
                    707:         */
                    708:        nfsm_build(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
                    709:        if (verf_str) {
                    710:                *tl++ = txdr_unsigned(RPCAUTH_KERB4);
                    711:                *tl = txdr_unsigned(verf_len);
                    712:                siz = verf_len;
                    713:                while (siz > 0) {
                    714:                        if (M_TRAILINGSPACE(mb) == 0) {
1.109     matt      715:                                struct mbuf *mb2;
                    716:                                mb2 = m_get(M_WAIT, MT_DATA);
                    717:                                MCLAIM(mb2, &nfs_mowner);
1.25      fvdl      718:                                if (siz >= MINCLSIZE)
1.109     matt      719:                                        m_clget(mb2, M_WAIT);
1.25      fvdl      720:                                mb->m_next = mb2;
                    721:                                mb = mb2;
                    722:                                mb->m_len = 0;
1.149.2.5  yamt      723:                                bpos = mtod(mb, void *);
1.25      fvdl      724:                        }
                    725:                        i = min(siz, M_TRAILINGSPACE(mb));
1.63      perry     726:                        memcpy(bpos, verf_str, i);
1.25      fvdl      727:                        mb->m_len += i;
                    728:                        verf_str += i;
                    729:                        bpos += i;
                    730:                        siz -= i;
                    731:                }
                    732:                if ((siz = (nfsm_rndup(verf_len) - verf_len)) > 0) {
                    733:                        for (i = 0; i < siz; i++)
                    734:                                *bpos++ = '\0';
                    735:                        mb->m_len += siz;
                    736:                }
                    737:        } else {
                    738:                *tl++ = txdr_unsigned(RPCAUTH_NULL);
                    739:                *tl = 0;
                    740:        }
1.12      mycroft   741:        mb->m_next = mrest;
1.25      fvdl      742:        mreq->m_pkthdr.len = authsiz + 10 * NFSX_UNSIGNED + mrest_len;
1.12      mycroft   743:        mreq->m_pkthdr.rcvif = (struct ifnet *)0;
                    744:        *mbp = mb;
1.1       cgd       745:        return (mreq);
                    746: }
                    747:
                    748: /*
                    749:  * copies mbuf chain to the uio scatter/gather list
                    750:  */
1.24      christos  751: int
1.1       cgd       752: nfsm_mbuftouio(mrep, uiop, siz, dpos)
                    753:        struct mbuf **mrep;
1.75      augustss  754:        struct uio *uiop;
1.1       cgd       755:        int siz;
1.149.2.5  yamt      756:        char **dpos;
1.1       cgd       757: {
1.75      augustss  758:        char *mbufcp, *uiocp;
                    759:        int xfer, left, len;
                    760:        struct mbuf *mp;
1.1       cgd       761:        long uiosiz, rem;
                    762:        int error = 0;
                    763:
                    764:        mp = *mrep;
                    765:        mbufcp = *dpos;
1.149.2.5  yamt      766:        len = mtod(mp, char *) + mp->m_len - mbufcp;
1.1       cgd       767:        rem = nfsm_rndup(siz)-siz;
                    768:        while (siz > 0) {
                    769:                if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL)
                    770:                        return (EFBIG);
                    771:                left = uiop->uio_iov->iov_len;
                    772:                uiocp = uiop->uio_iov->iov_base;
                    773:                if (left > siz)
                    774:                        left = siz;
                    775:                uiosiz = left;
                    776:                while (left > 0) {
                    777:                        while (len == 0) {
                    778:                                mp = mp->m_next;
                    779:                                if (mp == NULL)
                    780:                                        return (EBADRPC);
1.149.2.5  yamt      781:                                mbufcp = mtod(mp, void *);
1.1       cgd       782:                                len = mp->m_len;
                    783:                        }
                    784:                        xfer = (left > len) ? len : left;
1.149.2.2  yamt      785:                        error = copyout_vmspace(uiop->uio_vmspace, mbufcp,
                    786:                            uiocp, xfer);
                    787:                        if (error) {
                    788:                                return error;
                    789:                        }
1.1       cgd       790:                        left -= xfer;
                    791:                        len -= xfer;
                    792:                        mbufcp += xfer;
                    793:                        uiocp += xfer;
                    794:                        uiop->uio_offset += xfer;
                    795:                        uiop->uio_resid -= xfer;
                    796:                }
                    797:                if (uiop->uio_iov->iov_len <= siz) {
                    798:                        uiop->uio_iovcnt--;
                    799:                        uiop->uio_iov++;
                    800:                } else {
1.95      lukem     801:                        uiop->uio_iov->iov_base =
1.149.2.5  yamt      802:                            (char *)uiop->uio_iov->iov_base + uiosiz;
1.1       cgd       803:                        uiop->uio_iov->iov_len -= uiosiz;
                    804:                }
                    805:                siz -= uiosiz;
                    806:        }
                    807:        *dpos = mbufcp;
                    808:        *mrep = mp;
                    809:        if (rem > 0) {
                    810:                if (len < rem)
                    811:                        error = nfs_adv(mrep, dpos, rem, len);
                    812:                else
                    813:                        *dpos += rem;
                    814:        }
                    815:        return (error);
                    816: }
                    817:
                    818: /*
1.29      fvdl      819:  * copies a uio scatter/gather list to an mbuf chain.
                    820:  * NOTE: can ony handle iovcnt == 1
1.1       cgd       821:  */
1.24      christos  822: int
1.1       cgd       823: nfsm_uiotombuf(uiop, mq, siz, bpos)
1.75      augustss  824:        struct uio *uiop;
1.1       cgd       825:        struct mbuf **mq;
                    826:        int siz;
1.149.2.5  yamt      827:        char **bpos;
1.1       cgd       828: {
1.75      augustss  829:        char *uiocp;
                    830:        struct mbuf *mp, *mp2;
                    831:        int xfer, left, mlen;
1.1       cgd       832:        int uiosiz, clflg, rem;
                    833:        char *cp;
1.149.2.2  yamt      834:        int error;
1.1       cgd       835:
1.29      fvdl      836: #ifdef DIAGNOSTIC
                    837:        if (uiop->uio_iovcnt != 1)
                    838:                panic("nfsm_uiotombuf: iovcnt != 1");
                    839: #endif
                    840:
1.1       cgd       841:        if (siz > MLEN)         /* or should it >= MCLBYTES ?? */
                    842:                clflg = 1;
                    843:        else
                    844:                clflg = 0;
                    845:        rem = nfsm_rndup(siz)-siz;
1.12      mycroft   846:        mp = mp2 = *mq;
1.1       cgd       847:        while (siz > 0) {
                    848:                left = uiop->uio_iov->iov_len;
                    849:                uiocp = uiop->uio_iov->iov_base;
                    850:                if (left > siz)
                    851:                        left = siz;
                    852:                uiosiz = left;
                    853:                while (left > 0) {
1.12      mycroft   854:                        mlen = M_TRAILINGSPACE(mp);
                    855:                        if (mlen == 0) {
1.109     matt      856:                                mp = m_get(M_WAIT, MT_DATA);
                    857:                                MCLAIM(mp, &nfs_mowner);
1.12      mycroft   858:                                if (clflg)
1.109     matt      859:                                        m_clget(mp, M_WAIT);
1.12      mycroft   860:                                mp->m_len = 0;
                    861:                                mp2->m_next = mp;
                    862:                                mp2 = mp;
                    863:                                mlen = M_TRAILINGSPACE(mp);
                    864:                        }
                    865:                        xfer = (left > mlen) ? mlen : left;
1.149.2.5  yamt      866:                        cp = mtod(mp, char *) + mp->m_len;
1.149.2.2  yamt      867:                        error = copyin_vmspace(uiop->uio_vmspace, uiocp, cp,
                    868:                            xfer);
                    869:                        if (error) {
                    870:                                /* XXX */
                    871:                        }
1.12      mycroft   872:                        mp->m_len += xfer;
1.1       cgd       873:                        left -= xfer;
                    874:                        uiocp += xfer;
                    875:                        uiop->uio_offset += xfer;
                    876:                        uiop->uio_resid -= xfer;
                    877:                }
1.149.2.5  yamt      878:                uiop->uio_iov->iov_base = (char *)uiop->uio_iov->iov_base +
1.95      lukem     879:                    uiosiz;
1.29      fvdl      880:                uiop->uio_iov->iov_len -= uiosiz;
1.1       cgd       881:                siz -= uiosiz;
                    882:        }
                    883:        if (rem > 0) {
1.12      mycroft   884:                if (rem > M_TRAILINGSPACE(mp)) {
1.109     matt      885:                        mp = m_get(M_WAIT, MT_DATA);
                    886:                        MCLAIM(mp, &nfs_mowner);
1.1       cgd       887:                        mp->m_len = 0;
                    888:                        mp2->m_next = mp;
                    889:                }
1.149.2.5  yamt      890:                cp = mtod(mp, char *) + mp->m_len;
1.1       cgd       891:                for (left = 0; left < rem; left++)
                    892:                        *cp++ = '\0';
                    893:                mp->m_len += rem;
                    894:                *bpos = cp;
                    895:        } else
1.149.2.5  yamt      896:                *bpos = mtod(mp, char *) + mp->m_len;
1.1       cgd       897:        *mq = mp;
                    898:        return (0);
                    899: }
                    900:
                    901: /*
1.39      fvdl      902:  * Get at least "siz" bytes of correctly aligned data.
                    903:  * When called the mbuf pointers are not necessarily correct,
                    904:  * dsosp points to what ought to be in m_data and left contains
1.148     perry     905:  * what ought to be in m_len.
1.12      mycroft   906:  * This is used by the macros nfsm_dissect and nfsm_dissecton for tough
1.1       cgd       907:  * cases. (The macros use the vars. dpos and dpos2)
                    908:  */
1.24      christos  909: int
1.12      mycroft   910: nfsm_disct(mdp, dposp, siz, left, cp2)
1.1       cgd       911:        struct mbuf **mdp;
1.149.2.5  yamt      912:        char **dposp;
1.1       cgd       913:        int siz;
                    914:        int left;
1.149.2.5  yamt      915:        char **cp2;
1.1       cgd       916: {
1.75      augustss  917:        struct mbuf *m1, *m2;
1.39      fvdl      918:        struct mbuf *havebuf = NULL;
1.149.2.5  yamt      919:        char *src = *dposp;
                    920:        char *dst;
1.39      fvdl      921:        int len;
                    922:
                    923: #ifdef DEBUG
                    924:        if (left < 0)
1.148     perry     925:                panic("nfsm_disct: left < 0");
1.39      fvdl      926: #endif
                    927:        m1 = *mdp;
                    928:        /*
                    929:         * Skip through the mbuf chain looking for an mbuf with
                    930:         * some data. If the first mbuf found has enough data
                    931:         * and it is correctly aligned return it.
                    932:         */
1.1       cgd       933:        while (left == 0) {
1.39      fvdl      934:                havebuf = m1;
                    935:                *mdp = m1 = m1->m_next;
                    936:                if (m1 == NULL)
1.1       cgd       937:                        return (EBADRPC);
1.149.2.5  yamt      938:                src = mtod(m1, void *);
1.39      fvdl      939:                left = m1->m_len;
                    940:                /*
                    941:                 * If we start a new mbuf and it is big enough
                    942:                 * and correctly aligned just return it, don't
                    943:                 * do any pull up.
                    944:                 */
                    945:                if (left >= siz && nfsm_aligned(src)) {
                    946:                        *cp2 = src;
                    947:                        *dposp = src + siz;
                    948:                        return (0);
                    949:                }
1.1       cgd       950:        }
1.149.2.1  yamt      951:        if ((m1->m_flags & M_EXT) != 0) {
                    952:                if (havebuf && M_TRAILINGSPACE(havebuf) >= siz &&
                    953:                    nfsm_aligned(mtod(havebuf, char *) + havebuf->m_len)) {
                    954:                        /*
                    955:                         * If the first mbuf with data has external data
                    956:                         * and there is a previous mbuf with some trailing
                    957:                         * space, use it to move the data into.
1.39      fvdl      958:                         */
                    959:                        m2 = m1;
                    960:                        *mdp = m1 = havebuf;
1.149.2.1  yamt      961:                        *cp2 = mtod(m1, char *) + m1->m_len;
                    962:                } else if (havebuf) {
1.39      fvdl      963:                        /*
                    964:                         * If the first mbuf has a external data
                    965:                         * and there is no previous empty mbuf
                    966:                         * allocate a new mbuf and move the external
1.148     perry     967:                         * data to the new mbuf. Also make the first
1.39      fvdl      968:                         * mbuf look empty.
                    969:                         */
1.149.2.1  yamt      970:                        m2 = m1;
                    971:                        *mdp = m1 = m_get(M_WAIT, MT_DATA);
                    972:                        MCLAIM(m1, m2->m_owner);
                    973:                        if ((m2->m_flags & M_PKTHDR) != 0) {
                    974:                                /* XXX MOVE */
                    975:                                M_COPY_PKTHDR(m1, m2);
                    976:                                m_tag_delete_chain(m2, NULL);
                    977:                                m2->m_flags &= ~M_PKTHDR;
                    978:                        }
                    979:                        if (havebuf) {
                    980:                                havebuf->m_next = m1;
                    981:                        }
                    982:                        m1->m_next = m2;
                    983:                        MRESETDATA(m1);
                    984:                        m1->m_len = 0;
1.39      fvdl      985:                        m2->m_data = src;
                    986:                        m2->m_len = left;
1.149.2.1  yamt      987:                        *cp2 = mtod(m1, char *);
                    988:                } else {
                    989:                        struct mbuf **nextp = &m1->m_next;
                    990:
                    991:                        m1->m_len -= left;
                    992:                        do {
                    993:                                m2 = m_get(M_WAIT, MT_DATA);
                    994:                                MCLAIM(m2, m1->m_owner);
                    995:                                if (left >= MINCLSIZE) {
                    996:                                        MCLGET(m2, M_WAIT);
                    997:                                }
                    998:                                m2->m_next = *nextp;
                    999:                                *nextp = m2;
                   1000:                                nextp = &m2->m_next;
                   1001:                                len = (m2->m_flags & M_EXT) != 0 ?
                   1002:                                    MCLBYTES : MLEN;
                   1003:                                if (len > left) {
                   1004:                                        len = left;
                   1005:                                }
                   1006:                                memcpy(mtod(m2, char *), src, len);
                   1007:                                m2->m_len = len;
                   1008:                                src += len;
                   1009:                                left -= len;
                   1010:                        } while (left > 0);
                   1011:                        *mdp = m1 = m1->m_next;
                   1012:                        m2 = m1->m_next;
                   1013:                        *cp2 = mtod(m1, char *);
1.1       cgd      1014:                }
1.39      fvdl     1015:        } else {
                   1016:                /*
                   1017:                 * If the first mbuf has no external data
                   1018:                 * move the data to the front of the mbuf.
                   1019:                 */
1.149.2.1  yamt     1020:                MRESETDATA(m1);
                   1021:                dst = mtod(m1, char *);
                   1022:                if (dst != src) {
1.63      perry    1023:                        memmove(dst, src, left);
1.149.2.1  yamt     1024:                }
1.39      fvdl     1025:                m1->m_len = left;
                   1026:                m2 = m1->m_next;
1.149.2.1  yamt     1027:                *cp2 = m1->m_data;
1.1       cgd      1028:        }
1.149.2.1  yamt     1029:        *dposp = *cp2 + siz;
1.39      fvdl     1030:        /*
                   1031:         * Loop through mbufs pulling data up into first mbuf until
                   1032:         * the first mbuf is full or there is no more data to
                   1033:         * pullup.
                   1034:         */
1.149.2.1  yamt     1035:        dst = mtod(m1, char *) + m1->m_len;
1.129     itojun   1036:        while ((len = M_TRAILINGSPACE(m1)) != 0 && m2) {
1.149.2.1  yamt     1037:                if ((len = min(len, m2->m_len)) != 0) {
                   1038:                        memcpy(dst, mtod(m2, char *), len);
                   1039:                }
1.39      fvdl     1040:                m1->m_len += len;
                   1041:                dst += len;
                   1042:                m2->m_data += len;
                   1043:                m2->m_len -= len;
                   1044:                m2 = m2->m_next;
                   1045:        }
                   1046:        if (m1->m_len < siz)
                   1047:                return (EBADRPC);
1.1       cgd      1048:        return (0);
                   1049: }
                   1050:
                   1051: /*
                   1052:  * Advance the position in the mbuf chain.
                   1053:  */
1.24      christos 1054: int
1.1       cgd      1055: nfs_adv(mdp, dposp, offs, left)
                   1056:        struct mbuf **mdp;
1.149.2.5  yamt     1057:        char **dposp;
1.1       cgd      1058:        int offs;
                   1059:        int left;
                   1060: {
1.75      augustss 1061:        struct mbuf *m;
                   1062:        int s;
1.1       cgd      1063:
                   1064:        m = *mdp;
                   1065:        s = left;
                   1066:        while (s < offs) {
                   1067:                offs -= s;
                   1068:                m = m->m_next;
                   1069:                if (m == NULL)
                   1070:                        return (EBADRPC);
                   1071:                s = m->m_len;
                   1072:        }
                   1073:        *mdp = m;
1.149.2.5  yamt     1074:        *dposp = mtod(m, char *) + offs;
1.1       cgd      1075:        return (0);
                   1076: }
                   1077:
                   1078: /*
                   1079:  * Copy a string into mbufs for the hard cases...
                   1080:  */
1.24      christos 1081: int
1.1       cgd      1082: nfsm_strtmbuf(mb, bpos, cp, siz)
                   1083:        struct mbuf **mb;
                   1084:        char **bpos;
1.33      cgd      1085:        const char *cp;
1.1       cgd      1086:        long siz;
                   1087: {
1.75      augustss 1088:        struct mbuf *m1 = NULL, *m2;
1.1       cgd      1089:        long left, xfer, len, tlen;
1.22      cgd      1090:        u_int32_t *tl;
1.1       cgd      1091:        int putsize;
                   1092:
                   1093:        putsize = 1;
                   1094:        m2 = *mb;
1.12      mycroft  1095:        left = M_TRAILINGSPACE(m2);
1.1       cgd      1096:        if (left > 0) {
1.22      cgd      1097:                tl = ((u_int32_t *)(*bpos));
1.1       cgd      1098:                *tl++ = txdr_unsigned(siz);
                   1099:                putsize = 0;
                   1100:                left -= NFSX_UNSIGNED;
                   1101:                m2->m_len += NFSX_UNSIGNED;
                   1102:                if (left > 0) {
1.149.2.5  yamt     1103:                        memcpy((void *) tl, cp, left);
1.1       cgd      1104:                        siz -= left;
                   1105:                        cp += left;
                   1106:                        m2->m_len += left;
                   1107:                        left = 0;
                   1108:                }
                   1109:        }
1.12      mycroft  1110:        /* Loop around adding mbufs */
1.1       cgd      1111:        while (siz > 0) {
1.109     matt     1112:                m1 = m_get(M_WAIT, MT_DATA);
                   1113:                MCLAIM(m1, &nfs_mowner);
1.1       cgd      1114:                if (siz > MLEN)
1.109     matt     1115:                        m_clget(m1, M_WAIT);
1.1       cgd      1116:                m1->m_len = NFSMSIZ(m1);
                   1117:                m2->m_next = m1;
                   1118:                m2 = m1;
1.22      cgd      1119:                tl = mtod(m1, u_int32_t *);
1.1       cgd      1120:                tlen = 0;
                   1121:                if (putsize) {
                   1122:                        *tl++ = txdr_unsigned(siz);
                   1123:                        m1->m_len -= NFSX_UNSIGNED;
                   1124:                        tlen = NFSX_UNSIGNED;
                   1125:                        putsize = 0;
                   1126:                }
                   1127:                if (siz < m1->m_len) {
                   1128:                        len = nfsm_rndup(siz);
                   1129:                        xfer = siz;
                   1130:                        if (xfer < len)
                   1131:                                *(tl+(xfer>>2)) = 0;
                   1132:                } else {
                   1133:                        xfer = len = m1->m_len;
                   1134:                }
1.149.2.5  yamt     1135:                memcpy((void *) tl, cp, xfer);
1.1       cgd      1136:                m1->m_len = len+tlen;
                   1137:                siz -= xfer;
                   1138:                cp += xfer;
                   1139:        }
                   1140:        *mb = m1;
1.149.2.5  yamt     1141:        *bpos = mtod(m1, char *) + m1->m_len;
1.1       cgd      1142:        return (0);
                   1143: }
                   1144:
1.49      fvdl     1145: /*
                   1146:  * Directory caching routines. They work as follows:
                   1147:  * - a cache is maintained per VDIR nfsnode.
                   1148:  * - for each offset cookie that is exported to userspace, and can
                   1149:  *   thus be thrown back at us as an offset to VOP_READDIR, store
                   1150:  *   information in the cache.
                   1151:  * - cached are:
                   1152:  *   - cookie itself
                   1153:  *   - blocknumber (essentially just a search key in the buffer cache)
                   1154:  *   - entry number in block.
                   1155:  *   - offset cookie of block in which this entry is stored
                   1156:  *   - 32 bit cookie if NFSMNT_XLATECOOKIE is used.
                   1157:  * - entries are looked up in a hash table
                   1158:  * - also maintained is an LRU list of entries, used to determine
                   1159:  *   which ones to delete if the cache grows too large.
                   1160:  * - if 32 <-> 64 translation mode is requested for a filesystem,
                   1161:  *   the cache also functions as a translation table
                   1162:  * - in the translation case, invalidating the cache does not mean
                   1163:  *   flushing it, but just marking entries as invalid, except for
                   1164:  *   the <64bit cookie, 32bitcookie> pair which is still valid, to
                   1165:  *   still be able to use the cache as a translation table.
                   1166:  * - 32 bit cookies are uniquely created by combining the hash table
                   1167:  *   entry value, and one generation count per hash table entry,
                   1168:  *   incremented each time an entry is appended to the chain.
                   1169:  * - the cache is invalidated each time a direcory is modified
                   1170:  * - sanity checks are also done; if an entry in a block turns
                   1171:  *   out not to have a matching cookie, the cache is invalidated
                   1172:  *   and a new block starting from the wanted offset is fetched from
                   1173:  *   the server.
                   1174:  * - directory entries as read from the server are extended to contain
                   1175:  *   the 64bit and, optionally, the 32bit cookies, for sanity checking
                   1176:  *   the cache and exporting them to userspace through the cookie
                   1177:  *   argument to VOP_READDIR.
                   1178:  */
                   1179:
1.46      fvdl     1180: u_long
                   1181: nfs_dirhash(off)
                   1182:        off_t off;
                   1183: {
                   1184:        int i;
                   1185:        char *cp = (char *)&off;
                   1186:        u_long sum = 0L;
                   1187:
                   1188:        for (i = 0 ; i < sizeof (off); i++)
                   1189:                sum += *cp++;
                   1190:
                   1191:        return sum;
                   1192: }
                   1193:
1.135     yamt     1194: #define        _NFSDC_MTX(np)          (&NFSTOV(np)->v_interlock)
1.149.2.8! yamt     1195: #define        NFSDC_LOCK(np)          mutex_enter(_NFSDC_MTX(np))
        !          1196: #define        NFSDC_UNLOCK(np)        mutex_exit(_NFSDC_MTX(np))
        !          1197: #define        NFSDC_ASSERT_LOCKED(np) KASSERT(mutex_owned(_NFSDC_MTX(np)))
1.135     yamt     1198:
1.49      fvdl     1199: void
                   1200: nfs_initdircache(vp)
                   1201:        struct vnode *vp;
                   1202: {
                   1203:        struct nfsnode *np = VTONFS(vp);
1.135     yamt     1204:        struct nfsdirhashhead *dircache;
1.120     yamt     1205:
1.135     yamt     1206:        dircache = hashinit(NFS_DIRHASHSIZ, HASH_LIST, M_NFSDIROFF,
                   1207:            M_WAITOK, &nfsdirhashmask);
1.49      fvdl     1208:
1.135     yamt     1209:        NFSDC_LOCK(np);
                   1210:        if (np->n_dircache == NULL) {
                   1211:                np->n_dircachesize = 0;
                   1212:                np->n_dircache = dircache;
                   1213:                dircache = NULL;
                   1214:                TAILQ_INIT(&np->n_dirchain);
                   1215:        }
                   1216:        NFSDC_UNLOCK(np);
                   1217:        if (dircache)
                   1218:                hashdone(dircache, M_NFSDIROFF);
1.120     yamt     1219: }
                   1220:
                   1221: void
                   1222: nfs_initdirxlatecookie(vp)
                   1223:        struct vnode *vp;
                   1224: {
                   1225:        struct nfsnode *np = VTONFS(vp);
1.135     yamt     1226:        unsigned *dirgens;
1.120     yamt     1227:
                   1228:        KASSERT(VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_XLATECOOKIE);
                   1229:
1.149.2.8! yamt     1230:        dirgens = kmem_zalloc(NFS_DIRHASHSIZ * sizeof(unsigned), KM_SLEEP);
1.135     yamt     1231:        NFSDC_LOCK(np);
                   1232:        if (np->n_dirgens == NULL) {
                   1233:                np->n_dirgens = dirgens;
                   1234:                dirgens = NULL;
                   1235:        }
                   1236:        NFSDC_UNLOCK(np);
                   1237:        if (dirgens)
1.149.2.8! yamt     1238:                kmem_free(dirgens, NFS_DIRHASHSIZ * sizeof(unsigned));
1.135     yamt     1239: }
                   1240:
                   1241: static const struct nfsdircache dzero;
                   1242:
                   1243: static void nfs_unlinkdircache __P((struct nfsnode *np, struct nfsdircache *));
                   1244: static void nfs_putdircache_unlocked __P((struct nfsnode *,
                   1245:     struct nfsdircache *));
                   1246:
                   1247: static void
                   1248: nfs_unlinkdircache(np, ndp)
                   1249:        struct nfsnode *np;
                   1250:        struct nfsdircache *ndp;
                   1251: {
                   1252:
                   1253:        NFSDC_ASSERT_LOCKED(np);
                   1254:        KASSERT(ndp != &dzero);
                   1255:
                   1256:        if (LIST_NEXT(ndp, dc_hash) == (void *)-1)
                   1257:                return;
                   1258:
                   1259:        TAILQ_REMOVE(&np->n_dirchain, ndp, dc_chain);
                   1260:        LIST_REMOVE(ndp, dc_hash);
                   1261:        LIST_NEXT(ndp, dc_hash) = (void *)-1; /* mark as unlinked */
                   1262:
                   1263:        nfs_putdircache_unlocked(np, ndp);
                   1264: }
                   1265:
                   1266: void
                   1267: nfs_putdircache(np, ndp)
                   1268:        struct nfsnode *np;
                   1269:        struct nfsdircache *ndp;
                   1270: {
                   1271:        int ref;
                   1272:
                   1273:        if (ndp == &dzero)
                   1274:                return;
                   1275:
                   1276:        KASSERT(ndp->dc_refcnt > 0);
                   1277:        NFSDC_LOCK(np);
                   1278:        ref = --ndp->dc_refcnt;
                   1279:        NFSDC_UNLOCK(np);
                   1280:
                   1281:        if (ref == 0)
1.149.2.8! yamt     1282:                kmem_free(ndp, sizeof(*ndp));
1.49      fvdl     1283: }
                   1284:
1.135     yamt     1285: static void
1.149.2.3  yamt     1286: nfs_putdircache_unlocked(struct nfsnode *np, struct nfsdircache *ndp)
1.135     yamt     1287: {
                   1288:        int ref;
                   1289:
                   1290:        NFSDC_ASSERT_LOCKED(np);
                   1291:
                   1292:        if (ndp == &dzero)
                   1293:                return;
                   1294:
                   1295:        KASSERT(ndp->dc_refcnt > 0);
                   1296:        ref = --ndp->dc_refcnt;
                   1297:        if (ref == 0)
1.149.2.8! yamt     1298:                kmem_free(ndp, sizeof(*ndp));
1.135     yamt     1299: }
1.46      fvdl     1300:
                   1301: struct nfsdircache *
1.49      fvdl     1302: nfs_searchdircache(vp, off, do32, hashent)
1.46      fvdl     1303:        struct vnode *vp;
                   1304:        off_t off;
1.49      fvdl     1305:        int do32;
                   1306:        int *hashent;
                   1307: {
                   1308:        struct nfsdirhashhead *ndhp;
                   1309:        struct nfsdircache *ndp = NULL;
                   1310:        struct nfsnode *np = VTONFS(vp);
                   1311:        unsigned ent;
                   1312:
                   1313:        /*
                   1314:         * Zero is always a valid cookie.
                   1315:         */
                   1316:        if (off == 0)
1.149     christos 1317:                /* XXXUNCONST */
                   1318:                return (struct nfsdircache *)__UNCONST(&dzero);
1.49      fvdl     1319:
1.134     yamt     1320:        if (!np->n_dircache)
                   1321:                return NULL;
                   1322:
1.49      fvdl     1323:        /*
                   1324:         * We use a 32bit cookie as search key, directly reconstruct
                   1325:         * the hashentry. Else use the hashfunction.
                   1326:         */
                   1327:        if (do32) {
                   1328:                ent = (u_int32_t)off >> 24;
                   1329:                if (ent >= NFS_DIRHASHSIZ)
                   1330:                        return NULL;
                   1331:                ndhp = &np->n_dircache[ent];
                   1332:        } else {
                   1333:                ndhp = NFSDIRHASH(np, off);
                   1334:        }
                   1335:
                   1336:        if (hashent)
                   1337:                *hashent = (int)(ndhp - np->n_dircache);
1.135     yamt     1338:
                   1339:        NFSDC_LOCK(np);
1.49      fvdl     1340:        if (do32) {
1.113     yamt     1341:                LIST_FOREACH(ndp, ndhp, dc_hash) {
1.49      fvdl     1342:                        if (ndp->dc_cookie32 == (u_int32_t)off) {
                   1343:                                /*
                   1344:                                 * An invalidated entry will become the
                   1345:                                 * start of a new block fetched from
                   1346:                                 * the server.
                   1347:                                 */
1.135     yamt     1348:                                if (ndp->dc_flags & NFSDC_INVALID) {
1.49      fvdl     1349:                                        ndp->dc_blkcookie = ndp->dc_cookie;
                   1350:                                        ndp->dc_entry = 0;
1.135     yamt     1351:                                        ndp->dc_flags &= ~NFSDC_INVALID;
1.49      fvdl     1352:                                }
                   1353:                                break;
                   1354:                        }
                   1355:                }
                   1356:        } else {
1.113     yamt     1357:                LIST_FOREACH(ndp, ndhp, dc_hash) {
1.49      fvdl     1358:                        if (ndp->dc_cookie == off)
                   1359:                                break;
1.113     yamt     1360:                }
1.49      fvdl     1361:        }
1.135     yamt     1362:        if (ndp != NULL)
                   1363:                ndp->dc_refcnt++;
                   1364:        NFSDC_UNLOCK(np);
1.49      fvdl     1365:        return ndp;
                   1366: }
                   1367:
                   1368:
                   1369: struct nfsdircache *
1.149.2.3  yamt     1370: nfs_enterdircache(struct vnode *vp, off_t off, off_t blkoff, int en,
                   1371:     daddr_t blkno)
1.46      fvdl     1372: {
                   1373:        struct nfsnode *np = VTONFS(vp);
                   1374:        struct nfsdirhashhead *ndhp;
1.135     yamt     1375:        struct nfsdircache *ndp = NULL;
                   1376:        struct nfsdircache *newndp = NULL;
1.49      fvdl     1377:        struct nfsmount *nmp = VFSTONFS(vp->v_mount);
1.149.2.2  yamt     1378:        int hashent = 0, gen, overwrite;        /* XXX: GCC */
1.46      fvdl     1379:
1.135     yamt     1380:        /*
                   1381:         * XXX refuse entries for offset 0. amd(8) erroneously sets
                   1382:         * cookie 0 for the '.' entry, making this necessary. This
                   1383:         * isn't so bad, as 0 is a special case anyway.
                   1384:         */
                   1385:        if (off == 0)
1.149     christos 1386:                /* XXXUNCONST */
                   1387:                return (struct nfsdircache *)__UNCONST(&dzero);
1.135     yamt     1388:
1.49      fvdl     1389:        if (!np->n_dircache)
                   1390:                /*
                   1391:                 * XXX would like to do this in nfs_nget but vtype
                   1392:                 * isn't known at that time.
                   1393:                 */
                   1394:                nfs_initdircache(vp);
1.50      fvdl     1395:
1.120     yamt     1396:        if ((nmp->nm_flag & NFSMNT_XLATECOOKIE) && !np->n_dirgens)
                   1397:                nfs_initdirxlatecookie(vp);
                   1398:
1.135     yamt     1399: retry:
1.49      fvdl     1400:        ndp = nfs_searchdircache(vp, off, 0, &hashent);
                   1401:
1.135     yamt     1402:        NFSDC_LOCK(np);
                   1403:        if (ndp && (ndp->dc_flags & NFSDC_INVALID) == 0) {
1.49      fvdl     1404:                /*
                   1405:                 * Overwriting an old entry. Check if it's the same.
                   1406:                 * If so, just return. If not, remove the old entry.
                   1407:                 */
                   1408:                if (ndp->dc_blkcookie == blkoff && ndp->dc_entry == en)
1.135     yamt     1409:                        goto done;
                   1410:                nfs_unlinkdircache(np, ndp);
                   1411:                nfs_putdircache_unlocked(np, ndp);
                   1412:                ndp = NULL;
1.46      fvdl     1413:        }
                   1414:
1.49      fvdl     1415:        ndhp = &np->n_dircache[hashent];
1.46      fvdl     1416:
1.49      fvdl     1417:        if (!ndp) {
1.135     yamt     1418:                if (newndp == NULL) {
                   1419:                        NFSDC_UNLOCK(np);
1.149.2.8! yamt     1420:                        newndp = kmem_alloc(sizeof(*newndp), KM_SLEEP);
1.135     yamt     1421:                        newndp->dc_refcnt = 1;
                   1422:                        LIST_NEXT(newndp, dc_hash) = (void *)-1;
                   1423:                        goto retry;
                   1424:                }
                   1425:                ndp = newndp;
                   1426:                newndp = NULL;
1.49      fvdl     1427:                overwrite = 0;
                   1428:                if (nmp->nm_flag & NFSMNT_XLATECOOKIE) {
                   1429:                        /*
                   1430:                         * We're allocating a new entry, so bump the
                   1431:                         * generation number.
                   1432:                         */
1.149.2.2  yamt     1433:                        KASSERT(np->n_dirgens);
1.49      fvdl     1434:                        gen = ++np->n_dirgens[hashent];
                   1435:                        if (gen == 0) {
                   1436:                                np->n_dirgens[hashent]++;
                   1437:                                gen++;
                   1438:                        }
                   1439:                        ndp->dc_cookie32 = (hashent << 24) | (gen & 0xffffff);
                   1440:                }
                   1441:        } else
                   1442:                overwrite = 1;
1.46      fvdl     1443:
1.49      fvdl     1444:        ndp->dc_cookie = off;
                   1445:        ndp->dc_blkcookie = blkoff;
1.46      fvdl     1446:        ndp->dc_entry = en;
1.137     yamt     1447:        ndp->dc_flags = 0;
1.46      fvdl     1448:
1.49      fvdl     1449:        if (overwrite)
1.135     yamt     1450:                goto done;
1.49      fvdl     1451:
1.46      fvdl     1452:        /*
                   1453:         * If the maximum directory cookie cache size has been reached
                   1454:         * for this node, take one off the front. The idea is that
                   1455:         * directories are typically read front-to-back once, so that
                   1456:         * the oldest entries can be thrown away without much performance
                   1457:         * loss.
                   1458:         */
                   1459:        if (np->n_dircachesize == NFS_MAXDIRCACHE) {
1.135     yamt     1460:                nfs_unlinkdircache(np, TAILQ_FIRST(&np->n_dirchain));
1.46      fvdl     1461:        } else
                   1462:                np->n_dircachesize++;
1.148     perry    1463:
1.135     yamt     1464:        KASSERT(ndp->dc_refcnt == 1);
1.46      fvdl     1465:        LIST_INSERT_HEAD(ndhp, ndp, dc_hash);
                   1466:        TAILQ_INSERT_TAIL(&np->n_dirchain, ndp, dc_chain);
1.135     yamt     1467:        ndp->dc_refcnt++;
                   1468: done:
                   1469:        KASSERT(ndp->dc_refcnt > 0);
                   1470:        NFSDC_UNLOCK(np);
                   1471:        if (newndp)
                   1472:                nfs_putdircache(np, newndp);
1.46      fvdl     1473:        return ndp;
                   1474: }
                   1475:
                   1476: void
1.145     yamt     1477: nfs_invaldircache(vp, flags)
1.46      fvdl     1478:        struct vnode *vp;
1.145     yamt     1479:        int flags;
1.46      fvdl     1480: {
                   1481:        struct nfsnode *np = VTONFS(vp);
                   1482:        struct nfsdircache *ndp = NULL;
1.49      fvdl     1483:        struct nfsmount *nmp = VFSTONFS(vp->v_mount);
1.149.2.4  yamt     1484:        const bool forcefree = flags & NFS_INVALDIRCACHE_FORCE;
1.46      fvdl     1485:
                   1486: #ifdef DIAGNOSTIC
                   1487:        if (vp->v_type != VDIR)
                   1488:                panic("nfs: invaldircache: not dir");
                   1489: #endif
                   1490:
1.145     yamt     1491:        if ((flags & NFS_INVALDIRCACHE_KEEPEOF) == 0)
                   1492:                np->n_flag &= ~NEOFVALID;
1.144     yamt     1493:
1.46      fvdl     1494:        if (!np->n_dircache)
                   1495:                return;
                   1496:
1.135     yamt     1497:        NFSDC_LOCK(np);
1.49      fvdl     1498:        if (!(nmp->nm_flag & NFSMNT_XLATECOOKIE) || forcefree) {
1.135     yamt     1499:                while ((ndp = TAILQ_FIRST(&np->n_dirchain)) != NULL) {
                   1500:                        KASSERT(!forcefree || ndp->dc_refcnt == 1);
                   1501:                        nfs_unlinkdircache(np, ndp);
1.49      fvdl     1502:                }
                   1503:                np->n_dircachesize = 0;
                   1504:                if (forcefree && np->n_dirgens) {
1.149.2.8! yamt     1505:                        kmem_free(np->n_dirgens,
        !          1506:                            NFS_DIRHASHSIZ * sizeof(unsigned));
1.120     yamt     1507:                        np->n_dirgens = NULL;
1.49      fvdl     1508:                }
                   1509:        } else {
1.135     yamt     1510:                TAILQ_FOREACH(ndp, &np->n_dirchain, dc_chain)
                   1511:                        ndp->dc_flags |= NFSDC_INVALID;
1.46      fvdl     1512:        }
                   1513:
1.135     yamt     1514:        NFSDC_UNLOCK(np);
1.46      fvdl     1515: }
                   1516:
1.1       cgd      1517: /*
1.35      thorpej  1518:  * Called once before VFS init to initialize shared and
                   1519:  * server-specific data structures.
1.1       cgd      1520:  */
1.149.2.2  yamt     1521: static int
                   1522: nfs_init0(void)
1.1       cgd      1523: {
1.149.2.5  yamt     1524:
1.12      mycroft  1525:        nfsrtt.pos = 0;
1.1       cgd      1526:        rpc_vers = txdr_unsigned(RPC_VER2);
                   1527:        rpc_call = txdr_unsigned(RPC_CALL);
                   1528:        rpc_reply = txdr_unsigned(RPC_REPLY);
                   1529:        rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED);
                   1530:        rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED);
                   1531:        rpc_mismatch = txdr_unsigned(RPC_MISMATCH);
1.12      mycroft  1532:        rpc_autherr = txdr_unsigned(RPC_AUTHERR);
1.1       cgd      1533:        rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX);
1.25      fvdl     1534:        rpc_auth_kerb = txdr_unsigned(RPCAUTH_KERB4);
1.1       cgd      1535:        nfs_prog = txdr_unsigned(NFS_PROG);
1.149.2.4  yamt     1536:        nfs_true = txdr_unsigned(true);
                   1537:        nfs_false = txdr_unsigned(false);
1.12      mycroft  1538:        nfs_xdrneg1 = txdr_unsigned(-1);
1.25      fvdl     1539:        nfs_ticks = (hz * NFS_TICKINTVL + 500) / 1000;
                   1540:        if (nfs_ticks < 1)
                   1541:                nfs_ticks = 1;
1.2       glass    1542: #ifdef NFSSERVER
1.12      mycroft  1543:        nfsrv_init(0);                  /* Init server data structures */
1.1       cgd      1544:        nfsrv_initcache();              /* Init the server request cache */
1.149.2.5  yamt     1545:        {
                   1546:                extern krwlock_t netexport_lock;        /* XXX */
                   1547:                rw_init(&netexport_lock);
                   1548:        }
1.36      fvdl     1549: #endif /* NFSSERVER */
1.12      mycroft  1550:
1.149.2.2  yamt     1551: #if defined(NFSSERVER) || (defined(NFS) && !defined(NFS_V2_ONLY))
                   1552:        nfsdreq_init();
                   1553: #endif /* defined(NFSSERVER) || (defined(NFS) && !defined(NFS_V2_ONLY)) */
                   1554:
1.1       cgd      1555:        /*
                   1556:         * Initialize reply list and start timer
                   1557:         */
1.16      mycroft  1558:        TAILQ_INIT(&nfs_reqq);
1.149.2.5  yamt     1559:        nfs_timer_init();
1.109     matt     1560:        MOWNER_ATTACH(&nfs_mowner);
1.106     jdolecek 1561:
                   1562: #ifdef NFS
                   1563:        /* Initialize the kqueue structures */
                   1564:        nfs_kqinit();
1.119     yamt     1565:        /* Initialize the iod structures */
                   1566:        nfs_iodinit();
1.106     jdolecek 1567: #endif
1.149.2.2  yamt     1568:        return 0;
                   1569: }
                   1570:
                   1571: void
                   1572: nfs_init(void)
                   1573: {
                   1574:        static ONCE_DECL(nfs_init_once);
                   1575:
                   1576:        RUN_ONCE(&nfs_init_once, nfs_init0);
1.1       cgd      1577: }
                   1578:
1.38      thorpej  1579: #ifdef NFS
1.35      thorpej  1580: /*
                   1581:  * Called once at VFS init to initialize client-specific data structures.
                   1582:  */
                   1583: void
                   1584: nfs_vfs_init()
                   1585: {
1.149.2.2  yamt     1586:        /* Initialize NFS server / client shared data. */
                   1587:        nfs_init();
                   1588:
1.96      chs      1589:        nfs_nhinit();                   /* Init the nfsnode table */
1.100     chs      1590:        nfs_commitsize = uvmexp.npages << (PAGE_SHIFT - 4);
1.96      chs      1591: }
1.35      thorpej  1592:
1.96      chs      1593: void
                   1594: nfs_vfs_reinit()
                   1595: {
                   1596:        nfs_nhreinit();
1.73      jdolecek 1597: }
                   1598:
                   1599: void
                   1600: nfs_vfs_done()
                   1601: {
                   1602:        nfs_nhdone();
1.35      thorpej  1603: }
                   1604:
1.1       cgd      1605: /*
1.12      mycroft  1606:  * Attribute cache routines.
                   1607:  * nfs_loadattrcache() - loads or updates the cache contents from attributes
                   1608:  *     that are on the mbuf list
                   1609:  * nfs_getattrcache() - returns valid attributes if found in cache, returns
                   1610:  *     error otherwise
1.1       cgd      1611:  */
1.12      mycroft  1612:
                   1613: /*
                   1614:  * Load the attribute cache (that lives in the nfsnode entry) with
                   1615:  * the values on the mbuf list and
                   1616:  * Iff vap not NULL
                   1617:  *    copy the attributes to *vaper
                   1618:  */
1.24      christos 1619: int
1.105     yamt     1620: nfsm_loadattrcache(vpp, mdp, dposp, vaper, flags)
1.12      mycroft  1621:        struct vnode **vpp;
                   1622:        struct mbuf **mdp;
1.149.2.5  yamt     1623:        char **dposp;
1.12      mycroft  1624:        struct vattr *vaper;
1.105     yamt     1625:        int flags;
1.1       cgd      1626: {
1.75      augustss 1627:        int32_t t1;
1.149.2.5  yamt     1628:        char *cp2;
1.25      fvdl     1629:        int error = 0;
1.12      mycroft  1630:        struct mbuf *md;
1.45      fvdl     1631:        int v3 = NFS_ISV3(*vpp);
1.1       cgd      1632:
1.12      mycroft  1633:        md = *mdp;
1.149.2.5  yamt     1634:        t1 = (mtod(md, char *) + md->m_len) - *dposp;
1.25      fvdl     1635:        error = nfsm_disct(mdp, dposp, NFSX_FATTR(v3), t1, &cp2);
1.24      christos 1636:        if (error)
1.12      mycroft  1637:                return (error);
1.105     yamt     1638:        return nfs_loadattrcache(vpp, (struct nfs_fattr *)cp2, vaper, flags);
1.45      fvdl     1639: }
                   1640:
                   1641: int
1.105     yamt     1642: nfs_loadattrcache(vpp, fp, vaper, flags)
1.45      fvdl     1643:        struct vnode **vpp;
                   1644:        struct nfs_fattr *fp;
                   1645:        struct vattr *vaper;
1.105     yamt     1646:        int flags;
1.45      fvdl     1647: {
1.75      augustss 1648:        struct vnode *vp = *vpp;
                   1649:        struct vattr *vap;
1.45      fvdl     1650:        int v3 = NFS_ISV3(vp);
                   1651:        enum vtype vtyp;
                   1652:        u_short vmode;
                   1653:        struct timespec mtime;
1.139     yamt     1654:        struct timespec ctime;
1.45      fvdl     1655:        struct vnode *nvp;
                   1656:        int32_t rdev;
1.75      augustss 1657:        struct nfsnode *np;
1.45      fvdl     1658:        extern int (**spec_nfsv2nodeop_p) __P((void *));
1.101     fvdl     1659:        uid_t uid;
                   1660:        gid_t gid;
1.45      fvdl     1661:
1.25      fvdl     1662:        if (v3) {
                   1663:                vtyp = nfsv3tov_type(fp->fa_type);
                   1664:                vmode = fxdr_unsigned(u_short, fp->fa_mode);
1.71      is       1665:                rdev = makedev(fxdr_unsigned(u_int32_t, fp->fa3_rdev.specdata1),
                   1666:                        fxdr_unsigned(u_int32_t, fp->fa3_rdev.specdata2));
1.25      fvdl     1667:                fxdr_nfsv3time(&fp->fa3_mtime, &mtime);
1.139     yamt     1668:                fxdr_nfsv3time(&fp->fa3_ctime, &ctime);
1.12      mycroft  1669:        } else {
1.25      fvdl     1670:                vtyp = nfsv2tov_type(fp->fa_type);
                   1671:                vmode = fxdr_unsigned(u_short, fp->fa_mode);
                   1672:                if (vtyp == VNON || vtyp == VREG)
                   1673:                        vtyp = IFTOVT(vmode);
                   1674:                rdev = fxdr_unsigned(int32_t, fp->fa2_rdev);
                   1675:                fxdr_nfsv2time(&fp->fa2_mtime, &mtime);
1.139     yamt     1676:                ctime.tv_sec = fxdr_unsigned(u_int32_t,
                   1677:                    fp->fa2_ctime.nfsv2_sec);
                   1678:                ctime.tv_nsec = 0;
1.25      fvdl     1679:
                   1680:                /*
                   1681:                 * Really ugly NFSv2 kludge.
                   1682:                 */
                   1683:                if (vtyp == VCHR && rdev == 0xffffffff)
                   1684:                        vtyp = VFIFO;
1.12      mycroft  1685:        }
1.25      fvdl     1686:
1.101     fvdl     1687:        vmode &= ALLPERMS;
                   1688:
1.12      mycroft  1689:        /*
                   1690:         * If v_type == VNON it is a new node, so fill in the v_type,
1.148     perry    1691:         * n_mtime fields. Check to see if it represents a special
1.12      mycroft  1692:         * device, and if so, check for a possible alias. Once the
                   1693:         * correct vnode has been obtained, fill in the rest of the
                   1694:         * information.
                   1695:         */
                   1696:        np = VTONFS(vp);
1.87      fvdl     1697:        if (vp->v_type == VNON) {
1.25      fvdl     1698:                vp->v_type = vtyp;
1.12      mycroft  1699:                if (vp->v_type == VFIFO) {
1.24      christos 1700:                        extern int (**fifo_nfsv2nodeop_p) __P((void *));
1.12      mycroft  1701:                        vp->v_op = fifo_nfsv2nodeop_p;
1.131     yamt     1702:                } else if (vp->v_type == VREG) {
1.149.2.4  yamt     1703:                        mutex_init(&np->n_commitlock, MUTEX_DEFAULT, IPL_NONE);
1.131     yamt     1704:                } else if (vp->v_type == VCHR || vp->v_type == VBLK) {
1.12      mycroft  1705:                        vp->v_op = spec_nfsv2nodeop_p;
1.24      christos 1706:                        nvp = checkalias(vp, (dev_t)rdev, vp->v_mount);
                   1707:                        if (nvp) {
1.12      mycroft  1708:                                /*
                   1709:                                 * Discard unneeded vnode, but save its nfsnode.
1.25      fvdl     1710:                                 * Since the nfsnode does not have a lock, its
                   1711:                                 * vnode lock has to be carried over.
1.12      mycroft  1712:                                 */
1.94      bjh21    1713:                                /*
                   1714:                                 * XXX is the old node sure to be locked here?
                   1715:                                 */
                   1716:                                KASSERT(lockstatus(&vp->v_lock) ==
                   1717:                                    LK_EXCLUSIVE);
1.12      mycroft  1718:                                nvp->v_data = vp->v_data;
                   1719:                                vp->v_data = NULL;
1.93      fvdl     1720:                                VOP_UNLOCK(vp, 0);
1.12      mycroft  1721:                                vp->v_op = spec_vnodeop_p;
                   1722:                                vgone(vp);
1.94      bjh21    1723:                                lockmgr(&nvp->v_lock, LK_EXCLUSIVE,
                   1724:                                    &nvp->v_interlock);
1.12      mycroft  1725:                                /*
                   1726:                                 * Reinitialize aliased node.
                   1727:                                 */
                   1728:                                np->n_vnode = nvp;
                   1729:                                *vpp = vp = nvp;
                   1730:                        }
                   1731:                }
1.128     yamt     1732:                np->n_mtime = mtime;
1.12      mycroft  1733:        }
1.101     fvdl     1734:        uid = fxdr_unsigned(uid_t, fp->fa_uid);
                   1735:        gid = fxdr_unsigned(gid_t, fp->fa_gid);
1.49      fvdl     1736:        vap = np->n_vattr;
1.101     fvdl     1737:
                   1738:        /*
1.139     yamt     1739:         * Invalidate access cache if uid, gid, mode or ctime changed.
1.101     fvdl     1740:         */
                   1741:        if (np->n_accstamp != -1 &&
1.139     yamt     1742:            (gid != vap->va_gid || uid != vap->va_uid || vmode != vap->va_mode
                   1743:            || timespeccmp(&ctime, &vap->va_ctime, !=)))
1.101     fvdl     1744:                np->n_accstamp = -1;
                   1745:
1.12      mycroft  1746:        vap->va_type = vtyp;
1.101     fvdl     1747:        vap->va_mode = vmode;
1.12      mycroft  1748:        vap->va_rdev = (dev_t)rdev;
                   1749:        vap->va_mtime = mtime;
1.139     yamt     1750:        vap->va_ctime = ctime;
1.133     christos 1751:        vap->va_fsid = vp->v_mount->mnt_stat.f_fsidx.__fsid_val[0];
1.72      fvdl     1752:        switch (vtyp) {
                   1753:        case VDIR:
                   1754:                vap->va_blocksize = NFS_DIRFRAGSIZ;
                   1755:                break;
                   1756:        case VBLK:
                   1757:                vap->va_blocksize = BLKDEV_IOSIZE;
                   1758:                break;
                   1759:        case VCHR:
                   1760:                vap->va_blocksize = MAXBSIZE;
                   1761:                break;
                   1762:        default:
                   1763:                vap->va_blocksize = v3 ? vp->v_mount->mnt_stat.f_iosize :
                   1764:                    fxdr_unsigned(int32_t, fp->fa2_blocksize);
                   1765:                break;
                   1766:        }
1.25      fvdl     1767:        if (v3) {
                   1768:                vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink);
1.101     fvdl     1769:                vap->va_uid = uid;
                   1770:                vap->va_gid = gid;
1.66      fair     1771:                vap->va_size = fxdr_hyper(&fp->fa3_size);
                   1772:                vap->va_bytes = fxdr_hyper(&fp->fa3_used);
1.149.2.2  yamt     1773:                vap->va_fileid = fxdr_hyper(&fp->fa3_fileid);
1.25      fvdl     1774:                fxdr_nfsv3time(&fp->fa3_atime, &vap->va_atime);
                   1775:                vap->va_flags = 0;
                   1776:                vap->va_filerev = 0;
1.12      mycroft  1777:        } else {
1.25      fvdl     1778:                vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink);
1.101     fvdl     1779:                vap->va_uid = uid;
                   1780:                vap->va_gid = gid;
1.25      fvdl     1781:                vap->va_size = fxdr_unsigned(u_int32_t, fp->fa2_size);
                   1782:                vap->va_bytes = fxdr_unsigned(int32_t, fp->fa2_blocks)
                   1783:                    * NFS_FABLKSIZE;
                   1784:                vap->va_fileid = fxdr_unsigned(int32_t, fp->fa2_fileid);
                   1785:                fxdr_nfsv2time(&fp->fa2_atime, &vap->va_atime);
1.12      mycroft  1786:                vap->va_flags = 0;
1.25      fvdl     1787:                vap->va_gen = fxdr_unsigned(u_int32_t,fp->fa2_ctime.nfsv2_usec);
1.12      mycroft  1788:                vap->va_filerev = 0;
                   1789:        }
                   1790:        if (vap->va_size != np->n_size) {
1.89      chs      1791:                if ((np->n_flag & NMODIFIED) && vap->va_size < np->n_size) {
                   1792:                        vap->va_size = np->n_size;
                   1793:                } else {
1.12      mycroft  1794:                        np->n_size = vap->va_size;
1.89      chs      1795:                        if (vap->va_type == VREG) {
1.140     yamt     1796:                                /*
                   1797:                                 * we can't free pages if NAC_NOTRUNC because
                   1798:                                 * the pages can be owned by ourselves.
                   1799:                                 */
                   1800:                                if (flags & NAC_NOTRUNC) {
1.105     yamt     1801:                                        np->n_flag |= NTRUNCDELAYED;
1.140     yamt     1802:                                } else {
1.149.2.3  yamt     1803:                                        genfs_node_wrlock(vp);
1.149.2.8! yamt     1804:                                        mutex_enter(&vp->v_interlock);
1.140     yamt     1805:                                        (void)VOP_PUTPAGES(vp, 0,
                   1806:                                            0, PGO_SYNCIO | PGO_CLEANIT |
                   1807:                                            PGO_FREE | PGO_ALLPAGES);
1.105     yamt     1808:                                        uvm_vnp_setsize(vp, np->n_size);
1.149.2.3  yamt     1809:                                        genfs_node_unlock(vp);
1.105     yamt     1810:                                }
1.89      chs      1811:                        }
                   1812:                }
1.12      mycroft  1813:        }
1.149.2.2  yamt     1814:        np->n_attrstamp = time_second;
1.12      mycroft  1815:        if (vaper != NULL) {
1.149.2.5  yamt     1816:                memcpy((void *)vaper, (void *)vap, sizeof(*vap));
1.12      mycroft  1817:                if (np->n_flag & NCHG) {
1.25      fvdl     1818:                        if (np->n_flag & NACC)
                   1819:                                vaper->va_atime = np->n_atim;
                   1820:                        if (np->n_flag & NUPD)
                   1821:                                vaper->va_mtime = np->n_mtim;
1.12      mycroft  1822:                }
                   1823:        }
                   1824:        return (0);
                   1825: }
                   1826:
                   1827: /*
                   1828:  * Check the time stamp
                   1829:  * If the cache is valid, copy contents to *vap and return 0
                   1830:  * otherwise return an error
                   1831:  */
1.24      christos 1832: int
1.12      mycroft  1833: nfs_getattrcache(vp, vaper)
1.75      augustss 1834:        struct vnode *vp;
1.12      mycroft  1835:        struct vattr *vaper;
                   1836: {
1.75      augustss 1837:        struct nfsnode *np = VTONFS(vp);
1.149.2.2  yamt     1838:        struct nfsmount *nmp = VFSTONFS(vp->v_mount);
1.75      augustss 1839:        struct vattr *vap;
1.12      mycroft  1840:
1.132     yamt     1841:        if (np->n_attrstamp == 0 ||
1.149.2.6  yamt     1842:            (time_second - np->n_attrstamp) >= nfs_attrtimeo(nmp, np)) {
1.12      mycroft  1843:                nfsstats.attrcache_misses++;
                   1844:                return (ENOENT);
                   1845:        }
                   1846:        nfsstats.attrcache_hits++;
1.49      fvdl     1847:        vap = np->n_vattr;
1.12      mycroft  1848:        if (vap->va_size != np->n_size) {
                   1849:                if (vap->va_type == VREG) {
1.149.2.5  yamt     1850:                        if ((np->n_flag & NMODIFIED) != 0 &&
                   1851:                            vap->va_size < np->n_size) {
                   1852:                                vap->va_size = np->n_size;
                   1853:                        } else {
1.12      mycroft  1854:                                np->n_size = vap->va_size;
1.149.2.5  yamt     1855:                        }
1.149.2.3  yamt     1856:                        genfs_node_wrlock(vp);
1.51      mrg      1857:                        uvm_vnp_setsize(vp, np->n_size);
1.149.2.3  yamt     1858:                        genfs_node_unlock(vp);
1.12      mycroft  1859:                } else
                   1860:                        np->n_size = vap->va_size;
                   1861:        }
1.149.2.5  yamt     1862:        memcpy((void *)vaper, (void *)vap, sizeof(struct vattr));
1.12      mycroft  1863:        if (np->n_flag & NCHG) {
1.25      fvdl     1864:                if (np->n_flag & NACC)
                   1865:                        vaper->va_atime = np->n_atim;
                   1866:                if (np->n_flag & NUPD)
                   1867:                        vaper->va_mtime = np->n_mtim;
1.1       cgd      1868:        }
1.12      mycroft  1869:        return (0);
1.105     yamt     1870: }
                   1871:
                   1872: void
                   1873: nfs_delayedtruncate(vp)
                   1874:        struct vnode *vp;
                   1875: {
                   1876:        struct nfsnode *np = VTONFS(vp);
                   1877:
                   1878:        if (np->n_flag & NTRUNCDELAYED) {
                   1879:                np->n_flag &= ~NTRUNCDELAYED;
1.149.2.3  yamt     1880:                genfs_node_wrlock(vp);
1.149.2.8! yamt     1881:                mutex_enter(&vp->v_interlock);
1.140     yamt     1882:                (void)VOP_PUTPAGES(vp, 0,
                   1883:                    0, PGO_SYNCIO | PGO_CLEANIT | PGO_FREE | PGO_ALLPAGES);
1.105     yamt     1884:                uvm_vnp_setsize(vp, np->n_size);
1.149.2.3  yamt     1885:                genfs_node_unlock(vp);
1.105     yamt     1886:        }
1.1       cgd      1887: }
1.48      fvdl     1888:
1.141     yamt     1889: #define        NFS_WCCKLUDGE_TIMEOUT   (24 * 60 * 60)  /* 1 day */
                   1890: #define        NFS_WCCKLUDGE(nmp, now) \
                   1891:        (((nmp)->nm_iflag & NFSMNT_WCCKLUDGE) && \
                   1892:        ((now) - (nmp)->nm_wcckludgetime - NFS_WCCKLUDGE_TIMEOUT) < 0)
                   1893:
                   1894: /*
                   1895:  * nfs_check_wccdata: check inaccurate wcc_data
                   1896:  *
                   1897:  * => return non-zero if we shouldn't trust the wcc_data.
                   1898:  * => NFS_WCCKLUDGE_TIMEOUT is for the case that the server is "fixed".
                   1899:  */
                   1900:
                   1901: int
                   1902: nfs_check_wccdata(struct nfsnode *np, const struct timespec *ctime,
1.149.2.4  yamt     1903:     struct timespec *mtime, bool docheck)
1.141     yamt     1904: {
                   1905:        int error = 0;
                   1906:
                   1907: #if !defined(NFS_V2_ONLY)
                   1908:
                   1909:        if (docheck) {
                   1910:                struct vnode *vp = NFSTOV(np);
                   1911:                struct nfsmount *nmp;
1.149.2.2  yamt     1912:                long now = time_second;
1.149.2.5  yamt     1913:                const struct timespec *omtime = &np->n_vattr->va_mtime;
                   1914:                const struct timespec *octime = &np->n_vattr->va_ctime;
1.141     yamt     1915: #if defined(DEBUG)
                   1916:                const char *reason = NULL; /* XXX: gcc */
                   1917: #endif
                   1918:
1.149.2.5  yamt     1919:                if (timespeccmp(omtime, mtime, <=)) {
1.141     yamt     1920: #if defined(DEBUG)
                   1921:                        reason = "mtime";
                   1922: #endif
                   1923:                        error = EINVAL;
                   1924:                }
                   1925:
1.149.2.5  yamt     1926:                if (vp->v_type == VDIR && timespeccmp(octime, ctime, <=)) {
1.141     yamt     1927: #if defined(DEBUG)
                   1928:                        reason = "ctime";
                   1929: #endif
                   1930:                        error = EINVAL;
                   1931:                }
                   1932:
                   1933:                nmp = VFSTONFS(vp->v_mount);
                   1934:                if (error) {
1.143     yamt     1935:
                   1936:                        /*
                   1937:                         * despite of the fact that we've updated the file,
                   1938:                         * timestamps of the file were not updated as we
                   1939:                         * expected.
                   1940:                         * it means that the server has incompatible
                   1941:                         * semantics of timestamps or (more likely)
                   1942:                         * the server time is not precise enough to
                   1943:                         * track each modifications.
                   1944:                         * in that case, we disable wcc processing.
                   1945:                         *
                   1946:                         * yes, strictly speaking, we should disable all
                   1947:                         * caching.  it's a compromise.
                   1948:                         */
                   1949:
1.149.2.5  yamt     1950:                        mutex_enter(&nmp->nm_lock);
1.141     yamt     1951: #if defined(DEBUG)
                   1952:                        if (!NFS_WCCKLUDGE(nmp, now)) {
                   1953:                                printf("%s: inaccurate wcc data (%s) detected,"
1.149.2.5  yamt     1954:                                    " disabling wcc"
                   1955:                                    " (ctime %u.%09u %u.%09u,"
                   1956:                                    " mtime %u.%09u %u.%09u)\n",
1.141     yamt     1957:                                    vp->v_mount->mnt_stat.f_mntfromname,
1.149.2.5  yamt     1958:                                    reason,
                   1959:                                    (unsigned int)octime->tv_sec,
                   1960:                                    (unsigned int)octime->tv_nsec,
                   1961:                                    (unsigned int)ctime->tv_sec,
                   1962:                                    (unsigned int)ctime->tv_nsec,
                   1963:                                    (unsigned int)omtime->tv_sec,
                   1964:                                    (unsigned int)omtime->tv_nsec,
                   1965:                                    (unsigned int)mtime->tv_sec,
                   1966:                                    (unsigned int)mtime->tv_nsec);
1.141     yamt     1967:                        }
                   1968: #endif
                   1969:                        nmp->nm_iflag |= NFSMNT_WCCKLUDGE;
                   1970:                        nmp->nm_wcckludgetime = now;
1.149.2.5  yamt     1971:                        mutex_exit(&nmp->nm_lock);
1.141     yamt     1972:                } else if (NFS_WCCKLUDGE(nmp, now)) {
                   1973:                        error = EPERM; /* XXX */
                   1974:                } else if (nmp->nm_iflag & NFSMNT_WCCKLUDGE) {
1.149.2.5  yamt     1975:                        mutex_enter(&nmp->nm_lock);
1.141     yamt     1976:                        if (nmp->nm_iflag & NFSMNT_WCCKLUDGE) {
                   1977: #if defined(DEBUG)
                   1978:                                printf("%s: re-enabling wcc\n",
                   1979:                                    vp->v_mount->mnt_stat.f_mntfromname);
                   1980: #endif
                   1981:                                nmp->nm_iflag &= ~NFSMNT_WCCKLUDGE;
                   1982:                        }
1.149.2.5  yamt     1983:                        mutex_exit(&nmp->nm_lock);
1.141     yamt     1984:                }
                   1985:        }
                   1986:
                   1987: #endif /* !defined(NFS_V2_ONLY) */
                   1988:
                   1989:        return error;
                   1990: }
                   1991:
1.48      fvdl     1992: /*
                   1993:  * Heuristic to see if the server XDR encodes directory cookies or not.
                   1994:  * it is not supposed to, but a lot of servers may do this. Also, since
                   1995:  * most/all servers will implement V2 as well, it is expected that they
                   1996:  * may return just 32 bits worth of cookie information, so we need to
                   1997:  * find out in which 32 bits this information is available. We do this
                   1998:  * to avoid trouble with emulated binaries that can't handle 64 bit
                   1999:  * directory offsets.
                   2000:  */
                   2001:
                   2002: void
1.149.2.2  yamt     2003: nfs_cookieheuristic(vp, flagp, l, cred)
1.48      fvdl     2004:        struct vnode *vp;
                   2005:        int *flagp;
1.149.2.2  yamt     2006:        struct lwp *l;
                   2007:        kauth_cred_t cred;
1.48      fvdl     2008: {
                   2009:        struct uio auio;
                   2010:        struct iovec aiov;
1.149.2.5  yamt     2011:        char *tbuf, *cp;
1.48      fvdl     2012:        struct dirent *dp;
1.57      fvdl     2013:        off_t *cookies = NULL, *cop;
1.48      fvdl     2014:        int error, eof, nc, len;
                   2015:
1.149.2.5  yamt     2016:        MALLOC(tbuf, void *, NFS_DIRFRAGSIZ, M_TEMP, M_WAITOK);
1.48      fvdl     2017:
1.149     christos 2018:        aiov.iov_base = tbuf;
1.48      fvdl     2019:        aiov.iov_len = NFS_DIRFRAGSIZ;
                   2020:        auio.uio_iov = &aiov;
                   2021:        auio.uio_iovcnt = 1;
                   2022:        auio.uio_rw = UIO_READ;
                   2023:        auio.uio_resid = NFS_DIRFRAGSIZ;
                   2024:        auio.uio_offset = 0;
1.149.2.2  yamt     2025:        UIO_SETUP_SYSSPACE(&auio);
1.48      fvdl     2026:
1.56      fvdl     2027:        error = VOP_READDIR(vp, &auio, cred, &eof, &cookies, &nc);
1.48      fvdl     2028:
                   2029:        len = NFS_DIRFRAGSIZ - auio.uio_resid;
                   2030:        if (error || len == 0) {
1.149     christos 2031:                FREE(tbuf, M_TEMP);
1.57      fvdl     2032:                if (cookies)
1.80      thorpej  2033:                        free(cookies, M_TEMP);
1.48      fvdl     2034:                return;
                   2035:        }
                   2036:
                   2037:        /*
                   2038:         * Find the first valid entry and look at its offset cookie.
                   2039:         */
                   2040:
1.149     christos 2041:        cp = tbuf;
1.48      fvdl     2042:        for (cop = cookies; len > 0; len -= dp->d_reclen) {
                   2043:                dp = (struct dirent *)cp;
                   2044:                if (dp->d_fileno != 0 && len >= dp->d_reclen) {
                   2045:                        if ((*cop >> 32) != 0 && (*cop & 0xffffffffLL) == 0) {
                   2046:                                *flagp |= NFSMNT_SWAPCOOKIE;
1.49      fvdl     2047:                                nfs_invaldircache(vp, 0);
1.149.2.2  yamt     2048:                                nfs_vinvalbuf(vp, 0, cred, l, 1);
1.48      fvdl     2049:                        }
                   2050:                        break;
                   2051:                }
                   2052:                cop++;
                   2053:                cp += dp->d_reclen;
                   2054:        }
                   2055:
1.149     christos 2056:        FREE(tbuf, M_TEMP);
1.80      thorpej  2057:        free(cookies, M_TEMP);
1.48      fvdl     2058: }
1.38      thorpej  2059: #endif /* NFS */
1.1       cgd      2060:
1.149.2.2  yamt     2061: #ifdef NFSSERVER
1.1       cgd      2062: /*
1.43      fvdl     2063:  * Set up nameidata for a lookup() call and do it.
                   2064:  *
                   2065:  * If pubflag is set, this call is done for a lookup operation on the
                   2066:  * public filehandle. In that case we allow crossing mountpoints and
                   2067:  * absolute pathnames. However, the caller is expected to check that
                   2068:  * the lookup result is within the public fs, and deny access if
                   2069:  * it is not.
1.1       cgd      2070:  */
1.24      christos 2071: int
1.149.2.3  yamt     2072: nfs_namei(ndp, nsfh, len, slp, nam, mdp, dposp, retdirp, l, kerbflag, pubflag)
1.75      augustss 2073:        struct nameidata *ndp;
1.149.2.3  yamt     2074:        nfsrvfh_t *nsfh;
1.110     yamt     2075:        uint32_t len;
1.12      mycroft  2076:        struct nfssvc_sock *slp;
                   2077:        struct mbuf *nam;
1.1       cgd      2078:        struct mbuf **mdp;
1.149.2.5  yamt     2079:        char **dposp;
1.25      fvdl     2080:        struct vnode **retdirp;
1.149.2.2  yamt     2081:        struct lwp *l;
1.43      fvdl     2082:        int kerbflag, pubflag;
1.1       cgd      2083: {
1.75      augustss 2084:        int i, rem;
                   2085:        struct mbuf *md;
                   2086:        char *fromcp, *tocp, *cp;
1.43      fvdl     2087:        struct iovec aiov;
                   2088:        struct uio auio;
1.1       cgd      2089:        struct vnode *dp;
1.43      fvdl     2090:        int error, rdonly, linklen;
1.12      mycroft  2091:        struct componentname *cnp = &ndp->ni_cnd;
1.1       cgd      2092:
1.149.2.3  yamt     2093:        *retdirp = NULL;
1.81      thorpej  2094:
                   2095:        if ((len + 1) > MAXPATHLEN)
                   2096:                return (ENAMETOOLONG);
1.147     yamt     2097:        if (len == 0)
                   2098:                return (EACCES);
1.81      thorpej  2099:        cnp->cn_pnbuf = PNBUF_GET();
                   2100:
1.1       cgd      2101:        /*
                   2102:         * Copy the name from the mbuf list to ndp->ni_pnbuf
                   2103:         * and set the various ndp fields appropriately.
                   2104:         */
                   2105:        fromcp = *dposp;
1.12      mycroft  2106:        tocp = cnp->cn_pnbuf;
1.1       cgd      2107:        md = *mdp;
1.149.2.5  yamt     2108:        rem = mtod(md, char *) + md->m_len - fromcp;
1.1       cgd      2109:        for (i = 0; i < len; i++) {
                   2110:                while (rem == 0) {
                   2111:                        md = md->m_next;
                   2112:                        if (md == NULL) {
                   2113:                                error = EBADRPC;
                   2114:                                goto out;
                   2115:                        }
1.149.2.5  yamt     2116:                        fromcp = mtod(md, void *);
1.1       cgd      2117:                        rem = md->m_len;
                   2118:                }
1.43      fvdl     2119:                if (*fromcp == '\0' || (!pubflag && *fromcp == '/')) {
1.25      fvdl     2120:                        error = EACCES;
1.1       cgd      2121:                        goto out;
                   2122:                }
                   2123:                *tocp++ = *fromcp++;
                   2124:                rem--;
                   2125:        }
                   2126:        *tocp = '\0';
                   2127:        *mdp = md;
                   2128:        *dposp = fromcp;
                   2129:        len = nfsm_rndup(len)-len;
                   2130:        if (len > 0) {
                   2131:                if (rem >= len)
                   2132:                        *dposp += len;
1.24      christos 2133:                else if ((error = nfs_adv(mdp, dposp, len, rem)) != 0)
1.1       cgd      2134:                        goto out;
                   2135:        }
1.43      fvdl     2136:
1.1       cgd      2137:        /*
                   2138:         * Extract and set starting directory.
                   2139:         */
1.149.2.4  yamt     2140:        error = nfsrv_fhtovp(nsfh, false, &dp, ndp->ni_cnd.cn_cred, slp,
1.124     thorpej  2141:            nam, &rdonly, kerbflag, pubflag);
1.24      christos 2142:        if (error)
1.1       cgd      2143:                goto out;
                   2144:        if (dp->v_type != VDIR) {
                   2145:                vrele(dp);
                   2146:                error = ENOTDIR;
                   2147:                goto out;
                   2148:        }
1.43      fvdl     2149:
                   2150:        if (rdonly)
                   2151:                cnp->cn_flags |= RDONLY;
                   2152:
                   2153:        *retdirp = dp;
                   2154:
                   2155:        if (pubflag) {
                   2156:                /*
                   2157:                 * Oh joy. For WebNFS, handle those pesky '%' escapes,
                   2158:                 * and the 'native path' indicator.
                   2159:                 */
1.81      thorpej  2160:                cp = PNBUF_GET();
1.43      fvdl     2161:                fromcp = cnp->cn_pnbuf;
                   2162:                tocp = cp;
                   2163:                if ((unsigned char)*fromcp >= WEBNFS_SPECCHAR_START) {
                   2164:                        switch ((unsigned char)*fromcp) {
                   2165:                        case WEBNFS_NATIVE_CHAR:
                   2166:                                /*
                   2167:                                 * 'Native' path for us is the same
                   2168:                                 * as a path according to the NFS spec,
                   2169:                                 * just skip the escape char.
                   2170:                                 */
                   2171:                                fromcp++;
                   2172:                                break;
                   2173:                        /*
                   2174:                         * More may be added in the future, range 0x80-0xff
                   2175:                         */
                   2176:                        default:
                   2177:                                error = EIO;
1.149.2.3  yamt     2178:                                vrele(dp);
1.104     enami    2179:                                PNBUF_PUT(cp);
1.43      fvdl     2180:                                goto out;
                   2181:                        }
                   2182:                }
                   2183:                /*
                   2184:                 * Translate the '%' escapes, URL-style.
                   2185:                 */
                   2186:                while (*fromcp != '\0') {
                   2187:                        if (*fromcp == WEBNFS_ESC_CHAR) {
                   2188:                                if (fromcp[1] != '\0' && fromcp[2] != '\0') {
                   2189:                                        fromcp++;
                   2190:                                        *tocp++ = HEXSTRTOI(fromcp);
                   2191:                                        fromcp += 2;
                   2192:                                        continue;
                   2193:                                } else {
                   2194:                                        error = ENOENT;
1.149.2.3  yamt     2195:                                        vrele(dp);
1.104     enami    2196:                                        PNBUF_PUT(cp);
1.43      fvdl     2197:                                        goto out;
                   2198:                                }
                   2199:                        } else
                   2200:                                *tocp++ = *fromcp++;
                   2201:                }
                   2202:                *tocp = '\0';
1.81      thorpej  2203:                PNBUF_PUT(cnp->cn_pnbuf);
1.43      fvdl     2204:                cnp->cn_pnbuf = cp;
                   2205:        }
                   2206:
                   2207:        ndp->ni_pathlen = (tocp - cnp->cn_pnbuf) + 1;
                   2208:        ndp->ni_segflg = UIO_SYSSPACE;
1.98      fvdl     2209:        ndp->ni_rootdir = rootvnode;
1.149.2.5  yamt     2210:        ndp->ni_erootdir = NULL;
1.43      fvdl     2211:
                   2212:        if (pubflag) {
                   2213:                ndp->ni_loopcnt = 0;
                   2214:                if (cnp->cn_pnbuf[0] == '/')
                   2215:                        dp = rootvnode;
                   2216:        } else {
                   2217:                cnp->cn_flags |= NOCROSSMOUNT;
                   2218:        }
                   2219:
1.25      fvdl     2220:        VREF(dp);
1.149.2.3  yamt     2221:        vn_lock(dp, LK_EXCLUSIVE | LK_RETRY);
1.43      fvdl     2222:
                   2223:     for (;;) {
                   2224:        cnp->cn_nameptr = cnp->cn_pnbuf;
1.1       cgd      2225:        ndp->ni_startdir = dp;
1.149.2.3  yamt     2226:
1.1       cgd      2227:        /*
                   2228:         * And call lookup() to do the real work
                   2229:         */
1.25      fvdl     2230:        error = lookup(ndp);
1.91      fvdl     2231:        if (error) {
1.149.2.3  yamt     2232:                if (ndp->ni_dvp) {
                   2233:                        vput(ndp->ni_dvp);
                   2234:                }
1.91      fvdl     2235:                PNBUF_PUT(cnp->cn_pnbuf);
                   2236:                return (error);
                   2237:        }
1.149.2.3  yamt     2238:
1.1       cgd      2239:        /*
                   2240:         * Check for encountering a symbolic link
                   2241:         */
1.43      fvdl     2242:        if ((cnp->cn_flags & ISSYMLINK) == 0) {
1.149.2.3  yamt     2243:                if ((cnp->cn_flags & LOCKPARENT) == 0 && ndp->ni_dvp) {
                   2244:                        if (ndp->ni_dvp == ndp->ni_vp) {
                   2245:                                vrele(ndp->ni_dvp);
                   2246:                        } else {
                   2247:                                vput(ndp->ni_dvp);
                   2248:                        }
                   2249:                }
1.91      fvdl     2250:                if (cnp->cn_flags & (SAVENAME | SAVESTART))
1.43      fvdl     2251:                        cnp->cn_flags |= HASBUF;
1.91      fvdl     2252:                else
                   2253:                        PNBUF_PUT(cnp->cn_pnbuf);
                   2254:                return (0);
1.43      fvdl     2255:        } else {
                   2256:                if (!pubflag) {
                   2257:                        error = EINVAL;
                   2258:                        break;
                   2259:                }
                   2260:                if (ndp->ni_loopcnt++ >= MAXSYMLINKS) {
                   2261:                        error = ELOOP;
                   2262:                        break;
                   2263:                }
1.91      fvdl     2264:                if (ndp->ni_vp->v_mount->mnt_flag & MNT_SYMPERM) {
1.149.2.7  yamt     2265:                        error = VOP_ACCESS(ndp->ni_vp, VEXEC, cnp->cn_cred);
1.91      fvdl     2266:                        if (error != 0)
                   2267:                                break;
                   2268:                }
1.43      fvdl     2269:                if (ndp->ni_pathlen > 1)
1.81      thorpej  2270:                        cp = PNBUF_GET();
1.1       cgd      2271:                else
1.43      fvdl     2272:                        cp = cnp->cn_pnbuf;
                   2273:                aiov.iov_base = cp;
                   2274:                aiov.iov_len = MAXPATHLEN;
                   2275:                auio.uio_iov = &aiov;
                   2276:                auio.uio_iovcnt = 1;
                   2277:                auio.uio_offset = 0;
                   2278:                auio.uio_rw = UIO_READ;
                   2279:                auio.uio_resid = MAXPATHLEN;
1.149.2.2  yamt     2280:                UIO_SETUP_SYSSPACE(&auio);
1.43      fvdl     2281:                error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred);
                   2282:                if (error) {
1.149.2.3  yamt     2283: badlink:
1.43      fvdl     2284:                        if (ndp->ni_pathlen > 1)
1.81      thorpej  2285:                                PNBUF_PUT(cp);
1.43      fvdl     2286:                        break;
                   2287:                }
                   2288:                linklen = MAXPATHLEN - auio.uio_resid;
                   2289:                if (linklen == 0) {
                   2290:                        error = ENOENT;
                   2291:                        goto badlink;
                   2292:                }
                   2293:                if (linklen + ndp->ni_pathlen >= MAXPATHLEN) {
                   2294:                        error = ENAMETOOLONG;
                   2295:                        goto badlink;
                   2296:                }
                   2297:                if (ndp->ni_pathlen > 1) {
1.63      perry    2298:                        memcpy(cp + linklen, ndp->ni_next, ndp->ni_pathlen);
1.81      thorpej  2299:                        PNBUF_PUT(cnp->cn_pnbuf);
1.43      fvdl     2300:                        cnp->cn_pnbuf = cp;
                   2301:                } else
                   2302:                        cnp->cn_pnbuf[linklen] = '\0';
                   2303:                ndp->ni_pathlen += linklen;
1.1       cgd      2304:                vput(ndp->ni_vp);
1.43      fvdl     2305:                dp = ndp->ni_dvp;
1.149.2.3  yamt     2306:
1.43      fvdl     2307:                /*
                   2308:                 * Check if root directory should replace current directory.
                   2309:                 */
                   2310:                if (cnp->cn_pnbuf[0] == '/') {
1.149.2.3  yamt     2311:                        vput(dp);
1.43      fvdl     2312:                        dp = ndp->ni_rootdir;
                   2313:                        VREF(dp);
1.149.2.3  yamt     2314:                        vn_lock(dp, LK_EXCLUSIVE | LK_RETRY);
1.43      fvdl     2315:                }
1.1       cgd      2316:        }
1.43      fvdl     2317:    }
1.149.2.3  yamt     2318:        vput(ndp->ni_dvp);
1.91      fvdl     2319:        vput(ndp->ni_vp);
                   2320:        ndp->ni_vp = NULL;
1.1       cgd      2321: out:
1.81      thorpej  2322:        PNBUF_PUT(cnp->cn_pnbuf);
1.1       cgd      2323:        return (error);
                   2324: }
1.149.2.2  yamt     2325: #endif /* NFSSERVER */
1.1       cgd      2326:
                   2327: /*
1.118     yamt     2328:  * A fiddled version of m_adj() that ensures null fill to a 32-bit
1.1       cgd      2329:  * boundary and only trims off the back end
1.122     yamt     2330:  *
                   2331:  * 1. trim off 'len' bytes as m_adj(mp, -len).
                   2332:  * 2. add zero-padding 'nul' bytes at the end of the mbuf chain.
1.1       cgd      2333:  */
1.12      mycroft  2334: void
1.122     yamt     2335: nfs_zeropad(mp, len, nul)
1.1       cgd      2336:        struct mbuf *mp;
1.75      augustss 2337:        int len;
1.1       cgd      2338:        int nul;
                   2339: {
1.75      augustss 2340:        struct mbuf *m;
1.130     yamt     2341:        int count;
1.1       cgd      2342:
                   2343:        /*
                   2344:         * Trim from tail.  Scan the mbuf chain,
                   2345:         * calculating its length and finding the last mbuf.
                   2346:         * If the adjustment only affects this mbuf, then just
                   2347:         * adjust and return.  Otherwise, rescan and truncate
                   2348:         * after the remaining size.
                   2349:         */
                   2350:        count = 0;
                   2351:        m = mp;
                   2352:        for (;;) {
                   2353:                count += m->m_len;
1.122     yamt     2354:                if (m->m_next == NULL)
1.1       cgd      2355:                        break;
                   2356:                m = m->m_next;
                   2357:        }
1.122     yamt     2358:
                   2359:        KDASSERT(count >= len);
                   2360:
                   2361:        if (m->m_len >= len) {
1.1       cgd      2362:                m->m_len -= len;
1.122     yamt     2363:        } else {
                   2364:                count -= len;
                   2365:                /*
                   2366:                 * Correct length for chain is "count".
                   2367:                 * Find the mbuf with last data, adjust its length,
                   2368:                 * and toss data from remaining mbufs on chain.
                   2369:                 */
                   2370:                for (m = mp; m; m = m->m_next) {
                   2371:                        if (m->m_len >= count) {
                   2372:                                m->m_len = count;
                   2373:                                break;
1.118     yamt     2374:                        }
1.122     yamt     2375:                        count -= m->m_len;
1.1       cgd      2376:                }
1.149.2.2  yamt     2377:                KASSERT(m && m->m_next);
1.122     yamt     2378:                m_freem(m->m_next);
                   2379:                m->m_next = NULL;
1.1       cgd      2380:        }
1.122     yamt     2381:
1.130     yamt     2382:        KDASSERT(m->m_next == NULL);
                   2383:
1.122     yamt     2384:        /*
                   2385:         * zero-padding.
                   2386:         */
                   2387:        if (nul > 0) {
1.130     yamt     2388:                char *cp;
                   2389:                int i;
                   2390:
1.122     yamt     2391:                if (M_ROMAP(m) || M_TRAILINGSPACE(m) < nul) {
                   2392:                        struct mbuf *n;
                   2393:
                   2394:                        KDASSERT(MLEN >= nul);
                   2395:                        n = m_get(M_WAIT, MT_DATA);
                   2396:                        MCLAIM(n, &nfs_mowner);
                   2397:                        n->m_len = nul;
1.130     yamt     2398:                        n->m_next = NULL;
1.122     yamt     2399:                        m->m_next = n;
1.149.2.5  yamt     2400:                        cp = mtod(n, void *);
1.122     yamt     2401:                } else {
1.149.2.5  yamt     2402:                        cp = mtod(m, char *) + m->m_len;
1.122     yamt     2403:                        m->m_len += nul;
1.1       cgd      2404:                }
1.122     yamt     2405:                for (i = 0; i < nul; i++)
                   2406:                        *cp++ = '\0';
1.1       cgd      2407:        }
1.122     yamt     2408:        return;
1.1       cgd      2409: }
                   2410:
                   2411: /*
1.25      fvdl     2412:  * Make these functions instead of macros, so that the kernel text size
                   2413:  * doesn't get too big...
                   2414:  */
                   2415: void
                   2416: nfsm_srvwcc(nfsd, before_ret, before_vap, after_ret, after_vap, mbp, bposp)
                   2417:        struct nfsrv_descript *nfsd;
                   2418:        int before_ret;
1.75      augustss 2419:        struct vattr *before_vap;
1.25      fvdl     2420:        int after_ret;
                   2421:        struct vattr *after_vap;
                   2422:        struct mbuf **mbp;
                   2423:        char **bposp;
                   2424: {
1.109     matt     2425:        struct mbuf *mb = *mbp;
1.75      augustss 2426:        char *bpos = *bposp;
                   2427:        u_int32_t *tl;
1.25      fvdl     2428:
                   2429:        if (before_ret) {
                   2430:                nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED);
                   2431:                *tl = nfs_false;
                   2432:        } else {
                   2433:                nfsm_build(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
                   2434:                *tl++ = nfs_true;
1.66      fair     2435:                txdr_hyper(before_vap->va_size, tl);
1.25      fvdl     2436:                tl += 2;
                   2437:                txdr_nfsv3time(&(before_vap->va_mtime), tl);
                   2438:                tl += 2;
                   2439:                txdr_nfsv3time(&(before_vap->va_ctime), tl);
                   2440:        }
                   2441:        *bposp = bpos;
                   2442:        *mbp = mb;
                   2443:        nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp);
                   2444: }
                   2445:
                   2446: void
                   2447: nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp)
                   2448:        struct nfsrv_descript *nfsd;
                   2449:        int after_ret;
                   2450:        struct vattr *after_vap;
                   2451:        struct mbuf **mbp;
                   2452:        char **bposp;
                   2453: {
1.109     matt     2454:        struct mbuf *mb = *mbp;
1.75      augustss 2455:        char *bpos = *bposp;
                   2456:        u_int32_t *tl;
                   2457:        struct nfs_fattr *fp;
1.25      fvdl     2458:
                   2459:        if (after_ret) {
                   2460:                nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED);
                   2461:                *tl = nfs_false;
                   2462:        } else {
                   2463:                nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_V3FATTR);
                   2464:                *tl++ = nfs_true;
                   2465:                fp = (struct nfs_fattr *)tl;
                   2466:                nfsm_srvfattr(nfsd, after_vap, fp);
                   2467:        }
                   2468:        *mbp = mb;
                   2469:        *bposp = bpos;
                   2470: }
                   2471:
                   2472: void
                   2473: nfsm_srvfattr(nfsd, vap, fp)
1.75      augustss 2474:        struct nfsrv_descript *nfsd;
                   2475:        struct vattr *vap;
                   2476:        struct nfs_fattr *fp;
1.25      fvdl     2477: {
                   2478:
                   2479:        fp->fa_nlink = txdr_unsigned(vap->va_nlink);
                   2480:        fp->fa_uid = txdr_unsigned(vap->va_uid);
                   2481:        fp->fa_gid = txdr_unsigned(vap->va_gid);
                   2482:        if (nfsd->nd_flag & ND_NFSV3) {
                   2483:                fp->fa_type = vtonfsv3_type(vap->va_type);
                   2484:                fp->fa_mode = vtonfsv3_mode(vap->va_mode);
1.66      fair     2485:                txdr_hyper(vap->va_size, &fp->fa3_size);
                   2486:                txdr_hyper(vap->va_bytes, &fp->fa3_used);
1.25      fvdl     2487:                fp->fa3_rdev.specdata1 = txdr_unsigned(major(vap->va_rdev));
                   2488:                fp->fa3_rdev.specdata2 = txdr_unsigned(minor(vap->va_rdev));
                   2489:                fp->fa3_fsid.nfsuquad[0] = 0;
                   2490:                fp->fa3_fsid.nfsuquad[1] = txdr_unsigned(vap->va_fsid);
1.149.2.2  yamt     2491:                txdr_hyper(vap->va_fileid, &fp->fa3_fileid);
1.25      fvdl     2492:                txdr_nfsv3time(&vap->va_atime, &fp->fa3_atime);
                   2493:                txdr_nfsv3time(&vap->va_mtime, &fp->fa3_mtime);
                   2494:                txdr_nfsv3time(&vap->va_ctime, &fp->fa3_ctime);
                   2495:        } else {
                   2496:                fp->fa_type = vtonfsv2_type(vap->va_type);
                   2497:                fp->fa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode);
                   2498:                fp->fa2_size = txdr_unsigned(vap->va_size);
                   2499:                fp->fa2_blocksize = txdr_unsigned(vap->va_blocksize);
                   2500:                if (vap->va_type == VFIFO)
                   2501:                        fp->fa2_rdev = 0xffffffff;
                   2502:                else
                   2503:                        fp->fa2_rdev = txdr_unsigned(vap->va_rdev);
                   2504:                fp->fa2_blocks = txdr_unsigned(vap->va_bytes / NFS_FABLKSIZE);
                   2505:                fp->fa2_fsid = txdr_unsigned(vap->va_fsid);
                   2506:                fp->fa2_fileid = txdr_unsigned(vap->va_fileid);
                   2507:                txdr_nfsv2time(&vap->va_atime, &fp->fa2_atime);
                   2508:                txdr_nfsv2time(&vap->va_mtime, &fp->fa2_mtime);
                   2509:                txdr_nfsv2time(&vap->va_ctime, &fp->fa2_ctime);
                   2510:        }
                   2511: }
                   2512:
1.149.2.2  yamt     2513: #ifdef NFSSERVER
1.25      fvdl     2514: /*
1.1       cgd      2515:  * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked)
                   2516:  *     - look up fsid in mount list (if not found ret error)
1.12      mycroft  2517:  *     - get vp and export rights by calling VFS_FHTOVP()
                   2518:  *     - if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon
1.1       cgd      2519:  *     - if not lockflag unlock it with VOP_UNLOCK()
                   2520:  */
1.24      christos 2521: int
1.149.2.3  yamt     2522: nfsrv_fhtovp(nfsrvfh_t *nsfh, int lockflag, struct vnode **vpp,
                   2523:     kauth_cred_t cred, struct nfssvc_sock *slp, struct mbuf *nam, int *rdonlyp,
                   2524:     int kerbflag, int pubflag)
1.1       cgd      2525: {
1.75      augustss 2526:        struct mount *mp;
1.149.2.2  yamt     2527:        kauth_cred_t credanon;
1.12      mycroft  2528:        int error, exflags;
1.40      fvdl     2529:        struct sockaddr_in *saddr;
1.149.2.3  yamt     2530:        fhandle_t *fhp;
1.1       cgd      2531:
1.149.2.3  yamt     2532:        fhp = NFSRVFH_FHANDLE(nsfh);
1.12      mycroft  2533:        *vpp = (struct vnode *)0;
1.43      fvdl     2534:
1.149.2.3  yamt     2535:        if (nfs_ispublicfh(nsfh)) {
1.43      fvdl     2536:                if (!pubflag || !nfs_pub.np_valid)
                   2537:                        return (ESTALE);
1.149.2.3  yamt     2538:                fhp = nfs_pub.np_handle;
1.43      fvdl     2539:        }
                   2540:
1.149.2.2  yamt     2541:        error = netexport_check(&fhp->fh_fsid, nam, &mp, &exflags, &credanon);
                   2542:        if (error) {
                   2543:                return error;
                   2544:        }
                   2545:
1.124     thorpej  2546:        error = VFS_FHTOVP(mp, &fhp->fh_fid, vpp);
1.24      christos 2547:        if (error)
1.12      mycroft  2548:                return (error);
1.40      fvdl     2549:
1.43      fvdl     2550:        if (!(exflags & (MNT_EXNORESPORT|MNT_EXPUBLIC))) {
1.40      fvdl     2551:                saddr = mtod(nam, struct sockaddr_in *);
1.76      fvdl     2552:                if ((saddr->sin_family == AF_INET) &&
1.40      fvdl     2553:                    ntohs(saddr->sin_port) >= IPPORT_RESERVED) {
                   2554:                        vput(*vpp);
                   2555:                        return (NFSERR_AUTHERR | AUTH_TOOWEAK);
                   2556:                }
1.76      fvdl     2557: #ifdef INET6
                   2558:                if ((saddr->sin_family == AF_INET6) &&
                   2559:                    ntohs(saddr->sin_port) >= IPV6PORT_RESERVED) {
                   2560:                        vput(*vpp);
                   2561:                        return (NFSERR_AUTHERR | AUTH_TOOWEAK);
                   2562:                }
                   2563: #endif
1.40      fvdl     2564:        }
1.12      mycroft  2565:        /*
                   2566:         * Check/setup credentials.
                   2567:         */
                   2568:        if (exflags & MNT_EXKERB) {
1.25      fvdl     2569:                if (!kerbflag) {
1.12      mycroft  2570:                        vput(*vpp);
1.25      fvdl     2571:                        return (NFSERR_AUTHERR | AUTH_TOOWEAK);
1.12      mycroft  2572:                }
1.25      fvdl     2573:        } else if (kerbflag) {
                   2574:                vput(*vpp);
                   2575:                return (NFSERR_AUTHERR | AUTH_TOOWEAK);
1.149.2.2  yamt     2576:        } else if (kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER,
                   2577:                    NULL) == 0 || (exflags & MNT_EXPORTANON)) {
                   2578:                kauth_cred_clone(credanon, cred);
1.12      mycroft  2579:        }
                   2580:        if (exflags & MNT_EXRDONLY)
                   2581:                *rdonlyp = 1;
                   2582:        else
                   2583:                *rdonlyp = 0;
1.1       cgd      2584:        if (!lockflag)
1.56      fvdl     2585:                VOP_UNLOCK(*vpp, 0);
1.1       cgd      2586:        return (0);
1.43      fvdl     2587: }
                   2588:
                   2589: /*
                   2590:  * WebNFS: check if a filehandle is a public filehandle. For v3, this
1.149.2.3  yamt     2591:  * means a length of 0, for v2 it means all zeroes.
1.43      fvdl     2592:  */
                   2593: int
1.149.2.3  yamt     2594: nfs_ispublicfh(const nfsrvfh_t *nsfh)
1.43      fvdl     2595: {
1.149.2.3  yamt     2596:        const char *cp = (const void *)(NFSRVFH_DATA(nsfh));
1.43      fvdl     2597:        int i;
                   2598:
1.149.2.3  yamt     2599:        if (NFSRVFH_SIZE(nsfh) == 0) {
1.149.2.4  yamt     2600:                return true;
1.149.2.3  yamt     2601:        }
                   2602:        if (NFSRVFH_SIZE(nsfh) != NFSX_V2FH) {
1.149.2.4  yamt     2603:                return false;
1.149.2.3  yamt     2604:        }
                   2605:        for (i = 0; i < NFSX_V2FH; i++)
1.43      fvdl     2606:                if (*cp++ != 0)
1.149.2.4  yamt     2607:                        return false;
                   2608:        return true;
1.1       cgd      2609: }
1.149.2.2  yamt     2610: #endif /* NFSSERVER */
1.1       cgd      2611:
                   2612: /*
1.149.2.4  yamt     2613:  * This function compares two net addresses by family and returns true
1.12      mycroft  2614:  * if they are the same host.
1.149.2.4  yamt     2615:  * If there is any doubt, return false.
1.12      mycroft  2616:  * The AF_INET family is handled as a special case so that address mbufs
                   2617:  * don't need to be saved to store "struct in_addr", which is only 4 bytes.
1.1       cgd      2618:  */
1.24      christos 2619: int
1.12      mycroft  2620: netaddr_match(family, haddr, nam)
                   2621:        int family;
                   2622:        union nethostaddr *haddr;
                   2623:        struct mbuf *nam;
1.1       cgd      2624: {
1.75      augustss 2625:        struct sockaddr_in *inetaddr;
1.1       cgd      2626:
1.12      mycroft  2627:        switch (family) {
                   2628:        case AF_INET:
                   2629:                inetaddr = mtod(nam, struct sockaddr_in *);
                   2630:                if (inetaddr->sin_family == AF_INET &&
                   2631:                    inetaddr->sin_addr.s_addr == haddr->had_inetaddr)
                   2632:                        return (1);
                   2633:                break;
1.76      fvdl     2634: #ifdef INET6
                   2635:        case AF_INET6:
                   2636:            {
                   2637:                struct sockaddr_in6 *sin6_1, *sin6_2;
                   2638:
                   2639:                sin6_1 = mtod(nam, struct sockaddr_in6 *);
                   2640:                sin6_2 = mtod(haddr->had_nam, struct sockaddr_in6 *);
                   2641:                if (sin6_1->sin6_family == AF_INET6 &&
                   2642:                    IN6_ARE_ADDR_EQUAL(&sin6_1->sin6_addr, &sin6_2->sin6_addr))
                   2643:                        return 1;
                   2644:            }
                   2645: #endif
1.12      mycroft  2646: #ifdef ISO
                   2647:        case AF_ISO:
                   2648:            {
1.75      augustss 2649:                struct sockaddr_iso *isoaddr1, *isoaddr2;
1.12      mycroft  2650:
                   2651:                isoaddr1 = mtod(nam, struct sockaddr_iso *);
                   2652:                isoaddr2 = mtod(haddr->had_nam, struct sockaddr_iso *);
                   2653:                if (isoaddr1->siso_family == AF_ISO &&
                   2654:                    isoaddr1->siso_nlen > 0 &&
                   2655:                    isoaddr1->siso_nlen == isoaddr2->siso_nlen &&
                   2656:                    SAME_ISOADDR(isoaddr1, isoaddr2))
                   2657:                        return (1);
                   2658:                break;
                   2659:            }
                   2660: #endif /* ISO */
                   2661:        default:
                   2662:                break;
                   2663:        };
                   2664:        return (0);
1.25      fvdl     2665: }
                   2666:
                   2667: /*
                   2668:  * The write verifier has changed (probably due to a server reboot), so all
1.114     yamt     2669:  * PG_NEEDCOMMIT pages will have to be written again. Since they are marked
1.117     yamt     2670:  * as dirty or are being written out just now, all this takes is clearing
                   2671:  * the PG_NEEDCOMMIT flag. Once done the new write verifier can be set for
                   2672:  * the mount point.
1.25      fvdl     2673:  */
                   2674: void
                   2675: nfs_clearcommit(mp)
                   2676:        struct mount *mp;
                   2677: {
1.89      chs      2678:        struct vnode *vp;
1.83      fvdl     2679:        struct nfsnode *np;
1.89      chs      2680:        struct vm_page *pg;
1.116     yamt     2681:        struct nfsmount *nmp = VFSTONFS(mp);
                   2682:
1.149.2.4  yamt     2683:        rw_enter(&nmp->nm_writeverflock, RW_WRITER);
1.149.2.8! yamt     2684:        mutex_enter(&mntvnode_lock);
1.149.2.3  yamt     2685:        TAILQ_FOREACH(vp, &mp->mnt_vnodelist, v_mntvnodes) {
1.89      chs      2686:                KASSERT(vp->v_mount == mp);
1.146     yamt     2687:                if (vp->v_type != VREG)
1.85      enami    2688:                        continue;
1.83      fvdl     2689:                np = VTONFS(vp);
                   2690:                np->n_pushlo = np->n_pushhi = np->n_pushedlo =
                   2691:                    np->n_pushedhi = 0;
                   2692:                np->n_commitflags &=
                   2693:                    ~(NFS_COMMIT_PUSH_VALID | NFS_COMMIT_PUSHED_VALID);
1.149.2.8! yamt     2694:                mutex_enter(&vp->v_uobj.vmobjlock);
1.97      chs      2695:                TAILQ_FOREACH(pg, &vp->v_uobj.memq, listq) {
1.89      chs      2696:                        pg->flags &= ~PG_NEEDCOMMIT;
1.25      fvdl     2697:                }
1.149.2.8! yamt     2698:                mutex_exit(&vp->v_uobj.vmobjlock);
1.25      fvdl     2699:        }
1.149.2.8! yamt     2700:        mutex_exit(&mntvnode_lock);
1.149.2.5  yamt     2701:        mutex_enter(&nmp->nm_lock);
1.116     yamt     2702:        nmp->nm_iflag &= ~NFSMNT_STALEWRITEVERF;
1.149.2.5  yamt     2703:        mutex_exit(&nmp->nm_lock);
1.149.2.4  yamt     2704:        rw_exit(&nmp->nm_writeverflock);
1.83      fvdl     2705: }
                   2706:
                   2707: void
                   2708: nfs_merge_commit_ranges(vp)
                   2709:        struct vnode *vp;
                   2710: {
                   2711:        struct nfsnode *np = VTONFS(vp);
1.112     yamt     2712:
                   2713:        KASSERT(np->n_commitflags & NFS_COMMIT_PUSH_VALID);
1.83      fvdl     2714:
                   2715:        if (!(np->n_commitflags & NFS_COMMIT_PUSHED_VALID)) {
                   2716:                np->n_pushedlo = np->n_pushlo;
                   2717:                np->n_pushedhi = np->n_pushhi;
                   2718:                np->n_commitflags |= NFS_COMMIT_PUSHED_VALID;
                   2719:        } else {
                   2720:                if (np->n_pushlo < np->n_pushedlo)
                   2721:                        np->n_pushedlo = np->n_pushlo;
                   2722:                if (np->n_pushhi > np->n_pushedhi)
                   2723:                        np->n_pushedhi = np->n_pushhi;
                   2724:        }
                   2725:
                   2726:        np->n_pushlo = np->n_pushhi = 0;
                   2727:        np->n_commitflags &= ~NFS_COMMIT_PUSH_VALID;
                   2728:
1.111     yamt     2729: #ifdef NFS_DEBUG_COMMIT
1.83      fvdl     2730:        printf("merge: committed: %u - %u\n", (unsigned)np->n_pushedlo,
                   2731:            (unsigned)np->n_pushedhi);
                   2732: #endif
                   2733: }
                   2734:
                   2735: int
1.89      chs      2736: nfs_in_committed_range(vp, off, len)
1.83      fvdl     2737:        struct vnode *vp;
1.89      chs      2738:        off_t off, len;
1.83      fvdl     2739: {
                   2740:        struct nfsnode *np = VTONFS(vp);
                   2741:        off_t lo, hi;
                   2742:
                   2743:        if (!(np->n_commitflags & NFS_COMMIT_PUSHED_VALID))
                   2744:                return 0;
1.89      chs      2745:        lo = off;
                   2746:        hi = lo + len;
1.83      fvdl     2747:
                   2748:        return (lo >= np->n_pushedlo && hi <= np->n_pushedhi);
                   2749: }
                   2750:
                   2751: int
1.89      chs      2752: nfs_in_tobecommitted_range(vp, off, len)
1.83      fvdl     2753:        struct vnode *vp;
1.89      chs      2754:        off_t off, len;
1.83      fvdl     2755: {
                   2756:        struct nfsnode *np = VTONFS(vp);
                   2757:        off_t lo, hi;
                   2758:
                   2759:        if (!(np->n_commitflags & NFS_COMMIT_PUSH_VALID))
                   2760:                return 0;
1.89      chs      2761:        lo = off;
                   2762:        hi = lo + len;
1.83      fvdl     2763:
                   2764:        return (lo >= np->n_pushlo && hi <= np->n_pushhi);
                   2765: }
                   2766:
                   2767: void
1.89      chs      2768: nfs_add_committed_range(vp, off, len)
1.83      fvdl     2769:        struct vnode *vp;
1.89      chs      2770:        off_t off, len;
1.83      fvdl     2771: {
                   2772:        struct nfsnode *np = VTONFS(vp);
                   2773:        off_t lo, hi;
                   2774:
1.89      chs      2775:        lo = off;
                   2776:        hi = lo + len;
1.83      fvdl     2777:
                   2778:        if (!(np->n_commitflags & NFS_COMMIT_PUSHED_VALID)) {
                   2779:                np->n_pushedlo = lo;
                   2780:                np->n_pushedhi = hi;
                   2781:                np->n_commitflags |= NFS_COMMIT_PUSHED_VALID;
                   2782:        } else {
                   2783:                if (hi > np->n_pushedhi)
                   2784:                        np->n_pushedhi = hi;
                   2785:                if (lo < np->n_pushedlo)
                   2786:                        np->n_pushedlo = lo;
                   2787:        }
1.111     yamt     2788: #ifdef NFS_DEBUG_COMMIT
1.83      fvdl     2789:        printf("add: committed: %u - %u\n", (unsigned)np->n_pushedlo,
                   2790:            (unsigned)np->n_pushedhi);
                   2791: #endif
                   2792: }
                   2793:
                   2794: void
1.89      chs      2795: nfs_del_committed_range(vp, off, len)
1.83      fvdl     2796:        struct vnode *vp;
1.89      chs      2797:        off_t off, len;
1.83      fvdl     2798: {
                   2799:        struct nfsnode *np = VTONFS(vp);
                   2800:        off_t lo, hi;
                   2801:
                   2802:        if (!(np->n_commitflags & NFS_COMMIT_PUSHED_VALID))
                   2803:                return;
                   2804:
1.89      chs      2805:        lo = off;
                   2806:        hi = lo + len;
1.83      fvdl     2807:
                   2808:        if (lo > np->n_pushedhi || hi < np->n_pushedlo)
                   2809:                return;
                   2810:        if (lo <= np->n_pushedlo)
                   2811:                np->n_pushedlo = hi;
                   2812:        else if (hi >= np->n_pushedhi)
                   2813:                np->n_pushedhi = lo;
                   2814:        else {
                   2815:                /*
                   2816:                 * XXX There's only one range. If the deleted range
                   2817:                 * is in the middle, pick the largest of the
                   2818:                 * contiguous ranges that it leaves.
                   2819:                 */
                   2820:                if ((np->n_pushedlo - lo) > (hi - np->n_pushedhi))
                   2821:                        np->n_pushedhi = lo;
                   2822:                else
                   2823:                        np->n_pushedlo = hi;
                   2824:        }
1.111     yamt     2825: #ifdef NFS_DEBUG_COMMIT
1.83      fvdl     2826:        printf("del: committed: %u - %u\n", (unsigned)np->n_pushedlo,
                   2827:            (unsigned)np->n_pushedhi);
                   2828: #endif
                   2829: }
                   2830:
                   2831: void
1.89      chs      2832: nfs_add_tobecommitted_range(vp, off, len)
1.83      fvdl     2833:        struct vnode *vp;
1.89      chs      2834:        off_t off, len;
1.83      fvdl     2835: {
                   2836:        struct nfsnode *np = VTONFS(vp);
                   2837:        off_t lo, hi;
                   2838:
1.89      chs      2839:        lo = off;
                   2840:        hi = lo + len;
1.83      fvdl     2841:
                   2842:        if (!(np->n_commitflags & NFS_COMMIT_PUSH_VALID)) {
                   2843:                np->n_pushlo = lo;
                   2844:                np->n_pushhi = hi;
                   2845:                np->n_commitflags |= NFS_COMMIT_PUSH_VALID;
                   2846:        } else {
                   2847:                if (lo < np->n_pushlo)
                   2848:                        np->n_pushlo = lo;
                   2849:                if (hi > np->n_pushhi)
                   2850:                        np->n_pushhi = hi;
                   2851:        }
1.111     yamt     2852: #ifdef NFS_DEBUG_COMMIT
1.83      fvdl     2853:        printf("add: tobecommitted: %u - %u\n", (unsigned)np->n_pushlo,
                   2854:            (unsigned)np->n_pushhi);
                   2855: #endif
                   2856: }
                   2857:
                   2858: void
1.89      chs      2859: nfs_del_tobecommitted_range(vp, off, len)
1.83      fvdl     2860:        struct vnode *vp;
1.89      chs      2861:        off_t off, len;
1.83      fvdl     2862: {
                   2863:        struct nfsnode *np = VTONFS(vp);
                   2864:        off_t lo, hi;
                   2865:
                   2866:        if (!(np->n_commitflags & NFS_COMMIT_PUSH_VALID))
                   2867:                return;
                   2868:
1.89      chs      2869:        lo = off;
                   2870:        hi = lo + len;
1.83      fvdl     2871:
                   2872:        if (lo > np->n_pushhi || hi < np->n_pushlo)
                   2873:                return;
                   2874:
                   2875:        if (lo <= np->n_pushlo)
                   2876:                np->n_pushlo = hi;
                   2877:        else if (hi >= np->n_pushhi)
                   2878:                np->n_pushhi = lo;
                   2879:        else {
                   2880:                /*
                   2881:                 * XXX There's only one range. If the deleted range
                   2882:                 * is in the middle, pick the largest of the
                   2883:                 * contiguous ranges that it leaves.
                   2884:                 */
                   2885:                if ((np->n_pushlo - lo) > (hi - np->n_pushhi))
                   2886:                        np->n_pushhi = lo;
                   2887:                else
                   2888:                        np->n_pushlo = hi;
                   2889:        }
1.111     yamt     2890: #ifdef NFS_DEBUG_COMMIT
1.83      fvdl     2891:        printf("del: tobecommitted: %u - %u\n", (unsigned)np->n_pushlo,
                   2892:            (unsigned)np->n_pushhi);
                   2893: #endif
1.25      fvdl     2894: }
                   2895:
                   2896: /*
                   2897:  * Map errnos to NFS error numbers. For Version 3 also filter out error
                   2898:  * numbers not specified for the associated procedure.
                   2899:  */
                   2900: int
                   2901: nfsrv_errmap(nd, err)
                   2902:        struct nfsrv_descript *nd;
1.75      augustss 2903:        int err;
1.25      fvdl     2904: {
1.90      jdolecek 2905:        const short *defaulterrp, *errp;
1.25      fvdl     2906:
                   2907:        if (nd->nd_flag & ND_NFSV3) {
                   2908:            if (nd->nd_procnum <= NFSPROC_COMMIT) {
                   2909:                errp = defaulterrp = nfsrv_v3errmap[nd->nd_procnum];
                   2910:                while (*++errp) {
                   2911:                        if (*errp == err)
                   2912:                                return (err);
                   2913:                        else if (*errp > err)
                   2914:                                break;
                   2915:                }
                   2916:                return ((int)*defaulterrp);
                   2917:            } else
                   2918:                return (err & 0xffff);
                   2919:        }
                   2920:        if (err <= ELAST)
                   2921:                return ((int)nfsrv_v2errmap[err - 1]);
                   2922:        return (NFSERR_IO);
                   2923: }
                   2924:
1.126     yamt     2925: u_int32_t
                   2926: nfs_getxid()
                   2927: {
                   2928:        static u_int32_t base;
                   2929:        static u_int32_t nfs_xid = 0;
                   2930:        static struct simplelock nfs_xidlock = SIMPLELOCK_INITIALIZER;
                   2931:        u_int32_t newxid;
                   2932:
                   2933:        simple_lock(&nfs_xidlock);
                   2934:        /*
                   2935:         * derive initial xid from system time
                   2936:         * XXX time is invalid if root not yet mounted
                   2937:         */
                   2938:        if (__predict_false(!base && (rootvp))) {
                   2939:                struct timeval tv;
                   2940:
                   2941:                microtime(&tv);
                   2942:                base = tv.tv_sec << 12;
                   2943:                nfs_xid = base;
                   2944:        }
                   2945:
                   2946:        /*
                   2947:         * Skip zero xid if it should ever happen.
                   2948:         */
                   2949:        if (__predict_false(++nfs_xid == 0))
                   2950:                nfs_xid++;
                   2951:        newxid = nfs_xid;
                   2952:        simple_unlock(&nfs_xidlock);
                   2953:
                   2954:        return txdr_unsigned(newxid);
                   2955: }
                   2956:
                   2957: /*
                   2958:  * assign a new xid for existing request.
                   2959:  * used for NFSERR_JUKEBOX handling.
                   2960:  */
                   2961: void
                   2962: nfs_renewxid(struct nfsreq *req)
                   2963: {
                   2964:        u_int32_t xid;
                   2965:        int off;
                   2966:
                   2967:        xid = nfs_getxid();
                   2968:        if (req->r_nmp->nm_sotype == SOCK_STREAM)
                   2969:                off = sizeof(u_int32_t); /* RPC record mark */
                   2970:        else
                   2971:                off = 0;
                   2972:
                   2973:        m_copyback(req->r_mreq, off, sizeof(xid), (void *)&xid);
                   2974:        req->r_xid = xid;
1.1       cgd      2975: }
1.149.2.3  yamt     2976:
                   2977: #if defined(NFSSERVER)
                   2978: int
1.149.2.4  yamt     2979: nfsrv_composefh(struct vnode *vp, nfsrvfh_t *nsfh, bool v3)
1.149.2.3  yamt     2980: {
                   2981:        int error;
                   2982:        size_t fhsize;
                   2983:
                   2984:        fhsize = NFSD_MAXFHSIZE;
                   2985:        error = vfs_composefh(vp, (void *)NFSRVFH_DATA(nsfh), &fhsize);
                   2986:        if (NFSX_FHTOOBIG_P(fhsize, v3)) {
                   2987:                error = EOPNOTSUPP;
                   2988:        }
                   2989:        if (error != 0) {
                   2990:                return error;
                   2991:        }
                   2992:        if (!v3 && fhsize < NFSX_V2FH) {
                   2993:                memset((char *)NFSRVFH_DATA(nsfh) + fhsize, 0,
                   2994:                    NFSX_V2FH - fhsize);
                   2995:                fhsize = NFSX_V2FH;
                   2996:        }
                   2997:        if ((fhsize % NFSX_UNSIGNED) != 0) {
                   2998:                return EOPNOTSUPP;
                   2999:        }
                   3000:        nsfh->nsfh_size = fhsize;
                   3001:        return 0;
                   3002: }
                   3003:
                   3004: int
                   3005: nfsrv_comparefh(const nfsrvfh_t *fh1, const nfsrvfh_t *fh2)
                   3006: {
                   3007:
                   3008:        if (NFSRVFH_SIZE(fh1) != NFSRVFH_SIZE(fh2)) {
                   3009:                return NFSRVFH_SIZE(fh2) - NFSRVFH_SIZE(fh1);
                   3010:        }
                   3011:        return memcmp(NFSRVFH_DATA(fh1), NFSRVFH_DATA(fh2), NFSRVFH_SIZE(fh1));
                   3012: }
                   3013:
                   3014: void
                   3015: nfsrv_copyfh(nfsrvfh_t *fh1, const nfsrvfh_t *fh2)
                   3016: {
                   3017:        size_t size;
                   3018:
                   3019:        fh1->nsfh_size = size = NFSRVFH_SIZE(fh2);
                   3020:        memcpy(NFSRVFH_DATA(fh1), NFSRVFH_DATA(fh2), size);
                   3021: }
                   3022: #endif /* defined(NFSSERVER) */
1.149.2.6  yamt     3023:
                   3024: #if defined(NFS)
                   3025: /*
                   3026:  * Set the attribute timeout based on how recently the file has been modified.
                   3027:  */
                   3028:
                   3029: time_t
                   3030: nfs_attrtimeo(struct nfsmount *nmp, struct nfsnode *np)
                   3031: {
                   3032:        time_t timeo;
                   3033:
                   3034:        if ((nmp->nm_flag & NFSMNT_NOAC) != 0)
                   3035:                return 0;
                   3036:
                   3037:        if (((np)->n_flag & NMODIFIED) != 0)
                   3038:                return NFS_MINATTRTIMO;
                   3039:
                   3040:        timeo = (time_second - np->n_mtime.tv_sec) / 10;
                   3041:        timeo = max(timeo, NFS_MINATTRTIMO);
                   3042:        timeo = min(timeo, NFS_MAXATTRTIMO);
                   3043:        return timeo;
                   3044: }
                   3045: #endif /* defined(NFS) */

CVSweb <webmaster@jp.NetBSD.org>