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

1.202.2.1! wrstuden    1: /*     $NetBSD: nfs_subs.c,v 1.202 2008/05/05 17:11:17 ad 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.202.2.1! wrstuden   73: __KERNEL_RCSID(0, "$NetBSD: nfs_subs.c,v 1.202 2008/05/05 17:11:17 ad 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.196     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.98      fvdl       97: #include <sys/filedesc.h>
1.30      fvdl       98: #include <sys/time.h>
1.43      fvdl       99: #include <sys/dirent.h>
1.155     thorpej   100: #include <sys/once.h>
1.162     elad      101: #include <sys/kauth.h>
1.1       cgd       102:
1.51      mrg       103: #include <uvm/uvm_extern.h>
                    104:
1.9       mycroft   105: #include <nfs/rpcv2.h>
1.25      fvdl      106: #include <nfs/nfsproto.h>
1.9       mycroft   107: #include <nfs/nfsnode.h>
                    108: #include <nfs/nfs.h>
                    109: #include <nfs/xdr_subs.h>
                    110: #include <nfs/nfsm_subs.h>
1.12      mycroft   111: #include <nfs/nfsmount.h>
                    112: #include <nfs/nfsrtt.h>
1.24      christos  113: #include <nfs/nfs_var.h>
1.12      mycroft   114:
                    115: #include <miscfs/specfs/specdev.h>
1.24      christos  116:
1.12      mycroft   117: #include <netinet/in.h>
                    118: #ifdef ISO
                    119: #include <netiso/iso.h>
                    120: #endif
1.1       cgd       121:
                    122: /*
                    123:  * Data items converted to xdr at startup, since they are constant
                    124:  * This is kinda hokey, but may save a little time doing byte swaps
                    125:  */
1.22      cgd       126: u_int32_t nfs_xdrneg1;
                    127: u_int32_t rpc_call, rpc_vers, rpc_reply, rpc_msgdenied, rpc_autherr,
1.25      fvdl      128:        rpc_mismatch, rpc_auth_unix, rpc_msgaccepted,
1.12      mycroft   129:        rpc_auth_kerb;
1.179     yamt      130: u_int32_t nfs_prog, nfs_true, nfs_false;
1.12      mycroft   131:
1.1       cgd       132: /* And other global data */
1.90      jdolecek  133: const nfstype nfsv2_type[9] =
                    134:        { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFNON, NFCHR, NFNON };
                    135: const nfstype nfsv3_type[9] =
                    136:        { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFSOCK, NFFIFO, NFNON };
                    137: const enum vtype nv2tov_type[8] =
                    138:        { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON, VNON };
                    139: const enum vtype nv3tov_type[8] =
                    140:        { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO };
1.25      fvdl      141: int nfs_ticks;
1.100     chs       142: int nfs_commitsize;
1.108     christos  143:
                    144: MALLOC_DEFINE(M_NFSDIROFF, "NFS diroff", "NFS directory cookies");
1.25      fvdl      145:
1.35      thorpej   146: /* NFS client/server stats. */
                    147: struct nfsstats nfsstats;
                    148:
1.25      fvdl      149: /*
                    150:  * Mapping of old NFS Version 2 RPC numbers to generic numbers.
                    151:  */
1.90      jdolecek  152: const int nfsv3_procid[NFS_NPROCS] = {
1.25      fvdl      153:        NFSPROC_NULL,
                    154:        NFSPROC_GETATTR,
                    155:        NFSPROC_SETATTR,
                    156:        NFSPROC_NOOP,
                    157:        NFSPROC_LOOKUP,
                    158:        NFSPROC_READLINK,
                    159:        NFSPROC_READ,
                    160:        NFSPROC_NOOP,
                    161:        NFSPROC_WRITE,
                    162:        NFSPROC_CREATE,
                    163:        NFSPROC_REMOVE,
                    164:        NFSPROC_RENAME,
                    165:        NFSPROC_LINK,
                    166:        NFSPROC_SYMLINK,
                    167:        NFSPROC_MKDIR,
                    168:        NFSPROC_RMDIR,
                    169:        NFSPROC_READDIR,
                    170:        NFSPROC_FSSTAT,
                    171:        NFSPROC_NOOP,
                    172:        NFSPROC_NOOP,
                    173:        NFSPROC_NOOP,
                    174:        NFSPROC_NOOP,
                    175:        NFSPROC_NOOP
                    176: };
                    177:
                    178: /*
                    179:  * and the reverse mapping from generic to Version 2 procedure numbers
                    180:  */
1.90      jdolecek  181: const int nfsv2_procid[NFS_NPROCS] = {
1.25      fvdl      182:        NFSV2PROC_NULL,
                    183:        NFSV2PROC_GETATTR,
                    184:        NFSV2PROC_SETATTR,
                    185:        NFSV2PROC_LOOKUP,
                    186:        NFSV2PROC_NOOP,
                    187:        NFSV2PROC_READLINK,
                    188:        NFSV2PROC_READ,
                    189:        NFSV2PROC_WRITE,
                    190:        NFSV2PROC_CREATE,
                    191:        NFSV2PROC_MKDIR,
                    192:        NFSV2PROC_SYMLINK,
                    193:        NFSV2PROC_CREATE,
                    194:        NFSV2PROC_REMOVE,
                    195:        NFSV2PROC_RMDIR,
                    196:        NFSV2PROC_RENAME,
                    197:        NFSV2PROC_LINK,
                    198:        NFSV2PROC_READDIR,
                    199:        NFSV2PROC_NOOP,
                    200:        NFSV2PROC_STATFS,
                    201:        NFSV2PROC_NOOP,
                    202:        NFSV2PROC_NOOP,
                    203:        NFSV2PROC_NOOP,
                    204:        NFSV2PROC_NOOP,
                    205: };
                    206:
                    207: /*
                    208:  * Maps errno values to nfs error numbers.
                    209:  * Use NFSERR_IO as the catch all for ones not specifically defined in
                    210:  * RFC 1094.
                    211:  */
1.90      jdolecek  212: static const u_char nfsrv_v2errmap[ELAST] = {
1.25      fvdl      213:   NFSERR_PERM, NFSERR_NOENT,   NFSERR_IO,      NFSERR_IO,      NFSERR_IO,
                    214:   NFSERR_NXIO, NFSERR_IO,      NFSERR_IO,      NFSERR_IO,      NFSERR_IO,
                    215:   NFSERR_IO,   NFSERR_IO,      NFSERR_ACCES,   NFSERR_IO,      NFSERR_IO,
                    216:   NFSERR_IO,   NFSERR_EXIST,   NFSERR_IO,      NFSERR_NODEV,   NFSERR_NOTDIR,
                    217:   NFSERR_ISDIR,        NFSERR_IO,      NFSERR_IO,      NFSERR_IO,      NFSERR_IO,
                    218:   NFSERR_IO,   NFSERR_FBIG,    NFSERR_NOSPC,   NFSERR_IO,      NFSERR_ROFS,
                    219:   NFSERR_IO,   NFSERR_IO,      NFSERR_IO,      NFSERR_IO,      NFSERR_IO,
                    220:   NFSERR_IO,   NFSERR_IO,      NFSERR_IO,      NFSERR_IO,      NFSERR_IO,
                    221:   NFSERR_IO,   NFSERR_IO,      NFSERR_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_NAMETOL, NFSERR_IO,      NFSERR_IO,
                    226:   NFSERR_NOTEMPTY, NFSERR_IO,  NFSERR_IO,      NFSERR_DQUOT,   NFSERR_STALE,
                    227:   NFSERR_IO,   NFSERR_IO,      NFSERR_IO,      NFSERR_IO,      NFSERR_IO,
                    228:   NFSERR_IO,   NFSERR_IO,      NFSERR_IO,      NFSERR_IO,      NFSERR_IO,
1.52      mikel     229:   NFSERR_IO,   NFSERR_IO,
1.25      fvdl      230: };
                    231:
                    232: /*
                    233:  * Maps errno values to nfs error numbers.
                    234:  * Although it is not obvious whether or not NFS clients really care if
                    235:  * a returned error value is in the specified list for the procedure, the
                    236:  * safest thing to do is filter them appropriately. For Version 2, the
                    237:  * X/Open XNFS document is the only specification that defines error values
                    238:  * for each RPC (The RFC simply lists all possible error values for all RPCs),
                    239:  * so I have decided to not do this for Version 2.
                    240:  * The first entry is the default error return and the rest are the valid
                    241:  * errors for that RPC in increasing numeric order.
                    242:  */
1.90      jdolecek  243: static const short nfsv3err_null[] = {
1.25      fvdl      244:        0,
                    245:        0,
                    246: };
                    247:
1.90      jdolecek  248: static const short nfsv3err_getattr[] = {
1.25      fvdl      249:        NFSERR_IO,
                    250:        NFSERR_IO,
                    251:        NFSERR_STALE,
                    252:        NFSERR_BADHANDLE,
                    253:        NFSERR_SERVERFAULT,
                    254:        0,
                    255: };
                    256:
1.90      jdolecek  257: static const short nfsv3err_setattr[] = {
1.25      fvdl      258:        NFSERR_IO,
                    259:        NFSERR_PERM,
                    260:        NFSERR_IO,
                    261:        NFSERR_ACCES,
                    262:        NFSERR_INVAL,
                    263:        NFSERR_NOSPC,
                    264:        NFSERR_ROFS,
                    265:        NFSERR_DQUOT,
                    266:        NFSERR_STALE,
                    267:        NFSERR_BADHANDLE,
                    268:        NFSERR_NOT_SYNC,
                    269:        NFSERR_SERVERFAULT,
                    270:        0,
                    271: };
                    272:
1.90      jdolecek  273: static const short nfsv3err_lookup[] = {
1.25      fvdl      274:        NFSERR_IO,
                    275:        NFSERR_NOENT,
                    276:        NFSERR_IO,
                    277:        NFSERR_ACCES,
                    278:        NFSERR_NOTDIR,
                    279:        NFSERR_NAMETOL,
                    280:        NFSERR_STALE,
                    281:        NFSERR_BADHANDLE,
                    282:        NFSERR_SERVERFAULT,
                    283:        0,
                    284: };
                    285:
1.90      jdolecek  286: static const short nfsv3err_access[] = {
1.25      fvdl      287:        NFSERR_IO,
                    288:        NFSERR_IO,
                    289:        NFSERR_STALE,
                    290:        NFSERR_BADHANDLE,
                    291:        NFSERR_SERVERFAULT,
                    292:        0,
                    293: };
                    294:
1.90      jdolecek  295: static const short nfsv3err_readlink[] = {
1.25      fvdl      296:        NFSERR_IO,
                    297:        NFSERR_IO,
                    298:        NFSERR_ACCES,
                    299:        NFSERR_INVAL,
                    300:        NFSERR_STALE,
                    301:        NFSERR_BADHANDLE,
                    302:        NFSERR_NOTSUPP,
                    303:        NFSERR_SERVERFAULT,
                    304:        0,
                    305: };
                    306:
1.90      jdolecek  307: static const short nfsv3err_read[] = {
1.25      fvdl      308:        NFSERR_IO,
                    309:        NFSERR_IO,
                    310:        NFSERR_NXIO,
                    311:        NFSERR_ACCES,
                    312:        NFSERR_INVAL,
                    313:        NFSERR_STALE,
                    314:        NFSERR_BADHANDLE,
                    315:        NFSERR_SERVERFAULT,
1.67      fvdl      316:        NFSERR_JUKEBOX,
1.25      fvdl      317:        0,
                    318: };
                    319:
1.90      jdolecek  320: static const short nfsv3err_write[] = {
1.25      fvdl      321:        NFSERR_IO,
                    322:        NFSERR_IO,
                    323:        NFSERR_ACCES,
                    324:        NFSERR_INVAL,
                    325:        NFSERR_FBIG,
                    326:        NFSERR_NOSPC,
                    327:        NFSERR_ROFS,
                    328:        NFSERR_DQUOT,
                    329:        NFSERR_STALE,
                    330:        NFSERR_BADHANDLE,
                    331:        NFSERR_SERVERFAULT,
1.68      fvdl      332:        NFSERR_JUKEBOX,
1.25      fvdl      333:        0,
                    334: };
                    335:
