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

1.105   ! yamt        1: /*     $NetBSD: nfs_subs.c,v 1.104 2002/08/23 05:38:51 enami Exp $     */
1.14      cgd         2:
1.1       cgd         3: /*
1.12      mycroft     4:  * Copyright (c) 1989, 1993
                      5:  *     The Regents of the University of California.  All rights reserved.
1.1       cgd         6:  *
                      7:  * This code is derived from software contributed to Berkeley by
                      8:  * Rick Macklem at The University of Guelph.
                      9:  *
                     10:  * Redistribution and use in source and binary forms, with or without
                     11:  * modification, are permitted provided that the following conditions
                     12:  * are met:
                     13:  * 1. Redistributions of source code must retain the above copyright
                     14:  *    notice, this list of conditions and the following disclaimer.
                     15:  * 2. Redistributions in binary form must reproduce the above copyright
                     16:  *    notice, this list of conditions and the following disclaimer in the
                     17:  *    documentation and/or other materials provided with the distribution.
                     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.99      lukem      75:
                     76: #include <sys/cdefs.h>
1.105   ! yamt       77: __KERNEL_RCSID(0, "$NetBSD: nfs_subs.c,v 1.104 2002/08/23 05:38:51 enami Exp $");
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.98      fvdl      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.100     chs       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.95      lukem     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.95      lukem     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;
1.102     jdolecek 1307:        int en;
1.46      fvdl     1308:        daddr_t blkno;
                   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.103     christos 1482:
                   1483:        exithook_establish(nfs_exit, NULL);
1.12      mycroft  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: {
1.96      chs      1499:        nfs_nhinit();                   /* Init the nfsnode table */
1.100     chs      1500:        nfs_commitsize = uvmexp.npages << (PAGE_SHIFT - 4);
1.96      chs      1501: }
1.35      thorpej  1502:
1.96      chs      1503: void
                   1504: nfs_vfs_reinit()
                   1505: {
                   1506:        nfs_nhreinit();
1.73      jdolecek 1507: }
                   1508:
                   1509: void
                   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.105   ! yamt     1530: nfsm_loadattrcache(vpp, mdp, dposp, vaper, flags)
1.12      mycroft  1531:        struct vnode **vpp;
                   1532:        struct mbuf **mdp;
                   1533:        caddr_t *dposp;
                   1534:        struct vattr *vaper;
1.105   ! yamt     1535:        int flags;
1.1       cgd      1536: {
1.75      augustss 1537:        int32_t t1;
1.25      fvdl     1538:        caddr_t cp2;
                   1539:        int error = 0;
1.12      mycroft  1540:        struct mbuf *md;
1.45      fvdl     1541:        int v3 = NFS_ISV3(*vpp);
1.1       cgd      1542:
1.12      mycroft  1543:        md = *mdp;
1.25      fvdl     1544:        t1 = (mtod(md, caddr_t) + md->m_len) - *dposp;
                   1545:        error = nfsm_disct(mdp, dposp, NFSX_FATTR(v3), t1, &cp2);
1.24      christos 1546:        if (error)
1.12      mycroft  1547:                return (error);
1.105   ! yamt     1548:        return nfs_loadattrcache(vpp, (struct nfs_fattr *)cp2, vaper, flags);
1.45      fvdl     1549: }
                   1550:
                   1551: int
1.105   ! yamt     1552: nfs_loadattrcache(vpp, fp, vaper, flags)
1.45      fvdl     1553:        struct vnode **vpp;
                   1554:        struct nfs_fattr *fp;
                   1555:        struct vattr *vaper;
1.105   ! yamt     1556:        int flags;
1.45      fvdl     1557: {
1.75      augustss 1558:        struct vnode *vp = *vpp;
                   1559:        struct vattr *vap;
1.45      fvdl     1560:        int v3 = NFS_ISV3(vp);
                   1561:        enum vtype vtyp;
                   1562:        u_short vmode;
                   1563:        struct timespec mtime;
                   1564:        struct vnode *nvp;
                   1565:        int32_t rdev;
1.75      augustss 1566:        struct nfsnode *np;
1.45      fvdl     1567:        extern int (**spec_nfsv2nodeop_p) __P((void *));
1.101     fvdl     1568:        uid_t uid;
                   1569:        gid_t gid;
1.45      fvdl     1570:
1.25      fvdl     1571:        if (v3) {
                   1572:                vtyp = nfsv3tov_type(fp->fa_type);
                   1573:                vmode = fxdr_unsigned(u_short, fp->fa_mode);
1.71      is       1574:                rdev = makedev(fxdr_unsigned(u_int32_t, fp->fa3_rdev.specdata1),
                   1575:                        fxdr_unsigned(u_int32_t, fp->fa3_rdev.specdata2));
1.25      fvdl     1576:                fxdr_nfsv3time(&fp->fa3_mtime, &mtime);
1.12      mycroft  1577:        } else {
1.25      fvdl     1578:                vtyp = nfsv2tov_type(fp->fa_type);
                   1579:                vmode = fxdr_unsigned(u_short, fp->fa_mode);
                   1580:                if (vtyp == VNON || vtyp == VREG)
                   1581:                        vtyp = IFTOVT(vmode);
                   1582:                rdev = fxdr_unsigned(int32_t, fp->fa2_rdev);
                   1583:                fxdr_nfsv2time(&fp->fa2_mtime, &mtime);
                   1584:
                   1585:                /*
                   1586:                 * Really ugly NFSv2 kludge.
                   1587:                 */
                   1588:                if (vtyp == VCHR && rdev == 0xffffffff)
                   1589:                        vtyp = VFIFO;
1.12      mycroft  1590:        }
1.25      fvdl     1591:
1.101     fvdl     1592:        vmode &= ALLPERMS;
                   1593:
1.12      mycroft  1594:        /*
                   1595:         * If v_type == VNON it is a new node, so fill in the v_type,
                   1596:         * n_mtime fields. Check to see if it represents a special
                   1597:         * device, and if so, check for a possible alias. Once the
                   1598:         * correct vnode has been obtained, fill in the rest of the
                   1599:         * information.
                   1600:         */
                   1601:        np = VTONFS(vp);
1.87      fvdl     1602:        if (vp->v_type == VNON) {
1.25      fvdl     1603:                vp->v_type = vtyp;
1.12      mycroft  1604:                if (vp->v_type == VFIFO) {
1.24      christos 1605:                        extern int (**fifo_nfsv2nodeop_p) __P((void *));
1.12      mycroft  1606:                        vp->v_op = fifo_nfsv2nodeop_p;
                   1607:                }
                   1608:                if (vp->v_type == VCHR || vp->v_type == VBLK) {
                   1609:                        vp->v_op = spec_nfsv2nodeop_p;
1.24      christos 1610:                        nvp = checkalias(vp, (dev_t)rdev, vp->v_mount);
                   1611:                        if (nvp) {
1.12      mycroft  1612:                                /*
                   1613:                                 * Discard unneeded vnode, but save its nfsnode.
1.25      fvdl     1614:                                 * Since the nfsnode does not have a lock, its
                   1615:                                 * vnode lock has to be carried over.
1.12      mycroft  1616:                                 */
1.94      bjh21    1617:                                /*
                   1618:                                 * XXX is the old node sure to be locked here?
                   1619:                                 */
                   1620:                                KASSERT(lockstatus(&vp->v_lock) ==
                   1621:                                    LK_EXCLUSIVE);
1.12      mycroft  1622:                                nvp->v_data = vp->v_data;
                   1623:                                vp->v_data = NULL;
1.93      fvdl     1624:                                VOP_UNLOCK(vp, 0);
1.12      mycroft  1625:                                vp->v_op = spec_vnodeop_p;
1.93      fvdl     1626:                                vrele(vp);
1.12      mycroft  1627:                                vgone(vp);
1.94      bjh21    1628:                                lockmgr(&nvp->v_lock, LK_EXCLUSIVE,
                   1629:                                    &nvp->v_interlock);
1.12      mycroft  1630:                                /*
                   1631:                                 * Reinitialize aliased node.
                   1632:                                 */
                   1633:                                np->n_vnode = nvp;
                   1634:                                *vpp = vp = nvp;
                   1635:                        }
                   1636:                }
1.23      jtc      1637:                np->n_mtime = mtime.tv_sec;
1.12      mycroft  1638:        }
1.101     fvdl     1639:        uid = fxdr_unsigned(uid_t, fp->fa_uid);
                   1640:        gid = fxdr_unsigned(gid_t, fp->fa_gid);
1.49      fvdl     1641:        vap = np->n_vattr;
1.101     fvdl     1642:
                   1643:        /*
                   1644:         * Invalidate access cache if uid, gid or mode changed.
                   1645:         */
                   1646:        if (np->n_accstamp != -1 &&
                   1647:            (gid != vap->va_gid || uid != vap->va_uid || vmode != vap->va_mode))
                   1648:                np->n_accstamp = -1;
                   1649:
1.12      mycroft  1650:        vap->va_type = vtyp;
1.101     fvdl     1651:        vap->va_mode = vmode;
1.12      mycroft  1652:        vap->va_rdev = (dev_t)rdev;
                   1653:        vap->va_mtime = mtime;
                   1654:        vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0];
