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  -  FREEBSD11  -  FREEBSD10  -  FREEBSD9  -  FREEBSD92  -  FREEBSD91  -  FREEBSD90  -  FREEBSD8  -  FREEBSD82  -  FREEBSD81  -  FREEBSD80  -  FREEBSD7  -  FREEBSD74  -  FREEBSD73  -  FREEBSD72  -  FREEBSD71  -  FREEBSD70  -  FREEBSD6  -  FREEBSD64  -  FREEBSD63  -  FREEBSD62  -  FREEBSD61  -  FREEBSD60  -  FREEBSD5  -  FREEBSD55  -  FREEBSD54  -  FREEBSD53  -  FREEBSD52  -  FREEBSD51  -  FREEBSD50  -  FREEBSD4  -  FREEBSD3  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  xnu-1456.1.26  -  xnu-1699.24.8  -  xnu-2050.18.24  -  OPENSOLARIS  -  minix-3-1-1 
SearchContext: -  none  -  3  -  10 

    1 /*      $NetBSD: nfs_subs.c,v 1.220 2010/11/06 11:00:29 uebayasi 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.220 2010/11/06 11:00:29 uebayasi Exp $");
   74 
   75 #ifdef _KERNEL_OPT
   76 #include "opt_nfs.h"
   77 #endif
   78 
   79 /*
   80  * These functions support the macros and help fiddle mbuf chains for
   81  * the nfs op functions. They do things like create the rpc header and
   82  * copy data between mbuf chains and uio lists.
   83  */
   84 #include <sys/param.h>
   85 #include <sys/proc.h>
   86 #include <sys/systm.h>
   87 #include <sys/kernel.h>
   88 #include <sys/kmem.h>
   89 #include <sys/mount.h>
   90 #include <sys/vnode.h>
   91 #include <sys/namei.h>
   92 #include <sys/mbuf.h>
   93 #include <sys/socket.h>
   94 #include <sys/stat.h>
   95 #include <sys/filedesc.h>
   96 #include <sys/time.h>
   97 #include <sys/dirent.h>
   98 #include <sys/once.h>
   99 #include <sys/kauth.h>
  100 #include <sys/atomic.h>
  101 
  102 #include <uvm/uvm.h>
  103 
  104 #include <nfs/rpcv2.h>
  105 #include <nfs/nfsproto.h>
  106 #include <nfs/nfsnode.h>
  107 #include <nfs/nfs.h>
  108 #include <nfs/xdr_subs.h>
  109 #include <nfs/nfsm_subs.h>
  110 #include <nfs/nfsmount.h>
  111 #include <nfs/nfsrtt.h>
  112 #include <nfs/nfs_var.h>
  113 
  114 #include <miscfs/specfs/specdev.h>
  115 
  116 #include <netinet/in.h>
  117 
  118 static u_int32_t nfs_xid;
  119 
  120 int nuidhash_max = NFS_MAXUIDHASH;
  121 /*
  122  * Data items converted to xdr at startup, since they are constant
  123  * This is kinda hokey, but may save a little time doing byte swaps
  124  */
  125 u_int32_t nfs_xdrneg1;
  126 u_int32_t rpc_call, rpc_vers, rpc_reply, rpc_msgdenied, rpc_autherr,
  127         rpc_mismatch, rpc_auth_unix, rpc_msgaccepted,
  128         rpc_auth_kerb;
  129 u_int32_t nfs_prog, nfs_true, nfs_false;
  130 
  131 /* And other global data */
  132 const nfstype nfsv2_type[9] =
  133         { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFNON, NFCHR, NFNON };
  134 const nfstype nfsv3_type[9] =
  135         { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFSOCK, NFFIFO, NFNON };
  136 const enum vtype nv2tov_type[8] =
  137         { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON, VNON };
  138 const enum vtype nv3tov_type[8] =
  139         { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO };
  140 int nfs_ticks;
  141 
  142 /* NFS client/server stats. */
  143 struct nfsstats nfsstats;
  144 
  145 /*
  146  * Mapping of old NFS Version 2 RPC numbers to generic numbers.
  147  */
  148 const int nfsv3_procid[NFS_NPROCS] = {
  149         NFSPROC_NULL,
  150         NFSPROC_GETATTR,
  151         NFSPROC_SETATTR,
  152         NFSPROC_NOOP,
  153         NFSPROC_LOOKUP,
  154         NFSPROC_READLINK,
  155         NFSPROC_READ,
  156         NFSPROC_NOOP,
  157         NFSPROC_WRITE,
  158         NFSPROC_CREATE,
  159         NFSPROC_REMOVE,
  160         NFSPROC_RENAME,
  161         NFSPROC_LINK,
  162         NFSPROC_SYMLINK,
  163         NFSPROC_MKDIR,
  164         NFSPROC_RMDIR,
  165         NFSPROC_READDIR,
  166         NFSPROC_FSSTAT,
  167         NFSPROC_NOOP,
  168         NFSPROC_NOOP,
  169         NFSPROC_NOOP,
  170         NFSPROC_NOOP,
  171         NFSPROC_NOOP
  172 };
  173 
  174 /*
  175  * and the reverse mapping from generic to Version 2 procedure numbers
  176  */
  177 const int nfsv2_procid[NFS_NPROCS] = {
  178         NFSV2PROC_NULL,
  179         NFSV2PROC_GETATTR,
  180         NFSV2PROC_SETATTR,
  181         NFSV2PROC_LOOKUP,
  182         NFSV2PROC_NOOP,
  183         NFSV2PROC_READLINK,
  184         NFSV2PROC_READ,
  185         NFSV2PROC_WRITE,
  186         NFSV2PROC_CREATE,
  187         NFSV2PROC_MKDIR,
  188         NFSV2PROC_SYMLINK,
  189         NFSV2PROC_CREATE,
  190         NFSV2PROC_REMOVE,
  191         NFSV2PROC_RMDIR,
  192         NFSV2PROC_RENAME,
  193         NFSV2PROC_LINK,
  194         NFSV2PROC_READDIR,
  195         NFSV2PROC_NOOP,
  196         NFSV2PROC_STATFS,
  197         NFSV2PROC_NOOP,
  198         NFSV2PROC_NOOP,
  199         NFSV2PROC_NOOP,
  200         NFSV2PROC_NOOP,
  201 };
  202 
  203 /*
  204  * Maps errno values to nfs error numbers.
  205  * Use NFSERR_IO as the catch all for ones not specifically defined in
  206  * RFC 1094.
  207  */
  208 static const u_char nfsrv_v2errmap[ELAST] = {
  209   NFSERR_PERM,  NFSERR_NOENT,   NFSERR_IO,      NFSERR_IO,      NFSERR_IO,
  210   NFSERR_NXIO,  NFSERR_IO,      NFSERR_IO,      NFSERR_IO,      NFSERR_IO,
  211   NFSERR_IO,    NFSERR_IO,      NFSERR_ACCES,   NFSERR_IO,      NFSERR_IO,
  212   NFSERR_IO,    NFSERR_EXIST,   NFSERR_IO,      NFSERR_NODEV,   NFSERR_NOTDIR,
  213   NFSERR_ISDIR, NFSERR_IO,      NFSERR_IO,      NFSERR_IO,      NFSERR_IO,
  214   NFSERR_IO,    NFSERR_FBIG,    NFSERR_NOSPC,   NFSERR_IO,      NFSERR_ROFS,
  215   NFSERR_IO,    NFSERR_IO,      NFSERR_IO,      NFSERR_IO,      NFSERR_IO,
  216   NFSERR_IO,    NFSERR_IO,      NFSERR_IO,      NFSERR_IO,      NFSERR_IO,
  217   NFSERR_IO,    NFSERR_IO,      NFSERR_IO,      NFSERR_IO,      NFSERR_IO,
  218   NFSERR_IO,    NFSERR_IO,      NFSERR_IO,      NFSERR_IO,      NFSERR_IO,
  219   NFSERR_IO,    NFSERR_IO,      NFSERR_IO,      NFSERR_IO,      NFSERR_IO,
  220   NFSERR_IO,    NFSERR_IO,      NFSERR_IO,      NFSERR_IO,      NFSERR_IO,
  221   NFSERR_IO,    NFSERR_IO,      NFSERR_NAMETOL, NFSERR_IO,      NFSERR_IO,
  222   NFSERR_NOTEMPTY, NFSERR_IO,   NFSERR_IO,      NFSERR_DQUOT,   NFSERR_STALE,
  223   NFSERR_IO,    NFSERR_IO,      NFSERR_IO,      NFSERR_IO,      NFSERR_IO,
  224   NFSERR_IO,    NFSERR_IO,      NFSERR_IO,      NFSERR_IO,      NFSERR_IO,
  225   NFSERR_IO,    NFSERR_IO,
  226 };
  227 
  228 /*
  229  * Maps errno values to nfs error numbers.
  230  * Although it is not obvious whether or not NFS clients really care if
  231  * a returned error value is in the specified list for the procedure, the
  232  * safest thing to do is filter them appropriately. For Version 2, the
  233  * X/Open XNFS document is the only specification that defines error values
  234  * for each RPC (The RFC simply lists all possible error values for all RPCs),
  235  * so I have decided to not do this for Version 2.
  236  * The first entry is the default error return and the rest are the valid
  237  * errors for that RPC in increasing numeric order.
  238  */
  239 static const short nfsv3err_null[] = {
  240         0,
  241         0,
  242 };
  243 
  244 static const short nfsv3err_getattr[] = {
  245         NFSERR_IO,
  246         NFSERR_IO,
  247         NFSERR_STALE,
  248         NFSERR_BADHANDLE,
  249         NFSERR_SERVERFAULT,
  250         0,
  251 };
  252 
  253 static const short nfsv3err_setattr[] = {
  254         NFSERR_IO,
  255         NFSERR_PERM,
  256         NFSERR_IO,
  257         NFSERR_ACCES,
  258         NFSERR_INVAL,
  259         NFSERR_NOSPC,
  260         NFSERR_ROFS,
  261         NFSERR_DQUOT,
  262         NFSERR_STALE,
  263         NFSERR_BADHANDLE,
  264         NFSERR_NOT_SYNC,
  265         NFSERR_SERVERFAULT,
  266         0,
  267 };
  268 
  269 static const short nfsv3err_lookup[] = {
  270         NFSERR_IO,
  271         NFSERR_NOENT,
  272         NFSERR_IO,
  273         NFSERR_ACCES,
  274         NFSERR_NOTDIR,
  275         NFSERR_NAMETOL,
  276         NFSERR_STALE,
  277         NFSERR_BADHANDLE,
  278         NFSERR_SERVERFAULT,
  279         0,
  280 };
  281 
  282 static const short nfsv3err_access[] = {
  283         NFSERR_IO,
  284         NFSERR_IO,
  285         NFSERR_STALE,
  286         NFSERR_BADHANDLE,
  287         NFSERR_SERVERFAULT,
  288         0,
  289 };
  290 
  291 static const short nfsv3err_readlink[] = {
  292         NFSERR_IO,
  293         NFSERR_IO,
  294         NFSERR_ACCES,
  295         NFSERR_INVAL,
  296         NFSERR_STALE,
  297         NFSERR_BADHANDLE,
  298         NFSERR_NOTSUPP,
  299         NFSERR_SERVERFAULT,
  300         0,
  301 };
  302 
  303 static const short nfsv3err_read[] = {
  304         NFSERR_IO,
  305         NFSERR_IO,
  306         NFSERR_NXIO,
  307         NFSERR_ACCES,
  308         NFSERR_INVAL,
  309         NFSERR_STALE,
  310         NFSERR_BADHANDLE,
  311         NFSERR_SERVERFAULT,
  312         NFSERR_JUKEBOX,
  313         0,
  314 };
  315 
  316 static const short nfsv3err_write[] = {
  317         NFSERR_IO,
  318         NFSERR_IO,
  319         NFSERR_ACCES,
  320         NFSERR_INVAL,
  321         NFSERR_FBIG,
  322         NFSERR_NOSPC,
  323         NFSERR_ROFS,
  324         NFSERR_DQUOT,
  325         NFSERR_STALE,
  326         NFSERR_BADHANDLE,
  327         NFSERR_SERVERFAULT,
  328         NFSERR_JUKEBOX,
  329         0,
  330 };
  331 
  332 static const short nfsv3err_create[] = {
  333         NFSERR_IO,
  334         NFSERR_IO,
  335         NFSERR_ACCES,
  336         NFSERR_EXIST,
  337         NFSERR_NOTDIR,
  338         NFSERR_NOSPC,
  339         NFSERR_ROFS,
  340         NFSERR_NAMETOL,
  341         NFSERR_DQUOT,
  342         NFSERR_STALE,
  343         NFSERR_BADHANDLE,
  344         NFSERR_NOTSUPP,
  345         NFSERR_SERVERFAULT,
  346         0,
  347 };
  348 
  349 static const short nfsv3err_mkdir[] = {
  350         NFSERR_IO,
  351         NFSERR_IO,
  352         NFSERR_ACCES,
  353         NFSERR_EXIST,
  354         NFSERR_NOTDIR,
  355         NFSERR_NOSPC,
  356         NFSERR_ROFS,
  357         NFSERR_NAMETOL,
  358         NFSERR_DQUOT,
  359         NFSERR_STALE,
  360         NFSERR_BADHANDLE,
  361         NFSERR_NOTSUPP,
  362         NFSERR_SERVERFAULT,
  363         0,
  364 };
  365 
  366 static const short nfsv3err_symlink[] = {
  367         NFSERR_IO,
  368         NFSERR_IO,
  369         NFSERR_ACCES,
  370         NFSERR_EXIST,
  371         NFSERR_NOTDIR,
  372         NFSERR_NOSPC,
  373         NFSERR_ROFS,
  374         NFSERR_NAMETOL,
  375         NFSERR_DQUOT,
  376         NFSERR_STALE,
  377         NFSERR_BADHANDLE,
  378         NFSERR_NOTSUPP,
  379         NFSERR_SERVERFAULT,
  380         0,
  381 };
  382 
  383 static const short nfsv3err_mknod[] = {
  384         NFSERR_IO,
  385         NFSERR_IO,
  386         NFSERR_ACCES,
  387         NFSERR_EXIST,
  388         NFSERR_NOTDIR,
  389         NFSERR_NOSPC,
  390         NFSERR_ROFS,
  391         NFSERR_NAMETOL,
  392         NFSERR_DQUOT,
  393         NFSERR_STALE,
  394         NFSERR_BADHANDLE,
  395         NFSERR_NOTSUPP,
  396         NFSERR_SERVERFAULT,
  397         NFSERR_BADTYPE,
  398         0,
  399 };
  400 
  401 static const short nfsv3err_remove[] = {
  402         NFSERR_IO,
  403         NFSERR_NOENT,
  404         NFSERR_IO,
  405         NFSERR_ACCES,
  406         NFSERR_NOTDIR,
  407         NFSERR_ROFS,
  408         NFSERR_NAMETOL,
  409         NFSERR_STALE,
  410         NFSERR_BADHANDLE,
  411         NFSERR_SERVERFAULT,
  412         0,
  413 };
  414 
  415 static const short nfsv3err_rmdir[] = {
  416         NFSERR_IO,
  417         NFSERR_NOENT,
  418         NFSERR_IO,
  419         NFSERR_ACCES,
  420         NFSERR_EXIST,
  421         NFSERR_NOTDIR,
  422         NFSERR_INVAL,
  423         NFSERR_ROFS,
  424         NFSERR_NAMETOL,
  425         NFSERR_NOTEMPTY,
  426         NFSERR_STALE,
  427         NFSERR_BADHANDLE,
  428         NFSERR_NOTSUPP,
  429         NFSERR_SERVERFAULT,
  430         0,
  431 };
  432 
  433 static const short nfsv3err_rename[] = {
  434         NFSERR_IO,
  435         NFSERR_NOENT,
  436         NFSERR_IO,
  437         NFSERR_ACCES,
  438         NFSERR_EXIST,
  439         NFSERR_XDEV,
  440         NFSERR_NOTDIR,
  441         NFSERR_ISDIR,
  442         NFSERR_INVAL,
  443         NFSERR_NOSPC,
  444         NFSERR_ROFS,
  445         NFSERR_MLINK,
  446         NFSERR_NAMETOL,
  447         NFSERR_NOTEMPTY,
  448         NFSERR_DQUOT,
  449         NFSERR_STALE,
  450         NFSERR_BADHANDLE,
  451         NFSERR_NOTSUPP,
  452         NFSERR_SERVERFAULT,
  453         0,
  454 };
  455 
  456 static const short nfsv3err_link[] = {
  457         NFSERR_IO,
  458         NFSERR_IO,
  459         NFSERR_ACCES,
  460         NFSERR_EXIST,
  461         NFSERR_XDEV,
  462         NFSERR_NOTDIR,
  463         NFSERR_INVAL,
  464         NFSERR_NOSPC,
  465         NFSERR_ROFS,
  466         NFSERR_MLINK,
  467         NFSERR_NAMETOL,
  468         NFSERR_DQUOT,
  469         NFSERR_STALE,
  470         NFSERR_BADHANDLE,
  471         NFSERR_NOTSUPP,
  472         NFSERR_SERVERFAULT,
  473         0,
  474 };
  475 
  476 static const short nfsv3err_readdir[] = {
  477         NFSERR_IO,
  478         NFSERR_IO,
  479         NFSERR_ACCES,
  480         NFSERR_NOTDIR,
  481         NFSERR_STALE,
  482         NFSERR_BADHANDLE,
  483         NFSERR_BAD_COOKIE,
  484         NFSERR_TOOSMALL,
  485         NFSERR_SERVERFAULT,
  486         0,
  487 };
  488 
  489 static const short nfsv3err_readdirplus[] = {
  490         NFSERR_IO,
  491         NFSERR_IO,
  492         NFSERR_ACCES,
  493         NFSERR_NOTDIR,
  494         NFSERR_STALE,
  495         NFSERR_BADHANDLE,
  496         NFSERR_BAD_COOKIE,
  497         NFSERR_NOTSUPP,
  498         NFSERR_TOOSMALL,
  499         NFSERR_SERVERFAULT,
  500         0,
  501 };
  502 
  503 static const short nfsv3err_fsstat[] = {
  504         NFSERR_IO,
  505         NFSERR_IO,
  506         NFSERR_STALE,
  507         NFSERR_BADHANDLE,
  508         NFSERR_SERVERFAULT,
  509         0,
  510 };
  511 
  512 static const short nfsv3err_fsinfo[] = {
  513         NFSERR_STALE,
  514         NFSERR_STALE,
  515         NFSERR_BADHANDLE,
  516         NFSERR_SERVERFAULT,
  517         0,
  518 };
  519 
  520 static const short nfsv3err_pathconf[] = {
  521         NFSERR_STALE,
  522         NFSERR_STALE,
  523         NFSERR_BADHANDLE,
  524         NFSERR_SERVERFAULT,
  525         0,
  526 };
  527 
  528 static const short nfsv3err_commit[] = {
  529         NFSERR_IO,
  530         NFSERR_IO,
  531         NFSERR_STALE,
  532         NFSERR_BADHANDLE,
  533         NFSERR_SERVERFAULT,
  534         0,
  535 };
  536 
  537 static const short * const nfsrv_v3errmap[] = {
  538         nfsv3err_null,
  539         nfsv3err_getattr,
  540         nfsv3err_setattr,
  541         nfsv3err_lookup,
  542         nfsv3err_access,
  543         nfsv3err_readlink,
  544         nfsv3err_read,
  545         nfsv3err_write,
  546         nfsv3err_create,
  547         nfsv3err_mkdir,
  548         nfsv3err_symlink,
  549         nfsv3err_mknod,
  550         nfsv3err_remove,
  551         nfsv3err_rmdir,
  552         nfsv3err_rename,
  553         nfsv3err_link,
  554         nfsv3err_readdir,
  555         nfsv3err_readdirplus,
  556         nfsv3err_fsstat,
  557         nfsv3err_fsinfo,
  558         nfsv3err_pathconf,
  559         nfsv3err_commit,
  560 };
  561 
  562 extern struct nfsrtt nfsrtt;
  563 
  564 u_long nfsdirhashmask;
  565 
  566 int nfs_webnamei(struct nameidata *, struct vnode *, struct proc *);
  567 
  568 /*
  569  * Create the header for an rpc request packet
  570  * The hsiz is the size of the rest of the nfs request header.
  571  * (just used to decide if a cluster is a good idea)
  572  */
  573 struct mbuf *
  574 nfsm_reqh(struct nfsnode *np, u_long procid, int hsiz, char **bposp)
  575 {
  576         struct mbuf *mb;
  577         char *bpos;
  578 
  579         mb = m_get(M_WAIT, MT_DATA);
  580         MCLAIM(mb, &nfs_mowner);
  581         if (hsiz >= MINCLSIZE)
  582                 m_clget(mb, M_WAIT);
  583         mb->m_len = 0;
  584         bpos = mtod(mb, void *);
  585 
  586         /* Finally, return values */
  587         *bposp = bpos;
  588         return (mb);
  589 }
  590 
  591 /*
  592  * Build the RPC header and fill in the authorization info.
  593  * The authorization string argument is only used when the credentials
  594  * come from outside of the kernel.
  595  * Returns the head of the mbuf list.
  596  */
  597 struct mbuf *
  598 nfsm_rpchead(kauth_cred_t cr, int nmflag, int procid,
  599         int auth_type, int auth_len, char *auth_str, int verf_len,
  600         char *verf_str, struct mbuf *mrest, int mrest_len,
  601         struct mbuf **mbp, uint32_t *xidp)
  602 {
  603         struct mbuf *mb;
  604         u_int32_t *tl;
  605         char *bpos;
  606         int i;
  607         struct mbuf *mreq;
  608         int siz, grpsiz, authsiz;
  609 
  610         authsiz = nfsm_rndup(auth_len);
  611         mb = m_gethdr(M_WAIT, MT_DATA);
  612         MCLAIM(mb, &nfs_mowner);
  613         if ((authsiz + 10 * NFSX_UNSIGNED) >= MINCLSIZE) {
  614                 m_clget(mb, M_WAIT);
  615         } else if ((authsiz + 10 * NFSX_UNSIGNED) < MHLEN) {
  616                 MH_ALIGN(mb, authsiz + 10 * NFSX_UNSIGNED);
  617         } else {
  618                 MH_ALIGN(mb, 8 * NFSX_UNSIGNED);
  619         }
  620         mb->m_len = 0;
  621         mreq = mb;
  622         bpos = mtod(mb, void *);
  623 
  624         /*
  625          * First the RPC header.
  626          */
  627         nfsm_build(tl, u_int32_t *, 8 * NFSX_UNSIGNED);
  628 
  629         *tl++ = *xidp = nfs_getxid();
  630         *tl++ = rpc_call;
  631         *tl++ = rpc_vers;
  632         *tl++ = txdr_unsigned(NFS_PROG);
  633         if (nmflag & NFSMNT_NFSV3)
  634                 *tl++ = txdr_unsigned(NFS_VER3);
  635         else
  636                 *tl++ = txdr_unsigned(NFS_VER2);
  637         if (nmflag & NFSMNT_NFSV3)
  638                 *tl++ = txdr_unsigned(procid);
  639         else
  640                 *tl++ = txdr_unsigned(nfsv2_procid[procid]);
  641 
  642         /*
  643          * And then the authorization cred.
  644          */
  645         *tl++ = txdr_unsigned(auth_type);
  646         *tl = txdr_unsigned(authsiz);
  647         switch (auth_type) {
  648         case RPCAUTH_UNIX:
  649                 nfsm_build(tl, u_int32_t *, auth_len);
  650                 *tl++ = 0;              /* stamp ?? */
  651                 *tl++ = 0;              /* NULL hostname */
  652                 *tl++ = txdr_unsigned(kauth_cred_geteuid(cr));
  653                 *tl++ = txdr_unsigned(kauth_cred_getegid(cr));
  654                 grpsiz = (auth_len >> 2) - 5;
  655                 *tl++ = txdr_unsigned(grpsiz);
  656                 for (i = 0; i < grpsiz; i++)
  657                         *tl++ = txdr_unsigned(kauth_cred_group(cr, i)); /* XXX elad review */
  658                 break;
  659         case RPCAUTH_KERB4:
  660                 siz = auth_len;
  661                 while (siz > 0) {
  662                         if (M_TRAILINGSPACE(mb) == 0) {
  663                                 struct mbuf *mb2;
  664                                 mb2 = m_get(M_WAIT, MT_DATA);
  665                                 MCLAIM(mb2, &nfs_mowner);
  666                                 if (siz >= MINCLSIZE)
  667                                         m_clget(mb2, M_WAIT);
  668                                 mb->m_next = mb2;
  669                                 mb = mb2;
  670                                 mb->m_len = 0;
  671                                 bpos = mtod(mb, void *);
  672                         }
  673                         i = min(siz, M_TRAILINGSPACE(mb));
  674                         memcpy(bpos, auth_str, i);
  675                         mb->m_len += i;
  676                         auth_str += i;
  677                         bpos += i;
  678                         siz -= i;
  679                 }
  680                 if ((siz = (nfsm_rndup(auth_len) - auth_len)) > 0) {
  681                         for (i = 0; i < siz; i++)
  682                                 *bpos++ = '\0';
  683                         mb->m_len += siz;
  684                 }
  685                 break;
  686         };
  687 
  688         /*
  689          * And the verifier...
  690          */
  691         nfsm_build(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
  692         if (verf_str) {
  693                 *tl++ = txdr_unsigned(RPCAUTH_KERB4);
  694                 *tl = txdr_unsigned(verf_len);
  695                 siz = verf_len;
  696                 while (siz > 0) {
  697                         if (M_TRAILINGSPACE(mb) == 0) {
  698                                 struct mbuf *mb2;
  699                                 mb2 = m_get(M_WAIT, MT_DATA);
  700                                 MCLAIM(mb2, &nfs_mowner);
  701                                 if (siz >= MINCLSIZE)
  702                                         m_clget(mb2, M_WAIT);
  703                                 mb->m_next = mb2;
  704                                 mb = mb2;
  705                                 mb->m_len = 0;
  706                                 bpos = mtod(mb, void *);
  707                         }
  708                         i = min(siz, M_TRAILINGSPACE(mb));
  709                         memcpy(bpos, verf_str, i);
  710                         mb->m_len += i;
  711                         verf_str += i;
  712                         bpos += i;
  713                         siz -= i;
  714                 }
  715                 if ((siz = (nfsm_rndup(verf_len) - verf_len)) > 0) {
  716                         for (i = 0; i < siz; i++)
  717                                 *bpos++ = '\0';
  718                         mb->m_len += siz;
  719                 }
  720         } else {
  721                 *tl++ = txdr_unsigned(RPCAUTH_NULL);
  722                 *tl = 0;
  723         }
  724         mb->m_next = mrest;
  725         mreq->m_pkthdr.len = authsiz + 10 * NFSX_UNSIGNED + mrest_len;
  726         mreq->m_pkthdr.rcvif = (struct ifnet *)0;
  727         *mbp = mb;
  728         return (mreq);
  729 }
  730 
  731 /*
  732  * copies mbuf chain to the uio scatter/gather list
  733  */
  734 int
  735 nfsm_mbuftouio(struct mbuf **mrep, struct uio *uiop, int siz, char **dpos)
  736 {
  737         char *mbufcp, *uiocp;
  738         int xfer, left, len;
  739         struct mbuf *mp;
  740         long uiosiz, rem;
  741         int error = 0;
  742 
  743         mp = *mrep;
  744         mbufcp = *dpos;
  745         len = mtod(mp, char *) + mp->m_len - mbufcp;
  746         rem = nfsm_rndup(siz)-siz;
  747         while (siz > 0) {
  748                 if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL)
  749                         return (EFBIG);
  750                 left = uiop->uio_iov->iov_len;
  751                 uiocp = uiop->uio_iov->iov_base;
  752                 if (left > siz)
  753                         left = siz;
  754                 uiosiz = left;
  755                 while (left > 0) {
  756                         while (len == 0) {
  757                                 mp = mp->m_next;
  758                                 if (mp == NULL)
  759                                         return (EBADRPC);
  760                                 mbufcp = mtod(mp, void *);
  761                                 len = mp->m_len;
  762                         }
  763                         xfer = (left > len) ? len : left;
  764                         error = copyout_vmspace(uiop->uio_vmspace, mbufcp,
  765                             uiocp, xfer);
  766                         if (error) {
  767                                 return error;
  768                         }
  769                         left -= xfer;
  770                         len -= xfer;
  771                         mbufcp += xfer;
  772                         uiocp += xfer;
  773                         uiop->uio_offset += xfer;
  774                         uiop->uio_resid -= xfer;
  775                 }
  776                 if (uiop->uio_iov->iov_len <= siz) {
  777                         uiop->uio_iovcnt--;
  778                         uiop->uio_iov++;
  779                 } else {
  780                         uiop->uio_iov->iov_base =
  781                             (char *)uiop->uio_iov->iov_base + uiosiz;
  782                         uiop->uio_iov->iov_len -= uiosiz;
  783                 }
  784                 siz -= uiosiz;
  785         }
  786         *dpos = mbufcp;
  787         *mrep = mp;
  788         if (rem > 0) {
  789                 if (len < rem)
  790                         error = nfs_adv(mrep, dpos, rem, len);
  791                 else
  792                         *dpos += rem;
  793         }
  794         return (error);
  795 }
  796 
  797 /*
  798  * copies a uio scatter/gather list to an mbuf chain.
  799  * NOTE: can ony handle iovcnt == 1
  800  */
  801 int
  802 nfsm_uiotombuf(struct uio *uiop, struct mbuf **mq, int siz, char **bpos)
  803 {
  804         char *uiocp;
  805         struct mbuf *mp, *mp2;
  806         int xfer, left, mlen;
  807         int uiosiz, clflg, rem;
  808         char *cp;
  809         int error;
  810 
  811 #ifdef DIAGNOSTIC
  812         if (uiop->uio_iovcnt != 1)
  813                 panic("nfsm_uiotombuf: iovcnt != 1");
  814 #endif
  815 
  816         if (siz > MLEN)         /* or should it >= MCLBYTES ?? */
  817                 clflg = 1;
  818         else
  819                 clflg = 0;
  820         rem = nfsm_rndup(siz)-siz;
  821         mp = mp2 = *mq;
  822         while (siz > 0) {
  823                 left = uiop->uio_iov->iov_len;
  824                 uiocp = uiop->uio_iov->iov_base;
  825                 if (left > siz)
  826                         left = siz;
  827                 uiosiz = left;
  828                 while (left > 0) {
  829                         mlen = M_TRAILINGSPACE(mp);
  830                         if (mlen == 0) {
  831                                 mp = m_get(M_WAIT, MT_DATA);
  832                                 MCLAIM(mp, &nfs_mowner);
  833                                 if (clflg)
  834                                         m_clget(mp, M_WAIT);
  835                                 mp->m_len = 0;
  836                                 mp2->m_next = mp;
  837                                 mp2 = mp;
  838                                 mlen = M_TRAILINGSPACE(mp);
  839                         }
  840                         xfer = (left > mlen) ? mlen : left;
  841                         cp = mtod(mp, char *) + mp->m_len;
  842                         error = copyin_vmspace(uiop->uio_vmspace, uiocp, cp,
  843                             xfer);
  844                         if (error) {
  845                                 /* XXX */
  846                         }
  847                         mp->m_len += xfer;
  848                         left -= xfer;
  849                         uiocp += xfer;
  850                         uiop->uio_offset += xfer;
  851                         uiop->uio_resid -= xfer;
  852                 }
  853                 uiop->uio_iov->iov_base = (char *)uiop->uio_iov->iov_base +
  854                     uiosiz;
  855                 uiop->uio_iov->iov_len -= uiosiz;
  856                 siz -= uiosiz;
  857         }
  858         if (rem > 0) {
  859                 if (rem > M_TRAILINGSPACE(mp)) {
  860                         mp = m_get(M_WAIT, MT_DATA);
  861                         MCLAIM(mp, &nfs_mowner);
  862                         mp->m_len = 0;
  863                         mp2->m_next = mp;
  864                 }
  865                 cp = mtod(mp, char *) + mp->m_len;
  866                 for (left = 0; left < rem; left++)
  867                         *cp++ = '\0';
  868                 mp->m_len += rem;
  869                 *bpos = cp;
  870         } else
  871                 *bpos = mtod(mp, char *) + mp->m_len;
  872         *mq = mp;
  873         return (0);
  874 }
  875 
  876 /*
  877  * Get at least "siz" bytes of correctly aligned data.
  878  * When called the mbuf pointers are not necessarily correct,
  879  * dsosp points to what ought to be in m_data and left contains
  880  * what ought to be in m_len.
  881  * This is used by the macros nfsm_dissect and nfsm_dissecton for tough
  882  * cases. (The macros use the vars. dpos and dpos2)
  883  */
  884 int
  885 nfsm_disct(struct mbuf **mdp, char **dposp, int siz, int left, char **cp2)
  886 {
  887         struct mbuf *m1, *m2;
  888         struct mbuf *havebuf = NULL;
  889         char *src = *dposp;
  890         char *dst;
  891         int len;
  892 
  893 #ifdef DEBUG
  894         if (left < 0)
  895                 panic("nfsm_disct: left < 0");
  896 #endif
  897         m1 = *mdp;
  898         /*
  899          * Skip through the mbuf chain looking for an mbuf with
  900          * some data. If the first mbuf found has enough data
  901          * and it is correctly aligned return it.
  902          */
  903         while (left == 0) {
  904                 havebuf = m1;
  905                 *mdp = m1 = m1->m_next;
  906                 if (m1 == NULL)
  907                         return (EBADRPC);
  908                 src = mtod(m1, void *);
  909                 left = m1->m_len;
  910                 /*
  911                  * If we start a new mbuf and it is big enough
  912                  * and correctly aligned just return it, don't
  913                  * do any pull up.
  914                  */
  915                 if (left >= siz && nfsm_aligned(src)) {
  916                         *cp2 = src;
  917                         *dposp = src + siz;
  918                         return (0);
  919                 }
  920         }
  921         if ((m1->m_flags & M_EXT) != 0) {
  922                 if (havebuf && M_TRAILINGSPACE(havebuf) >= siz &&
  923                     nfsm_aligned(mtod(havebuf, char *) + havebuf->m_len)) {
  924                         /*
  925                          * If the first mbuf with data has external data
  926                          * and there is a previous mbuf with some trailing
  927                          * space, use it to move the data into.
  928                          */
  929                         m2 = m1;
  930                         *mdp = m1 = havebuf;
  931                         *cp2 = mtod(m1, char *) + m1->m_len;
  932                 } else if (havebuf) {
  933                         /*
  934                          * If the first mbuf has a external data
  935                          * and there is no previous empty mbuf
  936                          * allocate a new mbuf and move the external
  937                          * data to the new mbuf. Also make the first
  938                          * mbuf look empty.
  939                          */
  940                         m2 = m1;
  941                         *mdp = m1 = m_get(M_WAIT, MT_DATA);
  942                         MCLAIM(m1, m2->m_owner);
  943                         if ((m2->m_flags & M_PKTHDR) != 0) {
  944                                 /* XXX MOVE */
  945                                 M_COPY_PKTHDR(m1, m2);
  946                                 m_tag_delete_chain(m2, NULL);
  947                                 m2->m_flags &= ~M_PKTHDR;
  948                         }
  949                         if (havebuf) {
  950                                 havebuf->m_next = m1;
  951                         }
  952                         m1->m_next = m2;
  953                         MRESETDATA(m1);
  954                         m1->m_len = 0;
  955                         m2->m_data = src;
  956                         m2->m_len = left;
  957                         *cp2 = mtod(m1, char *);
  958                 } else {
  959                         struct mbuf **nextp = &m1->m_next;
  960 
  961                         m1->m_len -= left;
  962                         do {
  963                                 m2 = m_get(M_WAIT, MT_DATA);
  964                                 MCLAIM(m2, m1->m_owner);
  965                                 if (left >= MINCLSIZE) {
  966                                         MCLGET(m2, M_WAIT);
  967                                 }
  968                                 m2->m_next = *nextp;
  969                                 *nextp = m2;
  970                                 nextp = &m2->m_next;
  971                                 len = (m2->m_flags & M_EXT) != 0 ?
  972                                     MCLBYTES : MLEN;
  973                                 if (len > left) {
  974                                         len = left;
  975                                 }
  976                                 memcpy(mtod(m2, char *), src, len);
  977                                 m2->m_len = len;
  978                                 src += len;
  979                                 left -= len;
  980                         } while (left > 0);
  981                         *mdp = m1 = m1->m_next;
  982                         m2 = m1->m_next;
  983                         *cp2 = mtod(m1, char *);
  984                 }
  985         } else {
  986                 /*
  987                  * If the first mbuf has no external data
  988                  * move the data to the front of the mbuf.
  989                  */
  990                 MRESETDATA(m1);
  991                 dst = mtod(m1, char *);
  992                 if (dst != src) {
  993                         memmove(dst, src, left);
  994                 }
  995                 m1->m_len = left;
  996                 m2 = m1->m_next;
  997                 *cp2 = m1->m_data;
  998         }
  999         *dposp = *cp2 + siz;
 1000         /*
 1001          * Loop through mbufs pulling data up into first mbuf until
 1002          * the first mbuf is full or there is no more data to
 1003          * pullup.
 1004          */
 1005         dst = mtod(m1, char *) + m1->m_len;
 1006         while ((len = M_TRAILINGSPACE(m1)) != 0 && m2) {
 1007                 if ((len = min(len, m2->m_len)) != 0) {
 1008                         memcpy(dst, mtod(m2, char *), len);
 1009                 }
 1010                 m1->m_len += len;
 1011                 dst += len;
 1012                 m2->m_data += len;
 1013                 m2->m_len -= len;
 1014                 m2 = m2->m_next;
 1015         }
 1016         if (m1->m_len < siz)
 1017                 return (EBADRPC);
 1018         return (0);
 1019 }
 1020 
 1021 /*
 1022  * Advance the position in the mbuf chain.
 1023  */
 1024 int
 1025 nfs_adv(struct mbuf **mdp, char **dposp, int offs, int left)
 1026 {
 1027         struct mbuf *m;
 1028         int s;
 1029 
 1030         m = *mdp;
 1031         s = left;
 1032         while (s < offs) {
 1033                 offs -= s;
 1034                 m = m->m_next;
 1035                 if (m == NULL)
 1036                         return (EBADRPC);
 1037                 s = m->m_len;
 1038         }
 1039         *mdp = m;
 1040         *dposp = mtod(m, char *) + offs;
 1041         return (0);
 1042 }
 1043 
 1044 /*
 1045  * Copy a string into mbufs for the hard cases...
 1046  */
 1047 int
 1048 nfsm_strtmbuf(struct mbuf **mb, char **bpos, const char *cp, long siz)
 1049 {
 1050         struct mbuf *m1 = NULL, *m2;
 1051         long left, xfer, len, tlen;
 1052         u_int32_t *tl;
 1053         int putsize;
 1054 
 1055         putsize = 1;
 1056         m2 = *mb;
 1057         left = M_TRAILINGSPACE(m2);
 1058         if (left > 0) {
 1059                 tl = ((u_int32_t *)(*bpos));
 1060                 *tl++ = txdr_unsigned(siz);
 1061                 putsize = 0;
 1062                 left -= NFSX_UNSIGNED;
 1063                 m2->m_len += NFSX_UNSIGNED;
 1064                 if (left > 0) {
 1065                         memcpy((void *) tl, cp, left);
 1066                         siz -= left;
 1067                         cp += left;
 1068                         m2->m_len += left;
 1069                         left = 0;
 1070                 }
 1071         }
 1072         /* Loop around adding mbufs */
 1073         while (siz > 0) {
 1074                 m1 = m_get(M_WAIT, MT_DATA);
 1075                 MCLAIM(m1, &nfs_mowner);
 1076                 if (siz > MLEN)
 1077                         m_clget(m1, M_WAIT);
 1078                 m1->m_len = NFSMSIZ(m1);
 1079                 m2->m_next = m1;
 1080                 m2 = m1;
 1081                 tl = mtod(m1, u_int32_t *);
 1082                 tlen = 0;
 1083                 if (putsize) {
 1084                         *tl++ = txdr_unsigned(siz);
 1085                         m1->m_len -= NFSX_UNSIGNED;
 1086                         tlen = NFSX_UNSIGNED;
 1087                         putsize = 0;
 1088                 }
 1089                 if (siz < m1->m_len) {
 1090                         len = nfsm_rndup(siz);
 1091                         xfer = siz;
 1092                         if (xfer < len)
 1093                                 *(tl+(xfer>>2)) = 0;
 1094                 } else {
 1095                         xfer = len = m1->m_len;
 1096                 }
 1097                 memcpy((void *) tl, cp, xfer);
 1098                 m1->m_len = len+tlen;
 1099                 siz -= xfer;
 1100                 cp += xfer;
 1101         }
 1102         *mb = m1;
 1103         *bpos = mtod(m1, char *) + m1->m_len;
 1104         return (0);
 1105 }
 1106 
 1107 /*
 1108  * Directory caching routines. They work as follows:
 1109  * - a cache is maintained per VDIR nfsnode.
 1110  * - for each offset cookie that is exported to userspace, and can
 1111  *   thus be thrown back at us as an offset to VOP_READDIR, store
 1112  *   information in the cache.
 1113  * - cached are:
 1114  *   - cookie itself
 1115  *   - blocknumber (essentially just a search key in the buffer cache)
 1116  *   - entry number in block.
 1117  *   - offset cookie of block in which this entry is stored
 1118  *   - 32 bit cookie if NFSMNT_XLATECOOKIE is used.
 1119  * - entries are looked up in a hash table
 1120  * - also maintained is an LRU list of entries, used to determine
 1121  *   which ones to delete if the cache grows too large.
 1122  * - if 32 <-> 64 translation mode is requested for a filesystem,
 1123  *   the cache also functions as a translation table
 1124  * - in the translation case, invalidating the cache does not mean
 1125  *   flushing it, but just marking entries as invalid, except for
 1126  *   the <64bit cookie, 32bitcookie> pair which is still valid, to
 1127  *   still be able to use the cache as a translation table.
 1128  * - 32 bit cookies are uniquely created by combining the hash table
 1129  *   entry value, and one generation count per hash table entry,
 1130  *   incremented each time an entry is appended to the chain.
 1131  * - the cache is invalidated each time a direcory is modified
 1132  * - sanity checks are also done; if an entry in a block turns
 1133  *   out not to have a matching cookie, the cache is invalidated
 1134  *   and a new block starting from the wanted offset is fetched from
 1135  *   the server.
 1136  * - directory entries as read from the server are extended to contain
 1137  *   the 64bit and, optionally, the 32bit cookies, for sanity checking
 1138  *   the cache and exporting them to userspace through the cookie
 1139  *   argument to VOP_READDIR.
 1140  */
 1141 
 1142 u_long
 1143 nfs_dirhash(off_t off)
 1144 {
 1145         int i;
 1146         char *cp = (char *)&off;
 1147         u_long sum = 0L;
 1148 
 1149         for (i = 0 ; i < sizeof (off); i++)
 1150                 sum += *cp++;
 1151 
 1152         return sum;
 1153 }
 1154 
 1155 #define _NFSDC_MTX(np)          (&NFSTOV(np)->v_interlock)
 1156 #define NFSDC_LOCK(np)          mutex_enter(_NFSDC_MTX(np))
 1157 #define NFSDC_UNLOCK(np)        mutex_exit(_NFSDC_MTX(np))
 1158 #define NFSDC_ASSERT_LOCKED(np) KASSERT(mutex_owned(_NFSDC_MTX(np)))
 1159 
 1160 void
 1161 nfs_initdircache(struct vnode *vp)
 1162 {
 1163         struct nfsnode *np = VTONFS(vp);
 1164         struct nfsdirhashhead *dircache;
 1165 
 1166         dircache = hashinit(NFS_DIRHASHSIZ, HASH_LIST, true,
 1167             &nfsdirhashmask);
 1168 
 1169         NFSDC_LOCK(np);
 1170         if (np->n_dircache == NULL) {
 1171                 np->n_dircachesize = 0;
 1172                 np->n_dircache = dircache;
 1173                 dircache = NULL;
 1174                 TAILQ_INIT(&np->n_dirchain);
 1175         }
 1176         NFSDC_UNLOCK(np);
 1177         if (dircache)
 1178                 hashdone(dircache, HASH_LIST, nfsdirhashmask);
 1179 }
 1180 
 1181 void
 1182 nfs_initdirxlatecookie(struct vnode *vp)
 1183 {
 1184         struct nfsnode *np = VTONFS(vp);
 1185         unsigned *dirgens;
 1186 
 1187         KASSERT(VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_XLATECOOKIE);
 1188 
 1189         dirgens = kmem_zalloc(NFS_DIRHASHSIZ * sizeof(unsigned), KM_SLEEP);
 1190         NFSDC_LOCK(np);
 1191         if (np->n_dirgens == NULL) {
 1192                 np->n_dirgens = dirgens;
 1193                 dirgens = NULL;
 1194         }
 1195         NFSDC_UNLOCK(np);
 1196         if (dirgens)
 1197                 kmem_free(dirgens, NFS_DIRHASHSIZ * sizeof(unsigned));
 1198 }
 1199 
 1200 static const struct nfsdircache dzero;
 1201 
 1202 static void nfs_unlinkdircache(struct nfsnode *np, struct nfsdircache *);
 1203 static void nfs_putdircache_unlocked(struct nfsnode *,
 1204     struct nfsdircache *);
 1205 
 1206 static void
 1207 nfs_unlinkdircache(struct nfsnode *np, struct nfsdircache *ndp)
 1208 {
 1209 
 1210         NFSDC_ASSERT_LOCKED(np);
 1211         KASSERT(ndp != &dzero);
 1212 
 1213         if (LIST_NEXT(ndp, dc_hash) == (void *)-1)
 1214                 return;
 1215 
 1216         TAILQ_REMOVE(&np->n_dirchain, ndp, dc_chain);
 1217         LIST_REMOVE(ndp, dc_hash);
 1218         LIST_NEXT(ndp, dc_hash) = (void *)-1; /* mark as unlinked */
 1219 
 1220         nfs_putdircache_unlocked(np, ndp);
 1221 }
 1222 
 1223 void
 1224 nfs_putdircache(struct nfsnode *np, struct nfsdircache *ndp)
 1225 {
 1226         int ref;
 1227 
 1228         if (ndp == &dzero)
 1229                 return;
 1230 
 1231         KASSERT(ndp->dc_refcnt > 0);
 1232         NFSDC_LOCK(np);
 1233         ref = --ndp->dc_refcnt;
 1234         NFSDC_UNLOCK(np);
 1235 
 1236         if (ref == 0)
 1237                 kmem_free(ndp, sizeof(*ndp));
 1238 }
 1239 
 1240 static void
 1241 nfs_putdircache_unlocked(struct nfsnode *np, struct nfsdircache *ndp)
 1242 {
 1243         int ref;
 1244 
 1245         NFSDC_ASSERT_LOCKED(np);
 1246 
 1247         if (ndp == &dzero)
 1248                 return;
 1249 
 1250         KASSERT(ndp->dc_refcnt > 0);
 1251         ref = --ndp->dc_refcnt;
 1252         if (ref == 0)
 1253                 kmem_free(ndp, sizeof(*ndp));
 1254 }
 1255 
 1256 struct nfsdircache *
 1257 nfs_searchdircache(struct vnode *vp, off_t off, int do32, int *hashent)
 1258 {
 1259         struct nfsdirhashhead *ndhp;
 1260         struct nfsdircache *ndp = NULL;
 1261         struct nfsnode *np = VTONFS(vp);
 1262         unsigned ent;
 1263 
 1264         /*
 1265          * Zero is always a valid cookie.
 1266          */
 1267         if (off == 0)
 1268                 /* XXXUNCONST */
 1269                 return (struct nfsdircache *)__UNCONST(&dzero);
 1270 
 1271         if (!np->n_dircache)
 1272                 return NULL;
 1273 
 1274         /*
 1275          * We use a 32bit cookie as search key, directly reconstruct
 1276          * the hashentry. Else use the hashfunction.
 1277          */
 1278         if (do32) {
 1279                 ent = (u_int32_t)off >> 24;
 1280                 if (ent >= NFS_DIRHASHSIZ)
 1281                         return NULL;
 1282                 ndhp = &np->n_dircache[ent];
 1283         } else {
 1284                 ndhp = NFSDIRHASH(np, off);
 1285         }
 1286 
 1287         if (hashent)
 1288                 *hashent = (int)(ndhp - np->n_dircache);
 1289 
 1290         NFSDC_LOCK(np);
 1291         if (do32) {
 1292                 LIST_FOREACH(ndp, ndhp, dc_hash) {
 1293                         if (ndp->dc_cookie32 == (u_int32_t)off) {
 1294                                 /*
 1295                                  * An invalidated entry will become the
 1296                                  * start of a new block fetched from
 1297                                  * the server.
 1298                                  */
 1299                                 if (ndp->dc_flags & NFSDC_INVALID) {
 1300                                         ndp->dc_blkcookie = ndp->dc_cookie;
 1301                                         ndp->dc_entry = 0;
 1302                                         ndp->dc_flags &= ~NFSDC_INVALID;
 1303                                 }
 1304                                 break;
 1305                         }
 1306                 }
 1307         } else {
 1308                 LIST_FOREACH(ndp, ndhp, dc_hash) {
 1309                         if (ndp->dc_cookie == off)
 1310                                 break;
 1311                 }
 1312         }
 1313         if (ndp != NULL)
 1314                 ndp->dc_refcnt++;
 1315         NFSDC_UNLOCK(np);
 1316         return ndp;
 1317 }
 1318 
 1319 
 1320 struct nfsdircache *
 1321 nfs_enterdircache(struct vnode *vp, off_t off, off_t blkoff, int en,
 1322     daddr_t blkno)
 1323 {
 1324         struct nfsnode *np = VTONFS(vp);
 1325         struct nfsdirhashhead *ndhp;
 1326         struct nfsdircache *ndp = NULL;
 1327         struct nfsdircache *newndp = NULL;
 1328         struct nfsmount *nmp = VFSTONFS(vp->v_mount);
 1329         int hashent = 0, gen, overwrite;        /* XXX: GCC */
 1330 
 1331         /*
 1332          * XXX refuse entries for offset 0. amd(8) erroneously sets
 1333          * cookie 0 for the '.' entry, making this necessary. This
 1334          * isn't so bad, as 0 is a special case anyway.
 1335          */
 1336         if (off == 0)
 1337                 /* XXXUNCONST */
 1338                 return (struct nfsdircache *)__UNCONST(&dzero);
 1339 
 1340         if (!np->n_dircache)
 1341                 /*
 1342                  * XXX would like to do this in nfs_nget but vtype
 1343                  * isn't known at that time.
 1344                  */
 1345                 nfs_initdircache(vp);
 1346 
 1347         if ((nmp->nm_flag & NFSMNT_XLATECOOKIE) && !np->n_dirgens)
 1348                 nfs_initdirxlatecookie(vp);
 1349 
 1350 retry:
 1351         ndp = nfs_searchdircache(vp, off, 0, &hashent);
 1352 
 1353         NFSDC_LOCK(np);
 1354         if (ndp && (ndp->dc_flags & NFSDC_INVALID) == 0) {
 1355                 /*
 1356                  * Overwriting an old entry. Check if it's the same.
 1357                  * If so, just return. If not, remove the old entry.
 1358                  */
 1359                 if (ndp->dc_blkcookie == blkoff && ndp->dc_entry == en)
 1360                         goto done;
 1361                 nfs_unlinkdircache(np, ndp);
 1362                 nfs_putdircache_unlocked(np, ndp);
 1363                 ndp = NULL;
 1364         }
 1365 
 1366         ndhp = &np->n_dircache[hashent];
 1367 
 1368         if (!ndp) {
 1369                 if (newndp == NULL) {
 1370                         NFSDC_UNLOCK(np);
 1371                         newndp = kmem_alloc(sizeof(*newndp), KM_SLEEP);
 1372                         newndp->dc_refcnt = 1;
 1373                         LIST_NEXT(newndp, dc_hash) = (void *)-1;
 1374                         goto retry;
 1375                 }
 1376                 ndp = newndp;
 1377                 newndp = NULL;
 1378                 overwrite = 0;
 1379                 if (nmp->nm_flag & NFSMNT_XLATECOOKIE) {
 1380                         /*
 1381                          * We're allocating a new entry, so bump the
 1382                          * generation number.
 1383                          */
 1384                         KASSERT(np->n_dirgens);
 1385                         gen = ++np->n_dirgens[hashent];
 1386                         if (gen == 0) {
 1387                                 np->n_dirgens[hashent]++;
 1388                                 gen++;
 1389                         }
 1390                         ndp->dc_cookie32 = (hashent << 24) | (gen & 0xffffff);
 1391                 }
 1392         } else
 1393                 overwrite = 1;
 1394 
 1395         ndp->dc_cookie = off;
 1396         ndp->dc_blkcookie = blkoff;
 1397         ndp->dc_entry = en;
 1398         ndp->dc_flags = 0;
 1399 
 1400         if (overwrite)
 1401                 goto done;
 1402 
 1403         /*
 1404          * If the maximum directory cookie cache size has been reached
 1405          * for this node, take one off the front. The idea is that
 1406          * directories are typically read front-to-back once, so that
 1407          * the oldest entries can be thrown away without much performance
 1408          * loss.
 1409          */
 1410         if (np->n_dircachesize == NFS_MAXDIRCACHE) {
 1411                 nfs_unlinkdircache(np, TAILQ_FIRST(&np->n_dirchain));
 1412         } else
 1413                 np->n_dircachesize++;
 1414 
 1415         KASSERT(ndp->dc_refcnt == 1);
 1416         LIST_INSERT_HEAD(ndhp, ndp, dc_hash);
 1417         TAILQ_INSERT_TAIL(&np->n_dirchain, ndp, dc_chain);
 1418         ndp->dc_refcnt++;
 1419 done:
 1420         KASSERT(ndp->dc_refcnt > 0);
 1421         NFSDC_UNLOCK(np);
 1422         if (newndp)
 1423                 nfs_putdircache(np, newndp);
 1424         return ndp;
 1425 }
 1426 
 1427 void
 1428 nfs_invaldircache(struct vnode *vp, int flags)
 1429 {
 1430         struct nfsnode *np = VTONFS(vp);
 1431         struct nfsdircache *ndp = NULL;
 1432         struct nfsmount *nmp = VFSTONFS(vp->v_mount);
 1433         const bool forcefree = flags & NFS_INVALDIRCACHE_FORCE;
 1434 
 1435 #ifdef DIAGNOSTIC
 1436         if (vp->v_type != VDIR)
 1437                 panic("nfs: invaldircache: not dir");
 1438 #endif
 1439 
 1440         if ((flags & NFS_INVALDIRCACHE_KEEPEOF) == 0)
 1441                 np->n_flag &= ~NEOFVALID;
 1442 
 1443         if (!np->n_dircache)
 1444                 return;
 1445 
 1446         NFSDC_LOCK(np);
 1447         if (!(nmp->nm_flag & NFSMNT_XLATECOOKIE) || forcefree) {
 1448                 while ((ndp = TAILQ_FIRST(&np->n_dirchain)) != NULL) {
 1449                         KASSERT(!forcefree || ndp->dc_refcnt == 1);
 1450                         nfs_unlinkdircache(np, ndp);
 1451                 }
 1452                 np->n_dircachesize = 0;
 1453                 if (forcefree && np->n_dirgens) {
 1454                         kmem_free(np->n_dirgens,
 1455                             NFS_DIRHASHSIZ * sizeof(unsigned));
 1456                         np->n_dirgens = NULL;
 1457                 }
 1458         } else {
 1459                 TAILQ_FOREACH(ndp, &np->n_dirchain, dc_chain)
 1460                         ndp->dc_flags |= NFSDC_INVALID;
 1461         }
 1462 
 1463         NFSDC_UNLOCK(np);
 1464 }
 1465 
 1466 /*
 1467  * Called once before VFS init to initialize shared and
 1468  * server-specific data structures.
 1469  */
 1470 static int
 1471 nfs_init0(void)
 1472 {
 1473 
 1474         nfsrtt.pos = 0;
 1475         rpc_vers = txdr_unsigned(RPC_VER2);
 1476         rpc_call = txdr_unsigned(RPC_CALL);
 1477         rpc_reply = txdr_unsigned(RPC_REPLY);
 1478         rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED);
 1479         rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED);
 1480         rpc_mismatch = txdr_unsigned(RPC_MISMATCH);
 1481         rpc_autherr = txdr_unsigned(RPC_AUTHERR);
 1482         rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX);
 1483         rpc_auth_kerb = txdr_unsigned(RPCAUTH_KERB4);
 1484         nfs_prog = txdr_unsigned(NFS_PROG);
 1485         nfs_true = txdr_unsigned(true);
 1486         nfs_false = txdr_unsigned(false);
 1487         nfs_xdrneg1 = txdr_unsigned(-1);
 1488         nfs_ticks = (hz * NFS_TICKINTVL + 500) / 1000;
 1489         if (nfs_ticks < 1)
 1490                 nfs_ticks = 1;
 1491         nfs_xid = arc4random();
 1492         nfsdreq_init();
 1493 
 1494         /*
 1495          * Initialize reply list and start timer
 1496          */
 1497         TAILQ_INIT(&nfs_reqq);
 1498         nfs_timer_init();
 1499         MOWNER_ATTACH(&nfs_mowner);
 1500 
 1501         return 0;
 1502 }
 1503 
 1504 /*
 1505  * This is disgusting, but it must support both modular and monolothic
 1506  * configurations.  For monolithic builds NFSSERVER may not imply NFS.
 1507  *
 1508  * Yuck.
 1509  */
 1510 void
 1511 nfs_init(void)
 1512 {
 1513         static ONCE_DECL(nfs_init_once);
 1514 
 1515         RUN_ONCE(&nfs_init_once, nfs_init0);
 1516 }
 1517 
 1518 void
 1519 nfs_fini(void)
 1520 {
 1521 
 1522         nfsdreq_fini();
 1523         nfs_timer_fini();
 1524         MOWNER_DETACH(&nfs_mowner);
 1525 }
 1526 
 1527 /*
 1528  * A fiddled version of m_adj() that ensures null fill to a 32-bit
 1529  * boundary and only trims off the back end
 1530  *
 1531  * 1. trim off 'len' bytes as m_adj(mp, -len).
 1532  * 2. add zero-padding 'nul' bytes at the end of the mbuf chain.
 1533  */
 1534 void
 1535 nfs_zeropad(struct mbuf *mp, int len, int nul)
 1536 {
 1537         struct mbuf *m;
 1538         int count;
 1539 
 1540         /*
 1541          * Trim from tail.  Scan the mbuf chain,
 1542          * calculating its length and finding the last mbuf.
 1543          * If the adjustment only affects this mbuf, then just
 1544          * adjust and return.  Otherwise, rescan and truncate
 1545          * after the remaining size.
 1546          */
 1547         count = 0;
 1548         m = mp;
 1549         for (;;) {
 1550                 count += m->m_len;
 1551                 if (m->m_next == NULL)
 1552                         break;
 1553                 m = m->m_next;
 1554         }
 1555 
 1556         KDASSERT(count >= len);
 1557 
 1558         if (m->m_len >= len) {
 1559                 m->m_len -= len;
 1560         } else {
 1561                 count -= len;
 1562                 /*
 1563                  * Correct length for chain is "count".
 1564                  * Find the mbuf with last data, adjust its length,
 1565                  * and toss data from remaining mbufs on chain.
 1566                  */
 1567                 for (m = mp; m; m = m->m_next) {
 1568                         if (m->m_len >= count) {
 1569                                 m->m_len = count;
 1570                                 break;
 1571                         }
 1572                         count -= m->m_len;
 1573                 }
 1574                 KASSERT(m && m->m_next);
 1575                 m_freem(m->m_next);
 1576                 m->m_next = NULL;
 1577         }
 1578 
 1579         KDASSERT(m->m_next == NULL);
 1580 
 1581         /*
 1582          * zero-padding.
 1583          */
 1584         if (nul > 0) {
 1585                 char *cp;
 1586                 int i;
 1587 
 1588                 if (M_ROMAP(m) || M_TRAILINGSPACE(m) < nul) {
 1589                         struct mbuf *n;
 1590 
 1591                         KDASSERT(MLEN >= nul);
 1592                         n = m_get(M_WAIT, MT_DATA);
 1593                         MCLAIM(n, &nfs_mowner);
 1594                         n->m_len = nul;
 1595                         n->m_next = NULL;
 1596                         m->m_next = n;
 1597                         cp = mtod(n, void *);
 1598                 } else {
 1599                         cp = mtod(m, char *) + m->m_len;
 1600                         m->m_len += nul;
 1601                 }
 1602                 for (i = 0; i < nul; i++)
 1603                         *cp++ = '\0';
 1604         }
 1605         return;
 1606 }
 1607 
 1608 /*
 1609  * Make these functions instead of macros, so that the kernel text size
 1610  * doesn't get too big...
 1611  */
 1612 void
 1613 nfsm_srvwcc(struct nfsrv_descript *nfsd, int before_ret, struct vattr *before_vap, int after_ret, struct vattr *after_vap, struct mbuf **mbp, char **bposp)
 1614 {
 1615         struct mbuf *mb = *mbp;
 1616         char *bpos = *bposp;
 1617         u_int32_t *tl;
 1618 
 1619         if (before_ret) {
 1620                 nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED);
 1621                 *tl = nfs_false;
 1622         } else {
 1623                 nfsm_build(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
 1624                 *tl++ = nfs_true;
 1625                 txdr_hyper(before_vap->va_size, tl);
 1626                 tl += 2;
 1627                 txdr_nfsv3time(&(before_vap->va_mtime), tl);
 1628                 tl += 2;
 1629                 txdr_nfsv3time(&(before_vap->va_ctime), tl);
 1630         }
 1631         *bposp = bpos;
 1632         *mbp = mb;
 1633         nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp);
 1634 }
 1635 
 1636 void
 1637 nfsm_srvpostopattr(struct nfsrv_descript *nfsd, int after_ret, struct vattr *after_vap, struct mbuf **mbp, char **bposp)
 1638 {
 1639         struct mbuf *mb = *mbp;
 1640         char *bpos = *bposp;
 1641         u_int32_t *tl;
 1642         struct nfs_fattr *fp;
 1643 
 1644         if (after_ret) {
 1645                 nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED);
 1646                 *tl = nfs_false;
 1647         } else {
 1648                 nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_V3FATTR);
 1649                 *tl++ = nfs_true;
 1650                 fp = (struct nfs_fattr *)tl;
 1651                 nfsm_srvfattr(nfsd, after_vap, fp);
 1652         }
 1653         *mbp = mb;
 1654         *bposp = bpos;
 1655 }
 1656 
 1657 void
 1658 nfsm_srvfattr(struct nfsrv_descript *nfsd, struct vattr *vap, struct nfs_fattr *fp)
 1659 {
 1660 
 1661         fp->fa_nlink = txdr_unsigned(vap->va_nlink);
 1662         fp->fa_uid = txdr_unsigned(vap->va_uid);
 1663         fp->fa_gid = txdr_unsigned(vap->va_gid);
 1664         if (nfsd->nd_flag & ND_NFSV3) {
 1665                 fp->fa_type = vtonfsv3_type(vap->va_type);
 1666                 fp->fa_mode = vtonfsv3_mode(vap->va_mode);
 1667                 txdr_hyper(vap->va_size, &fp->fa3_size);
 1668                 txdr_hyper(vap->va_bytes, &fp->fa3_used);
 1669                 fp->fa3_rdev.specdata1 = txdr_unsigned(major(vap->va_rdev));
 1670                 fp->fa3_rdev.specdata2 = txdr_unsigned(minor(vap->va_rdev));
 1671                 fp->fa3_fsid.nfsuquad[0] = 0;
 1672                 fp->fa3_fsid.nfsuquad[1] = txdr_unsigned(vap->va_fsid);
 1673                 txdr_hyper(vap->va_fileid, &fp->fa3_fileid);
 1674                 txdr_nfsv3time(&vap->va_atime, &fp->fa3_atime);
 1675                 txdr_nfsv3time(&vap->va_mtime, &fp->fa3_mtime);
 1676                 txdr_nfsv3time(&vap->va_ctime, &fp->fa3_ctime);
 1677         } else {
 1678                 fp->fa_type = vtonfsv2_type(vap->va_type);
 1679                 fp->fa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode);
 1680                 fp->fa2_size = txdr_unsigned(vap->va_size);
 1681                 fp->fa2_blocksize = txdr_unsigned(vap->va_blocksize);
 1682                 if (vap->va_type == VFIFO)
 1683                         fp->fa2_rdev = 0xffffffff;
 1684                 else
 1685                         fp->fa2_rdev = txdr_unsigned(vap->va_rdev);
 1686                 fp->fa2_blocks = txdr_unsigned(vap->va_bytes / NFS_FABLKSIZE);
 1687                 fp->fa2_fsid = txdr_unsigned(vap->va_fsid);
 1688                 fp->fa2_fileid = txdr_unsigned(vap->va_fileid);
 1689                 txdr_nfsv2time(&vap->va_atime, &fp->fa2_atime);
 1690                 txdr_nfsv2time(&vap->va_mtime, &fp->fa2_mtime);
 1691                 txdr_nfsv2time(&vap->va_ctime, &fp->fa2_ctime);
 1692         }
 1693 }
 1694 
 1695 /*
 1696  * This function compares two net addresses by family and returns true
 1697  * if they are the same host.
 1698  * If there is any doubt, return false.
 1699  * The AF_INET family is handled as a special case so that address mbufs
 1700  * don't need to be saved to store "struct in_addr", which is only 4 bytes.
 1701  */
 1702 int
 1703 netaddr_match(int family, union nethostaddr *haddr, struct mbuf *nam)
 1704 {
 1705         struct sockaddr_in *inetaddr;
 1706 
 1707         switch (family) {
 1708         case AF_INET:
 1709                 inetaddr = mtod(nam, struct sockaddr_in *);
 1710                 if (inetaddr->sin_family == AF_INET &&
 1711                     inetaddr->sin_addr.s_addr == haddr->had_inetaddr)
 1712                         return (1);
 1713                 break;
 1714         case AF_INET6:
 1715             {
 1716                 struct sockaddr_in6 *sin6_1, *sin6_2;
 1717 
 1718                 sin6_1 = mtod(nam, struct sockaddr_in6 *);
 1719                 sin6_2 = mtod(haddr->had_nam, struct sockaddr_in6 *);
 1720                 if (sin6_1->sin6_family == AF_INET6 &&
 1721                     IN6_ARE_ADDR_EQUAL(&sin6_1->sin6_addr, &sin6_2->sin6_addr))
 1722                         return 1;
 1723             }
 1724         default:
 1725                 break;
 1726         };
 1727         return (0);
 1728 }
 1729 
 1730 /*
 1731  * The write verifier has changed (probably due to a server reboot), so all
 1732  * PG_NEEDCOMMIT pages will have to be written again. Since they are marked
 1733  * as dirty or are being written out just now, all this takes is clearing
 1734  * the PG_NEEDCOMMIT flag. Once done the new write verifier can be set for
 1735  * the mount point.
 1736  */
 1737 void
 1738 nfs_clearcommit(struct mount *mp)
 1739 {
 1740         struct vnode *vp;
 1741         struct nfsnode *np;
 1742         struct vm_page *pg;
 1743         struct nfsmount *nmp = VFSTONFS(mp);
 1744 
 1745         rw_enter(&nmp->nm_writeverflock, RW_WRITER);
 1746         mutex_enter(&mntvnode_lock);
 1747         TAILQ_FOREACH(vp, &mp->mnt_vnodelist, v_mntvnodes) {
 1748                 KASSERT(vp->v_mount == mp);
 1749                 if (vp->v_type != VREG)
 1750                         continue;
 1751                 mutex_enter(&vp->v_interlock);
 1752                 if (vp->v_iflag & (VI_XLOCK | VI_CLEAN)) {
 1753                         mutex_exit(&vp->v_interlock);
 1754                         continue;
 1755                 }
 1756                 np = VTONFS(vp);
 1757                 np->n_pushlo = np->n_pushhi = np->n_pushedlo =
 1758                     np->n_pushedhi = 0;
 1759                 np->n_commitflags &=
 1760                     ~(NFS_COMMIT_PUSH_VALID | NFS_COMMIT_PUSHED_VALID);
 1761                 TAILQ_FOREACH(pg, &vp->v_uobj.memq, listq.queue) {
 1762                         pg->flags &= ~PG_NEEDCOMMIT;
 1763                 }
 1764                 mutex_exit(&vp->v_interlock);
 1765         }
 1766         mutex_exit(&mntvnode_lock);
 1767         mutex_enter(&nmp->nm_lock);
 1768         nmp->nm_iflag &= ~NFSMNT_STALEWRITEVERF;
 1769         mutex_exit(&nmp->nm_lock);
 1770         rw_exit(&nmp->nm_writeverflock);
 1771 }
 1772 
 1773 void
 1774 nfs_merge_commit_ranges(struct vnode *vp)
 1775 {
 1776         struct nfsnode *np = VTONFS(vp);
 1777 
 1778         KASSERT(np->n_commitflags & NFS_COMMIT_PUSH_VALID);
 1779 
 1780         if (!(np->n_commitflags & NFS_COMMIT_PUSHED_VALID)) {
 1781                 np->n_pushedlo = np->n_pushlo;
 1782                 np->n_pushedhi = np->n_pushhi;
 1783                 np->n_commitflags |= NFS_COMMIT_PUSHED_VALID;
 1784         } else {
 1785                 if (np->n_pushlo < np->n_pushedlo)
 1786                         np->n_pushedlo = np->n_pushlo;
 1787                 if (np->n_pushhi > np->n_pushedhi)
 1788                         np->n_pushedhi = np->n_pushhi;
 1789         }
 1790 
 1791         np->n_pushlo = np->n_pushhi = 0;
 1792         np->n_commitflags &= ~NFS_COMMIT_PUSH_VALID;
 1793 
 1794 #ifdef NFS_DEBUG_COMMIT
 1795         printf("merge: committed: %u - %u\n", (unsigned)np->n_pushedlo,
 1796             (unsigned)np->n_pushedhi);
 1797 #endif
 1798 }
 1799 
 1800 int
 1801 nfs_in_committed_range(struct vnode *vp, off_t off, off_t len)
 1802 {
 1803         struct nfsnode *np = VTONFS(vp);
 1804         off_t lo, hi;
 1805 
 1806         if (!(np->n_commitflags & NFS_COMMIT_PUSHED_VALID))
 1807                 return 0;
 1808         lo = off;
 1809         hi = lo + len;
 1810 
 1811         return (lo >= np->n_pushedlo && hi <= np->n_pushedhi);
 1812 }
 1813 
 1814 int
 1815 nfs_in_tobecommitted_range(struct vnode *vp, off_t off, off_t len)
 1816 {
 1817         struct nfsnode *np = VTONFS(vp);
 1818         off_t lo, hi;
 1819 
 1820         if (!(np->n_commitflags & NFS_COMMIT_PUSH_VALID))
 1821                 return 0;
 1822         lo = off;
 1823         hi = lo + len;
 1824 
 1825         return (lo >= np->n_pushlo && hi <= np->n_pushhi);
 1826 }
 1827 
 1828 void
 1829 nfs_add_committed_range(struct vnode *vp, off_t off, off_t len)
 1830 {
 1831         struct nfsnode *np = VTONFS(vp);
 1832         off_t lo, hi;
 1833 
 1834         lo = off;
 1835         hi = lo + len;
 1836 
 1837         if (!(np->n_commitflags & NFS_COMMIT_PUSHED_VALID)) {
 1838                 np->n_pushedlo = lo;
 1839                 np->n_pushedhi = hi;
 1840                 np->n_commitflags |= NFS_COMMIT_PUSHED_VALID;
 1841         } else {
 1842                 if (hi > np->n_pushedhi)
 1843                         np->n_pushedhi = hi;
 1844                 if (lo < np->n_pushedlo)
 1845                         np->n_pushedlo = lo;
 1846         }
 1847 #ifdef NFS_DEBUG_COMMIT
 1848         printf("add: committed: %u - %u\n", (unsigned)np->n_pushedlo,
 1849             (unsigned)np->n_pushedhi);
 1850 #endif
 1851 }
 1852 
 1853 void
 1854 nfs_del_committed_range(struct vnode *vp, off_t off, off_t len)
 1855 {
 1856         struct nfsnode *np = VTONFS(vp);
 1857         off_t lo, hi;
 1858 
 1859         if (!(np->n_commitflags & NFS_COMMIT_PUSHED_VALID))
 1860                 return;
 1861 
 1862         lo = off;
 1863         hi = lo + len;
 1864 
 1865         if (lo > np->n_pushedhi || hi < np->n_pushedlo)
 1866                 return;
 1867         if (lo <= np->n_pushedlo)
 1868                 np->n_pushedlo = hi;
 1869         else if (hi >= np->n_pushedhi)
 1870                 np->n_pushedhi = lo;
 1871         else {
 1872                 /*
 1873                  * XXX There's only one range. If the deleted range
 1874                  * is in the middle, pick the largest of the
 1875                  * contiguous ranges that it leaves.
 1876                  */
 1877                 if ((np->n_pushedlo - lo) > (hi - np->n_pushedhi))
 1878                         np->n_pushedhi = lo;
 1879                 else
 1880                         np->n_pushedlo = hi;
 1881         }
 1882 #ifdef NFS_DEBUG_COMMIT
 1883         printf("del: committed: %u - %u\n", (unsigned)np->n_pushedlo,
 1884             (unsigned)np->n_pushedhi);
 1885 #endif
 1886 }
 1887 
 1888 void
 1889 nfs_add_tobecommitted_range(struct vnode *vp, off_t off, off_t len)
 1890 {
 1891         struct nfsnode *np = VTONFS(vp);
 1892         off_t lo, hi;
 1893 
 1894         lo = off;
 1895         hi = lo + len;
 1896 
 1897         if (!(np->n_commitflags & NFS_COMMIT_PUSH_VALID)) {
 1898                 np->n_pushlo = lo;
 1899                 np->n_pushhi = hi;
 1900                 np->n_commitflags |= NFS_COMMIT_PUSH_VALID;
 1901         } else {
 1902                 if (lo < np->n_pushlo)
 1903                         np->n_pushlo = lo;
 1904                 if (hi > np->n_pushhi)
 1905                         np->n_pushhi = hi;
 1906         }
 1907 #ifdef NFS_DEBUG_COMMIT
 1908         printf("add: tobecommitted: %u - %u\n", (unsigned)np->n_pushlo,
 1909             (unsigned)np->n_pushhi);
 1910 #endif
 1911 }
 1912 
 1913 void
 1914 nfs_del_tobecommitted_range(struct vnode *vp, off_t off, off_t len)
 1915 {
 1916         struct nfsnode *np = VTONFS(vp);
 1917         off_t lo, hi;
 1918 
 1919         if (!(np->n_commitflags & NFS_COMMIT_PUSH_VALID))
 1920                 return;
 1921 
 1922         lo = off;
 1923         hi = lo + len;
 1924 
 1925         if (lo > np->n_pushhi || hi < np->n_pushlo)
 1926                 return;
 1927 
 1928         if (lo <= np->n_pushlo)
 1929                 np->n_pushlo = hi;
 1930         else if (hi >= np->n_pushhi)
 1931                 np->n_pushhi = lo;
 1932         else {
 1933                 /*
 1934                  * XXX There's only one range. If the deleted range
 1935                  * is in the middle, pick the largest of the
 1936                  * contiguous ranges that it leaves.
 1937                  */
 1938                 if ((np->n_pushlo - lo) > (hi - np->n_pushhi))
 1939                         np->n_pushhi = lo;
 1940                 else
 1941                         np->n_pushlo = hi;
 1942         }
 1943 #ifdef NFS_DEBUG_COMMIT
 1944         printf("del: tobecommitted: %u - %u\n", (unsigned)np->n_pushlo,
 1945             (unsigned)np->n_pushhi);
 1946 #endif
 1947 }
 1948 
 1949 /*
 1950  * Map errnos to NFS error numbers. For Version 3 also filter out error
 1951  * numbers not specified for the associated procedure.
 1952  */
 1953 int
 1954 nfsrv_errmap(struct nfsrv_descript *nd, int err)
 1955 {
 1956         const short *defaulterrp, *errp;
 1957 
 1958         if (nd->nd_flag & ND_NFSV3) {
 1959             if (nd->nd_procnum <= NFSPROC_COMMIT) {
 1960                 errp = defaulterrp = nfsrv_v3errmap[nd->nd_procnum];
 1961                 while (*++errp) {
 1962                         if (*errp == err)
 1963                                 return (err);
 1964                         else if (*errp > err)
 1965                                 break;
 1966                 }
 1967                 return ((int)*defaulterrp);
 1968             } else
 1969                 return (err & 0xffff);
 1970         }
 1971         if (err <= ELAST)
 1972                 return ((int)nfsrv_v2errmap[err - 1]);
 1973         return (NFSERR_IO);
 1974 }
 1975 
 1976 u_int32_t
 1977 nfs_getxid(void)
 1978 {
 1979         u_int32_t newxid;
 1980 
 1981         /* get next xid.  skip 0 */
 1982         do {
 1983                 newxid = atomic_inc_32_nv(&nfs_xid);
 1984         } while (__predict_false(newxid == 0));
 1985 
 1986         return txdr_unsigned(newxid);
 1987 }
 1988 
 1989 /*
 1990  * assign a new xid for existing request.
 1991  * used for NFSERR_JUKEBOX handling.
 1992  */
 1993 void
 1994 nfs_renewxid(struct nfsreq *req)
 1995 {
 1996         u_int32_t xid;
 1997         int off;
 1998 
 1999         xid = nfs_getxid();
 2000         if (req->r_nmp->nm_sotype == SOCK_STREAM)
 2001                 off = sizeof(u_int32_t); /* RPC record mark */
 2002         else
 2003                 off = 0;
 2004 
 2005         m_copyback(req->r_mreq, off, sizeof(xid), (void *)&xid);
 2006         req->r_xid = xid;
 2007 }

Cache object: 9123a1e99b8dee2735b2ab053985f7bd


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