1.90      jdolecek  336: static const short nfsv3err_create[] = {
1.25      fvdl      337:        NFSERR_IO,
                    338:        NFSERR_IO,
                    339:        NFSERR_ACCES,
                    340:        NFSERR_EXIST,
                    341:        NFSERR_NOTDIR,
                    342:        NFSERR_NOSPC,
                    343:        NFSERR_ROFS,
                    344:        NFSERR_NAMETOL,
                    345:        NFSERR_DQUOT,
                    346:        NFSERR_STALE,
                    347:        NFSERR_BADHANDLE,
                    348:        NFSERR_NOTSUPP,
                    349:        NFSERR_SERVERFAULT,
                    350:        0,
                    351: };
                    352:
1.90      jdolecek  353: static const short nfsv3err_mkdir[] = {
1.25      fvdl      354:        NFSERR_IO,
                    355:        NFSERR_IO,
                    356:        NFSERR_ACCES,
                    357:        NFSERR_EXIST,
                    358:        NFSERR_NOTDIR,
                    359:        NFSERR_NOSPC,
                    360:        NFSERR_ROFS,
                    361:        NFSERR_NAMETOL,
                    362:        NFSERR_DQUOT,
                    363:        NFSERR_STALE,
                    364:        NFSERR_BADHANDLE,
                    365:        NFSERR_NOTSUPP,
                    366:        NFSERR_SERVERFAULT,
                    367:        0,
                    368: };
                    369:
1.90      jdolecek  370: static const short nfsv3err_symlink[] = {
1.25      fvdl      371:        NFSERR_IO,
                    372:        NFSERR_IO,
                    373:        NFSERR_ACCES,
                    374:        NFSERR_EXIST,
                    375:        NFSERR_NOTDIR,
                    376:        NFSERR_NOSPC,
                    377:        NFSERR_ROFS,
                    378:        NFSERR_NAMETOL,
                    379:        NFSERR_DQUOT,
                    380:        NFSERR_STALE,
                    381:        NFSERR_BADHANDLE,
                    382:        NFSERR_NOTSUPP,
                    383:        NFSERR_SERVERFAULT,
                    384:        0,
                    385: };
                    386:
1.90      jdolecek  387: static const short nfsv3err_mknod[] = {
1.25      fvdl      388:        NFSERR_IO,
                    389:        NFSERR_IO,
                    390:        NFSERR_ACCES,
                    391:        NFSERR_EXIST,
                    392:        NFSERR_NOTDIR,
                    393:        NFSERR_NOSPC,
                    394:        NFSERR_ROFS,
                    395:        NFSERR_NAMETOL,
                    396:        NFSERR_DQUOT,
                    397:        NFSERR_STALE,
                    398:        NFSERR_BADHANDLE,
                    399:        NFSERR_NOTSUPP,
                    400:        NFSERR_SERVERFAULT,
                    401:        NFSERR_BADTYPE,
                    402:        0,
                    403: };
                    404:
1.90      jdolecek  405: static const short nfsv3err_remove[] = {
1.25      fvdl      406:        NFSERR_IO,
                    407:        NFSERR_NOENT,
                    408:        NFSERR_IO,
                    409:        NFSERR_ACCES,
                    410:        NFSERR_NOTDIR,
                    411:        NFSERR_ROFS,
                    412:        NFSERR_NAMETOL,
                    413:        NFSERR_STALE,
                    414:        NFSERR_BADHANDLE,
                    415:        NFSERR_SERVERFAULT,
                    416:        0,
                    417: };
                    418:
1.90      jdolecek  419: static const short nfsv3err_rmdir[] = {
1.25      fvdl      420:        NFSERR_IO,
                    421:        NFSERR_NOENT,
                    422:        NFSERR_IO,
                    423:        NFSERR_ACCES,
                    424:        NFSERR_EXIST,
                    425:        NFSERR_NOTDIR,
                    426:        NFSERR_INVAL,
                    427:        NFSERR_ROFS,
                    428:        NFSERR_NAMETOL,
                    429:        NFSERR_NOTEMPTY,
                    430:        NFSERR_STALE,
                    431:        NFSERR_BADHANDLE,
                    432:        NFSERR_NOTSUPP,
                    433:        NFSERR_SERVERFAULT,
                    434:        0,
                    435: };
                    436:
1.90      jdolecek  437: static const short nfsv3err_rename[] = {
1.25      fvdl      438:        NFSERR_IO,
                    439:        NFSERR_NOENT,
                    440:        NFSERR_IO,
                    441:        NFSERR_ACCES,
                    442:        NFSERR_EXIST,
                    443:        NFSERR_XDEV,
                    444:        NFSERR_NOTDIR,
                    445:        NFSERR_ISDIR,
                    446:        NFSERR_INVAL,
                    447:        NFSERR_NOSPC,
                    448:        NFSERR_ROFS,
                    449:        NFSERR_MLINK,
                    450:        NFSERR_NAMETOL,
                    451:        NFSERR_NOTEMPTY,
                    452:        NFSERR_DQUOT,
                    453:        NFSERR_STALE,
                    454:        NFSERR_BADHANDLE,
                    455:        NFSERR_NOTSUPP,
                    456:        NFSERR_SERVERFAULT,
                    457:        0,
                    458: };
                    459:
1.90      jdolecek  460: static const short nfsv3err_link[] = {
1.25      fvdl      461:        NFSERR_IO,
                    462:        NFSERR_IO,
                    463:        NFSERR_ACCES,
                    464:        NFSERR_EXIST,
                    465:        NFSERR_XDEV,
                    466:        NFSERR_NOTDIR,
                    467:        NFSERR_INVAL,
                    468:        NFSERR_NOSPC,
                    469:        NFSERR_ROFS,
                    470:        NFSERR_MLINK,
                    471:        NFSERR_NAMETOL,
                    472:        NFSERR_DQUOT,
                    473:        NFSERR_STALE,
                    474:        NFSERR_BADHANDLE,
                    475:        NFSERR_NOTSUPP,
                    476:        NFSERR_SERVERFAULT,
                    477:        0,
                    478: };
                    479:
1.90      jdolecek  480: static const short nfsv3err_readdir[] = {
1.25      fvdl      481:        NFSERR_IO,
                    482:        NFSERR_IO,
                    483:        NFSERR_ACCES,
                    484:        NFSERR_NOTDIR,
                    485:        NFSERR_STALE,
                    486:        NFSERR_BADHANDLE,
                    487:        NFSERR_BAD_COOKIE,
                    488:        NFSERR_TOOSMALL,
                    489:        NFSERR_SERVERFAULT,
                    490:        0,
                    491: };
                    492:
1.90      jdolecek  493: static const short nfsv3err_readdirplus[] = {
1.25      fvdl      494:        NFSERR_IO,
                    495:        NFSERR_IO,
                    496:        NFSERR_ACCES,
                    497:        NFSERR_NOTDIR,
                    498:        NFSERR_STALE,
                    499:        NFSERR_BADHANDLE,
                    500:        NFSERR_BAD_COOKIE,
                    501:        NFSERR_NOTSUPP,
                    502:        NFSERR_TOOSMALL,
                    503:        NFSERR_SERVERFAULT,
                    504:        0,
                    505: };
                    506:
1.90      jdolecek  507: static const short nfsv3err_fsstat[] = {
1.25      fvdl      508:        NFSERR_IO,
                    509:        NFSERR_IO,
                    510:        NFSERR_STALE,
                    511:        NFSERR_BADHANDLE,
                    512:        NFSERR_SERVERFAULT,
                    513:        0,
                    514: };
                    515:
1.90      jdolecek  516: static const short nfsv3err_fsinfo[] = {
1.25      fvdl      517:        NFSERR_STALE,
                    518:        NFSERR_STALE,
                    519:        NFSERR_BADHANDLE,
                    520:        NFSERR_SERVERFAULT,
                    521:        0,
                    522: };
                    523:
1.90      jdolecek  524: static const short nfsv3err_pathconf[] = {
1.25      fvdl      525:        NFSERR_STALE,
                    526:        NFSERR_STALE,
                    527:        NFSERR_BADHANDLE,
                    528:        NFSERR_SERVERFAULT,
                    529:        0,
                    530: };
                    531:
1.90      jdolecek  532: static const short nfsv3err_commit[] = {
1.25      fvdl      533:        NFSERR_IO,
                    534:        NFSERR_IO,
                    535:        NFSERR_STALE,
                    536:        NFSERR_BADHANDLE,
                    537:        NFSERR_SERVERFAULT,
                    538:        0,
                    539: };
                    540:
1.90      jdolecek  541: static const short * const nfsrv_v3errmap[] = {
1.25      fvdl      542:        nfsv3err_null,
                    543:        nfsv3err_getattr,
                    544:        nfsv3err_setattr,
                    545:        nfsv3err_lookup,
                    546:        nfsv3err_access,
                    547:        nfsv3err_readlink,
                    548:        nfsv3err_read,
                    549:        nfsv3err_write,
                    550:        nfsv3err_create,
                    551:        nfsv3err_mkdir,
                    552:        nfsv3err_symlink,
                    553:        nfsv3err_mknod,
                    554:        nfsv3err_remove,
                    555:        nfsv3err_rmdir,
                    556:        nfsv3err_rename,
                    557:        nfsv3err_link,
                    558:        nfsv3err_readdir,
                    559:        nfsv3err_readdirplus,
                    560:        nfsv3err_fsstat,
                    561:        nfsv3err_fsinfo,
                    562:        nfsv3err_pathconf,
                    563:        nfsv3err_commit,
                    564: };
                    565:
1.202.2.1! wrstuden  566: extern struct vfs_hooks nfs_export_hooks;
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.183     christos  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.183     christos  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.183     christos  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.162     elad      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.183     christos  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.183     christos  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.179     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.162     elad      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.162     elad      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.183     christos  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.183     christos  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.183     christos  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.183     christos  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.183     christos  781:                                mbufcp = mtod(mp, void *);
1.1       cgd       782:                                len = mp->m_len;
                    783:                        }
                    784:                        xfer = (left > len) ? len : left;
1.158     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.183     christos  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.183     christos  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.158     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.183     christos  866:                        cp = mtod(mp, char *) + mp->m_len;
1.158     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.183     christos  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.183     christos  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.183     christos  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.183     christos  912:        char **dposp;
1.1       cgd       913:        int siz;
                    914:        int left;
1.183     christos  915:        char **cp2;
1.1       cgd       916: {
1.75      augustss  917:        struct mbuf *m1, *m2;
1.39      fvdl      918:        struct mbuf *havebuf = NULL;
1.183     christos  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.183     christos  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.201     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.201     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.201     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.201     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.201     yamt     1020:                MRESETDATA(m1);
                   1021:                dst = mtod(m1, char *);
                   1022:                if (dst != src) {
1.63      perry    1023:                        memmove(dst, src, left);
1.201     yamt     1024:                }
1.39      fvdl     1025:                m1->m_len = left;
                   1026:                m2 = m1->m_next;
1.201     yamt     1027:                *cp2 = m1->m_data;
1.1       cgd      1028:        }
1.201     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.201     yamt     1035:        dst = mtod(m1, char *) + m1->m_len;
1.129     itojun   1036:        while ((len = M_TRAILINGSPACE(m1)) != 0 && m2) {
1.201     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.183     christos 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.183     christos 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.183     christos 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.183     christos 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.183     christos 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.195     ad       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.202     ad       1206:        dircache = hashinit(NFS_DIRHASHSIZ, HASH_LIST, true,
                   1207:            &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)
1.202     ad       1218:                hashdone(dircache, HASH_LIST, nfsdirhashmask);
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.196     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.196     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.196     yamt     1282:                kmem_free(ndp, sizeof(*ndp));
1.49      fvdl     1283: }
                   1284:
