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


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

FreeBSD/Linux Kernel Cross Reference
sys/fs/nfs/nfs_commonsubs.c

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

    1 /*-
    2  * SPDX-License-Identifier: BSD-3-Clause
    3  *
    4  * Copyright (c) 1989, 1993
    5  *      The Regents of the University of California.  All rights reserved.
    6  *
    7  * This code is derived from software contributed to Berkeley by
    8  * Rick Macklem at The University of Guelph.
    9  *
   10  * Redistribution and use in source and binary forms, with or without
   11  * modification, are permitted provided that the following conditions
   12  * are met:
   13  * 1. Redistributions of source code must retain the above copyright
   14  *    notice, this list of conditions and the following disclaimer.
   15  * 2. Redistributions in binary form must reproduce the above copyright
   16  *    notice, this list of conditions and the following disclaimer in the
   17  *    documentation and/or other materials provided with the distribution.
   18  * 3. Neither the name of the University nor the names of its contributors
   19  *    may be used to endorse or promote products derived from this software
   20  *    without specific prior written permission.
   21  *
   22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   32  * SUCH DAMAGE.
   33  *
   34  */
   35 
   36 #include <sys/cdefs.h>
   37 __FBSDID("$FreeBSD$");
   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 "opt_inet.h"
   45 #include "opt_inet6.h"
   46 
   47 #include <fs/nfs/nfsport.h>
   48 
   49 #include <sys/extattr.h>
   50 
   51 #include <security/mac/mac_framework.h>
   52 
   53 #include <vm/vm_param.h>
   54 
   55 /*
   56  * Data items converted to xdr at startup, since they are constant
   57  * This is kinda hokey, but may save a little time doing byte swaps
   58  */
   59 u_int32_t newnfs_true, newnfs_false, newnfs_xdrneg1;
   60 
   61 /* And other global data */
   62 nfstype nfsv34_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFSOCK,
   63                       NFFIFO, NFNON };
   64 enum vtype newnv2tov_type[8] = { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON, VNON };
   65 enum vtype nv34tov_type[8]={ VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO };
   66 struct timeval nfsboottime;     /* Copy boottime once, so it never changes */
   67 int nfscl_ticks;
   68 int nfsrv_useacl = 1;
   69 struct nfssockreq nfsrv_nfsuserdsock;
   70 nfsuserd_state nfsrv_nfsuserd = NOTRUNNING;
   71 static int nfsrv_userdupcalls = 0;
   72 struct nfsreqhead nfsd_reqq;
   73 uid_t nfsrv_defaultuid = UID_NOBODY;
   74 gid_t nfsrv_defaultgid = GID_NOGROUP;
   75 int nfsrv_lease = NFSRV_LEASE;
   76 int ncl_mbuf_mlen = MLEN;
   77 int nfsd_enable_stringtouid = 0;
   78 int nfsrv_doflexfile = 0;
   79 static int nfs_enable_uidtostring = 0;
   80 NFSNAMEIDMUTEX;
   81 NFSSOCKMUTEX;
   82 extern int nfsrv_lughashsize;
   83 extern struct mtx nfsrv_dslock_mtx;
   84 extern volatile int nfsrv_devidcnt;
   85 extern int nfscl_debuglevel;
   86 extern struct nfsdevicehead nfsrv_devidhead;
   87 extern struct nfsstatsv1 nfsstatsv1;
   88 extern uint32_t nfs_srvmaxio;
   89 
   90 SYSCTL_DECL(_vfs_nfs);
   91 SYSCTL_INT(_vfs_nfs, OID_AUTO, enable_uidtostring, CTLFLAG_RW,
   92     &nfs_enable_uidtostring, 0, "Make nfs always send numeric owner_names");
   93 
   94 int nfsrv_maxpnfsmirror = 1;
   95 SYSCTL_INT(_vfs_nfs, OID_AUTO, pnfsmirror, CTLFLAG_RD,
   96     &nfsrv_maxpnfsmirror, 0, "Mirror level for pNFS service");
   97 
   98 /*
   99  * This array of structures indicates, for V4:
  100  * retfh - which of 3 types of calling args are used
  101  *      0 - doesn't change cfh or use a sfh
  102  *      1 - replaces cfh with a new one (unless it returns an error status)
  103  *      2 - uses cfh and sfh
  104  * needscfh - if the op wants a cfh and premtime
  105  *      0 - doesn't use a cfh
  106  *      1 - uses a cfh, but doesn't want pre-op attributes
  107  *      2 - uses a cfh and wants pre-op attributes
  108  * savereply - indicates a non-idempotent Op
  109  *      0 - not non-idempotent
  110  *      1 - non-idempotent
  111  * Ops that are ordered via seqid# are handled separately from these
  112  * non-idempotent Ops.
  113  * Define it here, since it is used by both the client and server.
  114  */
  115 struct nfsv4_opflag nfsv4_opflag[NFSV42_NOPS] = {
  116         { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },             /* undef */
  117         { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },             /* undef */
  118         { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },             /* undef */
  119         { 0, 1, 0, 0, LK_SHARED, 1, 1 },                /* Access */
  120         { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 },             /* Close */
  121         { 0, 2, 0, 1, LK_EXCLUSIVE, 1, 1 },             /* Commit */
  122         { 1, 2, 1, 1, LK_EXCLUSIVE, 1, 1 },             /* Create */
  123         { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 },             /* Delegpurge */
  124         { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 },             /* Delegreturn */
  125         { 0, 1, 0, 0, LK_SHARED, 1, 1 },                /* Getattr */
  126         { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 },             /* GetFH */
  127         { 2, 1, 1, 1, LK_EXCLUSIVE, 1, 1 },             /* Link */
  128         { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 },             /* Lock */
  129         { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 },             /* LockT */
  130         { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 },             /* LockU */
  131         { 1, 2, 0, 0, LK_EXCLUSIVE, 1, 1 },             /* Lookup */
  132         { 1, 2, 0, 0, LK_EXCLUSIVE, 1, 1 },             /* Lookupp */
  133         { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 },             /* NVerify */
  134         { 1, 1, 0, 1, LK_EXCLUSIVE, 1, 0 },             /* Open */
  135         { 1, 1, 0, 0, LK_EXCLUSIVE, 1, 0 },             /* OpenAttr */
  136         { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 },             /* OpenConfirm */
  137         { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 },             /* OpenDowngrade */
  138         { 1, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },             /* PutFH */
  139         { 1, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },             /* PutPubFH */
  140         { 1, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },             /* PutRootFH */
  141         { 0, 1, 0, 0, LK_SHARED, 1, 0 },                /* Read */
  142         { 0, 1, 0, 0, LK_SHARED, 1, 1 },                /* Readdir */
  143         { 0, 1, 0, 0, LK_SHARED, 1, 1 },                /* ReadLink */
  144         { 0, 2, 1, 1, LK_EXCLUSIVE, 1, 1 },             /* Remove */
  145         { 2, 1, 1, 1, LK_EXCLUSIVE, 1, 1 },             /* Rename */
  146         { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 },             /* Renew */
  147         { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },             /* RestoreFH */
  148         { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 },             /* SaveFH */
  149         { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 },             /* SecInfo */
  150         { 0, 2, 1, 1, LK_EXCLUSIVE, 1, 0 },             /* Setattr */
  151         { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },             /* SetClientID */
  152         { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },             /* SetClientIDConfirm */
  153         { 0, 2, 0, 0, LK_EXCLUSIVE, 1, 0 },             /* Verify (AppWrite) */
  154         { 0, 2, 1, 1, LK_EXCLUSIVE, 1, 0 },             /* Write */
  155         { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 },             /* ReleaseLockOwner */
  156         { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },             /* Backchannel Ctrl */
  157         { 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 },             /* Bind Conn to Sess */
  158         { 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 },             /* Exchange ID */
  159         { 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 },             /* Create Session */
  160         { 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 },             /* Destroy Session */
  161         { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 },             /* Free StateID */
  162         { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },             /* Get Dir Deleg */
  163         { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },             /* Get Device Info */
  164         { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },             /* Get Device List */
  165         { 0, 1, 0, 1, LK_EXCLUSIVE, 1, 1 },             /* Layout Commit */
  166         { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 },             /* Layout Get */
  167         { 0, 1, 0, 1, LK_EXCLUSIVE, 1, 0 },             /* Layout Return */
  168         { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 },             /* Secinfo No name */
  169         { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 },             /* Sequence */
  170         { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },             /* Set SSV */
  171         { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },             /* Test StateID */
  172         { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },             /* Want Delegation */
  173         { 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 },             /* Destroy ClientID */
  174         { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 },             /* Reclaim Complete */
  175         { 0, 1, 1, 1, LK_EXCLUSIVE, 1, 0 },             /* Allocate */
  176         { 2, 1, 1, 0, LK_SHARED, 1, 0 },                /* Copy */
  177         { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },             /* Copy Notify */
  178         { 0, 2, 1, 1, LK_EXCLUSIVE, 1, 0 },             /* Deallocate */
  179         { 0, 1, 0, 0, LK_SHARED, 1, 0 },                /* IO Advise */
  180         { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 },             /* Layout Error */
  181         { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 },             /* Layout Stats */
  182         { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },             /* Offload Cancel */
  183         { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },             /* Offload Status */
  184         { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },             /* Read Plus */
  185         { 0, 1, 0, 0, LK_SHARED, 1, 0 },                /* Seek */
  186         { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },             /* Write Same */
  187         { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 },             /* Clone */
  188         { 0, 1, 0, 0, LK_SHARED, 1, 1 },                /* Getxattr */
  189         { 0, 1, 1, 1, LK_EXCLUSIVE, 1, 1 },             /* Setxattr */
  190         { 0, 1, 0, 0, LK_SHARED, 1, 1 },                /* Listxattrs */
  191         { 0, 1, 1, 1, LK_EXCLUSIVE, 1, 1 },             /* Removexattr */
  192 };
  193 
  194 static int ncl_mbuf_mhlen = MHLEN;
  195 static int nfsrv_usercnt = 0;
  196 static int nfsrv_dnsnamelen;
  197 static u_char *nfsrv_dnsname = NULL;
  198 static int nfsrv_usermax = 999999999;
  199 struct nfsrv_lughash {
  200         struct mtx              mtx;
  201         struct nfsuserhashhead  lughead;
  202 };
  203 static struct nfsrv_lughash     *nfsuserhash;
  204 static struct nfsrv_lughash     *nfsusernamehash;
  205 static struct nfsrv_lughash     *nfsgrouphash;
  206 static struct nfsrv_lughash     *nfsgroupnamehash;
  207 
  208 /*
  209  * This static array indicates whether or not the RPC generates a large
  210  * reply. This is used by nfs_reply() to decide whether or not an mbuf
  211  * cluster should be allocated. (If a cluster is required by an RPC
  212  * marked 0 in this array, the code will still work, just not quite as
  213  * efficiently.)
  214  */
  215 static int nfs_bigreply[NFSV42_NPROCS] = { 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0,
  216     0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  217     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
  218     1, 0, 0, 1, 0, 0, 0, 0, 0 };
  219 
  220 /* local functions */
  221 static int nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep);
  222 static void nfsv4_wanted(struct nfsv4lock *lp);
  223 static uint32_t nfsv4_filesavail(struct statfs *, struct mount *);
  224 static int nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len);
  225 static int nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name);
  226 static void nfsrv_removeuser(struct nfsusrgrp *usrp, int isuser);
  227 static int nfsrv_getrefstr(struct nfsrv_descript *, u_char **, u_char **,
  228     int *, int *);
  229 static void nfsrv_refstrbigenough(int, u_char **, u_char **, int *);
  230 
  231 static struct {
  232         int     op;
  233         int     opcnt;
  234         const u_char *tag;
  235         int     taglen;
  236 } nfsv4_opmap[NFSV42_NPROCS] = {
  237         { 0, 1, "Null", 4 },
  238         { NFSV4OP_GETATTR, 1, "Getattr", 7, },
  239         { NFSV4OP_SETATTR, 2, "Setattr", 7, },
  240         { NFSV4OP_LOOKUP, 3, "Lookup", 6, },
  241         { NFSV4OP_ACCESS, 2, "Access", 6, },
  242         { NFSV4OP_READLINK, 2, "Readlink", 8, },
  243         { NFSV4OP_READ, 1, "Read", 4, },
  244         { NFSV4OP_WRITE, 2, "Write", 5, },
  245         { NFSV4OP_OPEN, 5, "Open", 4, },
  246         { NFSV4OP_CREATE, 5, "Create", 6, },
  247         { NFSV4OP_CREATE, 1, "Create", 6, },
  248         { NFSV4OP_CREATE, 3, "Create", 6, },
  249         { NFSV4OP_REMOVE, 1, "Remove", 6, },
  250         { NFSV4OP_REMOVE, 1, "Remove", 6, },
  251         { NFSV4OP_SAVEFH, 5, "Rename", 6, },
  252         { NFSV4OP_SAVEFH, 4, "Link", 4, },
  253         { NFSV4OP_READDIR, 2, "Readdir", 7, },
  254         { NFSV4OP_READDIR, 2, "Readdir", 7, },
  255         { NFSV4OP_GETATTR, 1, "Getattr", 7, },
  256         { NFSV4OP_GETATTR, 1, "Getattr", 7, },
  257         { NFSV4OP_GETATTR, 1, "Getattr", 7, },
  258         { NFSV4OP_COMMIT, 2, "Commit", 6, },
  259         { NFSV4OP_LOOKUPP, 3, "Lookupp", 7, },
  260         { NFSV4OP_SETCLIENTID, 1, "SetClientID", 11, },
  261         { NFSV4OP_SETCLIENTIDCFRM, 1, "SetClientIDConfirm", 18, },
  262         { NFSV4OP_LOCK, 1, "Lock", 4, },
  263         { NFSV4OP_LOCKU, 1, "LockU", 5, },
  264         { NFSV4OP_OPEN, 2, "Open", 4, },
  265         { NFSV4OP_CLOSE, 1, "Close", 5, },
  266         { NFSV4OP_OPENCONFIRM, 1, "Openconfirm", 11, },
  267         { NFSV4OP_LOCKT, 1, "LockT", 5, },
  268         { NFSV4OP_OPENDOWNGRADE, 1, "Opendowngrade", 13, },
  269         { NFSV4OP_RENEW, 1, "Renew", 5, },
  270         { NFSV4OP_PUTROOTFH, 1, "Dirpath", 7, },
  271         { NFSV4OP_RELEASELCKOWN, 1, "Rellckown", 9, },
  272         { NFSV4OP_DELEGRETURN, 1, "Delegret", 8, },
  273         { NFSV4OP_DELEGRETURN, 3, "DelegRemove", 11, },
  274         { NFSV4OP_DELEGRETURN, 7, "DelegRename1", 12, },
  275         { NFSV4OP_DELEGRETURN, 9, "DelegRename2", 12, },
  276         { NFSV4OP_GETATTR, 1, "Getacl", 6, },
  277         { NFSV4OP_SETATTR, 1, "Setacl", 6, },
  278         { NFSV4OP_EXCHANGEID, 1, "ExchangeID", 10, },
  279         { NFSV4OP_CREATESESSION, 1, "CreateSession", 13, },
  280         { NFSV4OP_DESTROYSESSION, 1, "DestroySession", 14, },
  281         { NFSV4OP_DESTROYCLIENTID, 1, "DestroyClient", 13, },
  282         { NFSV4OP_FREESTATEID, 1, "FreeStateID", 11, },
  283         { NFSV4OP_LAYOUTGET, 1, "LayoutGet", 9, },
  284         { NFSV4OP_GETDEVINFO, 1, "GetDeviceInfo", 13, },
  285         { NFSV4OP_LAYOUTCOMMIT, 1, "LayoutCommit", 12, },
  286         { NFSV4OP_LAYOUTRETURN, 1, "LayoutReturn", 12, },
  287         { NFSV4OP_RECLAIMCOMPL, 1, "ReclaimComplete", 15, },
  288         { NFSV4OP_WRITE, 1, "WriteDS", 7, },
  289         { NFSV4OP_READ, 1, "ReadDS", 6, },
  290         { NFSV4OP_COMMIT, 1, "CommitDS", 8, },
  291         { NFSV4OP_OPEN, 3, "OpenLayoutGet", 13, },
  292         { NFSV4OP_OPEN, 8, "CreateLayGet", 12, },
  293         { NFSV4OP_IOADVISE, 1, "Advise", 6, },
  294         { NFSV4OP_ALLOCATE, 2, "Allocate", 8, },
  295         { NFSV4OP_SAVEFH, 5, "Copy", 4, },
  296         { NFSV4OP_SEEK, 2, "Seek", 4, },
  297         { NFSV4OP_SEEK, 1, "SeekDS", 6, },
  298         { NFSV4OP_GETXATTR, 2, "Getxattr", 8, },
  299         { NFSV4OP_SETXATTR, 2, "Setxattr", 8, },
  300         { NFSV4OP_REMOVEXATTR, 2, "Rmxattr", 7, },
  301         { NFSV4OP_LISTXATTRS, 2, "Listxattr", 9, },
  302         { NFSV4OP_BINDCONNTOSESS, 1, "BindConSess", 11, },
  303         { NFSV4OP_LOOKUP, 5, "LookupOpen", 10, },
  304         { NFSV4OP_DEALLOCATE, 2, "Deallocate", 10, },
  305         { NFSV4OP_LAYOUTERROR, 1, "LayoutError", 11, },
  306         { NFSV4OP_VERIFY, 3, "AppendWrite", 11, },
  307 };
  308 
  309 /*
  310  * NFS RPCS that have large request message size.
  311  */
  312 static int nfs_bigrequest[NFSV42_NPROCS] = {
  313         0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  314         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  315         0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
  316         0, 1
  317 };
  318 
  319 /*
  320  * Start building a request. Mostly just put the first file handle in
  321  * place.
  322  */
  323 void
  324 nfscl_reqstart(struct nfsrv_descript *nd, int procnum, struct nfsmount *nmp,
  325     u_int8_t *nfhp, int fhlen, u_int32_t **opcntpp, struct nfsclsession *sep,
  326     int vers, int minorvers, struct ucred *cred)
  327 {
  328         struct mbuf *mb;
  329         u_int32_t *tl;
  330         int opcnt;
  331         nfsattrbit_t attrbits;
  332 
  333         /*
  334          * First, fill in some of the fields of nd.
  335          */
  336         nd->nd_slotseq = NULL;
  337         if (vers == NFS_VER4) {
  338                 nd->nd_flag = ND_NFSV4 | ND_NFSCL;
  339                 if (minorvers == NFSV41_MINORVERSION)
  340                         nd->nd_flag |= ND_NFSV41;
  341                 else if (minorvers == NFSV42_MINORVERSION)
  342                         nd->nd_flag |= (ND_NFSV41 | ND_NFSV42);
  343         } else if (vers == NFS_VER3)
  344                 nd->nd_flag = ND_NFSV3 | ND_NFSCL;
  345         else {
  346                 if (NFSHASNFSV4(nmp)) {
  347                         nd->nd_flag = ND_NFSV4 | ND_NFSCL;
  348                         if (nmp->nm_minorvers == 1)
  349                                 nd->nd_flag |= ND_NFSV41;
  350                         else if (nmp->nm_minorvers == 2)
  351                                 nd->nd_flag |= (ND_NFSV41 | ND_NFSV42);
  352                 } else if (NFSHASNFSV3(nmp))
  353                         nd->nd_flag = ND_NFSV3 | ND_NFSCL;
  354                 else
  355                         nd->nd_flag = ND_NFSV2 | ND_NFSCL;
  356         }
  357         nd->nd_procnum = procnum;
  358         nd->nd_repstat = 0;
  359         nd->nd_maxextsiz = 0;
  360 
  361         /*
  362          * Get the first mbuf for the request.
  363          */
  364         if (nfs_bigrequest[procnum])
  365                 NFSMCLGET(mb, M_WAITOK);
  366         else
  367                 NFSMGET(mb);
  368         mb->m_len = 0;
  369         nd->nd_mreq = nd->nd_mb = mb;
  370         nd->nd_bpos = mtod(mb, char *);
  371 
  372         /*
  373          * And fill the first file handle into the request.
  374          */
  375         if (nd->nd_flag & ND_NFSV4) {
  376                 opcnt = nfsv4_opmap[procnum].opcnt +
  377                     nfsv4_opflag[nfsv4_opmap[procnum].op].needscfh;
  378                 if ((nd->nd_flag & ND_NFSV41) != 0) {
  379                         opcnt += nfsv4_opflag[nfsv4_opmap[procnum].op].needsseq;
  380                         if (procnum == NFSPROC_RENEW)
  381                                 /*
  382                                  * For the special case of Renew, just do a
  383                                  * Sequence Op.
  384                                  */
  385                                 opcnt = 1;
  386                         else if (procnum == NFSPROC_WRITEDS ||
  387                             procnum == NFSPROC_COMMITDS)
  388                                 /*
  389                                  * For the special case of a Writeor Commit to
  390                                  * a DS, the opcnt == 3, for Sequence, PutFH,
  391                                  * Write/Commit.
  392                                  */
  393                                 opcnt = 3;
  394                 }
  395                 /*
  396                  * What should the tag really be?
  397                  */
  398                 (void) nfsm_strtom(nd, nfsv4_opmap[procnum].tag,
  399                         nfsv4_opmap[procnum].taglen);
  400                 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
  401                 if ((nd->nd_flag & ND_NFSV42) != 0)
  402                         *tl++ = txdr_unsigned(NFSV42_MINORVERSION);
  403                 else if ((nd->nd_flag & ND_NFSV41) != 0)
  404                         *tl++ = txdr_unsigned(NFSV41_MINORVERSION);
  405                 else
  406                         *tl++ = txdr_unsigned(NFSV4_MINORVERSION);
  407                 if (opcntpp != NULL)
  408                         *opcntpp = tl;
  409                 *tl = txdr_unsigned(opcnt);
  410                 if ((nd->nd_flag & ND_NFSV41) != 0 &&
  411                     nfsv4_opflag[nfsv4_opmap[procnum].op].needsseq > 0) {
  412                         if (nfsv4_opflag[nfsv4_opmap[procnum].op].loopbadsess >
  413                             0)
  414                                 nd->nd_flag |= ND_LOOPBADSESS;
  415                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
  416                         *tl = txdr_unsigned(NFSV4OP_SEQUENCE);
  417                         if (sep == NULL) {
  418                                 sep = nfsmnt_mdssession(nmp);
  419                                 /*
  420                                  * For MDS mount sessions, check for bad
  421                                  * slots.  If the caller does not want this
  422                                  * check to be done, the "cred" argument can
  423                                  * be passed in as NULL.
  424                                  */
  425                                 nfsv4_setsequence(nmp, nd, sep,
  426                                     nfs_bigreply[procnum], cred);
  427                         } else
  428                                 nfsv4_setsequence(nmp, nd, sep,
  429                                     nfs_bigreply[procnum], NULL);
  430                 }
  431                 if (nfsv4_opflag[nfsv4_opmap[procnum].op].needscfh > 0) {
  432                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
  433                         *tl = txdr_unsigned(NFSV4OP_PUTFH);
  434                         (void) nfsm_fhtom(nd, nfhp, fhlen, 0);
  435                         if (nfsv4_opflag[nfsv4_opmap[procnum].op].needscfh
  436                             == 2 && procnum != NFSPROC_WRITEDS &&
  437                             procnum != NFSPROC_COMMITDS) {
  438                                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
  439                                 *tl = txdr_unsigned(NFSV4OP_GETATTR);
  440                                 /*
  441                                  * For Lookup Ops, we want all the directory
  442                                  * attributes, so we can load the name cache.
  443                                  */
  444                                 if (procnum == NFSPROC_LOOKUP ||
  445                                     procnum == NFSPROC_LOOKUPP ||
  446                                     procnum == NFSPROC_LOOKUPOPEN)
  447                                         NFSGETATTR_ATTRBIT(&attrbits);
  448                                 else {
  449                                         NFSWCCATTR_ATTRBIT(&attrbits);
  450                                         /* For AppendWrite, get the size. */
  451                                         if (procnum == NFSPROC_APPENDWRITE)
  452                                                 NFSSETBIT_ATTRBIT(&attrbits,
  453                                                     NFSATTRBIT_SIZE);
  454                                         nd->nd_flag |= ND_V4WCCATTR;
  455                                 }
  456                                 (void) nfsrv_putattrbit(nd, &attrbits);
  457                         }
  458                 }
  459                 if (procnum != NFSPROC_RENEW ||
  460                     (nd->nd_flag & ND_NFSV41) == 0) {
  461                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
  462                         *tl = txdr_unsigned(nfsv4_opmap[procnum].op);
  463                 }
  464         } else {
  465                 (void) nfsm_fhtom(nd, nfhp, fhlen, 0);
  466         }
  467         if (procnum < NFSV42_NPROCS)
  468                 NFSINCRGLOBAL(nfsstatsv1.rpccnt[procnum]);
  469 }
  470 
  471 /*
  472  * Put a state Id in the mbuf list.
  473  */
  474 void
  475 nfsm_stateidtom(struct nfsrv_descript *nd, nfsv4stateid_t *stateidp, int flag)
  476 {
  477         nfsv4stateid_t *st;
  478 
  479         NFSM_BUILD(st, nfsv4stateid_t *, NFSX_STATEID);
  480         if (flag == NFSSTATEID_PUTALLZERO) {
  481                 st->seqid = 0;
  482                 st->other[0] = 0;
  483                 st->other[1] = 0;
  484                 st->other[2] = 0;
  485         } else if (flag == NFSSTATEID_PUTALLONE) {
  486                 st->seqid = 0xffffffff;
  487                 st->other[0] = 0xffffffff;
  488                 st->other[1] = 0xffffffff;
  489                 st->other[2] = 0xffffffff;
  490         } else if (flag == NFSSTATEID_PUTSEQIDZERO) {
  491                 st->seqid = 0;
  492                 st->other[0] = stateidp->other[0];
  493                 st->other[1] = stateidp->other[1];
  494                 st->other[2] = stateidp->other[2];
  495         } else {
  496                 st->seqid = stateidp->seqid;
  497                 st->other[0] = stateidp->other[0];
  498                 st->other[1] = stateidp->other[1];
  499                 st->other[2] = stateidp->other[2];
  500         }
  501 }
  502 
  503 /*
  504  * Fill in the setable attributes. The full argument indicates whether
  505  * to fill in them all or just mode and time.
  506  */
  507 void
  508 nfscl_fillsattr(struct nfsrv_descript *nd, struct vattr *vap,
  509     struct vnode *vp, int flags, u_int32_t rdev)
  510 {
  511         u_int32_t *tl;
  512         struct nfsv2_sattr *sp;
  513         nfsattrbit_t attrbits;
  514         struct nfsnode *np;
  515 
  516         switch (nd->nd_flag & (ND_NFSV2 | ND_NFSV3 | ND_NFSV4)) {
  517         case ND_NFSV2:
  518                 NFSM_BUILD(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
  519                 if (vap->va_mode == (mode_t)VNOVAL)
  520                         sp->sa_mode = newnfs_xdrneg1;
  521                 else
  522                         sp->sa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode);
  523                 if (vap->va_uid == (uid_t)VNOVAL)
  524                         sp->sa_uid = newnfs_xdrneg1;
  525                 else
  526                         sp->sa_uid = txdr_unsigned(vap->va_uid);
  527                 if (vap->va_gid == (gid_t)VNOVAL)
  528                         sp->sa_gid = newnfs_xdrneg1;
  529                 else
  530                         sp->sa_gid = txdr_unsigned(vap->va_gid);
  531                 if (flags & NFSSATTR_SIZE0)
  532                         sp->sa_size = 0;
  533                 else if (flags & NFSSATTR_SIZENEG1)
  534                         sp->sa_size = newnfs_xdrneg1;
  535                 else if (flags & NFSSATTR_SIZERDEV)
  536                         sp->sa_size = txdr_unsigned(rdev);
  537                 else
  538                         sp->sa_size = txdr_unsigned(vap->va_size);
  539                 txdr_nfsv2time(&vap->va_atime, &sp->sa_atime);
  540                 txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime);
  541                 break;
  542         case ND_NFSV3:
  543                 if (vap->va_mode != (mode_t)VNOVAL) {
  544                         NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
  545                         *tl++ = newnfs_true;
  546                         *tl = txdr_unsigned(vap->va_mode);
  547                 } else {
  548                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
  549                         *tl = newnfs_false;
  550                 }
  551                 if ((flags & NFSSATTR_FULL) && vap->va_uid != (uid_t)VNOVAL) {
  552                         NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
  553                         *tl++ = newnfs_true;
  554                         *tl = txdr_unsigned(vap->va_uid);
  555                 } else {
  556                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
  557                         *tl = newnfs_false;
  558                 }
  559                 if ((flags & NFSSATTR_FULL) && vap->va_gid != (gid_t)VNOVAL) {
  560                         NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
  561                         *tl++ = newnfs_true;
  562                         *tl = txdr_unsigned(vap->va_gid);
  563                 } else {
  564                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
  565                         *tl = newnfs_false;
  566                 }
  567                 if ((flags & NFSSATTR_FULL) && vap->va_size != VNOVAL) {
  568                         NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
  569                         *tl++ = newnfs_true;
  570                         txdr_hyper(vap->va_size, tl);
  571                 } else {
  572                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
  573                         *tl = newnfs_false;
  574                 }
  575                 if (vap->va_atime.tv_sec != VNOVAL) {
  576                         if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
  577                                 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
  578                                 *tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT);
  579                                 txdr_nfsv3time(&vap->va_atime, tl);
  580                         } else {
  581                                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
  582                                 *tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER);
  583                         }
  584                 } else {
  585                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
  586                         *tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE);
  587                 }
  588                 if (vap->va_mtime.tv_sec != VNOVAL) {
  589                         if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
  590                                 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
  591                                 *tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT);
  592                                 txdr_nfsv3time(&vap->va_mtime, tl);
  593                         } else {
  594                                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
  595                                 *tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER);
  596                         }
  597                 } else {
  598                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
  599                         *tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE);
  600                 }
  601                 break;
  602         case ND_NFSV4:
  603                 NFSZERO_ATTRBIT(&attrbits);
  604                 if (vap->va_mode != (mode_t)VNOVAL)
  605                         NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_MODE);
  606                 if ((flags & NFSSATTR_FULL) && vap->va_uid != (uid_t)VNOVAL)
  607                         NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER);
  608                 if ((flags & NFSSATTR_FULL) && vap->va_gid != (gid_t)VNOVAL)
  609                         NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNERGROUP);
  610                 if ((flags & NFSSATTR_FULL) && vap->va_size != VNOVAL)
  611                         NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_SIZE);
  612                 if (vap->va_atime.tv_sec != VNOVAL)
  613                         NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET);
  614                 if (vap->va_mtime.tv_sec != VNOVAL)
  615                         NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFYSET);
  616                 if (vap->va_birthtime.tv_sec != VNOVAL &&
  617                     strcmp(vp->v_mount->mnt_vfc->vfc_name, "nfs") == 0) {
  618                         /*
  619                          * We can only test for support of TimeCreate if
  620                          * the "vp" argument is for an NFS vnode.
  621                          */
  622                         np = VTONFS(vp);
  623                         if (NFSISSET_ATTRBIT(&np->n_vattr.na_suppattr,
  624                             NFSATTRBIT_TIMECREATE))
  625                                 NFSSETBIT_ATTRBIT(&attrbits,
  626                                     NFSATTRBIT_TIMECREATE);
  627                 }
  628                 (void) nfsv4_fillattr(nd, vp->v_mount, vp, NULL, vap, NULL, 0,
  629                     &attrbits, NULL, NULL, 0, 0, 0, 0, (uint64_t)0, NULL);
  630                 break;
  631         }
  632 }
  633 
  634 /*
  635  * copies mbuf chain to the uio scatter/gather list
  636  */
  637 int
  638 nfsm_mbufuio(struct nfsrv_descript *nd, struct uio *uiop, int siz)
  639 {
  640         char *mbufcp, *uiocp;
  641         int xfer, left, len;
  642         struct mbuf *mp;
  643         long uiosiz, rem;
  644         int error = 0;
  645 
  646         mp = nd->nd_md;
  647         mbufcp = nd->nd_dpos;
  648         len = mtod(mp, caddr_t) + mp->m_len - mbufcp;
  649         rem = NFSM_RNDUP(siz) - siz;
  650         while (siz > 0) {
  651                 if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) {
  652                         error = EBADRPC;
  653                         goto out;
  654                 }
  655                 left = uiop->uio_iov->iov_len;
  656                 uiocp = uiop->uio_iov->iov_base;
  657                 if (left > siz)
  658                         left = siz;
  659                 uiosiz = left;
  660                 while (left > 0) {
  661                         while (len == 0) {
  662                                 mp = mp->m_next;
  663                                 if (mp == NULL) {
  664                                         error = EBADRPC;
  665                                         goto out;
  666                                 }
  667                                 mbufcp = mtod(mp, caddr_t);
  668                                 len = mp->m_len;
  669                                 KASSERT(len >= 0,
  670                                     ("len %d, corrupted mbuf?", len));
  671                         }
  672                         xfer = (left > len) ? len : left;
  673 #ifdef notdef
  674                         /* Not Yet.. */
  675                         if (uiop->uio_iov->iov_op != NULL)
  676                                 (*(uiop->uio_iov->iov_op))
  677                                 (mbufcp, uiocp, xfer);
  678                         else
  679 #endif
  680                         if (uiop->uio_segflg == UIO_SYSSPACE)
  681                                 NFSBCOPY(mbufcp, uiocp, xfer);
  682                         else
  683                                 copyout(mbufcp, uiocp, xfer);
  684                         left -= xfer;
  685                         len -= xfer;
  686                         mbufcp += xfer;
  687                         uiocp += xfer;
  688                         uiop->uio_offset += xfer;
  689                         uiop->uio_resid -= xfer;
  690                 }
  691                 if (uiop->uio_iov->iov_len <= siz) {
  692                         uiop->uio_iovcnt--;
  693                         uiop->uio_iov++;
  694                 } else {
  695                         uiop->uio_iov->iov_base = (void *)
  696                                 ((char *)uiop->uio_iov->iov_base + uiosiz);
  697                         uiop->uio_iov->iov_len -= uiosiz;
  698                 }
  699                 siz -= uiosiz;
  700         }
  701         nd->nd_dpos = mbufcp;
  702         nd->nd_md = mp;
  703         if (rem > 0) {
  704                 if (len < rem)
  705                         error = nfsm_advance(nd, rem, len);
  706                 else
  707                         nd->nd_dpos += rem;
  708         }
  709 
  710 out:
  711         NFSEXITCODE2(error, nd);
  712         return (error);
  713 }
  714 
  715 /*
  716  * Help break down an mbuf chain by setting the first siz bytes contiguous
  717  * pointed to by returned val.
  718  * This is used by the macro NFSM_DISSECT for tough
  719  * cases.
  720  */
  721 void *
  722 nfsm_dissct(struct nfsrv_descript *nd, int siz, int how)
  723 {
  724         struct mbuf *mp2;
  725         int siz2, xfer;
  726         caddr_t p;
  727         int left;
  728         caddr_t retp;
  729 
  730         retp = NULL;
  731         left = mtod(nd->nd_md, caddr_t) + nd->nd_md->m_len - nd->nd_dpos;
  732         while (left == 0) {
  733                 nd->nd_md = nd->nd_md->m_next;
  734                 if (nd->nd_md == NULL)
  735                         return (retp);
  736                 left = nd->nd_md->m_len;
  737                 nd->nd_dpos = mtod(nd->nd_md, caddr_t);
  738         }
  739         if (left >= siz) {
  740                 retp = nd->nd_dpos;
  741                 nd->nd_dpos += siz;
  742         } else if (nd->nd_md->m_next == NULL) {
  743                 return (retp);
  744         } else if (siz > ncl_mbuf_mhlen) {
  745                 panic("nfs S too big");
  746         } else {
  747                 MGET(mp2, how, MT_DATA);
  748                 if (mp2 == NULL)
  749                         return (NULL);
  750                 mp2->m_next = nd->nd_md->m_next;
  751                 nd->nd_md->m_next = mp2;
  752                 nd->nd_md->m_len -= left;
  753                 nd->nd_md = mp2;
  754                 retp = p = mtod(mp2, caddr_t);
  755                 NFSBCOPY(nd->nd_dpos, p, left); /* Copy what was left */
  756                 siz2 = siz - left;
  757                 p += left;
  758                 mp2 = mp2->m_next;
  759                 /* Loop around copying up the siz2 bytes */
  760                 while (siz2 > 0) {
  761                         if (mp2 == NULL)
  762                                 return (NULL);
  763                         xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2;
  764                         if (xfer > 0) {
  765                                 NFSBCOPY(mtod(mp2, caddr_t), p, xfer);
  766                                 mp2->m_data += xfer;
  767                                 mp2->m_len -= xfer;
  768                                 p += xfer;
  769                                 siz2 -= xfer;
  770                         }
  771                         if (siz2 > 0)
  772                                 mp2 = mp2->m_next;
  773                 }
  774                 nd->nd_md->m_len = siz;
  775                 nd->nd_md = mp2;
  776                 nd->nd_dpos = mtod(mp2, caddr_t);
  777         }
  778         return (retp);
  779 }
  780 
  781 /*
  782  * Advance the position in the mbuf chain.
  783  * If offs == 0, this is a no-op, but it is simpler to just return from
  784  * here than check for offs > 0 for all calls to nfsm_advance.
  785  * If left == -1, it should be calculated here.
  786  */
  787 int
  788 nfsm_advance(struct nfsrv_descript *nd, int offs, int left)
  789 {
  790         int error = 0;
  791 
  792         if (offs == 0)
  793                 goto out;
  794         /*
  795          * A negative offs might indicate a corrupted mbuf chain and,
  796          * as such, a printf is logged.
  797          */
  798         if (offs < 0) {
  799                 printf("nfsrv_advance: negative offs\n");
  800                 error = EBADRPC;
  801                 goto out;
  802         }
  803 
  804         /*
  805          * If left == -1, calculate it here.
  806          */
  807         if (left == -1)
  808                 left = mtod(nd->nd_md, caddr_t) + nd->nd_md->m_len -
  809                     nd->nd_dpos;
  810 
  811         /*
  812          * Loop around, advancing over the mbuf data.
  813          */
  814         while (offs > left) {
  815                 offs -= left;
  816                 nd->nd_md = nd->nd_md->m_next;
  817                 if (nd->nd_md == NULL) {
  818                         error = EBADRPC;
  819                         goto out;
  820                 }
  821                 left = nd->nd_md->m_len;
  822                 nd->nd_dpos = mtod(nd->nd_md, caddr_t);
  823         }
  824         nd->nd_dpos += offs;
  825 
  826 out:
  827         NFSEXITCODE(error);
  828         return (error);
  829 }
  830 
  831 /*
  832  * Copy a string into mbuf(s).
  833  * Return the number of bytes output, including XDR overheads.
  834  */
  835 int
  836 nfsm_strtom(struct nfsrv_descript *nd, const char *cp, int siz)
  837 {
  838         struct mbuf *m2;
  839         int xfer, left;
  840         struct mbuf *m1;
  841         int rem, bytesize;
  842         u_int32_t *tl;
  843         char *cp2;
  844 
  845         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
  846         *tl = txdr_unsigned(siz);
  847         rem = NFSM_RNDUP(siz) - siz;
  848         bytesize = NFSX_UNSIGNED + siz + rem;
  849         m2 = nd->nd_mb;
  850         cp2 = nd->nd_bpos;
  851         if ((nd->nd_flag & ND_EXTPG) != 0)
  852                 left = nd->nd_bextpgsiz;
  853         else
  854                 left = M_TRAILINGSPACE(m2);
  855 
  856         KASSERT(((m2->m_flags & (M_EXT | M_EXTPG)) ==
  857             (M_EXT | M_EXTPG) && (nd->nd_flag & ND_EXTPG) != 0) ||
  858             ((m2->m_flags & (M_EXT | M_EXTPG)) !=
  859             (M_EXT | M_EXTPG) && (nd->nd_flag & ND_EXTPG) == 0),
  860             ("nfsm_strtom: ext_pgs and non-ext_pgs mbufs mixed"));
  861         /*
  862          * Loop around copying the string to mbuf(s).
  863          */
  864         while (siz > 0) {
  865                 if (left == 0) {
  866                         if ((nd->nd_flag & ND_EXTPG) != 0) {
  867                                 m2 = nfsm_add_ext_pgs(m2,
  868                                     nd->nd_maxextsiz, &nd->nd_bextpg);
  869                                 cp2 = (char *)(void *)PHYS_TO_DMAP(
  870                                     m2->m_epg_pa[nd->nd_bextpg]);
  871                                 nd->nd_bextpgsiz = left = PAGE_SIZE;
  872                         } else {
  873                                 if (siz > ncl_mbuf_mlen)
  874                                         NFSMCLGET(m1, M_WAITOK);
  875                                 else
  876                                         NFSMGET(m1);
  877                                 m1->m_len = 0;
  878                                 cp2 = mtod(m1, char *);
  879                                 left = M_TRAILINGSPACE(m1);
  880                                 m2->m_next = m1;
  881                                 m2 = m1;
  882                         }
  883                 }
  884                 if (left >= siz)
  885                         xfer = siz;
  886                 else
  887                         xfer = left;
  888                 NFSBCOPY(cp, cp2, xfer);
  889                 cp += xfer;
  890                 cp2 += xfer;
  891                 m2->m_len += xfer;
  892                 siz -= xfer;
  893                 left -= xfer;
  894                 if ((nd->nd_flag & ND_EXTPG) != 0) {
  895                         nd->nd_bextpgsiz -= xfer;
  896                         m2->m_epg_last_len += xfer;
  897                 }
  898                 if (siz == 0 && rem) {
  899                         if (left < rem)
  900                                 panic("nfsm_strtom");
  901                         NFSBZERO(cp2, rem);
  902                         m2->m_len += rem;
  903                         cp2 += rem;
  904                         if ((nd->nd_flag & ND_EXTPG) != 0) {
  905                                 nd->nd_bextpgsiz -= rem;
  906                                 m2->m_epg_last_len += rem;
  907                         }
  908                 }
  909         }
  910         nd->nd_mb = m2;
  911         if ((nd->nd_flag & ND_EXTPG) != 0)
  912                 nd->nd_bpos = cp2;
  913         else
  914                 nd->nd_bpos = mtod(m2, char *) + m2->m_len;
  915         return (bytesize);
  916 }
  917 
  918 /*
  919  * Called once to initialize data structures...
  920  */
  921 void
  922 newnfs_init(void)
  923 {
  924         static int nfs_inited = 0;
  925 
  926         if (nfs_inited)
  927                 return;
  928         nfs_inited = 1;
  929 
  930         newnfs_true = txdr_unsigned(TRUE);
  931         newnfs_false = txdr_unsigned(FALSE);
  932         newnfs_xdrneg1 = txdr_unsigned(-1);
  933         nfscl_ticks = (hz * NFS_TICKINTVL + 500) / 1000;
  934         if (nfscl_ticks < 1)
  935                 nfscl_ticks = 1;
  936         NFSSETBOOTTIME(nfsboottime);
  937 
  938         /*
  939          * Initialize reply list and start timer
  940          */
  941         TAILQ_INIT(&nfsd_reqq);
  942 }
  943 
  944 /*
  945  * Put a file handle in an mbuf list.
  946  * If the size argument == 0, just use the default size.
  947  * set_true == 1 if there should be an newnfs_true prepended on the file handle.
  948  * Return the number of bytes output, including XDR overhead.
  949  */
  950 int
  951 nfsm_fhtom(struct nfsrv_descript *nd, u_int8_t *fhp, int size, int set_true)
  952 {
  953         u_int32_t *tl;
  954         u_int8_t *cp;
  955         int fullsiz, bytesize = 0;
  956 
  957         if (size == 0)
  958                 size = NFSX_MYFH;
  959         switch (nd->nd_flag & (ND_NFSV2 | ND_NFSV3 | ND_NFSV4)) {
  960         case ND_NFSV2:
  961                 if (size > NFSX_V2FH)
  962                         panic("fh size > NFSX_V2FH for NFSv2");
  963                 NFSM_BUILD(cp, u_int8_t *, NFSX_V2FH);
  964                 NFSBCOPY(fhp, cp, size);
  965                 if (size < NFSX_V2FH)
  966                         NFSBZERO(cp + size, NFSX_V2FH - size);
  967                 bytesize = NFSX_V2FH;
  968                 break;
  969         case ND_NFSV3:
  970         case ND_NFSV4:
  971                 fullsiz = NFSM_RNDUP(size);
  972                 if (set_true) {
  973                     bytesize = 2 * NFSX_UNSIGNED + fullsiz;
  974                     NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
  975                     *tl = newnfs_true;
  976                 } else {
  977                     bytesize = NFSX_UNSIGNED + fullsiz;
  978                 }
  979                 (void) nfsm_strtom(nd, fhp, size);
  980                 break;
  981         }
  982         return (bytesize);
  983 }
  984 
  985 /*
  986  * This function compares two net addresses by family and returns TRUE
  987  * if they are the same host.
  988  * If there is any doubt, return FALSE.
  989  * The AF_INET family is handled as a special case so that address mbufs
  990  * don't need to be saved to store "struct in_addr", which is only 4 bytes.
  991  */
  992 int
  993 nfsaddr_match(int family, union nethostaddr *haddr, NFSSOCKADDR_T nam)
  994 {
  995 #ifdef INET
  996         struct sockaddr_in *inetaddr;
  997 #endif
  998 
  999         switch (family) {
 1000 #ifdef INET
 1001         case AF_INET:
 1002                 inetaddr = NFSSOCKADDR(nam, struct sockaddr_in *);
 1003                 if (inetaddr->sin_family == AF_INET &&
 1004                     inetaddr->sin_addr.s_addr == haddr->had_inet.s_addr)
 1005                         return (1);
 1006                 break;
 1007 #endif
 1008 #ifdef INET6
 1009         case AF_INET6:
 1010                 {
 1011                 struct sockaddr_in6 *inetaddr6;
 1012 
 1013                 inetaddr6 = NFSSOCKADDR(nam, struct sockaddr_in6 *);
 1014                 /* XXX - should test sin6_scope_id ? */
 1015                 if (inetaddr6->sin6_family == AF_INET6 &&
 1016                     IN6_ARE_ADDR_EQUAL(&inetaddr6->sin6_addr,
 1017                           &haddr->had_inet6))
 1018                         return (1);
 1019                 }
 1020                 break;
 1021 #endif
 1022         }
 1023         return (0);
 1024 }
 1025 
 1026 /*
 1027  * Similar to the above, but takes to NFSSOCKADDR_T args.
 1028  */
 1029 int
 1030 nfsaddr2_match(NFSSOCKADDR_T nam1, NFSSOCKADDR_T nam2)
 1031 {
 1032         struct sockaddr_in *addr1, *addr2;
 1033         struct sockaddr *inaddr;
 1034 
 1035         inaddr = NFSSOCKADDR(nam1, struct sockaddr *);
 1036         switch (inaddr->sa_family) {
 1037         case AF_INET:
 1038                 addr1 = NFSSOCKADDR(nam1, struct sockaddr_in *);
 1039                 addr2 = NFSSOCKADDR(nam2, struct sockaddr_in *);
 1040                 if (addr2->sin_family == AF_INET &&
 1041                     addr1->sin_addr.s_addr == addr2->sin_addr.s_addr)
 1042                         return (1);
 1043                 break;
 1044 #ifdef INET6
 1045         case AF_INET6:
 1046                 {
 1047                 struct sockaddr_in6 *inet6addr1, *inet6addr2;
 1048 
 1049                 inet6addr1 = NFSSOCKADDR(nam1, struct sockaddr_in6 *);
 1050                 inet6addr2 = NFSSOCKADDR(nam2, struct sockaddr_in6 *);
 1051                 /* XXX - should test sin6_scope_id ? */
 1052                 if (inet6addr2->sin6_family == AF_INET6 &&
 1053                     IN6_ARE_ADDR_EQUAL(&inet6addr1->sin6_addr,
 1054                           &inet6addr2->sin6_addr))
 1055                         return (1);
 1056                 }
 1057                 break;
 1058 #endif
 1059         }
 1060         return (0);
 1061 }
 1062 
 1063 /*
 1064  * Dissect a file handle on the client.
 1065  */
 1066 int
 1067 nfsm_getfh(struct nfsrv_descript *nd, struct nfsfh **nfhpp)
 1068 {
 1069         u_int32_t *tl;
 1070         struct nfsfh *nfhp;
 1071         int error, len;
 1072 
 1073         *nfhpp = NULL;
 1074         if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
 1075                 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 1076                 if ((len = fxdr_unsigned(int, *tl)) <= 0 ||
 1077                         len > NFSX_FHMAX) {
 1078                         error = EBADRPC;
 1079                         goto nfsmout;
 1080                 }
 1081         } else
 1082                 len = NFSX_V2FH;
 1083         nfhp = malloc(sizeof (struct nfsfh) + len,
 1084             M_NFSFH, M_WAITOK);
 1085         error = nfsrv_mtostr(nd, nfhp->nfh_fh, len);
 1086         if (error) {
 1087                 free(nfhp, M_NFSFH);
 1088                 goto nfsmout;
 1089         }
 1090         nfhp->nfh_len = len;
 1091         *nfhpp = nfhp;
 1092 nfsmout:
 1093         NFSEXITCODE2(error, nd);
 1094         return (error);
 1095 }
 1096 
 1097 /*
 1098  * Break down the nfsv4 acl.
 1099  * If the aclp == NULL or won't fit in an acl, just discard the acl info.
 1100  */
 1101 int
 1102 nfsrv_dissectacl(struct nfsrv_descript *nd, NFSACL_T *aclp, bool server,
 1103     int *aclerrp, int *aclsizep, __unused NFSPROC_T *p)
 1104 {
 1105         u_int32_t *tl;
 1106         int i, aclsize;
 1107         int acecnt, error = 0, aceerr = 0, acesize;
 1108 
 1109         *aclerrp = 0;
 1110         if (aclp)
 1111                 aclp->acl_cnt = 0;
 1112         /*
 1113          * Parse out the ace entries and expect them to conform to
 1114          * what can be supported by R/W/X bits.
 1115          */
 1116         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 1117         aclsize = NFSX_UNSIGNED;
 1118         acecnt = fxdr_unsigned(int, *tl);
 1119         /*
 1120          * The RFCs do not define a fixed limit to the number of ACEs in
 1121          * an ACL, but 10240 should be more than sufficient.
 1122          */
 1123         if (acecnt < 0 || acecnt > 10240) {
 1124                 error = NFSERR_BADXDR;
 1125                 goto nfsmout;
 1126         }
 1127         if (acecnt > ACL_MAX_ENTRIES)
 1128                 aceerr = NFSERR_ATTRNOTSUPP;
 1129         if (nfsrv_useacl == 0)
 1130                 aceerr = NFSERR_ATTRNOTSUPP;
 1131         for (i = 0; i < acecnt; i++) {
 1132                 if (aclp && !aceerr)
 1133                         error = nfsrv_dissectace(nd, &aclp->acl_entry[i],
 1134                             server, &aceerr, &acesize, p);
 1135                 else
 1136                         error = nfsrv_skipace(nd, &acesize);
 1137                 if (error)
 1138                         goto nfsmout;
 1139                 aclsize += acesize;
 1140         }
 1141         if (aclp && !aceerr)
 1142                 aclp->acl_cnt = acecnt;
 1143         if (aceerr)
 1144                 *aclerrp = aceerr;
 1145         if (aclsizep)
 1146                 *aclsizep = aclsize;
 1147 nfsmout:
 1148         NFSEXITCODE2(error, nd);
 1149         return (error);
 1150 }
 1151 
 1152 /*
 1153  * Skip over an NFSv4 ace entry. Just dissect the xdr and discard it.
 1154  */
 1155 static int
 1156 nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep)
 1157 {
 1158         u_int32_t *tl;
 1159         int error, len = 0;
 1160 
 1161         NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
 1162         len = fxdr_unsigned(int, *(tl + 3));
 1163         error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
 1164 nfsmout:
 1165         *acesizep = NFSM_RNDUP(len) + (4 * NFSX_UNSIGNED);
 1166         NFSEXITCODE2(error, nd);
 1167         return (error);
 1168 }
 1169 
 1170 /*
 1171  * Get attribute bits from an mbuf list.
 1172  * Returns EBADRPC for a parsing error, 0 otherwise.
 1173  * If the clearinvalid flag is set, clear the bits not supported.
 1174  */
 1175 int
 1176 nfsrv_getattrbits(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp, int *cntp,
 1177     int *retnotsupp)
 1178 {
 1179         u_int32_t *tl;
 1180         int cnt, i, outcnt;
 1181         int error = 0;
 1182 
 1183         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 1184         cnt = fxdr_unsigned(int, *tl);
 1185         if (cnt < 0) {
 1186                 error = NFSERR_BADXDR;
 1187                 goto nfsmout;
 1188         }
 1189         if (cnt > NFSATTRBIT_MAXWORDS)
 1190                 outcnt = NFSATTRBIT_MAXWORDS;
 1191         else
 1192                 outcnt = cnt;
 1193         NFSZERO_ATTRBIT(attrbitp);
 1194         if (outcnt > 0) {
 1195                 NFSM_DISSECT(tl, u_int32_t *, outcnt * NFSX_UNSIGNED);
 1196                 for (i = 0; i < outcnt; i++)
 1197                         attrbitp->bits[i] = fxdr_unsigned(u_int32_t, *tl++);
 1198         }
 1199         for (i = 0; i < (cnt - outcnt); i++) {
 1200                 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 1201                 if (retnotsupp != NULL && *tl != 0)
 1202                         *retnotsupp = NFSERR_ATTRNOTSUPP;
 1203         }
 1204         if (cntp)
 1205                 *cntp = NFSX_UNSIGNED + (cnt * NFSX_UNSIGNED);
 1206 nfsmout:
 1207         NFSEXITCODE2(error, nd);
 1208         return (error);
 1209 }
 1210 
 1211 /*
 1212  * Get the attributes for V4.
 1213  * If the compare flag is true, test for any attribute changes,
 1214  * otherwise return the attribute values.
 1215  * These attributes cover fields in "struct vattr", "struct statfs",
 1216  * "struct nfsfsinfo", the file handle and the lease duration.
 1217  * The value of retcmpp is set to 1 if all attributes are the same,
 1218  * and 0 otherwise.
 1219  * Returns EBADRPC if it can't be parsed, 0 otherwise.
 1220  */
 1221 int
 1222 nfsv4_loadattr(struct nfsrv_descript *nd, vnode_t vp,
 1223     struct nfsvattr *nap, struct nfsfh **nfhpp, fhandle_t *fhp, int fhsize,
 1224     struct nfsv3_pathconf *pc, struct statfs *sbp, struct nfsstatfs *sfp,
 1225     struct nfsfsinfo *fsp, NFSACL_T *aclp, int compare, int *retcmpp,
 1226     u_int32_t *leasep, u_int32_t *rderrp, NFSPROC_T *p, struct ucred *cred)
 1227 {
 1228         u_int32_t *tl;
 1229         int i = 0, j, k, l = 0, m, bitpos, attrsum = 0;
 1230         int error, tfhsize, aceerr, attrsize, cnt, retnotsup;
 1231         u_char *cp, *cp2, namestr[NFSV4_SMALLSTR + 1];
 1232         nfsattrbit_t attrbits, retattrbits, checkattrbits;
 1233         struct nfsfh *tnfhp;
 1234         struct nfsreferral *refp;
 1235         u_quad_t tquad;
 1236         nfsquad_t tnfsquad;
 1237         struct timespec temptime;
 1238         uid_t uid;
 1239         gid_t gid;
 1240         u_int32_t freenum = 0, tuint;
 1241         u_int64_t uquad = 0, thyp, thyp2;
 1242 #ifdef QUOTA
 1243         struct dqblk dqb;
 1244         uid_t savuid;
 1245 #endif
 1246 
 1247         CTASSERT(sizeof(ino_t) == sizeof(uint64_t));
 1248         if (compare) {
 1249                 retnotsup = 0;
 1250                 error = nfsrv_getattrbits(nd, &attrbits, NULL, &retnotsup);
 1251         } else {
 1252                 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
 1253         }
 1254         if (error)
 1255                 goto nfsmout;
 1256 
 1257         if (compare) {
 1258                 *retcmpp = retnotsup;
 1259         } else {
 1260                 /*
 1261                  * Just set default values to some of the important ones.
 1262                  */
 1263                 if (nap != NULL) {
 1264                         nap->na_type = VREG;
 1265                         nap->na_mode = 0;
 1266                         nap->na_rdev = (NFSDEV_T)0;
 1267                         nap->na_mtime.tv_sec = 0;
 1268                         nap->na_mtime.tv_nsec = 0;
 1269                         nap->na_btime.tv_sec = -1;
 1270                         nap->na_btime.tv_nsec = 0;
 1271                         nap->na_gen = 0;
 1272                         nap->na_flags = 0;
 1273                         nap->na_blocksize = NFS_FABLKSIZE;
 1274                 }
 1275                 if (sbp != NULL) {
 1276                         sbp->f_bsize = NFS_FABLKSIZE;
 1277                         sbp->f_blocks = 0;
 1278                         sbp->f_bfree = 0;
 1279                         sbp->f_bavail = 0;
 1280                         sbp->f_files = 0;
 1281                         sbp->f_ffree = 0;
 1282                 }
 1283                 if (fsp != NULL) {
 1284                         fsp->fs_rtmax = 8192;
 1285                         fsp->fs_rtpref = 8192;
 1286                         fsp->fs_maxname = NFS_MAXNAMLEN;
 1287                         fsp->fs_wtmax = 8192;
 1288                         fsp->fs_wtpref = 8192;
 1289                         fsp->fs_wtmult = NFS_FABLKSIZE;
 1290                         fsp->fs_dtpref = 8192;
 1291                         fsp->fs_maxfilesize = 0xffffffffffffffffull;
 1292                         fsp->fs_timedelta.tv_sec = 0;
 1293                         fsp->fs_timedelta.tv_nsec = 1;
 1294                         fsp->fs_properties = (NFSV3_FSFLINK | NFSV3_FSFSYMLINK |
 1295                                 NFSV3_FSFHOMOGENEOUS | NFSV3_FSFCANSETTIME);
 1296                 }
 1297                 if (pc != NULL) {
 1298                         pc->pc_linkmax = NFS_LINK_MAX;
 1299                         pc->pc_namemax = NAME_MAX;
 1300                         pc->pc_notrunc = 0;
 1301                         pc->pc_chownrestricted = 0;
 1302                         pc->pc_caseinsensitive = 0;
 1303                         pc->pc_casepreserving = 1;
 1304                 }
 1305                 if (sfp != NULL) {
 1306                         sfp->sf_ffiles = UINT64_MAX;
 1307                         sfp->sf_tfiles = UINT64_MAX;
 1308                         sfp->sf_afiles = UINT64_MAX;
 1309                         sfp->sf_fbytes = UINT64_MAX;
 1310                         sfp->sf_tbytes = UINT64_MAX;
 1311                         sfp->sf_abytes = UINT64_MAX;
 1312                 }
 1313         }
 1314 
 1315         /*
 1316          * Loop around getting the attributes.
 1317          */
 1318         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 1319         attrsize = fxdr_unsigned(int, *tl);
 1320         for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
 1321             if (attrsum > attrsize) {
 1322                 error = NFSERR_BADXDR;
 1323                 goto nfsmout;
 1324             }
 1325             if (NFSISSET_ATTRBIT(&attrbits, bitpos))
 1326                 switch (bitpos) {
 1327                 case NFSATTRBIT_SUPPORTEDATTRS:
 1328                         retnotsup = 0;
 1329                         if (compare || nap == NULL)
 1330                             error = nfsrv_getattrbits(nd, &retattrbits,
 1331                                 &cnt, &retnotsup);
 1332                         else
 1333                             error = nfsrv_getattrbits(nd, &nap->na_suppattr,
 1334                                 &cnt, &retnotsup);
 1335                         if (error)
 1336                             goto nfsmout;
 1337                         if (compare && !(*retcmpp)) {
 1338                            NFSSETSUPP_ATTRBIT(&checkattrbits, nd);
 1339 
 1340                            /* Some filesystem do not support NFSv4ACL   */
 1341                            if (nfsrv_useacl == 0 || nfs_supportsnfsv4acls(vp) == 0) {
 1342                                 NFSCLRBIT_ATTRBIT(&checkattrbits, NFSATTRBIT_ACL);
 1343                                 NFSCLRBIT_ATTRBIT(&checkattrbits, NFSATTRBIT_ACLSUPPORT);
 1344                            }
 1345                            if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits)
 1346                                || retnotsup)
 1347                                 *retcmpp = NFSERR_NOTSAME;
 1348                         }
 1349                         attrsum += cnt;
 1350                         break;
 1351                 case NFSATTRBIT_TYPE:
 1352                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 1353                         if (compare) {
 1354                                 if (!(*retcmpp)) {
 1355                                     if (nap->na_type != nfsv34tov_type(*tl))
 1356                                         *retcmpp = NFSERR_NOTSAME;
 1357                                 }
 1358                         } else if (nap != NULL) {
 1359                                 nap->na_type = nfsv34tov_type(*tl);
 1360                         }
 1361                         attrsum += NFSX_UNSIGNED;
 1362                         break;
 1363                 case NFSATTRBIT_FHEXPIRETYPE:
 1364                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 1365                         if (compare && !(*retcmpp)) {
 1366                                 if (fxdr_unsigned(int, *tl) !=
 1367                                         NFSV4FHTYPE_PERSISTENT)
 1368                                         *retcmpp = NFSERR_NOTSAME;
 1369                         }
 1370                         attrsum += NFSX_UNSIGNED;
 1371                         break;
 1372                 case NFSATTRBIT_CHANGE:
 1373                         NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
 1374                         if (compare) {
 1375                                 if (!(*retcmpp)) {
 1376                                     if (nap->na_filerev != fxdr_hyper(tl))
 1377                                         *retcmpp = NFSERR_NOTSAME;
 1378                                 }
 1379                         } else if (nap != NULL) {
 1380                                 nap->na_filerev = fxdr_hyper(tl);
 1381                         }
 1382                         attrsum += NFSX_HYPER;
 1383                         break;
 1384                 case NFSATTRBIT_SIZE:
 1385                         NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
 1386                         if (compare) {
 1387                                 if (!(*retcmpp)) {
 1388                                     if (nap->na_size != fxdr_hyper(tl))
 1389                                         *retcmpp = NFSERR_NOTSAME;
 1390                                 }
 1391                         } else if (nap != NULL) {
 1392                                 nap->na_size = fxdr_hyper(tl);
 1393                         }
 1394                         attrsum += NFSX_HYPER;
 1395                         break;
 1396                 case NFSATTRBIT_LINKSUPPORT:
 1397                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 1398                         if (compare) {
 1399                                 if (!(*retcmpp)) {
 1400                                     if (fsp->fs_properties & NFSV3_FSFLINK) {
 1401                                         if (*tl == newnfs_false)
 1402                                                 *retcmpp = NFSERR_NOTSAME;
 1403                                     } else {
 1404                                         if (*tl == newnfs_true)
 1405                                                 *retcmpp = NFSERR_NOTSAME;
 1406                                     }
 1407                                 }
 1408                         } else if (fsp != NULL) {
 1409                                 if (*tl == newnfs_true)
 1410                                         fsp->fs_properties |= NFSV3_FSFLINK;
 1411                                 else
 1412                                         fsp->fs_properties &= ~NFSV3_FSFLINK;
 1413                         }
 1414                         attrsum += NFSX_UNSIGNED;
 1415                         break;
 1416                 case NFSATTRBIT_SYMLINKSUPPORT:
 1417                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 1418                         if (compare) {
 1419                                 if (!(*retcmpp)) {
 1420                                     if (fsp->fs_properties & NFSV3_FSFSYMLINK) {
 1421                                         if (*tl == newnfs_false)
 1422                                                 *retcmpp = NFSERR_NOTSAME;
 1423                                     } else {
 1424                                         if (*tl == newnfs_true)
 1425                                                 *retcmpp = NFSERR_NOTSAME;
 1426                                     }
 1427                                 }
 1428                         } else if (fsp != NULL) {
 1429                                 if (*tl == newnfs_true)
 1430                                         fsp->fs_properties |= NFSV3_FSFSYMLINK;
 1431                                 else
 1432                                         fsp->fs_properties &= ~NFSV3_FSFSYMLINK;
 1433                         }
 1434                         attrsum += NFSX_UNSIGNED;
 1435                         break;
 1436                 case NFSATTRBIT_NAMEDATTR:
 1437                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 1438                         if (compare && !(*retcmpp)) {
 1439                                 if (*tl != newnfs_false)
 1440                                         *retcmpp = NFSERR_NOTSAME;
 1441                         }
 1442                         attrsum += NFSX_UNSIGNED;
 1443                         break;
 1444                 case NFSATTRBIT_FSID:
 1445                         NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
 1446                         thyp = fxdr_hyper(tl);
 1447                         tl += 2;
 1448                         thyp2 = fxdr_hyper(tl);
 1449                         if (compare) {
 1450                             if (*retcmpp == 0) {
 1451                                 if (thyp != (u_int64_t)
 1452                                     vp->v_mount->mnt_stat.f_fsid.val[0] ||
 1453                                     thyp2 != (u_int64_t)
 1454                                     vp->v_mount->mnt_stat.f_fsid.val[1])
 1455                                         *retcmpp = NFSERR_NOTSAME;
 1456                             }
 1457                         } else if (nap != NULL) {
 1458                                 nap->na_filesid[0] = thyp;
 1459                                 nap->na_filesid[1] = thyp2;
 1460                         }
 1461                         attrsum += (4 * NFSX_UNSIGNED);
 1462                         break;
 1463                 case NFSATTRBIT_UNIQUEHANDLES:
 1464                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 1465                         if (compare && !(*retcmpp)) {
 1466                                 if (*tl != newnfs_true)
 1467                                         *retcmpp = NFSERR_NOTSAME;
 1468                         }
 1469                         attrsum += NFSX_UNSIGNED;
 1470                         break;
 1471                 case NFSATTRBIT_LEASETIME:
 1472                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 1473                         if (compare) {
 1474                                 if (fxdr_unsigned(int, *tl) != nfsrv_lease &&
 1475                                     !(*retcmpp))
 1476                                         *retcmpp = NFSERR_NOTSAME;
 1477                         } else if (leasep != NULL) {
 1478                                 *leasep = fxdr_unsigned(u_int32_t, *tl);
 1479                         }
 1480                         attrsum += NFSX_UNSIGNED;
 1481                         break;
 1482                 case NFSATTRBIT_RDATTRERROR:
 1483                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 1484                         if (compare) {
 1485                                  if (!(*retcmpp))
 1486                                         *retcmpp = NFSERR_INVAL;
 1487                         } else if (rderrp != NULL) {
 1488                                 *rderrp = fxdr_unsigned(u_int32_t, *tl);
 1489                         }
 1490                         attrsum += NFSX_UNSIGNED;
 1491                         break;
 1492                 case NFSATTRBIT_ACL:
 1493                         if (compare) {
 1494                           if (!(*retcmpp)) {
 1495                             if (nfsrv_useacl && nfs_supportsnfsv4acls(vp)) {
 1496                                 NFSACL_T *naclp;
 1497 
 1498                                 naclp = acl_alloc(M_WAITOK);
 1499                                 error = nfsrv_dissectacl(nd, naclp, true,
 1500                                     &aceerr, &cnt, p);
 1501                                 if (error) {
 1502                                     acl_free(naclp);
 1503                                     goto nfsmout;
 1504                                 }
 1505                                 if (aceerr || aclp == NULL ||
 1506                                     nfsrv_compareacl(aclp, naclp))
 1507                                     *retcmpp = NFSERR_NOTSAME;
 1508                                 acl_free(naclp);
 1509                             } else {
 1510                                 error = nfsrv_dissectacl(nd, NULL, true,
 1511                                     &aceerr, &cnt, p);
 1512                                 if (error)
 1513                                     goto nfsmout;
 1514                                 *retcmpp = NFSERR_ATTRNOTSUPP;
 1515                             }
 1516                           }
 1517                         } else {
 1518                                 if (vp != NULL && aclp != NULL)
 1519                                     error = nfsrv_dissectacl(nd, aclp, false,
 1520                                         &aceerr, &cnt, p);
 1521                                 else
 1522                                     error = nfsrv_dissectacl(nd, NULL, false,
 1523                                         &aceerr, &cnt, p);
 1524                                 if (error)
 1525                                     goto nfsmout;
 1526                         }
 1527                         
 1528                         attrsum += cnt;
 1529                         break;
 1530                 case NFSATTRBIT_ACLSUPPORT:
 1531                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 1532                         if (compare && !(*retcmpp)) {
 1533                                 if (nfsrv_useacl && nfs_supportsnfsv4acls(vp)) {
 1534                                         if (fxdr_unsigned(u_int32_t, *tl) !=
 1535                                             NFSV4ACE_SUPTYPES)
 1536                                                 *retcmpp = NFSERR_NOTSAME;
 1537                                 } else {
 1538                                         *retcmpp = NFSERR_ATTRNOTSUPP;
 1539                                 }
 1540                         }
 1541                         attrsum += NFSX_UNSIGNED;
 1542                         break;
 1543                 case NFSATTRBIT_ARCHIVE:
 1544                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 1545                         if (compare && !(*retcmpp))
 1546                                 *retcmpp = NFSERR_ATTRNOTSUPP;
 1547                         attrsum += NFSX_UNSIGNED;
 1548                         break;
 1549                 case NFSATTRBIT_CANSETTIME:
 1550                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 1551                         if (compare) {
 1552                                 if (!(*retcmpp)) {
 1553                                     if (fsp->fs_properties & NFSV3_FSFCANSETTIME) {
 1554                                         if (*tl == newnfs_false)
 1555                                                 *retcmpp = NFSERR_NOTSAME;
 1556                                     } else {
 1557                                         if (*tl == newnfs_true)
 1558                                                 *retcmpp = NFSERR_NOTSAME;
 1559                                     }
 1560                                 }
 1561                         } else if (fsp != NULL) {
 1562                                 if (*tl == newnfs_true)
 1563                                         fsp->fs_properties |= NFSV3_FSFCANSETTIME;
 1564                                 else
 1565                                         fsp->fs_properties &= ~NFSV3_FSFCANSETTIME;
 1566                         }
 1567                         attrsum += NFSX_UNSIGNED;
 1568                         break;
 1569                 case NFSATTRBIT_CASEINSENSITIVE:
 1570                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 1571                         if (compare) {
 1572                                 if (!(*retcmpp)) {
 1573                                     if (*tl != newnfs_false)
 1574                                         *retcmpp = NFSERR_NOTSAME;
 1575                                 }
 1576                         } else if (pc != NULL) {
 1577                                 pc->pc_caseinsensitive =
 1578                                     fxdr_unsigned(u_int32_t, *tl);
 1579                         }
 1580                         attrsum += NFSX_UNSIGNED;
 1581                         break;
 1582                 case NFSATTRBIT_CASEPRESERVING:
 1583                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 1584                         if (compare) {
 1585                                 if (!(*retcmpp)) {
 1586                                     if (*tl != newnfs_true)
 1587                                         *retcmpp = NFSERR_NOTSAME;
 1588                                 }
 1589                         } else if (pc != NULL) {
 1590                                 pc->pc_casepreserving =
 1591                                     fxdr_unsigned(u_int32_t, *tl);
 1592                         }
 1593                         attrsum += NFSX_UNSIGNED;
 1594                         break;
 1595                 case NFSATTRBIT_CHOWNRESTRICTED:
 1596                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 1597                         if (compare) {
 1598                                 if (!(*retcmpp)) {
 1599                                     if (*tl != newnfs_true)
 1600                                         *retcmpp = NFSERR_NOTSAME;
 1601                                 }
 1602                         } else if (pc != NULL) {
 1603                                 pc->pc_chownrestricted =
 1604                                     fxdr_unsigned(u_int32_t, *tl);
 1605                         }
 1606                         attrsum += NFSX_UNSIGNED;
 1607                         break;
 1608                 case NFSATTRBIT_FILEHANDLE:
 1609                         error = nfsm_getfh(nd, &tnfhp);
 1610                         if (error)
 1611                                 goto nfsmout;
 1612                         tfhsize = tnfhp->nfh_len;
 1613                         if (compare) {
 1614                                 if (!(*retcmpp) &&
 1615                                     !NFSRV_CMPFH(tnfhp->nfh_fh, tfhsize,
 1616                                      fhp, fhsize))
 1617                                         *retcmpp = NFSERR_NOTSAME;
 1618                                 free(tnfhp, M_NFSFH);
 1619                         } else if (nfhpp != NULL) {
 1620                                 *nfhpp = tnfhp;
 1621                         } else {
 1622                                 free(tnfhp, M_NFSFH);
 1623                         }
 1624                         attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(tfhsize));
 1625                         break;
 1626                 case NFSATTRBIT_FILEID:
 1627                         NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
 1628                         thyp = fxdr_hyper(tl);
 1629                         if (compare) {
 1630                                 if (!(*retcmpp)) {
 1631                                         if (nap->na_fileid != thyp)
 1632                                                 *retcmpp = NFSERR_NOTSAME;
 1633                                 }
 1634                         } else if (nap != NULL)
 1635                                 nap->na_fileid = thyp;
 1636                         attrsum += NFSX_HYPER;
 1637                         break;
 1638                 case NFSATTRBIT_FILESAVAIL:
 1639                         NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
 1640                         if (compare) {
 1641                                 uquad = nfsv4_filesavail(sbp, vp->v_mount);
 1642                                 if (!(*retcmpp) && uquad != fxdr_hyper(tl))
 1643                                         *retcmpp = NFSERR_NOTSAME;
 1644                         } else if (sfp != NULL) {
 1645                                 sfp->sf_afiles = fxdr_hyper(tl);
 1646                         }
 1647                         attrsum += NFSX_HYPER;
 1648                         break;
 1649                 case NFSATTRBIT_FILESFREE:
 1650                         NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
 1651                         if (compare) {
 1652                                 uquad = (uint64_t)sbp->f_ffree;
 1653                                 if (!(*retcmpp) && uquad != fxdr_hyper(tl))
 1654                                         *retcmpp = NFSERR_NOTSAME;
 1655                         } else if (sfp != NULL) {
 1656                                 sfp->sf_ffiles = fxdr_hyper(tl);
 1657                         }
 1658                         attrsum += NFSX_HYPER;
 1659                         break;
 1660                 case NFSATTRBIT_FILESTOTAL:
 1661                         NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
 1662                         if (compare) {
 1663                                 uquad = sbp->f_files;
 1664                                 if (!(*retcmpp) && uquad != fxdr_hyper(tl))
 1665                                         *retcmpp = NFSERR_NOTSAME;
 1666                         } else if (sfp != NULL) {
 1667                                 sfp->sf_tfiles = fxdr_hyper(tl);
 1668                         }
 1669                         attrsum += NFSX_HYPER;
 1670                         break;
 1671                 case NFSATTRBIT_FSLOCATIONS:
 1672                         error = nfsrv_getrefstr(nd, &cp, &cp2, &l, &m);
 1673                         if (error)
 1674                                 goto nfsmout;
 1675                         attrsum += l;
 1676                         if (compare && !(*retcmpp)) {
 1677                                 refp = nfsv4root_getreferral(vp, NULL, 0);
 1678                                 if (refp != NULL) {
 1679                                         if (cp == NULL || cp2 == NULL ||
 1680                                             strcmp(cp, "/") ||
 1681                                             strcmp(cp2, refp->nfr_srvlist))
 1682                                                 *retcmpp = NFSERR_NOTSAME;
 1683                                 } else if (m == 0) {
 1684                                         *retcmpp = NFSERR_NOTSAME;
 1685                                 }
 1686                         }
 1687                         if (cp != NULL)
 1688                                 free(cp, M_NFSSTRING);
 1689                         if (cp2 != NULL)
 1690                                 free(cp2, M_NFSSTRING);
 1691                         break;
 1692                 case NFSATTRBIT_HIDDEN:
 1693                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 1694                         if (compare && !(*retcmpp))
 1695                                 *retcmpp = NFSERR_ATTRNOTSUPP;
 1696                         attrsum += NFSX_UNSIGNED;
 1697                         break;
 1698                 case NFSATTRBIT_HOMOGENEOUS:
 1699                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 1700                         if (compare) {
 1701                                 if (!(*retcmpp)) {
 1702                                     if (fsp->fs_properties &
 1703                                         NFSV3_FSFHOMOGENEOUS) {
 1704                                         if (*tl == newnfs_false)
 1705                                                 *retcmpp = NFSERR_NOTSAME;
 1706                                     } else {
 1707                                         if (*tl == newnfs_true)
 1708                                                 *retcmpp = NFSERR_NOTSAME;
 1709                                     }
 1710                                 }
 1711                         } else if (fsp != NULL) {
 1712                                 if (*tl == newnfs_true)
 1713                                     fsp->fs_properties |= NFSV3_FSFHOMOGENEOUS;
 1714                                 else
 1715                                     fsp->fs_properties &= ~NFSV3_FSFHOMOGENEOUS;
 1716                         }
 1717                         attrsum += NFSX_UNSIGNED;
 1718                         break;
 1719                 case NFSATTRBIT_MAXFILESIZE:
 1720                         NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
 1721                         tnfsquad.qval = fxdr_hyper(tl);
 1722                         if (compare) {
 1723                                 if (!(*retcmpp)) {
 1724                                         tquad = NFSRV_MAXFILESIZE;
 1725                                         if (tquad != tnfsquad.qval)
 1726                                                 *retcmpp = NFSERR_NOTSAME;
 1727                                 }
 1728                         } else if (fsp != NULL) {
 1729                                 fsp->fs_maxfilesize = tnfsquad.qval;
 1730                         }
 1731                         attrsum += NFSX_HYPER;
 1732                         break;
 1733                 case NFSATTRBIT_MAXLINK:
 1734                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 1735                         if (compare) {
 1736                                 if (!(*retcmpp)) {
 1737                                     if (fxdr_unsigned(int, *tl) != NFS_LINK_MAX)
 1738                                         *retcmpp = NFSERR_NOTSAME;
 1739                                 }
 1740                         } else if (pc != NULL) {
 1741                                 pc->pc_linkmax = fxdr_unsigned(u_int32_t, *tl);
 1742                         }
 1743                         attrsum += NFSX_UNSIGNED;
 1744                         break;
 1745                 case NFSATTRBIT_MAXNAME:
 1746                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 1747                         if (compare) {
 1748                                 if (!(*retcmpp)) {
 1749                                     if (fsp->fs_maxname !=
 1750                                         fxdr_unsigned(u_int32_t, *tl))
 1751                                                 *retcmpp = NFSERR_NOTSAME;
 1752                                 }
 1753                         } else {
 1754                                 tuint = fxdr_unsigned(u_int32_t, *tl);
 1755                                 /*
 1756                                  * Some Linux NFSv4 servers report this
 1757                                  * as 0 or 4billion, so I'll set it to
 1758                                  * NFS_MAXNAMLEN. If a server actually creates
 1759                                  * a name longer than NFS_MAXNAMLEN, it will
 1760                                  * get an error back.
 1761                                  */
 1762                                 if (tuint == 0 || tuint > NFS_MAXNAMLEN)
 1763                                         tuint = NFS_MAXNAMLEN;
 1764                                 if (fsp != NULL)
 1765                                         fsp->fs_maxname = tuint;
 1766                                 if (pc != NULL)
 1767                                         pc->pc_namemax = tuint;
 1768                         }
 1769                         attrsum += NFSX_UNSIGNED;
 1770                         break;
 1771                 case NFSATTRBIT_MAXREAD:
 1772                         NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
 1773                         if (compare) {
 1774                                 if (!(*retcmpp)) {
 1775                                     if (fsp->fs_rtmax != fxdr_unsigned(u_int32_t,
 1776                                         *(tl + 1)) || *tl != 0)
 1777                                         *retcmpp = NFSERR_NOTSAME;
 1778                                 }
 1779                         } else if (fsp != NULL) {
 1780                                 fsp->fs_rtmax = fxdr_unsigned(u_int32_t, *++tl);
 1781                                 fsp->fs_rtpref = fsp->fs_rtmax;
 1782                                 fsp->fs_dtpref = fsp->fs_rtpref;
 1783                         }
 1784                         attrsum += NFSX_HYPER;
 1785                         break;
 1786                 case NFSATTRBIT_MAXWRITE:
 1787                         NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
 1788                         if (compare) {
 1789                                 if (!(*retcmpp)) {
 1790                                     if (fsp->fs_wtmax != fxdr_unsigned(u_int32_t,
 1791                                         *(tl + 1)) || *tl != 0)
 1792                                         *retcmpp = NFSERR_NOTSAME;
 1793                                 }
 1794                         } else if (fsp != NULL) {
 1795                                 fsp->fs_wtmax = fxdr_unsigned(int, *++tl);
 1796                                 fsp->fs_wtpref = fsp->fs_wtmax;
 1797                         }
 1798                         attrsum += NFSX_HYPER;
 1799                         break;
 1800                 case NFSATTRBIT_MIMETYPE:
 1801                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 1802                         i = fxdr_unsigned(int, *tl);
 1803                         attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(i));
 1804                         error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
 1805                         if (error)
 1806                                 goto nfsmout;
 1807                         if (compare && !(*retcmpp))
 1808                                 *retcmpp = NFSERR_ATTRNOTSUPP;
 1809                         break;
 1810                 case NFSATTRBIT_MODE:
 1811                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 1812                         if (compare) {
 1813                                 if (!(*retcmpp)) {
 1814                                     if (nap->na_mode != nfstov_mode(*tl))
 1815                                         *retcmpp = NFSERR_NOTSAME;
 1816                                 }
 1817                         } else if (nap != NULL) {
 1818                                 nap->na_mode = nfstov_mode(*tl);
 1819                         }
 1820                         attrsum += NFSX_UNSIGNED;
 1821                         break;
 1822                 case NFSATTRBIT_NOTRUNC:
 1823                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 1824                         if (compare) {
 1825                                 if (!(*retcmpp)) {
 1826                                     if (*tl != newnfs_true)
 1827                                         *retcmpp = NFSERR_NOTSAME;
 1828                                 }
 1829                         } else if (pc != NULL) {
 1830                                 pc->pc_notrunc = fxdr_unsigned(u_int32_t, *tl);
 1831                         }
 1832                         attrsum += NFSX_UNSIGNED;
 1833                         break;
 1834                 case NFSATTRBIT_NUMLINKS:
 1835                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 1836                         tuint = fxdr_unsigned(u_int32_t, *tl);
 1837                         if (compare) {
 1838                             if (!(*retcmpp)) {
 1839                                 if ((u_int32_t)nap->na_nlink != tuint)
 1840                                         *retcmpp = NFSERR_NOTSAME;
 1841                             }
 1842                         } else if (nap != NULL) {
 1843                                 nap->na_nlink = tuint;
 1844                         }
 1845                         attrsum += NFSX_UNSIGNED;
 1846                         break;
 1847                 case NFSATTRBIT_OWNER:
 1848                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 1849                         j = fxdr_unsigned(int, *tl);
 1850                         if (j < 0 || j > NFSV4_MAXOWNERGROUPLEN) {
 1851                                 error = NFSERR_BADXDR;
 1852                                 goto nfsmout;
 1853                         }
 1854                         attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
 1855                         if (j > NFSV4_SMALLSTR)
 1856                                 cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
 1857                         else
 1858                                 cp = namestr;
 1859                         error = nfsrv_mtostr(nd, cp, j);
 1860                         if (error) {
 1861                                 if (j > NFSV4_SMALLSTR)
 1862                                         free(cp, M_NFSSTRING);
 1863                                 goto nfsmout;
 1864                         }
 1865                         if (compare) {
 1866                             if (!(*retcmpp)) {
 1867                                 if (nfsv4_strtouid(nd, cp, j, &uid) ||
 1868                                     nap->na_uid != uid)
 1869                                     *retcmpp = NFSERR_NOTSAME;
 1870                             }
 1871                         } else if (nap != NULL) {
 1872                                 if (nfsv4_strtouid(nd, cp, j, &uid))
 1873                                         nap->na_uid = nfsrv_defaultuid;
 1874                                 else
 1875                                         nap->na_uid = uid;
 1876                         }
 1877                         if (j > NFSV4_SMALLSTR)
 1878                                 free(cp, M_NFSSTRING);
 1879                         break;
 1880                 case NFSATTRBIT_OWNERGROUP:
 1881                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 1882                         j = fxdr_unsigned(int, *tl);
 1883                         if (j < 0 || j > NFSV4_MAXOWNERGROUPLEN) {
 1884                                 error =  NFSERR_BADXDR;
 1885                                 goto nfsmout;
 1886                         }
 1887                         attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
 1888                         if (j > NFSV4_SMALLSTR)
 1889                                 cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
 1890                         else
 1891                                 cp = namestr;
 1892                         error = nfsrv_mtostr(nd, cp, j);
 1893                         if (error) {
 1894                                 if (j > NFSV4_SMALLSTR)
 1895                                         free(cp, M_NFSSTRING);
 1896                                 goto nfsmout;
 1897                         }
 1898                         if (compare) {
 1899                             if (!(*retcmpp)) {
 1900                                 if (nfsv4_strtogid(nd, cp, j, &gid) ||
 1901                                     nap->na_gid != gid)
 1902                                     *retcmpp = NFSERR_NOTSAME;
 1903                             }
 1904                         } else if (nap != NULL) {
 1905                                 if (nfsv4_strtogid(nd, cp, j, &gid))
 1906                                         nap->na_gid = nfsrv_defaultgid;
 1907                                 else
 1908                                         nap->na_gid = gid;
 1909                         }
 1910                         if (j > NFSV4_SMALLSTR)
 1911                                 free(cp, M_NFSSTRING);
 1912                         break;
 1913                 case NFSATTRBIT_QUOTAHARD:
 1914                         NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
 1915                         if (sbp != NULL) {
 1916                             if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA))
 1917                                 freenum = sbp->f_bfree;
 1918                             else
 1919                                 freenum = sbp->f_bavail;
 1920 #ifdef QUOTA
 1921                             /*
 1922                              * ufs_quotactl() insists that the uid argument
 1923                              * equal p_ruid for non-root quota access, so
 1924                              * we'll just make sure that's the case.
 1925                              */
 1926                             savuid = p->p_cred->p_ruid;
 1927                             p->p_cred->p_ruid = cred->cr_uid;
 1928                             if (!VFS_QUOTACTL(vp->v_mount,QCMD(Q_GETQUOTA,
 1929                                 USRQUOTA), cred->cr_uid, &dqb))
 1930                                 freenum = min(dqb.dqb_bhardlimit, freenum);
 1931                             p->p_cred->p_ruid = savuid;
 1932 #endif  /* QUOTA */
 1933                             uquad = (u_int64_t)freenum;
 1934                             NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
 1935                         }
 1936                         if (compare && !(*retcmpp)) {
 1937                                 if (uquad != fxdr_hyper(tl))
 1938                                         *retcmpp = NFSERR_NOTSAME;
 1939                         }
 1940                         attrsum += NFSX_HYPER;
 1941                         break;
 1942                 case NFSATTRBIT_QUOTASOFT:
 1943                         NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
 1944                         if (sbp != NULL) {
 1945                             if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA))
 1946                                 freenum = sbp->f_bfree;
 1947                             else
 1948                                 freenum = sbp->f_bavail;
 1949 #ifdef QUOTA
 1950                             /*
 1951                              * ufs_quotactl() insists that the uid argument
 1952                              * equal p_ruid for non-root quota access, so
 1953                              * we'll just make sure that's the case.
 1954                              */
 1955                             savuid = p->p_cred->p_ruid;
 1956                             p->p_cred->p_ruid = cred->cr_uid;
 1957                             if (!VFS_QUOTACTL(vp->v_mount,QCMD(Q_GETQUOTA,
 1958                                 USRQUOTA), cred->cr_uid, &dqb))
 1959                                 freenum = min(dqb.dqb_bsoftlimit, freenum);
 1960                             p->p_cred->p_ruid = savuid;
 1961 #endif  /* QUOTA */
 1962                             uquad = (u_int64_t)freenum;
 1963                             NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
 1964                         }
 1965                         if (compare && !(*retcmpp)) {
 1966                                 if (uquad != fxdr_hyper(tl))
 1967                                         *retcmpp = NFSERR_NOTSAME;
 1968                         }
 1969                         attrsum += NFSX_HYPER;
 1970                         break;
 1971                 case NFSATTRBIT_QUOTAUSED:
 1972                         NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
 1973                         if (sbp != NULL) {
 1974                             freenum = 0;
 1975 #ifdef QUOTA
 1976                             /*
 1977                              * ufs_quotactl() insists that the uid argument
 1978                              * equal p_ruid for non-root quota access, so
 1979                              * we'll just make sure that's the case.
 1980                              */
 1981                             savuid = p->p_cred->p_ruid;
 1982                             p->p_cred->p_ruid = cred->cr_uid;
 1983                             if (!VFS_QUOTACTL(vp->v_mount,QCMD(Q_GETQUOTA,
 1984                                 USRQUOTA), cred->cr_uid, &dqb))
 1985                                 freenum = dqb.dqb_curblocks;
 1986                             p->p_cred->p_ruid = savuid;
 1987 #endif  /* QUOTA */
 1988                             uquad = (u_int64_t)freenum;
 1989                             NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize);
 1990                         }
 1991                         if (compare && !(*retcmpp)) {
 1992                                 if (uquad != fxdr_hyper(tl))
 1993                                         *retcmpp = NFSERR_NOTSAME;
 1994                         }
 1995                         attrsum += NFSX_HYPER;
 1996                         break;
 1997                 case NFSATTRBIT_RAWDEV:
 1998                         NFSM_DISSECT(tl, u_int32_t *, NFSX_V4SPECDATA);
 1999                         j = fxdr_unsigned(int, *tl++);
 2000                         k = fxdr_unsigned(int, *tl);
 2001                         if (compare) {
 2002                             if (!(*retcmpp)) {
 2003                                 if (nap->na_rdev != NFSMAKEDEV(j, k))
 2004                                         *retcmpp = NFSERR_NOTSAME;
 2005                             }
 2006                         } else if (nap != NULL) {
 2007                                 nap->na_rdev = NFSMAKEDEV(j, k);
 2008                         }
 2009                         attrsum += NFSX_V4SPECDATA;
 2010                         break;
 2011                 case NFSATTRBIT_SPACEAVAIL:
 2012                         NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
 2013                         if (compare) {
 2014                                 if (priv_check_cred(cred,
 2015                                     PRIV_VFS_BLOCKRESERVE))
 2016                                         uquad = sbp->f_bfree;
 2017                                 else
 2018                                         uquad = (uint64_t)sbp->f_bavail;
 2019                                 uquad *= sbp->f_bsize;
 2020                                 if (!(*retcmpp) && uquad != fxdr_hyper(tl))
 2021                                         *retcmpp = NFSERR_NOTSAME;
 2022                         } else if (sfp != NULL) {
 2023                                 sfp->sf_abytes = fxdr_hyper(tl);
 2024                         }
 2025                         attrsum += NFSX_HYPER;
 2026                         break;
 2027                 case NFSATTRBIT_SPACEFREE:
 2028                         NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
 2029                         if (compare) {
 2030                                 uquad = sbp->f_bfree;
 2031                                 uquad *= sbp->f_bsize;
 2032                                 if (!(*retcmpp) && uquad != fxdr_hyper(tl))
 2033                                         *retcmpp = NFSERR_NOTSAME;
 2034                         } else if (sfp != NULL) {
 2035                                 sfp->sf_fbytes = fxdr_hyper(tl);
 2036                         }
 2037                         attrsum += NFSX_HYPER;
 2038                         break;
 2039                 case NFSATTRBIT_SPACETOTAL:
 2040                         NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
 2041                         if (compare) {
 2042                                 uquad = sbp->f_blocks;
 2043                                 uquad *= sbp->f_bsize;
 2044                                 if (!(*retcmpp) && uquad != fxdr_hyper(tl))
 2045                                         *retcmpp = NFSERR_NOTSAME;
 2046                         } else if (sfp != NULL) {
 2047                                 sfp->sf_tbytes = fxdr_hyper(tl);
 2048                         }
 2049                         attrsum += NFSX_HYPER;
 2050                         break;
 2051                 case NFSATTRBIT_SPACEUSED:
 2052                         NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
 2053                         thyp = fxdr_hyper(tl);
 2054                         if (compare) {
 2055                             if (!(*retcmpp)) {
 2056                                 if ((u_int64_t)nap->na_bytes != thyp)
 2057                                         *retcmpp = NFSERR_NOTSAME;
 2058                             }
 2059                         } else if (nap != NULL) {
 2060                                 nap->na_bytes = thyp;
 2061                         }
 2062                         attrsum += NFSX_HYPER;
 2063                         break;
 2064                 case NFSATTRBIT_SYSTEM:
 2065                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 2066                         if (compare && !(*retcmpp))
 2067                                 *retcmpp = NFSERR_ATTRNOTSUPP;
 2068                         attrsum += NFSX_UNSIGNED;
 2069                         break;
 2070                 case NFSATTRBIT_TIMEACCESS:
 2071                         NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
 2072                         fxdr_nfsv4time(tl, &temptime);
 2073                         if (compare) {
 2074                             if (!(*retcmpp)) {
 2075                                 if (!NFS_CMPTIME(temptime, nap->na_atime))
 2076                                         *retcmpp = NFSERR_NOTSAME;
 2077                             }
 2078                         } else if (nap != NULL) {
 2079                                 nap->na_atime = temptime;
 2080                         }
 2081                         attrsum += NFSX_V4TIME;
 2082                         break;
 2083                 case NFSATTRBIT_TIMEACCESSSET:
 2084                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 2085                         attrsum += NFSX_UNSIGNED;
 2086                         i = fxdr_unsigned(int, *tl);
 2087                         if (i == NFSV4SATTRTIME_TOCLIENT) {
 2088                                 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
 2089                                 attrsum += NFSX_V4TIME;
 2090                         }
 2091                         if (compare && !(*retcmpp))
 2092                                 *retcmpp = NFSERR_INVAL;
 2093                         break;
 2094                 case NFSATTRBIT_TIMEBACKUP:
 2095                         NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
 2096                         if (compare && !(*retcmpp))
 2097                                 *retcmpp = NFSERR_ATTRNOTSUPP;
 2098                         attrsum += NFSX_V4TIME;
 2099                         break;
 2100                 case NFSATTRBIT_TIMECREATE:
 2101                         NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
 2102                         fxdr_nfsv4time(tl, &temptime);
 2103                         if (compare) {
 2104                             if (!(*retcmpp)) {
 2105                                 if (!NFS_CMPTIME(temptime, nap->na_btime))
 2106                                         *retcmpp = NFSERR_NOTSAME;
 2107                             }
 2108                         } else if (nap != NULL) {
 2109                                 nap->na_btime = temptime;
 2110                         }
 2111                         attrsum += NFSX_V4TIME;
 2112                         break;
 2113                 case NFSATTRBIT_TIMEDELTA:
 2114                         NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
 2115                         if (fsp != NULL) {
 2116                             if (compare) {
 2117                                 if (!(*retcmpp)) {
 2118                                     if ((u_int32_t)fsp->fs_timedelta.tv_sec !=
 2119                                         fxdr_unsigned(u_int32_t, *(tl + 1)) ||
 2120                                         (u_int32_t)fsp->fs_timedelta.tv_nsec !=
 2121                                         (fxdr_unsigned(u_int32_t, *(tl + 2)) %
 2122                                          1000000000) ||
 2123                                         *tl != 0)
 2124                                             *retcmpp = NFSERR_NOTSAME;
 2125                                 }
 2126                             } else {
 2127                                 fxdr_nfsv4time(tl, &fsp->fs_timedelta);
 2128                             }
 2129                         }
 2130                         attrsum += NFSX_V4TIME;
 2131                         break;
 2132                 case NFSATTRBIT_TIMEMETADATA:
 2133                         NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
 2134                         fxdr_nfsv4time(tl, &temptime);
 2135                         if (compare) {
 2136                             if (!(*retcmpp)) {
 2137                                 if (!NFS_CMPTIME(temptime, nap->na_ctime))
 2138                                         *retcmpp = NFSERR_NOTSAME;
 2139                             }
 2140                         } else if (nap != NULL) {
 2141                                 nap->na_ctime = temptime;
 2142                         }
 2143                         attrsum += NFSX_V4TIME;
 2144                         break;
 2145                 case NFSATTRBIT_TIMEMODIFY:
 2146                         NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
 2147                         fxdr_nfsv4time(tl, &temptime);
 2148                         if (compare) {
 2149                             if (!(*retcmpp)) {
 2150                                 if (!NFS_CMPTIME(temptime, nap->na_mtime))
 2151                                         *retcmpp = NFSERR_NOTSAME;
 2152                             }
 2153                         } else if (nap != NULL) {
 2154                                 nap->na_mtime = temptime;
 2155                         }
 2156                         attrsum += NFSX_V4TIME;
 2157                         break;
 2158                 case NFSATTRBIT_TIMEMODIFYSET:
 2159                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 2160                         attrsum += NFSX_UNSIGNED;
 2161                         i = fxdr_unsigned(int, *tl);
 2162                         if (i == NFSV4SATTRTIME_TOCLIENT) {
 2163                                 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
 2164                                 attrsum += NFSX_V4TIME;
 2165                         }
 2166                         if (compare && !(*retcmpp))
 2167                                 *retcmpp = NFSERR_INVAL;
 2168                         break;
 2169                 case NFSATTRBIT_MOUNTEDONFILEID:
 2170                         NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
 2171                         thyp = fxdr_hyper(tl);
 2172                         if (compare) {
 2173                                 if (!(*retcmpp)) {
 2174                                         if (!vp || !nfsrv_atroot(vp, &thyp2))
 2175                                                 thyp2 = nap->na_fileid;
 2176                                         if (thyp2 != thyp)
 2177                                                 *retcmpp = NFSERR_NOTSAME;
 2178                                 }
 2179                         } else if (nap != NULL)
 2180                                 nap->na_mntonfileno = thyp;
 2181                         attrsum += NFSX_HYPER;
 2182                         break;
 2183                 case NFSATTRBIT_SUPPATTREXCLCREAT:
 2184                         retnotsup = 0;
 2185                         error = nfsrv_getattrbits(nd, &retattrbits,
 2186                             &cnt, &retnotsup);
 2187                         if (error)
 2188                             goto nfsmout;
 2189                         if (compare && !(*retcmpp)) {
 2190                            NFSSETSUPP_ATTRBIT(&checkattrbits, nd);
 2191                            NFSCLRNOTSETABLE_ATTRBIT(&checkattrbits, nd);
 2192                            NFSCLRBIT_ATTRBIT(&checkattrbits,
 2193                                 NFSATTRBIT_TIMEACCESSSET);
 2194                            if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits)
 2195                                || retnotsup)
 2196                                 *retcmpp = NFSERR_NOTSAME;
 2197                         }
 2198                         attrsum += cnt;
 2199                         break;
 2200                 case NFSATTRBIT_FSLAYOUTTYPE:
 2201                 case NFSATTRBIT_LAYOUTTYPE:
 2202                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 2203                         attrsum += NFSX_UNSIGNED;
 2204                         i = fxdr_unsigned(int, *tl);
 2205                         /*
 2206                          * The RFCs do not define an upper limit for the
 2207                          * number of layout types, but 32 should be more
 2208                          * than enough.
 2209                          */
 2210                         if (i < 0 || i > 32) {
 2211                                 error = NFSERR_BADXDR;
 2212                                 goto nfsmout;
 2213                         }
 2214                         if (i > 0) {
 2215                                 NFSM_DISSECT(tl, u_int32_t *, i *
 2216                                     NFSX_UNSIGNED);
 2217                                 attrsum += i * NFSX_UNSIGNED;
 2218                                 j = fxdr_unsigned(int, *tl);
 2219                                 if (i == 1 && compare && !(*retcmpp) &&
 2220                                     (((nfsrv_doflexfile != 0 ||
 2221                                        nfsrv_maxpnfsmirror > 1) &&
 2222                                       j != NFSLAYOUT_FLEXFILE) ||
 2223                                     (nfsrv_doflexfile == 0 &&
 2224                                      j != NFSLAYOUT_NFSV4_1_FILES)))
 2225                                         *retcmpp = NFSERR_NOTSAME;
 2226                         }
 2227                         if (nfsrv_devidcnt == 0) {
 2228                                 if (compare && !(*retcmpp) && i > 0)
 2229                                         *retcmpp = NFSERR_NOTSAME;
 2230                         } else {
 2231                                 if (compare && !(*retcmpp) && i != 1)
 2232                                         *retcmpp = NFSERR_NOTSAME;
 2233                         }
 2234                         break;
 2235                 case NFSATTRBIT_LAYOUTALIGNMENT:
 2236                 case NFSATTRBIT_LAYOUTBLKSIZE:
 2237                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 2238                         attrsum += NFSX_UNSIGNED;
 2239                         i = fxdr_unsigned(int, *tl);
 2240                         if (compare && !(*retcmpp) && i != nfs_srvmaxio)
 2241                                 *retcmpp = NFSERR_NOTSAME;
 2242                         break;
 2243                 default:
 2244                         printf("EEK! nfsv4_loadattr unknown attr=%d\n",
 2245                                 bitpos);
 2246                         if (compare && !(*retcmpp))
 2247                                 *retcmpp = NFSERR_ATTRNOTSUPP;
 2248                         /*
 2249                          * and get out of the loop, since we can't parse
 2250                          * the unknown attribute data.
 2251                          */
 2252                         bitpos = NFSATTRBIT_MAX;
 2253                         break;
 2254                 }
 2255         }
 2256 
 2257         /*
 2258          * some clients pad the attrlist, so we need to skip over the
 2259          * padding.
 2260          */
 2261         if (attrsum > attrsize) {
 2262                 error = NFSERR_BADXDR;
 2263         } else {
 2264                 attrsize = NFSM_RNDUP(attrsize);
 2265                 if (attrsum < attrsize)
 2266                         error = nfsm_advance(nd, attrsize - attrsum, -1);
 2267         }
 2268 nfsmout:
 2269         NFSEXITCODE2(error, nd);
 2270         return (error);
 2271 }
 2272 
 2273 /*
 2274  * Implement sleep locks for newnfs. The nfslock_usecnt allows for a
 2275  * shared lock and the NFSXXX_LOCK flag permits an exclusive lock.
 2276  * The first argument is a pointer to an nfsv4lock structure.
 2277  * The second argument is 1 iff a blocking lock is wanted.
 2278  * If this argument is 0, the call waits until no thread either wants nor
 2279  * holds an exclusive lock.
 2280  * It returns 1 if the lock was acquired, 0 otherwise.
 2281  * If several processes call this function concurrently wanting the exclusive
 2282  * lock, one will get the lock and the rest will return without getting the
 2283  * lock. (If the caller must have the lock, it simply calls this function in a
 2284  *  loop until the function returns 1 to indicate the lock was acquired.)
 2285  * Any usecnt must be decremented by calling nfsv4_relref() before
 2286  * calling nfsv4_lock(). It was done this way, so nfsv4_lock() could
 2287  * be called in a loop.
 2288  * The isleptp argument is set to indicate if the call slept, iff not NULL
 2289  * and the mp argument indicates to check for a forced dismount, iff not
 2290  * NULL.
 2291  */
 2292 int
 2293 nfsv4_lock(struct nfsv4lock *lp, int iwantlock, int *isleptp,
 2294     struct mtx *mutex, struct mount *mp)
 2295 {
 2296 
 2297         if (isleptp)
 2298                 *isleptp = 0;
 2299         /*
 2300          * If a lock is wanted, loop around until the lock is acquired by
 2301          * someone and then released. If I want the lock, try to acquire it.
 2302          * For a lock to be issued, no lock must be in force and the usecnt
 2303          * must be zero.
 2304          */
 2305         if (iwantlock) {
 2306             if (!(lp->nfslock_lock & NFSV4LOCK_LOCK) &&
 2307                 lp->nfslock_usecnt == 0) {
 2308                 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
 2309                 lp->nfslock_lock |= NFSV4LOCK_LOCK;
 2310                 return (1);
 2311             }
 2312             lp->nfslock_lock |= NFSV4LOCK_LOCKWANTED;
 2313         }
 2314         while (lp->nfslock_lock & (NFSV4LOCK_LOCK | NFSV4LOCK_LOCKWANTED)) {
 2315                 if (mp != NULL && NFSCL_FORCEDISM(mp)) {
 2316                         lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
 2317                         return (0);
 2318                 }
 2319                 lp->nfslock_lock |= NFSV4LOCK_WANTED;
 2320                 if (isleptp)
 2321                         *isleptp = 1;
 2322                 msleep(&lp->nfslock_lock, mutex, PVFS, "nfsv4lck", hz);
 2323                 if (iwantlock && !(lp->nfslock_lock & NFSV4LOCK_LOCK) &&
 2324                     lp->nfslock_usecnt == 0) {
 2325                         lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED;
 2326                         lp->nfslock_lock |= NFSV4LOCK_LOCK;
 2327                         return (1);
 2328                 }
 2329         }
 2330         return (0);
 2331 }
 2332 
 2333 /*
 2334  * Release the lock acquired by nfsv4_lock().
 2335  * The second argument is set to 1 to indicate the nfslock_usecnt should be
 2336  * incremented, as well.
 2337  */
 2338 void
 2339 nfsv4_unlock(struct nfsv4lock *lp, int incref)
 2340 {
 2341 
 2342         lp->nfslock_lock &= ~NFSV4LOCK_LOCK;
 2343         if (incref)
 2344                 lp->nfslock_usecnt++;
 2345         nfsv4_wanted(lp);
 2346 }
 2347 
 2348 /*
 2349  * Release a reference cnt.
 2350  */
 2351 void
 2352 nfsv4_relref(struct nfsv4lock *lp)
 2353 {
 2354 
 2355         if (lp->nfslock_usecnt <= 0)
 2356                 panic("nfsv4root ref cnt");
 2357         lp->nfslock_usecnt--;
 2358         if (lp->nfslock_usecnt == 0)
 2359                 nfsv4_wanted(lp);
 2360 }
 2361 
 2362 /*
 2363  * Get a reference cnt.
 2364  * This function will wait for any exclusive lock to be released, but will
 2365  * not wait for threads that want the exclusive lock. If priority needs
 2366  * to be given to threads that need the exclusive lock, a call to nfsv4_lock()
 2367  * with the 2nd argument == 0 should be done before calling nfsv4_getref().
 2368  * If the mp argument is not NULL, check for NFSCL_FORCEDISM() being set and
 2369  * return without getting a refcnt for that case.
 2370  */
 2371 void
 2372 nfsv4_getref(struct nfsv4lock *lp, int *isleptp, struct mtx *mutex,
 2373     struct mount *mp)
 2374 {
 2375 
 2376         if (isleptp)
 2377                 *isleptp = 0;
 2378 
 2379         /*
 2380          * Wait for a lock held.
 2381          */
 2382         while (lp->nfslock_lock & NFSV4LOCK_LOCK) {
 2383                 if (mp != NULL && NFSCL_FORCEDISM(mp))
 2384                         return;
 2385                 lp->nfslock_lock |= NFSV4LOCK_WANTED;
 2386                 if (isleptp)
 2387                         *isleptp = 1;
 2388                 msleep(&lp->nfslock_lock, mutex, PVFS, "nfsv4gr", hz);
 2389         }
 2390         if (mp != NULL && NFSCL_FORCEDISM(mp))
 2391                 return;
 2392 
 2393         lp->nfslock_usecnt++;
 2394 }
 2395 
 2396 /*
 2397  * Get a reference as above, but return failure instead of sleeping if
 2398  * an exclusive lock is held.
 2399  */
 2400 int
 2401 nfsv4_getref_nonblock(struct nfsv4lock *lp)
 2402 {
 2403 
 2404         if ((lp->nfslock_lock & NFSV4LOCK_LOCK) != 0)
 2405                 return (0);
 2406 
 2407         lp->nfslock_usecnt++;
 2408         return (1);
 2409 }
 2410 
 2411 /*
 2412  * Test for a lock. Return 1 if locked, 0 otherwise.
 2413  */
 2414 int
 2415 nfsv4_testlock(struct nfsv4lock *lp)
 2416 {
 2417 
 2418         if ((lp->nfslock_lock & NFSV4LOCK_LOCK) == 0 &&
 2419             lp->nfslock_usecnt == 0)
 2420                 return (0);
 2421         return (1);
 2422 }
 2423 
 2424 /*
 2425  * Wake up anyone sleeping, waiting for this lock.
 2426  */
 2427 static void
 2428 nfsv4_wanted(struct nfsv4lock *lp)
 2429 {
 2430 
 2431         if (lp->nfslock_lock & NFSV4LOCK_WANTED) {
 2432                 lp->nfslock_lock &= ~NFSV4LOCK_WANTED;
 2433                 wakeup((caddr_t)&lp->nfslock_lock);
 2434         }
 2435 }
 2436 
 2437 /*
 2438  * Copy a string from an mbuf list into a character array.
 2439  * Return EBADRPC if there is an mbuf error,
 2440  * 0 otherwise.
 2441  */
 2442 int
 2443 nfsrv_mtostr(struct nfsrv_descript *nd, char *str, int siz)
 2444 {
 2445         char *cp;
 2446         int xfer, len;
 2447         struct mbuf *mp;
 2448         int rem, error = 0;
 2449 
 2450         mp = nd->nd_md;
 2451         cp = nd->nd_dpos;
 2452         len = mtod(mp, caddr_t) + mp->m_len - cp;
 2453         rem = NFSM_RNDUP(siz) - siz;
 2454         while (siz > 0) {
 2455                 if (len > siz)
 2456                         xfer = siz;
 2457                 else
 2458                         xfer = len;
 2459                 NFSBCOPY(cp, str, xfer);
 2460                 str += xfer;
 2461                 siz -= xfer;
 2462                 if (siz > 0) {
 2463                         mp = mp->m_next;
 2464                         if (mp == NULL) {
 2465                                 error = EBADRPC;
 2466                                 goto out;
 2467                         }
 2468                         cp = mtod(mp, caddr_t);
 2469                         len = mp->m_len;
 2470                 } else {
 2471                         cp += xfer;
 2472                         len -= xfer;
 2473                 }
 2474         }
 2475         *str = '\0';
 2476         nd->nd_dpos = cp;
 2477         nd->nd_md = mp;
 2478         if (rem > 0) {
 2479                 if (len < rem)
 2480                         error = nfsm_advance(nd, rem, len);
 2481                 else
 2482                         nd->nd_dpos += rem;
 2483         }
 2484 
 2485 out:
 2486         NFSEXITCODE2(error, nd);
 2487         return (error);
 2488 }
 2489 
 2490 /*
 2491  * Fill in the attributes as marked by the bitmap (V4).
 2492  */
 2493 int
 2494 nfsv4_fillattr(struct nfsrv_descript *nd, struct mount *mp, vnode_t vp,
 2495     NFSACL_T *saclp, struct vattr *vap, fhandle_t *fhp, int rderror,
 2496     nfsattrbit_t *attrbitp, struct ucred *cred, NFSPROC_T *p, int isdgram,
 2497     int reterr, int supports_nfsv4acls, int at_root, uint64_t mounted_on_fileno,
 2498     struct statfs *pnfssf)
 2499 {
 2500         int bitpos, retnum = 0;
 2501         u_int32_t *tl;
 2502         int siz, prefixnum, error;
 2503         u_char *cp, namestr[NFSV4_SMALLSTR];
 2504         nfsattrbit_t attrbits, retbits;
 2505         nfsattrbit_t *retbitp = &retbits;
 2506         u_int32_t freenum, *retnump;
 2507         u_int64_t uquad;
 2508         struct statfs *fs;
 2509         struct nfsfsinfo fsinf;
 2510         struct timespec temptime;
 2511         NFSACL_T *aclp, *naclp = NULL;
 2512         size_t atsiz;
 2513         bool xattrsupp;
 2514 #ifdef QUOTA
 2515         struct dqblk dqb;
 2516         uid_t savuid;
 2517 #endif
 2518 
 2519         /*
 2520          * First, set the bits that can be filled and get fsinfo.
 2521          */
 2522         NFSSET_ATTRBIT(retbitp, attrbitp);
 2523         /*
 2524          * If both p and cred are NULL, it is a client side setattr call.
 2525          * If both p and cred are not NULL, it is a server side reply call.
 2526          * If p is not NULL and cred is NULL, it is a client side callback
 2527          * reply call.
 2528          */
 2529         if (p == NULL && cred == NULL) {
 2530                 NFSCLRNOTSETABLE_ATTRBIT(retbitp, nd);
 2531                 aclp = saclp;
 2532         } else {
 2533                 NFSCLRNOTFILLABLE_ATTRBIT(retbitp, nd);
 2534                 naclp = acl_alloc(M_WAITOK);
 2535                 aclp = naclp;
 2536         }
 2537         nfsvno_getfs(&fsinf, isdgram);
 2538         /*
 2539          * Get the VFS_STATFS(), since some attributes need them.
 2540          */
 2541         fs = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
 2542         if (NFSISSETSTATFS_ATTRBIT(retbitp)) {
 2543                 error = VFS_STATFS(mp, fs);
 2544                 if (error != 0) {
 2545                         if (reterr) {
 2546                                 nd->nd_repstat = NFSERR_ACCES;
 2547                                 free(fs, M_STATFS);
 2548                                 return (0);
 2549                         }
 2550                         NFSCLRSTATFS_ATTRBIT(retbitp);
 2551                 }
 2552                 /*
 2553                  * Since NFS handles these values as unsigned on the
 2554                  * wire, there is no way to represent negative values,
 2555                  * so set them to 0. Without this, they will appear
 2556                  * to be very large positive values for clients like
 2557                  * Solaris10.
 2558                  */
 2559                 if (fs->f_bavail < 0)
 2560                         fs->f_bavail = 0;
 2561                 if (fs->f_ffree < 0)
 2562                         fs->f_ffree = 0;
 2563         }
 2564 
 2565         /*
 2566          * And the NFSv4 ACL...
 2567          */
 2568         if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT) &&
 2569             (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
 2570                 supports_nfsv4acls == 0))) {
 2571                 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT);
 2572         }
 2573         if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACL)) {
 2574                 if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) &&
 2575                     supports_nfsv4acls == 0)) {
 2576                         NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
 2577                 } else if (naclp != NULL) {
 2578                         if (NFSVOPLOCK(vp, LK_SHARED) == 0) {
 2579                                 error = VOP_ACCESSX(vp, VREAD_ACL, cred, p);
 2580                                 if (error == 0)
 2581                                         error = VOP_GETACL(vp, ACL_TYPE_NFS4,
 2582                                             naclp, cred, p);
 2583                                 NFSVOPUNLOCK(vp);
 2584                         } else
 2585                                 error = NFSERR_PERM;
 2586                         if (error != 0) {
 2587                                 if (reterr) {
 2588                                         nd->nd_repstat = NFSERR_ACCES;
 2589                                         free(fs, M_STATFS);
 2590                                         return (0);
 2591                                 }
 2592                                 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL);
 2593                         }
 2594                 }
 2595         }
 2596 
 2597         /* Check to see if Extended Attributes are supported. */
 2598         xattrsupp = false;
 2599         if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_XATTRSUPPORT)) {
 2600                 if (NFSVOPLOCK(vp, LK_SHARED) == 0) {
 2601                         error = VOP_GETEXTATTR(vp, EXTATTR_NAMESPACE_USER,
 2602                             "xxx", NULL, &atsiz, cred, p);
 2603                         NFSVOPUNLOCK(vp);
 2604                         if (error != EOPNOTSUPP)
 2605                                 xattrsupp = true;
 2606                 }
 2607         }
 2608 
 2609         /*
 2610          * Put out the attribute bitmap for the ones being filled in
 2611          * and get the field for the number of attributes returned.
 2612          */
 2613         prefixnum = nfsrv_putattrbit(nd, retbitp);
 2614         NFSM_BUILD(retnump, u_int32_t *, NFSX_UNSIGNED);
 2615         prefixnum += NFSX_UNSIGNED;
 2616 
 2617         /*
 2618          * Now, loop around filling in the attributes for each bit set.
 2619          */
 2620         for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) {
 2621             if (NFSISSET_ATTRBIT(retbitp, bitpos)) {
 2622                 switch (bitpos) {
 2623                 case NFSATTRBIT_SUPPORTEDATTRS:
 2624                         NFSSETSUPP_ATTRBIT(&attrbits, nd);
 2625                         if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL)
 2626                             && supports_nfsv4acls == 0)) {
 2627                             NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACLSUPPORT);
 2628                             NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACL);
 2629                         }
 2630                         retnum += nfsrv_putattrbit(nd, &attrbits);
 2631                         break;
 2632                 case NFSATTRBIT_TYPE:
 2633                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 2634                         *tl = vtonfsv34_type(vap->va_type);
 2635                         retnum += NFSX_UNSIGNED;
 2636                         break;
 2637                 case NFSATTRBIT_FHEXPIRETYPE:
 2638                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 2639                         *tl = txdr_unsigned(NFSV4FHTYPE_PERSISTENT);
 2640                         retnum += NFSX_UNSIGNED;
 2641                         break;
 2642                 case NFSATTRBIT_CHANGE:
 2643                         NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
 2644                         txdr_hyper(vap->va_filerev, tl);
 2645                         retnum += NFSX_HYPER;
 2646                         break;
 2647                 case NFSATTRBIT_SIZE:
 2648                         NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
 2649                         txdr_hyper(vap->va_size, tl);
 2650                         retnum += NFSX_HYPER;
 2651                         break;
 2652                 case NFSATTRBIT_LINKSUPPORT:
 2653                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 2654                         if (fsinf.fs_properties & NFSV3FSINFO_LINK)
 2655                                 *tl = newnfs_true;
 2656                         else
 2657                                 *tl = newnfs_false;
 2658                         retnum += NFSX_UNSIGNED;
 2659                         break;
 2660                 case NFSATTRBIT_SYMLINKSUPPORT:
 2661                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 2662                         if (fsinf.fs_properties & NFSV3FSINFO_SYMLINK)
 2663                                 *tl = newnfs_true;
 2664                         else
 2665                                 *tl = newnfs_false;
 2666                         retnum += NFSX_UNSIGNED;
 2667                         break;
 2668                 case NFSATTRBIT_NAMEDATTR:
 2669                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 2670                         *tl = newnfs_false;
 2671                         retnum += NFSX_UNSIGNED;
 2672                         break;
 2673                 case NFSATTRBIT_FSID:
 2674                         NFSM_BUILD(tl, u_int32_t *, NFSX_V4FSID);
 2675                         *tl++ = 0;
 2676                         *tl++ = txdr_unsigned(mp->mnt_stat.f_fsid.val[0]);
 2677                         *tl++ = 0;
 2678                         *tl = txdr_unsigned(mp->mnt_stat.f_fsid.val[1]);
 2679                         retnum += NFSX_V4FSID;
 2680                         break;
 2681                 case NFSATTRBIT_UNIQUEHANDLES:
 2682                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 2683                         *tl = newnfs_true;
 2684                         retnum += NFSX_UNSIGNED;
 2685                         break;
 2686                 case NFSATTRBIT_LEASETIME:
 2687                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 2688                         *tl = txdr_unsigned(nfsrv_lease);
 2689                         retnum += NFSX_UNSIGNED;
 2690                         break;
 2691                 case NFSATTRBIT_RDATTRERROR:
 2692                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 2693                         *tl = txdr_unsigned(rderror);
 2694                         retnum += NFSX_UNSIGNED;
 2695                         break;
 2696                 /*
 2697                  * Recommended Attributes. (Only the supported ones.)
 2698                  */
 2699                 case NFSATTRBIT_ACL:
 2700                         retnum += nfsrv_buildacl(nd, aclp, vp->v_type, p);
 2701                         break;
 2702                 case NFSATTRBIT_ACLSUPPORT:
 2703                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 2704                         *tl = txdr_unsigned(NFSV4ACE_SUPTYPES);
 2705                         retnum += NFSX_UNSIGNED;
 2706                         break;
 2707                 case NFSATTRBIT_CANSETTIME:
 2708                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 2709                         if (fsinf.fs_properties & NFSV3FSINFO_CANSETTIME)
 2710                                 *tl = newnfs_true;
 2711                         else
 2712                                 *tl = newnfs_false;
 2713                         retnum += NFSX_UNSIGNED;
 2714                         break;
 2715                 case NFSATTRBIT_CASEINSENSITIVE:
 2716                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 2717                         *tl = newnfs_false;
 2718                         retnum += NFSX_UNSIGNED;
 2719                         break;
 2720                 case NFSATTRBIT_CASEPRESERVING:
 2721                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 2722                         *tl = newnfs_true;
 2723                         retnum += NFSX_UNSIGNED;
 2724                         break;
 2725                 case NFSATTRBIT_CHOWNRESTRICTED:
 2726                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 2727                         *tl = newnfs_true;
 2728                         retnum += NFSX_UNSIGNED;
 2729                         break;
 2730                 case NFSATTRBIT_FILEHANDLE:
 2731                         retnum += nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
 2732                         break;
 2733                 case NFSATTRBIT_FILEID:
 2734                         NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
 2735                         uquad = vap->va_fileid;
 2736                         txdr_hyper(uquad, tl);
 2737                         retnum += NFSX_HYPER;
 2738                         break;
 2739                 case NFSATTRBIT_FILESAVAIL:
 2740                         freenum = nfsv4_filesavail(fs, mp);
 2741                         NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
 2742                         *tl++ = 0;
 2743                         *tl = txdr_unsigned(freenum);
 2744                         retnum += NFSX_HYPER;
 2745                         break;
 2746                 case NFSATTRBIT_FILESFREE:
 2747                         NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
 2748                         *tl++ = 0;
 2749                         *tl = txdr_unsigned(fs->f_ffree);
 2750                         retnum += NFSX_HYPER;
 2751                         break;
 2752                 case NFSATTRBIT_FILESTOTAL:
 2753                         NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
 2754                         *tl++ = 0;
 2755                         *tl = txdr_unsigned(fs->f_files);
 2756                         retnum += NFSX_HYPER;
 2757                         break;
 2758                 case NFSATTRBIT_FSLOCATIONS:
 2759                         NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
 2760                         *tl++ = 0;
 2761                         *tl = 0;
 2762                         retnum += 2 * NFSX_UNSIGNED;
 2763                         break;
 2764                 case NFSATTRBIT_HOMOGENEOUS:
 2765                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 2766                         if (fsinf.fs_properties & NFSV3FSINFO_HOMOGENEOUS)
 2767                                 *tl = newnfs_true;
 2768                         else
 2769                                 *tl = newnfs_false;
 2770                         retnum += NFSX_UNSIGNED;
 2771                         break;
 2772                 case NFSATTRBIT_MAXFILESIZE:
 2773                         NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
 2774                         uquad = NFSRV_MAXFILESIZE;
 2775                         txdr_hyper(uquad, tl);
 2776                         retnum += NFSX_HYPER;
 2777                         break;
 2778                 case NFSATTRBIT_MAXLINK:
 2779                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 2780                         *tl = txdr_unsigned(NFS_LINK_MAX);
 2781                         retnum += NFSX_UNSIGNED;
 2782                         break;
 2783                 case NFSATTRBIT_MAXNAME:
 2784                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 2785                         *tl = txdr_unsigned(NFS_MAXNAMLEN);
 2786                         retnum += NFSX_UNSIGNED;
 2787                         break;
 2788                 case NFSATTRBIT_MAXREAD:
 2789                         NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
 2790                         *tl++ = 0;
 2791                         *tl = txdr_unsigned(fsinf.fs_rtmax);
 2792                         retnum += NFSX_HYPER;
 2793                         break;
 2794                 case NFSATTRBIT_MAXWRITE:
 2795                         NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
 2796                         *tl++ = 0;
 2797                         *tl = txdr_unsigned(fsinf.fs_wtmax);
 2798                         retnum += NFSX_HYPER;
 2799                         break;
 2800                 case NFSATTRBIT_MODE:
 2801                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 2802                         *tl = vtonfsv34_mode(vap->va_mode);
 2803                         retnum += NFSX_UNSIGNED;
 2804                         break;
 2805                 case NFSATTRBIT_NOTRUNC:
 2806                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 2807                         *tl = newnfs_true;
 2808                         retnum += NFSX_UNSIGNED;
 2809                         break;
 2810                 case NFSATTRBIT_NUMLINKS:
 2811                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 2812                         *tl = txdr_unsigned(vap->va_nlink);
 2813                         retnum += NFSX_UNSIGNED;
 2814                         break;
 2815                 case NFSATTRBIT_OWNER:
 2816                         cp = namestr;
 2817                         nfsv4_uidtostr(vap->va_uid, &cp, &siz);
 2818                         retnum += nfsm_strtom(nd, cp, siz);
 2819                         if (cp != namestr)
 2820                                 free(cp, M_NFSSTRING);
 2821                         break;
 2822                 case NFSATTRBIT_OWNERGROUP:
 2823                         cp = namestr;
 2824                         nfsv4_gidtostr(vap->va_gid, &cp, &siz);
 2825                         retnum += nfsm_strtom(nd, cp, siz);
 2826                         if (cp != namestr)
 2827                                 free(cp, M_NFSSTRING);
 2828                         break;
 2829                 case NFSATTRBIT_QUOTAHARD:
 2830                         if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA))
 2831                                 freenum = fs->f_bfree;
 2832                         else
 2833                                 freenum = fs->f_bavail;
 2834 #ifdef QUOTA
 2835                         /*
 2836                          * ufs_quotactl() insists that the uid argument
 2837                          * equal p_ruid for non-root quota access, so
 2838                          * we'll just make sure that's the case.
 2839                          */
 2840                         savuid = p->p_cred->p_ruid;
 2841                         p->p_cred->p_ruid = cred->cr_uid;
 2842                         if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
 2843                             cred->cr_uid, &dqb))
 2844                             freenum = min(dqb.dqb_bhardlimit, freenum);
 2845                         p->p_cred->p_ruid = savuid;
 2846 #endif  /* QUOTA */
 2847                         NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
 2848                         uquad = (u_int64_t)freenum;
 2849                         NFSQUOTABLKTOBYTE(uquad, fs->f_bsize);
 2850                         txdr_hyper(uquad, tl);
 2851                         retnum += NFSX_HYPER;
 2852                         break;
 2853                 case NFSATTRBIT_QUOTASOFT:
 2854                         if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA))
 2855                                 freenum = fs->f_bfree;
 2856                         else
 2857                                 freenum = fs->f_bavail;
 2858 #ifdef QUOTA
 2859                         /*
 2860                          * ufs_quotactl() insists that the uid argument
 2861                          * equal p_ruid for non-root quota access, so
 2862                          * we'll just make sure that's the case.
 2863                          */
 2864                         savuid = p->p_cred->p_ruid;
 2865                         p->p_cred->p_ruid = cred->cr_uid;
 2866                         if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
 2867                             cred->cr_uid, &dqb))
 2868                             freenum = min(dqb.dqb_bsoftlimit, freenum);
 2869                         p->p_cred->p_ruid = savuid;
 2870 #endif  /* QUOTA */
 2871                         NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
 2872                         uquad = (u_int64_t)freenum;
 2873                         NFSQUOTABLKTOBYTE(uquad, fs->f_bsize);
 2874                         txdr_hyper(uquad, tl);
 2875                         retnum += NFSX_HYPER;
 2876                         break;
 2877                 case NFSATTRBIT_QUOTAUSED:
 2878                         freenum = 0;
 2879 #ifdef QUOTA
 2880                         /*
 2881                          * ufs_quotactl() insists that the uid argument
 2882                          * equal p_ruid for non-root quota access, so
 2883                          * we'll just make sure that's the case.
 2884                          */
 2885                         savuid = p->p_cred->p_ruid;
 2886                         p->p_cred->p_ruid = cred->cr_uid;
 2887                         if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
 2888                             cred->cr_uid, &dqb))
 2889                             freenum = dqb.dqb_curblocks;
 2890                         p->p_cred->p_ruid = savuid;
 2891 #endif  /* QUOTA */
 2892                         NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
 2893                         uquad = (u_int64_t)freenum;
 2894                         NFSQUOTABLKTOBYTE(uquad, fs->f_bsize);
 2895                         txdr_hyper(uquad, tl);
 2896                         retnum += NFSX_HYPER;
 2897                         break;
 2898                 case NFSATTRBIT_RAWDEV:
 2899                         NFSM_BUILD(tl, u_int32_t *, NFSX_V4SPECDATA);
 2900                         *tl++ = txdr_unsigned(NFSMAJOR(vap->va_rdev));
 2901                         *tl = txdr_unsigned(NFSMINOR(vap->va_rdev));
 2902                         retnum += NFSX_V4SPECDATA;
 2903                         break;
 2904                 case NFSATTRBIT_SPACEAVAIL:
 2905                         NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
 2906                         if (priv_check_cred(cred, PRIV_VFS_BLOCKRESERVE)) {
 2907                                 if (pnfssf != NULL)
 2908                                         uquad = (u_int64_t)pnfssf->f_bfree;
 2909                                 else
 2910                                         uquad = (u_int64_t)fs->f_bfree;
 2911                         } else {
 2912                                 if (pnfssf != NULL)
 2913                                         uquad = (u_int64_t)pnfssf->f_bavail;
 2914                                 else
 2915                                         uquad = (u_int64_t)fs->f_bavail;
 2916                         }
 2917                         if (pnfssf != NULL)
 2918                                 uquad *= pnfssf->f_bsize;
 2919                         else
 2920                                 uquad *= fs->f_bsize;
 2921                         txdr_hyper(uquad, tl);
 2922                         retnum += NFSX_HYPER;
 2923                         break;
 2924                 case NFSATTRBIT_SPACEFREE:
 2925                         NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
 2926                         if (pnfssf != NULL) {
 2927                                 uquad = (u_int64_t)pnfssf->f_bfree;
 2928                                 uquad *= pnfssf->f_bsize;
 2929                         } else {
 2930                                 uquad = (u_int64_t)fs->f_bfree;
 2931                                 uquad *= fs->f_bsize;
 2932                         }
 2933                         txdr_hyper(uquad, tl);
 2934                         retnum += NFSX_HYPER;
 2935                         break;
 2936                 case NFSATTRBIT_SPACETOTAL:
 2937                         NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
 2938                         if (pnfssf != NULL) {
 2939                                 uquad = (u_int64_t)pnfssf->f_blocks;
 2940                                 uquad *= pnfssf->f_bsize;
 2941                         } else {
 2942                                 uquad = (u_int64_t)fs->f_blocks;
 2943                                 uquad *= fs->f_bsize;
 2944                         }
 2945                         txdr_hyper(uquad, tl);
 2946                         retnum += NFSX_HYPER;
 2947                         break;
 2948                 case NFSATTRBIT_SPACEUSED:
 2949                         NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
 2950                         txdr_hyper(vap->va_bytes, tl);
 2951                         retnum += NFSX_HYPER;
 2952                         break;
 2953                 case NFSATTRBIT_TIMEACCESS:
 2954                         NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
 2955                         txdr_nfsv4time(&vap->va_atime, tl);
 2956                         retnum += NFSX_V4TIME;
 2957                         break;
 2958                 case NFSATTRBIT_TIMEACCESSSET:
 2959                         if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
 2960                                 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
 2961                                 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
 2962                                 txdr_nfsv4time(&vap->va_atime, tl);
 2963                                 retnum += NFSX_V4SETTIME;
 2964                         } else {
 2965                                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 2966                                 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
 2967                                 retnum += NFSX_UNSIGNED;
 2968                         }
 2969                         break;
 2970                 case NFSATTRBIT_TIMEDELTA:
 2971                         NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
 2972                         temptime.tv_sec = 0;
 2973                         temptime.tv_nsec = 1000000000 / hz;
 2974                         txdr_nfsv4time(&temptime, tl);
 2975                         retnum += NFSX_V4TIME;
 2976                         break;
 2977                 case NFSATTRBIT_TIMEMETADATA:
 2978                         NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
 2979                         txdr_nfsv4time(&vap->va_ctime, tl);
 2980                         retnum += NFSX_V4TIME;
 2981                         break;
 2982                 case NFSATTRBIT_TIMEMODIFY:
 2983                         NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
 2984                         txdr_nfsv4time(&vap->va_mtime, tl);
 2985                         retnum += NFSX_V4TIME;
 2986                         break;
 2987                 case NFSATTRBIT_TIMECREATE:
 2988                         NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME);
 2989                         txdr_nfsv4time(&vap->va_birthtime, tl);
 2990                         retnum += NFSX_V4TIME;
 2991                         break;
 2992                 case NFSATTRBIT_TIMEMODIFYSET:
 2993                         if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) {
 2994                                 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME);
 2995                                 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT);
 2996                                 txdr_nfsv4time(&vap->va_mtime, tl);
 2997                                 retnum += NFSX_V4SETTIME;
 2998                         } else {
 2999                                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 3000                                 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER);
 3001                                 retnum += NFSX_UNSIGNED;
 3002                         }
 3003                         break;
 3004                 case NFSATTRBIT_MOUNTEDONFILEID:
 3005                         NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
 3006                         if (at_root != 0)
 3007                                 uquad = mounted_on_fileno;
 3008                         else
 3009                                 uquad = vap->va_fileid;
 3010                         txdr_hyper(uquad, tl);
 3011                         retnum += NFSX_HYPER;
 3012                         break;
 3013                 case NFSATTRBIT_SUPPATTREXCLCREAT:
 3014                         NFSSETSUPP_ATTRBIT(&attrbits, nd);
 3015                         NFSCLRNOTSETABLE_ATTRBIT(&attrbits, nd);
 3016                         NFSCLRBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET);
 3017                         retnum += nfsrv_putattrbit(nd, &attrbits);
 3018                         break;
 3019                 case NFSATTRBIT_FSLAYOUTTYPE:
 3020                 case NFSATTRBIT_LAYOUTTYPE:
 3021                         if (nfsrv_devidcnt == 0)
 3022                                 siz = 1;
 3023                         else
 3024                                 siz = 2;
 3025                         if (siz == 2) {
 3026                                 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
 3027                                 *tl++ = txdr_unsigned(1);       /* One entry. */
 3028                                 if (nfsrv_doflexfile != 0 ||
 3029                                     nfsrv_maxpnfsmirror > 1)
 3030                                         *tl = txdr_unsigned(NFSLAYOUT_FLEXFILE);
 3031                                 else
 3032                                         *tl = txdr_unsigned(
 3033                                             NFSLAYOUT_NFSV4_1_FILES);
 3034                         } else {
 3035                                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 3036                                 *tl = 0;
 3037                         }
 3038                         retnum += siz * NFSX_UNSIGNED;
 3039                         break;
 3040                 case NFSATTRBIT_LAYOUTALIGNMENT:
 3041                 case NFSATTRBIT_LAYOUTBLKSIZE:
 3042                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 3043                         *tl = txdr_unsigned(nfs_srvmaxio);
 3044                         retnum += NFSX_UNSIGNED;
 3045                         break;
 3046                 case NFSATTRBIT_XATTRSUPPORT:
 3047                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 3048                         if (xattrsupp)
 3049                                 *tl = newnfs_true;
 3050                         else
 3051                                 *tl = newnfs_false;
 3052                         retnum += NFSX_UNSIGNED;
 3053                         break;
 3054                 default:
 3055                         printf("EEK! Bad V4 attribute bitpos=%d\n", bitpos);
 3056                 }
 3057             }
 3058         }
 3059         if (naclp != NULL)
 3060                 acl_free(naclp);
 3061         free(fs, M_STATFS);
 3062         *retnump = txdr_unsigned(retnum);
 3063         return (retnum + prefixnum);
 3064 }
 3065 
 3066 /*
 3067  * Calculate the files available attribute value.
 3068  */
 3069 static uint32_t
 3070 nfsv4_filesavail(struct statfs *fs, struct mount *mp)
 3071 {
 3072         uint32_t freenum;
 3073 #ifdef QUOTA
 3074         struct dqblk dqb;
 3075         uid_t savuid;
 3076         NFSPROC_T *p;
 3077 #endif
 3078 
 3079         /*
 3080          * Check quota and use min(quota, f_ffree).
 3081          */
 3082         freenum = fs->f_ffree;
 3083 #ifdef QUOTA
 3084         /*
 3085          * This is old OpenBSD code that does not build
 3086          * for FreeBSD.  I do not know if doing this is
 3087          * useful, so I will just leave the code here.
 3088          */
 3089         p = curthread();
 3090         /*
 3091          * ufs_quotactl() insists that the uid argument
 3092          * equal p_ruid for non-root quota access, so
 3093          * we'll just make sure that's the case.
 3094          */
 3095         savuid = p->p_cred->p_ruid;
 3096         p->p_cred->p_ruid = cred->cr_uid;
 3097         if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA),
 3098             cred->cr_uid, &dqb))
 3099             freenum = min(dqb.dqb_isoftlimit-dqb.dqb_curinodes,
 3100                 freenum);
 3101         p->p_cred->p_ruid = savuid;
 3102 #endif  /* QUOTA */
 3103         return (freenum);
 3104 }
 3105 
 3106 /*
 3107  * Put the attribute bits onto an mbuf list.
 3108  * Return the number of bytes of output generated.
 3109  */
 3110 int
 3111 nfsrv_putattrbit(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp)
 3112 {
 3113         u_int32_t *tl;
 3114         int cnt, i, bytesize;
 3115 
 3116         for (cnt = NFSATTRBIT_MAXWORDS; cnt > 0; cnt--)
 3117                 if (attrbitp->bits[cnt - 1])
 3118                         break;
 3119         bytesize = (cnt + 1) * NFSX_UNSIGNED;
 3120         NFSM_BUILD(tl, u_int32_t *, bytesize);
 3121         *tl++ = txdr_unsigned(cnt);
 3122         for (i = 0; i < cnt; i++)
 3123                 *tl++ = txdr_unsigned(attrbitp->bits[i]);
 3124         return (bytesize);
 3125 }
 3126 
 3127 /*
 3128  * Convert a uid to a string.
 3129  * If the lookup fails, just output the digits.
 3130  * uid - the user id
 3131  * cpp - points to a buffer of size NFSV4_SMALLSTR
 3132  *       (malloc a larger one, as required)
 3133  * retlenp - pointer to length to be returned
 3134  */
 3135 void
 3136 nfsv4_uidtostr(uid_t uid, u_char **cpp, int *retlenp)
 3137 {
 3138         int i;
 3139         struct nfsusrgrp *usrp;
 3140         u_char *cp = *cpp;
 3141         uid_t tmp;
 3142         int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
 3143         struct nfsrv_lughash *hp;
 3144 
 3145         cnt = 0;
 3146 tryagain:
 3147         if (nfsrv_dnsnamelen > 0 && !nfs_enable_uidtostring) {
 3148                 /*
 3149                  * Always map nfsrv_defaultuid to "nobody".
 3150                  */
 3151                 if (uid == nfsrv_defaultuid) {
 3152                         i = nfsrv_dnsnamelen + 7;
 3153                         if (i > len) {
 3154                                 if (len > NFSV4_SMALLSTR)
 3155                                         free(cp, M_NFSSTRING);
 3156                                 cp = malloc(i, M_NFSSTRING, M_WAITOK);
 3157                                 *cpp = cp;
 3158                                 len = i;
 3159                                 goto tryagain;
 3160                         }
 3161                         *retlenp = i;
 3162                         NFSBCOPY("nobody@", cp, 7);
 3163                         cp += 7;
 3164                         NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
 3165                         return;
 3166                 }
 3167                 hasampersand = 0;
 3168                 hp = NFSUSERHASH(uid);
 3169                 mtx_lock(&hp->mtx);
 3170                 TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
 3171                         if (usrp->lug_uid == uid) {
 3172                                 if (usrp->lug_expiry < NFSD_MONOSEC)
 3173                                         break;
 3174                                 /*
 3175                                  * If the name doesn't already have an '@'
 3176                                  * in it, append @domainname to it.
 3177                                  */
 3178                                 for (i = 0; i < usrp->lug_namelen; i++) {
 3179                                         if (usrp->lug_name[i] == '@') {
 3180                                                 hasampersand = 1;
 3181                                                 break;
 3182                                         }
 3183                                 }
 3184                                 if (hasampersand)
 3185                                         i = usrp->lug_namelen;
 3186                                 else
 3187                                         i = usrp->lug_namelen +
 3188                                             nfsrv_dnsnamelen + 1;
 3189                                 if (i > len) {
 3190                                         mtx_unlock(&hp->mtx);
 3191                                         if (len > NFSV4_SMALLSTR)
 3192                                                 free(cp, M_NFSSTRING);
 3193                                         cp = malloc(i, M_NFSSTRING, M_WAITOK);
 3194                                         *cpp = cp;
 3195                                         len = i;
 3196                                         goto tryagain;
 3197                                 }
 3198                                 *retlenp = i;
 3199                                 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
 3200                                 if (!hasampersand) {
 3201                                         cp += usrp->lug_namelen;
 3202                                         *cp++ = '@';
 3203                                         NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
 3204                                 }
 3205                                 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
 3206                                 TAILQ_INSERT_TAIL(&hp->lughead, usrp,
 3207                                     lug_numhash);
 3208                                 mtx_unlock(&hp->mtx);
 3209                                 return;
 3210                         }
 3211                 }
 3212                 mtx_unlock(&hp->mtx);
 3213                 cnt++;
 3214                 ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0, NULL);
 3215                 if (ret == 0 && cnt < 2)
 3216                         goto tryagain;
 3217         }
 3218 
 3219         /*
 3220          * No match, just return a string of digits.
 3221          */
 3222         tmp = uid;
 3223         i = 0;
 3224         while (tmp || i == 0) {
 3225                 tmp /= 10;
 3226                 i++;
 3227         }
 3228         len = (i > len) ? len : i;
 3229         *retlenp = len;
 3230         cp += (len - 1);
 3231         tmp = uid;
 3232         for (i = 0; i < len; i++) {
 3233                 *cp-- = '' + (tmp % 10);
 3234                 tmp /= 10;
 3235         }
 3236         return;
 3237 }
 3238 
 3239 /*
 3240  * Get a credential for the uid with the server's group list.
 3241  * If none is found, just return the credential passed in after
 3242  * logging a warning message.
 3243  */
 3244 struct ucred *
 3245 nfsrv_getgrpscred(struct ucred *oldcred)
 3246 {
 3247         struct nfsusrgrp *usrp;
 3248         struct ucred *newcred;
 3249         int cnt, ret;
 3250         uid_t uid;
 3251         struct nfsrv_lughash *hp;
 3252 
 3253         cnt = 0;
 3254         uid = oldcred->cr_uid;
 3255 tryagain:
 3256         if (nfsrv_dnsnamelen > 0) {
 3257                 hp = NFSUSERHASH(uid);
 3258                 mtx_lock(&hp->mtx);
 3259                 TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
 3260                         if (usrp->lug_uid == uid) {
 3261                                 if (usrp->lug_expiry < NFSD_MONOSEC)
 3262                                         break;
 3263                                 if (usrp->lug_cred != NULL) {
 3264                                         newcred = crhold(usrp->lug_cred);
 3265                                         crfree(oldcred);
 3266                                 } else
 3267                                         newcred = oldcred;
 3268                                 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
 3269                                 TAILQ_INSERT_TAIL(&hp->lughead, usrp,
 3270                                     lug_numhash);
 3271                                 mtx_unlock(&hp->mtx);
 3272                                 return (newcred);
 3273                         }
 3274                 }
 3275                 mtx_unlock(&hp->mtx);
 3276                 cnt++;
 3277                 ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0, NULL);
 3278                 if (ret == 0 && cnt < 2)
 3279                         goto tryagain;
 3280         }
 3281         return (oldcred);
 3282 }
 3283 
 3284 /*
 3285  * Convert a string to a uid.
 3286  * If no conversion is possible return NFSERR_BADOWNER, otherwise
 3287  * return 0.
 3288  * If this is called from a client side mount using AUTH_SYS and the
 3289  * string is made up entirely of digits, just convert the string to
 3290  * a number.
 3291  */
 3292 int
 3293 nfsv4_strtouid(struct nfsrv_descript *nd, u_char *str, int len, uid_t *uidp)
 3294 {
 3295         int i;
 3296         char *cp, *endstr, *str0;
 3297         struct nfsusrgrp *usrp;
 3298         int cnt, ret;
 3299         int error = 0;
 3300         uid_t tuid;
 3301         struct nfsrv_lughash *hp, *hp2;
 3302 
 3303         if (len == 0) {
 3304                 error = NFSERR_BADOWNER;
 3305                 goto out;
 3306         }
 3307         /* If a string of digits and an AUTH_SYS mount, just convert it. */
 3308         str0 = str;
 3309         tuid = (uid_t)strtoul(str0, &endstr, 10);
 3310         if ((endstr - str0) == len) {
 3311                 /* A numeric string. */
 3312                 if ((nd->nd_flag & ND_KERBV) == 0 &&
 3313                     ((nd->nd_flag & ND_NFSCL) != 0 ||
 3314                       nfsd_enable_stringtouid != 0))
 3315                         *uidp = tuid;
 3316                 else
 3317                         error = NFSERR_BADOWNER;
 3318                 goto out;
 3319         }
 3320         /*
 3321          * Look for an '@'.
 3322          */
 3323         cp = strchr(str0, '@');
 3324         if (cp != NULL)
 3325                 i = (int)(cp++ - str0);
 3326         else
 3327                 i = len;
 3328 
 3329         cnt = 0;
 3330 tryagain:
 3331         if (nfsrv_dnsnamelen > 0) {
 3332                 /*
 3333                  * If an '@' is found and the domain name matches, search for
 3334                  * the name with dns stripped off.
 3335                  * Mixed case alpahbetics will match for the domain name, but
 3336                  * all upper case will not.
 3337                  */
 3338                 if (cnt == 0 && i < len && i > 0 &&
 3339                     (len - 1 - i) == nfsrv_dnsnamelen &&
 3340                     !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
 3341                         len -= (nfsrv_dnsnamelen + 1);
 3342                         *(cp - 1) = '\0';
 3343                 }
 3344 
 3345                 /*
 3346                  * Check for the special case of "nobody".
 3347                  */
 3348                 if (len == 6 && !NFSBCMP(str, "nobody", 6)) {
 3349                         *uidp = nfsrv_defaultuid;
 3350                         error = 0;
 3351                         goto out;
 3352                 }
 3353 
 3354                 hp = NFSUSERNAMEHASH(str, len);
 3355                 mtx_lock(&hp->mtx);
 3356                 TAILQ_FOREACH(usrp, &hp->lughead, lug_namehash) {
 3357                         if (usrp->lug_namelen == len &&
 3358                             !NFSBCMP(usrp->lug_name, str, len)) {
 3359                                 if (usrp->lug_expiry < NFSD_MONOSEC)
 3360                                         break;
 3361                                 hp2 = NFSUSERHASH(usrp->lug_uid);
 3362                                 mtx_lock(&hp2->mtx);
 3363                                 TAILQ_REMOVE(&hp2->lughead, usrp, lug_numhash);
 3364                                 TAILQ_INSERT_TAIL(&hp2->lughead, usrp,
 3365                                     lug_numhash);
 3366                                 *uidp = usrp->lug_uid;
 3367                                 mtx_unlock(&hp2->mtx);
 3368                                 mtx_unlock(&hp->mtx);
 3369                                 error = 0;
 3370                                 goto out;
 3371                         }
 3372                 }
 3373                 mtx_unlock(&hp->mtx);
 3374                 cnt++;
 3375                 ret = nfsrv_getuser(RPCNFSUSERD_GETUSER, (uid_t)0, (gid_t)0,
 3376                     str);
 3377                 if (ret == 0 && cnt < 2)
 3378                         goto tryagain;
 3379         }
 3380         error = NFSERR_BADOWNER;
 3381 
 3382 out:
 3383         NFSEXITCODE(error);
 3384         return (error);
 3385 }
 3386 
 3387 /*
 3388  * Convert a gid to a string.
 3389  * gid - the group id
 3390  * cpp - points to a buffer of size NFSV4_SMALLSTR
 3391  *       (malloc a larger one, as required)
 3392  * retlenp - pointer to length to be returned
 3393  */
 3394 void
 3395 nfsv4_gidtostr(gid_t gid, u_char **cpp, int *retlenp)
 3396 {
 3397         int i;
 3398         struct nfsusrgrp *usrp;
 3399         u_char *cp = *cpp;
 3400         gid_t tmp;
 3401         int cnt, hasampersand, len = NFSV4_SMALLSTR, ret;
 3402         struct nfsrv_lughash *hp;
 3403 
 3404         cnt = 0;
 3405 tryagain:
 3406         if (nfsrv_dnsnamelen > 0 && !nfs_enable_uidtostring) {
 3407                 /*
 3408                  * Always map nfsrv_defaultgid to "nogroup".
 3409                  */
 3410                 if (gid == nfsrv_defaultgid) {
 3411                         i = nfsrv_dnsnamelen + 8;
 3412                         if (i > len) {
 3413                                 if (len > NFSV4_SMALLSTR)
 3414                                         free(cp, M_NFSSTRING);
 3415                                 cp = malloc(i, M_NFSSTRING, M_WAITOK);
 3416                                 *cpp = cp;
 3417                                 len = i;
 3418                                 goto tryagain;
 3419                         }
 3420                         *retlenp = i;
 3421                         NFSBCOPY("nogroup@", cp, 8);
 3422                         cp += 8;
 3423                         NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
 3424                         return;
 3425                 }
 3426                 hasampersand = 0;
 3427                 hp = NFSGROUPHASH(gid);
 3428                 mtx_lock(&hp->mtx);
 3429                 TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) {
 3430                         if (usrp->lug_gid == gid) {
 3431                                 if (usrp->lug_expiry < NFSD_MONOSEC)
 3432                                         break;
 3433                                 /*
 3434                                  * If the name doesn't already have an '@'
 3435                                  * in it, append @domainname to it.
 3436                                  */
 3437                                 for (i = 0; i < usrp->lug_namelen; i++) {
 3438                                         if (usrp->lug_name[i] == '@') {
 3439                                                 hasampersand = 1;
 3440                                                 break;
 3441                                         }
 3442                                 }
 3443                                 if (hasampersand)
 3444                                         i = usrp->lug_namelen;
 3445                                 else
 3446                                         i = usrp->lug_namelen +
 3447                                             nfsrv_dnsnamelen + 1;
 3448                                 if (i > len) {
 3449                                         mtx_unlock(&hp->mtx);
 3450                                         if (len > NFSV4_SMALLSTR)
 3451                                                 free(cp, M_NFSSTRING);
 3452                                         cp = malloc(i, M_NFSSTRING, M_WAITOK);
 3453                                         *cpp = cp;
 3454                                         len = i;
 3455                                         goto tryagain;
 3456                                 }
 3457                                 *retlenp = i;
 3458                                 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen);
 3459                                 if (!hasampersand) {
 3460                                         cp += usrp->lug_namelen;
 3461                                         *cp++ = '@';
 3462                                         NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen);
 3463                                 }
 3464                                 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
 3465                                 TAILQ_INSERT_TAIL(&hp->lughead, usrp,
 3466                                     lug_numhash);
 3467                                 mtx_unlock(&hp->mtx);
 3468                                 return;
 3469                         }
 3470                 }
 3471                 mtx_unlock(&hp->mtx);
 3472                 cnt++;
 3473                 ret = nfsrv_getuser(RPCNFSUSERD_GETGID, (uid_t)0, gid, NULL);
 3474                 if (ret == 0 && cnt < 2)
 3475                         goto tryagain;
 3476         }
 3477 
 3478         /*
 3479          * No match, just return a string of digits.
 3480          */
 3481         tmp = gid;
 3482         i = 0;
 3483         while (tmp || i == 0) {
 3484                 tmp /= 10;
 3485                 i++;
 3486         }
 3487         len = (i > len) ? len : i;
 3488         *retlenp = len;
 3489         cp += (len - 1);
 3490         tmp = gid;
 3491         for (i = 0; i < len; i++) {
 3492                 *cp-- = '' + (tmp % 10);
 3493                 tmp /= 10;
 3494         }
 3495         return;
 3496 }
 3497 
 3498 /*
 3499  * Convert a string to a gid.
 3500  * If no conversion is possible return NFSERR_BADOWNER, otherwise
 3501  * return 0.
 3502  * If this is called from a client side mount using AUTH_SYS and the
 3503  * string is made up entirely of digits, just convert the string to
 3504  * a number.
 3505  */
 3506 int
 3507 nfsv4_strtogid(struct nfsrv_descript *nd, u_char *str, int len, gid_t *gidp)
 3508 {
 3509         int i;
 3510         char *cp, *endstr, *str0;
 3511         struct nfsusrgrp *usrp;
 3512         int cnt, ret;
 3513         int error = 0;
 3514         gid_t tgid;
 3515         struct nfsrv_lughash *hp, *hp2;
 3516 
 3517         if (len == 0) {
 3518                 error =  NFSERR_BADOWNER;
 3519                 goto out;
 3520         }
 3521         /* If a string of digits and an AUTH_SYS mount, just convert it. */
 3522         str0 = str;
 3523         tgid = (gid_t)strtoul(str0, &endstr, 10);
 3524         if ((endstr - str0) == len) {
 3525                 /* A numeric string. */
 3526                 if ((nd->nd_flag & ND_KERBV) == 0 &&
 3527                     ((nd->nd_flag & ND_NFSCL) != 0 ||
 3528                       nfsd_enable_stringtouid != 0))
 3529                         *gidp = tgid;
 3530                 else
 3531                         error = NFSERR_BADOWNER;
 3532                 goto out;
 3533         }
 3534         /*
 3535          * Look for an '@'.
 3536          */
 3537         cp = strchr(str0, '@');
 3538         if (cp != NULL)
 3539                 i = (int)(cp++ - str0);
 3540         else
 3541                 i = len;
 3542 
 3543         cnt = 0;
 3544 tryagain:
 3545         if (nfsrv_dnsnamelen > 0) {
 3546                 /*
 3547                  * If an '@' is found and the dns name matches, search for the
 3548                  * name with the dns stripped off.
 3549                  */
 3550                 if (cnt == 0 && i < len && i > 0 &&
 3551                     (len - 1 - i) == nfsrv_dnsnamelen &&
 3552                     !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) {
 3553                         len -= (nfsrv_dnsnamelen + 1);
 3554                         *(cp - 1) = '\0';
 3555                 }
 3556 
 3557                 /*
 3558                  * Check for the special case of "nogroup".
 3559                  */
 3560                 if (len == 7 && !NFSBCMP(str, "nogroup", 7)) {
 3561                         *gidp = nfsrv_defaultgid;
 3562                         error = 0;
 3563                         goto out;
 3564                 }
 3565 
 3566                 hp = NFSGROUPNAMEHASH(str, len);
 3567                 mtx_lock(&hp->mtx);
 3568                 TAILQ_FOREACH(usrp, &hp->lughead, lug_namehash) {
 3569                         if (usrp->lug_namelen == len &&
 3570                             !NFSBCMP(usrp->lug_name, str, len)) {
 3571                                 if (usrp->lug_expiry < NFSD_MONOSEC)
 3572                                         break;
 3573                                 hp2 = NFSGROUPHASH(usrp->lug_gid);
 3574                                 mtx_lock(&hp2->mtx);
 3575                                 TAILQ_REMOVE(&hp2->lughead, usrp, lug_numhash);
 3576                                 TAILQ_INSERT_TAIL(&hp2->lughead, usrp,
 3577                                     lug_numhash);
 3578                                 *gidp = usrp->lug_gid;
 3579                                 mtx_unlock(&hp2->mtx);
 3580                                 mtx_unlock(&hp->mtx);
 3581                                 error = 0;
 3582                                 goto out;
 3583                         }
 3584                 }
 3585                 mtx_unlock(&hp->mtx);
 3586                 cnt++;
 3587                 ret = nfsrv_getuser(RPCNFSUSERD_GETGROUP, (uid_t)0, (gid_t)0,
 3588                     str);
 3589                 if (ret == 0 && cnt < 2)
 3590                         goto tryagain;
 3591         }
 3592         error = NFSERR_BADOWNER;
 3593 
 3594 out:
 3595         NFSEXITCODE(error);
 3596         return (error);
 3597 }
 3598 
 3599 /*
 3600  * Cmp len chars, allowing mixed case in the first argument to match lower
 3601  * case in the second, but not if the first argument is all upper case.
 3602  * Return 0 for a match, 1 otherwise.
 3603  */
 3604 static int
 3605 nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len)
 3606 {
 3607         int i;
 3608         u_char tmp;
 3609         int fndlower = 0;
 3610 
 3611         for (i = 0; i < len; i++) {
 3612                 if (*cp >= 'A' && *cp <= 'Z') {
 3613                         tmp = *cp++ + ('a' - 'A');
 3614                 } else {
 3615                         tmp = *cp++;
 3616                         if (tmp >= 'a' && tmp <= 'z')
 3617                                 fndlower = 1;
 3618                 }
 3619                 if (tmp != *cp2++)
 3620                         return (1);
 3621         }
 3622         if (fndlower)
 3623                 return (0);
 3624         else
 3625                 return (1);
 3626 }
 3627 
 3628 /*
 3629  * Set the port for the nfsuserd.
 3630  */
 3631 int
 3632 nfsrv_nfsuserdport(struct nfsuserd_args *nargs, NFSPROC_T *p)
 3633 {
 3634         struct nfssockreq *rp;
 3635 #ifdef INET
 3636         struct sockaddr_in *ad;
 3637 #endif
 3638 #ifdef INET6
 3639         struct sockaddr_in6 *ad6;
 3640         const struct in6_addr in6loopback = IN6ADDR_LOOPBACK_INIT;
 3641 #endif
 3642         int error;
 3643 
 3644         NFSLOCKNAMEID();
 3645         if (nfsrv_nfsuserd != NOTRUNNING) {
 3646                 NFSUNLOCKNAMEID();
 3647                 error = EPERM;
 3648                 goto out;
 3649         }
 3650         nfsrv_nfsuserd = STARTSTOP;
 3651         /*
 3652          * Set up the socket record and connect.
 3653          * Set nr_client NULL before unlocking, just to ensure that no other
 3654          * process/thread/core will use a bogus old value.  This could only
 3655          * occur if the use of the nameid lock to protect nfsrv_nfsuserd is
 3656          * broken.
 3657          */
 3658         rp = &nfsrv_nfsuserdsock;
 3659         rp->nr_client = NULL;
 3660         NFSUNLOCKNAMEID();
 3661         rp->nr_sotype = SOCK_DGRAM;
 3662         rp->nr_soproto = IPPROTO_UDP;
 3663         rp->nr_lock = (NFSR_RESERVEDPORT | NFSR_LOCALHOST);
 3664         rp->nr_cred = NULL;
 3665         rp->nr_prog = RPCPROG_NFSUSERD;
 3666         error = 0;
 3667         switch (nargs->nuserd_family) {
 3668 #ifdef INET
 3669         case AF_INET:
 3670                 rp->nr_nam = malloc(sizeof(struct sockaddr_in), M_SONAME,
 3671                     M_WAITOK | M_ZERO);
 3672                 ad = (struct sockaddr_in *)rp->nr_nam;
 3673                 ad->sin_len = sizeof(struct sockaddr_in);
 3674                 ad->sin_family = AF_INET;
 3675                 ad->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
 3676                 ad->sin_port = nargs->nuserd_port;
 3677                 break;
 3678 #endif
 3679 #ifdef INET6
 3680         case AF_INET6:
 3681                 rp->nr_nam = malloc(sizeof(struct sockaddr_in6), M_SONAME,
 3682                     M_WAITOK | M_ZERO);
 3683                 ad6 = (struct sockaddr_in6 *)rp->nr_nam;
 3684                 ad6->sin6_len = sizeof(struct sockaddr_in6);
 3685                 ad6->sin6_family = AF_INET6;
 3686                 ad6->sin6_addr = in6loopback;
 3687                 ad6->sin6_port = nargs->nuserd_port;
 3688                 break;
 3689 #endif
 3690         default:
 3691                 error = ENXIO;
 3692         }
 3693         rp->nr_vers = RPCNFSUSERD_VERS;
 3694         if (error == 0)
 3695                 error = newnfs_connect(NULL, rp, NFSPROCCRED(p), p, 0, false,
 3696                     &rp->nr_client);
 3697         if (error == 0) {
 3698                 NFSLOCKNAMEID();
 3699                 nfsrv_nfsuserd = RUNNING;
 3700                 NFSUNLOCKNAMEID();
 3701         } else {
 3702                 free(rp->nr_nam, M_SONAME);
 3703                 NFSLOCKNAMEID();
 3704                 nfsrv_nfsuserd = NOTRUNNING;
 3705                 NFSUNLOCKNAMEID();
 3706         }
 3707 out:
 3708         NFSEXITCODE(error);
 3709         return (error);
 3710 }
 3711 
 3712 /*
 3713  * Delete the nfsuserd port.
 3714  */
 3715 void
 3716 nfsrv_nfsuserddelport(void)
 3717 {
 3718 
 3719         NFSLOCKNAMEID();
 3720         if (nfsrv_nfsuserd != RUNNING) {
 3721                 NFSUNLOCKNAMEID();
 3722                 return;
 3723         }
 3724         nfsrv_nfsuserd = STARTSTOP;
 3725         /* Wait for all upcalls to complete. */
 3726         while (nfsrv_userdupcalls > 0)
 3727                 msleep(&nfsrv_userdupcalls, NFSNAMEIDMUTEXPTR, PVFS,
 3728                     "nfsupcalls", 0);
 3729         NFSUNLOCKNAMEID();
 3730         newnfs_disconnect(NULL, &nfsrv_nfsuserdsock);
 3731         free(nfsrv_nfsuserdsock.nr_nam, M_SONAME);
 3732         NFSLOCKNAMEID();
 3733         nfsrv_nfsuserd = NOTRUNNING;
 3734         NFSUNLOCKNAMEID();
 3735 }
 3736 
 3737 /*
 3738  * Do upcalls to the nfsuserd, for cache misses of the owner/ownergroup
 3739  * name<-->id cache.
 3740  * Returns 0 upon success, non-zero otherwise.
 3741  */
 3742 static int
 3743 nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name)
 3744 {
 3745         u_int32_t *tl;
 3746         struct nfsrv_descript *nd;
 3747         int len;
 3748         struct nfsrv_descript nfsd;
 3749         struct ucred *cred;
 3750         int error;
 3751 
 3752         NFSLOCKNAMEID();
 3753         if (nfsrv_nfsuserd != RUNNING) {
 3754                 NFSUNLOCKNAMEID();
 3755                 error = EPERM;
 3756                 goto out;
 3757         }
 3758         /*
 3759          * Maintain a count of upcalls in progress, so that nfsrv_X()
 3760          * can wait until no upcalls are in progress.
 3761          */
 3762         nfsrv_userdupcalls++;
 3763         NFSUNLOCKNAMEID();
 3764         KASSERT(nfsrv_userdupcalls > 0,
 3765             ("nfsrv_getuser: non-positive upcalls"));
 3766         nd = &nfsd;
 3767         cred = newnfs_getcred();
 3768         nd->nd_flag = ND_GSSINITREPLY;
 3769         nfsrvd_rephead(nd);
 3770 
 3771         nd->nd_procnum = procnum;
 3772         if (procnum == RPCNFSUSERD_GETUID || procnum == RPCNFSUSERD_GETGID) {
 3773                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 3774                 if (procnum == RPCNFSUSERD_GETUID)
 3775                         *tl = txdr_unsigned(uid);
 3776                 else
 3777                         *tl = txdr_unsigned(gid);
 3778         } else {
 3779                 len = strlen(name);
 3780                 (void) nfsm_strtom(nd, name, len);
 3781         }
 3782         error = newnfs_request(nd, NULL, NULL, &nfsrv_nfsuserdsock, NULL, NULL,
 3783                 cred, RPCPROG_NFSUSERD, RPCNFSUSERD_VERS, NULL, 0, NULL, NULL);
 3784         NFSLOCKNAMEID();
 3785         if (--nfsrv_userdupcalls == 0 && nfsrv_nfsuserd == STARTSTOP)
 3786                 wakeup(&nfsrv_userdupcalls);
 3787         NFSUNLOCKNAMEID();
 3788         NFSFREECRED(cred);
 3789         if (!error) {
 3790                 m_freem(nd->nd_mrep);
 3791                 error = nd->nd_repstat;
 3792         }
 3793 out:
 3794         NFSEXITCODE(error);
 3795         return (error);
 3796 }
 3797 
 3798 /*
 3799  * This function is called from the nfssvc(2) system call, to update the
 3800  * kernel user/group name list(s) for the V4 owner and ownergroup attributes.
 3801  */
 3802 int
 3803 nfssvc_idname(struct nfsd_idargs *nidp)
 3804 {
 3805         struct nfsusrgrp *nusrp, *usrp, *newusrp;
 3806         struct nfsrv_lughash *hp_name, *hp_idnum, *thp;
 3807         int i, group_locked, groupname_locked, user_locked, username_locked;
 3808         int error = 0;
 3809         u_char *cp;
 3810         gid_t *grps;
 3811         struct ucred *cr;
 3812         static int onethread = 0;
 3813         static time_t lasttime = 0;
 3814 
 3815         if (nidp->nid_namelen <= 0 || nidp->nid_namelen > MAXHOSTNAMELEN) {
 3816                 error = EINVAL;
 3817                 goto out;
 3818         }
 3819         if (nidp->nid_flag & NFSID_INITIALIZE) {
 3820                 cp = malloc(nidp->nid_namelen + 1, M_NFSSTRING, M_WAITOK);
 3821                 error = copyin(nidp->nid_name, cp, nidp->nid_namelen);
 3822                 if (error != 0) {
 3823                         free(cp, M_NFSSTRING);
 3824                         goto out;
 3825                 }
 3826                 if (atomic_cmpset_acq_int(&nfsrv_dnsnamelen, 0, 0) == 0) {
 3827                         /*
 3828                          * Free up all the old stuff and reinitialize hash
 3829                          * lists.  All mutexes for both lists must be locked,
 3830                          * with the user/group name ones before the uid/gid
 3831                          * ones, to avoid a LOR.
 3832                          */
 3833                         for (i = 0; i < nfsrv_lughashsize; i++)
 3834                                 mtx_lock(&nfsusernamehash[i].mtx);
 3835                         for (i = 0; i < nfsrv_lughashsize; i++)
 3836                                 mtx_lock(&nfsuserhash[i].mtx);
 3837                         for (i = 0; i < nfsrv_lughashsize; i++)
 3838                                 TAILQ_FOREACH_SAFE(usrp,
 3839                                     &nfsuserhash[i].lughead, lug_numhash, nusrp)
 3840                                         nfsrv_removeuser(usrp, 1);
 3841                         for (i = 0; i < nfsrv_lughashsize; i++)
 3842                                 mtx_unlock(&nfsuserhash[i].mtx);
 3843                         for (i = 0; i < nfsrv_lughashsize; i++)
 3844                                 mtx_unlock(&nfsusernamehash[i].mtx);
 3845                         for (i = 0; i < nfsrv_lughashsize; i++)
 3846                                 mtx_lock(&nfsgroupnamehash[i].mtx);
 3847                         for (i = 0; i < nfsrv_lughashsize; i++)
 3848                                 mtx_lock(&nfsgrouphash[i].mtx);
 3849                         for (i = 0; i < nfsrv_lughashsize; i++)
 3850                                 TAILQ_FOREACH_SAFE(usrp,
 3851                                     &nfsgrouphash[i].lughead, lug_numhash,
 3852                                     nusrp)
 3853                                         nfsrv_removeuser(usrp, 0);
 3854                         for (i = 0; i < nfsrv_lughashsize; i++)
 3855                                 mtx_unlock(&nfsgrouphash[i].mtx);
 3856                         for (i = 0; i < nfsrv_lughashsize; i++)
 3857                                 mtx_unlock(&nfsgroupnamehash[i].mtx);
 3858                         free(nfsrv_dnsname, M_NFSSTRING);
 3859                         nfsrv_dnsname = NULL;
 3860                 }
 3861                 if (nfsuserhash == NULL) {
 3862                         /* Allocate the hash tables. */
 3863                         nfsuserhash = malloc(sizeof(struct nfsrv_lughash) *
 3864                             nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
 3865                             M_ZERO);
 3866                         for (i = 0; i < nfsrv_lughashsize; i++)
 3867                                 mtx_init(&nfsuserhash[i].mtx, "nfsuidhash",
 3868                                     NULL, MTX_DEF | MTX_DUPOK);
 3869                         nfsusernamehash = malloc(sizeof(struct nfsrv_lughash) *
 3870                             nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
 3871                             M_ZERO);
 3872                         for (i = 0; i < nfsrv_lughashsize; i++)
 3873                                 mtx_init(&nfsusernamehash[i].mtx,
 3874                                     "nfsusrhash", NULL, MTX_DEF |
 3875                                     MTX_DUPOK);
 3876                         nfsgrouphash = malloc(sizeof(struct nfsrv_lughash) *
 3877                             nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
 3878                             M_ZERO);
 3879                         for (i = 0; i < nfsrv_lughashsize; i++)
 3880                                 mtx_init(&nfsgrouphash[i].mtx, "nfsgidhash",
 3881                                     NULL, MTX_DEF | MTX_DUPOK);
 3882                         nfsgroupnamehash = malloc(sizeof(struct nfsrv_lughash) *
 3883                             nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK |
 3884                             M_ZERO);
 3885                         for (i = 0; i < nfsrv_lughashsize; i++)
 3886                             mtx_init(&nfsgroupnamehash[i].mtx,
 3887                             "nfsgrphash", NULL, MTX_DEF | MTX_DUPOK);
 3888                 }
 3889                 /* (Re)initialize the list heads. */
 3890                 for (i = 0; i < nfsrv_lughashsize; i++)
 3891                         TAILQ_INIT(&nfsuserhash[i].lughead);
 3892                 for (i = 0; i < nfsrv_lughashsize; i++)
 3893                         TAILQ_INIT(&nfsusernamehash[i].lughead);
 3894                 for (i = 0; i < nfsrv_lughashsize; i++)
 3895                         TAILQ_INIT(&nfsgrouphash[i].lughead);
 3896                 for (i = 0; i < nfsrv_lughashsize; i++)
 3897                         TAILQ_INIT(&nfsgroupnamehash[i].lughead);
 3898 
 3899                 /*
 3900                  * Put name in "DNS" string.
 3901                  */
 3902                 nfsrv_dnsname = cp;
 3903                 nfsrv_defaultuid = nidp->nid_uid;
 3904                 nfsrv_defaultgid = nidp->nid_gid;
 3905                 nfsrv_usercnt = 0;
 3906                 nfsrv_usermax = nidp->nid_usermax;
 3907                 atomic_store_rel_int(&nfsrv_dnsnamelen, nidp->nid_namelen);
 3908                 goto out;
 3909         }
 3910 
 3911         /*
 3912          * malloc the new one now, so any potential sleep occurs before
 3913          * manipulation of the lists.
 3914          */
 3915         newusrp = malloc(sizeof(struct nfsusrgrp) + nidp->nid_namelen,
 3916             M_NFSUSERGROUP, M_WAITOK | M_ZERO);
 3917         error = copyin(nidp->nid_name, newusrp->lug_name,
 3918             nidp->nid_namelen);
 3919         if (error == 0 && nidp->nid_ngroup > 0 &&
 3920             (nidp->nid_flag & NFSID_ADDUID) != 0) {
 3921                 grps = malloc(sizeof(gid_t) * nidp->nid_ngroup, M_TEMP,
 3922                     M_WAITOK);
 3923                 error = copyin(nidp->nid_grps, grps,
 3924                     sizeof(gid_t) * nidp->nid_ngroup);
 3925                 if (error == 0) {
 3926                         /*
 3927                          * Create a credential just like svc_getcred(),
 3928                          * but using the group list provided.
 3929                          */
 3930                         cr = crget();
 3931                         cr->cr_uid = cr->cr_ruid = cr->cr_svuid = nidp->nid_uid;
 3932                         crsetgroups(cr, nidp->nid_ngroup, grps);
 3933                         cr->cr_rgid = cr->cr_svgid = cr->cr_groups[0];
 3934                         cr->cr_prison = &prison0;
 3935                         prison_hold(cr->cr_prison);
 3936 #ifdef MAC
 3937                         mac_cred_associate_nfsd(cr);
 3938 #endif
 3939                         newusrp->lug_cred = cr;
 3940                 }
 3941                 free(grps, M_TEMP);
 3942         }
 3943         if (error) {
 3944                 free(newusrp, M_NFSUSERGROUP);
 3945                 goto out;
 3946         }
 3947         newusrp->lug_namelen = nidp->nid_namelen;
 3948 
 3949         /*
 3950          * The lock order is username[0]->[nfsrv_lughashsize - 1] followed
 3951          * by uid[0]->[nfsrv_lughashsize - 1], with the same for group.
 3952          * The flags user_locked, username_locked, group_locked and
 3953          * groupname_locked are set to indicate all of those hash lists are
 3954          * locked. hp_name != NULL  and hp_idnum != NULL indicates that
 3955          * the respective one mutex is locked.
 3956          */
 3957         user_locked = username_locked = group_locked = groupname_locked = 0;
 3958         hp_name = hp_idnum = NULL;
 3959 
 3960         /*
 3961          * Delete old entries, as required.
 3962          */
 3963         if (nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID)) {
 3964                 /* Must lock all username hash lists first, to avoid a LOR. */
 3965                 for (i = 0; i < nfsrv_lughashsize; i++)
 3966                         mtx_lock(&nfsusernamehash[i].mtx);
 3967                 username_locked = 1;
 3968                 hp_idnum = NFSUSERHASH(nidp->nid_uid);
 3969                 mtx_lock(&hp_idnum->mtx);
 3970                 TAILQ_FOREACH_SAFE(usrp, &hp_idnum->lughead, lug_numhash,
 3971                     nusrp) {
 3972                         if (usrp->lug_uid == nidp->nid_uid)
 3973                                 nfsrv_removeuser(usrp, 1);
 3974                 }
 3975         } else if (nidp->nid_flag & (NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) {
 3976                 hp_name = NFSUSERNAMEHASH(newusrp->lug_name,
 3977                     newusrp->lug_namelen);
 3978                 mtx_lock(&hp_name->mtx);
 3979                 TAILQ_FOREACH_SAFE(usrp, &hp_name->lughead, lug_namehash,
 3980                     nusrp) {
 3981                         if (usrp->lug_namelen == newusrp->lug_namelen &&
 3982                             !NFSBCMP(usrp->lug_name, newusrp->lug_name,
 3983                             usrp->lug_namelen)) {
 3984                                 thp = NFSUSERHASH(usrp->lug_uid);
 3985                                 mtx_lock(&thp->mtx);
 3986                                 nfsrv_removeuser(usrp, 1);
 3987                                 mtx_unlock(&thp->mtx);
 3988                         }
 3989                 }
 3990                 hp_idnum = NFSUSERHASH(nidp->nid_uid);
 3991                 mtx_lock(&hp_idnum->mtx);
 3992         } else if (nidp->nid_flag & (NFSID_DELGID | NFSID_ADDGID)) {
 3993                 /* Must lock all groupname hash lists first, to avoid a LOR. */
 3994                 for (i = 0; i < nfsrv_lughashsize; i++)
 3995                         mtx_lock(&nfsgroupnamehash[i].mtx);
 3996                 groupname_locked = 1;
 3997                 hp_idnum = NFSGROUPHASH(nidp->nid_gid);
 3998                 mtx_lock(&hp_idnum->mtx);
 3999                 TAILQ_FOREACH_SAFE(usrp, &hp_idnum->lughead, lug_numhash,
 4000                     nusrp) {
 4001                         if (usrp->lug_gid == nidp->nid_gid)
 4002                                 nfsrv_removeuser(usrp, 0);
 4003                 }
 4004         } else if (nidp->nid_flag & (NFSID_DELGROUPNAME | NFSID_ADDGROUPNAME)) {
 4005                 hp_name = NFSGROUPNAMEHASH(newusrp->lug_name,
 4006                     newusrp->lug_namelen);
 4007                 mtx_lock(&hp_name->mtx);
 4008                 TAILQ_FOREACH_SAFE(usrp, &hp_name->lughead, lug_namehash,
 4009                     nusrp) {
 4010                         if (usrp->lug_namelen == newusrp->lug_namelen &&
 4011                             !NFSBCMP(usrp->lug_name, newusrp->lug_name,
 4012                             usrp->lug_namelen)) {
 4013                                 thp = NFSGROUPHASH(usrp->lug_gid);
 4014                                 mtx_lock(&thp->mtx);
 4015                                 nfsrv_removeuser(usrp, 0);
 4016                                 mtx_unlock(&thp->mtx);
 4017                         }
 4018                 }
 4019                 hp_idnum = NFSGROUPHASH(nidp->nid_gid);
 4020                 mtx_lock(&hp_idnum->mtx);
 4021         }
 4022 
 4023         /*
 4024          * Now, we can add the new one.
 4025          */
 4026         if (nidp->nid_usertimeout)
 4027                 newusrp->lug_expiry = NFSD_MONOSEC + nidp->nid_usertimeout;
 4028         else
 4029                 newusrp->lug_expiry = NFSD_MONOSEC + 5;
 4030         if (nidp->nid_flag & (NFSID_ADDUID | NFSID_ADDUSERNAME)) {
 4031                 newusrp->lug_uid = nidp->nid_uid;
 4032                 thp = NFSUSERHASH(newusrp->lug_uid);
 4033                 mtx_assert(&thp->mtx, MA_OWNED);
 4034                 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_numhash);
 4035                 thp = NFSUSERNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
 4036                 mtx_assert(&thp->mtx, MA_OWNED);
 4037                 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_namehash);
 4038                 atomic_add_int(&nfsrv_usercnt, 1);
 4039         } else if (nidp->nid_flag & (NFSID_ADDGID | NFSID_ADDGROUPNAME)) {
 4040                 newusrp->lug_gid = nidp->nid_gid;
 4041                 thp = NFSGROUPHASH(newusrp->lug_gid);
 4042                 mtx_assert(&thp->mtx, MA_OWNED);
 4043                 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_numhash);
 4044                 thp = NFSGROUPNAMEHASH(newusrp->lug_name, newusrp->lug_namelen);
 4045                 mtx_assert(&thp->mtx, MA_OWNED);
 4046                 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_namehash);
 4047                 atomic_add_int(&nfsrv_usercnt, 1);
 4048         } else {
 4049                 if (newusrp->lug_cred != NULL)
 4050                         crfree(newusrp->lug_cred);
 4051                 free(newusrp, M_NFSUSERGROUP);
 4052         }
 4053 
 4054         /*
 4055          * Once per second, allow one thread to trim the cache.
 4056          */
 4057         if (lasttime < NFSD_MONOSEC &&
 4058             atomic_cmpset_acq_int(&onethread, 0, 1) != 0) {
 4059                 /*
 4060                  * First, unlock the single mutexes, so that all entries
 4061                  * can be locked and any LOR is avoided.
 4062                  */
 4063                 if (hp_name != NULL) {
 4064                         mtx_unlock(&hp_name->mtx);
 4065                         hp_name = NULL;
 4066                 }
 4067                 if (hp_idnum != NULL) {
 4068                         mtx_unlock(&hp_idnum->mtx);
 4069                         hp_idnum = NULL;
 4070                 }
 4071 
 4072                 if ((nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID |
 4073                     NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) != 0) {
 4074                         if (username_locked == 0) {
 4075                                 for (i = 0; i < nfsrv_lughashsize; i++)
 4076                                         mtx_lock(&nfsusernamehash[i].mtx);
 4077                                 username_locked = 1;
 4078                         }
 4079                         KASSERT(user_locked == 0,
 4080                             ("nfssvc_idname: user_locked"));
 4081                         for (i = 0; i < nfsrv_lughashsize; i++)
 4082                                 mtx_lock(&nfsuserhash[i].mtx);
 4083                         user_locked = 1;
 4084                         for (i = 0; i < nfsrv_lughashsize; i++) {
 4085                                 TAILQ_FOREACH_SAFE(usrp,
 4086                                     &nfsuserhash[i].lughead, lug_numhash,
 4087                                     nusrp)
 4088                                         if (usrp->lug_expiry < NFSD_MONOSEC)
 4089                                                 nfsrv_removeuser(usrp, 1);
 4090                         }
 4091                         for (i = 0; i < nfsrv_lughashsize; i++) {
 4092                                 /*
 4093                                  * Trim the cache using an approximate LRU
 4094                                  * algorithm.  This code deletes the least
 4095                                  * recently used entry on each hash list.
 4096                                  */
 4097                                 if (nfsrv_usercnt <= nfsrv_usermax)
 4098                                         break;
 4099                                 usrp = TAILQ_FIRST(&nfsuserhash[i].lughead);
 4100                                 if (usrp != NULL)
 4101                                         nfsrv_removeuser(usrp, 1);
 4102                         }
 4103                 } else {
 4104                         if (groupname_locked == 0) {
 4105                                 for (i = 0; i < nfsrv_lughashsize; i++)
 4106                                         mtx_lock(&nfsgroupnamehash[i].mtx);
 4107                                 groupname_locked = 1;
 4108                         }
 4109                         KASSERT(group_locked == 0,
 4110                             ("nfssvc_idname: group_locked"));
 4111                         for (i = 0; i < nfsrv_lughashsize; i++)
 4112                                 mtx_lock(&nfsgrouphash[i].mtx);
 4113                         group_locked = 1;
 4114                         for (i = 0; i < nfsrv_lughashsize; i++) {
 4115                                 TAILQ_FOREACH_SAFE(usrp,
 4116                                     &nfsgrouphash[i].lughead, lug_numhash,
 4117                                     nusrp)
 4118                                         if (usrp->lug_expiry < NFSD_MONOSEC)
 4119                                                 nfsrv_removeuser(usrp, 0);
 4120                         }
 4121                         for (i = 0; i < nfsrv_lughashsize; i++) {
 4122                                 /*
 4123                                  * Trim the cache using an approximate LRU
 4124                                  * algorithm.  This code deletes the least
 4125                                  * recently user entry on each hash list.
 4126                                  */
 4127                                 if (nfsrv_usercnt <= nfsrv_usermax)
 4128                                         break;
 4129                                 usrp = TAILQ_FIRST(&nfsgrouphash[i].lughead);
 4130                                 if (usrp != NULL)
 4131                                         nfsrv_removeuser(usrp, 0);
 4132                         }
 4133                 }
 4134                 lasttime = NFSD_MONOSEC;
 4135                 atomic_store_rel_int(&onethread, 0);
 4136         }
 4137 
 4138         /* Now, unlock all locked mutexes. */
 4139         if (hp_idnum != NULL)
 4140                 mtx_unlock(&hp_idnum->mtx);
 4141         if (hp_name != NULL)
 4142                 mtx_unlock(&hp_name->mtx);
 4143         if (user_locked != 0)
 4144                 for (i = 0; i < nfsrv_lughashsize; i++)
 4145                         mtx_unlock(&nfsuserhash[i].mtx);
 4146         if (username_locked != 0)
 4147                 for (i = 0; i < nfsrv_lughashsize; i++)
 4148                         mtx_unlock(&nfsusernamehash[i].mtx);
 4149         if (group_locked != 0)
 4150                 for (i = 0; i < nfsrv_lughashsize; i++)
 4151                         mtx_unlock(&nfsgrouphash[i].mtx);
 4152         if (groupname_locked != 0)
 4153                 for (i = 0; i < nfsrv_lughashsize; i++)
 4154                         mtx_unlock(&nfsgroupnamehash[i].mtx);
 4155 out:
 4156         NFSEXITCODE(error);
 4157         return (error);
 4158 }
 4159 
 4160 /*
 4161  * Remove a user/group name element.
 4162  */
 4163 static void
 4164 nfsrv_removeuser(struct nfsusrgrp *usrp, int isuser)
 4165 {
 4166         struct nfsrv_lughash *hp;
 4167 
 4168         if (isuser != 0) {
 4169                 hp = NFSUSERHASH(usrp->lug_uid);
 4170                 mtx_assert(&hp->mtx, MA_OWNED);
 4171                 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
 4172                 hp = NFSUSERNAMEHASH(usrp->lug_name, usrp->lug_namelen);
 4173                 mtx_assert(&hp->mtx, MA_OWNED);
 4174                 TAILQ_REMOVE(&hp->lughead, usrp, lug_namehash);
 4175         } else {
 4176                 hp = NFSGROUPHASH(usrp->lug_gid);
 4177                 mtx_assert(&hp->mtx, MA_OWNED);
 4178                 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
 4179                 hp = NFSGROUPNAMEHASH(usrp->lug_name, usrp->lug_namelen);
 4180                 mtx_assert(&hp->mtx, MA_OWNED);
 4181                 TAILQ_REMOVE(&hp->lughead, usrp, lug_namehash);
 4182         }
 4183         atomic_add_int(&nfsrv_usercnt, -1);
 4184         if (usrp->lug_cred != NULL)
 4185                 crfree(usrp->lug_cred);
 4186         free(usrp, M_NFSUSERGROUP);
 4187 }
 4188 
 4189 /*
 4190  * Free up all the allocations related to the name<-->id cache.
 4191  * This function should only be called when the nfsuserd daemon isn't
 4192  * running, since it doesn't do any locking.
 4193  * This function is meant to be used when the nfscommon module is unloaded.
 4194  */
 4195 void
 4196 nfsrv_cleanusergroup(void)
 4197 {
 4198         struct nfsrv_lughash *hp, *hp2;
 4199         struct nfsusrgrp *nusrp, *usrp;
 4200         int i;
 4201 
 4202         if (nfsuserhash == NULL)
 4203                 return;
 4204 
 4205         for (i = 0; i < nfsrv_lughashsize; i++) {
 4206                 hp = &nfsuserhash[i];
 4207                 TAILQ_FOREACH_SAFE(usrp, &hp->lughead, lug_numhash, nusrp) {
 4208                         TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
 4209                         hp2 = NFSUSERNAMEHASH(usrp->lug_name,
 4210                             usrp->lug_namelen);
 4211                         TAILQ_REMOVE(&hp2->lughead, usrp, lug_namehash);
 4212                         if (usrp->lug_cred != NULL)
 4213                                 crfree(usrp->lug_cred);
 4214                         free(usrp, M_NFSUSERGROUP);
 4215                 }
 4216                 hp = &nfsgrouphash[i];
 4217                 TAILQ_FOREACH_SAFE(usrp, &hp->lughead, lug_numhash, nusrp) {
 4218                         TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash);
 4219                         hp2 = NFSGROUPNAMEHASH(usrp->lug_name,
 4220                             usrp->lug_namelen);
 4221                         TAILQ_REMOVE(&hp2->lughead, usrp, lug_namehash);
 4222                         if (usrp->lug_cred != NULL)
 4223                                 crfree(usrp->lug_cred);
 4224                         free(usrp, M_NFSUSERGROUP);
 4225                 }
 4226                 mtx_destroy(&nfsuserhash[i].mtx);
 4227                 mtx_destroy(&nfsusernamehash[i].mtx);
 4228                 mtx_destroy(&nfsgroupnamehash[i].mtx);
 4229                 mtx_destroy(&nfsgrouphash[i].mtx);
 4230         }
 4231         free(nfsuserhash, M_NFSUSERGROUP);
 4232         free(nfsusernamehash, M_NFSUSERGROUP);
 4233         free(nfsgrouphash, M_NFSUSERGROUP);
 4234         free(nfsgroupnamehash, M_NFSUSERGROUP);
 4235         free(nfsrv_dnsname, M_NFSSTRING);
 4236 }
 4237 
 4238 /*
 4239  * This function scans a byte string and checks for UTF-8 compliance.
 4240  * It returns 0 if it conforms and NFSERR_INVAL if not.
 4241  */
 4242 int
 4243 nfsrv_checkutf8(u_int8_t *cp, int len)
 4244 {
 4245         u_int32_t val = 0x0;
 4246         int cnt = 0, gotd = 0, shift = 0;
 4247         u_int8_t byte;
 4248         static int utf8_shift[5] = { 7, 11, 16, 21, 26 };
 4249         int error = 0;
 4250 
 4251         /*
 4252          * Here are what the variables are used for:
 4253          * val - the calculated value of a multibyte char, used to check
 4254          *       that it was coded with the correct range
 4255          * cnt - the number of 10xxxxxx bytes to follow
 4256          * gotd - set for a char of Dxxx, so D800<->DFFF can be checked for
 4257          * shift - lower order bits of range (ie. "val >> shift" should
 4258          *       not be 0, in other words, dividing by the lower bound
 4259          *       of the range should get a non-zero value)
 4260          * byte - used to calculate cnt
 4261          */
 4262         while (len > 0) {
 4263                 if (cnt > 0) {
 4264                         /* This handles the 10xxxxxx bytes */
 4265                         if ((*cp & 0xc0) != 0x80 ||
 4266                             (gotd && (*cp & 0x20))) {
 4267                                 error = NFSERR_INVAL;
 4268                                 goto out;
 4269                         }
 4270                         gotd = 0;
 4271                         val <<= 6;
 4272                         val |= (*cp & 0x3f);
 4273                         cnt--;
 4274                         if (cnt == 0 && (val >> shift) == 0x0) {
 4275                                 error = NFSERR_INVAL;
 4276                                 goto out;
 4277                         }
 4278                 } else if (*cp & 0x80) {
 4279                         /* first byte of multi byte char */
 4280                         byte = *cp;
 4281                         while ((byte & 0x40) && cnt < 6) {
 4282                                 cnt++;
 4283                                 byte <<= 1;
 4284                         }
 4285                         if (cnt == 0 || cnt == 6) {
 4286                                 error = NFSERR_INVAL;
 4287                                 goto out;
 4288                         }
 4289                         val = (*cp & (0x3f >> cnt));
 4290                         shift = utf8_shift[cnt - 1];
 4291                         if (cnt == 2 && val == 0xd)
 4292                                 /* Check for the 0xd800-0xdfff case */
 4293                                 gotd = 1;
 4294                 }
 4295                 cp++;
 4296                 len--;
 4297         }
 4298         if (cnt > 0)
 4299                 error = NFSERR_INVAL;
 4300 
 4301 out:
 4302         NFSEXITCODE(error);
 4303         return (error);
 4304 }
 4305 
 4306 /*
 4307  * Parse the xdr for an NFSv4 FsLocations attribute. Return two malloc'd
 4308  * strings, one with the root path in it and the other with the list of
 4309  * locations. The list is in the same format as is found in nfr_refs.
 4310  * It is a "," separated list of entries, where each of them is of the
 4311  * form <server>:<rootpath>. For example
 4312  * "nfsv4-test:/sub2,nfsv4-test2:/user/mnt,nfsv4-test2:/user/mnt2"
 4313  * The nilp argument is set to 1 for the special case of a null fs_root
 4314  * and an empty server list.
 4315  * It returns NFSERR_BADXDR, if the xdr can't be parsed and returns the
 4316  * number of xdr bytes parsed in sump.
 4317  */
 4318 static int
 4319 nfsrv_getrefstr(struct nfsrv_descript *nd, u_char **fsrootp, u_char **srvp,
 4320     int *sump, int *nilp)
 4321 {
 4322         u_int32_t *tl;
 4323         u_char *cp = NULL, *cp2 = NULL, *cp3, *str;
 4324         int i, j, len, stringlen, cnt, slen, siz, xdrsum, error = 0, nsrv;
 4325         struct list {
 4326                 SLIST_ENTRY(list) next;
 4327                 int len;
 4328                 u_char host[1];
 4329         } *lsp, *nlsp;
 4330         SLIST_HEAD(, list) head;
 4331 
 4332         *fsrootp = NULL;
 4333         *srvp = NULL;
 4334         *nilp = 0;
 4335 
 4336         /*
 4337          * Get the fs_root path and check for the special case of null path
 4338          * and 0 length server list.
 4339          */
 4340         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 4341         len = fxdr_unsigned(int, *tl);
 4342         if (len < 0 || len > 10240) {
 4343                 error = NFSERR_BADXDR;
 4344                 goto nfsmout;
 4345         }
 4346         if (len == 0) {
 4347                 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 4348                 if (*tl != 0) {
 4349                         error = NFSERR_BADXDR;
 4350                         goto nfsmout;
 4351                 }
 4352                 *nilp = 1;
 4353                 *sump = 2 * NFSX_UNSIGNED;
 4354                 error = 0;
 4355                 goto nfsmout;
 4356         }
 4357         cp = malloc(len + 1, M_NFSSTRING, M_WAITOK);
 4358         error = nfsrv_mtostr(nd, cp, len);
 4359         if (!error) {
 4360                 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 4361                 cnt = fxdr_unsigned(int, *tl);
 4362                 if (cnt <= 0)
 4363                         error = NFSERR_BADXDR;
 4364         }
 4365         if (error)
 4366                 goto nfsmout;
 4367 
 4368         /*
 4369          * Now, loop through the location list and make up the srvlist.
 4370          */
 4371         xdrsum = (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
 4372         cp2 = cp3 = malloc(1024, M_NFSSTRING, M_WAITOK);
 4373         slen = 1024;
 4374         siz = 0;
 4375         for (i = 0; i < cnt; i++) {
 4376                 SLIST_INIT(&head);
 4377                 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 4378                 nsrv = fxdr_unsigned(int, *tl);
 4379                 if (nsrv <= 0) {
 4380                         error = NFSERR_BADXDR;
 4381                         goto nfsmout;
 4382                 }
 4383 
 4384                 /*
 4385                  * Handle the first server by putting it in the srvstr.
 4386                  */
 4387                 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 4388                 len = fxdr_unsigned(int, *tl);
 4389                 if (len <= 0 || len > 1024) {
 4390                         error = NFSERR_BADXDR;
 4391                         goto nfsmout;
 4392                 }
 4393                 nfsrv_refstrbigenough(siz + len + 3, &cp2, &cp3, &slen);
 4394                 if (cp3 != cp2) {
 4395                         *cp3++ = ',';
 4396                         siz++;
 4397                 }
 4398                 error = nfsrv_mtostr(nd, cp3, len);
 4399                 if (error)
 4400                         goto nfsmout;
 4401                 cp3 += len;
 4402                 *cp3++ = ':';
 4403                 siz += (len + 1);
 4404                 xdrsum += (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len);
 4405                 for (j = 1; j < nsrv; j++) {
 4406                         /*
 4407                          * Yuck, put them in an slist and process them later.
 4408                          */
 4409                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 4410                         len = fxdr_unsigned(int, *tl);
 4411                         if (len <= 0 || len > 1024) {
 4412                                 error = NFSERR_BADXDR;
 4413                                 goto nfsmout;
 4414                         }
 4415                         lsp = (struct list *)malloc(sizeof (struct list)
 4416                             + len, M_TEMP, M_WAITOK);
 4417                         error = nfsrv_mtostr(nd, lsp->host, len);
 4418                         if (error)
 4419                                 goto nfsmout;
 4420                         xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
 4421                         lsp->len = len;
 4422                         SLIST_INSERT_HEAD(&head, lsp, next);
 4423                 }
 4424 
 4425                 /*
 4426                  * Finally, we can get the path.
 4427                  */
 4428                 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 4429                 len = fxdr_unsigned(int, *tl);
 4430                 if (len <= 0 || len > 1024) {
 4431                         error = NFSERR_BADXDR;
 4432                         goto nfsmout;
 4433                 }
 4434                 nfsrv_refstrbigenough(siz + len + 1, &cp2, &cp3, &slen);
 4435                 error = nfsrv_mtostr(nd, cp3, len);
 4436                 if (error)
 4437                         goto nfsmout;
 4438                 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len);
 4439                 str = cp3;
 4440                 stringlen = len;
 4441                 cp3 += len;
 4442                 siz += len;
 4443                 SLIST_FOREACH_SAFE(lsp, &head, next, nlsp) {
 4444                         nfsrv_refstrbigenough(siz + lsp->len + stringlen + 3,
 4445                             &cp2, &cp3, &slen);
 4446                         *cp3++ = ',';
 4447                         NFSBCOPY(lsp->host, cp3, lsp->len);
 4448                         cp3 += lsp->len;
 4449                         *cp3++ = ':';
 4450                         NFSBCOPY(str, cp3, stringlen);
 4451                         cp3 += stringlen;
 4452                         *cp3 = '\0';
 4453                         siz += (lsp->len + stringlen + 2);
 4454                         free(lsp, M_TEMP);
 4455                 }
 4456         }
 4457         *fsrootp = cp;
 4458         *srvp = cp2;
 4459         *sump = xdrsum;
 4460         NFSEXITCODE2(0, nd);
 4461         return (0);
 4462 nfsmout:
 4463         if (cp != NULL)
 4464                 free(cp, M_NFSSTRING);
 4465         if (cp2 != NULL)
 4466                 free(cp2, M_NFSSTRING);
 4467         NFSEXITCODE2(error, nd);
 4468         return (error);
 4469 }
 4470 
 4471 /*
 4472  * Make the malloc'd space large enough. This is a pain, but the xdr
 4473  * doesn't set an upper bound on the side, so...
 4474  */
 4475 static void
 4476 nfsrv_refstrbigenough(int siz, u_char **cpp, u_char **cpp2, int *slenp)
 4477 {
 4478         u_char *cp;
 4479         int i;
 4480 
 4481         if (siz <= *slenp)
 4482                 return;
 4483         cp = malloc(siz + 1024, M_NFSSTRING, M_WAITOK);
 4484         NFSBCOPY(*cpp, cp, *slenp);
 4485         free(*cpp, M_NFSSTRING);
 4486         i = *cpp2 - *cpp;
 4487         *cpp = cp;
 4488         *cpp2 = cp + i;
 4489         *slenp = siz + 1024;
 4490 }
 4491 
 4492 /*
 4493  * Initialize the reply header data structures.
 4494  */
 4495 void
 4496 nfsrvd_rephead(struct nfsrv_descript *nd)
 4497 {
 4498         struct mbuf *mreq;
 4499 
 4500         if ((nd->nd_flag & ND_EXTPG) != 0) {
 4501                 mreq = mb_alloc_ext_plus_pages(PAGE_SIZE, M_WAITOK);
 4502                 nd->nd_mreq = nd->nd_mb = mreq;
 4503                 nd->nd_bpos = (char *)(void *)
 4504                     PHYS_TO_DMAP(mreq->m_epg_pa[0]);
 4505                 nd->nd_bextpg = 0;
 4506                 nd->nd_bextpgsiz = PAGE_SIZE;
 4507         } else {
 4508                 /*
 4509                  * If this is a big reply, use a cluster.
 4510                  */
 4511                 if ((nd->nd_flag & ND_GSSINITREPLY) == 0 &&
 4512                     nfs_bigreply[nd->nd_procnum]) {
 4513                         NFSMCLGET(mreq, M_WAITOK);
 4514                         nd->nd_mreq = mreq;
 4515                         nd->nd_mb = mreq;
 4516                 } else {
 4517                         NFSMGET(mreq);
 4518                         nd->nd_mreq = mreq;
 4519                         nd->nd_mb = mreq;
 4520                 }
 4521                 nd->nd_bpos = mtod(mreq, char *);
 4522                 mreq->m_len = 0;
 4523         }
 4524 
 4525         if ((nd->nd_flag & ND_GSSINITREPLY) == 0)
 4526                 NFSM_BUILD(nd->nd_errp, int *, NFSX_UNSIGNED);
 4527 }
 4528 
 4529 /*
 4530  * Lock a socket against others.
 4531  * Currently used to serialize connect/disconnect attempts.
 4532  */
 4533 int
 4534 newnfs_sndlock(int *flagp)
 4535 {
 4536         struct timespec ts;
 4537 
 4538         NFSLOCKSOCK();
 4539         while (*flagp & NFSR_SNDLOCK) {
 4540                 *flagp |= NFSR_WANTSND;
 4541                 ts.tv_sec = 0;
 4542                 ts.tv_nsec = 0;
 4543                 (void) nfsmsleep((caddr_t)flagp, NFSSOCKMUTEXPTR,
 4544                     PZERO - 1, "nfsndlck", &ts);
 4545         }
 4546         *flagp |= NFSR_SNDLOCK;
 4547         NFSUNLOCKSOCK();
 4548         return (0);
 4549 }
 4550 
 4551 /*
 4552  * Unlock the stream socket for others.
 4553  */
 4554 void
 4555 newnfs_sndunlock(int *flagp)
 4556 {
 4557 
 4558         NFSLOCKSOCK();
 4559         if ((*flagp & NFSR_SNDLOCK) == 0)
 4560                 panic("nfs sndunlock");
 4561         *flagp &= ~NFSR_SNDLOCK;
 4562         if (*flagp & NFSR_WANTSND) {
 4563                 *flagp &= ~NFSR_WANTSND;
 4564                 wakeup((caddr_t)flagp);
 4565         }
 4566         NFSUNLOCKSOCK();
 4567 }
 4568 
 4569 int
 4570 nfsv4_getipaddr(struct nfsrv_descript *nd, struct sockaddr_in *sin,
 4571     struct sockaddr_in6 *sin6, sa_family_t *saf, int *isudp)
 4572 {
 4573         struct in_addr saddr;
 4574         uint32_t portnum, *tl;
 4575         int i, j, k;
 4576         sa_family_t af = AF_UNSPEC;
 4577         char addr[64], protocol[5], *cp;
 4578         int cantparse = 0, error = 0;
 4579         uint16_t portv;
 4580 
 4581         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 4582         i = fxdr_unsigned(int, *tl);
 4583         if (i >= 3 && i <= 4) {
 4584                 error = nfsrv_mtostr(nd, protocol, i);
 4585                 if (error)
 4586                         goto nfsmout;
 4587                 if (strcmp(protocol, "tcp") == 0) {
 4588                         af = AF_INET;
 4589                         *isudp = 0;
 4590                 } else if (strcmp(protocol, "udp") == 0) {
 4591                         af = AF_INET;
 4592                         *isudp = 1;
 4593                 } else if (strcmp(protocol, "tcp6") == 0) {
 4594                         af = AF_INET6;
 4595                         *isudp = 0;
 4596                 } else if (strcmp(protocol, "udp6") == 0) {
 4597                         af = AF_INET6;
 4598                         *isudp = 1;
 4599                 } else
 4600                         cantparse = 1;
 4601         } else {
 4602                 cantparse = 1;
 4603                 if (i > 0) {
 4604                         error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
 4605                         if (error)
 4606                                 goto nfsmout;
 4607                 }
 4608         }
 4609         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 4610         i = fxdr_unsigned(int, *tl);
 4611         if (i < 0) {
 4612                 error = NFSERR_BADXDR;
 4613                 goto nfsmout;
 4614         } else if (cantparse == 0 && i >= 11 && i < 64) {
 4615                 /*
 4616                  * The shortest address is 11chars and the longest is < 64.
 4617                  */
 4618                 error = nfsrv_mtostr(nd, addr, i);
 4619                 if (error)
 4620                         goto nfsmout;
 4621 
 4622                 /* Find the port# at the end and extract that. */
 4623                 i = strlen(addr);
 4624                 k = 0;
 4625                 cp = &addr[i - 1];
 4626                 /* Count back two '.'s from end to get port# field. */
 4627                 for (j = 0; j < i; j++) {
 4628                         if (*cp == '.') {
 4629                                 k++;
 4630                                 if (k == 2)
 4631                                         break;
 4632                         }
 4633                         cp--;
 4634                 }
 4635                 if (k == 2) {
 4636                         /*
 4637                          * The NFSv4 port# is appended as .N.N, where N is
 4638                          * a decimal # in the range 0-255, just like an inet4
 4639                          * address. Cheat and use inet_aton(), which will
 4640                          * return a Class A address and then shift the high
 4641                          * order 8bits over to convert it to the port#.
 4642                          */
 4643                         *cp++ = '\0';
 4644                         if (inet_aton(cp, &saddr) == 1) {
 4645                                 portnum = ntohl(saddr.s_addr);
 4646                                 portv = (uint16_t)((portnum >> 16) |
 4647                                     (portnum & 0xff));
 4648                         } else
 4649                                 cantparse = 1;
 4650                 } else
 4651                         cantparse = 1;
 4652                 if (cantparse == 0) {
 4653                         if (af == AF_INET) {
 4654                                 if (inet_pton(af, addr, &sin->sin_addr) == 1) {
 4655                                         sin->sin_len = sizeof(*sin);
 4656                                         sin->sin_family = AF_INET;
 4657                                         sin->sin_port = htons(portv);
 4658                                         *saf = af;
 4659                                         return (0);
 4660                                 }
 4661                         } else {
 4662                                 if (inet_pton(af, addr, &sin6->sin6_addr)
 4663                                     == 1) {
 4664                                         sin6->sin6_len = sizeof(*sin6);
 4665                                         sin6->sin6_family = AF_INET6;
 4666                                         sin6->sin6_port = htons(portv);
 4667                                         *saf = af;
 4668                                         return (0);
 4669                                 }
 4670                         }
 4671                 }
 4672         } else {
 4673                 if (i > 0) {
 4674                         error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
 4675                         if (error)
 4676                                 goto nfsmout;
 4677                 }
 4678         }
 4679         error = EPERM;
 4680 nfsmout:
 4681         return (error);
 4682 }
 4683 
 4684 /*
 4685  * Handle an NFSv4.1 Sequence request for the session.
 4686  * If reply != NULL, use it to return the cached reply, as required.
 4687  * The client gets a cached reply via this call for callbacks, however the
 4688  * server gets a cached reply via the nfsv4_seqsess_cacherep() call.
 4689  */
 4690 int
 4691 nfsv4_seqsession(uint32_t seqid, uint32_t slotid, uint32_t highslot,
 4692     struct nfsslot *slots, struct mbuf **reply, uint16_t maxslot)
 4693 {
 4694         struct mbuf *m;
 4695         int error;
 4696 
 4697         error = 0;
 4698         if (reply != NULL)
 4699                 *reply = NULL;
 4700         if (slotid > maxslot)
 4701                 return (NFSERR_BADSLOT);
 4702         if (seqid == slots[slotid].nfssl_seq) {
 4703                 /* A retry. */
 4704                 if (slots[slotid].nfssl_inprog != 0)
 4705                         error = NFSERR_DELAY;
 4706                 else if (slots[slotid].nfssl_reply != NULL) {
 4707                         if (reply != NULL) {
 4708                                 m = m_copym(slots[slotid].nfssl_reply, 0,
 4709                                     M_COPYALL, M_NOWAIT);
 4710                                 if (m != NULL)
 4711                                         *reply = m;
 4712                                 else {
 4713                                         *reply = slots[slotid].nfssl_reply;
 4714                                         slots[slotid].nfssl_reply = NULL;
 4715                                 }
 4716                         }
 4717                         slots[slotid].nfssl_inprog = 1;
 4718                         error = NFSERR_REPLYFROMCACHE;
 4719                 } else
 4720                         /* No reply cached, so just do it. */
 4721                         slots[slotid].nfssl_inprog = 1;
 4722         } else if ((slots[slotid].nfssl_seq + 1) == seqid) {
 4723                 if (slots[slotid].nfssl_reply != NULL)
 4724                         m_freem(slots[slotid].nfssl_reply);
 4725                 slots[slotid].nfssl_reply = NULL;
 4726                 slots[slotid].nfssl_inprog = 1;
 4727                 slots[slotid].nfssl_seq++;
 4728         } else
 4729                 error = NFSERR_SEQMISORDERED;
 4730         return (error);
 4731 }
 4732 
 4733 /*
 4734  * Cache this reply for the slot.
 4735  * Use the "rep" argument to return the cached reply if repstat is set to
 4736  * NFSERR_REPLYFROMCACHE. The client never sets repstat to this value.
 4737  */
 4738 void
 4739 nfsv4_seqsess_cacherep(uint32_t slotid, struct nfsslot *slots, int repstat,
 4740    struct mbuf **rep)
 4741 {
 4742         struct mbuf *m;
 4743 
 4744         if (repstat == NFSERR_REPLYFROMCACHE) {
 4745                 if (slots[slotid].nfssl_reply != NULL) {
 4746                         /*
 4747                          * We cannot sleep here, but copy will usually
 4748                          * succeed.
 4749                          */
 4750                         m = m_copym(slots[slotid].nfssl_reply, 0, M_COPYALL,
 4751                             M_NOWAIT);
 4752                         if (m != NULL)
 4753                                 *rep = m;
 4754                         else {
 4755                                 /*
 4756                                  * Multiple retries would be extremely rare,
 4757                                  * so using the cached reply will likely
 4758                                  * be ok.
 4759                                  */
 4760                                 *rep = slots[slotid].nfssl_reply;
 4761                                 slots[slotid].nfssl_reply = NULL;
 4762                         }
 4763                 } else
 4764                         *rep = NULL;
 4765         } else {
 4766                 if (slots[slotid].nfssl_reply != NULL)
 4767                         m_freem(slots[slotid].nfssl_reply);
 4768                 slots[slotid].nfssl_reply = *rep;
 4769         }
 4770         slots[slotid].nfssl_inprog = 0;
 4771 }
 4772 
 4773 /*
 4774  * Generate the xdr for an NFSv4.1 Sequence Operation.
 4775  */
 4776 void
 4777 nfsv4_setsequence(struct nfsmount *nmp, struct nfsrv_descript *nd,
 4778     struct nfsclsession *sep, int dont_replycache, struct ucred *cred)
 4779 {
 4780         uint32_t *tl, slotseq = 0;
 4781         int error, maxslot, slotpos;
 4782         uint8_t sessionid[NFSX_V4SESSIONID];
 4783 
 4784         if (cred != NULL) {
 4785                 error = nfsv4_sequencelookup(nmp, sep, &slotpos, &maxslot,
 4786                     &slotseq, sessionid, false);
 4787                 if (error == NFSERR_SEQMISORDERED) {
 4788                         /* If all slots are bad, Destroy the session. */
 4789                         nfsrpc_destroysession(nmp, sep, cred, curthread);
 4790                 }
 4791         } else
 4792                 error = nfsv4_sequencelookup(nmp, sep, &slotpos, &maxslot,
 4793                     &slotseq, sessionid, true);
 4794         nd->nd_maxreq = sep->nfsess_maxreq;
 4795         nd->nd_maxresp = sep->nfsess_maxresp;
 4796 
 4797         /* Build the Sequence arguments. */
 4798         NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID + 4 * NFSX_UNSIGNED);
 4799         nd->nd_sequence = tl;
 4800         bcopy(sessionid, tl, NFSX_V4SESSIONID);
 4801         tl += NFSX_V4SESSIONID / NFSX_UNSIGNED;
 4802         nd->nd_slotseq = tl;
 4803         if (error == 0) {
 4804                 nd->nd_flag |= ND_HASSLOTID;
 4805                 nd->nd_slotid = slotpos;
 4806                 *tl++ = txdr_unsigned(slotseq);
 4807                 *tl++ = txdr_unsigned(slotpos);
 4808                 *tl++ = txdr_unsigned(maxslot);
 4809                 if (dont_replycache == 0)
 4810                         *tl = newnfs_true;
 4811                 else
 4812                         *tl = newnfs_false;
 4813         } else {
 4814                 /*
 4815                  * There are two errors and the rest of the session can
 4816                  * just be zeros.
 4817                  * NFSERR_BADSESSION: This bad session should just generate
 4818                  *    the same error again when the RPC is retried.
 4819                  * ESTALE: A forced dismount is in progress and will cause the
 4820                  *    RPC to fail later.
 4821                  */
 4822                 *tl++ = 0;
 4823                 *tl++ = 0;
 4824                 *tl++ = 0;
 4825                 *tl = 0;
 4826         }
 4827         nd->nd_flag |= ND_HASSEQUENCE;
 4828 }
 4829 
 4830 /*
 4831  * If fnd_init is true, ignore the badslots.
 4832  * If fnd_init is false, return NFSERR_SEQMISORDERED if all slots are bad.
 4833  */
 4834 int
 4835 nfsv4_sequencelookup(struct nfsmount *nmp, struct nfsclsession *sep,
 4836     int *slotposp, int *maxslotp, uint32_t *slotseqp, uint8_t *sessionid,
 4837     bool fnd_init)
 4838 {
 4839         int i, maxslot, slotpos;
 4840         uint64_t bitval;
 4841         bool fnd_ok;
 4842 
 4843         /* Find an unused slot. */
 4844         slotpos = -1;
 4845         maxslot = -1;
 4846         mtx_lock(&sep->nfsess_mtx);
 4847         do {
 4848                 if (nmp != NULL && sep->nfsess_defunct != 0) {
 4849                         /* Just return the bad session. */
 4850                         bcopy(sep->nfsess_sessionid, sessionid,
 4851                             NFSX_V4SESSIONID);
 4852                         mtx_unlock(&sep->nfsess_mtx);
 4853                         return (NFSERR_BADSESSION);
 4854                 }
 4855                 fnd_ok = fnd_init;
 4856                 bitval = 1;
 4857                 for (i = 0; i < sep->nfsess_foreslots; i++) {
 4858                         if ((bitval & sep->nfsess_badslots) == 0 || fnd_init) {
 4859                                 fnd_ok = true;
 4860                                 if ((bitval & sep->nfsess_slots) == 0) {
 4861                                         slotpos = i;
 4862                                         sep->nfsess_slots |= bitval;
 4863                                         sep->nfsess_slotseq[i]++;
 4864                                         *slotseqp = sep->nfsess_slotseq[i];
 4865                                         break;
 4866                                 }
 4867                         }
 4868                         bitval <<= 1;
 4869                 }
 4870                 if (slotpos == -1) {
 4871                         /*
 4872                          * If a forced dismount is in progress, just return.
 4873                          * This RPC attempt will fail when it calls
 4874                          * newnfs_request().
 4875                          */
 4876                         if (nmp != NULL && NFSCL_FORCEDISM(nmp->nm_mountp)) {
 4877                                 mtx_unlock(&sep->nfsess_mtx);
 4878                                 return (ESTALE);
 4879                         }
 4880                         /* Wake up once/sec, to check for a forced dismount. */
 4881                         if (fnd_ok)
 4882                                 mtx_sleep(&sep->nfsess_slots, &sep->nfsess_mtx,
 4883                                     PZERO, "nfsclseq", hz);
 4884                 }
 4885         } while (slotpos == -1 && fnd_ok);
 4886         /*
 4887          * If all slots are bad, just return slot 0 and NFSERR_SEQMISORDERED.
 4888          * The caller will do a DestroySession, so that the session's use
 4889          * will get a NFSERR_BADSESSION reply from the server.
 4890          */
 4891         if (!fnd_ok)
 4892                 slotpos = 0;
 4893 
 4894         /* Now, find the highest slot in use. (nfsc_slots is 64bits) */
 4895         bitval = 1;
 4896         for (i = 0; i < 64; i++) {
 4897                 if ((bitval & sep->nfsess_slots) != 0)
 4898                         maxslot = i;
 4899                 bitval <<= 1;
 4900         }
 4901         bcopy(sep->nfsess_sessionid, sessionid, NFSX_V4SESSIONID);
 4902         mtx_unlock(&sep->nfsess_mtx);
 4903         *slotposp = slotpos;
 4904         *maxslotp = maxslot;
 4905 
 4906         if (!fnd_ok)
 4907                 return (NFSERR_SEQMISORDERED);
 4908         return (0);
 4909 }
 4910 
 4911 /*
 4912  * Free a session slot.
 4913  */
 4914 void
 4915 nfsv4_freeslot(struct nfsclsession *sep, int slot, bool resetseq)
 4916 {
 4917         uint64_t bitval;
 4918 
 4919         bitval = 1;
 4920         if (slot > 0)
 4921                 bitval <<= slot;
 4922         mtx_lock(&sep->nfsess_mtx);
 4923         if (resetseq)
 4924                 sep->nfsess_slotseq[slot]--;
 4925         if ((bitval & sep->nfsess_slots) == 0)
 4926                 printf("freeing free slot!!\n");
 4927         sep->nfsess_slots &= ~bitval;
 4928         wakeup(&sep->nfsess_slots);
 4929         mtx_unlock(&sep->nfsess_mtx);
 4930 }
 4931 
 4932 /*
 4933  * Search for a matching pnfsd DS, based on the nmp arg.
 4934  * Return one if found, NULL otherwise.
 4935  */
 4936 struct nfsdevice *
 4937 nfsv4_findmirror(struct nfsmount *nmp)
 4938 {
 4939         struct nfsdevice *ds;
 4940 
 4941         mtx_assert(NFSDDSMUTEXPTR, MA_OWNED);
 4942         /*
 4943          * Search the DS server list for a match with nmp.
 4944          */
 4945         if (nfsrv_devidcnt == 0)
 4946                 return (NULL);
 4947         TAILQ_FOREACH(ds, &nfsrv_devidhead, nfsdev_list) {
 4948                 if (ds->nfsdev_nmp == nmp) {
 4949                         NFSCL_DEBUG(4, "nfsv4_findmirror: fnd main ds\n");
 4950                         break;
 4951                 }
 4952         }
 4953         return (ds);
 4954 }
 4955 
 4956 /*
 4957  * Fill in the fields of "struct nfsrv_descript".
 4958  */
 4959 void
 4960 nfsm_set(struct nfsrv_descript *nd, u_int offs)
 4961 {
 4962         struct mbuf *m;
 4963         int rlen;
 4964 
 4965         m = nd->nd_mb;
 4966         if ((m->m_flags & M_EXTPG) != 0) {
 4967                 nd->nd_bextpg = 0;
 4968                 while (offs > 0) {
 4969                         if (nd->nd_bextpg == 0)
 4970                                 rlen = m_epg_pagelen(m, 0, m->m_epg_1st_off);
 4971                         else
 4972                                 rlen = m_epg_pagelen(m, nd->nd_bextpg, 0);
 4973                         if (offs <= rlen)
 4974                                 break;
 4975                         offs -= rlen;
 4976                         nd->nd_bextpg++;
 4977                         if (nd->nd_bextpg == m->m_epg_npgs) {
 4978                                 printf("nfsm_set: build offs "
 4979                                     "out of range\n");
 4980                                 nd->nd_bextpg--;
 4981                                 break;
 4982                         }
 4983                 }
 4984                 nd->nd_bpos = (char *)(void *)
 4985                     PHYS_TO_DMAP(m->m_epg_pa[nd->nd_bextpg]);
 4986                 if (nd->nd_bextpg == 0)
 4987                         nd->nd_bpos += m->m_epg_1st_off;
 4988                 if (offs > 0) {
 4989                         nd->nd_bpos += offs;
 4990                         nd->nd_bextpgsiz = rlen - offs;
 4991                 } else if (nd->nd_bextpg == 0)
 4992                         nd->nd_bextpgsiz = PAGE_SIZE - m->m_epg_1st_off;
 4993                 else
 4994                         nd->nd_bextpgsiz = PAGE_SIZE;
 4995         } else
 4996                 nd->nd_bpos = mtod(m, char *) + offs;
 4997 }
 4998 
 4999 /*
 5000  * Grow a ext_pgs mbuf list.  Either allocate another page or add
 5001  * an mbuf to the list.
 5002  */
 5003 struct mbuf *
 5004 nfsm_add_ext_pgs(struct mbuf *m, int maxextsiz, int *bextpg)
 5005 {
 5006         struct mbuf *mp;
 5007         vm_page_t pg;
 5008 
 5009         if ((m->m_epg_npgs + 1) * PAGE_SIZE > maxextsiz) {
 5010                 mp = mb_alloc_ext_plus_pages(PAGE_SIZE, M_WAITOK);
 5011                 *bextpg = 0;
 5012                 m->m_next = mp;
 5013         } else {
 5014                 pg = vm_page_alloc_noobj(VM_ALLOC_WAITOK | VM_ALLOC_NODUMP |
 5015                     VM_ALLOC_WIRED);
 5016                 m->m_epg_pa[m->m_epg_npgs] = VM_PAGE_TO_PHYS(pg);
 5017                 *bextpg = m->m_epg_npgs;
 5018                 m->m_epg_npgs++;
 5019                 m->m_epg_last_len = 0;
 5020                 mp = m;
 5021         }
 5022         return (mp);
 5023 }
 5024 
 5025 /*
 5026  * Do the NFSv4.1 Destroy Session.
 5027  */
 5028 int
 5029 nfsrpc_destroysession(struct nfsmount *nmp, struct nfsclsession *tsep,
 5030     struct ucred *cred, NFSPROC_T *p)
 5031 {
 5032         uint32_t *tl;
 5033         struct nfsrv_descript nfsd;
 5034         struct nfsrv_descript *nd = &nfsd;
 5035         int error;
 5036 
 5037         nfscl_reqstart(nd, NFSPROC_DESTROYSESSION, nmp, NULL, 0, NULL, NULL, 0,
 5038             0, NULL);
 5039         NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID);
 5040         if (tsep == NULL)
 5041                 tsep = nfsmnt_mdssession(nmp);
 5042         bcopy(tsep->nfsess_sessionid, tl, NFSX_V4SESSIONID);
 5043         nd->nd_flag |= ND_USEGSSNAME;
 5044         error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
 5045             NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
 5046         if (error != 0)
 5047                 return (error);
 5048         error = nd->nd_repstat;
 5049         m_freem(nd->nd_mrep);
 5050         return (error);
 5051 }

Cache object: 7c5e442064ee9a44e1cfa1a879abdea4


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


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