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

1.184.2.1! ad          1: /*     $NetBSD: nfs_subs.c,v 1.184 2007/03/09 05:55:33 yamt Exp $      */
1.14      cgd         2:
1.1       cgd         3: /*
1.12      mycroft     4:  * Copyright (c) 1989, 1993
                      5:  *     The Regents of the University of California.  All rights reserved.
1.1       cgd         6:  *
                      7:  * This code is derived from software contributed to Berkeley by
                      8:  * Rick Macklem at The University of Guelph.
                      9:  *
                     10:  * Redistribution and use in source and binary forms, with or without
                     11:  * modification, are permitted provided that the following conditions
                     12:  * are met:
                     13:  * 1. Redistributions of source code must retain the above copyright
                     14:  *    notice, this list of conditions and the following disclaimer.
                     15:  * 2. Redistributions in binary form must reproduce the above copyright
                     16:  *    notice, this list of conditions and the following disclaimer in the
                     17:  *    documentation and/or other materials provided with the distribution.
1.127     agc        18:  * 3. Neither the name of the University nor the names of its contributors
1.1       cgd        19:  *    may be used to endorse or promote products derived from this software
                     20:  *    without specific prior written permission.
                     21:  *
                     22:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     23:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     24:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     25:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     26:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     27:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     28:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     29:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     30:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     31:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     32:  * SUCH DAMAGE.
                     33:  *
1.25      fvdl       34:  *     @(#)nfs_subs.c  8.8 (Berkeley) 5/22/95
1.1       cgd        35:  */
                     36:
1.83      fvdl       37: /*
                     38:  * Copyright 2000 Wasabi Systems, Inc.
                     39:  * All rights reserved.
                     40:  *
                     41:  * Written by Frank van der Linden for Wasabi Systems, Inc.
                     42:  *
                     43:  * Redistribution and use in source and binary forms, with or without
                     44:  * modification, are permitted provided that the following conditions
                     45:  * are met:
                     46:  * 1. Redistributions of source code must retain the above copyright
                     47:  *    notice, this list of conditions and the following disclaimer.
                     48:  * 2. Redistributions in binary form must reproduce the above copyright
                     49:  *    notice, this list of conditions and the following disclaimer in the
                     50:  *    documentation and/or other materials provided with the distribution.
                     51:  * 3. All advertising materials mentioning features or use of this software
                     52:  *    must display the following acknowledgement:
                     53:  *      This product includes software developed for the NetBSD Project by
                     54:  *      Wasabi Systems, Inc.
                     55:  * 4. The name of Wasabi Systems, Inc. may not be used to endorse
                     56:  *    or promote products derived from this software without specific prior
                     57:  *    written permission.
                     58:  *
                     59:  * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
                     60:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
                     61:  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
                     62:  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL WASABI SYSTEMS, INC
                     63:  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
                     64:  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
                     65:  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
                     66:  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
                     67:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
                     68:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
                     69:  * POSSIBILITY OF SUCH DAMAGE.
                     70:  */
1.99      lukem      71:
                     72: #include <sys/cdefs.h>
1.184.2.1! ad         73: __KERNEL_RCSID(0, "$NetBSD: nfs_subs.c,v 1.184 2007/03/09 05:55:33 yamt Exp $");
1.83      fvdl       74:
1.55      thorpej    75: #include "fs_nfs.h"
1.82      bjh21      76: #include "opt_nfs.h"
1.61      thorpej    77: #include "opt_nfsserver.h"
1.62      jonathan   78: #include "opt_iso.h"
1.76      fvdl       79: #include "opt_inet.h"
1.25      fvdl       80:
1.1       cgd        81: /*
                     82:  * These functions support the macros and help fiddle mbuf chains for
                     83:  * the nfs op functions. They do things like create the rpc header and
                     84:  * copy data between mbuf chains and uio lists.
                     85:  */
1.9       mycroft    86: #include <sys/param.h>
                     87: #include <sys/proc.h>
                     88: #include <sys/systm.h>
                     89: #include <sys/kernel.h>
                     90: #include <sys/mount.h>
                     91: #include <sys/vnode.h>
                     92: #include <sys/namei.h>
                     93: #include <sys/mbuf.h>
1.12      mycroft    94: #include <sys/socket.h>
                     95: #include <sys/stat.h>
1.25      fvdl       96: #include <sys/malloc.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.12      mycroft   566: extern struct nfsrtt nfsrtt;
1.25      fvdl      567: extern struct nfsnodehashhead *nfsnodehashtbl;
                    568: extern u_long nfsnodehash;
1.1       cgd       569:
1.46      fvdl      570: u_long nfsdirhashmask;
1.18      mycroft   571:
1.43      fvdl      572: int nfs_webnamei __P((struct nameidata *, struct vnode *, struct proc *));
                    573:
1.1       cgd       574: /*
                    575:  * Create the header for an rpc request packet
                    576:  * The hsiz is the size of the rest of the nfs request header.
                    577:  * (just used to decide if a cluster is a good idea)
                    578:  */
1.12      mycroft   579: struct mbuf *
1.183     christos  580: nfsm_reqh(struct nfsnode *np, u_long procid, int hsiz, char **bposp)
1.12      mycroft   581: {
1.75      augustss  582:        struct mbuf *mb;
1.183     christos  583:        char *bpos;
1.12      mycroft   584:
1.109     matt      585:        mb = m_get(M_WAIT, MT_DATA);
                    586:        MCLAIM(mb, &nfs_mowner);
1.12      mycroft   587:        if (hsiz >= MINCLSIZE)
1.109     matt      588:                m_clget(mb, M_WAIT);
1.12      mycroft   589:        mb->m_len = 0;
1.183     christos  590:        bpos = mtod(mb, void *);
1.148     perry     591:
1.12      mycroft   592:        /* Finally, return values */
                    593:        *bposp = bpos;
                    594:        return (mb);
                    595: }
                    596:
                    597: /*
                    598:  * Build the RPC header and fill in the authorization info.
                    599:  * The authorization string argument is only used when the credentials
                    600:  * come from outside of the kernel.
                    601:  * Returns the head of the mbuf list.
                    602:  */
                    603: struct mbuf *
1.25      fvdl      604: nfsm_rpchead(cr, nmflag, procid, auth_type, auth_len, auth_str, verf_len,
                    605:        verf_str, mrest, mrest_len, mbp, xidp)
1.162     elad      606:        kauth_cred_t cr;
1.25      fvdl      607:        int nmflag;
1.12      mycroft   608:        int procid;
                    609:        int auth_type;
                    610:        int auth_len;
                    611:        char *auth_str;
1.25      fvdl      612:        int verf_len;
                    613:        char *verf_str;
1.12      mycroft   614:        struct mbuf *mrest;
                    615:        int mrest_len;
                    616:        struct mbuf **mbp;
1.22      cgd       617:        u_int32_t *xidp;
1.1       cgd       618: {
1.75      augustss  619:        struct mbuf *mb;
                    620:        u_int32_t *tl;
1.183     christos  621:        char *bpos;
1.75      augustss  622:        int i;
1.109     matt      623:        struct mbuf *mreq;
1.12      mycroft   624:        int siz, grpsiz, authsiz;
1.1       cgd       625:
1.12      mycroft   626:        authsiz = nfsm_rndup(auth_len);
1.109     matt      627:        mb = m_gethdr(M_WAIT, MT_DATA);
                    628:        MCLAIM(mb, &nfs_mowner);
1.25      fvdl      629:        if ((authsiz + 10 * NFSX_UNSIGNED) >= MINCLSIZE) {
1.109     matt      630:                m_clget(mb, M_WAIT);
1.25      fvdl      631:        } else if ((authsiz + 10 * NFSX_UNSIGNED) < MHLEN) {
                    632:                MH_ALIGN(mb, authsiz + 10 * NFSX_UNSIGNED);
1.12      mycroft   633:        } else {
1.25      fvdl      634:                MH_ALIGN(mb, 8 * NFSX_UNSIGNED);
1.1       cgd       635:        }
1.12      mycroft   636:        mb->m_len = 0;
                    637:        mreq = mb;
1.183     christos  638:        bpos = mtod(mb, void *);
1.12      mycroft   639:
                    640:        /*
                    641:         * First the RPC header.
                    642:         */
1.25      fvdl      643:        nfsm_build(tl, u_int32_t *, 8 * NFSX_UNSIGNED);
1.30      fvdl      644:
1.126     yamt      645:        *tl++ = *xidp = nfs_getxid();
1.1       cgd       646:        *tl++ = rpc_call;
                    647:        *tl++ = rpc_vers;
1.179     yamt      648:        *tl++ = txdr_unsigned(NFS_PROG);
                    649:        if (nmflag & NFSMNT_NFSV3)
                    650:                *tl++ = txdr_unsigned(NFS_VER3);
                    651:        else
                    652:                *tl++ = txdr_unsigned(NFS_VER2);
1.25      fvdl      653:        if (nmflag & NFSMNT_NFSV3)
                    654:                *tl++ = txdr_unsigned(procid);
                    655:        else
                    656:                *tl++ = txdr_unsigned(nfsv2_procid[procid]);
1.12      mycroft   657:
                    658:        /*
                    659:         * And then the authorization cred.
                    660:         */
                    661:        *tl++ = txdr_unsigned(auth_type);
                    662:        *tl = txdr_unsigned(authsiz);
                    663:        switch (auth_type) {
                    664:        case RPCAUTH_UNIX:
1.22      cgd       665:                nfsm_build(tl, u_int32_t *, auth_len);
1.12      mycroft   666:                *tl++ = 0;              /* stamp ?? */
                    667:                *tl++ = 0;              /* NULL hostname */
1.162     elad      668:                *tl++ = txdr_unsigned(kauth_cred_geteuid(cr));
                    669:                *tl++ = txdr_unsigned(kauth_cred_getegid(cr));
1.12      mycroft   670:                grpsiz = (auth_len >> 2) - 5;
                    671:                *tl++ = txdr_unsigned(grpsiz);
1.20      mycroft   672:                for (i = 0; i < grpsiz; i++)
1.162     elad      673:                        *tl++ = txdr_unsigned(kauth_cred_group(cr, i)); /* XXX elad review */
1.12      mycroft   674:                break;
1.25      fvdl      675:        case RPCAUTH_KERB4:
1.12      mycroft   676:                siz = auth_len;
                    677:                while (siz > 0) {
                    678:                        if (M_TRAILINGSPACE(mb) == 0) {
1.109     matt      679:                                struct mbuf *mb2;
                    680:                                mb2 = m_get(M_WAIT, MT_DATA);
                    681:                                MCLAIM(mb2, &nfs_mowner);
1.12      mycroft   682:                                if (siz >= MINCLSIZE)
1.109     matt      683:                                        m_clget(mb2, M_WAIT);
1.12      mycroft   684:                                mb->m_next = mb2;
                    685:                                mb = mb2;
                    686:                                mb->m_len = 0;
1.183     christos  687:                                bpos = mtod(mb, void *);
1.12      mycroft   688:                        }
                    689:                        i = min(siz, M_TRAILINGSPACE(mb));
1.63      perry     690:                        memcpy(bpos, auth_str, i);
1.12      mycroft   691:                        mb->m_len += i;
                    692:                        auth_str += i;
                    693:                        bpos += i;
                    694:                        siz -= i;
                    695:                }
                    696:                if ((siz = (nfsm_rndup(auth_len) - auth_len)) > 0) {
                    697:                        for (i = 0; i < siz; i++)
                    698:                                *bpos++ = '\0';
                    699:                        mb->m_len += siz;
                    700:                }
                    701:                break;
                    702:        };
1.25      fvdl      703:
                    704:        /*
                    705:         * And the verifier...
                    706:         */
                    707:        nfsm_build(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
                    708:        if (verf_str) {
                    709:                *tl++ = txdr_unsigned(RPCAUTH_KERB4);
                    710:                *tl = txdr_unsigned(verf_len);
                    711:                siz = verf_len;
                    712:                while (siz > 0) {
                    713:                        if (M_TRAILINGSPACE(mb) == 0) {
1.109     matt      714:                                struct mbuf *mb2;
                    715:                                mb2 = m_get(M_WAIT, MT_DATA);
                    716:                                MCLAIM(mb2, &nfs_mowner);
1.25      fvdl      717:                                if (siz >= MINCLSIZE)
1.109     matt      718:                                        m_clget(mb2, M_WAIT);
1.25      fvdl      719:                                mb->m_next = mb2;
                    720:                                mb = mb2;
                    721:                                mb->m_len = 0;
1.183     christos  722:                                bpos = mtod(mb, void *);
1.25      fvdl      723:                        }
                    724:                        i = min(siz, M_TRAILINGSPACE(mb));
1.63      perry     725:                        memcpy(bpos, verf_str, i);
1.25      fvdl      726:                        mb->m_len += i;
                    727:                        verf_str += i;
                    728:                        bpos += i;
                    729:                        siz -= i;
                    730:                }
                    731:                if ((siz = (nfsm_rndup(verf_len) - verf_len)) > 0) {
                    732:                        for (i = 0; i < siz; i++)
                    733:                                *bpos++ = '\0';
                    734:                        mb->m_len += siz;
                    735:                }
                    736:        } else {
                    737:                *tl++ = txdr_unsigned(RPCAUTH_NULL);
                    738:                *tl = 0;
                    739:        }
1.12      mycroft   740:        mb->m_next = mrest;
1.25      fvdl      741:        mreq->m_pkthdr.len = authsiz + 10 * NFSX_UNSIGNED + mrest_len;
1.12      mycroft   742:        mreq->m_pkthdr.rcvif = (struct ifnet *)0;
                    743:        *mbp = mb;
1.1       cgd       744:        return (mreq);
                    745: }
                    746:
                    747: /*
                    748:  * copies mbuf chain to the uio scatter/gather list
                    749:  */
1.24      christos  750: int
1.1       cgd       751: nfsm_mbuftouio(mrep, uiop, siz, dpos)
                    752:        struct mbuf **mrep;
1.75      augustss  753:        struct uio *uiop;
1.1       cgd       754:        int siz;
1.183     christos  755:        char **dpos;
1.1       cgd       756: {
1.75      augustss  757:        char *mbufcp, *uiocp;
                    758:        int xfer, left, len;
                    759:        struct mbuf *mp;
1.1       cgd       760:        long uiosiz, rem;
                    761:        int error = 0;
                    762:
                    763:        mp = *mrep;
                    764:        mbufcp = *dpos;
1.183     christos  765:        len = mtod(mp, char *) + mp->m_len - mbufcp;
1.1       cgd       766:        rem = nfsm_rndup(siz)-siz;
                    767:        while (siz > 0) {
                    768:                if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL)
                    769:                        return (EFBIG);
                    770:                left = uiop->uio_iov->iov_len;
                    771:                uiocp = uiop->uio_iov->iov_base;
                    772:                if (left > siz)
                    773:                        left = siz;
                    774:                uiosiz = left;
                    775:                while (left > 0) {
                    776:                        while (len == 0) {
                    777:                                mp = mp->m_next;
                    778:                                if (mp == NULL)
                    779:                                        return (EBADRPC);
1.183     christos  780:                                mbufcp = mtod(mp, void *);
1.1       cgd       781:                                len = mp->m_len;
                    782:                        }
                    783:                        xfer = (left > len) ? len : left;
1.158     yamt      784:                        error = copyout_vmspace(uiop->uio_vmspace, mbufcp,
                    785:                            uiocp, xfer);
                    786:                        if (error) {
                    787:                                return error;
                    788:                        }
1.1       cgd       789:                        left -= xfer;
                    790:                        len -= xfer;
                    791:                        mbufcp += xfer;
                    792:                        uiocp += xfer;
                    793:                        uiop->uio_offset += xfer;
                    794:                        uiop->uio_resid -= xfer;
                    795:                }
                    796:                if (uiop->uio_iov->iov_len <= siz) {
                    797:                        uiop->uio_iovcnt--;
                    798:                        uiop->uio_iov++;
                    799:                } else {
1.95      lukem     800:                        uiop->uio_iov->iov_base =
1.183     christos  801:                            (char *)uiop->uio_iov->iov_base + uiosiz;
1.1       cgd       802:                        uiop->uio_iov->iov_len -= uiosiz;
                    803:                }
                    804:                siz -= uiosiz;
                    805:        }
                    806:        *dpos = mbufcp;
                    807:        *mrep = mp;
                    808:        if (rem > 0) {
                    809:                if (len < rem)
                    810:                        error = nfs_adv(mrep, dpos, rem, len);
                    811:                else
                    812:                        *dpos += rem;
                    813:        }
                    814:        return (error);
                    815: }
                    816:
                    817: /*
1.29      fvdl      818:  * copies a uio scatter/gather list to an mbuf chain.
                    819:  * NOTE: can ony handle iovcnt == 1
1.1       cgd       820:  */
1.24      christos  821: int
1.1       cgd       822: nfsm_uiotombuf(uiop, mq, siz, bpos)
1.75      augustss  823:        struct uio *uiop;
1.1       cgd       824:        struct mbuf **mq;
                    825:        int siz;