1.135     yamt     1285: static void
1.177     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.196     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.171     christos 1370: nfs_enterdircache(struct vnode *vp, off_t off, off_t blkoff, int en,
1.177     yamt     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.161     christos 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.196     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.160     christos 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.181     thorpej  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.196     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.157     yamt     1521: static int
1.155     thorpej  1522: nfs_init0(void)
1.1       cgd      1523: {
1.189     ad       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.182     thorpej  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.202.2.1! wrstuden 1543:        vfs_hooks_attach(&nfs_export_hooks);
1.12      mycroft  1544:        nfsrv_init(0);                  /* Init server data structures */
1.1       cgd      1545:        nfsrv_initcache();              /* Init the server request cache */
1.190     ad       1546:        {
                   1547:                extern krwlock_t netexport_lock;        /* XXX */
                   1548:                rw_init(&netexport_lock);
                   1549:        }
1.36      fvdl     1550: #endif /* NFSSERVER */
1.12      mycroft  1551:
1.164     yamt     1552: #if defined(NFSSERVER) || (defined(NFS) && !defined(NFS_V2_ONLY))
                   1553:        nfsdreq_init();
                   1554: #endif /* defined(NFSSERVER) || (defined(NFS) && !defined(NFS_V2_ONLY)) */
                   1555:
1.1       cgd      1556:        /*
                   1557:         * Initialize reply list and start timer
                   1558:         */
1.16      mycroft  1559:        TAILQ_INIT(&nfs_reqq);
1.191     yamt     1560:        nfs_timer_init();
1.109     matt     1561:        MOWNER_ATTACH(&nfs_mowner);
1.106     jdolecek 1562:
                   1563: #ifdef NFS
                   1564:        /* Initialize the kqueue structures */
                   1565:        nfs_kqinit();
1.119     yamt     1566:        /* Initialize the iod structures */
                   1567:        nfs_iodinit();
1.106     jdolecek 1568: #endif
1.157     yamt     1569:        return 0;
1.1       cgd      1570: }
                   1571:
1.155     thorpej  1572: void
                   1573: nfs_init(void)
                   1574: {
                   1575:        static ONCE_DECL(nfs_init_once);
                   1576:
                   1577:        RUN_ONCE(&nfs_init_once, nfs_init0);
                   1578: }
                   1579:
1.38      thorpej  1580: #ifdef NFS
1.35      thorpej  1581: /*
                   1582:  * Called once at VFS init to initialize client-specific data structures.
                   1583:  */
                   1584: void
                   1585: nfs_vfs_init()
                   1586: {
1.155     thorpej  1587:        /* Initialize NFS server / client shared data. */
                   1588:        nfs_init();
                   1589:
1.96      chs      1590:        nfs_nhinit();                   /* Init the nfsnode table */
1.100     chs      1591:        nfs_commitsize = uvmexp.npages << (PAGE_SHIFT - 4);
1.96      chs      1592: }
1.35      thorpej  1593:
1.96      chs      1594: void
                   1595: nfs_vfs_reinit()
                   1596: {
                   1597:        nfs_nhreinit();
1.73      jdolecek 1598: }
                   1599:
                   1600: void
                   1601: nfs_vfs_done()
                   1602: {
                   1603:        nfs_nhdone();
1.35      thorpej  1604: }
                   1605:
1.1       cgd      1606: /*
1.12      mycroft  1607:  * Attribute cache routines.
                   1608:  * nfs_loadattrcache() - loads or updates the cache contents from attributes
                   1609:  *     that are on the mbuf list
                   1610:  * nfs_getattrcache() - returns valid attributes if found in cache, returns
                   1611:  *     error otherwise
1.1       cgd      1612:  */
1.12      mycroft  1613:
                   1614: /*
                   1615:  * Load the attribute cache (that lives in the nfsnode entry) with
                   1616:  * the values on the mbuf list and
                   1617:  * Iff vap not NULL
                   1618:  *    copy the attributes to *vaper
                   1619:  */
1.24      christos 1620: int
1.105     yamt     1621: nfsm_loadattrcache(vpp, mdp, dposp, vaper, flags)
1.12      mycroft  1622:        struct vnode **vpp;
                   1623:        struct mbuf **mdp;
1.183     christos 1624:        char **dposp;
1.12      mycroft  1625:        struct vattr *vaper;
1.105     yamt     1626:        int flags;
1.1       cgd      1627: {
1.75      augustss 1628:        int32_t t1;
1.183     christos 1629:        char *cp2;
1.25      fvdl     1630:        int error = 0;
1.12      mycroft  1631:        struct mbuf *md;
1.45      fvdl     1632:        int v3 = NFS_ISV3(*vpp);
1.1       cgd      1633:
1.12      mycroft  1634:        md = *mdp;
1.183     christos 1635:        t1 = (mtod(md, char *) + md->m_len) - *dposp;
1.25      fvdl     1636:        error = nfsm_disct(mdp, dposp, NFSX_FATTR(v3), t1, &cp2);
1.24      christos 1637:        if (error)
1.12      mycroft  1638:                return (error);
1.105     yamt     1639:        return nfs_loadattrcache(vpp, (struct nfs_fattr *)cp2, vaper, flags);
1.45      fvdl     1640: }
                   1641:
                   1642: int
1.105     yamt     1643: nfs_loadattrcache(vpp, fp, vaper, flags)
1.45      fvdl     1644:        struct vnode **vpp;
                   1645:        struct nfs_fattr *fp;
                   1646:        struct vattr *vaper;
1.105     yamt     1647:        int flags;
1.45      fvdl     1648: {
1.75      augustss 1649:        struct vnode *vp = *vpp;
                   1650:        struct vattr *vap;
1.45      fvdl     1651:        int v3 = NFS_ISV3(vp);
                   1652:        enum vtype vtyp;
                   1653:        u_short vmode;
                   1654:        struct timespec mtime;
1.139     yamt     1655:        struct timespec ctime;
1.45      fvdl     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.180     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.197     ad       1706:                        spec_node_init(vp, (dev_t)rdev);
1.12      mycroft  1707:                }
1.128     yamt     1708:                np->n_mtime = mtime;
1.12      mycroft  1709:        }
1.101     fvdl     1710:        uid = fxdr_unsigned(uid_t, fp->fa_uid);
                   1711:        gid = fxdr_unsigned(gid_t, fp->fa_gid);
1.49      fvdl     1712:        vap = np->n_vattr;
1.101     fvdl     1713:
                   1714:        /*
1.139     yamt     1715:         * Invalidate access cache if uid, gid, mode or ctime changed.
1.101     fvdl     1716:         */
                   1717:        if (np->n_accstamp != -1 &&
1.139     yamt     1718:            (gid != vap->va_gid || uid != vap->va_uid || vmode != vap->va_mode
                   1719:            || timespeccmp(&ctime, &vap->va_ctime, !=)))
1.101     fvdl     1720:                np->n_accstamp = -1;
                   1721:
1.12      mycroft  1722:        vap->va_type = vtyp;
1.101     fvdl     1723:        vap->va_mode = vmode;
1.12      mycroft  1724:        vap->va_rdev = (dev_t)rdev;
                   1725:        vap->va_mtime = mtime;
1.139     yamt     1726:        vap->va_ctime = ctime;
1.133     christos 1727:        vap->va_fsid = vp->v_mount->mnt_stat.f_fsidx.__fsid_val[0];
1.72      fvdl     1728:        switch (vtyp) {
                   1729:        case VDIR:
                   1730:                vap->va_blocksize = NFS_DIRFRAGSIZ;
                   1731:                break;
                   1732:        case VBLK:
                   1733:                vap->va_blocksize = BLKDEV_IOSIZE;
                   1734:                break;
                   1735:        case VCHR:
                   1736:                vap->va_blocksize = MAXBSIZE;
                   1737:                break;
                   1738:        default:
                   1739:                vap->va_blocksize = v3 ? vp->v_mount->mnt_stat.f_iosize :
                   1740:                    fxdr_unsigned(int32_t, fp->fa2_blocksize);
                   1741:                break;
                   1742:        }
1.25      fvdl     1743:        if (v3) {
                   1744:                vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink);
1.101     fvdl     1745:                vap->va_uid = uid;
                   1746:                vap->va_gid = gid;
1.66      fair     1747:                vap->va_size = fxdr_hyper(&fp->fa3_size);
                   1748:                vap->va_bytes = fxdr_hyper(&fp->fa3_used);
1.151     yamt     1749:                vap->va_fileid = fxdr_hyper(&fp->fa3_fileid);
1.25      fvdl     1750:                fxdr_nfsv3time(&fp->fa3_atime, &vap->va_atime);
                   1751:                vap->va_flags = 0;
                   1752:                vap->va_filerev = 0;
1.12      mycroft  1753:        } else {
1.25      fvdl     1754:                vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink);
1.101     fvdl     1755:                vap->va_uid = uid;
                   1756:                vap->va_gid = gid;
1.25      fvdl     1757:                vap->va_size = fxdr_unsigned(u_int32_t, fp->fa2_size);
                   1758:                vap->va_bytes = fxdr_unsigned(int32_t, fp->fa2_blocks)
                   1759:                    * NFS_FABLKSIZE;
                   1760:                vap->va_fileid = fxdr_unsigned(int32_t, fp->fa2_fileid);
                   1761:                fxdr_nfsv2time(&fp->fa2_atime, &vap->va_atime);
1.12      mycroft  1762:                vap->va_flags = 0;
1.25      fvdl     1763:                vap->va_gen = fxdr_unsigned(u_int32_t,fp->fa2_ctime.nfsv2_usec);
1.12      mycroft  1764:                vap->va_filerev = 0;
                   1765:        }
1.199     yamt     1766:        if (vap->va_size > VFSTONFS(vp->v_mount)->nm_maxfilesize) {
                   1767:                return EFBIG;
                   1768:        }
1.12      mycroft  1769:        if (vap->va_size != np->n_size) {
1.89      chs      1770:                if ((np->n_flag & NMODIFIED) && vap->va_size < np->n_size) {
                   1771:                        vap->va_size = np->n_size;
                   1772:                } else {
1.12      mycroft  1773:                        np->n_size = vap->va_size;
1.89      chs      1774:                        if (vap->va_type == VREG) {
1.140     yamt     1775:                                /*
                   1776:                                 * we can't free pages if NAC_NOTRUNC because
                   1777:                                 * the pages can be owned by ourselves.
                   1778:                                 */
                   1779:                                if (flags & NAC_NOTRUNC) {
1.105     yamt     1780:                                        np->n_flag |= NTRUNCDELAYED;
1.140     yamt     1781:                                } else {
1.174     yamt     1782:                                        genfs_node_wrlock(vp);
1.195     ad       1783:                                        mutex_enter(&vp->v_interlock);
1.140     yamt     1784:                                        (void)VOP_PUTPAGES(vp, 0,
                   1785:                                            0, PGO_SYNCIO | PGO_CLEANIT |
                   1786:                                            PGO_FREE | PGO_ALLPAGES);
1.105     yamt     1787:                                        uvm_vnp_setsize(vp, np->n_size);
1.174     yamt     1788:                                        genfs_node_unlock(vp);
1.105     yamt     1789:                                }
1.89      chs      1790:                        }
                   1791:                }
1.12      mycroft  1792:        }
1.165     kardel   1793:        np->n_attrstamp = time_second;
1.12      mycroft  1794:        if (vaper != NULL) {
1.183     christos 1795:                memcpy((void *)vaper, (void *)vap, sizeof(*vap));
1.12      mycroft  1796:                if (np->n_flag & NCHG) {
1.25      fvdl     1797:                        if (np->n_flag & NACC)
                   1798:                                vaper->va_atime = np->n_atim;
                   1799:                        if (np->n_flag & NUPD)
                   1800:                                vaper->va_mtime = np->n_mtim;
1.12      mycroft  1801:                }
                   1802:        }
                   1803:        return (0);
                   1804: }
                   1805:
                   1806: /*
                   1807:  * Check the time stamp
                   1808:  * If the cache is valid, copy contents to *vap and return 0
                   1809:  * otherwise return an error
                   1810:  */