1.72      fvdl     1655:        switch (vtyp) {
                   1656:        case VDIR:
                   1657:                vap->va_blocksize = NFS_DIRFRAGSIZ;
                   1658:                break;
                   1659:        case VBLK:
                   1660:                vap->va_blocksize = BLKDEV_IOSIZE;
                   1661:                break;
                   1662:        case VCHR:
                   1663:                vap->va_blocksize = MAXBSIZE;
                   1664:                break;
                   1665:        default:
                   1666:                vap->va_blocksize = v3 ? vp->v_mount->mnt_stat.f_iosize :
                   1667:                    fxdr_unsigned(int32_t, fp->fa2_blocksize);
                   1668:                break;
                   1669:        }
1.25      fvdl     1670:        if (v3) {
                   1671:                vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink);
1.101     fvdl     1672:                vap->va_uid = uid;
                   1673:                vap->va_gid = gid;
1.66      fair     1674:                vap->va_size = fxdr_hyper(&fp->fa3_size);
                   1675:                vap->va_bytes = fxdr_hyper(&fp->fa3_used);
1.25      fvdl     1676:                vap->va_fileid = fxdr_unsigned(int32_t,
                   1677:                    fp->fa3_fileid.nfsuquad[1]);
                   1678:                fxdr_nfsv3time(&fp->fa3_atime, &vap->va_atime);
                   1679:                fxdr_nfsv3time(&fp->fa3_ctime, &vap->va_ctime);
                   1680:                vap->va_flags = 0;
                   1681:                vap->va_filerev = 0;
1.12      mycroft  1682:        } else {
1.25      fvdl     1683:                vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink);
1.101     fvdl     1684:                vap->va_uid = uid;
                   1685:                vap->va_gid = gid;
1.25      fvdl     1686:                vap->va_size = fxdr_unsigned(u_int32_t, fp->fa2_size);
                   1687:                vap->va_bytes = fxdr_unsigned(int32_t, fp->fa2_blocks)
                   1688:                    * NFS_FABLKSIZE;
                   1689:                vap->va_fileid = fxdr_unsigned(int32_t, fp->fa2_fileid);
                   1690:                fxdr_nfsv2time(&fp->fa2_atime, &vap->va_atime);
1.12      mycroft  1691:                vap->va_flags = 0;
1.25      fvdl     1692:                vap->va_ctime.tv_sec = fxdr_unsigned(u_int32_t,
                   1693:                    fp->fa2_ctime.nfsv2_sec);
                   1694:                vap->va_ctime.tv_nsec = 0;
                   1695:                vap->va_gen = fxdr_unsigned(u_int32_t,fp->fa2_ctime.nfsv2_usec);
1.12      mycroft  1696:                vap->va_filerev = 0;
                   1697:        }
                   1698:        if (vap->va_size != np->n_size) {
1.89      chs      1699:                if ((np->n_flag & NMODIFIED) && vap->va_size < np->n_size) {
                   1700:                        vap->va_size = np->n_size;
                   1701:                } else {
1.12      mycroft  1702:                        np->n_size = vap->va_size;
1.89      chs      1703:                        if (vap->va_type == VREG) {
1.105   ! yamt     1704:                                if ((flags & NAC_NOTRUNC)
        !          1705:                                    && np->n_size < vp->v_size) {
        !          1706:                                        /*
        !          1707:                                         * we can't free pages now because
        !          1708:                                         * the pages can be owned by ourselves.
        !          1709:                                         */
        !          1710:                                        np->n_flag |= NTRUNCDELAYED;
        !          1711:                                }
        !          1712:                                else {
        !          1713:                                        uvm_vnp_setsize(vp, np->n_size);
        !          1714:                                }
1.89      chs      1715:                        }
                   1716:                }
1.12      mycroft  1717:        }
                   1718:        np->n_attrstamp = time.tv_sec;
                   1719:        if (vaper != NULL) {
1.63      perry    1720:                memcpy((caddr_t)vaper, (caddr_t)vap, sizeof(*vap));
1.12      mycroft  1721:                if (np->n_flag & NCHG) {
1.25      fvdl     1722:                        if (np->n_flag & NACC)
                   1723:                                vaper->va_atime = np->n_atim;
                   1724:                        if (np->n_flag & NUPD)
                   1725:                                vaper->va_mtime = np->n_mtim;
1.12      mycroft  1726:                }
                   1727:        }
                   1728:        return (0);
                   1729: }
                   1730:
                   1731: /*
                   1732:  * Check the time stamp
                   1733:  * If the cache is valid, copy contents to *vap and return 0
                   1734:  * otherwise return an error
                   1735:  */