1.183     christos  826:        char **bpos;
1.1       cgd       827: {
1.75      augustss  828:        char *uiocp;
                    829:        struct mbuf *mp, *mp2;
                    830:        int xfer, left, mlen;
1.1       cgd       831:        int uiosiz, clflg, rem;
                    832:        char *cp;
1.158     yamt      833:        int error;
1.1       cgd       834:
1.29      fvdl      835: #ifdef DIAGNOSTIC
                    836:        if (uiop->uio_iovcnt != 1)
                    837:                panic("nfsm_uiotombuf: iovcnt != 1");
                    838: #endif
                    839:
1.1       cgd       840:        if (siz > MLEN)         /* or should it >= MCLBYTES ?? */
                    841:                clflg = 1;
                    842:        else
                    843:                clflg = 0;
                    844:        rem = nfsm_rndup(siz)-siz;
1.12      mycroft   845:        mp = mp2 = *mq;
1.1       cgd       846:        while (siz > 0) {
                    847:                left = uiop->uio_iov->iov_len;
                    848:                uiocp = uiop->uio_iov->iov_base;
                    849:                if (left > siz)
                    850:                        left = siz;
                    851:                uiosiz = left;
                    852:                while (left > 0) {
1.12      mycroft   853:                        mlen = M_TRAILINGSPACE(mp);
                    854:                        if (mlen == 0) {
1.109     matt      855:                                mp = m_get(M_WAIT, MT_DATA);
                    856:                                MCLAIM(mp, &nfs_mowner);
1.12      mycroft   857:                                if (clflg)
1.109     matt      858:                                        m_clget(mp, M_WAIT);
1.12      mycroft   859:                                mp->m_len = 0;
                    860:                                mp2->m_next = mp;
                    861:                                mp2 = mp;
                    862:                                mlen = M_TRAILINGSPACE(mp);
                    863:                        }
                    864:                        xfer = (left > mlen) ? mlen : left;
1.183     christos  865:                        cp = mtod(mp, char *) + mp->m_len;
1.158     yamt      866:                        error = copyin_vmspace(uiop->uio_vmspace, uiocp, cp,
                    867:                            xfer);
                    868:                        if (error) {
                    869:                                /* XXX */
                    870:                        }
1.12      mycroft   871:                        mp->m_len += xfer;
1.1       cgd       872:                        left -= xfer;
                    873:                        uiocp += xfer;
                    874:                        uiop->uio_offset += xfer;
                    875:                        uiop->uio_resid -= xfer;
                    876:                }
1.183     christos  877:                uiop->uio_iov->iov_base = (char *)uiop->uio_iov->iov_base +
1.95      lukem     878:                    uiosiz;
1.29      fvdl      879:                uiop->uio_iov->iov_len -= uiosiz;
1.1       cgd       880:                siz -= uiosiz;
                    881:        }
                    882:        if (rem > 0) {
1.12      mycroft   883:                if (rem > M_TRAILINGSPACE(mp)) {
1.109     matt      884:                        mp = m_get(M_WAIT, MT_DATA);
                    885:                        MCLAIM(mp, &nfs_mowner);
1.1       cgd       886:                        mp->m_len = 0;
                    887:                        mp2->m_next = mp;
                    888:                }
1.183     christos  889:                cp = mtod(mp, char *) + mp->m_len;
1.1       cgd       890:                for (left = 0; left < rem; left++)
                    891:                        *cp++ = '\0';
                    892:                mp->m_len += rem;
                    893:                *bpos = cp;
                    894:        } else
1.183     christos  895:                *bpos = mtod(mp, char *) + mp->m_len;
1.1       cgd       896:        *mq = mp;
                    897:        return (0);
                    898: }
                    899:
                    900: /*
1.39      fvdl      901:  * Get at least "siz" bytes of correctly aligned data.
                    902:  * When called the mbuf pointers are not necessarily correct,
                    903:  * dsosp points to what ought to be in m_data and left contains
1.148     perry     904:  * what ought to be in m_len.
1.12      mycroft   905:  * This is used by the macros nfsm_dissect and nfsm_dissecton for tough
1.1       cgd       906:  * cases. (The macros use the vars. dpos and dpos2)
                    907:  */
1.24      christos  908: int
1.12      mycroft   909: nfsm_disct(mdp, dposp, siz, left, cp2)
1.1       cgd       910:        struct mbuf **mdp;
1.183     christos  911:        char **dposp;
1.1       cgd       912:        int siz;
                    913:        int left;
1.183     christos  914:        char **cp2;
1.1       cgd       915: {
1.75      augustss  916:        struct mbuf *m1, *m2;
1.39      fvdl      917:        struct mbuf *havebuf = NULL;
1.183     christos  918:        char *src = *dposp;
                    919:        char *dst;
1.39      fvdl      920:        int len;
                    921:
                    922: #ifdef DEBUG
                    923:        if (left < 0)
1.148     perry     924:                panic("nfsm_disct: left < 0");
1.39      fvdl      925: #endif
                    926:        m1 = *mdp;
                    927:        /*
                    928:         * Skip through the mbuf chain looking for an mbuf with
                    929:         * some data. If the first mbuf found has enough data
                    930:         * and it is correctly aligned return it.
                    931:         */
1.1       cgd       932:        while (left == 0) {
1.39      fvdl      933:                havebuf = m1;
                    934:                *mdp = m1 = m1->m_next;
                    935:                if (m1 == NULL)
1.1       cgd       936:                        return (EBADRPC);
1.183     christos  937:                src = mtod(m1, void *);
1.39      fvdl      938:                left = m1->m_len;
                    939:                /*
                    940:                 * If we start a new mbuf and it is big enough
                    941:                 * and correctly aligned just return it, don't
                    942:                 * do any pull up.
                    943:                 */
                    944:                if (left >= siz && nfsm_aligned(src)) {
                    945:                        *cp2 = src;
                    946:                        *dposp = src + siz;
                    947:                        return (0);
                    948:                }
1.1       cgd       949:        }
1.39      fvdl      950:        if (m1->m_flags & M_EXT) {
                    951:                if (havebuf) {
                    952:                        /* If the first mbuf with data has external data
                    953:                         * and there is a previous empty mbuf use it
                    954:                         * to move the data into.
                    955:                         */
                    956:                        m2 = m1;
                    957:                        *mdp = m1 = havebuf;
                    958:                        if (m1->m_flags & M_EXT) {
1.41      thorpej   959:                                MEXTREMOVE(m1);
1.1       cgd       960:                        }
1.39      fvdl      961:                } else {
                    962:                        /*
                    963:                         * If the first mbuf has a external data
                    964:                         * and there is no previous empty mbuf
                    965:                         * allocate a new mbuf and move the external
1.148     perry     966:                         * data to the new mbuf. Also make the first
1.39      fvdl      967:                         * mbuf look empty.
                    968:                         */
                    969:                        m2 = m_get(M_WAIT, MT_DATA);
                    970:                        m2->m_ext = m1->m_ext;
                    971:                        m2->m_data = src;
                    972:                        m2->m_len = left;
1.41      thorpej   973:                        MCLADDREFERENCE(m1, m2);
                    974:                        MEXTREMOVE(m1);
1.39      fvdl      975:                        m2->m_next = m1->m_next;
                    976:                        m1->m_next = m2;
1.1       cgd       977:                }
1.39      fvdl      978:                m1->m_len = 0;
1.129     itojun    979:                if (m1->m_flags & M_PKTHDR)
                    980:                        dst = m1->m_pktdat;
                    981:                else
                    982:                        dst = m1->m_dat;
                    983:                m1->m_data = dst;
1.39      fvdl      984:        } else {
                    985:                /*
                    986:                 * If the first mbuf has no external data
                    987:                 * move the data to the front of the mbuf.
                    988:                 */
1.129     itojun    989:                if (m1->m_flags & M_PKTHDR)
                    990:                        dst = m1->m_pktdat;
                    991:                else
                    992:                        dst = m1->m_dat;
                    993:                m1->m_data = dst;
                    994:                if (dst != src)
1.63      perry     995:                        memmove(dst, src, left);
1.148     perry     996:                dst += left;
1.39      fvdl      997:                m1->m_len = left;
                    998:                m2 = m1->m_next;
1.1       cgd       999:        }
1.129     itojun   1000:        *cp2 = m1->m_data;
1.183     christos 1001:        *dposp = mtod(m1, char *) + siz;
1.39      fvdl     1002:        /*
                   1003:         * Loop through mbufs pulling data up into first mbuf until
                   1004:         * the first mbuf is full or there is no more data to
                   1005:         * pullup.
                   1006:         */
1.129     itojun   1007:        while ((len = M_TRAILINGSPACE(m1)) != 0 && m2) {
1.39      fvdl     1008:                if ((len = min(len, m2->m_len)) != 0)
1.63      perry    1009:                        memcpy(dst, m2->m_data, len);
1.39      fvdl     1010:                m1->m_len += len;
                   1011:                dst += len;
                   1012:                m2->m_data += len;
                   1013:                m2->m_len -= len;
                   1014:                m2 = m2->m_next;
                   1015:        }
                   1016:        if (m1->m_len < siz)
                   1017:                return (EBADRPC);
1.1       cgd      1018:        return (0);
                   1019: }
                   1020:
                   1021: /*
                   1022:  * Advance the position in the mbuf chain.
                   1023:  */
1.24      christos 1024: int
1.1       cgd      1025: nfs_adv(mdp, dposp, offs, left)
                   1026:        struct mbuf **mdp;
1.183     christos 1027:        char **dposp;
1.1       cgd      1028:        int offs;
                   1029:        int left;
                   1030: {
1.75      augustss 1031:        struct mbuf *m;
                   1032:        int s;
1.1       cgd      1033:
                   1034:        m = *mdp;
                   1035:        s = left;
                   1036:        while (s < offs) {
                   1037:                offs -= s;
                   1038:                m = m->m_next;
                   1039:                if (m == NULL)
                   1040:                        return (EBADRPC);
                   1041:                s = m->m_len;
                   1042:        }
                   1043:        *mdp = m;
1.183     christos 1044:        *dposp = mtod(m, char *) + offs;
1.1       cgd      1045:        return (0);
                   1046: }
                   1047:
                   1048: /*
                   1049:  * Copy a string into mbufs for the hard cases...
                   1050:  */
1.24      christos 1051: int
1.1       cgd      1052: nfsm_strtmbuf(mb, bpos, cp, siz)
                   1053:        struct mbuf **mb;
                   1054:        char **bpos;
1.33      cgd      1055:        const char *cp;
1.1       cgd      1056:        long siz;
                   1057: {
1.75      augustss 1058:        struct mbuf *m1 = NULL, *m2;
1.1       cgd      1059:        long left, xfer, len, tlen;
1.22      cgd      1060:        u_int32_t *tl;
1.1       cgd      1061:        int putsize;
                   1062:
                   1063:        putsize = 1;
                   1064:        m2 = *mb;
1.12      mycroft  1065:        left = M_TRAILINGSPACE(m2);
1.1       cgd      1066:        if (left > 0) {
1.22      cgd      1067:                tl = ((u_int32_t *)(*bpos));
1.1       cgd      1068:                *tl++ = txdr_unsigned(siz);
                   1069:                putsize = 0;
                   1070:                left -= NFSX_UNSIGNED;
                   1071:                m2->m_len += NFSX_UNSIGNED;
                   1072:                if (left > 0) {
1.183     christos 1073:                        memcpy((void *) tl, cp, left);
1.1       cgd      1074:                        siz -= left;
                   1075:                        cp += left;
                   1076:                        m2->m_len += left;
                   1077:                        left = 0;
                   1078:                }
                   1079:        }
1.12      mycroft  1080:        /* Loop around adding mbufs */
1.1       cgd      1081:        while (siz > 0) {
1.109     matt     1082:                m1 = m_get(M_WAIT, MT_DATA);
                   1083:                MCLAIM(m1, &nfs_mowner);
1.1       cgd      1084:                if (siz > MLEN)
1.109     matt     1085:                        m_clget(m1, M_WAIT);
1.1       cgd      1086:                m1->m_len = NFSMSIZ(m1);
                   1087:                m2->m_next = m1;
                   1088:                m2 = m1;
1.22      cgd      1089:                tl = mtod(m1, u_int32_t *);
1.1       cgd      1090:                tlen = 0;
                   1091:                if (putsize) {
                   1092:                        *tl++ = txdr_unsigned(siz);
                   1093:                        m1->m_len -= NFSX_UNSIGNED;
                   1094:                        tlen = NFSX_UNSIGNED;
                   1095:                        putsize = 0;
                   1096:                }
                   1097:                if (siz < m1->m_len) {
                   1098:                        len = nfsm_rndup(siz);
                   1099:                        xfer = siz;
                   1100:                        if (xfer < len)
                   1101:                                *(tl+(xfer>>2)) = 0;
                   1102:                } else {
                   1103:                        xfer = len = m1->m_len;
                   1104:                }
1.183     christos 1105:                memcpy((void *) tl, cp, xfer);
1.1       cgd      1106:                m1->m_len = len+tlen;
                   1107:                siz -= xfer;
                   1108:                cp += xfer;
                   1109:        }
                   1110:        *mb = m1;
1.183     christos 1111:        *bpos = mtod(m1, char *) + m1->m_len;
1.1       cgd      1112:        return (0);
                   1113: }
                   1114:
1.49      fvdl     1115: /*
                   1116:  * Directory caching routines. They work as follows:
                   1117:  * - a cache is maintained per VDIR nfsnode.
                   1118:  * - for each offset cookie that is exported to userspace, and can
                   1119:  *   thus be thrown back at us as an offset to VOP_READDIR, store
                   1120:  *   information in the cache.
                   1121:  * - cached are:
                   1122:  *   - cookie itself
                   1123:  *   - blocknumber (essentially just a search key in the buffer cache)
                   1124:  *   - entry number in block.
                   1125:  *   - offset cookie of block in which this entry is stored
                   1126:  *   - 32 bit cookie if NFSMNT_XLATECOOKIE is used.
                   1127:  * - entries are looked up in a hash table
                   1128:  * - also maintained is an LRU list of entries, used to determine
                   1129:  *   which ones to delete if the cache grows too large.
                   1130:  * - if 32 <-> 64 translation mode is requested for a filesystem,
                   1131:  *   the cache also functions as a translation table
                   1132:  * - in the translation case, invalidating the cache does not mean
                   1133:  *   flushing it, but just marking entries as invalid, except for
                   1134:  *   the <64bit cookie, 32bitcookie> pair which is still valid, to
                   1135:  *   still be able to use the cache as a translation table.
                   1136:  * - 32 bit cookies are uniquely created by combining the hash table
                   1137:  *   entry value, and one generation count per hash table entry,
                   1138:  *   incremented each time an entry is appended to the chain.
                   1139:  * - the cache is invalidated each time a direcory is modified
                   1140:  * - sanity checks are also done; if an entry in a block turns
                   1141:  *   out not to have a matching cookie, the cache is invalidated
                   1142:  *   and a new block starting from the wanted offset is fetched from
                   1143:  *   the server.
                   1144:  * - directory entries as read from the server are extended to contain
                   1145:  *   the 64bit and, optionally, the 32bit cookies, for sanity checking
                   1146:  *   the cache and exporting them to userspace through the cookie
                   1147:  *   argument to VOP_READDIR.
                   1148:  */
                   1149:
1.46      fvdl     1150: u_long
                   1151: nfs_dirhash(off)
                   1152:        off_t off;
                   1153: {
                   1154:        int i;
                   1155:        char *cp = (char *)&off;
                   1156:        u_long sum = 0L;
                   1157:
                   1158:        for (i = 0 ; i < sizeof (off); i++)
                   1159:                sum += *cp++;
                   1160:
                   1161:        return sum;
                   1162: }
                   1163:
1.135     yamt     1164: #define        _NFSDC_MTX(np)          (&NFSTOV(np)->v_interlock)
1.184.2.1! ad       1165: #define        NFSDC_LOCK(np)          mutex_enter(_NFSDC_MTX(np))
        !          1166: #define        NFSDC_UNLOCK(np)        mutex_exit(_NFSDC_MTX(np))
        !          1167: #define        NFSDC_ASSERT_LOCKED(np) KASSERT(mutex_owned(_NFSDC_MTX(np)))
1.135     yamt     1168:
1.49      fvdl     1169: void
                   1170: nfs_initdircache(vp)
                   1171:        struct vnode *vp;
                   1172: {
                   1173:        struct nfsnode *np = VTONFS(vp);
1.135     yamt     1174:        struct nfsdirhashhead *dircache;
1.120     yamt     1175:
1.135     yamt     1176:        dircache = hashinit(NFS_DIRHASHSIZ, HASH_LIST, M_NFSDIROFF,
                   1177:            M_WAITOK, &nfsdirhashmask);
1.49      fvdl     1178:
1.135     yamt     1179:        NFSDC_LOCK(np);
                   1180:        if (np->n_dircache == NULL) {
                   1181:                np->n_dircachesize = 0;
                   1182:                np->n_dircache = dircache;
                   1183:                dircache = NULL;
                   1184:                TAILQ_INIT(&np->n_dirchain);
                   1185:        }
                   1186:        NFSDC_UNLOCK(np);
                   1187:        if (dircache)
                   1188:                hashdone(dircache, M_NFSDIROFF);
1.120     yamt     1189: }
                   1190:
                   1191: void
                   1192: nfs_initdirxlatecookie(vp)
                   1193:        struct vnode *vp;
                   1194: {
                   1195:        struct nfsnode *np = VTONFS(vp);
1.135     yamt     1196:        unsigned *dirgens;
1.120     yamt     1197:
                   1198:        KASSERT(VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_XLATECOOKIE);
                   1199:
1.135     yamt     1200:        dirgens = malloc(NFS_DIRHASHSIZ * sizeof (unsigned), M_NFSDIROFF,
                   1201:            M_WAITOK|M_ZERO);
                   1202:        NFSDC_LOCK(np);
                   1203:        if (np->n_dirgens == NULL) {
                   1204:                np->n_dirgens = dirgens;
                   1205:                dirgens = NULL;
                   1206:        }
                   1207:        NFSDC_UNLOCK(np);
                   1208:        if (dirgens)
                   1209:                free(dirgens, M_NFSDIROFF);
                   1210: }
                   1211:
                   1212: static const struct nfsdircache dzero;
                   1213:
                   1214: static void nfs_unlinkdircache __P((struct nfsnode *np, struct nfsdircache *));
                   1215: static void nfs_putdircache_unlocked __P((struct nfsnode *,
                   1216:     struct nfsdircache *));
                   1217:
                   1218: static void
                   1219: nfs_unlinkdircache(np, ndp)
                   1220:        struct nfsnode *np;
                   1221:        struct nfsdircache *ndp;
                   1222: {
                   1223:
                   1224:        NFSDC_ASSERT_LOCKED(np);
                   1225:        KASSERT(ndp != &dzero);
                   1226:
                   1227:        if (LIST_NEXT(ndp, dc_hash) == (void *)-1)
                   1228:                return;
                   1229:
                   1230:        TAILQ_REMOVE(&np->n_dirchain, ndp, dc_chain);
                   1231:        LIST_REMOVE(ndp, dc_hash);
                   1232:        LIST_NEXT(ndp, dc_hash) = (void *)-1; /* mark as unlinked */
                   1233:
                   1234:        nfs_putdircache_unlocked(np, ndp);
                   1235: }
                   1236:
                   1237: void
                   1238: nfs_putdircache(np, ndp)
                   1239:        struct nfsnode *np;
                   1240:        struct nfsdircache *ndp;
                   1241: {
                   1242:        int ref;
                   1243:
                   1244:        if (ndp == &dzero)
                   1245:                return;
                   1246:
                   1247:        KASSERT(ndp->dc_refcnt > 0);
                   1248:        NFSDC_LOCK(np);
                   1249:        ref = --ndp->dc_refcnt;
                   1250:        NFSDC_UNLOCK(np);
                   1251:
                   1252:        if (ref == 0)
                   1253:                free(ndp, M_NFSDIROFF);
1.49      fvdl     1254: }
                   1255:
1.135     yamt     1256: static void
1.177     yamt     1257: nfs_putdircache_unlocked(struct nfsnode *np, struct nfsdircache *ndp)
1.135     yamt     1258: {
                   1259:        int ref;
                   1260:
                   1261:        NFSDC_ASSERT_LOCKED(np);
                   1262:
                   1263:        if (ndp == &dzero)
                   1264:                return;
                   1265:
                   1266:        KASSERT(ndp->dc_refcnt > 0);
                   1267:        ref = --ndp->dc_refcnt;
                   1268:        if (ref == 0)
                   1269:                free(ndp, M_NFSDIROFF);
                   1270: }
1.46      fvdl     1271:
                   1272: struct nfsdircache *
1.49      fvdl     1273: nfs_searchdircache(vp, off, do32, hashent)
1.46      fvdl     1274:        struct vnode *vp;
                   1275:        off_t off;
1.49      fvdl     1276:        int do32;
                   1277:        int *hashent;
                   1278: {
                   1279:        struct nfsdirhashhead *ndhp;
                   1280:        struct nfsdircache *ndp = NULL;
                   1281:        struct nfsnode *np = VTONFS(vp);
                   1282:        unsigned ent;
                   1283:
                   1284:        /*
                   1285:         * Zero is always a valid cookie.
                   1286:         */
                   1287:        if (off == 0)
1.149     christos 1288:                /* XXXUNCONST */
                   1289:                return (struct nfsdircache *)__UNCONST(&dzero);
1.49      fvdl     1290:
1.134     yamt     1291:        if (!np->n_dircache)
                   1292:                return NULL;
                   1293:
1.49      fvdl     1294:        /*
                   1295:         * We use a 32bit cookie as search key, directly reconstruct
                   1296:         * the hashentry. Else use the hashfunction.
                   1297:         */
                   1298:        if (do32) {
                   1299:                ent = (u_int32_t)off >> 24;
                   1300:                if (ent >= NFS_DIRHASHSIZ)
                   1301:                        return NULL;
                   1302:                ndhp = &np->n_dircache[ent];
                   1303:        } else {
                   1304:                ndhp = NFSDIRHASH(np, off);
                   1305:        }
                   1306:
                   1307:        if (hashent)
                   1308:                *hashent = (int)(ndhp - np->n_dircache);
1.135     yamt     1309:
                   1310:        NFSDC_LOCK(np);
1.49      fvdl     1311:        if (do32) {
1.113     yamt     1312:                LIST_FOREACH(ndp, ndhp, dc_hash) {
1.49      fvdl     1313:                        if (ndp->dc_cookie32 == (u_int32_t)off) {
                   1314:                                /*
                   1315:                                 * An invalidated entry will become the
                   1316:                                 * start of a new block fetched from
                   1317:                                 * the server.
                   1318:                                 */
1.135     yamt     1319:                                if (ndp->dc_flags & NFSDC_INVALID) {
1.49      fvdl     1320:                                        ndp->dc_blkcookie = ndp->dc_cookie;
                   1321:                                        ndp->dc_entry = 0;
1.135     yamt     1322:                                        ndp->dc_flags &= ~NFSDC_INVALID;
1.49      fvdl     1323:                                }
                   1324:                                break;
                   1325:                        }
                   1326:                }
                   1327:        } else {
1.113     yamt     1328:                LIST_FOREACH(ndp, ndhp, dc_hash) {
1.49      fvdl     1329:                        if (ndp->dc_cookie == off)
                   1330:                                break;
1.113     yamt     1331:                }
1.49      fvdl     1332:        }
1.135     yamt     1333:        if (ndp != NULL)
                   1334:                ndp->dc_refcnt++;
                   1335:        NFSDC_UNLOCK(np);
1.49      fvdl     1336:        return ndp;
                   1337: }
                   1338:
                   1339:
                   1340: struct nfsdircache *
1.171     christos 1341: nfs_enterdircache(struct vnode *vp, off_t off, off_t blkoff, int en,
1.177     yamt     1342:     daddr_t blkno)
1.46      fvdl     1343: {
                   1344:        struct nfsnode *np = VTONFS(vp);
                   1345:        struct nfsdirhashhead *ndhp;
1.135     yamt     1346:        struct nfsdircache *ndp = NULL;
                   1347:        struct nfsdircache *newndp = NULL;
1.49      fvdl     1348:        struct nfsmount *nmp = VFSTONFS(vp->v_mount);
1.161     christos 1349:        int hashent = 0, gen, overwrite;        /* XXX: GCC */
1.46      fvdl     1350:
1.135     yamt     1351:        /*
                   1352:         * XXX refuse entries for offset 0. amd(8) erroneously sets
                   1353:         * cookie 0 for the '.' entry, making this necessary. This
                   1354:         * isn't so bad, as 0 is a special case anyway.
                   1355:         */
                   1356:        if (off == 0)
1.149     christos 1357:                /* XXXUNCONST */
                   1358:                return (struct nfsdircache *)__UNCONST(&dzero);
1.135     yamt     1359:
1.49      fvdl     1360:        if (!np->n_dircache)
                   1361:                /*
                   1362:                 * XXX would like to do this in nfs_nget but vtype
                   1363:                 * isn't known at that time.
                   1364:                 */
                   1365:                nfs_initdircache(vp);
1.50      fvdl     1366:
1.120     yamt     1367:        if ((nmp->nm_flag & NFSMNT_XLATECOOKIE) && !np->n_dirgens)
                   1368:                nfs_initdirxlatecookie(vp);
                   1369:
1.135     yamt     1370: retry:
1.49      fvdl     1371:        ndp = nfs_searchdircache(vp, off, 0, &hashent);
                   1372:
1.135     yamt     1373:        NFSDC_LOCK(np);
                   1374:        if (ndp && (ndp->dc_flags & NFSDC_INVALID) == 0) {
1.49      fvdl     1375:                /*
                   1376:                 * Overwriting an old entry. Check if it's the same.
                   1377:                 * If so, just return. If not, remove the old entry.
                   1378:                 */
                   1379:                if (ndp->dc_blkcookie == blkoff && ndp->dc_entry == en)
1.135     yamt     1380:                        goto done;
                   1381:                nfs_unlinkdircache(np, ndp);
                   1382:                nfs_putdircache_unlocked(np, ndp);
                   1383:                ndp = NULL;
1.46      fvdl     1384:        }
                   1385:
1.49      fvdl     1386:        ndhp = &np->n_dircache[hashent];
1.46      fvdl     1387:
1.49      fvdl     1388:        if (!ndp) {
1.135     yamt     1389:                if (newndp == NULL) {
                   1390:                        NFSDC_UNLOCK(np);
                   1391:                        newndp = malloc(sizeof(*ndp), M_NFSDIROFF, M_WAITOK);
                   1392:                        newndp->dc_refcnt = 1;
                   1393:                        LIST_NEXT(newndp, dc_hash) = (void *)-1;
                   1394:                        goto retry;
                   1395:                }
                   1396:                ndp = newndp;
                   1397:                newndp = NULL;
1.49      fvdl     1398:                overwrite = 0;
                   1399:                if (nmp->nm_flag & NFSMNT_XLATECOOKIE) {
                   1400:                        /*
                   1401:                         * We're allocating a new entry, so bump the
                   1402:                         * generation number.
                   1403:                         */
1.160     christos 1404:                        KASSERT(np->n_dirgens);
1.49      fvdl     1405:                        gen = ++np->n_dirgens[hashent];
                   1406:                        if (gen == 0) {
                   1407:                                np->n_dirgens[hashent]++;
                   1408:                                gen++;
                   1409:                        }
                   1410:                        ndp->dc_cookie32 = (hashent << 24) | (gen & 0xffffff);
                   1411:                }
                   1412:        } else
                   1413:                overwrite = 1;
1.46      fvdl     1414:
1.49      fvdl     1415:        ndp->dc_cookie = off;
                   1416:        ndp->dc_blkcookie = blkoff;
1.46      fvdl     1417:        ndp->dc_entry = en;
1.137     yamt     1418:        ndp->dc_flags = 0;
1.46      fvdl     1419:
1.49      fvdl     1420:        if (overwrite)
1.135     yamt     1421:                goto done;
1.49      fvdl     1422:
1.46      fvdl     1423:        /*
                   1424:         * If the maximum directory cookie cache size has been reached
                   1425:         * for this node, take one off the front. The idea is that
                   1426:         * directories are typically read front-to-back once, so that
                   1427:         * the oldest entries can be thrown away without much performance
                   1428:         * loss.
                   1429:         */
                   1430:        if (np->n_dircachesize == NFS_MAXDIRCACHE) {
1.135     yamt     1431:                nfs_unlinkdircache(np, TAILQ_FIRST(&np->n_dirchain));
1.46      fvdl     1432:        } else
                   1433:                np->n_dircachesize++;
1.148     perry    1434:
1.135     yamt     1435:        KASSERT(ndp->dc_refcnt == 1);
1.46      fvdl     1436:        LIST_INSERT_HEAD(ndhp, ndp, dc_hash);
                   1437:        TAILQ_INSERT_TAIL(&np->n_dirchain, ndp, dc_chain);
1.135     yamt     1438:        ndp->dc_refcnt++;
                   1439: done:
                   1440:        KASSERT(ndp->dc_refcnt > 0);
                   1441:        NFSDC_UNLOCK(np);
                   1442:        if (newndp)
                   1443:                nfs_putdircache(np, newndp);
1.46      fvdl     1444:        return ndp;
                   1445: }
                   1446:
                   1447: void