1.24      christos 1811: int
1.12      mycroft  1812: nfs_getattrcache(vp, vaper)
1.75      augustss 1813:        struct vnode *vp;
1.12      mycroft  1814:        struct vattr *vaper;
                   1815: {
1.75      augustss 1816:        struct nfsnode *np = VTONFS(vp);
1.152     christos 1817:        struct nfsmount *nmp = VFSTONFS(vp->v_mount);
1.75      augustss 1818:        struct vattr *vap;
1.12      mycroft  1819:
1.132     yamt     1820:        if (np->n_attrstamp == 0 ||
1.192     yamt     1821:            (time_second - np->n_attrstamp) >= nfs_attrtimeo(nmp, np)) {
1.12      mycroft  1822:                nfsstats.attrcache_misses++;
                   1823:                return (ENOENT);
                   1824:        }
                   1825:        nfsstats.attrcache_hits++;
1.49      fvdl     1826:        vap = np->n_vattr;
1.12      mycroft  1827:        if (vap->va_size != np->n_size) {
                   1828:                if (vap->va_type == VREG) {
1.188     yamt     1829:                        if ((np->n_flag & NMODIFIED) != 0 &&
                   1830:                            vap->va_size < np->n_size) {
                   1831:                                vap->va_size = np->n_size;
                   1832:                        } else {
1.12      mycroft  1833:                                np->n_size = vap->va_size;
1.188     yamt     1834:                        }
1.174     yamt     1835:                        genfs_node_wrlock(vp);
1.51      mrg      1836:                        uvm_vnp_setsize(vp, np->n_size);
1.174     yamt     1837:                        genfs_node_unlock(vp);
1.12      mycroft  1838:                } else
                   1839:                        np->n_size = vap->va_size;
                   1840:        }
1.183     christos 1841:        memcpy((void *)vaper, (void *)vap, sizeof(struct vattr));
1.12      mycroft  1842:        if (np->n_flag & NCHG) {
1.25      fvdl     1843:                if (np->n_flag & NACC)
                   1844:                        vaper->va_atime = np->n_atim;
                   1845:                if (np->n_flag & NUPD)
                   1846:                        vaper->va_mtime = np->n_mtim;
1.1       cgd      1847:        }
1.12      mycroft  1848:        return (0);
1.105     yamt     1849: }
                   1850:
                   1851: void
                   1852: nfs_delayedtruncate(vp)
                   1853:        struct vnode *vp;
                   1854: {
                   1855:        struct nfsnode *np = VTONFS(vp);
                   1856:
                   1857:        if (np->n_flag & NTRUNCDELAYED) {
                   1858:                np->n_flag &= ~NTRUNCDELAYED;
1.174     yamt     1859:                genfs_node_wrlock(vp);
1.195     ad       1860:                mutex_enter(&vp->v_interlock);
1.140     yamt     1861:                (void)VOP_PUTPAGES(vp, 0,
                   1862:                    0, PGO_SYNCIO | PGO_CLEANIT | PGO_FREE | PGO_ALLPAGES);
1.105     yamt     1863:                uvm_vnp_setsize(vp, np->n_size);
1.174     yamt     1864:                genfs_node_unlock(vp);
1.105     yamt     1865:        }
1.1       cgd      1866: }
1.48      fvdl     1867:
1.141     yamt     1868: #define        NFS_WCCKLUDGE_TIMEOUT   (24 * 60 * 60)  /* 1 day */
                   1869: #define        NFS_WCCKLUDGE(nmp, now) \
                   1870:        (((nmp)->nm_iflag & NFSMNT_WCCKLUDGE) && \
                   1871:        ((now) - (nmp)->nm_wcckludgetime - NFS_WCCKLUDGE_TIMEOUT) < 0)
                   1872:
                   1873: /*
                   1874:  * nfs_check_wccdata: check inaccurate wcc_data
                   1875:  *
                   1876:  * => return non-zero if we shouldn't trust the wcc_data.
                   1877:  * => NFS_WCCKLUDGE_TIMEOUT is for the case that the server is "fixed".
                   1878:  */
                   1879:
                   1880: int
1.177     yamt     1881: nfs_check_wccdata(struct nfsnode *np, const struct timespec *ctime,
1.181     thorpej  1882:     struct timespec *mtime, bool docheck)
1.141     yamt     1883: {
                   1884:        int error = 0;
                   1885:
                   1886: #if !defined(NFS_V2_ONLY)
                   1887:
                   1888:        if (docheck) {
                   1889:                struct vnode *vp = NFSTOV(np);
                   1890:                struct nfsmount *nmp;
1.165     kardel   1891:                long now = time_second;
1.184     yamt     1892:                const struct timespec *omtime = &np->n_vattr->va_mtime;
                   1893:                const struct timespec *octime = &np->n_vattr->va_ctime;
1.141     yamt     1894:                const char *reason = NULL; /* XXX: gcc */
                   1895:
1.184     yamt     1896:                if (timespeccmp(omtime, mtime, <=)) {
1.141     yamt     1897:                        reason = "mtime";
                   1898:                        error = EINVAL;
                   1899:                }
                   1900:
1.184     yamt     1901:                if (vp->v_type == VDIR && timespeccmp(octime, ctime, <=)) {
1.141     yamt     1902:                        reason = "ctime";
                   1903:                        error = EINVAL;
                   1904:                }
                   1905:
                   1906:                nmp = VFSTONFS(vp->v_mount);
                   1907:                if (error) {
1.143     yamt     1908:
                   1909:                        /*
                   1910:                         * despite of the fact that we've updated the file,
                   1911:                         * timestamps of the file were not updated as we
                   1912:                         * expected.
                   1913:                         * it means that the server has incompatible
                   1914:                         * semantics of timestamps or (more likely)
                   1915:                         * the server time is not precise enough to
                   1916:                         * track each modifications.
                   1917:                         * in that case, we disable wcc processing.
                   1918:                         *
                   1919:                         * yes, strictly speaking, we should disable all
                   1920:                         * caching.  it's a compromise.
                   1921:                         */
                   1922:
1.186     yamt     1923:                        mutex_enter(&nmp->nm_lock);
1.141     yamt     1924:                        if (!NFS_WCCKLUDGE(nmp, now)) {
                   1925:                                printf("%s: inaccurate wcc data (%s) detected,"
1.184     yamt     1926:                                    " disabling wcc"
                   1927:                                    " (ctime %u.%09u %u.%09u,"
                   1928:                                    " mtime %u.%09u %u.%09u)\n",
1.141     yamt     1929:                                    vp->v_mount->mnt_stat.f_mntfromname,
1.184     yamt     1930:                                    reason,
                   1931:                                    (unsigned int)octime->tv_sec,
                   1932:                                    (unsigned int)octime->tv_nsec,
                   1933:                                    (unsigned int)ctime->tv_sec,
                   1934:                                    (unsigned int)ctime->tv_nsec,
                   1935:                                    (unsigned int)omtime->tv_sec,
                   1936:                                    (unsigned int)omtime->tv_nsec,
                   1937:                                    (unsigned int)mtime->tv_sec,
                   1938:                                    (unsigned int)mtime->tv_nsec);
1.141     yamt     1939:                        }
                   1940:                        nmp->nm_iflag |= NFSMNT_WCCKLUDGE;
                   1941:                        nmp->nm_wcckludgetime = now;
1.186     yamt     1942:                        mutex_exit(&nmp->nm_lock);
1.141     yamt     1943:                } else if (NFS_WCCKLUDGE(nmp, now)) {
                   1944:                        error = EPERM; /* XXX */
                   1945:                } else if (nmp->nm_iflag & NFSMNT_WCCKLUDGE) {
1.186     yamt     1946:                        mutex_enter(&nmp->nm_lock);
1.141     yamt     1947:                        if (nmp->nm_iflag & NFSMNT_WCCKLUDGE) {
                   1948:                                printf("%s: re-enabling wcc\n",
                   1949:                                    vp->v_mount->mnt_stat.f_mntfromname);
                   1950:                                nmp->nm_iflag &= ~NFSMNT_WCCKLUDGE;
                   1951:                        }
1.186     yamt     1952:                        mutex_exit(&nmp->nm_lock);
1.141     yamt     1953:                }
                   1954:        }
                   1955:
                   1956: #endif /* !defined(NFS_V2_ONLY) */
                   1957:
                   1958:        return error;
                   1959: }
                   1960:
1.48      fvdl     1961: /*
                   1962:  * Heuristic to see if the server XDR encodes directory cookies or not.
                   1963:  * it is not supposed to, but a lot of servers may do this. Also, since
                   1964:  * most/all servers will implement V2 as well, it is expected that they
                   1965:  * may return just 32 bits worth of cookie information, so we need to
                   1966:  * find out in which 32 bits this information is available. We do this
                   1967:  * to avoid trouble with emulated binaries that can't handle 64 bit
                   1968:  * directory offsets.
                   1969:  */
                   1970:
                   1971: void
1.156     christos 1972: nfs_cookieheuristic(vp, flagp, l, cred)
1.48      fvdl     1973:        struct vnode *vp;
                   1974:        int *flagp;
1.156     christos 1975:        struct lwp *l;
1.162     elad     1976:        kauth_cred_t cred;
1.48      fvdl     1977: {
                   1978:        struct uio auio;
                   1979:        struct iovec aiov;
1.183     christos 1980:        char *tbuf, *cp;
1.48      fvdl     1981:        struct dirent *dp;
1.57      fvdl     1982:        off_t *cookies = NULL, *cop;
1.48      fvdl     1983:        int error, eof, nc, len;
                   1984:
1.183     christos 1985:        MALLOC(tbuf, void *, NFS_DIRFRAGSIZ, M_TEMP, M_WAITOK);
1.48      fvdl     1986:
1.149     christos 1987:        aiov.iov_base = tbuf;
1.48      fvdl     1988:        aiov.iov_len = NFS_DIRFRAGSIZ;
                   1989:        auio.uio_iov = &aiov;
                   1990:        auio.uio_iovcnt = 1;
                   1991:        auio.uio_rw = UIO_READ;
                   1992:        auio.uio_resid = NFS_DIRFRAGSIZ;
                   1993:        auio.uio_offset = 0;
1.158     yamt     1994:        UIO_SETUP_SYSSPACE(&auio);
1.48      fvdl     1995:
1.56      fvdl     1996:        error = VOP_READDIR(vp, &auio, cred, &eof, &cookies, &nc);
1.48      fvdl     1997:
                   1998:        len = NFS_DIRFRAGSIZ - auio.uio_resid;
                   1999:        if (error || len == 0) {
1.149     christos 2000:                FREE(tbuf, M_TEMP);
1.57      fvdl     2001:                if (cookies)
1.80      thorpej  2002:                        free(cookies, M_TEMP);
1.48      fvdl     2003:                return;
                   2004:        }
                   2005:
                   2006:        /*
                   2007:         * Find the first valid entry and look at its offset cookie.
                   2008:         */
                   2009:
1.149     christos 2010:        cp = tbuf;
1.48      fvdl     2011:        for (cop = cookies; len > 0; len -= dp->d_reclen) {
                   2012:                dp = (struct dirent *)cp;
                   2013:                if (dp->d_fileno != 0 && len >= dp->d_reclen) {
                   2014:                        if ((*cop >> 32) != 0 && (*cop & 0xffffffffLL) == 0) {
                   2015:                                *flagp |= NFSMNT_SWAPCOOKIE;
1.49      fvdl     2016:                                nfs_invaldircache(vp, 0);
1.156     christos 2017:                                nfs_vinvalbuf(vp, 0, cred, l, 1);
1.48      fvdl     2018:                        }
                   2019:                        break;
                   2020:                }
                   2021:                cop++;
                   2022:                cp += dp->d_reclen;
                   2023:        }
                   2024:
1.149     christos 2025:        FREE(tbuf, M_TEMP);
1.80      thorpej  2026:        free(cookies, M_TEMP);
1.48      fvdl     2027: }
1.38      thorpej  2028: #endif /* NFS */
1.1       cgd      2029:
1.153     jmmv     2030: #ifdef NFSSERVER
1.1       cgd      2031: /*
1.43      fvdl     2032:  * Set up nameidata for a lookup() call and do it.
                   2033:  *
                   2034:  * If pubflag is set, this call is done for a lookup operation on the
                   2035:  * public filehandle. In that case we allow crossing mountpoints and
                   2036:  * absolute pathnames. However, the caller is expected to check that
                   2037:  * the lookup result is within the public fs, and deny access if
                   2038:  * it is not.
1.1       cgd      2039:  */
1.24      christos 2040: int
1.168     yamt     2041: nfs_namei(ndp, nsfh, len, slp, nam, mdp, dposp, retdirp, l, kerbflag, pubflag)
1.75      augustss 2042:        struct nameidata *ndp;
1.168     yamt     2043:        nfsrvfh_t *nsfh;
1.110     yamt     2044:        uint32_t len;
1.12      mycroft  2045:        struct nfssvc_sock *slp;
                   2046:        struct mbuf *nam;