1.24      christos 1736: int
1.12      mycroft  1737: nfs_getattrcache(vp, vaper)
1.75      augustss 1738:        struct vnode *vp;
1.12      mycroft  1739:        struct vattr *vaper;
                   1740: {
1.75      augustss 1741:        struct nfsnode *np = VTONFS(vp);
                   1742:        struct vattr *vap;
1.12      mycroft  1743:
1.25      fvdl     1744:        if ((time.tv_sec - np->n_attrstamp) >= NFS_ATTRTIMEO(np)) {
1.12      mycroft  1745:                nfsstats.attrcache_misses++;
                   1746:                return (ENOENT);
                   1747:        }
                   1748:        nfsstats.attrcache_hits++;
1.49      fvdl     1749:        vap = np->n_vattr;
1.12      mycroft  1750:        if (vap->va_size != np->n_size) {
                   1751:                if (vap->va_type == VREG) {
                   1752:                        if (np->n_flag & NMODIFIED) {
                   1753:                                if (vap->va_size < np->n_size)
                   1754:                                        vap->va_size = np->n_size;
                   1755:                                else
                   1756:                                        np->n_size = vap->va_size;
                   1757:                        } else
                   1758:                                np->n_size = vap->va_size;
1.51      mrg      1759:                        uvm_vnp_setsize(vp, np->n_size);
1.12      mycroft  1760:                } else
                   1761:                        np->n_size = vap->va_size;
                   1762:        }
1.63      perry    1763:        memcpy((caddr_t)vaper, (caddr_t)vap, sizeof(struct vattr));
1.12      mycroft  1764:        if (np->n_flag & NCHG) {
1.25      fvdl     1765:                if (np->n_flag & NACC)
                   1766:                        vaper->va_atime = np->n_atim;
                   1767:                if (np->n_flag & NUPD)
                   1768:                        vaper->va_mtime = np->n_mtim;
1.1       cgd      1769:        }
1.12      mycroft  1770:        return (0);
1.105   ! yamt     1771: }
        !          1772:
        !          1773: void
        !          1774: nfs_delayedtruncate(vp)
        !          1775:        struct vnode *vp;
        !          1776: {
        !          1777:        struct nfsnode *np = VTONFS(vp);
        !          1778:
        !          1779:        if (np->n_flag & NTRUNCDELAYED) {
        !          1780:                np->n_flag &= ~NTRUNCDELAYED;
        !          1781:                uvm_vnp_setsize(vp, np->n_size);
        !          1782:        }
1.1       cgd      1783: }
1.48      fvdl     1784:
                   1785: /*
                   1786:  * Heuristic to see if the server XDR encodes directory cookies or not.
                   1787:  * it is not supposed to, but a lot of servers may do this. Also, since
                   1788:  * most/all servers will implement V2 as well, it is expected that they
                   1789:  * may return just 32 bits worth of cookie information, so we need to
                   1790:  * find out in which 32 bits this information is available. We do this
                   1791:  * to avoid trouble with emulated binaries that can't handle 64 bit
                   1792:  * directory offsets.
                   1793:  */
                   1794:
                   1795: void
                   1796: nfs_cookieheuristic(vp, flagp, p, cred)
                   1797:        struct vnode *vp;
                   1798:        int *flagp;
                   1799:        struct proc *p;
                   1800:        struct ucred *cred;
                   1801: {
                   1802:        struct uio auio;
                   1803:        struct iovec aiov;
                   1804:        caddr_t buf, cp;
                   1805:        struct dirent *dp;
1.57      fvdl     1806:        off_t *cookies = NULL, *cop;
1.48      fvdl     1807:        int error, eof, nc, len;
                   1808:
                   1809:        MALLOC(buf, caddr_t, NFS_DIRFRAGSIZ, M_TEMP, M_WAITOK);
                   1810:
                   1811:        aiov.iov_base = buf;
                   1812:        aiov.iov_len = NFS_DIRFRAGSIZ;
                   1813:        auio.uio_iov = &aiov;
                   1814:        auio.uio_iovcnt = 1;
                   1815:        auio.uio_rw = UIO_READ;
                   1816:        auio.uio_segflg = UIO_SYSSPACE;
                   1817:        auio.uio_procp = p;
                   1818:        auio.uio_resid = NFS_DIRFRAGSIZ;
                   1819:        auio.uio_offset = 0;
                   1820:
1.56      fvdl     1821:        error = VOP_READDIR(vp, &auio, cred, &eof, &cookies, &nc);
1.48      fvdl     1822:
                   1823:        len = NFS_DIRFRAGSIZ - auio.uio_resid;
                   1824:        if (error || len == 0) {
                   1825:                FREE(buf, M_TEMP);
1.57      fvdl     1826:                if (cookies)
1.80      thorpej  1827:                        free(cookies, M_TEMP);
1.48      fvdl     1828:                return;
                   1829:        }
                   1830:
                   1831:        /*
                   1832:         * Find the first valid entry and look at its offset cookie.
                   1833:         */
                   1834:
                   1835:        cp = buf;
                   1836:        for (cop = cookies; len > 0; len -= dp->d_reclen) {
                   1837:                dp = (struct dirent *)cp;
                   1838:                if (dp->d_fileno != 0 && len >= dp->d_reclen) {
                   1839:                        if ((*cop >> 32) != 0 && (*cop & 0xffffffffLL) == 0) {
                   1840:                                *flagp |= NFSMNT_SWAPCOOKIE;
1.49      fvdl     1841:                                nfs_invaldircache(vp, 0);
1.48      fvdl     1842:                                nfs_vinvalbuf(vp, 0, cred, p, 1);
                   1843:                        }
                   1844:                        break;
                   1845:                }
                   1846:                cop++;
                   1847:                cp += dp->d_reclen;
                   1848:        }
                   1849:
                   1850:        FREE(buf, M_TEMP);
1.80      thorpej  1851:        free(cookies, M_TEMP);
1.48      fvdl     1852: }
1.38      thorpej  1853: #endif /* NFS */
1.1       cgd      1854:
                   1855: /*
1.43      fvdl     1856:  * Set up nameidata for a lookup() call and do it.
                   1857:  *
                   1858:  * If pubflag is set, this call is done for a lookup operation on the
                   1859:  * public filehandle. In that case we allow crossing mountpoints and
                   1860:  * absolute pathnames. However, the caller is expected to check that
                   1861:  * the lookup result is within the public fs, and deny access if
                   1862:  * it is not.
1.1       cgd      1863:  */
1.24      christos 1864: int
1.43      fvdl     1865: nfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, retdirp, p, kerbflag, pubflag)
1.75      augustss 1866:        struct nameidata *ndp;
1.1       cgd      1867:        fhandle_t *fhp;
                   1868:        int len;
1.12      mycroft  1869:        struct nfssvc_sock *slp;
                   1870:        struct mbuf *nam;
1.1       cgd      1871:        struct mbuf **mdp;
                   1872:        caddr_t *dposp;
1.25      fvdl     1873:        struct vnode **retdirp;
1.1       cgd      1874:        struct proc *p;
1.43      fvdl     1875:        int kerbflag, pubflag;
1.1       cgd      1876: {
1.75      augustss 1877:        int i, rem;
                   1878:        struct mbuf *md;
                   1879:        char *fromcp, *tocp, *cp;
1.43      fvdl     1880:        struct iovec aiov;
                   1881:        struct uio auio;
1.1       cgd      1882:        struct vnode *dp;
1.43      fvdl     1883:        int error, rdonly, linklen;
1.12      mycroft  1884:        struct componentname *cnp = &ndp->ni_cnd;
1.1       cgd      1885:
1.25      fvdl     1886:        *retdirp = (struct vnode *)0;
1.81      thorpej  1887:
                   1888:        if ((len + 1) > MAXPATHLEN)
                   1889:                return (ENAMETOOLONG);
                   1890:        cnp->cn_pnbuf = PNBUF_GET();
                   1891:
1.1       cgd      1892:        /*
                   1893:         * Copy the name from the mbuf list to ndp->ni_pnbuf
                   1894:         * and set the various ndp fields appropriately.
                   1895:         */
                   1896:        fromcp = *dposp;
1.12      mycroft  1897:        tocp = cnp->cn_pnbuf;
1.1       cgd      1898:        md = *mdp;
                   1899:        rem = mtod(md, caddr_t) + md->m_len - fromcp;
                   1900:        for (i = 0; i < len; i++) {
                   1901:                while (rem == 0) {
                   1902:                        md = md->m_next;
                   1903:                        if (md == NULL) {
                   1904:                                error = EBADRPC;
                   1905:                                goto out;
                   1906:                        }
                   1907:                        fromcp = mtod(md, caddr_t);
                   1908:                        rem = md->m_len;
                   1909:                }
1.43      fvdl     1910:                if (*fromcp == '\0' || (!pubflag && *fromcp == '/')) {
1.25      fvdl     1911:                        error = EACCES;
1.1       cgd      1912:                        goto out;
                   1913:                }
                   1914:                *tocp++ = *fromcp++;
                   1915:                rem--;
                   1916:        }
                   1917:        *tocp = '\0';
                   1918:        *mdp = md;
                   1919:        *dposp = fromcp;
                   1920:        len = nfsm_rndup(len)-len;
                   1921:        if (len > 0) {
                   1922:                if (rem >= len)
                   1923:                        *dposp += len;
1.24      christos 1924:                else if ((error = nfs_adv(mdp, dposp, len, rem)) != 0)
1.1       cgd      1925:                        goto out;
                   1926:        }
1.43      fvdl     1927:
1.1       cgd      1928:        /*
                   1929:         * Extract and set starting directory.
                   1930:         */
1.24      christos 1931:        error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cnd.cn_cred, slp,
1.43      fvdl     1932:            nam, &rdonly, kerbflag, pubflag);
1.24      christos 1933:        if (error)
1.1       cgd      1934:                goto out;
                   1935:        if (dp->v_type != VDIR) {
                   1936:                vrele(dp);
                   1937:                error = ENOTDIR;
                   1938:                goto out;
                   1939:        }