1.145     yamt     1448: nfs_invaldircache(vp, flags)
1.46      fvdl     1449:        struct vnode *vp;
1.145     yamt     1450:        int flags;
1.46      fvdl     1451: {
                   1452:        struct nfsnode *np = VTONFS(vp);
                   1453:        struct nfsdircache *ndp = NULL;
1.49      fvdl     1454:        struct nfsmount *nmp = VFSTONFS(vp->v_mount);
1.181     thorpej  1455:        const bool forcefree = flags & NFS_INVALDIRCACHE_FORCE;
1.46      fvdl     1456:
                   1457: #ifdef DIAGNOSTIC
                   1458:        if (vp->v_type != VDIR)
                   1459:                panic("nfs: invaldircache: not dir");
                   1460: #endif
                   1461:
1.145     yamt     1462:        if ((flags & NFS_INVALDIRCACHE_KEEPEOF) == 0)
                   1463:                np->n_flag &= ~NEOFVALID;
1.144     yamt     1464:
1.46      fvdl     1465:        if (!np->n_dircache)
                   1466:                return;
                   1467:
1.135     yamt     1468:        NFSDC_LOCK(np);
1.49      fvdl     1469:        if (!(nmp->nm_flag & NFSMNT_XLATECOOKIE) || forcefree) {
1.135     yamt     1470:                while ((ndp = TAILQ_FIRST(&np->n_dirchain)) != NULL) {
                   1471:                        KASSERT(!forcefree || ndp->dc_refcnt == 1);
                   1472:                        nfs_unlinkdircache(np, ndp);
1.49      fvdl     1473:                }
                   1474:                np->n_dircachesize = 0;
                   1475:                if (forcefree && np->n_dirgens) {
                   1476:                        FREE(np->n_dirgens, M_NFSDIROFF);
1.120     yamt     1477:                        np->n_dirgens = NULL;
1.49      fvdl     1478:                }
                   1479:        } else {
1.135     yamt     1480:                TAILQ_FOREACH(ndp, &np->n_dirchain, dc_chain)
                   1481:                        ndp->dc_flags |= NFSDC_INVALID;
1.46      fvdl     1482:        }
                   1483:
1.135     yamt     1484:        NFSDC_UNLOCK(np);
1.46      fvdl     1485: }
                   1486:
1.1       cgd      1487: /*
1.35      thorpej  1488:  * Called once before VFS init to initialize shared and
                   1489:  * server-specific data structures.
1.1       cgd      1490:  */
1.157     yamt     1491: static int
1.155     thorpej  1492: nfs_init0(void)
1.1       cgd      1493: {
1.184.2.1! ad       1494:        extern krwlock_t netexport_lock;        /* XXX */
        !          1495:
        !          1496:        rw_init(&netexport_lock);
        !          1497:
1.12      mycroft  1498:        nfsrtt.pos = 0;
1.1       cgd      1499:        rpc_vers = txdr_unsigned(RPC_VER2);
                   1500:        rpc_call = txdr_unsigned(RPC_CALL);
                   1501:        rpc_reply = txdr_unsigned(RPC_REPLY);
                   1502:        rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED);
                   1503:        rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED);
                   1504:        rpc_mismatch = txdr_unsigned(RPC_MISMATCH);
1.12      mycroft  1505:        rpc_autherr = txdr_unsigned(RPC_AUTHERR);
1.1       cgd      1506:        rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX);
1.25      fvdl     1507:        rpc_auth_kerb = txdr_unsigned(RPCAUTH_KERB4);
1.1       cgd      1508:        nfs_prog = txdr_unsigned(NFS_PROG);
1.182     thorpej  1509:        nfs_true = txdr_unsigned(true);
                   1510:        nfs_false = txdr_unsigned(false);
1.12      mycroft  1511:        nfs_xdrneg1 = txdr_unsigned(-1);
1.25      fvdl     1512:        nfs_ticks = (hz * NFS_TICKINTVL + 500) / 1000;
                   1513:        if (nfs_ticks < 1)
                   1514:                nfs_ticks = 1;
1.2       glass    1515: #ifdef NFSSERVER
1.12      mycroft  1516:        nfsrv_init(0);                  /* Init server data structures */
1.1       cgd      1517:        nfsrv_initcache();              /* Init the server request cache */
1.36      fvdl     1518: #endif /* NFSSERVER */
1.12      mycroft  1519:
1.164     yamt     1520: #if defined(NFSSERVER) || (defined(NFS) && !defined(NFS_V2_ONLY))
                   1521:        nfsdreq_init();
                   1522: #endif /* defined(NFSSERVER) || (defined(NFS) && !defined(NFS_V2_ONLY)) */
                   1523:
1.103     christos 1524:        exithook_establish(nfs_exit, NULL);
1.12      mycroft  1525:
1.1       cgd      1526:        /*
                   1527:         * Initialize reply list and start timer
                   1528:         */
1.16      mycroft  1529:        TAILQ_INIT(&nfs_reqq);
1.24      christos 1530:        nfs_timer(NULL);
1.109     matt     1531:        MOWNER_ATTACH(&nfs_mowner);
1.106     jdolecek 1532:
                   1533: #ifdef NFS
                   1534:        /* Initialize the kqueue structures */
                   1535:        nfs_kqinit();
1.119     yamt     1536:        /* Initialize the iod structures */
                   1537:        nfs_iodinit();
1.106     jdolecek 1538: #endif
1.157     yamt     1539:        return 0;
1.1       cgd      1540: }
                   1541:
1.155     thorpej  1542: void
                   1543: nfs_init(void)
                   1544: {
                   1545:        static ONCE_DECL(nfs_init_once);
                   1546:
                   1547:        RUN_ONCE(&nfs_init_once, nfs_init0);
                   1548: }
                   1549:
1.38      thorpej  1550: #ifdef NFS
1.35      thorpej  1551: /*
                   1552:  * Called once at VFS init to initialize client-specific data structures.
                   1553:  */
                   1554: void
                   1555: nfs_vfs_init()
                   1556: {
1.155     thorpej  1557:        /* Initialize NFS server / client shared data. */
                   1558:        nfs_init();
                   1559:
1.96      chs      1560:        nfs_nhinit();                   /* Init the nfsnode table */
1.100     chs      1561:        nfs_commitsize = uvmexp.npages << (PAGE_SHIFT - 4);
1.96      chs      1562: }
1.35      thorpej  1563:
1.96      chs      1564: void
                   1565: nfs_vfs_reinit()
                   1566: {
                   1567:        nfs_nhreinit();
1.73      jdolecek 1568: }
                   1569:
                   1570: void
                   1571: nfs_vfs_done()
                   1572: {
                   1573:        nfs_nhdone();
1.35      thorpej  1574: }
                   1575:
1.1       cgd      1576: /*
1.12      mycroft  1577:  * Attribute cache routines.
                   1578:  * nfs_loadattrcache() - loads or updates the cache contents from attributes
                   1579:  *     that are on the mbuf list
                   1580:  * nfs_getattrcache() - returns valid attributes if found in cache, returns
                   1581:  *     error otherwise
1.1       cgd      1582:  */
1.12      mycroft  1583:
                   1584: /*
                   1585:  * Load the attribute cache (that lives in the nfsnode entry) with
                   1586:  * the values on the mbuf list and
                   1587:  * Iff vap not NULL
                   1588:  *    copy the attributes to *vaper
                   1589:  */
1.24      christos 1590: int
1.105     yamt     1591: nfsm_loadattrcache(vpp, mdp, dposp, vaper, flags)
1.12      mycroft  1592:        struct vnode **vpp;
                   1593:        struct mbuf **mdp;
1.183     christos 1594:        char **dposp;
1.12      mycroft  1595:        struct vattr *vaper;
1.105     yamt     1596:        int flags;
1.1       cgd      1597: {
1.75      augustss 1598:        int32_t t1;
1.183     christos 1599:        char *cp2;
1.25      fvdl     1600:        int error = 0;
1.12      mycroft  1601:        struct mbuf *md;
1.45      fvdl     1602:        int v3 = NFS_ISV3(*vpp);
1.1       cgd      1603:
1.12      mycroft  1604:        md = *mdp;
1.183     christos 1605:        t1 = (mtod(md, char *) + md->m_len) - *dposp;
1.25      fvdl     1606:        error = nfsm_disct(mdp, dposp, NFSX_FATTR(v3), t1, &cp2);
1.24      christos 1607:        if (error)
1.12      mycroft  1608:                return (error);
1.105     yamt     1609:        return nfs_loadattrcache(vpp, (struct nfs_fattr *)cp2, vaper, flags);
1.45      fvdl     1610: }
                   1611:
                   1612: int
1.105     yamt     1613: nfs_loadattrcache(vpp, fp, vaper, flags)
1.45      fvdl     1614:        struct vnode **vpp;
                   1615:        struct nfs_fattr *fp;
                   1616:        struct vattr *vaper;
1.105     yamt     1617:        int flags;
1.45      fvdl     1618: {
1.75      augustss 1619:        struct vnode *vp = *vpp;
                   1620:        struct vattr *vap;
1.45      fvdl     1621:        int v3 = NFS_ISV3(vp);
                   1622:        enum vtype vtyp;
                   1623:        u_short vmode;
                   1624:        struct timespec mtime;
1.139     yamt     1625:        struct timespec ctime;
1.45      fvdl     1626:        struct vnode *nvp;
                   1627:        int32_t rdev;
1.75      augustss 1628:        struct nfsnode *np;
1.45      fvdl     1629:        extern int (**spec_nfsv2nodeop_p) __P((void *));
1.101     fvdl     1630:        uid_t uid;
                   1631:        gid_t gid;
1.45      fvdl     1632:
1.25      fvdl     1633:        if (v3) {
                   1634:                vtyp = nfsv3tov_type(fp->fa_type);
                   1635:                vmode = fxdr_unsigned(u_short, fp->fa_mode);
1.71      is       1636:                rdev = makedev(fxdr_unsigned(u_int32_t, fp->fa3_rdev.specdata1),
                   1637:                        fxdr_unsigned(u_int32_t, fp->fa3_rdev.specdata2));
1.25      fvdl     1638:                fxdr_nfsv3time(&fp->fa3_mtime, &mtime);
1.139     yamt     1639:                fxdr_nfsv3time(&fp->fa3_ctime, &ctime);
1.12      mycroft  1640:        } else {
1.25      fvdl     1641:                vtyp = nfsv2tov_type(fp->fa_type);
                   1642:                vmode = fxdr_unsigned(u_short, fp->fa_mode);
                   1643:                if (vtyp == VNON || vtyp == VREG)
                   1644:                        vtyp = IFTOVT(vmode);
                   1645:                rdev = fxdr_unsigned(int32_t, fp->fa2_rdev);
                   1646:                fxdr_nfsv2time(&fp->fa2_mtime, &mtime);
1.139     yamt     1647:                ctime.tv_sec = fxdr_unsigned(u_int32_t,
                   1648:                    fp->fa2_ctime.nfsv2_sec);
                   1649:                ctime.tv_nsec = 0;
1.25      fvdl     1650:
                   1651:                /*
                   1652:                 * Really ugly NFSv2 kludge.
                   1653:                 */
                   1654:                if (vtyp == VCHR && rdev == 0xffffffff)
                   1655:                        vtyp = VFIFO;
1.12      mycroft  1656:        }
1.25      fvdl     1657:
1.101     fvdl     1658:        vmode &= ALLPERMS;
                   1659:
1.12      mycroft  1660:        /*
                   1661:         * If v_type == VNON it is a new node, so fill in the v_type,
1.148     perry    1662:         * n_mtime fields. Check to see if it represents a special
1.12      mycroft  1663:         * device, and if so, check for a possible alias. Once the
                   1664:         * correct vnode has been obtained, fill in the rest of the
                   1665:         * information.
                   1666:         */
                   1667:        np = VTONFS(vp);
1.87      fvdl     1668:        if (vp->v_type == VNON) {
1.25      fvdl     1669:                vp->v_type = vtyp;
1.12      mycroft  1670:                if (vp->v_type == VFIFO) {
1.24      christos 1671:                        extern int (**fifo_nfsv2nodeop_p) __P((void *));
1.12      mycroft  1672:                        vp->v_op = fifo_nfsv2nodeop_p;
1.131     yamt     1673:                } else if (vp->v_type == VREG) {
1.180     yamt     1674:                        mutex_init(&np->n_commitlock, MUTEX_DEFAULT, IPL_NONE);
1.131     yamt     1675:                } else if (vp->v_type == VCHR || vp->v_type == VBLK) {
1.12      mycroft  1676:                        vp->v_op = spec_nfsv2nodeop_p;
1.24      christos 1677:                        nvp = checkalias(vp, (dev_t)rdev, vp->v_mount);
                   1678:                        if (nvp) {
1.12      mycroft  1679:                                /*
                   1680:                                 * Discard unneeded vnode, but save its nfsnode.
1.25      fvdl     1681:                                 * Since the nfsnode does not have a lock, its
                   1682:                                 * vnode lock has to be carried over.
1.12      mycroft  1683:                                 */
1.94      bjh21    1684:                                /*
                   1685:                                 * XXX is the old node sure to be locked here?
                   1686:                                 */
                   1687:                                KASSERT(lockstatus(&vp->v_lock) ==
                   1688:                                    LK_EXCLUSIVE);
1.12      mycroft  1689:                                nvp->v_data = vp->v_data;
                   1690:                                vp->v_data = NULL;
1.93      fvdl     1691:                                VOP_UNLOCK(vp, 0);
1.12      mycroft  1692:                                vp->v_op = spec_vnodeop_p;
1.93      fvdl     1693:                                vrele(vp);
1.12      mycroft  1694:                                vgone(vp);
1.94      bjh21    1695:                                lockmgr(&nvp->v_lock, LK_EXCLUSIVE,
                   1696:                                    &nvp->v_interlock);
1.12      mycroft  1697:                                /*
                   1698:                                 * Reinitialize aliased node.
                   1699:                                 */
                   1700:                                np->n_vnode = nvp;
                   1701:                                *vpp = vp = nvp;
                   1702:                        }
                   1703:                }
1.128     yamt     1704:                np->n_mtime = mtime;
1.12      mycroft  1705:        }
1.101     fvdl     1706:        uid = fxdr_unsigned(uid_t, fp->fa_uid);
                   1707:        gid = fxdr_unsigned(gid_t, fp->fa_gid);
1.49      fvdl     1708:        vap = np->n_vattr;
1.101     fvdl     1709:
                   1710:        /*
1.139     yamt     1711:         * Invalidate access cache if uid, gid, mode or ctime changed.
1.101     fvdl     1712:         */
                   1713:        if (np->n_accstamp != -1 &&
1.139     yamt     1714:            (gid != vap->va_gid || uid != vap->va_uid || vmode != vap->va_mode
                   1715:            || timespeccmp(&ctime, &vap->va_ctime, !=)))
1.101     fvdl     1716:                np->n_accstamp = -1;
                   1717:
1.12      mycroft  1718:        vap->va_type = vtyp;
1.101     fvdl     1719:        vap->va_mode = vmode;
1.12      mycroft  1720:        vap->va_rdev = (dev_t)rdev;
                   1721:        vap->va_mtime = mtime;
1.139     yamt     1722:        vap->va_ctime = ctime;
1.133     christos 1723:        vap->va_fsid = vp->v_mount->mnt_stat.f_fsidx.__fsid_val[0];
1.72      fvdl     1724:        switch (vtyp) {
                   1725:        case VDIR:
                   1726:                vap->va_blocksize = NFS_DIRFRAGSIZ;
                   1727:                break;
                   1728:        case VBLK:
                   1729:                vap->va_blocksize = BLKDEV_IOSIZE;
                   1730:                break;
                   1731:        case VCHR:
                   1732:                vap->va_blocksize = MAXBSIZE;
                   1733:                break;
                   1734:        default:
                   1735:                vap->va_blocksize = v3 ? vp->v_mount->mnt_stat.f_iosize :
                   1736:                    fxdr_unsigned(int32_t, fp->fa2_blocksize);
                   1737:                break;
                   1738:        }
1.25      fvdl     1739:        if (v3) {
                   1740:                vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink);
1.101     fvdl     1741:                vap->va_uid = uid;
                   1742:                vap->va_gid = gid;
1.66      fair     1743:                vap->va_size = fxdr_hyper(&fp->fa3_size);
                   1744:                vap->va_bytes = fxdr_hyper(&fp->fa3_used);
1.151     yamt     1745:                vap->va_fileid = fxdr_hyper(&fp->fa3_fileid);
1.25      fvdl     1746:                fxdr_nfsv3time(&fp->fa3_atime, &vap->va_atime);
                   1747:                vap->va_flags = 0;
                   1748:                vap->va_filerev = 0;
1.12      mycroft  1749:        } else {
1.25      fvdl     1750:                vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink);
1.101     fvdl     1751:                vap->va_uid = uid;
                   1752:                vap->va_gid = gid;