1.1       cgd      2047:        struct mbuf **mdp;
1.183     christos 2048:        char **dposp;
1.25      fvdl     2049:        struct vnode **retdirp;
1.156     christos 2050:        struct lwp *l;
1.43      fvdl     2051:        int kerbflag, pubflag;
1.1       cgd      2052: {
1.75      augustss 2053:        int i, rem;
                   2054:        struct mbuf *md;
                   2055:        char *fromcp, *tocp, *cp;
1.43      fvdl     2056:        struct iovec aiov;
                   2057:        struct uio auio;
1.1       cgd      2058:        struct vnode *dp;
1.43      fvdl     2059:        int error, rdonly, linklen;
1.12      mycroft  2060:        struct componentname *cnp = &ndp->ni_cnd;
1.1       cgd      2061:
1.178     chs      2062:        *retdirp = NULL;
1.81      thorpej  2063:
                   2064:        if ((len + 1) > MAXPATHLEN)
                   2065:                return (ENAMETOOLONG);
1.147     yamt     2066:        if (len == 0)
                   2067:                return (EACCES);
1.81      thorpej  2068:        cnp->cn_pnbuf = PNBUF_GET();
                   2069:
1.1       cgd      2070:        /*
                   2071:         * Copy the name from the mbuf list to ndp->ni_pnbuf
                   2072:         * and set the various ndp fields appropriately.
                   2073:         */
                   2074:        fromcp = *dposp;
1.12      mycroft  2075:        tocp = cnp->cn_pnbuf;
1.1       cgd      2076:        md = *mdp;
1.183     christos 2077:        rem = mtod(md, char *) + md->m_len - fromcp;
1.1       cgd      2078:        for (i = 0; i < len; i++) {
                   2079:                while (rem == 0) {
                   2080:                        md = md->m_next;
                   2081:                        if (md == NULL) {
                   2082:                                error = EBADRPC;
                   2083:                                goto out;
                   2084:                        }
1.183     christos 2085:                        fromcp = mtod(md, void *);
1.1       cgd      2086:                        rem = md->m_len;
                   2087:                }
1.43      fvdl     2088:                if (*fromcp == '\0' || (!pubflag && *fromcp == '/')) {
1.25      fvdl     2089:                        error = EACCES;
1.1       cgd      2090:                        goto out;
                   2091:                }
                   2092:                *tocp++ = *fromcp++;
                   2093:                rem--;
                   2094:        }
                   2095:        *tocp = '\0';
                   2096:        *mdp = md;
                   2097:        *dposp = fromcp;
                   2098:        len = nfsm_rndup(len)-len;
                   2099:        if (len > 0) {
                   2100:                if (rem >= len)
                   2101:                        *dposp += len;
1.24      christos 2102:                else if ((error = nfs_adv(mdp, dposp, len, rem)) != 0)
1.1       cgd      2103:                        goto out;
                   2104:        }
1.43      fvdl     2105:
1.1       cgd      2106:        /*
                   2107:         * Extract and set starting directory.
                   2108:         */
1.182     thorpej  2109:        error = nfsrv_fhtovp(nsfh, false, &dp, ndp->ni_cnd.cn_cred, slp,
1.124     thorpej  2110:            nam, &rdonly, kerbflag, pubflag);
1.24      christos 2111:        if (error)
1.1       cgd      2112:                goto out;
                   2113:        if (dp->v_type != VDIR) {
                   2114:                vrele(dp);
                   2115:                error = ENOTDIR;
                   2116:                goto out;
                   2117:        }
1.43      fvdl     2118:
                   2119:        if (rdonly)
                   2120:                cnp->cn_flags |= RDONLY;
                   2121:
                   2122:        *retdirp = dp;
                   2123:
                   2124:        if (pubflag) {
                   2125:                /*
                   2126:                 * Oh joy. For WebNFS, handle those pesky '%' escapes,
                   2127:                 * and the 'native path' indicator.
                   2128:                 */
1.81      thorpej  2129:                cp = PNBUF_GET();
1.43      fvdl     2130:                fromcp = cnp->cn_pnbuf;
                   2131:                tocp = cp;
                   2132:                if ((unsigned char)*fromcp >= WEBNFS_SPECCHAR_START) {
                   2133:                        switch ((unsigned char)*fromcp) {
                   2134:                        case WEBNFS_NATIVE_CHAR:
                   2135:                                /*
                   2136:                                 * 'Native' path for us is the same
                   2137:                                 * as a path according to the NFS spec,
                   2138:                                 * just skip the escape char.
                   2139:                                 */
                   2140:                                fromcp++;
                   2141:                                break;
                   2142:                        /*
                   2143:                         * More may be added in the future, range 0x80-0xff
                   2144:                         */
                   2145:                        default:
                   2146:                                error = EIO;
1.178     chs      2147:                                vrele(dp);
1.104     enami    2148:                                PNBUF_PUT(cp);
1.43      fvdl     2149:                                goto out;
                   2150:                        }
                   2151:                }
                   2152:                /*
                   2153:                 * Translate the '%' escapes, URL-style.
                   2154:                 */
                   2155:                while (*fromcp != '\0') {
                   2156:                        if (*fromcp == WEBNFS_ESC_CHAR) {
                   2157:                                if (fromcp[1] != '\0' && fromcp[2] != '\0') {
                   2158:                                        fromcp++;
                   2159:                                        *tocp++ = HEXSTRTOI(fromcp);
                   2160:                                        fromcp += 2;
                   2161:                                        continue;
                   2162:                                } else {
                   2163:                                        error = ENOENT;
1.178     chs      2164:                                        vrele(dp);
1.104     enami    2165:                                        PNBUF_PUT(cp);
1.43      fvdl     2166:                                        goto out;
                   2167:                                }
                   2168:                        } else
                   2169:                                *tocp++ = *fromcp++;
                   2170:                }
                   2171:                *tocp = '\0';
1.81      thorpej  2172:                PNBUF_PUT(cnp->cn_pnbuf);
1.43      fvdl     2173:                cnp->cn_pnbuf = cp;
                   2174:        }
                   2175:
                   2176:        ndp->ni_pathlen = (tocp - cnp->cn_pnbuf) + 1;
                   2177:        ndp->ni_segflg = UIO_SYSSPACE;
1.98      fvdl     2178:        ndp->ni_rootdir = rootvnode;
1.185     dsl      2179:        ndp->ni_erootdir = NULL;
1.43      fvdl     2180:
                   2181:        if (pubflag) {
                   2182:                ndp->ni_loopcnt = 0;
                   2183:                if (cnp->cn_pnbuf[0] == '/')
                   2184:                        dp = rootvnode;
                   2185:        } else {
                   2186:                cnp->cn_flags |= NOCROSSMOUNT;
                   2187:        }
                   2188:
1.25      fvdl     2189:        VREF(dp);
1.178     chs      2190:        vn_lock(dp, LK_EXCLUSIVE | LK_RETRY);
1.43      fvdl     2191:
                   2192:     for (;;) {
                   2193:        cnp->cn_nameptr = cnp->cn_pnbuf;
1.1       cgd      2194:        ndp->ni_startdir = dp;
1.178     chs      2195:
1.1       cgd      2196:        /*
                   2197:         * And call lookup() to do the real work
                   2198:         */
1.25      fvdl     2199:        error = lookup(ndp);
1.91      fvdl     2200:        if (error) {
1.178     chs      2201:                if (ndp->ni_dvp) {
                   2202:                        vput(ndp->ni_dvp);
                   2203:                }
1.91      fvdl     2204:                PNBUF_PUT(cnp->cn_pnbuf);
                   2205:                return (error);
                   2206:        }
1.178     chs      2207:
1.1       cgd      2208:        /*
                   2209:         * Check for encountering a symbolic link
                   2210:         */
1.43      fvdl     2211:        if ((cnp->cn_flags & ISSYMLINK) == 0) {
1.178     chs      2212:                if ((cnp->cn_flags & LOCKPARENT) == 0 && ndp->ni_dvp) {
                   2213:                        if (ndp->ni_dvp == ndp->ni_vp) {
                   2214:                                vrele(ndp->ni_dvp);
                   2215:                        } else {
                   2216:                                vput(ndp->ni_dvp);
                   2217:                        }
                   2218:                }
1.91      fvdl     2219:                if (cnp->cn_flags & (SAVENAME | SAVESTART))
1.43      fvdl     2220:                        cnp->cn_flags |= HASBUF;
1.91      fvdl     2221:                else
                   2222:                        PNBUF_PUT(cnp->cn_pnbuf);
                   2223:                return (0);
1.43      fvdl     2224:        } else {
                   2225:                if (!pubflag) {
                   2226:                        error = EINVAL;
                   2227:                        break;
                   2228:                }
                   2229:                if (ndp->ni_loopcnt++ >= MAXSYMLINKS) {
                   2230:                        error = ELOOP;
                   2231:                        break;
                   2232:                }
1.91      fvdl     2233:                if (ndp->ni_vp->v_mount->mnt_flag & MNT_SYMPERM) {
1.193     pooka    2234:                        error = VOP_ACCESS(ndp->ni_vp, VEXEC, cnp->cn_cred);
1.91      fvdl     2235:                        if (error != 0)
                   2236:                                break;
                   2237:                }
1.43      fvdl     2238:                if (ndp->ni_pathlen > 1)
1.81      thorpej  2239:                        cp = PNBUF_GET();
1.1       cgd      2240:                else
1.43      fvdl     2241:                        cp = cnp->cn_pnbuf;
                   2242:                aiov.iov_base = cp;
                   2243:                aiov.iov_len = MAXPATHLEN;
                   2244:                auio.uio_iov = &aiov;
                   2245:                auio.uio_iovcnt = 1;
                   2246:                auio.uio_offset = 0;
                   2247:                auio.uio_rw = UIO_READ;
                   2248:                auio.uio_resid = MAXPATHLEN;
1.158     yamt     2249:                UIO_SETUP_SYSSPACE(&auio);
1.43      fvdl     2250:                error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred);
                   2251:                if (error) {
1.178     chs      2252: badlink:
1.43      fvdl     2253:                        if (ndp->ni_pathlen > 1)
1.81      thorpej  2254:                                PNBUF_PUT(cp);
1.43      fvdl     2255:                        break;
                   2256:                }
                   2257:                linklen = MAXPATHLEN - auio.uio_resid;
                   2258:                if (linklen == 0) {
                   2259:                        error = ENOENT;
                   2260:                        goto badlink;
                   2261:                }
                   2262:                if (linklen + ndp->ni_pathlen >= MAXPATHLEN) {
                   2263:                        error = ENAMETOOLONG;
                   2264:                        goto badlink;
                   2265:                }
                   2266:                if (ndp->ni_pathlen > 1) {
1.63      perry    2267:                        memcpy(cp + linklen, ndp->ni_next, ndp->ni_pathlen);
1.81      thorpej  2268:                        PNBUF_PUT(cnp->cn_pnbuf);
1.43      fvdl     2269:                        cnp->cn_pnbuf = cp;
                   2270:                } else
                   2271:                        cnp->cn_pnbuf[linklen] = '\0';
                   2272:                ndp->ni_pathlen += linklen;
1.1       cgd      2273:                vput(ndp->ni_vp);
1.43      fvdl     2274:                dp = ndp->ni_dvp;
1.178     chs      2275:
1.43      fvdl     2276:                /*
                   2277:                 * Check if root directory should replace current directory.
                   2278:                 */
                   2279:                if (cnp->cn_pnbuf[0] == '/') {
1.178     chs      2280:                        vput(dp);
1.43      fvdl     2281:                        dp = ndp->ni_rootdir;
                   2282:                        VREF(dp);
1.178     chs      2283:                        vn_lock(dp, LK_EXCLUSIVE | LK_RETRY);
1.43      fvdl     2284:                }
1.1       cgd      2285:        }
1.43      fvdl     2286:    }
1.178     chs      2287:        vput(ndp->ni_dvp);
1.91      fvdl     2288:        vput(ndp->ni_vp);
                   2289:        ndp->ni_vp = NULL;