1.43      fvdl     1940:
                   1941:        if (rdonly)
                   1942:                cnp->cn_flags |= RDONLY;
                   1943:
                   1944:        *retdirp = dp;
                   1945:
                   1946:        if (pubflag) {
                   1947:                /*
                   1948:                 * Oh joy. For WebNFS, handle those pesky '%' escapes,
                   1949:                 * and the 'native path' indicator.
                   1950:                 */
1.81      thorpej  1951:                cp = PNBUF_GET();
1.43      fvdl     1952:                fromcp = cnp->cn_pnbuf;
                   1953:                tocp = cp;
                   1954:                if ((unsigned char)*fromcp >= WEBNFS_SPECCHAR_START) {
                   1955:                        switch ((unsigned char)*fromcp) {
                   1956:                        case WEBNFS_NATIVE_CHAR:
                   1957:                                /*
                   1958:                                 * 'Native' path for us is the same
                   1959:                                 * as a path according to the NFS spec,
                   1960:                                 * just skip the escape char.
                   1961:                                 */
                   1962:                                fromcp++;
                   1963:                                break;
                   1964:                        /*
                   1965:                         * More may be added in the future, range 0x80-0xff
                   1966:                         */
                   1967:                        default:
                   1968:                                error = EIO;
1.104     enami    1969:                                PNBUF_PUT(cp);
1.43      fvdl     1970:                                goto out;
                   1971:                        }
                   1972:                }
                   1973:                /*
                   1974:                 * Translate the '%' escapes, URL-style.
                   1975:                 */
                   1976:                while (*fromcp != '\0') {
                   1977:                        if (*fromcp == WEBNFS_ESC_CHAR) {
                   1978:                                if (fromcp[1] != '\0' && fromcp[2] != '\0') {
                   1979:                                        fromcp++;
                   1980:                                        *tocp++ = HEXSTRTOI(fromcp);
                   1981:                                        fromcp += 2;
                   1982:                                        continue;
                   1983:                                } else {
                   1984:                                        error = ENOENT;
1.104     enami    1985:                                        PNBUF_PUT(cp);
1.43      fvdl     1986:                                        goto out;
                   1987:                                }
                   1988:                        } else
                   1989:                                *tocp++ = *fromcp++;
                   1990:                }
                   1991:                *tocp = '\0';
1.81      thorpej  1992:                PNBUF_PUT(cnp->cn_pnbuf);
1.43      fvdl     1993:                cnp->cn_pnbuf = cp;
                   1994:        }
                   1995:
                   1996:        ndp->ni_pathlen = (tocp - cnp->cn_pnbuf) + 1;
                   1997:        ndp->ni_segflg = UIO_SYSSPACE;
1.98      fvdl     1998:        ndp->ni_rootdir = rootvnode;
1.43      fvdl     1999:
                   2000:        if (pubflag) {
                   2001:                ndp->ni_loopcnt = 0;
                   2002:                if (cnp->cn_pnbuf[0] == '/')
                   2003:                        dp = rootvnode;
                   2004:        } else {
                   2005:                cnp->cn_flags |= NOCROSSMOUNT;
                   2006:        }
                   2007:
                   2008:        cnp->cn_proc = p;
1.25      fvdl     2009:        VREF(dp);
1.43      fvdl     2010:
                   2011:     for (;;) {
                   2012:        cnp->cn_nameptr = cnp->cn_pnbuf;
1.1       cgd      2013:        ndp->ni_startdir = dp;
                   2014:        /*
                   2015:         * And call lookup() to do the real work
                   2016:         */
1.25      fvdl     2017:        error = lookup(ndp);
1.91      fvdl     2018:        if (error) {
                   2019:                PNBUF_PUT(cnp->cn_pnbuf);
                   2020:                return (error);
                   2021:        }
1.1       cgd      2022:        /*
                   2023:         * Check for encountering a symbolic link
                   2024:         */
1.43      fvdl     2025:        if ((cnp->cn_flags & ISSYMLINK) == 0) {
1.91      fvdl     2026:                if (cnp->cn_flags & (SAVENAME | SAVESTART))
1.43      fvdl     2027:                        cnp->cn_flags |= HASBUF;
1.91      fvdl     2028:                else
                   2029:                        PNBUF_PUT(cnp->cn_pnbuf);
                   2030:                return (0);
1.43      fvdl     2031:        } else {
1.91      fvdl     2032:                if ((cnp->cn_flags & LOCKPARENT) && (cnp->cn_flags & ISLASTCN))
1.56      fvdl     2033:                        VOP_UNLOCK(ndp->ni_dvp, 0);
1.43      fvdl     2034:                if (!pubflag) {
                   2035:                        error = EINVAL;
                   2036:                        break;
                   2037:                }
                   2038:
                   2039:                if (ndp->ni_loopcnt++ >= MAXSYMLINKS) {
                   2040:                        error = ELOOP;
                   2041:                        break;
                   2042:                }
1.91      fvdl     2043:                if (ndp->ni_vp->v_mount->mnt_flag & MNT_SYMPERM) {
                   2044:                        error = VOP_ACCESS(ndp->ni_vp, VEXEC, cnp->cn_cred,
                   2045:                            cnp->cn_proc);
                   2046:                        if (error != 0)
                   2047:                                break;
                   2048:                }
1.43      fvdl     2049:                if (ndp->ni_pathlen > 1)
1.81      thorpej  2050:                        cp = PNBUF_GET();
1.1       cgd      2051:                else
1.43      fvdl     2052:                        cp = cnp->cn_pnbuf;
                   2053:                aiov.iov_base = cp;
                   2054:                aiov.iov_len = MAXPATHLEN;
                   2055:                auio.uio_iov = &aiov;
                   2056:                auio.uio_iovcnt = 1;
                   2057:                auio.uio_offset = 0;
                   2058:                auio.uio_rw = UIO_READ;
                   2059:                auio.uio_segflg = UIO_SYSSPACE;
                   2060:                auio.uio_procp = (struct proc *)0;
                   2061:                auio.uio_resid = MAXPATHLEN;
                   2062:                error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred);
                   2063:                if (error) {
                   2064:                badlink:
                   2065:                        if (ndp->ni_pathlen > 1)
1.81      thorpej  2066:                                PNBUF_PUT(cp);
1.43      fvdl     2067:                        break;
                   2068:                }
                   2069:                linklen = MAXPATHLEN - auio.uio_resid;
                   2070:                if (linklen == 0) {
                   2071:                        error = ENOENT;
                   2072:                        goto badlink;
                   2073:                }
                   2074:                if (linklen + ndp->ni_pathlen >= MAXPATHLEN) {
                   2075:                        error = ENAMETOOLONG;
                   2076:                        goto badlink;
                   2077:                }
                   2078:                if (ndp->ni_pathlen > 1) {
1.63      perry    2079:                        memcpy(cp + linklen, ndp->ni_next, ndp->ni_pathlen);
1.81      thorpej  2080:                        PNBUF_PUT(cnp->cn_pnbuf);
1.43      fvdl     2081:                        cnp->cn_pnbuf = cp;
                   2082:                } else
                   2083:                        cnp->cn_pnbuf[linklen] = '\0';
                   2084:                ndp->ni_pathlen += linklen;
1.1       cgd      2085:                vput(ndp->ni_vp);
1.43      fvdl     2086:                dp = ndp->ni_dvp;
                   2087:                /*
                   2088:                 * Check if root directory should replace current directory.
                   2089:                 */
                   2090:                if (cnp->cn_pnbuf[0] == '/') {
                   2091:                        vrele(dp);
                   2092:                        dp = ndp->ni_rootdir;
                   2093:                        VREF(dp);
                   2094:                }
1.1       cgd      2095:        }
1.43      fvdl     2096:    }
1.91      fvdl     2097:        vrele(ndp->ni_dvp);
                   2098:        vput(ndp->ni_vp);
                   2099:        ndp->ni_vp = NULL;