1.25      fvdl     1753:                vap->va_size = fxdr_unsigned(u_int32_t, fp->fa2_size);
                   1754:                vap->va_bytes = fxdr_unsigned(int32_t, fp->fa2_blocks)
                   1755:                    * NFS_FABLKSIZE;
                   1756:                vap->va_fileid = fxdr_unsigned(int32_t, fp->fa2_fileid);
                   1757:                fxdr_nfsv2time(&fp->fa2_atime, &vap->va_atime);
1.12      mycroft  1758:                vap->va_flags = 0;
1.25      fvdl     1759:                vap->va_gen = fxdr_unsigned(u_int32_t,fp->fa2_ctime.nfsv2_usec);
1.12      mycroft  1760:                vap->va_filerev = 0;
                   1761:        }
                   1762:        if (vap->va_size != np->n_size) {
1.89      chs      1763:                if ((np->n_flag & NMODIFIED) && vap->va_size < np->n_size) {
                   1764:                        vap->va_size = np->n_size;
                   1765:                } else {
1.12      mycroft  1766:                        np->n_size = vap->va_size;
1.89      chs      1767:                        if (vap->va_type == VREG) {
1.140     yamt     1768:                                /*
                   1769:                                 * we can't free pages if NAC_NOTRUNC because
                   1770:                                 * the pages can be owned by ourselves.
                   1771:                                 */
                   1772:                                if (flags & NAC_NOTRUNC) {
1.105     yamt     1773:                                        np->n_flag |= NTRUNCDELAYED;
1.140     yamt     1774:                                } else {
1.174     yamt     1775:                                        genfs_node_wrlock(vp);
1.184.2.1! ad       1776:                                        mutex_enter(&vp->v_interlock);
1.140     yamt     1777:                                        (void)VOP_PUTPAGES(vp, 0,
                   1778:                                            0, PGO_SYNCIO | PGO_CLEANIT |
                   1779:                                            PGO_FREE | PGO_ALLPAGES);
1.105     yamt     1780:                                        uvm_vnp_setsize(vp, np->n_size);
1.174     yamt     1781:                                        genfs_node_unlock(vp);
1.105     yamt     1782:                                }
1.89      chs      1783:                        }
                   1784:                }
1.12      mycroft  1785:        }
1.165     kardel   1786:        np->n_attrstamp = time_second;
1.12      mycroft  1787:        if (vaper != NULL) {
1.183     christos 1788:                memcpy((void *)vaper, (void *)vap, sizeof(*vap));
1.12      mycroft  1789:                if (np->n_flag & NCHG) {
1.25      fvdl     1790:                        if (np->n_flag & NACC)
                   1791:                                vaper->va_atime = np->n_atim;
                   1792:                        if (np->n_flag & NUPD)
                   1793:                                vaper->va_mtime = np->n_mtim;
1.12      mycroft  1794:                }
                   1795:        }
                   1796:        return (0);
                   1797: }
                   1798:
                   1799: /*
                   1800:  * Check the time stamp
                   1801:  * If the cache is valid, copy contents to *vap and return 0
                   1802:  * otherwise return an error
                   1803:  */
1.24      christos 1804: int
1.12      mycroft  1805: nfs_getattrcache(vp, vaper)
1.75      augustss 1806:        struct vnode *vp;
1.12      mycroft  1807:        struct vattr *vaper;
                   1808: {
1.75      augustss 1809:        struct nfsnode *np = VTONFS(vp);
1.152     christos 1810:        struct nfsmount *nmp = VFSTONFS(vp->v_mount);
1.75      augustss 1811:        struct vattr *vap;
1.12      mycroft  1812:
1.132     yamt     1813:        if (np->n_attrstamp == 0 ||
1.165     kardel   1814:            (time_second - np->n_attrstamp) >= NFS_ATTRTIMEO(nmp, np)) {
1.12      mycroft  1815:                nfsstats.attrcache_misses++;
                   1816:                return (ENOENT);
                   1817:        }
                   1818:        nfsstats.attrcache_hits++;
1.49      fvdl     1819:        vap = np->n_vattr;
1.12      mycroft  1820:        if (vap->va_size != np->n_size) {
                   1821:                if (vap->va_type == VREG) {
                   1822:                        if (np->n_flag & NMODIFIED) {
                   1823:                                if (vap->va_size < np->n_size)
                   1824:                                        vap->va_size = np->n_size;
                   1825:                                else
                   1826:                                        np->n_size = vap->va_size;
                   1827:                        } else
                   1828:                                np->n_size = vap->va_size;
1.174     yamt     1829:                        genfs_node_wrlock(vp);
1.51      mrg      1830:                        uvm_vnp_setsize(vp, np->n_size);
1.174     yamt     1831:                        genfs_node_unlock(vp);
1.12      mycroft  1832:                } else
                   1833:                        np->n_size = vap->va_size;
                   1834:        }
1.183     christos 1835:        memcpy((void *)vaper, (void *)vap, sizeof(struct vattr));
1.12      mycroft  1836:        if (np->n_flag & NCHG) {
1.25      fvdl     1837:                if (np->n_flag & NACC)
                   1838:                        vaper->va_atime = np->n_atim;
                   1839:                if (np->n_flag & NUPD)
                   1840:                        vaper->va_mtime = np->n_mtim;
1.1       cgd      1841:        }
1.12      mycroft  1842:        return (0);
1.105     yamt     1843: }
                   1844:
                   1845: void
                   1846: nfs_delayedtruncate(vp)
                   1847:        struct vnode *vp;
                   1848: {
                   1849:        struct nfsnode *np = VTONFS(vp);
                   1850:
                   1851:        if (np->n_flag & NTRUNCDELAYED) {
                   1852:                np->n_flag &= ~NTRUNCDELAYED;
1.174     yamt     1853:                genfs_node_wrlock(vp);
1.184.2.1! ad       1854:                mutex_enter(&vp->v_interlock);
1.140     yamt     1855:                (void)VOP_PUTPAGES(vp, 0,
                   1856:                    0, PGO_SYNCIO | PGO_CLEANIT | PGO_FREE | PGO_ALLPAGES);
1.105     yamt     1857:                uvm_vnp_setsize(vp, np->n_size);
1.174     yamt     1858:                genfs_node_unlock(vp);
1.105     yamt     1859:        }
1.1       cgd      1860: }
1.48      fvdl     1861:
1.141     yamt     1862: #define        NFS_WCCKLUDGE_TIMEOUT   (24 * 60 * 60)  /* 1 day */
                   1863: #define        NFS_WCCKLUDGE(nmp, now) \
                   1864:        (((nmp)->nm_iflag & NFSMNT_WCCKLUDGE) && \
                   1865:        ((now) - (nmp)->nm_wcckludgetime - NFS_WCCKLUDGE_TIMEOUT) < 0)
                   1866:
                   1867: /*
                   1868:  * nfs_check_wccdata: check inaccurate wcc_data
                   1869:  *
                   1870:  * => return non-zero if we shouldn't trust the wcc_data.
                   1871:  * => NFS_WCCKLUDGE_TIMEOUT is for the case that the server is "fixed".
                   1872:  */
                   1873:
                   1874: int
1.177     yamt     1875: nfs_check_wccdata(struct nfsnode *np, const struct timespec *ctime,
1.181     thorpej  1876:     struct timespec *mtime, bool docheck)
1.141     yamt     1877: {
                   1878:        int error = 0;
                   1879:
                   1880: #if !defined(NFS_V2_ONLY)
                   1881:
                   1882:        if (docheck) {
                   1883:                struct vnode *vp = NFSTOV(np);
                   1884:                struct nfsmount *nmp;
1.165     kardel   1885:                long now = time_second;
1.184     yamt     1886:                const struct timespec *omtime = &np->n_vattr->va_mtime;
                   1887:                const struct timespec *octime = &np->n_vattr->va_ctime;
1.141     yamt     1888: #if defined(DEBUG)
                   1889:                const char *reason = NULL; /* XXX: gcc */
                   1890: #endif
                   1891:
1.184     yamt     1892:                if (timespeccmp(omtime, mtime, <=)) {
1.141     yamt     1893: #if defined(DEBUG)
                   1894:                        reason = "mtime";
                   1895: #endif
                   1896:                        error = EINVAL;
                   1897:                }
                   1898:
1.184     yamt     1899:                if (vp->v_type == VDIR && timespeccmp(octime, ctime, <=)) {
1.141     yamt     1900: #if defined(DEBUG)
                   1901:                        reason = "ctime";
                   1902: #endif
                   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.184.2.1! ad       1923:                        mutex_enter(&nmp->nm_lock);
1.141     yamt     1924: #if defined(DEBUG)
                   1925:                        if (!NFS_WCCKLUDGE(nmp, now)) {
                   1926:                                printf("%s: inaccurate wcc data (%s) detected,"
1.184     yamt     1927:                                    " disabling wcc"
                   1928:                                    " (ctime %u.%09u %u.%09u,"
                   1929:                                    " mtime %u.%09u %u.%09u)\n",
1.141     yamt     1930:                                    vp->v_mount->mnt_stat.f_mntfromname,
1.184     yamt     1931:                                    reason,
                   1932:                                    (unsigned int)octime->tv_sec,
                   1933:                                    (unsigned int)octime->tv_nsec,
                   1934:                                    (unsigned int)ctime->tv_sec,
                   1935:                                    (unsigned int)ctime->tv_nsec,
                   1936:                                    (unsigned int)omtime->tv_sec,
                   1937:                                    (unsigned int)omtime->tv_nsec,
                   1938:                                    (unsigned int)mtime->tv_sec,
                   1939:                                    (unsigned int)mtime->tv_nsec);
1.141     yamt     1940:                        }
                   1941: #endif
                   1942:                        nmp->nm_iflag |= NFSMNT_WCCKLUDGE;
                   1943:                        nmp->nm_wcckludgetime = now;
1.184.2.1! ad       1944:                        mutex_exit(&nmp->nm_lock);
1.141     yamt     1945:                } else if (NFS_WCCKLUDGE(nmp, now)) {
                   1946:                        error = EPERM; /* XXX */
                   1947:                } else if (nmp->nm_iflag & NFSMNT_WCCKLUDGE) {
1.184.2.1! ad       1948:                        mutex_enter(&nmp->nm_lock);
1.141     yamt     1949:                        if (nmp->nm_iflag & NFSMNT_WCCKLUDGE) {
                   1950: #if defined(DEBUG)
                   1951:                                printf("%s: re-enabling wcc\n",
                   1952:                                    vp->v_mount->mnt_stat.f_mntfromname);
                   1953: #endif
                   1954:                                nmp->nm_iflag &= ~NFSMNT_WCCKLUDGE;
                   1955:                        }
1.184.2.1! ad       1956:                        mutex_exit(&nmp->nm_lock);
1.141     yamt     1957:                }
                   1958:        }
                   1959:
                   1960: #endif /* !defined(NFS_V2_ONLY) */
                   1961:
                   1962:        return error;
                   1963: }
                   1964:
1.48      fvdl     1965: /*
                   1966:  * Heuristic to see if the server XDR encodes directory cookies or not.
                   1967:  * it is not supposed to, but a lot of servers may do this. Also, since
                   1968:  * most/all servers will implement V2 as well, it is expected that they
                   1969:  * may return just 32 bits worth of cookie information, so we need to
                   1970:  * find out in which 32 bits this information is available. We do this
                   1971:  * to avoid trouble with emulated binaries that can't handle 64 bit
                   1972:  * directory offsets.
                   1973:  */
                   1974:
                   1975: void
1.156     christos 1976: nfs_cookieheuristic(vp, flagp, l, cred)
1.48      fvdl     1977:        struct vnode *vp;
                   1978:        int *flagp;
1.156     christos 1979:        struct lwp *l;
1.162     elad     1980:        kauth_cred_t cred;
1.48      fvdl     1981: {
                   1982:        struct uio auio;
                   1983:        struct iovec aiov;
1.183     christos 1984:        char *tbuf, *cp;
1.48      fvdl     1985:        struct dirent *dp;
1.57      fvdl     1986:        off_t *cookies = NULL, *cop;
1.48      fvdl     1987:        int error, eof, nc, len;
                   1988:
1.183     christos 1989:        MALLOC(tbuf, void *, NFS_DIRFRAGSIZ, M_TEMP, M_WAITOK);
1.48      fvdl     1990:
1.149     christos 1991:        aiov.iov_base = tbuf;
1.48      fvdl     1992:        aiov.iov_len = NFS_DIRFRAGSIZ;
                   1993:        auio.uio_iov = &aiov;
                   1994:        auio.uio_iovcnt = 1;
                   1995:        auio.uio_rw = UIO_READ;
                   1996:        auio.uio_resid = NFS_DIRFRAGSIZ;
                   1997:        auio.uio_offset = 0;
1.158     yamt     1998:        UIO_SETUP_SYSSPACE(&auio);
1.48      fvdl     1999:
1.56      fvdl     2000:        error = VOP_READDIR(vp, &auio, cred, &eof, &cookies, &nc);
1.48      fvdl     2001:
                   2002:        len = NFS_DIRFRAGSIZ - auio.uio_resid;
                   2003:        if (error || len == 0) {
1.149     christos 2004:                FREE(tbuf, M_TEMP);
1.57      fvdl     2005:                if (cookies)
1.80      thorpej  2006:                        free(cookies, M_TEMP);
1.48      fvdl     2007:                return;
                   2008:        }
                   2009:
                   2010:        /*
                   2011:         * Find the first valid entry and look at its offset cookie.
                   2012:         */
                   2013:
1.149     christos 2014:        cp = tbuf;
1.48      fvdl     2015:        for (cop = cookies; len > 0; len -= dp->d_reclen) {
                   2016:                dp = (struct dirent *)cp;
                   2017:                if (dp->d_fileno != 0 && len >= dp->d_reclen) {
                   2018:                        if ((*cop >> 32) != 0 && (*cop & 0xffffffffLL) == 0) {
                   2019:                                *flagp |= NFSMNT_SWAPCOOKIE;
1.49      fvdl     2020:                                nfs_invaldircache(vp, 0);
1.156     christos 2021:                                nfs_vinvalbuf(vp, 0, cred, l, 1);
1.48      fvdl     2022:                        }
                   2023:                        break;
                   2024:                }
                   2025:                cop++;
                   2026:                cp += dp->d_reclen;
                   2027:        }
                   2028:
1.149     christos 2029:        FREE(tbuf, M_TEMP);
1.80      thorpej  2030:        free(cookies, M_TEMP);
1.48      fvdl     2031: }
1.38      thorpej  2032: #endif /* NFS */
1.1       cgd      2033:
1.153     jmmv     2034: #ifdef NFSSERVER
1.1       cgd      2035: /*
1.43      fvdl     2036:  * Set up nameidata for a lookup() call and do it.
                   2037:  *
                   2038:  * If pubflag is set, this call is done for a lookup operation on the
                   2039:  * public filehandle. In that case we allow crossing mountpoints and
                   2040:  * absolute pathnames. However, the caller is expected to check that
                   2041:  * the lookup result is within the public fs, and deny access if
                   2042:  * it is not.
1.1       cgd      2043:  */
1.24      christos 2044: int
1.168     yamt     2045: nfs_namei(ndp, nsfh, len, slp, nam, mdp, dposp, retdirp, l, kerbflag, pubflag)
1.75      augustss 2046:        struct nameidata *ndp;
1.168     yamt     2047:        nfsrvfh_t *nsfh;
1.110     yamt     2048:        uint32_t len;
1.12      mycroft  2049:        struct nfssvc_sock *slp;
                   2050:        struct mbuf *nam;