1.1       cgd      2290: out:
1.81      thorpej  2291:        PNBUF_PUT(cnp->cn_pnbuf);
1.1       cgd      2292:        return (error);
                   2293: }
1.153     jmmv     2294: #endif /* NFSSERVER */
1.1       cgd      2295:
                   2296: /*
1.118     yamt     2297:  * A fiddled version of m_adj() that ensures null fill to a 32-bit
1.1       cgd      2298:  * boundary and only trims off the back end
1.122     yamt     2299:  *
                   2300:  * 1. trim off 'len' bytes as m_adj(mp, -len).
                   2301:  * 2. add zero-padding 'nul' bytes at the end of the mbuf chain.
1.1       cgd      2302:  */
1.12      mycroft  2303: void
1.122     yamt     2304: nfs_zeropad(mp, len, nul)
1.1       cgd      2305:        struct mbuf *mp;
1.75      augustss 2306:        int len;
1.1       cgd      2307:        int nul;
                   2308: {
1.75      augustss 2309:        struct mbuf *m;
1.130     yamt     2310:        int count;
1.1       cgd      2311:
                   2312:        /*
                   2313:         * Trim from tail.  Scan the mbuf chain,
                   2314:         * calculating its length and finding the last mbuf.
                   2315:         * If the adjustment only affects this mbuf, then just
                   2316:         * adjust and return.  Otherwise, rescan and truncate
                   2317:         * after the remaining size.
                   2318:         */
                   2319:        count = 0;
                   2320:        m = mp;
                   2321:        for (;;) {
                   2322:                count += m->m_len;
1.122     yamt     2323:                if (m->m_next == NULL)
1.1       cgd      2324:                        break;
                   2325:                m = m->m_next;
                   2326:        }
1.122     yamt     2327:
                   2328:        KDASSERT(count >= len);
                   2329:
                   2330:        if (m->m_len >= len) {
1.1       cgd      2331:                m->m_len -= len;
1.122     yamt     2332:        } else {
                   2333:                count -= len;
                   2334:                /*
                   2335:                 * Correct length for chain is "count".
                   2336:                 * Find the mbuf with last data, adjust its length,
                   2337:                 * and toss data from remaining mbufs on chain.
                   2338:                 */
                   2339:                for (m = mp; m; m = m->m_next) {
                   2340:                        if (m->m_len >= count) {
                   2341:                                m->m_len = count;
                   2342:                                break;
1.118     yamt     2343:                        }
1.122     yamt     2344:                        count -= m->m_len;
1.1       cgd      2345:                }
1.159     christos 2346:                KASSERT(m && m->m_next);
1.122     yamt     2347:                m_freem(m->m_next);
                   2348:                m->m_next = NULL;
1.1       cgd      2349:        }
1.122     yamt     2350:
1.130     yamt     2351:        KDASSERT(m->m_next == NULL);
                   2352:
1.122     yamt     2353:        /*
                   2354:         * zero-padding.
                   2355:         */
                   2356:        if (nul > 0) {
1.130     yamt     2357:                char *cp;
                   2358:                int i;
                   2359:
1.122     yamt     2360:                if (M_ROMAP(m) || M_TRAILINGSPACE(m) < nul) {
                   2361:                        struct mbuf *n;
                   2362:
                   2363:                        KDASSERT(MLEN >= nul);
                   2364:                        n = m_get(M_WAIT, MT_DATA);
                   2365:                        MCLAIM(n, &nfs_mowner);
                   2366:                        n->m_len = nul;
1.130     yamt     2367:                        n->m_next = NULL;
1.122     yamt     2368:                        m->m_next = n;
1.183     christos 2369:                        cp = mtod(n, void *);
1.122     yamt     2370:                } else {
1.183     christos 2371:                        cp = mtod(m, char *) + m->m_len;
1.122     yamt     2372:                        m->m_len += nul;
1.1       cgd      2373:                }
1.122     yamt     2374:                for (i = 0; i < nul; i++)
                   2375:                        *cp++ = '\0';
1.1       cgd      2376:        }
1.122     yamt     2377:        return;
1.1       cgd      2378: }
                   2379:
                   2380: /*
1.25      fvdl     2381:  * Make these functions instead of macros, so that the kernel text size
                   2382:  * doesn't get too big...
                   2383:  */
                   2384: void
                   2385: nfsm_srvwcc(nfsd, before_ret, before_vap, after_ret, after_vap, mbp, bposp)
                   2386:        struct nfsrv_descript *nfsd;
                   2387:        int before_ret;
1.75      augustss 2388:        struct vattr *before_vap;
1.25      fvdl     2389:        int after_ret;
                   2390:        struct vattr *after_vap;
                   2391:        struct mbuf **mbp;
                   2392:        char **bposp;
                   2393: {
1.109     matt     2394:        struct mbuf *mb = *mbp;
1.75      augustss 2395:        char *bpos = *bposp;
                   2396:        u_int32_t *tl;
1.25      fvdl     2397:
                   2398:        if (before_ret) {
                   2399:                nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED);
                   2400:                *tl = nfs_false;
                   2401:        } else {
                   2402:                nfsm_build(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
                   2403:                *tl++ = nfs_true;
1.66      fair     2404:                txdr_hyper(before_vap->va_size, tl);
1.25      fvdl     2405:                tl += 2;
                   2406:                txdr_nfsv3time(&(before_vap->va_mtime), tl);
                   2407:                tl += 2;
                   2408:                txdr_nfsv3time(&(before_vap->va_ctime), tl);
                   2409:        }
                   2410:        *bposp = bpos;
                   2411:        *mbp = mb;
                   2412:        nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp);
                   2413: }
                   2414:
                   2415: void
                   2416: nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp)
                   2417:        struct nfsrv_descript *nfsd;
                   2418:        int after_ret;
                   2419:        struct vattr *after_vap;
                   2420:        struct mbuf **mbp;
                   2421:        char **bposp;
                   2422: {
1.109     matt     2423:        struct mbuf *mb = *mbp;
1.75      augustss 2424:        char *bpos = *bposp;
                   2425:        u_int32_t *tl;
                   2426:        struct nfs_fattr *fp;
1.25      fvdl     2427:
                   2428:        if (after_ret) {
                   2429:                nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED);
                   2430:                *tl = nfs_false;
                   2431:        } else {
                   2432:                nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_V3FATTR);
                   2433:                *tl++ = nfs_true;
                   2434:                fp = (struct nfs_fattr *)tl;
                   2435:                nfsm_srvfattr(nfsd, after_vap, fp);
                   2436:        }
                   2437:        *mbp = mb;
                   2438:        *bposp = bpos;
                   2439: }
                   2440:
                   2441: void
                   2442: nfsm_srvfattr(nfsd, vap, fp)
1.75      augustss 2443:        struct nfsrv_descript *nfsd;
                   2444:        struct vattr *vap;
                   2445:        struct nfs_fattr *fp;
1.25      fvdl     2446: {
                   2447:
                   2448:        fp->fa_nlink = txdr_unsigned(vap->va_nlink);
                   2449:        fp->fa_uid = txdr_unsigned(vap->va_uid);
                   2450:        fp->fa_gid = txdr_unsigned(vap->va_gid);
                   2451:        if (nfsd->nd_flag & ND_NFSV3) {
                   2452:                fp->fa_type = vtonfsv3_type(vap->va_type);
                   2453:                fp->fa_mode = vtonfsv3_mode(vap->va_mode);
1.66      fair     2454:                txdr_hyper(vap->va_size, &fp->fa3_size);
                   2455:                txdr_hyper(vap->va_bytes, &fp->fa3_used);
1.25      fvdl     2456:                fp->fa3_rdev.specdata1 = txdr_unsigned(major(vap->va_rdev));
                   2457:                fp->fa3_rdev.specdata2 = txdr_unsigned(minor(vap->va_rdev));
                   2458:                fp->fa3_fsid.nfsuquad[0] = 0;
                   2459:                fp->fa3_fsid.nfsuquad[1] = txdr_unsigned(vap->va_fsid);
1.151     yamt     2460:                txdr_hyper(vap->va_fileid, &fp->fa3_fileid);
1.25      fvdl     2461:                txdr_nfsv3time(&vap->va_atime, &fp->fa3_atime);
                   2462:                txdr_nfsv3time(&vap->va_mtime, &fp->fa3_mtime);
                   2463:                txdr_nfsv3time(&vap->va_ctime, &fp->fa3_ctime);
                   2464:        } else {
                   2465:                fp->fa_type = vtonfsv2_type(vap->va_type);
                   2466:                fp->fa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode);
                   2467:                fp->fa2_size = txdr_unsigned(vap->va_size);
                   2468:                fp->fa2_blocksize = txdr_unsigned(vap->va_blocksize);
                   2469:                if (vap->va_type == VFIFO)
                   2470:                        fp->fa2_rdev = 0xffffffff;
                   2471:                else
                   2472:                        fp->fa2_rdev = txdr_unsigned(vap->va_rdev);
                   2473:                fp->fa2_blocks = txdr_unsigned(vap->va_bytes / NFS_FABLKSIZE);
                   2474:                fp->fa2_fsid = txdr_unsigned(vap->va_fsid);
                   2475:                fp->fa2_fileid = txdr_unsigned(vap->va_fileid);
                   2476:                txdr_nfsv2time(&vap->va_atime, &fp->fa2_atime);
                   2477:                txdr_nfsv2time(&vap->va_mtime, &fp->fa2_mtime);
                   2478:                txdr_nfsv2time(&vap->va_ctime, &fp->fa2_ctime);
                   2479:        }
                   2480: }
                   2481:
1.153     jmmv     2482: #ifdef NFSSERVER
1.25      fvdl     2483: /*
1.1       cgd      2484:  * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked)
                   2485:  *     - look up fsid in mount list (if not found ret error)
1.12      mycroft  2486:  *     - get vp and export rights by calling VFS_FHTOVP()
                   2487:  *     - if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon
1.1       cgd      2488:  *     - if not lockflag unlock it with VOP_UNLOCK()
                   2489:  */
1.24      christos 2490: int
1.177     yamt     2491: nfsrv_fhtovp(nfsrvfh_t *nsfh, int lockflag, struct vnode **vpp,
                   2492:     kauth_cred_t cred, struct nfssvc_sock *slp, struct mbuf *nam, int *rdonlyp,
                   2493:     int kerbflag, int pubflag)
