LCOV - code coverage report
Current view: top level - nfs - nfs_subs.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 817 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 36 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*      $OpenBSD: nfs_subs.c,v 1.137 2018/07/02 20:56:22 bluhm Exp $    */
       2             : /*      $NetBSD: nfs_subs.c,v 1.27.4.3 1996/07/08 20:34:24 jtc Exp $    */
       3             : 
       4             : /*
       5             :  * Copyright (c) 1989, 1993
       6             :  *      The Regents of the University of California.  All rights reserved.
       7             :  *
       8             :  * This code is derived from software contributed to Berkeley by
       9             :  * Rick Macklem at The University of Guelph.
      10             :  *
      11             :  * Redistribution and use in source and binary forms, with or without
      12             :  * modification, are permitted provided that the following conditions
      13             :  * are met:
      14             :  * 1. Redistributions of source code must retain the above copyright
      15             :  *    notice, this list of conditions and the following disclaimer.
      16             :  * 2. Redistributions in binary form must reproduce the above copyright
      17             :  *    notice, this list of conditions and the following disclaimer in the
      18             :  *    documentation and/or other materials provided with the distribution.
      19             :  * 3. Neither the name of the University nor the names of its contributors
      20             :  *    may be used to endorse or promote products derived from this software
      21             :  *    without specific prior written permission.
      22             :  *
      23             :  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
      24             :  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
      25             :  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
      26             :  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
      27             :  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
      28             :  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
      29             :  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
      30             :  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
      31             :  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
      32             :  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
      33             :  * SUCH DAMAGE.
      34             :  *
      35             :  *      @(#)nfs_subs.c  8.8 (Berkeley) 5/22/95
      36             :  */
      37             : 
      38             : 
      39             : /*
      40             :  * These functions support the macros and help fiddle mbuf chains for
      41             :  * the nfs op functions. They do things like create the rpc header and
      42             :  * copy data between mbuf chains and uio lists.
      43             :  */
      44             : #include <sys/param.h>
      45             : #include <sys/systm.h>
      46             : #include <sys/kernel.h>
      47             : #include <sys/mount.h>
      48             : #include <sys/vnode.h>
      49             : #include <sys/namei.h>
      50             : #include <sys/mbuf.h>
      51             : #include <sys/socket.h>
      52             : #include <sys/socketvar.h>
      53             : #include <sys/stat.h>
      54             : #include <sys/pool.h>
      55             : #include <sys/time.h>
      56             : 
      57             : #include <nfs/rpcv2.h>
      58             : #include <nfs/nfsproto.h>
      59             : #include <nfs/nfsnode.h>
      60             : #include <nfs/nfs.h>
      61             : #include <nfs/xdr_subs.h>
      62             : #include <nfs/nfsm_subs.h>
      63             : #include <nfs/nfsmount.h>
      64             : #include <nfs/nfs_var.h>
      65             : 
      66             : #include <uvm/uvm_extern.h>
      67             : 
      68             : #include <netinet/in.h>
      69             : 
      70             : #include <crypto/idgen.h>
      71             : 
      72             : int     nfs_attrtimeo(struct nfsnode *np);
      73             : u_int32_t nfs_get_xid(void);
      74             : 
      75             : /*
      76             :  * Data items converted to xdr at startup, since they are constant
      77             :  * This is kinda hokey, but may save a little time doing byte swaps
      78             :  */
      79             : u_int32_t nfs_xdrneg1;
      80             : u_int32_t rpc_call, rpc_vers, rpc_reply, rpc_msgdenied, rpc_autherr,
      81             :         rpc_mismatch, rpc_auth_unix, rpc_msgaccepted;
      82             : u_int32_t nfs_prog, nfs_true, nfs_false;
      83             : 
      84             : /* And other global data */
      85             : nfstype nfsv2_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFNON,
      86             :                       NFCHR, NFNON };
      87             : nfstype nfsv3_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFSOCK,
      88             :                       NFFIFO, NFNON };
      89             : enum vtype nv2tov_type[8] = { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON, VNON };
      90             : enum vtype nv3tov_type[8]={ VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO };
      91             : int nfs_ticks;
      92             : struct nfsstats nfsstats;
      93             : 
      94             : /*
      95             :  * Mapping of old NFS Version 2 RPC numbers to generic numbers.
      96             :  */
      97             : int nfsv3_procid[NFS_NPROCS] = {
      98             :         NFSPROC_NULL,
      99             :         NFSPROC_GETATTR,
     100             :         NFSPROC_SETATTR,
     101             :         NFSPROC_NOOP,
     102             :         NFSPROC_LOOKUP,
     103             :         NFSPROC_READLINK,
     104             :         NFSPROC_READ,
     105             :         NFSPROC_NOOP,
     106             :         NFSPROC_WRITE,
     107             :         NFSPROC_CREATE,
     108             :         NFSPROC_REMOVE,
     109             :         NFSPROC_RENAME,
     110             :         NFSPROC_LINK,
     111             :         NFSPROC_SYMLINK,
     112             :         NFSPROC_MKDIR,
     113             :         NFSPROC_RMDIR,
     114             :         NFSPROC_READDIR,
     115             :         NFSPROC_FSSTAT,
     116             :         NFSPROC_NOOP,
     117             :         NFSPROC_NOOP,
     118             :         NFSPROC_NOOP,
     119             :         NFSPROC_NOOP,
     120             :         NFSPROC_NOOP
     121             : };
     122             : 
     123             : /*
     124             :  * and the reverse mapping from generic to Version 2 procedure numbers
     125             :  */
     126             : int nfsv2_procid[NFS_NPROCS] = {
     127             :         NFSV2PROC_NULL,
     128             :         NFSV2PROC_GETATTR,
     129             :         NFSV2PROC_SETATTR,
     130             :         NFSV2PROC_LOOKUP,
     131             :         NFSV2PROC_NOOP,
     132             :         NFSV2PROC_READLINK,
     133             :         NFSV2PROC_READ,
     134             :         NFSV2PROC_WRITE,
     135             :         NFSV2PROC_CREATE,
     136             :         NFSV2PROC_MKDIR,
     137             :         NFSV2PROC_SYMLINK,
     138             :         NFSV2PROC_CREATE,
     139             :         NFSV2PROC_REMOVE,
     140             :         NFSV2PROC_RMDIR,
     141             :         NFSV2PROC_RENAME,
     142             :         NFSV2PROC_LINK,
     143             :         NFSV2PROC_READDIR,
     144             :         NFSV2PROC_NOOP,
     145             :         NFSV2PROC_STATFS,
     146             :         NFSV2PROC_NOOP,
     147             :         NFSV2PROC_NOOP,
     148             :         NFSV2PROC_NOOP,
     149             :         NFSV2PROC_NOOP
     150             : };
     151             : 
     152             : /*
     153             :  * Maps errno values to nfs error numbers.
     154             :  * Use NFSERR_IO as the catch all for ones not specifically defined in
     155             :  * RFC 1094.
     156             :  */
     157             : static u_char nfsrv_v2errmap[] = {
     158             :   NFSERR_PERM,  NFSERR_NOENT,   NFSERR_IO,      NFSERR_IO,      NFSERR_IO,
     159             :   NFSERR_NXIO,  NFSERR_IO,      NFSERR_IO,      NFSERR_IO,      NFSERR_IO,
     160             :   NFSERR_IO,    NFSERR_IO,      NFSERR_ACCES,   NFSERR_IO,      NFSERR_IO,
     161             :   NFSERR_IO,    NFSERR_EXIST,   NFSERR_IO,      NFSERR_NODEV,   NFSERR_NOTDIR,
     162             :   NFSERR_ISDIR, NFSERR_IO,      NFSERR_IO,      NFSERR_IO,      NFSERR_IO,
     163             :   NFSERR_IO,    NFSERR_FBIG,    NFSERR_NOSPC,   NFSERR_IO,      NFSERR_ROFS,
     164             :   NFSERR_IO,    NFSERR_IO,      NFSERR_IO,      NFSERR_IO,      NFSERR_IO,
     165             :   NFSERR_IO,    NFSERR_IO,      NFSERR_IO,      NFSERR_IO,      NFSERR_IO,
     166             :   NFSERR_IO,    NFSERR_IO,      NFSERR_IO,      NFSERR_IO,      NFSERR_IO,
     167             :   NFSERR_IO,    NFSERR_IO,      NFSERR_IO,      NFSERR_IO,      NFSERR_IO,
     168             :   NFSERR_IO,    NFSERR_IO,      NFSERR_IO,      NFSERR_IO,      NFSERR_IO,
     169             :   NFSERR_IO,    NFSERR_IO,      NFSERR_IO,      NFSERR_IO,      NFSERR_IO,
     170             :   NFSERR_IO,    NFSERR_IO,      NFSERR_NAMETOL, NFSERR_IO,      NFSERR_IO,
     171             :   NFSERR_NOTEMPTY, NFSERR_IO,   NFSERR_IO,      NFSERR_DQUOT,   NFSERR_STALE
     172             :   /* Everything after this maps to NFSERR_IO, so far */
     173             : };
     174             : 
     175             : /*
     176             :  * Maps errno values to nfs error numbers.
     177             :  * Although it is not obvious whether or not NFS clients really care if
     178             :  * a returned error value is in the specified list for the procedure, the
     179             :  * safest thing to do is filter them appropriately. For Version 2, the
     180             :  * X/Open XNFS document is the only specification that defines error values
     181             :  * for each RPC (The RFC simply lists all possible error values for all RPCs),
     182             :  * so I have decided to not do this for Version 2.
     183             :  * The first entry is the default error return and the rest are the valid
     184             :  * errors for that RPC in increasing numeric order.
     185             :  */
     186             : static short nfsv3err_null[] = {
     187             :         0,
     188             :         0,
     189             : };
     190             : 
     191             : static short nfsv3err_getattr[] = {
     192             :         NFSERR_IO,
     193             :         NFSERR_IO,
     194             :         NFSERR_STALE,
     195             :         NFSERR_BADHANDLE,
     196             :         NFSERR_SERVERFAULT,
     197             :         0,
     198             : };
     199             : 
     200             : static short nfsv3err_setattr[] = {
     201             :         NFSERR_IO,
     202             :         NFSERR_PERM,
     203             :         NFSERR_IO,
     204             :         NFSERR_ACCES,
     205             :         NFSERR_INVAL,
     206             :         NFSERR_NOSPC,
     207             :         NFSERR_ROFS,
     208             :         NFSERR_DQUOT,
     209             :         NFSERR_STALE,
     210             :         NFSERR_BADHANDLE,
     211             :         NFSERR_NOT_SYNC,
     212             :         NFSERR_SERVERFAULT,
     213             :         0,
     214             : };
     215             : 
     216             : static short nfsv3err_lookup[] = {
     217             :         NFSERR_IO,
     218             :         NFSERR_NOENT,
     219             :         NFSERR_IO,
     220             :         NFSERR_ACCES,
     221             :         NFSERR_NOTDIR,
     222             :         NFSERR_NAMETOL,
     223             :         NFSERR_STALE,
     224             :         NFSERR_BADHANDLE,
     225             :         NFSERR_SERVERFAULT,
     226             :         0,
     227             : };
     228             : 
     229             : static short nfsv3err_access[] = {
     230             :         NFSERR_IO,
     231             :         NFSERR_IO,
     232             :         NFSERR_STALE,
     233             :         NFSERR_BADHANDLE,
     234             :         NFSERR_SERVERFAULT,
     235             :         0,
     236             : };
     237             : 
     238             : static short nfsv3err_readlink[] = {
     239             :         NFSERR_IO,
     240             :         NFSERR_IO,
     241             :         NFSERR_ACCES,
     242             :         NFSERR_INVAL,
     243             :         NFSERR_STALE,
     244             :         NFSERR_BADHANDLE,
     245             :         NFSERR_NOTSUPP,
     246             :         NFSERR_SERVERFAULT,
     247             :         0,
     248             : };
     249             : 
     250             : static short nfsv3err_read[] = {
     251             :         NFSERR_IO,
     252             :         NFSERR_IO,
     253             :         NFSERR_NXIO,
     254             :         NFSERR_ACCES,
     255             :         NFSERR_INVAL,
     256             :         NFSERR_STALE,
     257             :         NFSERR_BADHANDLE,
     258             :         NFSERR_SERVERFAULT,
     259             :         0,
     260             : };
     261             : 
     262             : static short nfsv3err_write[] = {
     263             :         NFSERR_IO,
     264             :         NFSERR_IO,
     265             :         NFSERR_ACCES,
     266             :         NFSERR_INVAL,
     267             :         NFSERR_FBIG,
     268             :         NFSERR_NOSPC,
     269             :         NFSERR_ROFS,
     270             :         NFSERR_DQUOT,
     271             :         NFSERR_STALE,
     272             :         NFSERR_BADHANDLE,
     273             :         NFSERR_SERVERFAULT,
     274             :         0,
     275             : };
     276             : 
     277             : static short nfsv3err_create[] = {
     278             :         NFSERR_IO,
     279             :         NFSERR_IO,
     280             :         NFSERR_ACCES,
     281             :         NFSERR_EXIST,
     282             :         NFSERR_NOTDIR,
     283             :         NFSERR_NOSPC,
     284             :         NFSERR_ROFS,
     285             :         NFSERR_NAMETOL,
     286             :         NFSERR_DQUOT,
     287             :         NFSERR_STALE,
     288             :         NFSERR_BADHANDLE,
     289             :         NFSERR_NOTSUPP,
     290             :         NFSERR_SERVERFAULT,
     291             :         0,
     292             : };
     293             : 
     294             : static short nfsv3err_mkdir[] = {
     295             :         NFSERR_IO,
     296             :         NFSERR_IO,
     297             :         NFSERR_ACCES,
     298             :         NFSERR_EXIST,
     299             :         NFSERR_NOTDIR,
     300             :         NFSERR_NOSPC,
     301             :         NFSERR_ROFS,
     302             :         NFSERR_NAMETOL,
     303             :         NFSERR_DQUOT,
     304             :         NFSERR_STALE,
     305             :         NFSERR_BADHANDLE,
     306             :         NFSERR_NOTSUPP,
     307             :         NFSERR_SERVERFAULT,
     308             :         0,
     309             : };
     310             : 
     311             : static short nfsv3err_symlink[] = {
     312             :         NFSERR_IO,
     313             :         NFSERR_IO,
     314             :         NFSERR_ACCES,
     315             :         NFSERR_EXIST,
     316             :         NFSERR_NOTDIR,
     317             :         NFSERR_NOSPC,
     318             :         NFSERR_ROFS,
     319             :         NFSERR_NAMETOL,
     320             :         NFSERR_DQUOT,
     321             :         NFSERR_STALE,
     322             :         NFSERR_BADHANDLE,
     323             :         NFSERR_NOTSUPP,
     324             :         NFSERR_SERVERFAULT,
     325             :         0,
     326             : };
     327             : 
     328             : static short nfsv3err_mknod[] = {
     329             :         NFSERR_IO,
     330             :         NFSERR_IO,
     331             :         NFSERR_ACCES,
     332             :         NFSERR_EXIST,
     333             :         NFSERR_NOTDIR,
     334             :         NFSERR_NOSPC,
     335             :         NFSERR_ROFS,
     336             :         NFSERR_NAMETOL,
     337             :         NFSERR_DQUOT,
     338             :         NFSERR_STALE,
     339             :         NFSERR_BADHANDLE,
     340             :         NFSERR_NOTSUPP,
     341             :         NFSERR_SERVERFAULT,
     342             :         NFSERR_BADTYPE,
     343             :         0,
     344             : };
     345             : 
     346             : static short nfsv3err_remove[] = {
     347             :         NFSERR_IO,
     348             :         NFSERR_NOENT,
     349             :         NFSERR_IO,
     350             :         NFSERR_ACCES,
     351             :         NFSERR_NOTDIR,
     352             :         NFSERR_ROFS,
     353             :         NFSERR_NAMETOL,
     354             :         NFSERR_STALE,
     355             :         NFSERR_BADHANDLE,
     356             :         NFSERR_SERVERFAULT,
     357             :         0,
     358             : };
     359             : 
     360             : static short nfsv3err_rmdir[] = {
     361             :         NFSERR_IO,
     362             :         NFSERR_NOENT,
     363             :         NFSERR_IO,
     364             :         NFSERR_ACCES,
     365             :         NFSERR_EXIST,
     366             :         NFSERR_NOTDIR,
     367             :         NFSERR_INVAL,
     368             :         NFSERR_ROFS,
     369             :         NFSERR_NAMETOL,
     370             :         NFSERR_NOTEMPTY,
     371             :         NFSERR_STALE,
     372             :         NFSERR_BADHANDLE,
     373             :         NFSERR_NOTSUPP,
     374             :         NFSERR_SERVERFAULT,
     375             :         0,
     376             : };
     377             : 
     378             : static short nfsv3err_rename[] = {
     379             :         NFSERR_IO,
     380             :         NFSERR_NOENT,
     381             :         NFSERR_IO,
     382             :         NFSERR_ACCES,
     383             :         NFSERR_EXIST,
     384             :         NFSERR_XDEV,
     385             :         NFSERR_NOTDIR,
     386             :         NFSERR_ISDIR,
     387             :         NFSERR_INVAL,
     388             :         NFSERR_NOSPC,
     389             :         NFSERR_ROFS,
     390             :         NFSERR_MLINK,
     391             :         NFSERR_NAMETOL,
     392             :         NFSERR_NOTEMPTY,
     393             :         NFSERR_DQUOT,
     394             :         NFSERR_STALE,
     395             :         NFSERR_BADHANDLE,
     396             :         NFSERR_NOTSUPP,
     397             :         NFSERR_SERVERFAULT,
     398             :         0,
     399             : };
     400             : 
     401             : static short nfsv3err_link[] = {
     402             :         NFSERR_IO,
     403             :         NFSERR_IO,
     404             :         NFSERR_ACCES,
     405             :         NFSERR_EXIST,
     406             :         NFSERR_XDEV,
     407             :         NFSERR_NOTDIR,
     408             :         NFSERR_INVAL,
     409             :         NFSERR_NOSPC,
     410             :         NFSERR_ROFS,
     411             :         NFSERR_MLINK,
     412             :         NFSERR_NAMETOL,
     413             :         NFSERR_DQUOT,
     414             :         NFSERR_STALE,
     415             :         NFSERR_BADHANDLE,
     416             :         NFSERR_NOTSUPP,
     417             :         NFSERR_SERVERFAULT,
     418             :         0,
     419             : };
     420             : 
     421             : static short nfsv3err_readdir[] = {
     422             :         NFSERR_IO,
     423             :         NFSERR_IO,
     424             :         NFSERR_ACCES,
     425             :         NFSERR_NOTDIR,
     426             :         NFSERR_STALE,
     427             :         NFSERR_BADHANDLE,
     428             :         NFSERR_BAD_COOKIE,
     429             :         NFSERR_TOOSMALL,
     430             :         NFSERR_SERVERFAULT,
     431             :         0,
     432             : };
     433             : 
     434             : static short nfsv3err_readdirplus[] = {
     435             :         NFSERR_IO,
     436             :         NFSERR_IO,
     437             :         NFSERR_ACCES,
     438             :         NFSERR_NOTDIR,
     439             :         NFSERR_STALE,
     440             :         NFSERR_BADHANDLE,
     441             :         NFSERR_BAD_COOKIE,
     442             :         NFSERR_NOTSUPP,
     443             :         NFSERR_TOOSMALL,
     444             :         NFSERR_SERVERFAULT,
     445             :         0,
     446             : };
     447             : 
     448             : static short nfsv3err_fsstat[] = {
     449             :         NFSERR_IO,
     450             :         NFSERR_IO,
     451             :         NFSERR_STALE,
     452             :         NFSERR_BADHANDLE,
     453             :         NFSERR_SERVERFAULT,
     454             :         0,
     455             : };
     456             : 
     457             : static short nfsv3err_fsinfo[] = {
     458             :         NFSERR_STALE,
     459             :         NFSERR_STALE,
     460             :         NFSERR_BADHANDLE,
     461             :         NFSERR_SERVERFAULT,
     462             :         0,
     463             : };
     464             : 
     465             : static short nfsv3err_pathconf[] = {
     466             :         NFSERR_STALE,
     467             :         NFSERR_STALE,
     468             :         NFSERR_BADHANDLE,
     469             :         NFSERR_SERVERFAULT,
     470             :         0,
     471             : };
     472             : 
     473             : static short nfsv3err_commit[] = {
     474             :         NFSERR_IO,
     475             :         NFSERR_IO,
     476             :         NFSERR_STALE,
     477             :         NFSERR_BADHANDLE,
     478             :         NFSERR_SERVERFAULT,
     479             :         0,
     480             : };
     481             : 
     482             : static short *nfsrv_v3errmap[] = {
     483             :         nfsv3err_null,
     484             :         nfsv3err_getattr,
     485             :         nfsv3err_setattr,
     486             :         nfsv3err_lookup,
     487             :         nfsv3err_access,
     488             :         nfsv3err_readlink,
     489             :         nfsv3err_read,
     490             :         nfsv3err_write,
     491             :         nfsv3err_create,
     492             :         nfsv3err_mkdir,
     493             :         nfsv3err_symlink,
     494             :         nfsv3err_mknod,
     495             :         nfsv3err_remove,
     496             :         nfsv3err_rmdir,
     497             :         nfsv3err_rename,
     498             :         nfsv3err_link,
     499             :         nfsv3err_readdir,
     500             :         nfsv3err_readdirplus,
     501             :         nfsv3err_fsstat,
     502             :         nfsv3err_fsinfo,
     503             :         nfsv3err_pathconf,
     504             :         nfsv3err_commit,
     505             : };
     506             : 
     507             : struct pool nfsreqpl;
     508             : 
     509             : /*
     510             :  * Create the header for an rpc request packet
     511             :  * The hsiz is the size of the rest of the nfs request header.
     512             :  * (just used to decide if a cluster is a good idea)
     513             :  */
     514             : struct mbuf *
     515           0 : nfsm_reqhead(int hsiz)
     516             : {
     517             :         struct mbuf *mb;
     518             : 
     519           0 :         MGET(mb, M_WAIT, MT_DATA);
     520           0 :         if (hsiz > MLEN)
     521           0 :                 MCLGET(mb, M_WAIT);
     522           0 :         mb->m_len = 0;
     523             :         
     524             :         /* Finally, return values */
     525           0 :         return (mb);
     526             : }
     527             : 
     528             : /*
     529             :  * Return an unpredictable XID in XDR form.
     530             :  */
     531             : u_int32_t
     532           0 : nfs_get_xid(void)
     533             : {
     534             :         static struct idgen32_ctx nfs_xid_ctx;
     535             :         static int called = 0;
     536             : 
     537           0 :         if (!called) {
     538           0 :                 called = 1;
     539           0 :                 idgen32_init(&nfs_xid_ctx);
     540           0 :         }
     541           0 :         return (txdr_unsigned(idgen32(&nfs_xid_ctx)));
     542             : }
     543             : 
     544             : /*
     545             :  * Build the RPC header and fill in the authorization info.
     546             :  * Right now we are pretty centric around RPCAUTH_UNIX, in the
     547             :  * future, this function will need some love to be able to handle
     548             :  * other authorization methods, such as Kerberos.
     549             :  */
     550             : void
     551           0 : nfsm_rpchead(struct nfsreq *req, struct ucred *cr, int auth_type)
     552             : {
     553           0 :         struct mbuf     *mb;
     554             :         u_int32_t       *tl;
     555             :         int             i, authsiz, auth_len, ngroups;
     556             : 
     557           0 :         KASSERT(auth_type == RPCAUTH_UNIX);
     558             : 
     559             :         /*
     560             :          * RPCAUTH_UNIX fits in an hdr mbuf, in the future other
     561             :          * authorization methods need to figure out their own sizes
     562             :          * and allocate and chain mbuf's accorindgly.
     563             :          */
     564           0 :         mb = req->r_mreq;
     565             : 
     566             :         /*
     567             :          * We need to start out by finding how big the authorization cred
     568             :          * and verifer are for the auth_type, to be able to correctly
     569             :          * align the mbuf header/chain.
     570             :          */
     571           0 :         switch (auth_type) {
     572             :         case RPCAUTH_UNIX:
     573             :                 /*
     574             :                  * In the RPCAUTH_UNIX case, the size is the static
     575             :                  * part as shown in RFC1831 + the number of groups,
     576             :                  * RPCAUTH_UNIX has a zero verifer.
     577             :                  */
     578           0 :                 if (cr->cr_ngroups > req->r_nmp->nm_numgrps)
     579           0 :                         ngroups = req->r_nmp->nm_numgrps;
     580             :                 else
     581             :                         ngroups = cr->cr_ngroups;
     582             : 
     583           0 :                 auth_len = (ngroups << 2) + 5 * NFSX_UNSIGNED;
     584           0 :                 authsiz = nfsm_rndup(auth_len);
     585             :                 /* The authorization size + the size of the static part */
     586           0 :                 MH_ALIGN(mb, authsiz + 10 * NFSX_UNSIGNED);
     587           0 :                 break;
     588             :         }
     589             : 
     590           0 :         mb->m_len = 0;
     591             : 
     592             :         /* First the RPC header. */
     593           0 :         tl = nfsm_build(&mb, 6 * NFSX_UNSIGNED);
     594             : 
     595             :         /* Get a new (non-zero) xid */
     596           0 :         *tl++ = req->r_xid = nfs_get_xid();
     597           0 :         *tl++ = rpc_call;
     598           0 :         *tl++ = rpc_vers;
     599           0 :         *tl++ = nfs_prog;
     600           0 :         if (ISSET(req->r_nmp->nm_flag, NFSMNT_NFSV3)) {
     601           0 :                 *tl++ = txdr_unsigned(NFS_VER3);
     602           0 :                 *tl = txdr_unsigned(req->r_procnum);
     603           0 :         } else {
     604           0 :                 *tl++ = txdr_unsigned(NFS_VER2);
     605           0 :                 *tl = txdr_unsigned(nfsv2_procid[req->r_procnum]);
     606             :         }
     607             : 
     608             :         /* The Authorization cred and its verifier */
     609           0 :         switch (auth_type) {
     610             :         case RPCAUTH_UNIX:
     611           0 :                 tl = nfsm_build(&mb, auth_len + 4 * NFSX_UNSIGNED);
     612           0 :                 *tl++ = txdr_unsigned(RPCAUTH_UNIX);
     613           0 :                 *tl++ = txdr_unsigned(authsiz);
     614             : 
     615             :                 /* The authorization cred */
     616           0 :                 *tl++ = 0;              /* stamp */
     617           0 :                 *tl++ = 0;              /* NULL hostname */
     618           0 :                 *tl++ = txdr_unsigned(cr->cr_uid);
     619           0 :                 *tl++ = txdr_unsigned(cr->cr_gid);
     620           0 :                 *tl++ = txdr_unsigned(ngroups);
     621           0 :                 for (i = 0; i < ngroups; i++)
     622           0 :                         *tl++ = txdr_unsigned(cr->cr_groups[i]);
     623             :                 /* The authorization verifier */
     624           0 :                 *tl++ = txdr_unsigned(RPCAUTH_NULL);
     625           0 :                 *tl = 0;
     626           0 :                 break;
     627             :         }
     628             : 
     629           0 :         mb->m_pkthdr.len += authsiz + 10 * NFSX_UNSIGNED;
     630           0 :         mb->m_pkthdr.ph_ifidx = 0;
     631           0 : }
     632             : 
     633             : /*
     634             :  * copies mbuf chain to the uio scatter/gather list
     635             :  */
     636             : int
     637           0 : nfsm_mbuftouio(struct mbuf **mrep, struct uio *uiop, int siz, caddr_t *dpos)
     638             : {
     639             :         char *mbufcp, *uiocp;
     640             :         int xfer, left, len;
     641             :         struct mbuf *mp;
     642             :         long uiosiz, rem;
     643             :         int error = 0;
     644             : 
     645           0 :         mp = *mrep;
     646           0 :         mbufcp = *dpos;
     647           0 :         len = mtod(mp, caddr_t)+mp->m_len-mbufcp;
     648           0 :         rem = nfsm_padlen(siz);
     649           0 :         while (siz > 0) {
     650           0 :                 if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL)
     651           0 :                         return (EFBIG);
     652           0 :                 left = uiop->uio_iov->iov_len;
     653           0 :                 uiocp = uiop->uio_iov->iov_base;
     654           0 :                 if (left > siz)
     655           0 :                         left = siz;
     656           0 :                 uiosiz = left;
     657           0 :                 while (left > 0) {
     658           0 :                         while (len == 0) {
     659           0 :                                 mp = mp->m_next;
     660           0 :                                 if (mp == NULL)
     661           0 :                                         return (EBADRPC);
     662           0 :                                 mbufcp = mtod(mp, caddr_t);
     663           0 :                                 len = mp->m_len;
     664             :                         }
     665           0 :                         xfer = (left > len) ? len : left;
     666           0 :                         if (uiop->uio_segflg == UIO_SYSSPACE)
     667           0 :                                 memcpy(uiocp, mbufcp, xfer);
     668             :                         else
     669           0 :                                 copyout(mbufcp, uiocp, xfer);
     670           0 :                         left -= xfer;
     671           0 :                         len -= xfer;
     672           0 :                         mbufcp += xfer;
     673           0 :                         uiocp += xfer;
     674           0 :                         uiop->uio_offset += xfer;
     675           0 :                         uiop->uio_resid -= xfer;
     676             :                 }
     677           0 :                 if (uiop->uio_iov->iov_len <= siz) {
     678           0 :                         uiop->uio_iovcnt--;
     679           0 :                         uiop->uio_iov++;
     680           0 :                 } else {
     681           0 :                         uiop->uio_iov->iov_base =
     682           0 :                             (char *)uiop->uio_iov->iov_base + uiosiz;
     683           0 :                         uiop->uio_iov->iov_len -= uiosiz;
     684             :                 }
     685           0 :                 siz -= uiosiz;
     686             :         }
     687           0 :         *dpos = mbufcp;
     688           0 :         *mrep = mp;
     689           0 :         if (rem > 0) {
     690           0 :                 if (len < rem)
     691           0 :                         error = nfs_adv(mrep, dpos, rem, len);
     692             :                 else
     693           0 :                         *dpos += rem;
     694             :         }
     695           0 :         return (error);
     696           0 : }
     697             : 
     698             : /*
     699             :  * Copy a uio scatter/gather list to an mbuf chain.
     700             :  */
     701             : void
     702           0 : nfsm_uiotombuf(struct mbuf **mp, struct uio *uiop, size_t len)
     703             : {
     704             :         struct mbuf *mb, *mb2;
     705             :         size_t xfer, pad;
     706             : 
     707           0 :         mb = *mp;
     708             : 
     709           0 :         pad = nfsm_padlen(len);
     710             : 
     711             :         /* XXX -- the following should be done by the caller */
     712           0 :         uiop->uio_resid = len;
     713           0 :         uiop->uio_rw = UIO_WRITE;
     714             : 
     715           0 :         while (len) {
     716           0 :                 xfer = ulmin(len, M_TRAILINGSPACE(mb));
     717           0 :                 uiomove(mb_offset(mb), xfer, uiop);
     718           0 :                 mb->m_len += xfer;
     719           0 :                 len -= xfer;
     720           0 :                 if (len > 0) {
     721           0 :                         MGET(mb2, M_WAIT, MT_DATA);
     722           0 :                         if (len > MLEN)
     723           0 :                                 MCLGET(mb2, M_WAIT);
     724           0 :                         mb2->m_len = 0;
     725           0 :                         mb->m_next = mb2;
     726             :                         mb = mb2;
     727           0 :                 }
     728             :         }
     729             : 
     730           0 :         if (pad > 0) {
     731           0 :                 if (pad > M_TRAILINGSPACE(mb)) {
     732           0 :                         MGET(mb2, M_WAIT, MT_DATA);
     733           0 :                         mb2->m_len = 0;
     734           0 :                         mb->m_next = mb2;
     735             :                         mb = mb2;
     736           0 :                 }
     737           0 :                 memset(mb_offset(mb), 0, pad);
     738           0 :                 mb->m_len += pad;
     739           0 :         }
     740             : 
     741           0 :         *mp = mb;
     742           0 : }
     743             : 
     744             : /*
     745             :  * Copy a buffer to an mbuf chain
     746             :  */
     747             : void
     748           0 : nfsm_buftombuf(struct mbuf **mp, void *buf, size_t len)
     749             : {
     750           0 :         struct iovec iov;
     751           0 :         struct uio io;
     752             : 
     753           0 :         iov.iov_base = buf;
     754           0 :         iov.iov_len = len;
     755             : 
     756           0 :         io.uio_iov = &iov;
     757           0 :         io.uio_iovcnt = 1;
     758           0 :         io.uio_resid = len;
     759           0 :         io.uio_segflg = UIO_SYSSPACE;
     760           0 :         io.uio_rw = UIO_WRITE;
     761             : 
     762           0 :         nfsm_uiotombuf(mp, &io, len);
     763           0 : }
     764             : 
     765             : /*
     766             :  * Copy a string to an mbuf chain
     767             :  */
     768             : void
     769           0 : nfsm_strtombuf(struct mbuf **mp, void *str, size_t len)
     770             : {
     771           0 :         struct iovec iov[2];
     772           0 :         struct uio io;
     773           0 :         uint32_t strlen;
     774             : 
     775           0 :         strlen = txdr_unsigned(len);
     776             : 
     777           0 :         iov[0].iov_base = &strlen;
     778           0 :         iov[0].iov_len = sizeof(uint32_t);
     779           0 :         iov[1].iov_base = str;
     780           0 :         iov[1].iov_len = len;
     781             : 
     782           0 :         io.uio_iov = iov;
     783           0 :         io.uio_iovcnt = 2;
     784           0 :         io.uio_resid = sizeof(uint32_t) + len;
     785           0 :         io.uio_segflg = UIO_SYSSPACE;
     786           0 :         io.uio_rw = UIO_WRITE;
     787             : 
     788           0 :         nfsm_uiotombuf(mp, &io, io.uio_resid);
     789           0 : }
     790             : 
     791             : /*
     792             :  * Help break down an mbuf chain by setting the first siz bytes contiguous
     793             :  * pointed to by returned val.
     794             :  * This is used by the macros nfsm_dissect and nfsm_dissecton for tough
     795             :  * cases. (The macros use the vars. dpos and dpos2)
     796             :  */
     797             : int
     798           0 : nfsm_disct(struct mbuf **mdp, caddr_t *dposp, int siz, int left, caddr_t *cp2)
     799             : {
     800             :         struct mbuf *mp, *mp2;
     801             :         int siz2, xfer;
     802             :         caddr_t p;
     803             : 
     804           0 :         mp = *mdp;
     805           0 :         while (left == 0) {
     806           0 :                 *mdp = mp = mp->m_next;
     807           0 :                 if (mp == NULL)
     808           0 :                         return (EBADRPC);
     809           0 :                 left = mp->m_len;
     810           0 :                 *dposp = mtod(mp, caddr_t);
     811             :         }
     812           0 :         if (left >= siz) {
     813           0 :                 *cp2 = *dposp;
     814           0 :                 *dposp += siz;
     815           0 :         } else if (mp->m_next == NULL) {
     816           0 :                 return (EBADRPC);
     817           0 :         } else if (siz > MHLEN) {
     818           0 :                 panic("nfs S too big");
     819             :         } else {
     820           0 :                 MGET(mp2, M_WAIT, MT_DATA);
     821           0 :                 mp2->m_next = mp->m_next;
     822           0 :                 mp->m_next = mp2;
     823           0 :                 mp->m_len -= left;
     824             :                 mp = mp2;
     825           0 :                 *cp2 = p = mtod(mp, caddr_t);
     826           0 :                 bcopy(*dposp, p, left);         /* Copy what was left */
     827           0 :                 siz2 = siz-left;
     828           0 :                 p += left;
     829           0 :                 mp2 = mp->m_next;
     830             :                 /* Loop around copying up the siz2 bytes */
     831           0 :                 while (siz2 > 0) {
     832           0 :                         if (mp2 == NULL)
     833           0 :                                 return (EBADRPC);
     834           0 :                         xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2;
     835           0 :                         if (xfer > 0) {
     836           0 :                                 bcopy(mtod(mp2, caddr_t), p, xfer);
     837           0 :                                 mp2->m_data += xfer;
     838           0 :                                 mp2->m_len -= xfer;
     839           0 :                                 p += xfer;
     840           0 :                                 siz2 -= xfer;
     841           0 :                         }
     842           0 :                         if (siz2 > 0)
     843           0 :                                 mp2 = mp2->m_next;
     844             :                 }
     845           0 :                 mp->m_len = siz;
     846           0 :                 *mdp = mp2;
     847           0 :                 *dposp = mtod(mp2, caddr_t);
     848             :         }
     849           0 :         return (0);
     850           0 : }
     851             : 
     852             : /*
     853             :  * Advance the position in the mbuf chain.
     854             :  */
     855             : int
     856           0 : nfs_adv(struct mbuf **mdp, caddr_t *dposp, int offs, int left)
     857             : {
     858             :         struct mbuf *m;
     859             :         int s;
     860             : 
     861           0 :         m = *mdp;
     862             :         s = left;
     863           0 :         while (s < offs) {
     864           0 :                 offs -= s;
     865           0 :                 m = m->m_next;
     866           0 :                 if (m == NULL)
     867           0 :                         return (EBADRPC);
     868           0 :                 s = m->m_len;
     869             :         }
     870           0 :         *mdp = m;
     871           0 :         *dposp = mtod(m, caddr_t)+offs;
     872           0 :         return (0);
     873           0 : }
     874             : 
     875             : /*
     876             :  * Called once to initialize data structures...
     877             :  */
     878             : void
     879           0 : nfs_init(void)
     880             : {
     881           0 :         rpc_vers = txdr_unsigned(RPC_VER2);
     882           0 :         rpc_call = txdr_unsigned(RPC_CALL);
     883           0 :         rpc_reply = txdr_unsigned(RPC_REPLY);
     884           0 :         rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED);
     885           0 :         rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED);
     886           0 :         rpc_mismatch = txdr_unsigned(RPC_MISMATCH);
     887           0 :         rpc_autherr = txdr_unsigned(RPC_AUTHERR);
     888           0 :         rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX);
     889           0 :         nfs_prog = txdr_unsigned(NFS_PROG);
     890           0 :         nfs_true = txdr_unsigned(1);
     891           0 :         nfs_false = txdr_unsigned(0);
     892           0 :         nfs_xdrneg1 = txdr_unsigned(-1);
     893           0 :         nfs_ticks = (hz * NFS_TICKINTVL + 500) / 1000;
     894           0 :         if (nfs_ticks < 1)
     895             :                 nfs_ticks = 1;
     896             : #ifdef NFSSERVER
     897           0 :         nfsrv_init(0);                  /* Init server data structures */
     898           0 :         nfsrv_initcache();              /* Init the server request cache */
     899             : #endif /* NFSSERVER */
     900             : 
     901           0 :         pool_init(&nfsreqpl, sizeof(struct nfsreq), 0, IPL_NONE, PR_WAITOK,
     902             :             "nfsreqpl", NULL);
     903           0 : }
     904             : 
     905             : #ifdef NFSCLIENT
     906             : int
     907           0 : nfs_vfs_init(struct vfsconf *vfsp)
     908             : {
     909             :         extern struct pool nfs_node_pool;
     910             : 
     911           0 :         TAILQ_INIT(&nfs_bufq);
     912             : 
     913           0 :         pool_init(&nfs_node_pool, sizeof(struct nfsnode), 0, IPL_NONE,
     914             :                   PR_WAITOK, "nfsnodepl", NULL);
     915             : 
     916           0 :         return (0);
     917             : }
     918             : 
     919             : /*
     920             :  * Attribute cache routines.
     921             :  * nfs_loadattrcache() - loads or updates the cache contents from attributes
     922             :  *      that are on the mbuf list
     923             :  * nfs_getattrcache() - returns valid attributes if found in cache, returns
     924             :  *      error otherwise
     925             :  */
     926             : 
     927             : /*
     928             :  * Load the attribute cache (that lives in the nfsnode entry) with
     929             :  * the values on the mbuf list and
     930             :  * Iff vap not NULL
     931             :  *    copy the attributes to *vaper
     932             :  */
     933             : int
     934           0 : nfs_loadattrcache(struct vnode **vpp, struct mbuf **mdp, caddr_t *dposp,
     935             :     struct vattr *vaper)
     936             : {
     937           0 :         struct vnode *vp = *vpp;
     938             :         struct vattr *vap;
     939             :         struct nfs_fattr *fp;
     940             :         extern struct vops nfs_specvops;
     941             :         struct nfsnode *np;
     942             :         int32_t t1;
     943           0 :         caddr_t cp2;
     944             :         int error = 0;
     945             :         int32_t rdev;
     946             :         struct mbuf *md;
     947             :         enum vtype vtyp;
     948             :         mode_t vmode;
     949             :         struct timespec mtime;
     950             :         struct vnode *nvp;
     951           0 :         int v3 = NFS_ISV3(vp);
     952             :         uid_t uid;
     953             :         gid_t gid;
     954             : 
     955           0 :         md = *mdp;
     956           0 :         t1 = (mtod(md, caddr_t) + md->m_len) - *dposp;
     957           0 :         error = nfsm_disct(mdp, dposp, NFSX_FATTR(v3), t1, &cp2);
     958           0 :         if (error)
     959           0 :                 return (error);
     960           0 :         fp = (struct nfs_fattr *)cp2;
     961           0 :         if (v3) {
     962           0 :                 vtyp = nfsv3tov_type(fp->fa_type);
     963           0 :                 vmode = fxdr_unsigned(mode_t, fp->fa_mode);
     964           0 :                 rdev = makedev(fxdr_unsigned(u_int32_t, fp->fa3_rdev.specdata1),
     965             :                         fxdr_unsigned(u_int32_t, fp->fa3_rdev.specdata2));
     966           0 :                 fxdr_nfsv3time(&fp->fa3_mtime, &mtime);
     967           0 :         } else {
     968           0 :                 vtyp = nfsv2tov_type(fp->fa_type);
     969           0 :                 vmode = fxdr_unsigned(mode_t, fp->fa_mode);
     970           0 :                 if (vtyp == VNON || vtyp == VREG)
     971           0 :                         vtyp = IFTOVT(vmode);
     972           0 :                 rdev = fxdr_unsigned(int32_t, fp->fa2_rdev);
     973           0 :                 fxdr_nfsv2time(&fp->fa2_mtime, &mtime);
     974             : 
     975             :                 /*
     976             :                  * Really ugly NFSv2 kludge.
     977             :                  */
     978           0 :                 if (vtyp == VCHR && rdev == 0xffffffff)
     979           0 :                         vtyp = VFIFO;
     980             :         }
     981             : 
     982             :         /*
     983             :          * If v_type == VNON it is a new node, so fill in the v_type,
     984             :          * n_mtime fields. Check to see if it represents a special 
     985             :          * device, and if so, check for a possible alias. Once the
     986             :          * correct vnode has been obtained, fill in the rest of the
     987             :          * information.
     988             :          */
     989           0 :         np = VTONFS(vp);
     990           0 :         if (vp->v_type != vtyp) {
     991           0 :                 cache_purge(vp);
     992           0 :                 vp->v_type = vtyp;
     993           0 :                 if (vp->v_type == VFIFO) {
     994             : #ifndef FIFO
     995             :                         return (EOPNOTSUPP);
     996             : #else
     997             :                         extern struct vops nfs_fifovops;
     998           0 :                         vp->v_op = &nfs_fifovops;
     999             : #endif /* FIFO */
    1000           0 :                 }
    1001           0 :                 if (vp->v_type == VCHR || vp->v_type == VBLK) {
    1002           0 :                         vp->v_op = &nfs_specvops;
    1003           0 :                         nvp = checkalias(vp, (dev_t)rdev, vp->v_mount);
    1004           0 :                         if (nvp) {
    1005             :                                 /*
    1006             :                                  * Discard unneeded vnode, but save its nfsnode.
    1007             :                                  * Since the nfsnode does not have a lock, its
    1008             :                                  * vnode lock has to be carried over.
    1009             :                                  */
    1010             : 
    1011           0 :                                 nvp->v_data = vp->v_data;
    1012           0 :                                 vp->v_data = NULL;
    1013           0 :                                 vp->v_op = &spec_vops;
    1014           0 :                                 vrele(vp);
    1015           0 :                                 vgone(vp);
    1016             :                                 /*
    1017             :                                  * Reinitialize aliased node.
    1018             :                                  */
    1019           0 :                                 np->n_vnode = nvp;
    1020           0 :                                 *vpp = vp = nvp;
    1021           0 :                         }
    1022             :                 }
    1023           0 :                 np->n_mtime = mtime;
    1024           0 :         }
    1025           0 :         vap = &np->n_vattr;
    1026           0 :         vap->va_type = vtyp;
    1027           0 :         vap->va_rdev = (dev_t)rdev;
    1028           0 :         vap->va_mtime = mtime;
    1029           0 :         vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0];
    1030             : 
    1031           0 :         uid = fxdr_unsigned(uid_t, fp->fa_uid);
    1032           0 :         gid = fxdr_unsigned(gid_t, fp->fa_gid);
    1033             :         /* Invalidate access cache if uid, gid or mode changed. */
    1034           0 :         if (np->n_accstamp != -1 &&
    1035           0 :             (gid != vap->va_gid || uid != vap->va_uid ||
    1036           0 :             (vmode & 07777) != vap->va_mode))
    1037           0 :                 np->n_accstamp = -1;
    1038             : 
    1039           0 :         vap->va_mode = (vmode & 07777);
    1040             : 
    1041           0 :         switch (vtyp) {
    1042             :         case VBLK:
    1043           0 :                 vap->va_blocksize = BLKDEV_IOSIZE;
    1044           0 :                 break;
    1045             :         case VCHR:
    1046           0 :                 vap->va_blocksize = MAXBSIZE;
    1047           0 :                 break;
    1048             :         default:
    1049           0 :                 vap->va_blocksize = v3 ? vp->v_mount->mnt_stat.f_iosize :
    1050           0 :                      fxdr_unsigned(int32_t, fp->fa2_blocksize);
    1051           0 :                 break;
    1052             :         }
    1053           0 :         if (v3) {
    1054           0 :                 vap->va_nlink = fxdr_unsigned(nlink_t, fp->fa_nlink);
    1055           0 :                 vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid);
    1056           0 :                 vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid);
    1057           0 :                 vap->va_size = fxdr_hyper(&fp->fa3_size);
    1058           0 :                 vap->va_bytes = fxdr_hyper(&fp->fa3_used);
    1059           0 :                 vap->va_fileid = fxdr_hyper(&fp->fa3_fileid);
    1060           0 :                 fxdr_nfsv3time(&fp->fa3_atime, &vap->va_atime);
    1061           0 :                 fxdr_nfsv3time(&fp->fa3_ctime, &vap->va_ctime);
    1062           0 :                 vap->va_flags = 0;
    1063           0 :                 vap->va_filerev = 0;
    1064           0 :         } else {
    1065           0 :                 vap->va_nlink = fxdr_unsigned(nlink_t, fp->fa_nlink);
    1066           0 :                 vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid);
    1067           0 :                 vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid);
    1068           0 :                 vap->va_size = fxdr_unsigned(u_int32_t, fp->fa2_size);
    1069           0 :                 vap->va_bytes =
    1070           0 :                     (u_quad_t)fxdr_unsigned(int32_t, fp->fa2_blocks) *
    1071             :                     NFS_FABLKSIZE;
    1072           0 :                 vap->va_fileid = fxdr_unsigned(int32_t, fp->fa2_fileid);
    1073           0 :                 fxdr_nfsv2time(&fp->fa2_atime, &vap->va_atime);
    1074           0 :                 vap->va_flags = 0;
    1075           0 :                 vap->va_ctime.tv_sec = fxdr_unsigned(u_int32_t,
    1076             :                     fp->fa2_ctime.nfsv2_sec);
    1077           0 :                 vap->va_ctime.tv_nsec = 0;
    1078           0 :                 vap->va_gen = fxdr_unsigned(u_int32_t,fp->fa2_ctime.nfsv2_usec);
    1079           0 :                 vap->va_filerev = 0;
    1080             :         }
    1081             : 
    1082           0 :         if (vap->va_size != np->n_size) {
    1083           0 :                 if (vap->va_type == VREG) {
    1084           0 :                         if (np->n_flag & NMODIFIED) {
    1085           0 :                                 if (vap->va_size < np->n_size)
    1086           0 :                                         vap->va_size = np->n_size;
    1087             :                                 else
    1088           0 :                                         np->n_size = vap->va_size;
    1089             :                         } else
    1090           0 :                                 np->n_size = vap->va_size;
    1091           0 :                         uvm_vnp_setsize(vp, np->n_size);
    1092           0 :                 } else
    1093           0 :                         np->n_size = vap->va_size;
    1094             :         }
    1095           0 :         np->n_attrstamp = time_second;
    1096           0 :         if (vaper != NULL) {
    1097           0 :                 bcopy(vap, vaper, sizeof(*vap));
    1098           0 :                 if (np->n_flag & NCHG) {
    1099           0 :                         if (np->n_flag & NACC)
    1100           0 :                                 vaper->va_atime = np->n_atim;
    1101           0 :                         if (np->n_flag & NUPD)
    1102           0 :                                 vaper->va_mtime = np->n_mtim;
    1103             :                 }
    1104             :         }
    1105           0 :         return (0);
    1106           0 : }
    1107             : 
    1108             : int
    1109           0 : nfs_attrtimeo(struct nfsnode *np)
    1110             : {
    1111           0 :         struct vnode *vp = np->n_vnode;
    1112           0 :         struct nfsmount *nmp = VFSTONFS(vp->v_mount);
    1113           0 :         int tenthage = (time_second - np->n_mtime.tv_sec) / 10;
    1114             :         int minto, maxto;
    1115             : 
    1116           0 :         if (vp->v_type == VDIR) {
    1117           0 :                 maxto = nmp->nm_acdirmax;
    1118           0 :                 minto = nmp->nm_acdirmin;
    1119           0 :         }
    1120             :         else {
    1121           0 :                 maxto = nmp->nm_acregmax;
    1122           0 :                 minto = nmp->nm_acregmin;
    1123             :         }
    1124             : 
    1125           0 :         if (np->n_flag & NMODIFIED || tenthage < minto)
    1126           0 :                 return minto;
    1127           0 :         else if (tenthage < maxto)
    1128           0 :                 return tenthage;
    1129             :         else
    1130           0 :                 return maxto;
    1131           0 : }
    1132             : 
    1133             : /*
    1134             :  * Check the time stamp
    1135             :  * If the cache is valid, copy contents to *vap and return 0
    1136             :  * otherwise return an error
    1137             :  */
    1138             : int
    1139           0 : nfs_getattrcache(struct vnode *vp, struct vattr *vaper)
    1140             : {
    1141           0 :         struct nfsnode *np = VTONFS(vp);
    1142             :         struct vattr *vap;
    1143             : 
    1144           0 :         if (np->n_attrstamp == 0 ||
    1145           0 :             (time_second - np->n_attrstamp) >= nfs_attrtimeo(np)) {
    1146           0 :                 nfsstats.attrcache_misses++;
    1147           0 :                 return (ENOENT);
    1148             :         }
    1149           0 :         nfsstats.attrcache_hits++;
    1150           0 :         vap = &np->n_vattr;
    1151           0 :         if (vap->va_size != np->n_size) {
    1152           0 :                 if (vap->va_type == VREG) {
    1153           0 :                         if (np->n_flag & NMODIFIED) {
    1154           0 :                                 if (vap->va_size < np->n_size)
    1155           0 :                                         vap->va_size = np->n_size;
    1156             :                                 else
    1157           0 :                                         np->n_size = vap->va_size;
    1158             :                         } else
    1159           0 :                                 np->n_size = vap->va_size;
    1160           0 :                         uvm_vnp_setsize(vp, np->n_size);
    1161           0 :                 } else
    1162           0 :                         np->n_size = vap->va_size;
    1163             :         }
    1164           0 :         bcopy(vap, vaper, sizeof(struct vattr));
    1165           0 :         if (np->n_flag & NCHG) {
    1166           0 :                 if (np->n_flag & NACC)
    1167           0 :                         vaper->va_atime = np->n_atim;
    1168           0 :                 if (np->n_flag & NUPD)
    1169           0 :                         vaper->va_mtime = np->n_mtim;
    1170             :         }
    1171           0 :         return (0);
    1172           0 : }
    1173             : #endif /* NFSCLIENT */
    1174             : 
    1175             : /*
    1176             :  * Set up nameidata for a lookup() call and do it
    1177             :  */
    1178             : int
    1179           0 : nfs_namei(struct nameidata *ndp, fhandle_t *fhp, int len,
    1180             :     struct nfssvc_sock *slp, struct mbuf *nam, struct mbuf **mdp,
    1181             :     caddr_t *dposp, struct vnode **retdirp, struct proc *p)
    1182             : {
    1183             :         int i, rem;
    1184             :         struct mbuf *md;
    1185             :         char *fromcp, *tocp;
    1186           0 :         struct vnode *dp;
    1187           0 :         int error, rdonly;
    1188           0 :         struct componentname *cnp = &ndp->ni_cnd;
    1189             : 
    1190           0 :         *retdirp = NULL;
    1191           0 :         cnp->cn_pnbuf = pool_get(&namei_pool, PR_WAITOK);
    1192             :         /*
    1193             :          * Copy the name from the mbuf list to ndp->ni_pnbuf
    1194             :          * and set the various ndp fields appropriately.
    1195             :          */
    1196           0 :         fromcp = *dposp;
    1197             :         tocp = cnp->cn_pnbuf;
    1198           0 :         md = *mdp;
    1199           0 :         rem = mtod(md, caddr_t) + md->m_len - fromcp;
    1200           0 :         for (i = 0; i < len; i++) {
    1201           0 :                 while (rem == 0) {
    1202           0 :                         md = md->m_next;
    1203           0 :                         if (md == NULL) {
    1204             :                                 error = EBADRPC;
    1205           0 :                                 goto out;
    1206             :                         }
    1207           0 :                         fromcp = mtod(md, caddr_t);
    1208           0 :                         rem = md->m_len;
    1209             :                 }
    1210           0 :                 if (*fromcp == '\0' || *fromcp == '/') {
    1211             :                         error = EACCES;
    1212           0 :                         goto out;
    1213             :                 }
    1214           0 :                 *tocp++ = *fromcp++;
    1215           0 :                 rem--;
    1216             :         }
    1217           0 :         *tocp = '\0';
    1218           0 :         *mdp = md;
    1219           0 :         *dposp = fromcp;
    1220           0 :         len = nfsm_padlen(len);
    1221           0 :         if (len > 0) {
    1222           0 :                 if (rem >= len)
    1223           0 :                         *dposp += len;
    1224           0 :                 else if ((error = nfs_adv(mdp, dposp, len, rem)) != 0)
    1225             :                         goto out;
    1226             :         }
    1227           0 :         ndp->ni_pathlen = tocp - cnp->cn_pnbuf;
    1228           0 :         cnp->cn_nameptr = cnp->cn_pnbuf;
    1229             :         /*
    1230             :          * Extract and set starting directory.
    1231             :          */
    1232           0 :         error = nfsrv_fhtovp(fhp, 0, &dp, ndp->ni_cnd.cn_cred, slp,
    1233             :             nam, &rdonly);
    1234           0 :         if (error)
    1235             :                 goto out;
    1236           0 :         if (dp->v_type != VDIR) {
    1237           0 :                 vrele(dp);
    1238             :                 error = ENOTDIR;
    1239           0 :                 goto out;
    1240             :         }
    1241           0 :         vref(dp);
    1242           0 :         *retdirp = dp;
    1243           0 :         ndp->ni_startdir = dp;
    1244           0 :         if (rdonly)
    1245           0 :                 cnp->cn_flags |= (NOCROSSMOUNT | RDONLY);
    1246             :         else
    1247           0 :                 cnp->cn_flags |= NOCROSSMOUNT;
    1248             : 
    1249             :         /*
    1250             :          * And call lookup() to do the real work
    1251             :          */
    1252           0 :         cnp->cn_proc = p;
    1253           0 :         error = vfs_lookup(ndp);
    1254           0 :         if (error)
    1255             :                 goto out;
    1256             :         /*
    1257             :          * Check for encountering a symbolic link
    1258             :          */
    1259           0 :         if (cnp->cn_flags & ISSYMLINK) {
    1260           0 :                 if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1)
    1261           0 :                         vput(ndp->ni_dvp);
    1262             :                 else
    1263           0 :                         vrele(ndp->ni_dvp);
    1264           0 :                 vput(ndp->ni_vp);
    1265           0 :                 ndp->ni_vp = NULL;
    1266             :                 error = EINVAL;
    1267           0 :                 goto out;
    1268             :         }
    1269             :         /*
    1270             :          * Check for saved name request
    1271             :          */
    1272           0 :         if (cnp->cn_flags & (SAVENAME | SAVESTART)) {
    1273           0 :                 cnp->cn_flags |= HASBUF;
    1274           0 :                 return (0);
    1275             :         }
    1276             : out:
    1277           0 :         pool_put(&namei_pool, cnp->cn_pnbuf);
    1278           0 :         return (error);
    1279           0 : }
    1280             : 
    1281             : /*
    1282             :  * A fiddled version of m_adj() that ensures null fill to a long
    1283             :  * boundary and only trims off the back end
    1284             :  */
    1285             : void
    1286           0 : nfsm_adj(struct mbuf *mp, int len, int nul)
    1287             : {
    1288             :         struct mbuf *m;
    1289             :         int count, i;
    1290             :         char *cp;
    1291             : 
    1292             :         /*
    1293             :          * Trim from tail.  Scan the mbuf chain,
    1294             :          * calculating its length and finding the last mbuf.
    1295             :          * If the adjustment only affects this mbuf, then just
    1296             :          * adjust and return.  Otherwise, rescan and truncate
    1297             :          * after the remaining size.
    1298             :          */
    1299             :         count = 0;
    1300             :         m = mp;
    1301           0 :         for (;;) {
    1302           0 :                 count += m->m_len;
    1303           0 :                 if (m->m_next == NULL)
    1304             :                         break;
    1305             :                 m = m->m_next;
    1306             :         }
    1307           0 :         if (m->m_len > len) {
    1308           0 :                 m->m_len -= len;
    1309           0 :                 if (nul > 0) {
    1310           0 :                         cp = mtod(m, caddr_t)+m->m_len-nul;
    1311           0 :                         for (i = 0; i < nul; i++)
    1312           0 :                                 *cp++ = '\0';
    1313             :                 }
    1314           0 :                 return;
    1315             :         }
    1316           0 :         count -= len;
    1317           0 :         if (count < 0)
    1318             :                 count = 0;
    1319             :         /*
    1320             :          * Correct length for chain is "count".
    1321             :          * Find the mbuf with last data, adjust its length,
    1322             :          * and toss data from remaining mbufs on chain.
    1323             :          */
    1324           0 :         for (m = mp; m; m = m->m_next) {
    1325           0 :                 if (m->m_len >= count) {
    1326           0 :                         m->m_len = count;
    1327           0 :                         if (nul > 0) {
    1328           0 :                                 cp = mtod(m, caddr_t)+m->m_len-nul;
    1329           0 :                                 for (i = 0; i < nul; i++)
    1330           0 :                                         *cp++ = '\0';
    1331             :                         }
    1332             :                         break;
    1333             :                 }
    1334           0 :                 count -= m->m_len;
    1335             :         }
    1336           0 :         for (m = m->m_next;m;m = m->m_next)
    1337           0 :                 m->m_len = 0;
    1338           0 : }
    1339             : 
    1340             : /*
    1341             :  * Make these functions instead of macros, so that the kernel text size
    1342             :  * doesn't get too big...
    1343             :  */
    1344             : void
    1345           0 : nfsm_srvwcc(struct nfsrv_descript *nfsd, int before_ret,
    1346             :     struct vattr *before_vap, int after_ret, struct vattr *after_vap,
    1347             :     struct nfsm_info *info)
    1348             : {
    1349             :         u_int32_t *tl;
    1350             : 
    1351           0 :         if (before_ret) {
    1352           0 :                 tl = nfsm_build(&info->nmi_mb, NFSX_UNSIGNED);
    1353           0 :                 *tl = nfs_false;
    1354           0 :         } else {
    1355           0 :                 tl = nfsm_build(&info->nmi_mb, 7 * NFSX_UNSIGNED);
    1356           0 :                 *tl++ = nfs_true;
    1357           0 :                 txdr_hyper(before_vap->va_size, tl);
    1358           0 :                 tl += 2;
    1359           0 :                 txdr_nfsv3time(&(before_vap->va_mtime), tl);
    1360           0 :                 tl += 2;
    1361           0 :                 txdr_nfsv3time(&(before_vap->va_ctime), tl);
    1362             :         }
    1363           0 :         nfsm_srvpostop_attr(nfsd, after_ret, after_vap, info);
    1364           0 : }
    1365             : 
    1366             : void
    1367           0 : nfsm_srvpostop_attr(struct nfsrv_descript *nfsd, int after_ret,
    1368             :     struct vattr *after_vap, struct nfsm_info *info)
    1369             : {
    1370             :         u_int32_t *tl;
    1371             :         struct nfs_fattr *fp;
    1372             : 
    1373           0 :         if (after_ret) {
    1374           0 :                 tl = nfsm_build(&info->nmi_mb, NFSX_UNSIGNED);
    1375           0 :                 *tl = nfs_false;
    1376           0 :         } else {
    1377           0 :                 tl = nfsm_build(&info->nmi_mb, NFSX_UNSIGNED + NFSX_V3FATTR);
    1378           0 :                 *tl++ = nfs_true;
    1379           0 :                 fp = (struct nfs_fattr *)tl;
    1380           0 :                 nfsm_srvfattr(nfsd, after_vap, fp);
    1381             :         }
    1382           0 : }
    1383             : 
    1384             : void
    1385           0 : nfsm_srvfattr(struct nfsrv_descript *nfsd, struct vattr *vap,
    1386             :     struct nfs_fattr *fp)
    1387             : {
    1388             : 
    1389           0 :         fp->fa_nlink = txdr_unsigned(vap->va_nlink);
    1390           0 :         fp->fa_uid = txdr_unsigned(vap->va_uid);
    1391           0 :         fp->fa_gid = txdr_unsigned(vap->va_gid);
    1392           0 :         if (nfsd->nd_flag & ND_NFSV3) {
    1393           0 :                 fp->fa_type = vtonfsv3_type(vap->va_type);
    1394           0 :                 fp->fa_mode = vtonfsv3_mode(vap->va_mode);
    1395           0 :                 txdr_hyper(vap->va_size, &fp->fa3_size);
    1396           0 :                 txdr_hyper(vap->va_bytes, &fp->fa3_used);
    1397           0 :                 fp->fa3_rdev.specdata1 = txdr_unsigned(major(vap->va_rdev));
    1398           0 :                 fp->fa3_rdev.specdata2 = txdr_unsigned(minor(vap->va_rdev));
    1399           0 :                 fp->fa3_fsid.nfsuquad[0] = 0;
    1400           0 :                 fp->fa3_fsid.nfsuquad[1] = txdr_unsigned(vap->va_fsid);
    1401           0 :                 txdr_hyper(vap->va_fileid, &fp->fa3_fileid);
    1402           0 :                 txdr_nfsv3time(&vap->va_atime, &fp->fa3_atime);
    1403           0 :                 txdr_nfsv3time(&vap->va_mtime, &fp->fa3_mtime);
    1404           0 :                 txdr_nfsv3time(&vap->va_ctime, &fp->fa3_ctime);
    1405           0 :         } else {
    1406           0 :                 fp->fa_type = vtonfsv2_type(vap->va_type);
    1407           0 :                 fp->fa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode);
    1408           0 :                 fp->fa2_size = txdr_unsigned(vap->va_size);
    1409           0 :                 fp->fa2_blocksize = txdr_unsigned(vap->va_blocksize);
    1410           0 :                 if (vap->va_type == VFIFO)
    1411           0 :                         fp->fa2_rdev = 0xffffffff;
    1412             :                 else
    1413           0 :                         fp->fa2_rdev = txdr_unsigned(vap->va_rdev);
    1414           0 :                 fp->fa2_blocks = txdr_unsigned(vap->va_bytes / NFS_FABLKSIZE);
    1415           0 :                 fp->fa2_fsid = txdr_unsigned(vap->va_fsid);
    1416           0 :                 fp->fa2_fileid = txdr_unsigned((u_int32_t)vap->va_fileid);
    1417           0 :                 txdr_nfsv2time(&vap->va_atime, &fp->fa2_atime);
    1418           0 :                 txdr_nfsv2time(&vap->va_mtime, &fp->fa2_mtime);
    1419           0 :                 txdr_nfsv2time(&vap->va_ctime, &fp->fa2_ctime);
    1420             :         }
    1421           0 : }
    1422             : 
    1423             : /*
    1424             :  * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked)
    1425             :  *      - look up fsid in mount list (if not found ret error)
    1426             :  *      - get vp and export rights by calling VFS_FHTOVP() and VFS_CHECKEXP()
    1427             :  *      - if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon
    1428             :  *      - if not lockflag unlock it with VOP_UNLOCK()
    1429             :  */
    1430             : int
    1431           0 : nfsrv_fhtovp(fhandle_t *fhp, int lockflag, struct vnode **vpp,
    1432             :     struct ucred *cred, struct nfssvc_sock *slp, struct mbuf *nam,
    1433             :     int *rdonlyp)
    1434             : {
    1435             :         struct mount *mp;
    1436             :         int i;
    1437           0 :         struct ucred *credanon;
    1438           0 :         int error, exflags;
    1439             :         struct sockaddr_in *saddr;
    1440             : 
    1441           0 :         *vpp = NULL;
    1442           0 :         mp = vfs_getvfs(&fhp->fh_fsid);
    1443             : 
    1444           0 :         if (!mp)
    1445           0 :                 return (ESTALE);
    1446           0 :         error = VFS_CHECKEXP(mp, nam, &exflags, &credanon);
    1447           0 :         if (error)
    1448           0 :                 return (error);
    1449           0 :         error = VFS_FHTOVP(mp, &fhp->fh_fid, vpp);
    1450           0 :         if (error)
    1451           0 :                 return (error);
    1452             : 
    1453           0 :         saddr = mtod(nam, struct sockaddr_in *);
    1454           0 :         if (saddr->sin_family == AF_INET &&
    1455           0 :             (ntohs(saddr->sin_port) >= IPPORT_RESERVED ||
    1456           0 :             (slp->ns_so->so_type == SOCK_STREAM && ntohs(saddr->sin_port) == 20))) {
    1457           0 :                 vput(*vpp);
    1458           0 :                 return (NFSERR_AUTHERR | AUTH_TOOWEAK);
    1459             :         }
    1460             : 
    1461             :         /* Check/setup credentials. */
    1462           0 :         if (cred->cr_uid == 0 || (exflags & MNT_EXPORTANON)) {
    1463           0 :                 cred->cr_uid = credanon->cr_uid;
    1464           0 :                 cred->cr_gid = credanon->cr_gid;
    1465           0 :                 for (i = 0; i < credanon->cr_ngroups && i < NGROUPS_MAX; i++)
    1466           0 :                         cred->cr_groups[i] = credanon->cr_groups[i];
    1467           0 :                 cred->cr_ngroups = i;
    1468           0 :         }
    1469           0 :         if (exflags & MNT_EXRDONLY)
    1470           0 :                 *rdonlyp = 1;
    1471             :         else
    1472           0 :                 *rdonlyp = 0;
    1473           0 :         if (!lockflag)
    1474           0 :                 VOP_UNLOCK(*vpp);
    1475             : 
    1476           0 :         return (0);
    1477           0 : }
    1478             : 
    1479             : /*
    1480             :  * This function compares two net addresses by family and returns non zero
    1481             :  * if they are the same host, or if there is any doubt it returns 0.
    1482             :  * The AF_INET family is handled as a special case so that address mbufs
    1483             :  * don't need to be saved to store "struct in_addr", which is only 4 bytes.
    1484             :  */
    1485             : int
    1486           0 : netaddr_match(int family, union nethostaddr *haddr, struct mbuf *nam)
    1487             : {
    1488             :         struct sockaddr_in *inetaddr;
    1489             : 
    1490           0 :         switch (family) {
    1491             :         case AF_INET:
    1492           0 :                 inetaddr = mtod(nam, struct sockaddr_in *);
    1493           0 :                 if (inetaddr->sin_family == AF_INET &&
    1494           0 :                     inetaddr->sin_addr.s_addr == haddr->had_inetaddr)
    1495           0 :                         return (1);
    1496             :                 break;
    1497             :         default:
    1498             :                 break;
    1499             :         };
    1500           0 :         return (0);
    1501           0 : }
    1502             : 
    1503             : /*
    1504             :  * The write verifier has changed (probably due to a server reboot), so all
    1505             :  * B_NEEDCOMMIT blocks will have to be written again. Since they are on the
    1506             :  * dirty block list as B_DELWRI, all this takes is clearing the B_NEEDCOMMIT
    1507             :  * flag. Once done the new write verifier can be set for the mount point.
    1508             :  */
    1509             : void
    1510           0 : nfs_clearcommit(struct mount *mp)
    1511             : {
    1512             :         struct vnode *vp, *nvp;
    1513             :         struct buf *bp, *nbp;
    1514             :         int s;
    1515             : 
    1516           0 :         s = splbio();
    1517             : loop:
    1518           0 :         for (vp = LIST_FIRST(&mp->mnt_vnodelist); vp != NULL; vp = nvp) {
    1519           0 :                 if (vp->v_mount != mp)       /* Paranoia */
    1520           0 :                         goto loop;
    1521           0 :                 nvp = LIST_NEXT(vp, v_mntvnodes);
    1522           0 :                 LIST_FOREACH_SAFE(bp, &vp->v_dirtyblkhd, b_vnbufs, nbp) {
    1523           0 :                         if ((bp->b_flags & (B_BUSY | B_DELWRI | B_NEEDCOMMIT))
    1524           0 :                             == (B_DELWRI | B_NEEDCOMMIT))
    1525           0 :                                 bp->b_flags &= ~B_NEEDCOMMIT;
    1526             :                 }
    1527             :         }
    1528           0 :         splx(s);
    1529           0 : }
    1530             : 
    1531             : void
    1532           0 : nfs_merge_commit_ranges(struct vnode *vp)
    1533             : {
    1534           0 :         struct nfsnode *np = VTONFS(vp);
    1535             : 
    1536           0 :         if (!(np->n_commitflags & NFS_COMMIT_PUSHED_VALID)) {
    1537           0 :                 np->n_pushedlo = np->n_pushlo;
    1538           0 :                 np->n_pushedhi = np->n_pushhi;
    1539           0 :                 np->n_commitflags |= NFS_COMMIT_PUSHED_VALID;
    1540           0 :         } else {
    1541           0 :                 if (np->n_pushlo < np->n_pushedlo)
    1542           0 :                         np->n_pushedlo = np->n_pushlo;
    1543           0 :                 if (np->n_pushhi > np->n_pushedhi)
    1544           0 :                         np->n_pushedhi = np->n_pushhi;
    1545             :         }
    1546             : 
    1547           0 :         np->n_pushlo = np->n_pushhi = 0;
    1548           0 :         np->n_commitflags &= ~NFS_COMMIT_PUSH_VALID;
    1549           0 : }
    1550             : 
    1551             : int
    1552           0 : nfs_in_committed_range(struct vnode *vp, struct buf *bp)
    1553             : {
    1554           0 :         struct nfsnode *np = VTONFS(vp);
    1555             :         off_t lo, hi;
    1556             : 
    1557           0 :         if (!(np->n_commitflags & NFS_COMMIT_PUSHED_VALID))
    1558           0 :                 return 0;
    1559           0 :         lo = (off_t)bp->b_blkno * DEV_BSIZE;
    1560           0 :         hi = lo + bp->b_dirtyend;
    1561             : 
    1562           0 :         return (lo >= np->n_pushedlo && hi <= np->n_pushedhi);
    1563           0 : }
    1564             : 
    1565             : int
    1566           0 : nfs_in_tobecommitted_range(struct vnode *vp, struct buf *bp)
    1567             : {
    1568           0 :         struct nfsnode *np = VTONFS(vp);
    1569             :         off_t lo, hi;
    1570             : 
    1571           0 :         if (!(np->n_commitflags & NFS_COMMIT_PUSH_VALID))
    1572           0 :                 return 0;
    1573           0 :         lo = (off_t)bp->b_blkno * DEV_BSIZE;
    1574           0 :         hi = lo + bp->b_dirtyend;
    1575             : 
    1576           0 :         return (lo >= np->n_pushlo && hi <= np->n_pushhi);
    1577           0 : }
    1578             : 
    1579             : void
    1580           0 : nfs_add_committed_range(struct vnode *vp, struct buf *bp)
    1581             : {
    1582           0 :         struct nfsnode *np = VTONFS(vp);
    1583             :         off_t lo, hi;
    1584             : 
    1585           0 :         lo = (off_t)bp->b_blkno * DEV_BSIZE;
    1586           0 :         hi = lo + bp->b_dirtyend;
    1587             : 
    1588           0 :         if (!(np->n_commitflags & NFS_COMMIT_PUSHED_VALID)) {
    1589           0 :                 np->n_pushedlo = lo;
    1590           0 :                 np->n_pushedhi = hi;
    1591           0 :                 np->n_commitflags |= NFS_COMMIT_PUSHED_VALID;
    1592           0 :         } else {
    1593           0 :                 if (hi > np->n_pushedhi)
    1594           0 :                         np->n_pushedhi = hi;
    1595           0 :                 if (lo < np->n_pushedlo)
    1596           0 :                         np->n_pushedlo = lo;
    1597             :         }
    1598           0 : }
    1599             : 
    1600             : void
    1601           0 : nfs_del_committed_range(struct vnode *vp, struct buf *bp)
    1602             : {
    1603           0 :         struct nfsnode *np = VTONFS(vp);
    1604             :         off_t lo, hi;
    1605             : 
    1606           0 :         if (!(np->n_commitflags & NFS_COMMIT_PUSHED_VALID))
    1607           0 :                 return;
    1608             : 
    1609           0 :         lo = (off_t)bp->b_blkno * DEV_BSIZE;
    1610           0 :         hi = lo + bp->b_dirtyend;
    1611             : 
    1612           0 :         if (lo > np->n_pushedhi || hi < np->n_pushedlo)
    1613           0 :                 return;
    1614           0 :         if (lo <= np->n_pushedlo)
    1615           0 :                 np->n_pushedlo = hi;
    1616           0 :         else if (hi >= np->n_pushedhi)
    1617           0 :                 np->n_pushedhi = lo;
    1618             :         else {
    1619             :                 /*
    1620             :                  * XXX There's only one range. If the deleted range
    1621             :                  * is in the middle, pick the largest of the
    1622             :                  * contiguous ranges that it leaves.
    1623             :                  */
    1624           0 :                 if ((np->n_pushedlo - lo) > (hi - np->n_pushedhi))
    1625           0 :                         np->n_pushedhi = lo;
    1626             :                 else
    1627           0 :                         np->n_pushedlo = hi;
    1628             :         }
    1629           0 : }
    1630             : 
    1631             : void
    1632           0 : nfs_add_tobecommitted_range(struct vnode *vp, struct buf *bp)
    1633             : {
    1634           0 :         struct nfsnode *np = VTONFS(vp);
    1635             :         off_t lo, hi;
    1636             : 
    1637           0 :         lo = (off_t)bp->b_blkno * DEV_BSIZE;
    1638           0 :         hi = lo + bp->b_dirtyend;
    1639             : 
    1640           0 :         if (!(np->n_commitflags & NFS_COMMIT_PUSH_VALID)) {
    1641           0 :                 np->n_pushlo = lo;
    1642           0 :                 np->n_pushhi = hi;
    1643           0 :                 np->n_commitflags |= NFS_COMMIT_PUSH_VALID;
    1644           0 :         } else {
    1645           0 :                 if (lo < np->n_pushlo)
    1646           0 :                         np->n_pushlo = lo;
    1647           0 :                 if (hi > np->n_pushhi)
    1648           0 :                         np->n_pushhi = hi;
    1649             :         }
    1650           0 : }
    1651             : 
    1652             : void
    1653           0 : nfs_del_tobecommitted_range(struct vnode *vp, struct buf *bp)
    1654             : {
    1655           0 :         struct nfsnode *np = VTONFS(vp);
    1656             :         off_t lo, hi;
    1657             : 
    1658           0 :         if (!(np->n_commitflags & NFS_COMMIT_PUSH_VALID))
    1659           0 :                 return;
    1660             : 
    1661           0 :         lo = (off_t)bp->b_blkno * DEV_BSIZE;
    1662           0 :         hi = lo + bp->b_dirtyend;
    1663             : 
    1664           0 :         if (lo > np->n_pushhi || hi < np->n_pushlo)
    1665           0 :                 return;
    1666             : 
    1667           0 :         if (lo <= np->n_pushlo)
    1668           0 :                 np->n_pushlo = hi;
    1669           0 :         else if (hi >= np->n_pushhi)
    1670           0 :                 np->n_pushhi = lo;
    1671             :         else {
    1672             :                 /*
    1673             :                  * XXX There's only one range. If the deleted range
    1674             :                  * is in the middle, pick the largest of the
    1675             :                  * contiguous ranges that it leaves.
    1676             :                  */
    1677           0 :                 if ((np->n_pushlo - lo) > (hi - np->n_pushhi))
    1678           0 :                         np->n_pushhi = lo;
    1679             :                 else
    1680           0 :                         np->n_pushlo = hi;
    1681             :         }
    1682           0 : }
    1683             : 
    1684             : /*
    1685             :  * Map errnos to NFS error numbers. For Version 3 also filter out error
    1686             :  * numbers not specified for the associated procedure.
    1687             :  */
    1688             : int
    1689           0 : nfsrv_errmap(struct nfsrv_descript *nd, int err)
    1690             : {
    1691             :         short *defaulterrp, *errp;
    1692             : 
    1693           0 :         if (nd->nd_flag & ND_NFSV3) {
    1694           0 :             if (nd->nd_procnum <= NFSPROC_COMMIT) {
    1695           0 :                 errp = defaulterrp = nfsrv_v3errmap[nd->nd_procnum];
    1696           0 :                 while (*++errp) {
    1697           0 :                         if (*errp == err)
    1698           0 :                                 return (err);
    1699           0 :                         else if (*errp > err)
    1700             :                                 break;
    1701             :                 }
    1702           0 :                 return ((int)*defaulterrp);
    1703             :             } else
    1704           0 :                 return (err & 0xffff);
    1705             :         }
    1706           0 :         if (err <= nitems(nfsrv_v2errmap))
    1707           0 :                 return ((int)nfsrv_v2errmap[err - 1]);
    1708           0 :         return (NFSERR_IO);
    1709           0 : }
    1710             : 
    1711             : /*
    1712             :  * If full is non zero, set all fields, otherwise just set mode and time fields
    1713             :  */
    1714             : void
    1715           0 : nfsm_v3attrbuild(struct mbuf **mp, struct vattr *a, int full)
    1716             : {
    1717           0 :         struct mbuf *mb;
    1718             :         u_int32_t *tl;
    1719             : 
    1720           0 :         mb = *mp;
    1721             : 
    1722           0 :         if (a->va_mode != (mode_t)VNOVAL) {
    1723           0 :                 tl = nfsm_build(&mb, 2 * NFSX_UNSIGNED);
    1724           0 :                 *tl++ = nfs_true;
    1725           0 :                 *tl = txdr_unsigned(a->va_mode);
    1726           0 :         } else {
    1727           0 :                 tl = nfsm_build(&mb, NFSX_UNSIGNED);
    1728           0 :                 *tl = nfs_false;
    1729             :         }
    1730           0 :         if (full && a->va_uid != (uid_t)VNOVAL) {
    1731           0 :                 tl = nfsm_build(&mb, 2 * NFSX_UNSIGNED);
    1732           0 :                 *tl++ = nfs_true;
    1733           0 :                 *tl = txdr_unsigned(a->va_uid);
    1734           0 :         } else {
    1735           0 :                 tl = nfsm_build(&mb, NFSX_UNSIGNED);
    1736           0 :                 *tl = nfs_false;
    1737             :         }
    1738           0 :         if (full && a->va_gid != (gid_t)VNOVAL) {
    1739           0 :                 tl = nfsm_build(&mb, 2 * NFSX_UNSIGNED);
    1740           0 :                 *tl++ = nfs_true;
    1741           0 :                 *tl = txdr_unsigned((a)->va_gid);
    1742           0 :         } else {
    1743           0 :                 tl = nfsm_build(&mb, NFSX_UNSIGNED);
    1744           0 :                 *tl = nfs_false;
    1745             :         }
    1746           0 :         if (full && a->va_size != VNOVAL) {
    1747           0 :                 tl = nfsm_build(&mb, 3 * NFSX_UNSIGNED);
    1748           0 :                 *tl++ = nfs_true;
    1749           0 :                 txdr_hyper(a->va_size, tl);
    1750           0 :         } else {
    1751           0 :                 tl = nfsm_build(&mb, NFSX_UNSIGNED);
    1752           0 :                 *tl = nfs_false;
    1753             :         }
    1754           0 :         if (a->va_atime.tv_nsec != VNOVAL) {
    1755           0 :                 if (a->va_atime.tv_sec != time_second) {
    1756           0 :                         tl = nfsm_build(&mb, 3 * NFSX_UNSIGNED);
    1757           0 :                         *tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT);
    1758           0 :                         txdr_nfsv3time(&a->va_atime, tl);
    1759           0 :                 } else {
    1760           0 :                         tl = nfsm_build(&mb, NFSX_UNSIGNED);
    1761           0 :                         *tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER);
    1762             :                 }
    1763             :         } else {
    1764           0 :                 tl = nfsm_build(&mb, NFSX_UNSIGNED);
    1765           0 :                 *tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE);
    1766             :         }
    1767           0 :         if (a->va_mtime.tv_nsec != VNOVAL) {
    1768           0 :                 if (a->va_mtime.tv_sec != time_second) {
    1769           0 :                         tl = nfsm_build(&mb, 3 * NFSX_UNSIGNED);
    1770           0 :                         *tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT);
    1771           0 :                         txdr_nfsv3time(&a->va_mtime, tl);
    1772           0 :                 } else {
    1773           0 :                         tl = nfsm_build(&mb, NFSX_UNSIGNED);
    1774           0 :                         *tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER);
    1775             :                 }
    1776             :         } else {
    1777           0 :                 tl = nfsm_build(&mb, NFSX_UNSIGNED);
    1778           0 :                 *tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE);
    1779             :         }
    1780             : 
    1781           0 :         *mp = mb;
    1782           0 : }
    1783             : 
    1784             : /*
    1785             :  * Ensure a contiguous buffer len bytes long
    1786             :  */
    1787             : void *
    1788           0 : nfsm_build(struct mbuf **mp, u_int len)
    1789             : {
    1790             :         struct mbuf *mb, *mb2;
    1791             :         caddr_t bpos;
    1792             : 
    1793           0 :         mb = *mp;
    1794           0 :         bpos = mb_offset(mb);
    1795             : 
    1796           0 :         if (len > M_TRAILINGSPACE(mb)) {
    1797           0 :                 MGET(mb2, M_WAIT, MT_DATA);
    1798           0 :                 if (len > MLEN)
    1799           0 :                         panic("build > MLEN");
    1800           0 :                 mb->m_next = mb2;
    1801             :                 mb = mb2;
    1802           0 :                 mb->m_len = 0;
    1803           0 :                 bpos = mtod(mb, caddr_t);
    1804           0 :         }
    1805           0 :         mb->m_len += len;
    1806             : 
    1807           0 :         *mp = mb;
    1808             : 
    1809           0 :         return (bpos);
    1810             : }
    1811             : 
    1812             : void
    1813           0 : nfsm_fhtom(struct nfsm_info *info, struct vnode *v, int v3)
    1814             : {
    1815           0 :         struct nfsnode *n = VTONFS(v);
    1816             : 
    1817           0 :         if (v3) {
    1818           0 :                 nfsm_strtombuf(&info->nmi_mb, n->n_fhp, n->n_fhsize);
    1819           0 :         } else {
    1820           0 :                 nfsm_buftombuf(&info->nmi_mb, n->n_fhp, NFSX_V2FH);
    1821             :         }
    1822           0 : }
    1823             : 
    1824             : void
    1825           0 : nfsm_srvfhtom(struct mbuf **mp, fhandle_t *f, int v3)
    1826             : {
    1827           0 :         if (v3) {
    1828           0 :                 nfsm_strtombuf(mp, f, NFSX_V3FH);
    1829           0 :         } else {
    1830           0 :                 nfsm_buftombuf(mp, f, NFSX_V2FH);
    1831             :         }
    1832           0 : }
    1833             : 
    1834             : int
    1835           0 : nfsm_srvsattr(struct mbuf **mp, struct vattr *va, struct mbuf *mrep,
    1836             :     caddr_t *dposp)
    1837             : {
    1838           0 :         struct nfsm_info        info;
    1839             :         uint32_t *tl, t1;
    1840           0 :         caddr_t cp2;
    1841             :         int error = 0;
    1842             : 
    1843           0 :         info.nmi_md = *mp;
    1844           0 :         info.nmi_dpos = *dposp;
    1845             : 
    1846           0 :         nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED);
    1847           0 :         if (*tl == nfs_true) {
    1848           0 :                 nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED);
    1849           0 :                 va->va_mode = nfstov_mode(*tl);
    1850           0 :         }
    1851             : 
    1852           0 :         nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED);
    1853           0 :         if (*tl == nfs_true) {
    1854           0 :                 nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED);
    1855           0 :                 va->va_uid = fxdr_unsigned(uid_t, *tl);
    1856           0 :         }
    1857             : 
    1858           0 :         nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED);
    1859           0 :         if (*tl == nfs_true) {
    1860           0 :                 nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED);
    1861           0 :                 va->va_gid = fxdr_unsigned(gid_t, *tl);
    1862           0 :         }
    1863             : 
    1864           0 :         nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED);
    1865           0 :         if (*tl == nfs_true) {
    1866           0 :                 nfsm_dissect(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
    1867           0 :                 va->va_size = fxdr_hyper(tl);
    1868           0 :         }
    1869             : 
    1870           0 :         nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED);
    1871           0 :         switch (fxdr_unsigned(int, *tl)) {
    1872             :         case NFSV3SATTRTIME_TOCLIENT:
    1873           0 :                 va->va_vaflags |= VA_UTIMES_CHANGE;
    1874           0 :                 va->va_vaflags &= ~VA_UTIMES_NULL;
    1875           0 :                 nfsm_dissect(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
    1876           0 :                 fxdr_nfsv3time(tl, &va->va_atime);
    1877           0 :                 break;
    1878             :         case NFSV3SATTRTIME_TOSERVER:
    1879           0 :                 va->va_vaflags |= VA_UTIMES_CHANGE;
    1880           0 :                 getnanotime(&va->va_atime);
    1881           0 :                 break;
    1882             :         };
    1883             : 
    1884           0 :         nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED);
    1885           0 :         switch (fxdr_unsigned(int, *tl)) {
    1886             :         case NFSV3SATTRTIME_TOCLIENT:
    1887           0 :                 va->va_vaflags |= VA_UTIMES_CHANGE;
    1888           0 :                 va->va_vaflags &= ~VA_UTIMES_NULL;
    1889           0 :                 nfsm_dissect(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
    1890           0 :                 fxdr_nfsv3time(tl, &va->va_mtime);
    1891           0 :                 break;
    1892             :         case NFSV3SATTRTIME_TOSERVER:
    1893           0 :                 va->va_vaflags |= VA_UTIMES_CHANGE;
    1894           0 :                 getnanotime(&va->va_mtime);
    1895           0 :                 break;
    1896             :         };
    1897             : 
    1898           0 :         *dposp = info.nmi_dpos;
    1899           0 :         *mp = info.nmi_md;
    1900             : nfsmout:
    1901           0 :         return (error);
    1902           0 : }
    1903             : 
    1904             : void
    1905           0 : txdr_nfsv2time(const struct timespec *from, struct nfsv2_time *to)
    1906             : {
    1907           0 :         if (from->tv_nsec == VNOVAL) {
    1908           0 :                 to->nfsv2_sec = nfs_xdrneg1;
    1909           0 :                 to->nfsv2_usec = nfs_xdrneg1;
    1910           0 :         } else if (from->tv_sec == -1) {
    1911             :                 /*
    1912             :                  * can't request a time of -1; send
    1913             :                  * -1.000001 == {-2,999999} instead
    1914             :                  */
    1915           0 :                 to->nfsv2_sec = htonl(-2);
    1916           0 :                 to->nfsv2_usec = htonl(999999);
    1917           0 :         } else {
    1918           0 :                 to->nfsv2_sec = htonl(from->tv_sec);
    1919           0 :                 to->nfsv2_usec = htonl(from->tv_nsec / 1000);
    1920             :         }
    1921           0 : }

Generated by: LCOV version 1.13