1.1       cgd      2051:        struct mbuf **mdp;
1.183     christos 2052:        char **dposp;
1.25      fvdl     2053:        struct vnode **retdirp;
1.156     christos 2054:        struct lwp *l;
1.43      fvdl     2055:        int kerbflag, pubflag;
1.1       cgd      2056: {
1.75      augustss 2057:        int i, rem;
                   2058:        struct mbuf *md;
                   2059:        char *fromcp, *tocp, *cp;
1.43      fvdl     2060:        struct iovec aiov;
                   2061:        struct uio auio;
1.1       cgd      2062:        struct vnode *dp;
1.43      fvdl     2063:        int error, rdonly, linklen;
1.12      mycroft  2064:        struct componentname *cnp = &ndp->ni_cnd;
1.1       cgd      2065:
1.178     chs      2066:        *retdirp = NULL;
1.81      thorpej  2067:
                   2068:        if ((len + 1) > MAXPATHLEN)
                   2069:                return (ENAMETOOLONG);
1.147     yamt     2070:        if (len == 0)
                   2071:                return (EACCES);
1.81      thorpej  2072:        cnp->cn_pnbuf = PNBUF_GET();
                   2073:
1.1       cgd      2074:        /*
                   2075:         * Copy the name from the mbuf list to ndp->ni_pnbuf
                   2076:         * and set the various ndp fields appropriately.
                   2077:         */
                   2078:        fromcp = *dposp;
1.12      mycroft  2079:        tocp = cnp->cn_pnbuf;
1.1       cgd      2080:        md = *mdp;
1.183     christos 2081:        rem = mtod(md, char *) + md->m_len - fromcp;
1.1       cgd      2082:        for (i = 0; i < len; i++) {
                   2083:                while (rem == 0) {
                   2084:                        md = md->m_next;
                   2085:                        if (md == NULL) {
                   2086:                                error = EBADRPC;
                   2087:                                goto out;
                   2088:                        }
1.183     christos 2089:                        fromcp = mtod(md, void *);
1.1       cgd      2090:                        rem = md->m_len;
                   2091:                }
1.43      fvdl     2092:                if (*fromcp == '\0' || (!pubflag && *fromcp == '/')) {
1.25      fvdl     2093:                        error = EACCES;
1.1       cgd      2094:                        goto out;
                   2095:                }
                   2096:                *tocp++ = *fromcp++;
                   2097:                rem--;
                   2098:        }
                   2099:        *tocp = '\0';
                   2100:        *mdp = md;
                   2101:        *dposp = fromcp;
                   2102:        len = nfsm_rndup(len)-len;
                   2103:        if (len > 0) {
                   2104:                if (rem >= len)
                   2105:                        *dposp += len;
1.24      christos 2106:                else if ((error = nfs_adv(mdp, dposp, len, rem)) != 0)
1.1       cgd      2107:                        goto out;
                   2108:        }
1.43      fvdl     2109:
1.1       cgd      2110:        /*
                   2111:         * Extract and set starting directory.
                   2112:         */
1.182     thorpej  2113:        error = nfsrv_fhtovp(nsfh, false, &dp, ndp->ni_cnd.cn_cred, slp,
1.124     thorpej  2114:            nam, &rdonly, kerbflag, pubflag);
1.24      christos 2115:        if (error)
1.1       cgd      2116:                goto out;
                   2117:        if (dp->v_type != VDIR) {
                   2118:                vrele(dp);
                   2119:                error = ENOTDIR;
                   2120:                goto out;
                   2121:        }
1.43      fvdl     2122:
                   2123:        if (rdonly)
                   2124:                cnp->cn_flags |= RDONLY;
                   2125:
                   2126:        *retdirp = dp;
                   2127:
                   2128:        if (pubflag) {
                   2129:                /*
                   2130:                 * Oh joy. For WebNFS, handle those pesky '%' escapes,
                   2131:                 * and the 'native path' indicator.
                   2132:                 */
1.81      thorpej  2133:                cp = PNBUF_GET();
1.43      fvdl     2134:                fromcp = cnp->cn_pnbuf;
                   2135:                tocp = cp;
                   2136:                if ((unsigned char)*fromcp >= WEBNFS_SPECCHAR_START) {
                   2137:                        switch ((unsigned char)*fromcp) {
                   2138:                        case WEBNFS_NATIVE_CHAR:
                   2139:                                /*
                   2140:                                 * 'Native' path for us is the same
                   2141:                                 * as a path according to the NFS spec,
                   2142:                                 * just skip the escape char.
                   2143:                                 */
                   2144:                                fromcp++;
                   2145:                                break;
                   2146:                        /*
                   2147:                         * More may be added in the future, range 0x80-0xff
                   2148:                         */
                   2149:                        default:
                   2150:                                error = EIO;
1.178     chs      2151:                                vrele(dp);
1.104     enami    2152:                                PNBUF_PUT(cp);
1.43      fvdl     2153:                                goto out;
                   2154:                        }
                   2155:                }
                   2156:                /*
                   2157:                 * Translate the '%' escapes, URL-style.
                   2158:                 */
                   2159:                while (*fromcp != '\0') {
                   2160:                        if (*fromcp == WEBNFS_ESC_CHAR) {
                   2161:                                if (fromcp[1] != '\0' && fromcp[2] != '\0') {
                   2162:                                        fromcp++;
                   2163:                                        *tocp++ = HEXSTRTOI(fromcp);
                   2164:                                        fromcp += 2;
                   2165:                                        continue;
                   2166:                                } else {
                   2167:                                        error = ENOENT;
1.178     chs      2168:                                        vrele(dp);
1.104     enami    2169:                                        PNBUF_PUT(cp);
1.43      fvdl     2170:                                        goto out;
                   2171:                                }
                   2172:                        } else
                   2173:                                *tocp++ = *fromcp++;
                   2174:                }
                   2175:                *tocp = '\0';
1.81      thorpej  2176:                PNBUF_PUT(cnp->cn_pnbuf);
1.43      fvdl     2177:                cnp->cn_pnbuf = cp;
                   2178:        }
                   2179:
                   2180:        ndp->ni_pathlen = (tocp - cnp->cn_pnbuf) + 1;
                   2181:        ndp->ni_segflg = UIO_SYSSPACE;
1.98      fvdl     2182:        ndp->ni_rootdir = rootvnode;
1.43      fvdl     2183:
                   2184:        if (pubflag) {
                   2185:                ndp->ni_loopcnt = 0;
                   2186:                if (cnp->cn_pnbuf[0] == '/')
                   2187:                        dp = rootvnode;
                   2188:        } else {
                   2189:                cnp->cn_flags |= NOCROSSMOUNT;
                   2190:        }
                   2191:
1.156     christos 2192:        cnp->cn_lwp = l;
1.25      fvdl     2193:        VREF(dp);
1.178     chs      2194:        vn_lock(dp, LK_EXCLUSIVE | LK_RETRY);
1.43      fvdl     2195:
                   2196:     for (;;) {
                   2197:        cnp->cn_nameptr = cnp->cn_pnbuf;
1.1       cgd      2198:        ndp->ni_startdir = dp;
1.178     chs      2199:
1.1       cgd      2200:        /*
                   2201:         * And call lookup() to do the real work
                   2202:         */
1.25      fvdl     2203:        error = lookup(ndp);
1.91      fvdl     2204:        if (error) {
1.178     chs      2205:                if (ndp->ni_dvp) {
                   2206:                        vput(ndp->ni_dvp);
                   2207:                }
1.91      fvdl     2208:                PNBUF_PUT(cnp->cn_pnbuf);
                   2209:                return (error);
                   2210:        }
1.178     chs      2211:
1.1       cgd      2212:        /*
                   2213:         * Check for encountering a symbolic link
                   2214:         */
1.43      fvdl     2215:        if ((cnp->cn_flags & ISSYMLINK) == 0) {
1.178     chs      2216:                if ((cnp->cn_flags & LOCKPARENT) == 0 && ndp->ni_dvp) {
                   2217:                        if (ndp->ni_dvp == ndp->ni_vp) {
                   2218:                                vrele(ndp->ni_dvp);
                   2219:                        } else {
                   2220:                                vput(ndp->ni_dvp);
                   2221:                        }
                   2222:                }
1.91      fvdl     2223:                if (cnp->cn_flags & (SAVENAME | SAVESTART))
1.43      fvdl     2224:                        cnp->cn_flags |= HASBUF;
1.91      fvdl     2225:                else
                   2226:                        PNBUF_PUT(cnp->cn_pnbuf);
                   2227:                return (0);
1.43      fvdl     2228:        } else {
                   2229:                if (!pubflag) {
                   2230:                        error = EINVAL;
                   2231:                        break;
                   2232:                }
                   2233:                if (ndp->ni_loopcnt++ >= MAXSYMLINKS) {
                   2234:                        error = ELOOP;
                   2235:                        break;
                   2236:                }
1.91      fvdl     2237:                if (ndp->ni_vp->v_mount->mnt_flag & MNT_SYMPERM) {
                   2238:                        error = VOP_ACCESS(ndp->ni_vp, VEXEC, cnp->cn_cred,
1.156     christos 2239:                            cnp->cn_lwp);
1.91      fvdl     2240:                        if (error != 0)
                   2241:                                break;
                   2242:                }
1.43      fvdl     2243:                if (ndp->ni_pathlen > 1)
1.81      thorpej  2244:                        cp = PNBUF_GET();
1.1       cgd      2245:                else
1.43      fvdl     2246:                        cp = cnp->cn_pnbuf;
                   2247:                aiov.iov_base = cp;
                   2248:                aiov.iov_len = MAXPATHLEN;
                   2249:                auio.uio_iov = &aiov;
                   2250:                auio.uio_iovcnt = 1;
                   2251:                auio.uio_offset = 0;
                   2252:                auio.uio_rw = UIO_READ;
                   2253:                auio.uio_resid = MAXPATHLEN;
1.158     yamt     2254:                UIO_SETUP_SYSSPACE(&auio);
1.43      fvdl     2255:                error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred);
                   2256:                if (error) {
1.178     chs      2257: badlink:
1.43      fvdl     2258:                        if (ndp->ni_pathlen > 1)
1.81      thorpej  2259:                                PNBUF_PUT(cp);
1.43      fvdl     2260:                        break;
                   2261:                }
                   2262:                linklen = MAXPATHLEN - auio.uio_resid;
                   2263:                if (linklen == 0) {
                   2264:                        error = ENOENT;
                   2265:                        goto badlink;
                   2266:                }
                   2267:                if (linklen + ndp->ni_pathlen >= MAXPATHLEN) {
                   2268:                        error = ENAMETOOLONG;
                   2269:                        goto badlink;
                   2270:                }
                   2271:                if (ndp->ni_pathlen > 1) {
1.63      perry    2272:                        memcpy(cp + linklen, ndp->ni_next, ndp->ni_pathlen);
1.81      thorpej  2273:                        PNBUF_PUT(cnp->cn_pnbuf);
1.43      fvdl     2274:                        cnp->cn_pnbuf = cp;
                   2275:                } else
                   2276:                        cnp->cn_pnbuf[linklen] = '\0';
                   2277:                ndp->ni_pathlen += linklen;
1.1       cgd      2278:                vput(ndp->ni_vp);
1.43      fvdl     2279:                dp = ndp->ni_dvp;
1.178     chs      2280:
1.43      fvdl     2281:                /*
                   2282:                 * Check if root directory should replace current directory.
                   2283:                 */
                   2284:                if (cnp->cn_pnbuf[0] == '/') {
1.178     chs      2285:                        vput(dp);
1.43      fvdl     2286:                        dp = ndp->ni_rootdir;
                   2287:                        VREF(dp);
1.178     chs      2288:                        vn_lock(dp, LK_EXCLUSIVE | LK_RETRY);
1.43      fvdl     2289:                }
1.1       cgd      2290:        }
1.43      fvdl     2291:    }
1.178     chs      2292:        vput(ndp->ni_dvp);
1.91      fvdl     2293:        vput(ndp->ni_vp);
                   2294:        ndp->ni_vp = NULL;
1.1       cgd      2295: out:
1.81      thorpej  2296:        PNBUF_PUT(cnp->cn_pnbuf);
1.1       cgd      2297:        return (error);
                   2298: }
1.153     jmmv     2299: #endif /* NFSSERVER */
1.1       cgd      2300:
                   2301: /*
1.118     yamt     2302:  * A fiddled version of m_adj() that ensures null fill to a 32-bit
1.1       cgd      2303:  * boundary and only trims off the back end
1.122     yamt     2304:  *
                   2305:  * 1. trim off 'len' bytes as m_adj(mp, -len).
                   2306:  * 2. add zero-padding 'nul' bytes at the end of the mbuf chain.
1.1       cgd      2307:  */
1.12      mycroft  2308: void
1.122     yamt     2309: nfs_zeropad(mp, len, nul)
1.1       cgd      2310:        struct mbuf *mp;
1.75      augustss 2311:        int len;
1.1       cgd      2312:        int nul;
                   2313: {
1.75      augustss 2314:        struct mbuf *m;
1.130     yamt     2315:        int count;
1.1       cgd      2316:
                   2317:        /*
                   2318:         * Trim from tail.  Scan the mbuf chain,
                   2319:         * calculating its length and finding the last mbuf.
                   2320:         * If the adjustment only affects this mbuf, then just
                   2321:         * adjust and return.  Otherwise, rescan and truncate
                   2322:         * after the remaining size.
                   2323:         */
                   2324:        count = 0;
                   2325:        m = mp;
                   2326:        for (;;) {
                   2327:                count += m->m_len;
1.122     yamt     2328:                if (m->m_next == NULL)
1.1       cgd      2329:                        break;
                   2330:                m = m->m_next;
                   2331:        }
1.122     yamt     2332:
                   2333:        KDASSERT(count >= len);
                   2334:
                   2335:        if (m->m_len >= len) {
1.1       cgd      2336:                m->m_len -= len;
1.122     yamt     2337:        } else {
                   2338:                count -= len;
                   2339:                /*
                   2340:                 * Correct length for chain is "count".
                   2341:                 * Find the mbuf with last data, adjust its length,
                   2342:                 * and toss data from remaining mbufs on chain.
                   2343:                 */
                   2344:                for (m = mp; m; m = m->m_next) {
                   2345:                        if (m->m_len >= count) {
                   2346:                                m->m_len = count;
                   2347:                                break;
1.118     yamt     2348:                        }
1.122     yamt     2349:                        count -= m->m_len;
1.1       cgd      2350:                }
1.159     christos 2351:                KASSERT(m && m->m_next);
1.122     yamt     2352:                m_freem(m->m_next);
                   2353:                m->m_next = NULL;
1.1       cgd      2354:        }
1.122     yamt     2355:
1.130     yamt     2356:        KDASSERT(m->m_next == NULL);
                   2357:
1.122     yamt     2358:        /*
                   2359:         * zero-padding.
                   2360:         */
                   2361:        if (nul > 0) {
1.130     yamt     2362:                char *cp;
                   2363:                int i;
                   2364:
1.122     yamt     2365:                if (M_ROMAP(m) || M_TRAILINGSPACE(m) < nul) {
                   2366:                        struct mbuf *n;
                   2367:
                   2368:                        KDASSERT(MLEN >= nul);
                   2369:                        n = m_get(M_WAIT, MT_DATA);
                   2370:                        MCLAIM(n, &nfs_mowner);
                   2371:                        n->m_len = nul;
1.130     yamt     2372:                        n->m_next = NULL;
1.122     yamt     2373:                        m->m_next = n;
1.183     christos 2374:                        cp = mtod(n, void *);
1.122     yamt     2375:                } else {
1.183     christos 2376:                        cp = mtod(m, char *) + m->m_len;
1.122     yamt     2377:                        m->m_len += nul;
1.1       cgd      2378:                }
1.122     yamt     2379:                for (i = 0; i < nul; i++)
                   2380:                        *cp++ = '\0';
1.1       cgd      2381:        }
1.122     yamt     2382:        return;
1.1       cgd      2383: }
                   2384:
                   2385: /*
1.25      fvdl     2386:  * Make these functions instead of macros, so that the kernel text size
                   2387:  * doesn't get too big...
                   2388:  */
                   2389: void
                   2390: nfsm_srvwcc(nfsd, before_ret, before_vap, after_ret, after_vap, mbp, bposp)
                   2391:        struct nfsrv_descript *nfsd;
                   2392:        int before_ret;
