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

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

CVSweb <webmaster@jp.NetBSD.org>