The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/nfs/nfs_subs.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: ea827006b92c107dbc002078fee1e6e5


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.