1.75      augustss 2393:        struct vattr *before_vap;
1.25      fvdl     2394:        int after_ret;
                   2395:        struct vattr *after_vap;
                   2396:        struct mbuf **mbp;
                   2397:        char **bposp;
                   2398: {
1.109     matt     2399:        struct mbuf *mb = *mbp;
1.75      augustss 2400:        char *bpos = *bposp;
                   2401:        u_int32_t *tl;
1.25      fvdl     2402:
                   2403:        if (before_ret) {
                   2404:                nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED);
                   2405:                *tl = nfs_false;
                   2406:        } else {
                   2407:                nfsm_build(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
                   2408:                *tl++ = nfs_true;
1.66      fair     2409:                txdr_hyper(before_vap->va_size, tl);
1.25      fvdl     2410:                tl += 2;
                   2411:                txdr_nfsv3time(&(before_vap->va_mtime), tl);
                   2412:                tl += 2;
                   2413:                txdr_nfsv3time(&(before_vap->va_ctime), tl);
                   2414:        }
                   2415:        *bposp = bpos;
                   2416:        *mbp = mb;
                   2417:        nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp);
                   2418: }
                   2419:
                   2420: void
                   2421: nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp)
                   2422:        struct nfsrv_descript *nfsd;
                   2423:        int after_ret;
                   2424:        struct vattr *after_vap;
                   2425:        struct mbuf **mbp;
                   2426:        char **bposp;
                   2427: {
1.109     matt     2428:        struct mbuf *mb = *mbp;
1.75      augustss 2429:        char *bpos = *bposp;
                   2430:        u_int32_t *tl;
                   2431:        struct nfs_fattr *fp;
1.25      fvdl     2432:
                   2433:        if (after_ret) {
                   2434:                nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED);
                   2435:                *tl = nfs_false;
                   2436:        } else {
                   2437:                nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_V3FATTR);
                   2438:                *tl++ = nfs_true;
                   2439:                fp = (struct nfs_fattr *)tl;
                   2440:                nfsm_srvfattr(nfsd, after_vap, fp);
                   2441:        }
                   2442:        *mbp = mb;
                   2443:        *bposp = bpos;
                   2444: }
                   2445:
                   2446: void
                   2447: nfsm_srvfattr(nfsd, vap, fp)
1.75      augustss 2448:        struct nfsrv_descript *nfsd;
                   2449:        struct vattr *vap;
                   2450:        struct nfs_fattr *fp;
1.25      fvdl     2451: {
                   2452:
                   2453:        fp->fa_nlink = txdr_unsigned(vap->va_nlink);
                   2454:        fp->fa_uid = txdr_unsigned(vap->va_uid);
                   2455:        fp->fa_gid = txdr_unsigned(vap->va_gid);
                   2456:        if (nfsd->nd_flag & ND_NFSV3) {
                   2457:                fp->fa_type = vtonfsv3_type(vap->va_type);
                   2458:                fp->fa_mode = vtonfsv3_mode(vap->va_mode);
1.66      fair     2459:                txdr_hyper(vap->va_size, &fp->fa3_size);
                   2460:                txdr_hyper(vap->va_bytes, &fp->fa3_used);
1.25      fvdl     2461:                fp->fa3_rdev.specdata1 = txdr_unsigned(major(vap->va_rdev));
                   2462:                fp->fa3_rdev.specdata2 = txdr_unsigned(minor(vap->va_rdev));
                   2463:                fp->fa3_fsid.nfsuquad[0] = 0;
                   2464:                fp->fa3_fsid.nfsuquad[1] = txdr_unsigned(vap->va_fsid);
1.151     yamt     2465:                txdr_hyper(vap->va_fileid, &fp->fa3_fileid);
1.25      fvdl     2466:                txdr_nfsv3time(&vap->va_atime, &fp->fa3_atime);
                   2467:                txdr_nfsv3time(&vap->va_mtime, &fp->fa3_mtime);
                   2468:                txdr_nfsv3time(&vap->va_ctime, &fp->fa3_ctime);
                   2469:        } else {
                   2470:                fp->fa_type = vtonfsv2_type(vap->va_type);
                   2471:                fp->fa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode);
                   2472:                fp->fa2_size = txdr_unsigned(vap->va_size);
                   2473:                fp->fa2_blocksize = txdr_unsigned(vap->va_blocksize);
                   2474:                if (vap->va_type == VFIFO)
                   2475:                        fp->fa2_rdev = 0xffffffff;
                   2476:                else
                   2477:                        fp->fa2_rdev = txdr_unsigned(vap->va_rdev);
                   2478:                fp->fa2_blocks = txdr_unsigned(vap->va_bytes / NFS_FABLKSIZE);
                   2479:                fp->fa2_fsid = txdr_unsigned(vap->va_fsid);
                   2480:                fp->fa2_fileid = txdr_unsigned(vap->va_fileid);
                   2481:                txdr_nfsv2time(&vap->va_atime, &fp->fa2_atime);
                   2482:                txdr_nfsv2time(&vap->va_mtime, &fp->fa2_mtime);
                   2483:                txdr_nfsv2time(&vap->va_ctime, &fp->fa2_ctime);
                   2484:        }
                   2485: }
                   2486:
1.153     jmmv     2487: #ifdef NFSSERVER
1.25      fvdl     2488: /*
1.1       cgd      2489:  * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked)
                   2490:  *     - look up fsid in mount list (if not found ret error)
1.12      mycroft  2491:  *     - get vp and export rights by calling VFS_FHTOVP()
                   2492:  *     - if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon
1.1       cgd      2493:  *     - if not lockflag unlock it with VOP_UNLOCK()
                   2494:  */
1.24      christos 2495: int
1.177     yamt     2496: nfsrv_fhtovp(nfsrvfh_t *nsfh, int lockflag, struct vnode **vpp,
                   2497:     kauth_cred_t cred, struct nfssvc_sock *slp, struct mbuf *nam, int *rdonlyp,
                   2498:     int kerbflag, int pubflag)
1.1       cgd      2499: {
1.75      augustss 2500:        struct mount *mp;
1.162     elad     2501:        kauth_cred_t credanon;
1.12      mycroft  2502:        int error, exflags;
1.40      fvdl     2503:        struct sockaddr_in *saddr;
1.168     yamt     2504:        fhandle_t *fhp;
1.1       cgd      2505:
1.168     yamt     2506:        fhp = NFSRVFH_FHANDLE(nsfh);
1.12      mycroft  2507:        *vpp = (struct vnode *)0;
1.43      fvdl     2508:
1.168     yamt     2509:        if (nfs_ispublicfh(nsfh)) {
1.43      fvdl     2510:                if (!pubflag || !nfs_pub.np_valid)
                   2511:                        return (ESTALE);
1.166     martin   2512:                fhp = nfs_pub.np_handle;
1.43      fvdl     2513:        }
                   2514:
1.154     yamt     2515:        error = netexport_check(&fhp->fh_fsid, nam, &mp, &exflags, &credanon);
                   2516:        if (error) {
                   2517:                return error;
                   2518:        }
                   2519:
1.124     thorpej  2520:        error = VFS_FHTOVP(mp, &fhp->fh_fid, vpp);
1.24      christos 2521:        if (error)
1.12      mycroft  2522:                return (error);
1.40      fvdl     2523:
1.43      fvdl     2524:        if (!(exflags & (MNT_EXNORESPORT|MNT_EXPUBLIC))) {
1.40      fvdl     2525:                saddr = mtod(nam, struct sockaddr_in *);
1.76      fvdl     2526:                if ((saddr->sin_family == AF_INET) &&
1.40      fvdl     2527:                    ntohs(saddr->sin_port) >= IPPORT_RESERVED) {
                   2528:                        vput(*vpp);
                   2529:                        return (NFSERR_AUTHERR | AUTH_TOOWEAK);
                   2530:                }
1.76      fvdl     2531: #ifdef INET6
                   2532:                if ((saddr->sin_family == AF_INET6) &&
                   2533:                    ntohs(saddr->sin_port) >= IPV6PORT_RESERVED) {
                   2534:                        vput(*vpp);
                   2535:                        return (NFSERR_AUTHERR | AUTH_TOOWEAK);
                   2536:                }
                   2537: #endif
1.40      fvdl     2538:        }
1.12      mycroft  2539:        /*
                   2540:         * Check/setup credentials.
                   2541:         */
                   2542:        if (exflags & MNT_EXKERB) {
1.25      fvdl     2543:                if (!kerbflag) {
1.12      mycroft  2544:                        vput(*vpp);
1.25      fvdl     2545:                        return (NFSERR_AUTHERR | AUTH_TOOWEAK);
1.12      mycroft  2546:                }
1.25      fvdl     2547:        } else if (kerbflag) {
                   2548:                vput(*vpp);
                   2549:                return (NFSERR_AUTHERR | AUTH_TOOWEAK);
1.162     elad     2550:        } else if (kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER,
                   2551:                    NULL) == 0 || (exflags & MNT_EXPORTANON)) {
                   2552:                kauth_cred_clone(credanon, cred);
1.12      mycroft  2553:        }
                   2554:        if (exflags & MNT_EXRDONLY)
                   2555:                *rdonlyp = 1;
                   2556:        else
                   2557:                *rdonlyp = 0;
1.1       cgd      2558:        if (!lockflag)
1.56      fvdl     2559:                VOP_UNLOCK(*vpp, 0);
1.1       cgd      2560:        return (0);
1.43      fvdl     2561: }
                   2562:
                   2563: /*
                   2564:  * WebNFS: check if a filehandle is a public filehandle. For v3, this
1.168     yamt     2565:  * means a length of 0, for v2 it means all zeroes.
1.43      fvdl     2566:  */
                   2567: int
1.168     yamt     2568: nfs_ispublicfh(const nfsrvfh_t *nsfh)
1.43      fvdl     2569: {
1.170     yamt     2570:        const char *cp = (const void *)(NFSRVFH_DATA(nsfh));
1.43      fvdl     2571:        int i;
                   2572:
1.168     yamt     2573:        if (NFSRVFH_SIZE(nsfh) == 0) {
1.182     thorpej  2574:                return true;
1.168     yamt     2575:        }
                   2576:        if (NFSRVFH_SIZE(nsfh) != NFSX_V2FH) {
1.182     thorpej  2577:                return false;
1.168     yamt     2578:        }
                   2579:        for (i = 0; i < NFSX_V2FH; i++)
1.43      fvdl     2580:                if (*cp++ != 0)
1.182     thorpej  2581:                        return false;
                   2582:        return true;
1.1       cgd      2583: }
1.153     jmmv     2584: #endif /* NFSSERVER */
1.1       cgd      2585:
                   2586: /*
1.182     thorpej  2587:  * This function compares two net addresses by family and returns true
1.12      mycroft  2588:  * if they are the same host.
1.182     thorpej  2589:  * If there is any doubt, return false.
1.12      mycroft  2590:  * The AF_INET family is handled as a special case so that address mbufs
                   2591:  * don't need to be saved to store "struct in_addr", which is only 4 bytes.
1.1       cgd      2592:  */
1.24      christos 2593: int
1.12      mycroft  2594: netaddr_match(family, haddr, nam)
                   2595:        int family;
                   2596:        union nethostaddr *haddr;
                   2597:        struct mbuf *nam;
1.1       cgd      2598: {
1.75      augustss 2599:        struct sockaddr_in *inetaddr;
1.1       cgd      2600:
1.12      mycroft  2601:        switch (family) {
                   2602:        case AF_INET:
                   2603:                inetaddr = mtod(nam, struct sockaddr_in *);
                   2604:                if (inetaddr->sin_family == AF_INET &&
                   2605:                    inetaddr->sin_addr.s_addr == haddr->had_inetaddr)
                   2606:                        return (1);
                   2607:                break;
1.76      fvdl     2608: #ifdef INET6
                   2609:        case AF_INET6:
                   2610:            {
                   2611:                struct sockaddr_in6 *sin6_1, *sin6_2;
                   2612:
                   2613:                sin6_1 = mtod(nam, struct sockaddr_in6 *);
                   2614:                sin6_2 = mtod(haddr->had_nam, struct sockaddr_in6 *);
                   2615:                if (sin6_1->sin6_family == AF_INET6 &&
                   2616:                    IN6_ARE_ADDR_EQUAL(&sin6_1->sin6_addr, &sin6_2->sin6_addr))
                   2617:                        return 1;
                   2618:            }
                   2619: #endif
1.12      mycroft  2620: #ifdef ISO
                   2621:        case AF_ISO:
                   2622:            {
1.75      augustss 2623:                struct sockaddr_iso *isoaddr1, *isoaddr2;
1.12      mycroft  2624:
                   2625:                isoaddr1 = mtod(nam, struct sockaddr_iso *);
                   2626:                isoaddr2 = mtod(haddr->had_nam, struct sockaddr_iso *);
                   2627:                if (isoaddr1->siso_family == AF_ISO &&
                   2628:                    isoaddr1->siso_nlen > 0 &&
                   2629:                    isoaddr1->siso_nlen == isoaddr2->siso_nlen &&
                   2630:                    SAME_ISOADDR(isoaddr1, isoaddr2))
                   2631:                        return (1);
                   2632:                break;
                   2633:            }
                   2634: #endif /* ISO */
                   2635:        default:
                   2636:                break;
                   2637:        };
                   2638:        return (0);
1.25      fvdl     2639: }
                   2640:
                   2641: /*
                   2642:  * The write verifier has changed (probably due to a server reboot), so all
1.114     yamt     2643:  * PG_NEEDCOMMIT pages will have to be written again. Since they are marked
1.117     yamt     2644:  * as dirty or are being written out just now, all this takes is clearing
                   2645:  * the PG_NEEDCOMMIT flag. Once done the new write verifier can be set for
                   2646:  * the mount point.
1.25      fvdl     2647:  */
                   2648: void
                   2649: nfs_clearcommit(mp)
                   2650:        struct mount *mp;
                   2651: {
1.89      chs      2652:        struct vnode *vp;
1.83      fvdl     2653:        struct nfsnode *np;
1.89      chs      2654:        struct vm_page *pg;
1.116     yamt     2655:        struct nfsmount *nmp = VFSTONFS(mp);
                   2656:
1.180     yamt     2657:        rw_enter(&nmp->nm_writeverflock, RW_WRITER);
1.25      fvdl     2658:
1.176     reinoud  2659:        TAILQ_FOREACH(vp, &mp->mnt_vnodelist, v_mntvnodes) {
1.89      chs      2660:                KASSERT(vp->v_mount == mp);
1.146     yamt     2661:                if (vp->v_type != VREG)
1.85      enami    2662:                        continue;
1.83      fvdl     2663:                np = VTONFS(vp);
                   2664:                np->n_pushlo = np->n_pushhi = np->n_pushedlo =
                   2665:                    np->n_pushedhi = 0;
                   2666:                np->n_commitflags &=
                   2667:                    ~(NFS_COMMIT_PUSH_VALID | NFS_COMMIT_PUSHED_VALID);
1.184.2.1! ad       2668:                mutex_enter(&vp->v_uobj.vmobjlock);
1.97      chs      2669:                TAILQ_FOREACH(pg, &vp->v_uobj.memq, listq) {
1.89      chs      2670:                        pg->flags &= ~PG_NEEDCOMMIT;
1.25      fvdl     2671:                }
1.184.2.1! ad       2672:                mutex_exit(&vp->v_uobj.vmobjlock);
1.25      fvdl     2673:        }
1.184.2.1! ad       2674:        mutex_enter(&nmp->nm_lock);
1.116     yamt     2675:        nmp->nm_iflag &= ~NFSMNT_STALEWRITEVERF;
1.184.2.1! ad       2676:        mutex_exit(&nmp->nm_lock);
1.180     yamt     2677:        rw_exit(&nmp->nm_writeverflock);
1.83      fvdl     2678: }
                   2679:
                   2680: void
                   2681: nfs_merge_commit_ranges(vp)
                   2682:        struct vnode *vp;
                   2683: {
                   2684:        struct nfsnode *np = VTONFS(vp);
1.112     yamt     2685:
                   2686:        KASSERT(np->n_commitflags & NFS_COMMIT_PUSH_VALID);
1.83      fvdl     2687:
                   2688:        if (!(np->n_commitflags & NFS_COMMIT_PUSHED_VALID)) {
                   2689:                np->n_pushedlo = np->n_pushlo;
                   2690:                np->n_pushedhi = np->n_pushhi;
                   2691:                np->n_commitflags |= NFS_COMMIT_PUSHED_VALID;
                   2692:        } else {
                   2693:                if (np->n_pushlo < np->n_pushedlo)
                   2694:                        np->n_pushedlo = np->n_pushlo;
                   2695:                if (np->n_pushhi > np->n_pushedhi)
                   2696:                        np->n_pushedhi = np->n_pushhi;
                   2697:        }
                   2698:
                   2699:        np->n_pushlo = np->n_pushhi = 0;
                   2700:        np->n_commitflags &= ~NFS_COMMIT_PUSH_VALID;
                   2701:
1.111     yamt     2702: #ifdef NFS_DEBUG_COMMIT
1.83      fvdl     2703:        printf("merge: committed: %u - %u\n", (unsigned)np->n_pushedlo,
                   2704:            (unsigned)np->n_pushedhi);
                   2705: #endif
                   2706: }
                   2707:
                   2708: int