1.1       cgd      2100: out:
1.81      thorpej  2101:        PNBUF_PUT(cnp->cn_pnbuf);
1.1       cgd      2102:        return (error);
                   2103: }
                   2104:
                   2105: /*
                   2106:  * A fiddled version of m_adj() that ensures null fill to a long
                   2107:  * boundary and only trims off the back end
                   2108:  */
1.12      mycroft  2109: void
1.1       cgd      2110: nfsm_adj(mp, len, nul)
                   2111:        struct mbuf *mp;
1.75      augustss 2112:        int len;
1.1       cgd      2113:        int nul;
                   2114: {
1.75      augustss 2115:        struct mbuf *m;
                   2116:        int count, i;
                   2117:        char *cp;
1.1       cgd      2118:
                   2119:        /*
                   2120:         * Trim from tail.  Scan the mbuf chain,
                   2121:         * calculating its length and finding the last mbuf.
                   2122:         * If the adjustment only affects this mbuf, then just
                   2123:         * adjust and return.  Otherwise, rescan and truncate
                   2124:         * after the remaining size.
                   2125:         */
                   2126:        count = 0;
                   2127:        m = mp;
                   2128:        for (;;) {
                   2129:                count += m->m_len;
                   2130:                if (m->m_next == (struct mbuf *)0)
                   2131:                        break;
                   2132:                m = m->m_next;
                   2133:        }
                   2134:        if (m->m_len > len) {
                   2135:                m->m_len -= len;
                   2136:                if (nul > 0) {
                   2137:                        cp = mtod(m, caddr_t)+m->m_len-nul;
                   2138:                        for (i = 0; i < nul; i++)
                   2139:                                *cp++ = '\0';
                   2140:                }
                   2141:                return;
                   2142:        }
                   2143:        count -= len;
                   2144:        if (count < 0)
                   2145:                count = 0;
                   2146:        /*
                   2147:         * Correct length for chain is "count".
                   2148:         * Find the mbuf with last data, adjust its length,
                   2149:         * and toss data from remaining mbufs on chain.
                   2150:         */
                   2151:        for (m = mp; m; m = m->m_next) {
                   2152:                if (m->m_len >= count) {
                   2153:                        m->m_len = count;
                   2154:                        if (nul > 0) {
                   2155:                                cp = mtod(m, caddr_t)+m->m_len-nul;
                   2156:                                for (i = 0; i < nul; i++)
                   2157:                                        *cp++ = '\0';
                   2158:                        }
                   2159:                        break;
                   2160:                }
                   2161:                count -= m->m_len;
                   2162:        }
1.25      fvdl     2163:        for (m = m->m_next;m;m = m->m_next)
1.1       cgd      2164:                m->m_len = 0;
                   2165: }
                   2166:
                   2167: /*
1.25      fvdl     2168:  * Make these functions instead of macros, so that the kernel text size
                   2169:  * doesn't get too big...
                   2170:  */
                   2171: void
                   2172: nfsm_srvwcc(nfsd, before_ret, before_vap, after_ret, after_vap, mbp, bposp)
                   2173:        struct nfsrv_descript *nfsd;
                   2174:        int before_ret;
1.75      augustss 2175:        struct vattr *before_vap;
1.25      fvdl     2176:        int after_ret;
                   2177:        struct vattr *after_vap;
                   2178:        struct mbuf **mbp;
                   2179:        char **bposp;
                   2180: {
1.75      augustss 2181:        struct mbuf *mb = *mbp, *mb2;
                   2182:        char *bpos = *bposp;
                   2183:        u_int32_t *tl;
1.25      fvdl     2184:
                   2185:        if (before_ret) {
                   2186:                nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED);
                   2187:                *tl = nfs_false;
                   2188:        } else {
                   2189:                nfsm_build(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
                   2190:                *tl++ = nfs_true;
1.66      fair     2191:                txdr_hyper(before_vap->va_size, tl);
1.25      fvdl     2192:                tl += 2;
                   2193:                txdr_nfsv3time(&(before_vap->va_mtime), tl);
                   2194:                tl += 2;
                   2195:                txdr_nfsv3time(&(before_vap->va_ctime), tl);
                   2196:        }
                   2197:        *bposp = bpos;
                   2198:        *mbp = mb;
                   2199:        nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp);
                   2200: }
                   2201:
                   2202: void
                   2203: nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp)
                   2204:        struct nfsrv_descript *nfsd;
                   2205:        int after_ret;
                   2206:        struct vattr *after_vap;
                   2207:        struct mbuf **mbp;
                   2208:        char **bposp;
                   2209: {
1.75      augustss 2210:        struct mbuf *mb = *mbp, *mb2;
                   2211:        char *bpos = *bposp;
                   2212:        u_int32_t *tl;
                   2213:        struct nfs_fattr *fp;
1.25      fvdl     2214:
                   2215:        if (after_ret) {
                   2216:                nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED);
                   2217:                *tl = nfs_false;
                   2218:        } else {
                   2219:                nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_V3FATTR);
                   2220:                *tl++ = nfs_true;
                   2221:                fp = (struct nfs_fattr *)tl;
                   2222:                nfsm_srvfattr(nfsd, after_vap, fp);
                   2223:        }
                   2224:        *mbp = mb;
                   2225:        *bposp = bpos;
                   2226: }
                   2227:
                   2228: void
                   2229: nfsm_srvfattr(nfsd, vap, fp)
1.75      augustss 2230:        struct nfsrv_descript *nfsd;
                   2231:        struct vattr *vap;
                   2232:        struct nfs_fattr *fp;