1.1       cgd      2494: {
1.75      augustss 2495:        struct mount *mp;
1.162     elad     2496:        kauth_cred_t credanon;
1.12      mycroft  2497:        int error, exflags;
1.40      fvdl     2498:        struct sockaddr_in *saddr;
1.168     yamt     2499:        fhandle_t *fhp;
1.1       cgd      2500:
1.168     yamt     2501:        fhp = NFSRVFH_FHANDLE(nsfh);
1.12      mycroft  2502:        *vpp = (struct vnode *)0;
1.43      fvdl     2503:
1.168     yamt     2504:        if (nfs_ispublicfh(nsfh)) {
1.43      fvdl     2505:                if (!pubflag || !nfs_pub.np_valid)
                   2506:                        return (ESTALE);
1.166     martin   2507:                fhp = nfs_pub.np_handle;
1.43      fvdl     2508:        }
                   2509:
1.154     yamt     2510:        error = netexport_check(&fhp->fh_fsid, nam, &mp, &exflags, &credanon);
                   2511:        if (error) {
                   2512:                return error;
                   2513:        }
                   2514:
1.124     thorpej  2515:        error = VFS_FHTOVP(mp, &fhp->fh_fid, vpp);
1.24      christos 2516:        if (error)
1.12      mycroft  2517:                return (error);
1.40      fvdl     2518:
1.43      fvdl     2519:        if (!(exflags & (MNT_EXNORESPORT|MNT_EXPUBLIC))) {
1.40      fvdl     2520:                saddr = mtod(nam, struct sockaddr_in *);
1.76      fvdl     2521:                if ((saddr->sin_family == AF_INET) &&
1.40      fvdl     2522:                    ntohs(saddr->sin_port) >= IPPORT_RESERVED) {
                   2523:                        vput(*vpp);
                   2524:                        return (NFSERR_AUTHERR | AUTH_TOOWEAK);
                   2525:                }
1.76      fvdl     2526: #ifdef INET6
                   2527:                if ((saddr->sin_family == AF_INET6) &&
                   2528:                    ntohs(saddr->sin_port) >= IPV6PORT_RESERVED) {
                   2529:                        vput(*vpp);
                   2530:                        return (NFSERR_AUTHERR | AUTH_TOOWEAK);
                   2531:                }
                   2532: #endif
1.40      fvdl     2533:        }
1.12      mycroft  2534:        /*
                   2535:         * Check/setup credentials.
                   2536:         */
                   2537:        if (exflags & MNT_EXKERB) {
1.25      fvdl     2538:                if (!kerbflag) {
1.12      mycroft  2539:                        vput(*vpp);
1.25      fvdl     2540:                        return (NFSERR_AUTHERR | AUTH_TOOWEAK);
1.12      mycroft  2541:                }
1.25      fvdl     2542:        } else if (kerbflag) {
                   2543:                vput(*vpp);
                   2544:                return (NFSERR_AUTHERR | AUTH_TOOWEAK);
1.200     elad     2545:        } else if (kauth_cred_geteuid(cred) == 0 || /* NFS maproot, see below */
                   2546:            (exflags & MNT_EXPORTANON)) {
                   2547:                /*
                   2548:                 * This is used by the NFS maproot option. While we can change
                   2549:                 * the secmodel on our own host, we can't change it on the
                   2550:                 * clients. As means of least surprise, we're doing the
                   2551:                 * traditional thing here.
                   2552:                 * Should look into adding a "mapprivileged" or similar where
                   2553:                 * the users can be explicitly specified...
                   2554:                 * [elad, yamt 2008-03-05]
                   2555:                 */
1.162     elad     2556:                kauth_cred_clone(credanon, cred);
1.12      mycroft  2557:        }
                   2558:        if (exflags & MNT_EXRDONLY)
                   2559:                *rdonlyp = 1;
                   2560:        else
                   2561:                *rdonlyp = 0;
1.1       cgd      2562:        if (!lockflag)
1.56      fvdl     2563:                VOP_UNLOCK(*vpp, 0);
1.1       cgd      2564:        return (0);
1.43      fvdl     2565: }
                   2566:
                   2567: /*
                   2568:  * WebNFS: check if a filehandle is a public filehandle. For v3, this
1.168     yamt     2569:  * means a length of 0, for v2 it means all zeroes.
1.43      fvdl     2570:  */
                   2571: int
1.168     yamt     2572: nfs_ispublicfh(const nfsrvfh_t *nsfh)
1.43      fvdl     2573: {
1.170     yamt     2574:        const char *cp = (const void *)(NFSRVFH_DATA(nsfh));
1.43      fvdl     2575:        int i;
                   2576:
1.168     yamt     2577:        if (NFSRVFH_SIZE(nsfh) == 0) {
1.182     thorpej  2578:                return true;
1.168     yamt     2579:        }
                   2580:        if (NFSRVFH_SIZE(nsfh) != NFSX_V2FH) {
1.182     thorpej  2581:                return false;
1.168     yamt     2582:        }
                   2583:        for (i = 0; i < NFSX_V2FH; i++)
1.43      fvdl     2584:                if (*cp++ != 0)
1.182     thorpej  2585:                        return false;
                   2586:        return true;
1.1       cgd      2587: }
1.153     jmmv     2588: #endif /* NFSSERVER */
1.1       cgd      2589:
                   2590: /*
1.182     thorpej  2591:  * This function compares two net addresses by family and returns true
1.12      mycroft  2592:  * if they are the same host.
1.182     thorpej  2593:  * If there is any doubt, return false.
1.12      mycroft  2594:  * The AF_INET family is handled as a special case so that address mbufs
                   2595:  * don't need to be saved to store "struct in_addr", which is only 4 bytes.
1.1       cgd      2596:  */
1.24      christos 2597: int
1.12      mycroft  2598: netaddr_match(family, haddr, nam)
                   2599:        int family;
                   2600:        union nethostaddr *haddr;
                   2601:        struct mbuf *nam;
1.1       cgd      2602: {
1.75      augustss 2603:        struct sockaddr_in *inetaddr;
1.1       cgd      2604:
1.12      mycroft  2605:        switch (family) {
                   2606:        case AF_INET:
                   2607:                inetaddr = mtod(nam, struct sockaddr_in *);
                   2608:                if (inetaddr->sin_family == AF_INET &&
                   2609:                    inetaddr->sin_addr.s_addr == haddr->had_inetaddr)
                   2610:                        return (1);
                   2611:                break;
1.76      fvdl     2612: #ifdef INET6
                   2613:        case AF_INET6:
                   2614:            {
                   2615:                struct sockaddr_in6 *sin6_1, *sin6_2;
                   2616:
                   2617:                sin6_1 = mtod(nam, struct sockaddr_in6 *);
                   2618:                sin6_2 = mtod(haddr->had_nam, struct sockaddr_in6 *);
                   2619:                if (sin6_1->sin6_family == AF_INET6 &&
                   2620:                    IN6_ARE_ADDR_EQUAL(&sin6_1->sin6_addr, &sin6_2->sin6_addr))
                   2621:                        return 1;
                   2622:            }
                   2623: #endif
1.12      mycroft  2624: #ifdef ISO
                   2625:        case AF_ISO:
                   2626:            {
1.75      augustss 2627:                struct sockaddr_iso *isoaddr1, *isoaddr2;
1.12      mycroft  2628:
                   2629:                isoaddr1 = mtod(nam, struct sockaddr_iso *);
                   2630:                isoaddr2 = mtod(haddr->had_nam, struct sockaddr_iso *);
                   2631:                if (isoaddr1->siso_family == AF_ISO &&
                   2632:                    isoaddr1->siso_nlen > 0 &&
                   2633:                    isoaddr1->siso_nlen == isoaddr2->siso_nlen &&
                   2634:                    SAME_ISOADDR(isoaddr1, isoaddr2))
                   2635:                        return (1);
                   2636:                break;
                   2637:            }
                   2638: #endif /* ISO */
                   2639:        default:
                   2640:                break;
                   2641:        };
                   2642:        return (0);
1.25      fvdl     2643: }
                   2644:
                   2645: /*
                   2646:  * The write verifier has changed (probably due to a server reboot), so all
1.114     yamt     2647:  * PG_NEEDCOMMIT pages will have to be written again. Since they are marked
1.117     yamt     2648:  * as dirty or are being written out just now, all this takes is clearing
                   2649:  * the PG_NEEDCOMMIT flag. Once done the new write verifier can be set for
                   2650:  * the mount point.
1.25      fvdl     2651:  */
                   2652: void
                   2653: nfs_clearcommit(mp)
                   2654:        struct mount *mp;
                   2655: {
1.89      chs      2656:        struct vnode *vp;
1.83      fvdl     2657:        struct nfsnode *np;
1.89      chs      2658:        struct vm_page *pg;
1.116     yamt     2659:        struct nfsmount *nmp = VFSTONFS(mp);
                   2660:
1.180     yamt     2661:        rw_enter(&nmp->nm_writeverflock, RW_WRITER);
1.195     ad       2662:        mutex_enter(&mntvnode_lock);
1.176     reinoud  2663:        TAILQ_FOREACH(vp, &mp->mnt_vnodelist, v_mntvnodes) {
1.89      chs      2664:                KASSERT(vp->v_mount == mp);
1.146     yamt     2665:                if (vp->v_type != VREG)
1.85      enami    2666:                        continue;
1.83      fvdl     2667:                np = VTONFS(vp);
                   2668:                np->n_pushlo = np->n_pushhi = np->n_pushedlo =
                   2669:                    np->n_pushedhi = 0;
                   2670:                np->n_commitflags &=
                   2671:                    ~(NFS_COMMIT_PUSH_VALID | NFS_COMMIT_PUSHED_VALID);
1.195     ad       2672:                mutex_enter(&vp->v_uobj.vmobjlock);
1.202.2.1! wrstuden 2673:                TAILQ_FOREACH(pg, &vp->v_uobj.memq, listq.queue) {
1.89      chs      2674:                        pg->flags &= ~PG_NEEDCOMMIT;
1.25      fvdl     2675:                }
1.195     ad       2676:                mutex_exit(&vp->v_uobj.vmobjlock);
1.25      fvdl     2677:        }
1.195     ad       2678:        mutex_exit(&mntvnode_lock);
1.186     yamt     2679:        mutex_enter(&nmp->nm_lock);
1.116     yamt     2680:        nmp->nm_iflag &= ~NFSMNT_STALEWRITEVERF;
1.186     yamt     2681:        mutex_exit(&nmp->nm_lock);
1.180     yamt     2682:        rw_exit(&nmp->nm_writeverflock);
1.83      fvdl     2683: }
                   2684:
                   2685: void
                   2686: nfs_merge_commit_ranges(vp)
                   2687:        struct vnode *vp;
                   2688: {
                   2689:        struct nfsnode *np = VTONFS(vp);
1.112     yamt     2690:
                   2691:        KASSERT(np->n_commitflags & NFS_COMMIT_PUSH_VALID);
1.83      fvdl     2692:
                   2693:        if (!(np->n_commitflags & NFS_COMMIT_PUSHED_VALID)) {
                   2694:                np->n_pushedlo = np->n_pushlo;
                   2695:                np->n_pushedhi = np->n_pushhi;
                   2696:                np->n_commitflags |= NFS_COMMIT_PUSHED_VALID;
                   2697:        } else {
                   2698:                if (np->n_pushlo < np->n_pushedlo)
                   2699:                        np->n_pushedlo = np->n_pushlo;
                   2700:                if (np->n_pushhi > np->n_pushedhi)
                   2701:                        np->n_pushedhi = np->n_pushhi;
                   2702:        }
                   2703:
                   2704:        np->n_pushlo = np->n_pushhi = 0;
                   2705:        np->n_commitflags &= ~NFS_COMMIT_PUSH_VALID;
                   2706:
1.111     yamt     2707: #ifdef NFS_DEBUG_COMMIT
1.83      fvdl     2708:        printf("merge: committed: %u - %u\n", (unsigned)np->n_pushedlo,
                   2709:            (unsigned)np->n_pushedhi);
                   2710: #endif
                   2711: }
                   2712:
                   2713: int
1.89      chs      2714: nfs_in_committed_range(vp, off, len)
1.83      fvdl     2715:        struct vnode *vp;
1.89      chs      2716:        off_t off, len;
1.83      fvdl     2717: {
                   2718:        struct nfsnode *np = VTONFS(vp);
                   2719:        off_t lo, hi;
                   2720:
                   2721:        if (!(np->n_commitflags & NFS_COMMIT_PUSHED_VALID))
                   2722:                return 0;
1.89      chs      2723:        lo = off;
                   2724:        hi = lo + len;
1.83      fvdl     2725:
                   2726:        return (lo >= np->n_pushedlo && hi <= np->n_pushedhi);
                   2727: }
                   2728:
                   2729: int
1.89      chs      2730: nfs_in_tobecommitted_range(vp, off, len)
1.83      fvdl     2731:        struct vnode *vp;
1.89      chs      2732:        off_t off, len;
1.83      fvdl     2733: {
                   2734:        struct nfsnode *np = VTONFS(vp);
                   2735:        off_t lo, hi;
                   2736:
                   2737:        if (!(np->n_commitflags & NFS_COMMIT_PUSH_VALID))
                   2738:                return 0;
1.89      chs      2739:        lo = off;
                   2740:        hi = lo + len;
1.83      fvdl     2741:
                   2742:        return (lo >= np->n_pushlo && hi <= np->n_pushhi);
                   2743: }
                   2744:
                   2745: void