1.89      chs      2709: nfs_in_committed_range(vp, off, len)
1.83      fvdl     2710:        struct vnode *vp;
1.89      chs      2711:        off_t off, len;
1.83      fvdl     2712: {
                   2713:        struct nfsnode *np = VTONFS(vp);
                   2714:        off_t lo, hi;
                   2715:
                   2716:        if (!(np->n_commitflags & NFS_COMMIT_PUSHED_VALID))
                   2717:                return 0;
1.89      chs      2718:        lo = off;
                   2719:        hi = lo + len;
1.83      fvdl     2720:
                   2721:        return (lo >= np->n_pushedlo && hi <= np->n_pushedhi);
                   2722: }
                   2723:
                   2724: int
1.89      chs      2725: nfs_in_tobecommitted_range(vp, off, len)
1.83      fvdl     2726:        struct vnode *vp;
1.89      chs      2727:        off_t off, len;
1.83      fvdl     2728: {
                   2729:        struct nfsnode *np = VTONFS(vp);
                   2730:        off_t lo, hi;
                   2731:
                   2732:        if (!(np->n_commitflags & NFS_COMMIT_PUSH_VALID))
                   2733:                return 0;
1.89      chs      2734:        lo = off;
                   2735:        hi = lo + len;
1.83      fvdl     2736:
                   2737:        return (lo >= np->n_pushlo && hi <= np->n_pushhi);
                   2738: }
                   2739:
                   2740: void
1.89      chs      2741: nfs_add_committed_range(vp, off, len)
1.83      fvdl     2742:        struct vnode *vp;
1.89      chs      2743:        off_t off, len;
1.83      fvdl     2744: {
                   2745:        struct nfsnode *np = VTONFS(vp);
                   2746:        off_t lo, hi;
                   2747:
1.89      chs      2748:        lo = off;
                   2749:        hi = lo + len;
1.83      fvdl     2750:
                   2751:        if (!(np->n_commitflags & NFS_COMMIT_PUSHED_VALID)) {
                   2752:                np->n_pushedlo = lo;
                   2753:                np->n_pushedhi = hi;
                   2754:                np->n_commitflags |= NFS_COMMIT_PUSHED_VALID;
                   2755:        } else {
                   2756:                if (hi > np->n_pushedhi)
                   2757:                        np->n_pushedhi = hi;
                   2758:                if (lo < np->n_pushedlo)
                   2759:                        np->n_pushedlo = lo;
                   2760:        }
1.111     yamt     2761: #ifdef NFS_DEBUG_COMMIT
1.83      fvdl     2762:        printf("add: committed: %u - %u\n", (unsigned)np->n_pushedlo,
                   2763:            (unsigned)np->n_pushedhi);
                   2764: #endif
                   2765: }
                   2766:
                   2767: void
1.89      chs      2768: nfs_del_committed_range(vp, off, len)
1.83      fvdl     2769:        struct vnode *vp;
1.89      chs      2770:        off_t off, len;
1.83      fvdl     2771: {
                   2772:        struct nfsnode *np = VTONFS(vp);
                   2773:        off_t lo, hi;
                   2774:
                   2775:        if (!(np->n_commitflags & NFS_COMMIT_PUSHED_VALID))
                   2776:                return;
                   2777:
1.89      chs      2778:        lo = off;
                   2779:        hi = lo + len;
1.83      fvdl     2780:
                   2781:        if (lo > np->n_pushedhi || hi < np->n_pushedlo)
                   2782:                return;
                   2783:        if (lo <= np->n_pushedlo)
                   2784:                np->n_pushedlo = hi;
                   2785:        else if (hi >= np->n_pushedhi)
                   2786:                np->n_pushedhi = lo;
                   2787:        else {
                   2788:                /*
                   2789:                 * XXX There's only one range. If the deleted range
                   2790:                 * is in the middle, pick the largest of the
                   2791:                 * contiguous ranges that it leaves.
                   2792:                 */
                   2793:                if ((np->n_pushedlo - lo) > (hi - np->n_pushedhi))
                   2794:                        np->n_pushedhi = lo;
                   2795:                else
                   2796:                        np->n_pushedlo = hi;
                   2797:        }
1.111     yamt     2798: #ifdef NFS_DEBUG_COMMIT
1.83      fvdl     2799:        printf("del: committed: %u - %u\n", (unsigned)np->n_pushedlo,
                   2800:            (unsigned)np->n_pushedhi);
                   2801: #endif
                   2802: }
                   2803:
                   2804: void
1.89      chs      2805: nfs_add_tobecommitted_range(vp, off, len)
1.83      fvdl     2806:        struct vnode *vp;
1.89      chs      2807:        off_t off, len;
1.83      fvdl     2808: {
                   2809:        struct nfsnode *np = VTONFS(vp);
                   2810:        off_t lo, hi;
                   2811:
1.89      chs      2812:        lo = off;
                   2813:        hi = lo + len;
1.83      fvdl     2814:
                   2815:        if (!(np->n_commitflags & NFS_COMMIT_PUSH_VALID)) {
                   2816:                np->n_pushlo = lo;
                   2817:                np->n_pushhi = hi;
                   2818:                np->n_commitflags |= NFS_COMMIT_PUSH_VALID;
                   2819:        } else {
                   2820:                if (lo < np->n_pushlo)
                   2821:                        np->n_pushlo = lo;
                   2822:                if (hi > np->n_pushhi)
                   2823:                        np->n_pushhi = hi;
                   2824:        }
1.111     yamt     2825: #ifdef NFS_DEBUG_COMMIT
1.83      fvdl     2826:        printf("add: tobecommitted: %u - %u\n", (unsigned)np->n_pushlo,
                   2827:            (unsigned)np->n_pushhi);
                   2828: #endif
                   2829: }
                   2830:
                   2831: void
1.89      chs      2832: nfs_del_tobecommitted_range(vp, off, len)
1.83      fvdl     2833:        struct vnode *vp;
1.89      chs      2834:        off_t off, len;
1.83      fvdl     2835: {
                   2836:        struct nfsnode *np = VTONFS(vp);
                   2837:        off_t lo, hi;
                   2838:
                   2839:        if (!(np->n_commitflags & NFS_COMMIT_PUSH_VALID))
                   2840:                return;
                   2841:
1.89      chs      2842:        lo = off;
                   2843:        hi = lo + len;
1.83      fvdl     2844:
                   2845:        if (lo > np->n_pushhi || hi < np->n_pushlo)
                   2846:                return;
                   2847:
                   2848:        if (lo <= np->n_pushlo)
                   2849:                np->n_pushlo = hi;
                   2850:        else if (hi >= np->n_pushhi)
                   2851:                np->n_pushhi = lo;
                   2852:        else {
                   2853:                /*
                   2854:                 * XXX There's only one range. If the deleted range
                   2855:                 * is in the middle, pick the largest of the
                   2856:                 * contiguous ranges that it leaves.
                   2857:                 */
                   2858:                if ((np->n_pushlo - lo) > (hi - np->n_pushhi))
                   2859:                        np->n_pushhi = lo;
                   2860:                else
                   2861:                        np->n_pushlo = hi;
                   2862:        }
1.111     yamt     2863: #ifdef NFS_DEBUG_COMMIT
1.83      fvdl     2864:        printf("del: tobecommitted: %u - %u\n", (unsigned)np->n_pushlo,
                   2865:            (unsigned)np->n_pushhi);
                   2866: #endif
1.25      fvdl     2867: }
                   2868:
                   2869: /*
                   2870:  * Map errnos to NFS error numbers. For Version 3 also filter out error
                   2871:  * numbers not specified for the associated procedure.
                   2872:  */
                   2873: int
                   2874: nfsrv_errmap(nd, err)
                   2875:        struct nfsrv_descript *nd;
1.75      augustss 2876:        int err;
1.25      fvdl     2877: {
1.90      jdolecek 2878:        const short *defaulterrp, *errp;
1.25      fvdl     2879:
                   2880:        if (nd->nd_flag & ND_NFSV3) {
                   2881:            if (nd->nd_procnum <= NFSPROC_COMMIT) {
                   2882:                errp = defaulterrp = nfsrv_v3errmap[nd->nd_procnum];
                   2883:                while (*++errp) {
                   2884:                        if (*errp == err)
                   2885:                                return (err);
                   2886:                        else if (*errp > err)
                   2887:                                break;
                   2888:                }
                   2889:                return ((int)*defaulterrp);
                   2890:            } else
                   2891:                return (err & 0xffff);
                   2892:        }
                   2893:        if (err <= ELAST)
                   2894:                return ((int)nfsrv_v2errmap[err - 1]);
                   2895:        return (NFSERR_IO);
                   2896: }
                   2897:
1.126     yamt     2898: u_int32_t
                   2899: nfs_getxid()
                   2900: {
                   2901:        static u_int32_t base;
                   2902:        static u_int32_t nfs_xid = 0;
                   2903:        static struct simplelock nfs_xidlock = SIMPLELOCK_INITIALIZER;
                   2904:        u_int32_t newxid;
                   2905:
                   2906:        simple_lock(&nfs_xidlock);
                   2907:        /*
                   2908:         * derive initial xid from system time
                   2909:         * XXX time is invalid if root not yet mounted
                   2910:         */
                   2911:        if (__predict_false(!base && (rootvp))) {
                   2912:                struct timeval tv;
                   2913:
                   2914:                microtime(&tv);
                   2915:                base = tv.tv_sec << 12;
                   2916:                nfs_xid = base;
                   2917:        }
                   2918:
                   2919:        /*
                   2920:         * Skip zero xid if it should ever happen.
                   2921:         */
                   2922:        if (__predict_false(++nfs_xid == 0))
                   2923:                nfs_xid++;
                   2924:        newxid = nfs_xid;
                   2925:        simple_unlock(&nfs_xidlock);
                   2926:
                   2927:        return txdr_unsigned(newxid);
                   2928: }
                   2929:
                   2930: /*
                   2931:  * assign a new xid for existing request.
                   2932:  * used for NFSERR_JUKEBOX handling.
                   2933:  */
                   2934: void
                   2935: nfs_renewxid(struct nfsreq *req)
                   2936: {
                   2937:        u_int32_t xid;
                   2938:        int off;
                   2939:
                   2940:        xid = nfs_getxid();
                   2941:        if (req->r_nmp->nm_sotype == SOCK_STREAM)
                   2942:                off = sizeof(u_int32_t); /* RPC record mark */
                   2943:        else
                   2944:                off = 0;
                   2945:
                   2946:        m_copyback(req->r_mreq, off, sizeof(xid), (void *)&xid);
                   2947:        req->r_xid = xid;
1.1       cgd      2948: }
1.168     yamt     2949:
                   2950: #if defined(NFSSERVER)
                   2951: int
1.181     thorpej  2952: nfsrv_composefh(struct vnode *vp, nfsrvfh_t *nsfh, bool v3)
1.168     yamt     2953: {
                   2954:        int error;
                   2955:        size_t fhsize;
                   2956:
                   2957:        fhsize = NFSD_MAXFHSIZE;
1.169     yamt     2958:        error = vfs_composefh(vp, (void *)NFSRVFH_DATA(nsfh), &fhsize);
1.168     yamt     2959:        if (NFSX_FHTOOBIG_P(fhsize, v3)) {
                   2960:                error = EOPNOTSUPP;
                   2961:        }
                   2962:        if (error != 0) {
                   2963:                return error;
                   2964:        }
                   2965:        if (!v3 && fhsize < NFSX_V2FH) {
                   2966:                memset((char *)NFSRVFH_DATA(nsfh) + fhsize, 0,
                   2967:                    NFSX_V2FH - fhsize);
                   2968:                fhsize = NFSX_V2FH;
                   2969:        }
                   2970:        if ((fhsize % NFSX_UNSIGNED) != 0) {
                   2971:                return EOPNOTSUPP;
                   2972:        }
                   2973:        nsfh->nsfh_size = fhsize;
                   2974:        return 0;
                   2975: }
                   2976:
                   2977: int
                   2978: nfsrv_comparefh(const nfsrvfh_t *fh1, const nfsrvfh_t *fh2)
                   2979: {
                   2980:
                   2981:        if (NFSRVFH_SIZE(fh1) != NFSRVFH_SIZE(fh2)) {
                   2982:                return NFSRVFH_SIZE(fh2) - NFSRVFH_SIZE(fh1);
                   2983:        }
                   2984:        return memcmp(NFSRVFH_DATA(fh1), NFSRVFH_DATA(fh2), NFSRVFH_SIZE(fh1));
                   2985: }
                   2986:
                   2987: void
                   2988: nfsrv_copyfh(nfsrvfh_t *fh1, const nfsrvfh_t *fh2)
                   2989: {
                   2990:        size_t size;
                   2991:
                   2992:        fh1->nsfh_size = size = NFSRVFH_SIZE(fh2);
                   2993:        memcpy(NFSRVFH_DATA(fh1), NFSRVFH_DATA(fh2), size);
                   2994: }
                   2995: #endif /* defined(NFSSERVER) */

CVSweb <webmaster@jp.NetBSD.org>