1.25      fvdl     2233: {
                   2234:
                   2235:        fp->fa_nlink = txdr_unsigned(vap->va_nlink);
                   2236:        fp->fa_uid = txdr_unsigned(vap->va_uid);
                   2237:        fp->fa_gid = txdr_unsigned(vap->va_gid);
                   2238:        if (nfsd->nd_flag & ND_NFSV3) {
                   2239:                fp->fa_type = vtonfsv3_type(vap->va_type);
                   2240:                fp->fa_mode = vtonfsv3_mode(vap->va_mode);
1.66      fair     2241:                txdr_hyper(vap->va_size, &fp->fa3_size);
                   2242:                txdr_hyper(vap->va_bytes, &fp->fa3_used);
1.25      fvdl     2243:                fp->fa3_rdev.specdata1 = txdr_unsigned(major(vap->va_rdev));
                   2244:                fp->fa3_rdev.specdata2 = txdr_unsigned(minor(vap->va_rdev));
                   2245:                fp->fa3_fsid.nfsuquad[0] = 0;
                   2246:                fp->fa3_fsid.nfsuquad[1] = txdr_unsigned(vap->va_fsid);
                   2247:                fp->fa3_fileid.nfsuquad[0] = 0;
                   2248:                fp->fa3_fileid.nfsuquad[1] = txdr_unsigned(vap->va_fileid);
                   2249:                txdr_nfsv3time(&vap->va_atime, &fp->fa3_atime);
                   2250:                txdr_nfsv3time(&vap->va_mtime, &fp->fa3_mtime);
                   2251:                txdr_nfsv3time(&vap->va_ctime, &fp->fa3_ctime);
                   2252:        } else {
                   2253:                fp->fa_type = vtonfsv2_type(vap->va_type);
                   2254:                fp->fa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode);
                   2255:                fp->fa2_size = txdr_unsigned(vap->va_size);
                   2256:                fp->fa2_blocksize = txdr_unsigned(vap->va_blocksize);
                   2257:                if (vap->va_type == VFIFO)
                   2258:                        fp->fa2_rdev = 0xffffffff;
                   2259:                else
                   2260:                        fp->fa2_rdev = txdr_unsigned(vap->va_rdev);
                   2261:                fp->fa2_blocks = txdr_unsigned(vap->va_bytes / NFS_FABLKSIZE);
                   2262:                fp->fa2_fsid = txdr_unsigned(vap->va_fsid);
                   2263:                fp->fa2_fileid = txdr_unsigned(vap->va_fileid);
                   2264:                txdr_nfsv2time(&vap->va_atime, &fp->fa2_atime);
                   2265:                txdr_nfsv2time(&vap->va_mtime, &fp->fa2_mtime);
                   2266:                txdr_nfsv2time(&vap->va_ctime, &fp->fa2_ctime);
                   2267:        }
                   2268: }
                   2269:
                   2270: /*
1.1       cgd      2271:  * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked)
                   2272:  *     - look up fsid in mount list (if not found ret error)
1.12      mycroft  2273:  *     - get vp and export rights by calling VFS_FHTOVP()
                   2274:  *     - if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon
1.1       cgd      2275:  *     - if not lockflag unlock it with VOP_UNLOCK()
                   2276:  */
1.24      christos 2277: int
1.43      fvdl     2278: nfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp, kerbflag, pubflag)
1.1       cgd      2279:        fhandle_t *fhp;
                   2280:        int lockflag;
                   2281:        struct vnode **vpp;
                   2282:        struct ucred *cred;
1.12      mycroft  2283:        struct nfssvc_sock *slp;
                   2284:        struct mbuf *nam;
                   2285:        int *rdonlyp;
1.25      fvdl     2286:        int kerbflag;
1.1       cgd      2287: {
1.75      augustss 2288:        struct mount *mp;
                   2289:        int i;
1.12      mycroft  2290:        struct ucred *credanon;
                   2291:        int error, exflags;
1.40      fvdl     2292:        struct sockaddr_in *saddr;
1.1       cgd      2293:
1.12      mycroft  2294:        *vpp = (struct vnode *)0;
1.43      fvdl     2295:
                   2296:        if (nfs_ispublicfh(fhp)) {
                   2297:                if (!pubflag || !nfs_pub.np_valid)
                   2298:                        return (ESTALE);
                   2299:                fhp = &nfs_pub.np_handle;
                   2300:        }
                   2301:
1.25      fvdl     2302:        mp = vfs_getvfs(&fhp->fh_fsid);
                   2303:        if (!mp)
1.1       cgd      2304:                return (ESTALE);
1.65      wrstuden 2305:        error = VFS_CHECKEXP(mp, nam, &exflags, &credanon);
1.64      wrstuden 2306:        if (error)
                   2307:                return (error);
                   2308:        error = VFS_FHTOVP(mp, &fhp->fh_fid, vpp);
1.24      christos 2309:        if (error)
1.12      mycroft  2310:                return (error);
1.40      fvdl     2311:
1.43      fvdl     2312:        if (!(exflags & (MNT_EXNORESPORT|MNT_EXPUBLIC))) {
1.40      fvdl     2313:                saddr = mtod(nam, struct sockaddr_in *);
1.76      fvdl     2314:                if ((saddr->sin_family == AF_INET) &&
1.40      fvdl     2315:                    ntohs(saddr->sin_port) >= IPPORT_RESERVED) {
                   2316:                        vput(*vpp);
                   2317:                        return (NFSERR_AUTHERR | AUTH_TOOWEAK);
                   2318:                }
1.76      fvdl     2319: #ifdef INET6
                   2320:                if ((saddr->sin_family == AF_INET6) &&
                   2321:                    ntohs(saddr->sin_port) >= IPV6PORT_RESERVED) {
                   2322:                        vput(*vpp);
                   2323:                        return (NFSERR_AUTHERR | AUTH_TOOWEAK);
                   2324:                }
                   2325: #endif
1.40      fvdl     2326:        }
1.12      mycroft  2327:        /*
                   2328:         * Check/setup credentials.
                   2329:         */
                   2330:        if (exflags & MNT_EXKERB) {
1.25      fvdl     2331:                if (!kerbflag) {
1.12      mycroft  2332:                        vput(*vpp);
1.25      fvdl     2333:                        return (NFSERR_AUTHERR | AUTH_TOOWEAK);
1.12      mycroft  2334:                }
1.25      fvdl     2335:        } else if (kerbflag) {
                   2336:                vput(*vpp);
                   2337:                return (NFSERR_AUTHERR | AUTH_TOOWEAK);
1.12      mycroft  2338:        } else if (cred->cr_uid == 0 || (exflags & MNT_EXPORTANON)) {
                   2339:                cred->cr_uid = credanon->cr_uid;
1.19      jtc      2340:                cred->cr_gid = credanon->cr_gid;
1.12      mycroft  2341:                for (i = 0; i < credanon->cr_ngroups && i < NGROUPS; i++)
                   2342:                        cred->cr_groups[i] = credanon->cr_groups[i];
1.15      mycroft  2343:                cred->cr_ngroups = i;
1.12      mycroft  2344:        }
                   2345:        if (exflags & MNT_EXRDONLY)
                   2346:                *rdonlyp = 1;
                   2347:        else
                   2348:                *rdonlyp = 0;
1.1       cgd      2349:        if (!lockflag)
1.56      fvdl     2350:                VOP_UNLOCK(*vpp, 0);
1.1       cgd      2351:        return (0);
1.43      fvdl     2352: }
                   2353:
                   2354: /*
                   2355:  * WebNFS: check if a filehandle is a public filehandle. For v3, this
                   2356:  * means a length of 0, for v2 it means all zeroes. nfsm_srvmtofh has
                   2357:  * transformed this to all zeroes in both cases, so check for it.
                   2358:  */
                   2359: int
                   2360: nfs_ispublicfh(fhp)
                   2361:        fhandle_t *fhp;
                   2362: {
                   2363:        char *cp = (char *)fhp;
                   2364:        int i;
                   2365:
                   2366:        for (i = 0; i < NFSX_V3FH; i++)
                   2367:                if (*cp++ != 0)
                   2368:                        return (FALSE);
                   2369:        return (TRUE);
1.1       cgd      2370: }
                   2371:
                   2372: /*
1.12      mycroft  2373:  * This function compares two net addresses by family and returns TRUE
                   2374:  * if they are the same host.
                   2375:  * If there is any doubt, return FALSE.
                   2376:  * The AF_INET family is handled as a special case so that address mbufs
                   2377:  * don't need to be saved to store "struct in_addr", which is only 4 bytes.
1.1       cgd      2378:  */
1.24      christos 2379: int
1.12      mycroft  2380: netaddr_match(family, haddr, nam)
                   2381:        int family;
                   2382:        union nethostaddr *haddr;
                   2383:        struct mbuf *nam;