1.89      chs      2746: nfs_add_committed_range(vp, off, len)
1.83      fvdl     2747:        struct vnode *vp;
1.89      chs      2748:        off_t off, len;
1.83      fvdl     2749: {
                   2750:        struct nfsnode *np = VTONFS(vp);
                   2751:        off_t lo, hi;
                   2752:
1.89      chs      2753:        lo = off;
                   2754:        hi = lo + len;
1.83      fvdl     2755:
                   2756:        if (!(np->n_commitflags & NFS_COMMIT_PUSHED_VALID)) {
                   2757:                np->n_pushedlo = lo;
                   2758:                np->n_pushedhi = hi;
                   2759:                np->n_commitflags |= NFS_COMMIT_PUSHED_VALID;
                   2760:        } else {
                   2761:                if (hi > np->n_pushedhi)
                   2762:                        np->n_pushedhi = hi;
                   2763:                if (lo < np->n_pushedlo)
                   2764:                        np->n_pushedlo = lo;
                   2765:        }
1.111     yamt     2766: #ifdef NFS_DEBUG_COMMIT
1.83      fvdl     2767:        printf("add: committed: %u - %u\n", (unsigned)np->n_pushedlo,
                   2768:            (unsigned)np->n_pushedhi);
                   2769: #endif
                   2770: }
                   2771:
                   2772: void
1.89      chs      2773: nfs_del_committed_range(vp, off, len)
1.83      fvdl     2774:        struct vnode *vp;
1.89      chs      2775:        off_t off, len;
1.83      fvdl     2776: {
                   2777:        struct nfsnode *np = VTONFS(vp);
                   2778:        off_t lo, hi;
                   2779:
                   2780:        if (!(np->n_commitflags & NFS_COMMIT_PUSHED_VALID))
                   2781:                return;
                   2782:
1.89      chs      2783:        lo = off;
                   2784:        hi = lo + len;
1.83      fvdl     2785:
                   2786:        if (lo > np->n_pushedhi || hi < np->n_pushedlo)
                   2787:                return;
                   2788:        if (lo <= np->n_pushedlo)
                   2789:                np->n_pushedlo = hi;
                   2790:        else if (hi >= np->n_pushedhi)
                   2791:                np->n_pushedhi = lo;
                   2792:        else {
                   2793:                /*
                   2794:                 * XXX There's only one range. If the deleted range
                   2795:                 * is in the middle, pick the largest of the
                   2796:                 * contiguous ranges that it leaves.
                   2797:                 */
                   2798:                if ((np->n_pushedlo - lo) > (hi - np->n_pushedhi))
                   2799:                        np->n_pushedhi = lo;
                   2800:                else
                   2801:                        np->n_pushedlo = hi;
                   2802:        }
1.111     yamt     2803: #ifdef NFS_DEBUG_COMMIT
1.83      fvdl     2804:        printf("del: committed: %u - %u\n", (unsigned)np->n_pushedlo,
                   2805:            (unsigned)np->n_pushedhi);
                   2806: #endif
                   2807: }
                   2808:
                   2809: void
1.89      chs      2810: nfs_add_tobecommitted_range(vp, off, len)
1.83      fvdl     2811:        struct vnode *vp;
1.89      chs      2812:        off_t off, len;
1.83      fvdl     2813: {
                   2814:        struct nfsnode *np = VTONFS(vp);
                   2815:        off_t lo, hi;
                   2816:
1.89      chs      2817:        lo = off;
                   2818:        hi = lo + len;
1.83      fvdl     2819:
                   2820:        if (!(np->n_commitflags & NFS_COMMIT_PUSH_VALID)) {
                   2821:                np->n_pushlo = lo;
                   2822:                np->n_pushhi = hi;
                   2823:                np->n_commitflags |= NFS_COMMIT_PUSH_VALID;
                   2824:        } else {
                   2825:                if (lo < np->n_pushlo)
                   2826:                        np->n_pushlo = lo;
                   2827:                if (hi > np->n_pushhi)
                   2828:                        np->n_pushhi = hi;
                   2829:        }
1.111     yamt     2830: #ifdef NFS_DEBUG_COMMIT
1.83      fvdl     2831:        printf("add: tobecommitted: %u - %u\n", (unsigned)np->n_pushlo,
                   2832:            (unsigned)np->n_pushhi);
                   2833: #endif
                   2834: }
                   2835:
                   2836: void
1.89      chs      2837: nfs_del_tobecommitted_range(vp, off, len)
1.83      fvdl     2838:        struct vnode *vp;
1.89      chs      2839:        off_t off, len;
1.83      fvdl     2840: {
                   2841:        struct nfsnode *np = VTONFS(vp);
                   2842:        off_t lo, hi;
                   2843:
                   2844:        if (!(np->n_commitflags & NFS_COMMIT_PUSH_VALID))
                   2845:                return;
                   2846:
1.89      chs      2847:        lo = off;
                   2848:        hi = lo + len;
1.83      fvdl     2849:
                   2850:        if (lo > np->n_pushhi || hi < np->n_pushlo)
                   2851:                return;
                   2852:
                   2853:        if (lo <= np->n_pushlo)
                   2854:                np->n_pushlo = hi;
                   2855:        else if (hi >= np->n_pushhi)
                   2856:                np->n_pushhi = lo;
                   2857:        else {
                   2858:                /*
                   2859:                 * XXX There's only one range. If the deleted range
                   2860:                 * is in the middle, pick the largest of the
                   2861:                 * contiguous ranges that it leaves.
                   2862:                 */
                   2863:                if ((np->n_pushlo - lo) > (hi - np->n_pushhi))
                   2864:                        np->n_pushhi = lo;
                   2865:                else
                   2866:                        np->n_pushlo = hi;
                   2867:        }
1.111     yamt     2868: #ifdef NFS_DEBUG_COMMIT
1.83      fvdl     2869:        printf("del: tobecommitted: %u - %u\n", (unsigned)np->n_pushlo,
                   2870:            (unsigned)np->n_pushhi);
                   2871: #endif
1.25      fvdl     2872: }
                   2873:
                   2874: /*
                   2875:  * Map errnos to NFS error numbers. For Version 3 also filter out error
                   2876:  * numbers not specified for the associated procedure.
                   2877:  */
                   2878: int
                   2879: nfsrv_errmap(nd, err)
                   2880:        struct nfsrv_descript *nd;
1.75      augustss 2881:        int err;
1.25      fvdl     2882: {
1.90      jdolecek 2883:        const short *defaulterrp, *errp;
1.25      fvdl     2884:
                   2885:        if (nd->nd_flag & ND_NFSV3) {
                   2886:            if (nd->nd_procnum <= NFSPROC_COMMIT) {
                   2887:                errp = defaulterrp = nfsrv_v3errmap[nd->nd_procnum];
                   2888:                while (*++errp) {
                   2889:                        if (*errp == err)
                   2890:                                return (err);
                   2891:                        else if (*errp > err)
                   2892:                                break;
                   2893:                }
                   2894:                return ((int)*defaulterrp);
                   2895:            } else
                   2896:                return (err & 0xffff);
                   2897:        }
                   2898:        if (err <= ELAST)
                   2899:                return ((int)nfsrv_v2errmap[err - 1]);
                   2900:        return (NFSERR_IO);
                   2901: }
                   2902:
1.126     yamt     2903: u_int32_t
                   2904: nfs_getxid()
                   2905: {
                   2906:        static u_int32_t base;
                   2907:        static u_int32_t nfs_xid = 0;
                   2908:        static struct simplelock nfs_xidlock = SIMPLELOCK_INITIALIZER;
                   2909:        u_int32_t newxid;
                   2910:
                   2911:        simple_lock(&nfs_xidlock);
                   2912:        /*
                   2913:         * derive initial xid from system time
                   2914:         * XXX time is invalid if root not yet mounted
                   2915:         */
                   2916:        if (__predict_false(!base && (rootvp))) {
                   2917:                struct timeval tv;
                   2918:
                   2919:                microtime(&tv);
                   2920:                base = tv.tv_sec << 12;
                   2921:                nfs_xid = base;
                   2922:        }
                   2923:
                   2924:        /*
                   2925:         * Skip zero xid if it should ever happen.
                   2926:         */
                   2927:        if (__predict_false(++nfs_xid == 0))
                   2928:                nfs_xid++;
                   2929:        newxid = nfs_xid;
                   2930:        simple_unlock(&nfs_xidlock);
                   2931:
                   2932:        return txdr_unsigned(newxid);
                   2933: }
                   2934:
                   2935: /*
                   2936:  * assign a new xid for existing request.
                   2937:  * used for NFSERR_JUKEBOX handling.
                   2938:  */
                   2939: void
                   2940: nfs_renewxid(struct nfsreq *req)
                   2941: {
                   2942:        u_int32_t xid;
                   2943:        int off;
                   2944:
                   2945:        xid = nfs_getxid();
                   2946:        if (req->r_nmp->nm_sotype == SOCK_STREAM)
                   2947:                off = sizeof(u_int32_t); /* RPC record mark */
                   2948:        else
                   2949:                off = 0;
                   2950:
                   2951:        m_copyback(req->r_mreq, off, sizeof(xid), (void *)&xid);
                   2952:        req->r_xid = xid;
1.1       cgd      2953: }
1.168     yamt     2954:
                   2955: #if defined(NFSSERVER)
                   2956: int
1.181     thorpej  2957: nfsrv_composefh(struct vnode *vp, nfsrvfh_t *nsfh, bool v3)
1.168     yamt     2958: {
                   2959:        int error;
                   2960:        size_t fhsize;
                   2961:
                   2962:        fhsize = NFSD_MAXFHSIZE;
1.169     yamt     2963:        error = vfs_composefh(vp, (void *)NFSRVFH_DATA(nsfh), &fhsize);
1.168     yamt     2964:        if (NFSX_FHTOOBIG_P(fhsize, v3)) {
                   2965:                error = EOPNOTSUPP;
                   2966:        }
                   2967:        if (error != 0) {
                   2968:                return error;
                   2969:        }
                   2970:        if (!v3 && fhsize < NFSX_V2FH) {
                   2971:                memset((char *)NFSRVFH_DATA(nsfh) + fhsize, 0,
                   2972:                    NFSX_V2FH - fhsize);
                   2973:                fhsize = NFSX_V2FH;
                   2974:        }
                   2975:        if ((fhsize % NFSX_UNSIGNED) != 0) {
                   2976:                return EOPNOTSUPP;
                   2977:        }
                   2978:        nsfh->nsfh_size = fhsize;
                   2979:        return 0;
                   2980: }
                   2981:
                   2982: int
                   2983: nfsrv_comparefh(const nfsrvfh_t *fh1, const nfsrvfh_t *fh2)
                   2984: {
                   2985:
                   2986:        if (NFSRVFH_SIZE(fh1) != NFSRVFH_SIZE(fh2)) {
                   2987:                return NFSRVFH_SIZE(fh2) - NFSRVFH_SIZE(fh1);
                   2988:        }
                   2989:        return memcmp(NFSRVFH_DATA(fh1), NFSRVFH_DATA(fh2), NFSRVFH_SIZE(fh1));
                   2990: }
                   2991:
                   2992: void
                   2993: nfsrv_copyfh(nfsrvfh_t *fh1, const nfsrvfh_t *fh2)
                   2994: {
                   2995:        size_t size;
                   2996:
                   2997:        fh1->nsfh_size = size = NFSRVFH_SIZE(fh2);
                   2998:        memcpy(NFSRVFH_DATA(fh1), NFSRVFH_DATA(fh2), size);
                   2999: }
                   3000: #endif /* defined(NFSSERVER) */
1.192     yamt     3001:
                   3002: #if defined(NFS)
                   3003: /*
                   3004:  * Set the attribute timeout based on how recently the file has been modified.
                   3005:  */
                   3006:
                   3007: time_t
                   3008: nfs_attrtimeo(struct nfsmount *nmp, struct nfsnode *np)
                   3009: {
                   3010:        time_t timeo;
                   3011:
                   3012:        if ((nmp->nm_flag & NFSMNT_NOAC) != 0)
                   3013:                return 0;
                   3014:
                   3015:        if (((np)->n_flag & NMODIFIED) != 0)
                   3016:                return NFS_MINATTRTIMO;
                   3017:
                   3018:        timeo = (time_second - np->n_mtime.tv_sec) / 10;
                   3019:        timeo = max(timeo, NFS_MINATTRTIMO);
                   3020:        timeo = min(timeo, NFS_MAXATTRTIMO);
                   3021:        return timeo;
                   3022: }
                   3023: #endif /* defined(NFS) */

CVSweb <webmaster@jp.NetBSD.org>