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

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

CVSweb <webmaster@jp.NetBSD.org>