1.1       cgd      2384: {
1.75      augustss 2385:        struct sockaddr_in *inetaddr;
1.1       cgd      2386:
1.12      mycroft  2387:        switch (family) {
                   2388:        case AF_INET:
                   2389:                inetaddr = mtod(nam, struct sockaddr_in *);
                   2390:                if (inetaddr->sin_family == AF_INET &&
                   2391:                    inetaddr->sin_addr.s_addr == haddr->had_inetaddr)
                   2392:                        return (1);
                   2393:                break;
1.76      fvdl     2394: #ifdef INET6
                   2395:        case AF_INET6:
                   2396:            {
                   2397:                struct sockaddr_in6 *sin6_1, *sin6_2;
                   2398:
                   2399:                sin6_1 = mtod(nam, struct sockaddr_in6 *);
                   2400:                sin6_2 = mtod(haddr->had_nam, struct sockaddr_in6 *);
                   2401:                if (sin6_1->sin6_family == AF_INET6 &&
                   2402:                    IN6_ARE_ADDR_EQUAL(&sin6_1->sin6_addr, &sin6_2->sin6_addr))
                   2403:                        return 1;
                   2404:            }
                   2405: #endif
1.12      mycroft  2406: #ifdef ISO
                   2407:        case AF_ISO:
                   2408:            {
1.75      augustss 2409:                struct sockaddr_iso *isoaddr1, *isoaddr2;
1.12      mycroft  2410:
                   2411:                isoaddr1 = mtod(nam, struct sockaddr_iso *);
                   2412:                isoaddr2 = mtod(haddr->had_nam, struct sockaddr_iso *);
                   2413:                if (isoaddr1->siso_family == AF_ISO &&
                   2414:                    isoaddr1->siso_nlen > 0 &&
                   2415:                    isoaddr1->siso_nlen == isoaddr2->siso_nlen &&
                   2416:                    SAME_ISOADDR(isoaddr1, isoaddr2))
                   2417:                        return (1);
                   2418:                break;
                   2419:            }
                   2420: #endif /* ISO */
                   2421:        default:
                   2422:                break;
                   2423:        };
                   2424:        return (0);
1.25      fvdl     2425: }
                   2426:
                   2427: /*
                   2428:  * The write verifier has changed (probably due to a server reboot), so all
                   2429:  * B_NEEDCOMMIT blocks will have to be written again. Since they are on the
                   2430:  * dirty block list as B_DELWRI, all this takes is clearing the B_NEEDCOMMIT
                   2431:  * flag. Once done the new write verifier can be set for the mount point.
                   2432:  */
                   2433: void
                   2434: nfs_clearcommit(mp)
                   2435:        struct mount *mp;
                   2436: {
1.89      chs      2437:        struct vnode *vp;
1.83      fvdl     2438:        struct nfsnode *np;
1.89      chs      2439:        struct vm_page *pg;
1.25      fvdl     2440:        int s;
                   2441:
                   2442:        s = splbio();
1.89      chs      2443:        LIST_FOREACH(vp, &mp->mnt_vnodelist, v_mntvnodes) {
                   2444:                KASSERT(vp->v_mount == mp);
1.85      enami    2445:                if (vp->v_type == VNON)
                   2446:                        continue;
1.83      fvdl     2447:                np = VTONFS(vp);
                   2448:                np->n_pushlo = np->n_pushhi = np->n_pushedlo =
                   2449:                    np->n_pushedhi = 0;
                   2450:                np->n_commitflags &=
                   2451:                    ~(NFS_COMMIT_PUSH_VALID | NFS_COMMIT_PUSHED_VALID);
1.97      chs      2452:                simple_lock(&vp->v_uobj.vmobjlock);
                   2453:                TAILQ_FOREACH(pg, &vp->v_uobj.memq, listq) {
1.89      chs      2454:                        pg->flags &= ~PG_NEEDCOMMIT;
1.25      fvdl     2455:                }
1.97      chs      2456:                simple_unlock(&vp->v_uobj.vmobjlock);
1.25      fvdl     2457:        }
                   2458:        splx(s);
1.83      fvdl     2459: }
                   2460:
                   2461: void
                   2462: nfs_merge_commit_ranges(vp)
                   2463:        struct vnode *vp;
                   2464: {
                   2465:        struct nfsnode *np = VTONFS(vp);
                   2466:
                   2467:        if (!(np->n_commitflags & NFS_COMMIT_PUSHED_VALID)) {
                   2468:                np->n_pushedlo = np->n_pushlo;
                   2469:                np->n_pushedhi = np->n_pushhi;
                   2470:                np->n_commitflags |= NFS_COMMIT_PUSHED_VALID;
                   2471:        } else {
                   2472:                if (np->n_pushlo < np->n_pushedlo)
                   2473:                        np->n_pushedlo = np->n_pushlo;
                   2474:                if (np->n_pushhi > np->n_pushedhi)
                   2475:                        np->n_pushedhi = np->n_pushhi;
                   2476:        }
                   2477:
                   2478:        np->n_pushlo = np->n_pushhi = 0;
                   2479:        np->n_commitflags &= ~NFS_COMMIT_PUSH_VALID;
                   2480:
                   2481: #ifdef fvdl_debug
                   2482:        printf("merge: committed: %u - %u\n", (unsigned)np->n_pushedlo,
                   2483:            (unsigned)np->n_pushedhi);
                   2484: #endif
                   2485: }
                   2486:
                   2487: int
1.89      chs      2488: nfs_in_committed_range(vp, off, len)
1.83      fvdl     2489:        struct vnode *vp;
1.89      chs      2490:        off_t off, len;
1.83      fvdl     2491: {
                   2492:        struct nfsnode *np = VTONFS(vp);
                   2493:        off_t lo, hi;
                   2494:
                   2495:        if (!(np->n_commitflags & NFS_COMMIT_PUSHED_VALID))
                   2496:                return 0;
1.89      chs      2497:        lo = off;
                   2498:        hi = lo + len;
1.83      fvdl     2499:
                   2500:        return (lo >= np->n_pushedlo && hi <= np->n_pushedhi);
                   2501: }
                   2502:
                   2503: int
1.89      chs      2504: nfs_in_tobecommitted_range(vp, off, len)
1.83      fvdl     2505:        struct vnode *vp;
1.89      chs      2506:        off_t off, len;
1.83      fvdl     2507: {
                   2508:        struct nfsnode *np = VTONFS(vp);
                   2509:        off_t lo, hi;
                   2510:
                   2511:        if (!(np->n_commitflags & NFS_COMMIT_PUSH_VALID))
                   2512:                return 0;
1.89      chs      2513:        lo = off;
                   2514:        hi = lo + len;
1.83      fvdl     2515:
                   2516:        return (lo >= np->n_pushlo && hi <= np->n_pushhi);
                   2517: }
                   2518:
                   2519: void
1.89      chs      2520: nfs_add_committed_range(vp, off, len)
1.83      fvdl     2521:        struct vnode *vp;
1.89      chs      2522:        off_t off, len;
1.83      fvdl     2523: {
                   2524:        struct nfsnode *np = VTONFS(vp);
                   2525:        off_t lo, hi;
                   2526:
1.89      chs      2527:        lo = off;
                   2528:        hi = lo + len;
1.83      fvdl     2529:
                   2530:        if (!(np->n_commitflags & NFS_COMMIT_PUSHED_VALID)) {
                   2531:                np->n_pushedlo = lo;
                   2532:                np->n_pushedhi = hi;
                   2533:                np->n_commitflags |= NFS_COMMIT_PUSHED_VALID;
                   2534:        } else {
                   2535:                if (hi > np->n_pushedhi)
                   2536:                        np->n_pushedhi = hi;
                   2537:                if (lo < np->n_pushedlo)
                   2538:                        np->n_pushedlo = lo;
                   2539:        }
                   2540: #ifdef fvdl_debug
                   2541:        printf("add: committed: %u - %u\n", (unsigned)np->n_pushedlo,
                   2542:            (unsigned)np->n_pushedhi);
                   2543: #endif
                   2544: }
                   2545:
                   2546: void
1.89      chs      2547: nfs_del_committed_range(vp, off, len)
1.83      fvdl     2548:        struct vnode *vp;
1.89      chs      2549:        off_t off, len;
1.83      fvdl     2550: {
                   2551:        struct nfsnode *np = VTONFS(vp);
                   2552:        off_t lo, hi;
                   2553:
                   2554:        if (!(np->n_commitflags & NFS_COMMIT_PUSHED_VALID))
                   2555:                return;
                   2556:
1.89      chs      2557:        lo = off;
                   2558:        hi = lo + len;
1.83      fvdl     2559:
                   2560:        if (lo > np->n_pushedhi || hi < np->n_pushedlo)
                   2561:                return;
                   2562:        if (lo <= np->n_pushedlo)
                   2563:                np->n_pushedlo = hi;
                   2564:        else if (hi >= np->n_pushedhi)
                   2565:                np->n_pushedhi = lo;
                   2566:        else {
                   2567:                /*
                   2568:                 * XXX There's only one range. If the deleted range
                   2569:                 * is in the middle, pick the largest of the
                   2570:                 * contiguous ranges that it leaves.
                   2571:                 */
                   2572:                if ((np->n_pushedlo - lo) > (hi - np->n_pushedhi))
                   2573:                        np->n_pushedhi = lo;
                   2574:                else
                   2575:                        np->n_pushedlo = hi;
                   2576:        }
                   2577: #ifdef fvdl_debug
                   2578:        printf("del: committed: %u - %u\n", (unsigned)np->n_pushedlo,
                   2579:            (unsigned)np->n_pushedhi);
                   2580: #endif
                   2581: }
                   2582:
                   2583: void
1.89      chs      2584: nfs_add_tobecommitted_range(vp, off, len)
1.83      fvdl     2585:        struct vnode *vp;
1.89      chs      2586:        off_t off, len;
1.83      fvdl     2587: {
                   2588:        struct nfsnode *np = VTONFS(vp);
                   2589:        off_t lo, hi;
                   2590:
1.89      chs      2591:        lo = off;
                   2592:        hi = lo + len;
1.83      fvdl     2593:
                   2594:        if (!(np->n_commitflags & NFS_COMMIT_PUSH_VALID)) {
                   2595:                np->n_pushlo = lo;
                   2596:                np->n_pushhi = hi;
                   2597:                np->n_commitflags |= NFS_COMMIT_PUSH_VALID;
                   2598:        } else {
                   2599:                if (lo < np->n_pushlo)
                   2600:                        np->n_pushlo = lo;
                   2601:                if (hi > np->n_pushhi)
                   2602:                        np->n_pushhi = hi;
                   2603:        }
                   2604: #ifdef fvdl_debug
                   2605:        printf("add: tobecommitted: %u - %u\n", (unsigned)np->n_pushlo,
                   2606:            (unsigned)np->n_pushhi);
                   2607: #endif
                   2608: }
                   2609:
                   2610: void
1.89      chs      2611: nfs_del_tobecommitted_range(vp, off, len)
1.83      fvdl     2612:        struct vnode *vp;
1.89      chs      2613:        off_t off, len;
1.83      fvdl     2614: {
                   2615:        struct nfsnode *np = VTONFS(vp);
                   2616:        off_t lo, hi;
                   2617:
                   2618:        if (!(np->n_commitflags & NFS_COMMIT_PUSH_VALID))
                   2619:                return;
                   2620:
1.89      chs      2621:        lo = off;
                   2622:        hi = lo + len;
1.83      fvdl     2623:
                   2624:        if (lo > np->n_pushhi || hi < np->n_pushlo)
                   2625:                return;
                   2626:
                   2627:        if (lo <= np->n_pushlo)
                   2628:                np->n_pushlo = hi;
                   2629:        else if (hi >= np->n_pushhi)
                   2630:                np->n_pushhi = lo;
                   2631:        else {
                   2632:                /*
                   2633:                 * XXX There's only one range. If the deleted range
                   2634:                 * is in the middle, pick the largest of the
                   2635:                 * contiguous ranges that it leaves.
                   2636:                 */
                   2637:                if ((np->n_pushlo - lo) > (hi - np->n_pushhi))
                   2638:                        np->n_pushhi = lo;
                   2639:                else
                   2640:                        np->n_pushlo = hi;
                   2641:        }
                   2642: #ifdef fvdl_debug
                   2643:        printf("del: tobecommitted: %u - %u\n", (unsigned)np->n_pushlo,
                   2644:            (unsigned)np->n_pushhi);
                   2645: #endif
1.25      fvdl     2646: }
                   2647:
                   2648: /*
                   2649:  * Map errnos to NFS error numbers. For Version 3 also filter out error
                   2650:  * numbers not specified for the associated procedure.
                   2651:  */
                   2652: int
                   2653: nfsrv_errmap(nd, err)
                   2654:        struct nfsrv_descript *nd;
1.75      augustss 2655:        int err;
1.25      fvdl     2656: {
1.90      jdolecek 2657:        const short *defaulterrp, *errp;
1.25      fvdl     2658:
                   2659:        if (nd->nd_flag & ND_NFSV3) {
                   2660:            if (nd->nd_procnum <= NFSPROC_COMMIT) {
                   2661:                errp = defaulterrp = nfsrv_v3errmap[nd->nd_procnum];
                   2662:                while (*++errp) {
                   2663:                        if (*errp == err)
                   2664:                                return (err);
                   2665:                        else if (*errp > err)
                   2666:                                break;
                   2667:                }
                   2668:                return ((int)*defaulterrp);
                   2669:            } else
                   2670:                return (err & 0xffff);
                   2671:        }
                   2672:        if (err <= ELAST)
                   2673:                return ((int)nfsrv_v2errmap[err - 1]);
                   2674:        return (NFSERR_IO);
                   2675: }
                   2676:
                   2677: /*
                   2678:  * Sort the group list in increasing numerical order.
                   2679:  * (Insertion sort by Chris Torek, who was grossed out by the bubble sort
                   2680:  *  that used to be here.)
                   2681:  */
                   2682: void
                   2683: nfsrvw_sort(list, num)
1.75      augustss 2684:         gid_t *list;
                   2685:         int num;
1.25      fvdl     2686: {
1.75      augustss 2687:        int i, j;
1.25      fvdl     2688:        gid_t v;
                   2689:
                   2690:        /* Insertion sort. */
                   2691:        for (i = 1; i < num; i++) {
                   2692:                v = list[i];
                   2693:                /* find correct slot for value v, moving others up */
                   2694:                for (j = i; --j >= 0 && v < list[j];)
                   2695:                        list[j + 1] = list[j];
                   2696:                list[j + 1] = v;
                   2697:        }
                   2698: }
                   2699:
                   2700: /*
1.63      perry    2701:  * copy credentials making sure that the result can be compared with memcmp().
1.25      fvdl     2702:  */
                   2703: void
                   2704: nfsrv_setcred(incred, outcred)
1.75      augustss 2705:        struct ucred *incred, *outcred;
1.25      fvdl     2706: {
1.75      augustss 2707:        int i;
1.25      fvdl     2708:
1.63      perry    2709:        memset((caddr_t)outcred, 0, sizeof (struct ucred));
1.25      fvdl     2710:        outcred->cr_ref = 1;
                   2711:        outcred->cr_uid = incred->cr_uid;
                   2712:        outcred->cr_gid = incred->cr_gid;
                   2713:        outcred->cr_ngroups = incred->cr_ngroups;
                   2714:        for (i = 0; i < incred->cr_ngroups; i++)
                   2715:                outcred->cr_groups[i] = incred->cr_groups[i];
                   2716:        nfsrvw_sort(outcred->cr_groups, outcred->cr_ngroups);
1.1       cgd      2717: }

CVSweb <webmaster@jp.NetBSD.org>