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/nfsserver/nfs_nfsdport.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  * Copyright (c) 1989, 1993
    3  *      The Regents of the University of California.  All rights reserved.
    4  *
    5  * This code is derived from software contributed to Berkeley by
    6  * Rick Macklem at The University of Guelph.
    7  *
    8  * Redistribution and use in source and binary forms, with or without
    9  * modification, are permitted provided that the following conditions
   10  * are met:
   11  * 1. Redistributions of source code must retain the above copyright
   12  *    notice, this list of conditions and the following disclaimer.
   13  * 2. Redistributions in binary form must reproduce the above copyright
   14  *    notice, this list of conditions and the following disclaimer in the
   15  *    documentation and/or other materials provided with the distribution.
   16  * 4. Neither the name of the University nor the names of its contributors
   17  *    may be used to endorse or promote products derived from this software
   18  *    without specific prior written permission.
   19  *
   20  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   30  * SUCH DAMAGE.
   31  *
   32  */
   33 
   34 #include <sys/cdefs.h>
   35 __FBSDID("$FreeBSD$");
   36 
   37 #include <sys/capsicum.h>
   38 
   39 /*
   40  * Functions that perform the vfs operations required by the routines in
   41  * nfsd_serv.c. It is hoped that this change will make the server more
   42  * portable.
   43  */
   44 
   45 #include <fs/nfs/nfsport.h>
   46 #include <sys/hash.h>
   47 #include <sys/sysctl.h>
   48 #include <nlm/nlm_prot.h>
   49 #include <nlm/nlm.h>
   50 
   51 FEATURE(nfsd, "NFSv4 server");
   52 
   53 extern u_int32_t newnfs_true, newnfs_false, newnfs_xdrneg1;
   54 extern int nfsrv_useacl;
   55 extern int newnfs_numnfsd;
   56 extern struct mount nfsv4root_mnt;
   57 extern struct nfsrv_stablefirst nfsrv_stablefirst;
   58 extern void (*nfsd_call_servertimer)(void);
   59 extern SVCPOOL  *nfsrvd_pool;
   60 extern struct nfsv4lock nfsd_suspend_lock;
   61 extern struct nfsclienthashhead *nfsclienthash;
   62 extern struct nfslockhashhead *nfslockhash;
   63 extern struct nfssessionhash *nfssessionhash;
   64 extern int nfsrv_sessionhashsize;
   65 extern struct nfsstatsv1 nfsstatsv1;
   66 struct vfsoptlist nfsv4root_opt, nfsv4root_newopt;
   67 NFSDLOCKMUTEX;
   68 struct nfsrchash_bucket nfsrchash_table[NFSRVCACHE_HASHSIZE];
   69 struct nfsrchash_bucket nfsrcahash_table[NFSRVCACHE_HASHSIZE];
   70 struct mtx nfsrc_udpmtx;
   71 struct mtx nfs_v4root_mutex;
   72 struct nfsrvfh nfs_rootfh, nfs_pubfh;
   73 int nfs_pubfhset = 0, nfs_rootfhset = 0;
   74 struct proc *nfsd_master_proc = NULL;
   75 int nfsd_debuglevel = 0;
   76 static pid_t nfsd_master_pid = (pid_t)-1;
   77 static char nfsd_master_comm[MAXCOMLEN + 1];
   78 static struct timeval nfsd_master_start;
   79 static uint32_t nfsv4_sysid = 0;
   80 
   81 static int nfssvc_srvcall(struct thread *, struct nfssvc_args *,
   82     struct ucred *);
   83 
   84 int nfsrv_enable_crossmntpt = 1;
   85 static int nfs_commit_blks;
   86 static int nfs_commit_miss;
   87 extern int nfsrv_issuedelegs;
   88 extern int nfsrv_dolocallocks;
   89 extern int nfsd_enable_stringtouid;
   90 
   91 SYSCTL_NODE(_vfs, OID_AUTO, nfsd, CTLFLAG_RW, 0, "NFS server");
   92 SYSCTL_INT(_vfs_nfsd, OID_AUTO, mirrormnt, CTLFLAG_RW,
   93     &nfsrv_enable_crossmntpt, 0, "Enable nfsd to cross mount points");
   94 SYSCTL_INT(_vfs_nfsd, OID_AUTO, commit_blks, CTLFLAG_RW, &nfs_commit_blks,
   95     0, "");
   96 SYSCTL_INT(_vfs_nfsd, OID_AUTO, commit_miss, CTLFLAG_RW, &nfs_commit_miss,
   97     0, "");
   98 SYSCTL_INT(_vfs_nfsd, OID_AUTO, issue_delegations, CTLFLAG_RW,
   99     &nfsrv_issuedelegs, 0, "Enable nfsd to issue delegations");
  100 SYSCTL_INT(_vfs_nfsd, OID_AUTO, enable_locallocks, CTLFLAG_RW,
  101     &nfsrv_dolocallocks, 0, "Enable nfsd to acquire local locks on files");
  102 SYSCTL_INT(_vfs_nfsd, OID_AUTO, debuglevel, CTLFLAG_RW, &nfsd_debuglevel,
  103     0, "Debug level for NFS server");
  104 SYSCTL_INT(_vfs_nfsd, OID_AUTO, enable_stringtouid, CTLFLAG_RW,
  105     &nfsd_enable_stringtouid, 0, "Enable nfsd to accept numeric owner_names");
  106 
  107 #define MAX_REORDERED_RPC       16
  108 #define NUM_HEURISTIC           1031
  109 #define NHUSE_INIT              64
  110 #define NHUSE_INC               16
  111 #define NHUSE_MAX               2048
  112 
  113 static struct nfsheur {
  114         struct vnode *nh_vp;    /* vp to match (unreferenced pointer) */
  115         off_t nh_nextoff;       /* next offset for sequential detection */
  116         int nh_use;             /* use count for selection */
  117         int nh_seqcount;        /* heuristic */
  118 } nfsheur[NUM_HEURISTIC];
  119 
  120 
  121 /*
  122  * Heuristic to detect sequential operation.
  123  */
  124 static struct nfsheur *
  125 nfsrv_sequential_heuristic(struct uio *uio, struct vnode *vp)
  126 {
  127         struct nfsheur *nh;
  128         int hi, try;
  129 
  130         /* Locate best candidate. */
  131         try = 32;
  132         hi = ((int)(vm_offset_t)vp / sizeof(struct vnode)) % NUM_HEURISTIC;
  133         nh = &nfsheur[hi];
  134         while (try--) {
  135                 if (nfsheur[hi].nh_vp == vp) {
  136                         nh = &nfsheur[hi];
  137                         break;
  138                 }
  139                 if (nfsheur[hi].nh_use > 0)
  140                         --nfsheur[hi].nh_use;
  141                 hi = (hi + 1) % NUM_HEURISTIC;
  142                 if (nfsheur[hi].nh_use < nh->nh_use)
  143                         nh = &nfsheur[hi];
  144         }
  145 
  146         /* Initialize hint if this is a new file. */
  147         if (nh->nh_vp != vp) {
  148                 nh->nh_vp = vp;
  149                 nh->nh_nextoff = uio->uio_offset;
  150                 nh->nh_use = NHUSE_INIT;
  151                 if (uio->uio_offset == 0)
  152                         nh->nh_seqcount = 4;
  153                 else
  154                         nh->nh_seqcount = 1;
  155         }
  156 
  157         /* Calculate heuristic. */
  158         if ((uio->uio_offset == 0 && nh->nh_seqcount > 0) ||
  159             uio->uio_offset == nh->nh_nextoff) {
  160                 /* See comments in vfs_vnops.c:sequential_heuristic(). */
  161                 nh->nh_seqcount += howmany(uio->uio_resid, 16384);
  162                 if (nh->nh_seqcount > IO_SEQMAX)
  163                         nh->nh_seqcount = IO_SEQMAX;
  164         } else if (qabs(uio->uio_offset - nh->nh_nextoff) <= MAX_REORDERED_RPC *
  165             imax(vp->v_mount->mnt_stat.f_iosize, uio->uio_resid)) {
  166                 /* Probably a reordered RPC, leave seqcount alone. */
  167         } else if (nh->nh_seqcount > 1) {
  168                 nh->nh_seqcount /= 2;
  169         } else {
  170                 nh->nh_seqcount = 0;
  171         }
  172         nh->nh_use += NHUSE_INC;
  173         if (nh->nh_use > NHUSE_MAX)
  174                 nh->nh_use = NHUSE_MAX;
  175         return (nh);
  176 }
  177 
  178 /*
  179  * Get attributes into nfsvattr structure.
  180  */
  181 int
  182 nfsvno_getattr(struct vnode *vp, struct nfsvattr *nvap, struct ucred *cred,
  183     struct thread *p, int vpislocked)
  184 {
  185         int error, lockedit = 0;
  186 
  187         if (vpislocked == 0) {
  188                 /*
  189                  * When vpislocked == 0, the vnode is either exclusively
  190                  * locked by this thread or not locked by this thread.
  191                  * As such, shared lock it, if not exclusively locked.
  192                  */
  193                 if (NFSVOPISLOCKED(vp) != LK_EXCLUSIVE) {
  194                         lockedit = 1;
  195                         NFSVOPLOCK(vp, LK_SHARED | LK_RETRY);
  196                 }
  197         }
  198         error = VOP_GETATTR(vp, &nvap->na_vattr, cred);
  199         if (lockedit != 0)
  200                 NFSVOPUNLOCK(vp, 0);
  201 
  202         NFSEXITCODE(error);
  203         return (error);
  204 }
  205 
  206 /*
  207  * Get a file handle for a vnode.
  208  */
  209 int
  210 nfsvno_getfh(struct vnode *vp, fhandle_t *fhp, struct thread *p)
  211 {
  212         int error;
  213 
  214         NFSBZERO((caddr_t)fhp, sizeof(fhandle_t));
  215         fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid;
  216         error = VOP_VPTOFH(vp, &fhp->fh_fid);
  217 
  218         NFSEXITCODE(error);
  219         return (error);
  220 }
  221 
  222 /*
  223  * Perform access checking for vnodes obtained from file handles that would
  224  * refer to files already opened by a Unix client. You cannot just use
  225  * vn_writechk() and VOP_ACCESSX() for two reasons.
  226  * 1 - You must check for exported rdonly as well as MNT_RDONLY for the write
  227  *     case.
  228  * 2 - The owner is to be given access irrespective of mode bits for some
  229  *     operations, so that processes that chmod after opening a file don't
  230  *     break.
  231  */
  232 int
  233 nfsvno_accchk(struct vnode *vp, accmode_t accmode, struct ucred *cred,
  234     struct nfsexstuff *exp, struct thread *p, int override, int vpislocked,
  235     u_int32_t *supportedtypep)
  236 {
  237         struct vattr vattr;
  238         int error = 0, getret = 0;
  239 
  240         if (vpislocked == 0) {
  241                 if (NFSVOPLOCK(vp, LK_SHARED) != 0) {
  242                         error = EPERM;
  243                         goto out;
  244                 }
  245         }
  246         if (accmode & VWRITE) {
  247                 /* Just vn_writechk() changed to check rdonly */
  248                 /*
  249                  * Disallow write attempts on read-only file systems;
  250                  * unless the file is a socket or a block or character
  251                  * device resident on the file system.
  252                  */
  253                 if (NFSVNO_EXRDONLY(exp) ||
  254                     (vp->v_mount->mnt_flag & MNT_RDONLY)) {
  255                         switch (vp->v_type) {
  256                         case VREG:
  257                         case VDIR:
  258                         case VLNK:
  259                                 error = EROFS;
  260                         default:
  261                                 break;
  262                         }
  263                 }
  264                 /*
  265                  * If there's shared text associated with
  266                  * the inode, try to free it up once.  If
  267                  * we fail, we can't allow writing.
  268                  */
  269                 if (VOP_IS_TEXT(vp) && error == 0)
  270                         error = ETXTBSY;
  271         }
  272         if (error != 0) {
  273                 if (vpislocked == 0)
  274                         NFSVOPUNLOCK(vp, 0);
  275                 goto out;
  276         }
  277 
  278         /*
  279          * Should the override still be applied when ACLs are enabled?
  280          */
  281         error = VOP_ACCESSX(vp, accmode, cred, p);
  282         if (error != 0 && (accmode & (VDELETE | VDELETE_CHILD))) {
  283                 /*
  284                  * Try again with VEXPLICIT_DENY, to see if the test for
  285                  * deletion is supported.
  286                  */
  287                 error = VOP_ACCESSX(vp, accmode | VEXPLICIT_DENY, cred, p);
  288                 if (error == 0) {
  289                         if (vp->v_type == VDIR) {
  290                                 accmode &= ~(VDELETE | VDELETE_CHILD);
  291                                 accmode |= VWRITE;
  292                                 error = VOP_ACCESSX(vp, accmode, cred, p);
  293                         } else if (supportedtypep != NULL) {
  294                                 *supportedtypep &= ~NFSACCESS_DELETE;
  295                         }
  296                 }
  297         }
  298 
  299         /*
  300          * Allow certain operations for the owner (reads and writes
  301          * on files that are already open).
  302          */
  303         if (override != NFSACCCHK_NOOVERRIDE &&
  304             (error == EPERM || error == EACCES)) {
  305                 if (cred->cr_uid == 0 && (override & NFSACCCHK_ALLOWROOT))
  306                         error = 0;
  307                 else if (override & NFSACCCHK_ALLOWOWNER) {
  308                         getret = VOP_GETATTR(vp, &vattr, cred);
  309                         if (getret == 0 && cred->cr_uid == vattr.va_uid)
  310                                 error = 0;
  311                 }
  312         }
  313         if (vpislocked == 0)
  314                 NFSVOPUNLOCK(vp, 0);
  315 
  316 out:
  317         NFSEXITCODE(error);
  318         return (error);
  319 }
  320 
  321 /*
  322  * Set attribute(s) vnop.
  323  */
  324 int
  325 nfsvno_setattr(struct vnode *vp, struct nfsvattr *nvap, struct ucred *cred,
  326     struct thread *p, struct nfsexstuff *exp)
  327 {
  328         int error;
  329 
  330         error = VOP_SETATTR(vp, &nvap->na_vattr, cred);
  331         NFSEXITCODE(error);
  332         return (error);
  333 }
  334 
  335 /*
  336  * Set up nameidata for a lookup() call and do it.
  337  */
  338 int
  339 nfsvno_namei(struct nfsrv_descript *nd, struct nameidata *ndp,
  340     struct vnode *dp, int islocked, struct nfsexstuff *exp, struct thread *p,
  341     struct vnode **retdirp)
  342 {
  343         struct componentname *cnp = &ndp->ni_cnd;
  344         int i;
  345         struct iovec aiov;
  346         struct uio auio;
  347         int lockleaf = (cnp->cn_flags & LOCKLEAF) != 0, linklen;
  348         int error = 0, crossmnt;
  349         char *cp;
  350 
  351         *retdirp = NULL;
  352         cnp->cn_nameptr = cnp->cn_pnbuf;
  353         ndp->ni_lcf = 0;
  354         /*
  355          * Extract and set starting directory.
  356          */
  357         if (dp->v_type != VDIR) {
  358                 if (islocked)
  359                         vput(dp);
  360                 else
  361                         vrele(dp);
  362                 nfsvno_relpathbuf(ndp);
  363                 error = ENOTDIR;
  364                 goto out1;
  365         }
  366         if (islocked)
  367                 NFSVOPUNLOCK(dp, 0);
  368         VREF(dp);
  369         *retdirp = dp;
  370         if (NFSVNO_EXRDONLY(exp))
  371                 cnp->cn_flags |= RDONLY;
  372         ndp->ni_segflg = UIO_SYSSPACE;
  373         crossmnt = 1;
  374 
  375         if (nd->nd_flag & ND_PUBLOOKUP) {
  376                 ndp->ni_loopcnt = 0;
  377                 if (cnp->cn_pnbuf[0] == '/') {
  378                         vrele(dp);
  379                         /*
  380                          * Check for degenerate pathnames here, since lookup()
  381                          * panics on them.
  382                          */
  383                         for (i = 1; i < ndp->ni_pathlen; i++)
  384                                 if (cnp->cn_pnbuf[i] != '/')
  385                                         break;
  386                         if (i == ndp->ni_pathlen) {
  387                                 error = NFSERR_ACCES;
  388                                 goto out;
  389                         }
  390                         dp = rootvnode;
  391                         VREF(dp);
  392                 }
  393         } else if ((nfsrv_enable_crossmntpt == 0 && NFSVNO_EXPORTED(exp)) ||
  394             (nd->nd_flag & ND_NFSV4) == 0) {
  395                 /*
  396                  * Only cross mount points for NFSv4 when doing a
  397                  * mount while traversing the file system above
  398                  * the mount point, unless nfsrv_enable_crossmntpt is set.
  399                  */
  400                 cnp->cn_flags |= NOCROSSMOUNT;
  401                 crossmnt = 0;
  402         }
  403 
  404         /*
  405          * Initialize for scan, set ni_startdir and bump ref on dp again
  406          * because lookup() will dereference ni_startdir.
  407          */
  408 
  409         cnp->cn_thread = p;
  410         ndp->ni_startdir = dp;
  411         ndp->ni_rootdir = rootvnode;
  412         ndp->ni_topdir = NULL;
  413 
  414         if (!lockleaf)
  415                 cnp->cn_flags |= LOCKLEAF;
  416         for (;;) {
  417                 cnp->cn_nameptr = cnp->cn_pnbuf;
  418                 /*
  419                  * Call lookup() to do the real work.  If an error occurs,
  420                  * ndp->ni_vp and ni_dvp are left uninitialized or NULL and
  421                  * we do not have to dereference anything before returning.
  422                  * In either case ni_startdir will be dereferenced and NULLed
  423                  * out.
  424                  */
  425                 error = lookup(ndp);
  426                 if (error)
  427                         break;
  428 
  429                 /*
  430                  * Check for encountering a symbolic link.  Trivial
  431                  * termination occurs if no symlink encountered.
  432                  */
  433                 if ((cnp->cn_flags & ISSYMLINK) == 0) {
  434                         if ((cnp->cn_flags & (SAVENAME | SAVESTART)) == 0)
  435                                 nfsvno_relpathbuf(ndp);
  436                         if (ndp->ni_vp && !lockleaf)
  437                                 NFSVOPUNLOCK(ndp->ni_vp, 0);
  438                         break;
  439                 }
  440 
  441                 /*
  442                  * Validate symlink
  443                  */
  444                 if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1)
  445                         NFSVOPUNLOCK(ndp->ni_dvp, 0);
  446                 if (!(nd->nd_flag & ND_PUBLOOKUP)) {
  447                         error = EINVAL;
  448                         goto badlink2;
  449                 }
  450 
  451                 if (ndp->ni_loopcnt++ >= MAXSYMLINKS) {
  452                         error = ELOOP;
  453                         goto badlink2;
  454                 }
  455                 if (ndp->ni_pathlen > 1)
  456                         cp = uma_zalloc(namei_zone, M_WAITOK);
  457                 else
  458                         cp = cnp->cn_pnbuf;
  459                 aiov.iov_base = cp;
  460                 aiov.iov_len = MAXPATHLEN;
  461                 auio.uio_iov = &aiov;
  462                 auio.uio_iovcnt = 1;
  463                 auio.uio_offset = 0;
  464                 auio.uio_rw = UIO_READ;
  465                 auio.uio_segflg = UIO_SYSSPACE;
  466                 auio.uio_td = NULL;
  467                 auio.uio_resid = MAXPATHLEN;
  468                 error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred);
  469                 if (error) {
  470                 badlink1:
  471                         if (ndp->ni_pathlen > 1)
  472                                 uma_zfree(namei_zone, cp);
  473                 badlink2:
  474                         vrele(ndp->ni_dvp);
  475                         vput(ndp->ni_vp);
  476                         break;
  477                 }
  478                 linklen = MAXPATHLEN - auio.uio_resid;
  479                 if (linklen == 0) {
  480                         error = ENOENT;
  481                         goto badlink1;
  482                 }
  483                 if (linklen + ndp->ni_pathlen >= MAXPATHLEN) {
  484                         error = ENAMETOOLONG;
  485                         goto badlink1;
  486                 }
  487 
  488                 /*
  489                  * Adjust or replace path
  490                  */
  491                 if (ndp->ni_pathlen > 1) {
  492                         NFSBCOPY(ndp->ni_next, cp + linklen, ndp->ni_pathlen);
  493                         uma_zfree(namei_zone, cnp->cn_pnbuf);
  494                         cnp->cn_pnbuf = cp;
  495                 } else
  496                         cnp->cn_pnbuf[linklen] = '\0';
  497                 ndp->ni_pathlen += linklen;
  498 
  499                 /*
  500                  * Cleanup refs for next loop and check if root directory
  501                  * should replace current directory.  Normally ni_dvp
  502                  * becomes the new base directory and is cleaned up when
  503                  * we loop.  Explicitly null pointers after invalidation
  504                  * to clarify operation.
  505                  */
  506                 vput(ndp->ni_vp);
  507                 ndp->ni_vp = NULL;
  508 
  509                 if (cnp->cn_pnbuf[0] == '/') {
  510                         vrele(ndp->ni_dvp);
  511                         ndp->ni_dvp = ndp->ni_rootdir;
  512                         VREF(ndp->ni_dvp);
  513                 }
  514                 ndp->ni_startdir = ndp->ni_dvp;
  515                 ndp->ni_dvp = NULL;
  516         }
  517         if (!lockleaf)
  518                 cnp->cn_flags &= ~LOCKLEAF;
  519 
  520 out:
  521         if (error) {
  522                 nfsvno_relpathbuf(ndp);
  523                 ndp->ni_vp = NULL;
  524                 ndp->ni_dvp = NULL;
  525                 ndp->ni_startdir = NULL;
  526         } else if ((ndp->ni_cnd.cn_flags & (WANTPARENT|LOCKPARENT)) == 0) {
  527                 ndp->ni_dvp = NULL;
  528         }
  529 
  530 out1:
  531         NFSEXITCODE2(error, nd);
  532         return (error);
  533 }
  534 
  535 /*
  536  * Set up a pathname buffer and return a pointer to it and, optionally
  537  * set a hash pointer.
  538  */
  539 void
  540 nfsvno_setpathbuf(struct nameidata *ndp, char **bufpp, u_long **hashpp)
  541 {
  542         struct componentname *cnp = &ndp->ni_cnd;
  543 
  544         cnp->cn_flags |= (NOMACCHECK | HASBUF);
  545         cnp->cn_pnbuf = uma_zalloc(namei_zone, M_WAITOK);
  546         if (hashpp != NULL)
  547                 *hashpp = NULL;
  548         *bufpp = cnp->cn_pnbuf;
  549 }
  550 
  551 /*
  552  * Release the above path buffer, if not released by nfsvno_namei().
  553  */
  554 void
  555 nfsvno_relpathbuf(struct nameidata *ndp)
  556 {
  557 
  558         if ((ndp->ni_cnd.cn_flags & HASBUF) == 0)
  559                 panic("nfsrelpath");
  560         uma_zfree(namei_zone, ndp->ni_cnd.cn_pnbuf);
  561         ndp->ni_cnd.cn_flags &= ~HASBUF;
  562 }
  563 
  564 /*
  565  * Readlink vnode op into an mbuf list.
  566  */
  567 int
  568 nfsvno_readlink(struct vnode *vp, struct ucred *cred, struct thread *p,
  569     struct mbuf **mpp, struct mbuf **mpendp, int *lenp)
  570 {
  571         struct iovec iv[(NFS_MAXPATHLEN+MLEN-1)/MLEN];
  572         struct iovec *ivp = iv;
  573         struct uio io, *uiop = &io;
  574         struct mbuf *mp, *mp2 = NULL, *mp3 = NULL;
  575         int i, len, tlen, error = 0;
  576 
  577         len = 0;
  578         i = 0;
  579         while (len < NFS_MAXPATHLEN) {
  580                 NFSMGET(mp);
  581                 MCLGET(mp, M_WAITOK);
  582                 mp->m_len = M_SIZE(mp);
  583                 if (len == 0) {
  584                         mp3 = mp2 = mp;
  585                 } else {
  586                         mp2->m_next = mp;
  587                         mp2 = mp;
  588                 }
  589                 if ((len + mp->m_len) > NFS_MAXPATHLEN) {
  590                         mp->m_len = NFS_MAXPATHLEN - len;
  591                         len = NFS_MAXPATHLEN;
  592                 } else {
  593                         len += mp->m_len;
  594                 }
  595                 ivp->iov_base = mtod(mp, caddr_t);
  596                 ivp->iov_len = mp->m_len;
  597                 i++;
  598                 ivp++;
  599         }
  600         uiop->uio_iov = iv;
  601         uiop->uio_iovcnt = i;
  602         uiop->uio_offset = 0;
  603         uiop->uio_resid = len;
  604         uiop->uio_rw = UIO_READ;
  605         uiop->uio_segflg = UIO_SYSSPACE;
  606         uiop->uio_td = NULL;
  607         error = VOP_READLINK(vp, uiop, cred);
  608         if (error) {
  609                 m_freem(mp3);
  610                 *lenp = 0;
  611                 goto out;
  612         }
  613         if (uiop->uio_resid > 0) {
  614                 len -= uiop->uio_resid;
  615                 tlen = NFSM_RNDUP(len);
  616                 nfsrv_adj(mp3, NFS_MAXPATHLEN - tlen, tlen - len);
  617         }
  618         *lenp = len;
  619         *mpp = mp3;
  620         *mpendp = mp;
  621 
  622 out:
  623         NFSEXITCODE(error);
  624         return (error);
  625 }
  626 
  627 /*
  628  * Read vnode op call into mbuf list.
  629  */
  630 int
  631 nfsvno_read(struct vnode *vp, off_t off, int cnt, struct ucred *cred,
  632     struct thread *p, struct mbuf **mpp, struct mbuf **mpendp)
  633 {
  634         struct mbuf *m;
  635         int i;
  636         struct iovec *iv;
  637         struct iovec *iv2;
  638         int error = 0, len, left, siz, tlen, ioflag = 0;
  639         struct mbuf *m2 = NULL, *m3;
  640         struct uio io, *uiop = &io;
  641         struct nfsheur *nh;
  642 
  643         len = left = NFSM_RNDUP(cnt);
  644         m3 = NULL;
  645         /*
  646          * Generate the mbuf list with the uio_iov ref. to it.
  647          */
  648         i = 0;
  649         while (left > 0) {
  650                 NFSMGET(m);
  651                 MCLGET(m, M_WAITOK);
  652                 m->m_len = 0;
  653                 siz = min(M_TRAILINGSPACE(m), left);
  654                 left -= siz;
  655                 i++;
  656                 if (m3)
  657                         m2->m_next = m;
  658                 else
  659                         m3 = m;
  660                 m2 = m;
  661         }
  662         MALLOC(iv, struct iovec *, i * sizeof (struct iovec),
  663             M_TEMP, M_WAITOK);
  664         uiop->uio_iov = iv2 = iv;
  665         m = m3;
  666         left = len;
  667         i = 0;
  668         while (left > 0) {
  669                 if (m == NULL)
  670                         panic("nfsvno_read iov");
  671                 siz = min(M_TRAILINGSPACE(m), left);
  672                 if (siz > 0) {
  673                         iv->iov_base = mtod(m, caddr_t) + m->m_len;
  674                         iv->iov_len = siz;
  675                         m->m_len += siz;
  676                         left -= siz;
  677                         iv++;
  678                         i++;
  679                 }
  680                 m = m->m_next;
  681         }
  682         uiop->uio_iovcnt = i;
  683         uiop->uio_offset = off;
  684         uiop->uio_resid = len;
  685         uiop->uio_rw = UIO_READ;
  686         uiop->uio_segflg = UIO_SYSSPACE;
  687         uiop->uio_td = NULL;
  688         nh = nfsrv_sequential_heuristic(uiop, vp);
  689         ioflag |= nh->nh_seqcount << IO_SEQSHIFT;
  690         /* XXX KDM make this more systematic? */
  691         nfsstatsv1.srvbytes[NFSV4OP_READ] += uiop->uio_resid;
  692         error = VOP_READ(vp, uiop, IO_NODELOCKED | ioflag, cred);
  693         FREE((caddr_t)iv2, M_TEMP);
  694         if (error) {
  695                 m_freem(m3);
  696                 *mpp = NULL;
  697                 goto out;
  698         }
  699         nh->nh_nextoff = uiop->uio_offset;
  700         tlen = len - uiop->uio_resid;
  701         cnt = cnt < tlen ? cnt : tlen;
  702         tlen = NFSM_RNDUP(cnt);
  703         if (tlen == 0) {
  704                 m_freem(m3);
  705                 m3 = NULL;
  706         } else if (len != tlen || tlen != cnt)
  707                 nfsrv_adj(m3, len - tlen, tlen - cnt);
  708         *mpp = m3;
  709         *mpendp = m2;
  710 
  711 out:
  712         NFSEXITCODE(error);
  713         return (error);
  714 }
  715 
  716 /*
  717  * Write vnode op from an mbuf list.
  718  */
  719 int
  720 nfsvno_write(struct vnode *vp, off_t off, int retlen, int cnt, int stable,
  721     struct mbuf *mp, char *cp, struct ucred *cred, struct thread *p)
  722 {
  723         struct iovec *ivp;
  724         int i, len;
  725         struct iovec *iv;
  726         int ioflags, error;
  727         struct uio io, *uiop = &io;
  728         struct nfsheur *nh;
  729 
  730         MALLOC(ivp, struct iovec *, cnt * sizeof (struct iovec), M_TEMP,
  731             M_WAITOK);
  732         uiop->uio_iov = iv = ivp;
  733         uiop->uio_iovcnt = cnt;
  734         i = mtod(mp, caddr_t) + mp->m_len - cp;
  735         len = retlen;
  736         while (len > 0) {
  737                 if (mp == NULL)
  738                         panic("nfsvno_write");
  739                 if (i > 0) {
  740                         i = min(i, len);
  741                         ivp->iov_base = cp;
  742                         ivp->iov_len = i;
  743                         ivp++;
  744                         len -= i;
  745                 }
  746                 mp = mp->m_next;
  747                 if (mp) {
  748                         i = mp->m_len;
  749                         cp = mtod(mp, caddr_t);
  750                 }
  751         }
  752 
  753         if (stable == NFSWRITE_UNSTABLE)
  754                 ioflags = IO_NODELOCKED;
  755         else
  756                 ioflags = (IO_SYNC | IO_NODELOCKED);
  757         uiop->uio_resid = retlen;
  758         uiop->uio_rw = UIO_WRITE;
  759         uiop->uio_segflg = UIO_SYSSPACE;
  760         NFSUIOPROC(uiop, p);
  761         uiop->uio_offset = off;
  762         nh = nfsrv_sequential_heuristic(uiop, vp);
  763         ioflags |= nh->nh_seqcount << IO_SEQSHIFT;
  764         /* XXX KDM make this more systematic? */
  765         nfsstatsv1.srvbytes[NFSV4OP_WRITE] += uiop->uio_resid;
  766         error = VOP_WRITE(vp, uiop, ioflags, cred);
  767         if (error == 0)
  768                 nh->nh_nextoff = uiop->uio_offset;
  769         FREE((caddr_t)iv, M_TEMP);
  770 
  771         NFSEXITCODE(error);
  772         return (error);
  773 }
  774 
  775 /*
  776  * Common code for creating a regular file (plus special files for V2).
  777  */
  778 int
  779 nfsvno_createsub(struct nfsrv_descript *nd, struct nameidata *ndp,
  780     struct vnode **vpp, struct nfsvattr *nvap, int *exclusive_flagp,
  781     int32_t *cverf, NFSDEV_T rdev, struct thread *p, struct nfsexstuff *exp)
  782 {
  783         u_quad_t tempsize;
  784         int error;
  785 
  786         error = nd->nd_repstat;
  787         if (!error && ndp->ni_vp == NULL) {
  788                 if (nvap->na_type == VREG || nvap->na_type == VSOCK) {
  789                         vrele(ndp->ni_startdir);
  790                         error = VOP_CREATE(ndp->ni_dvp,
  791                             &ndp->ni_vp, &ndp->ni_cnd, &nvap->na_vattr);
  792                         vput(ndp->ni_dvp);
  793                         nfsvno_relpathbuf(ndp);
  794                         if (!error) {
  795                                 if (*exclusive_flagp) {
  796                                         *exclusive_flagp = 0;
  797                                         NFSVNO_ATTRINIT(nvap);
  798                                         nvap->na_atime.tv_sec = cverf[0];
  799                                         nvap->na_atime.tv_nsec = cverf[1];
  800                                         error = VOP_SETATTR(ndp->ni_vp,
  801                                             &nvap->na_vattr, nd->nd_cred);
  802                                         if (error != 0) {
  803                                                 vput(ndp->ni_vp);
  804                                                 ndp->ni_vp = NULL;
  805                                                 error = NFSERR_NOTSUPP;
  806                                         }
  807                                 }
  808                         }
  809                 /*
  810                  * NFS V2 Only. nfsrvd_mknod() does this for V3.
  811                  * (This implies, just get out on an error.)
  812                  */
  813                 } else if (nvap->na_type == VCHR || nvap->na_type == VBLK ||
  814                         nvap->na_type == VFIFO) {
  815                         if (nvap->na_type == VCHR && rdev == 0xffffffff)
  816                                 nvap->na_type = VFIFO;
  817                         if (nvap->na_type != VFIFO &&
  818                             (error = priv_check_cred(nd->nd_cred,
  819                              PRIV_VFS_MKNOD_DEV, 0))) {
  820                                 vrele(ndp->ni_startdir);
  821                                 nfsvno_relpathbuf(ndp);
  822                                 vput(ndp->ni_dvp);
  823                                 goto out;
  824                         }
  825                         nvap->na_rdev = rdev;
  826                         error = VOP_MKNOD(ndp->ni_dvp, &ndp->ni_vp,
  827                             &ndp->ni_cnd, &nvap->na_vattr);
  828                         vput(ndp->ni_dvp);
  829                         nfsvno_relpathbuf(ndp);
  830                         vrele(ndp->ni_startdir);
  831                         if (error)
  832                                 goto out;
  833                 } else {
  834                         vrele(ndp->ni_startdir);
  835                         nfsvno_relpathbuf(ndp);
  836                         vput(ndp->ni_dvp);
  837                         error = ENXIO;
  838                         goto out;
  839                 }
  840                 *vpp = ndp->ni_vp;
  841         } else {
  842                 /*
  843                  * Handle cases where error is already set and/or
  844                  * the file exists.
  845                  * 1 - clean up the lookup
  846                  * 2 - iff !error and na_size set, truncate it
  847                  */
  848                 vrele(ndp->ni_startdir);
  849                 nfsvno_relpathbuf(ndp);
  850                 *vpp = ndp->ni_vp;
  851                 if (ndp->ni_dvp == *vpp)
  852                         vrele(ndp->ni_dvp);
  853                 else
  854                         vput(ndp->ni_dvp);
  855                 if (!error && nvap->na_size != VNOVAL) {
  856                         error = nfsvno_accchk(*vpp, VWRITE,
  857                             nd->nd_cred, exp, p, NFSACCCHK_NOOVERRIDE,
  858                             NFSACCCHK_VPISLOCKED, NULL);
  859                         if (!error) {
  860                                 tempsize = nvap->na_size;
  861                                 NFSVNO_ATTRINIT(nvap);
  862                                 nvap->na_size = tempsize;
  863                                 error = VOP_SETATTR(*vpp,
  864                                     &nvap->na_vattr, nd->nd_cred);
  865                         }
  866                 }
  867                 if (error)
  868                         vput(*vpp);
  869         }
  870 
  871 out:
  872         NFSEXITCODE(error);
  873         return (error);
  874 }
  875 
  876 /*
  877  * Do a mknod vnode op.
  878  */
  879 int
  880 nfsvno_mknod(struct nameidata *ndp, struct nfsvattr *nvap, struct ucred *cred,
  881     struct thread *p)
  882 {
  883         int error = 0;
  884         enum vtype vtyp;
  885 
  886         vtyp = nvap->na_type;
  887         /*
  888          * Iff doesn't exist, create it.
  889          */
  890         if (ndp->ni_vp) {
  891                 vrele(ndp->ni_startdir);
  892                 nfsvno_relpathbuf(ndp);
  893                 vput(ndp->ni_dvp);
  894                 vrele(ndp->ni_vp);
  895                 error = EEXIST;
  896                 goto out;
  897         }
  898         if (vtyp != VCHR && vtyp != VBLK && vtyp != VSOCK && vtyp != VFIFO) {
  899                 vrele(ndp->ni_startdir);
  900                 nfsvno_relpathbuf(ndp);
  901                 vput(ndp->ni_dvp);
  902                 error = NFSERR_BADTYPE;
  903                 goto out;
  904         }
  905         if (vtyp == VSOCK) {
  906                 vrele(ndp->ni_startdir);
  907                 error = VOP_CREATE(ndp->ni_dvp, &ndp->ni_vp,
  908                     &ndp->ni_cnd, &nvap->na_vattr);
  909                 vput(ndp->ni_dvp);
  910                 nfsvno_relpathbuf(ndp);
  911         } else {
  912                 if (nvap->na_type != VFIFO &&
  913                     (error = priv_check_cred(cred, PRIV_VFS_MKNOD_DEV, 0))) {
  914                         vrele(ndp->ni_startdir);
  915                         nfsvno_relpathbuf(ndp);
  916                         vput(ndp->ni_dvp);
  917                         goto out;
  918                 }
  919                 error = VOP_MKNOD(ndp->ni_dvp, &ndp->ni_vp,
  920                     &ndp->ni_cnd, &nvap->na_vattr);
  921                 vput(ndp->ni_dvp);
  922                 nfsvno_relpathbuf(ndp);
  923                 vrele(ndp->ni_startdir);
  924                 /*
  925                  * Since VOP_MKNOD returns the ni_vp, I can't
  926                  * see any reason to do the lookup.
  927                  */
  928         }
  929 
  930 out:
  931         NFSEXITCODE(error);
  932         return (error);
  933 }
  934 
  935 /*
  936  * Mkdir vnode op.
  937  */
  938 int
  939 nfsvno_mkdir(struct nameidata *ndp, struct nfsvattr *nvap, uid_t saved_uid,
  940     struct ucred *cred, struct thread *p, struct nfsexstuff *exp)
  941 {
  942         int error = 0;
  943 
  944         if (ndp->ni_vp != NULL) {
  945                 if (ndp->ni_dvp == ndp->ni_vp)
  946                         vrele(ndp->ni_dvp);
  947                 else
  948                         vput(ndp->ni_dvp);
  949                 vrele(ndp->ni_vp);
  950                 nfsvno_relpathbuf(ndp);
  951                 error = EEXIST;
  952                 goto out;
  953         }
  954         error = VOP_MKDIR(ndp->ni_dvp, &ndp->ni_vp, &ndp->ni_cnd,
  955             &nvap->na_vattr);
  956         vput(ndp->ni_dvp);
  957         nfsvno_relpathbuf(ndp);
  958 
  959 out:
  960         NFSEXITCODE(error);
  961         return (error);
  962 }
  963 
  964 /*
  965  * symlink vnode op.
  966  */
  967 int
  968 nfsvno_symlink(struct nameidata *ndp, struct nfsvattr *nvap, char *pathcp,
  969     int pathlen, int not_v2, uid_t saved_uid, struct ucred *cred, struct thread *p,
  970     struct nfsexstuff *exp)
  971 {
  972         int error = 0;
  973 
  974         if (ndp->ni_vp) {
  975                 vrele(ndp->ni_startdir);
  976                 nfsvno_relpathbuf(ndp);
  977                 if (ndp->ni_dvp == ndp->ni_vp)
  978                         vrele(ndp->ni_dvp);
  979                 else
  980                         vput(ndp->ni_dvp);
  981                 vrele(ndp->ni_vp);
  982                 error = EEXIST;
  983                 goto out;
  984         }
  985 
  986         error = VOP_SYMLINK(ndp->ni_dvp, &ndp->ni_vp, &ndp->ni_cnd,
  987             &nvap->na_vattr, pathcp);
  988         vput(ndp->ni_dvp);
  989         vrele(ndp->ni_startdir);
  990         nfsvno_relpathbuf(ndp);
  991         /*
  992          * Although FreeBSD still had the lookup code in
  993          * it for 7/current, there doesn't seem to be any
  994          * point, since VOP_SYMLINK() returns the ni_vp.
  995          * Just vput it for v2.
  996          */
  997         if (!not_v2 && !error)
  998                 vput(ndp->ni_vp);
  999 
 1000 out:
 1001         NFSEXITCODE(error);
 1002         return (error);
 1003 }
 1004 
 1005 /*
 1006  * Parse symbolic link arguments.
 1007  * This function has an ugly side effect. It will MALLOC() an area for
 1008  * the symlink and set iov_base to point to it, only if it succeeds.
 1009  * So, if it returns with uiop->uio_iov->iov_base != NULL, that must
 1010  * be FREE'd later.
 1011  */
 1012 int
 1013 nfsvno_getsymlink(struct nfsrv_descript *nd, struct nfsvattr *nvap,
 1014     struct thread *p, char **pathcpp, int *lenp)
 1015 {
 1016         u_int32_t *tl;
 1017         char *pathcp = NULL;
 1018         int error = 0, len;
 1019         struct nfsv2_sattr *sp;
 1020 
 1021         *pathcpp = NULL;
 1022         *lenp = 0;
 1023         if ((nd->nd_flag & ND_NFSV3) &&
 1024             (error = nfsrv_sattr(nd, NULL, nvap, NULL, NULL, p)))
 1025                 goto nfsmout;
 1026         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 1027         len = fxdr_unsigned(int, *tl);
 1028         if (len > NFS_MAXPATHLEN || len <= 0) {
 1029                 error = EBADRPC;
 1030                 goto nfsmout;
 1031         }
 1032         MALLOC(pathcp, caddr_t, len + 1, M_TEMP, M_WAITOK);
 1033         error = nfsrv_mtostr(nd, pathcp, len);
 1034         if (error)
 1035                 goto nfsmout;
 1036         if (nd->nd_flag & ND_NFSV2) {
 1037                 NFSM_DISSECT(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
 1038                 nvap->na_mode = fxdr_unsigned(u_int16_t, sp->sa_mode);
 1039         }
 1040         *pathcpp = pathcp;
 1041         *lenp = len;
 1042         NFSEXITCODE2(0, nd);
 1043         return (0);
 1044 nfsmout:
 1045         if (pathcp)
 1046                 free(pathcp, M_TEMP);
 1047         NFSEXITCODE2(error, nd);
 1048         return (error);
 1049 }
 1050 
 1051 /*
 1052  * Remove a non-directory object.
 1053  */
 1054 int
 1055 nfsvno_removesub(struct nameidata *ndp, int is_v4, struct ucred *cred,
 1056     struct thread *p, struct nfsexstuff *exp)
 1057 {
 1058         struct vnode *vp;
 1059         int error = 0;
 1060 
 1061         vp = ndp->ni_vp;
 1062         if (vp->v_type == VDIR)
 1063                 error = NFSERR_ISDIR;
 1064         else if (is_v4)
 1065                 error = nfsrv_checkremove(vp, 1, p);
 1066         if (!error)
 1067                 error = VOP_REMOVE(ndp->ni_dvp, vp, &ndp->ni_cnd);
 1068         if (ndp->ni_dvp == vp)
 1069                 vrele(ndp->ni_dvp);
 1070         else
 1071                 vput(ndp->ni_dvp);
 1072         vput(vp);
 1073         if ((ndp->ni_cnd.cn_flags & SAVENAME) != 0)
 1074                 nfsvno_relpathbuf(ndp);
 1075         NFSEXITCODE(error);
 1076         return (error);
 1077 }
 1078 
 1079 /*
 1080  * Remove a directory.
 1081  */
 1082 int
 1083 nfsvno_rmdirsub(struct nameidata *ndp, int is_v4, struct ucred *cred,
 1084     struct thread *p, struct nfsexstuff *exp)
 1085 {
 1086         struct vnode *vp;
 1087         int error = 0;
 1088 
 1089         vp = ndp->ni_vp;
 1090         if (vp->v_type != VDIR) {
 1091                 error = ENOTDIR;
 1092                 goto out;
 1093         }
 1094         /*
 1095          * No rmdir "." please.
 1096          */
 1097         if (ndp->ni_dvp == vp) {
 1098                 error = EINVAL;
 1099                 goto out;
 1100         }
 1101         /*
 1102          * The root of a mounted filesystem cannot be deleted.
 1103          */
 1104         if (vp->v_vflag & VV_ROOT)
 1105                 error = EBUSY;
 1106 out:
 1107         if (!error)
 1108                 error = VOP_RMDIR(ndp->ni_dvp, vp, &ndp->ni_cnd);
 1109         if (ndp->ni_dvp == vp)
 1110                 vrele(ndp->ni_dvp);
 1111         else
 1112                 vput(ndp->ni_dvp);
 1113         vput(vp);
 1114         if ((ndp->ni_cnd.cn_flags & SAVENAME) != 0)
 1115                 nfsvno_relpathbuf(ndp);
 1116         NFSEXITCODE(error);
 1117         return (error);
 1118 }
 1119 
 1120 /*
 1121  * Rename vnode op.
 1122  */
 1123 int
 1124 nfsvno_rename(struct nameidata *fromndp, struct nameidata *tondp,
 1125     u_int32_t ndstat, u_int32_t ndflag, struct ucred *cred, struct thread *p)
 1126 {
 1127         struct vnode *fvp, *tvp, *tdvp;
 1128         int error = 0;
 1129 
 1130         fvp = fromndp->ni_vp;
 1131         if (ndstat) {
 1132                 vrele(fromndp->ni_dvp);
 1133                 vrele(fvp);
 1134                 error = ndstat;
 1135                 goto out1;
 1136         }
 1137         tdvp = tondp->ni_dvp;
 1138         tvp = tondp->ni_vp;
 1139         if (tvp != NULL) {
 1140                 if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
 1141                         error = (ndflag & ND_NFSV2) ? EISDIR : EEXIST;
 1142                         goto out;
 1143                 } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
 1144                         error = (ndflag & ND_NFSV2) ? ENOTDIR : EEXIST;
 1145                         goto out;
 1146                 }
 1147                 if (tvp->v_type == VDIR && tvp->v_mountedhere) {
 1148                         error = (ndflag & ND_NFSV2) ? ENOTEMPTY : EXDEV;
 1149                         goto out;
 1150                 }
 1151 
 1152                 /*
 1153                  * A rename to '.' or '..' results in a prematurely
 1154                  * unlocked vnode on FreeBSD5, so I'm just going to fail that
 1155                  * here.
 1156                  */
 1157                 if ((tondp->ni_cnd.cn_namelen == 1 &&
 1158                      tondp->ni_cnd.cn_nameptr[0] == '.') ||
 1159                     (tondp->ni_cnd.cn_namelen == 2 &&
 1160                      tondp->ni_cnd.cn_nameptr[0] == '.' &&
 1161                      tondp->ni_cnd.cn_nameptr[1] == '.')) {
 1162                         error = EINVAL;
 1163                         goto out;
 1164                 }
 1165         }
 1166         if (fvp->v_type == VDIR && fvp->v_mountedhere) {
 1167                 error = (ndflag & ND_NFSV2) ? ENOTEMPTY : EXDEV;
 1168                 goto out;
 1169         }
 1170         if (fvp->v_mount != tdvp->v_mount) {
 1171                 error = (ndflag & ND_NFSV2) ? ENOTEMPTY : EXDEV;
 1172                 goto out;
 1173         }
 1174         if (fvp == tdvp) {
 1175                 error = (ndflag & ND_NFSV2) ? ENOTEMPTY : EINVAL;
 1176                 goto out;
 1177         }
 1178         if (fvp == tvp) {
 1179                 /*
 1180                  * If source and destination are the same, there is nothing to
 1181                  * do. Set error to -1 to indicate this.
 1182                  */
 1183                 error = -1;
 1184                 goto out;
 1185         }
 1186         if (ndflag & ND_NFSV4) {
 1187                 if (NFSVOPLOCK(fvp, LK_EXCLUSIVE) == 0) {
 1188                         error = nfsrv_checkremove(fvp, 0, p);
 1189                         NFSVOPUNLOCK(fvp, 0);
 1190                 } else
 1191                         error = EPERM;
 1192                 if (tvp && !error)
 1193                         error = nfsrv_checkremove(tvp, 1, p);
 1194         } else {
 1195                 /*
 1196                  * For NFSv2 and NFSv3, try to get rid of the delegation, so
 1197                  * that the NFSv4 client won't be confused by the rename.
 1198                  * Since nfsd_recalldelegation() can only be called on an
 1199                  * unlocked vnode at this point and fvp is the file that will
 1200                  * still exist after the rename, just do fvp.
 1201                  */
 1202                 nfsd_recalldelegation(fvp, p);
 1203         }
 1204 out:
 1205         if (!error) {
 1206                 error = VOP_RENAME(fromndp->ni_dvp, fromndp->ni_vp,
 1207                     &fromndp->ni_cnd, tondp->ni_dvp, tondp->ni_vp,
 1208                     &tondp->ni_cnd);
 1209         } else {
 1210                 if (tdvp == tvp)
 1211                         vrele(tdvp);
 1212                 else
 1213                         vput(tdvp);
 1214                 if (tvp)
 1215                         vput(tvp);
 1216                 vrele(fromndp->ni_dvp);
 1217                 vrele(fvp);
 1218                 if (error == -1)
 1219                         error = 0;
 1220         }
 1221         vrele(tondp->ni_startdir);
 1222         nfsvno_relpathbuf(tondp);
 1223 out1:
 1224         vrele(fromndp->ni_startdir);
 1225         nfsvno_relpathbuf(fromndp);
 1226         NFSEXITCODE(error);
 1227         return (error);
 1228 }
 1229 
 1230 /*
 1231  * Link vnode op.
 1232  */
 1233 int
 1234 nfsvno_link(struct nameidata *ndp, struct vnode *vp, struct ucred *cred,
 1235     struct thread *p, struct nfsexstuff *exp)
 1236 {
 1237         struct vnode *xp;
 1238         int error = 0;
 1239 
 1240         xp = ndp->ni_vp;
 1241         if (xp != NULL) {
 1242                 error = EEXIST;
 1243         } else {
 1244                 xp = ndp->ni_dvp;
 1245                 if (vp->v_mount != xp->v_mount)
 1246                         error = EXDEV;
 1247         }
 1248         if (!error) {
 1249                 NFSVOPLOCK(vp, LK_EXCLUSIVE | LK_RETRY);
 1250                 if ((vp->v_iflag & VI_DOOMED) == 0)
 1251                         error = VOP_LINK(ndp->ni_dvp, vp, &ndp->ni_cnd);
 1252                 else
 1253                         error = EPERM;
 1254                 if (ndp->ni_dvp == vp)
 1255                         vrele(ndp->ni_dvp);
 1256                 else
 1257                         vput(ndp->ni_dvp);
 1258                 NFSVOPUNLOCK(vp, 0);
 1259         } else {
 1260                 if (ndp->ni_dvp == ndp->ni_vp)
 1261                         vrele(ndp->ni_dvp);
 1262                 else
 1263                         vput(ndp->ni_dvp);
 1264                 if (ndp->ni_vp)
 1265                         vrele(ndp->ni_vp);
 1266         }
 1267         nfsvno_relpathbuf(ndp);
 1268         NFSEXITCODE(error);
 1269         return (error);
 1270 }
 1271 
 1272 /*
 1273  * Do the fsync() appropriate for the commit.
 1274  */
 1275 int
 1276 nfsvno_fsync(struct vnode *vp, u_int64_t off, int cnt, struct ucred *cred,
 1277     struct thread *td)
 1278 {
 1279         int error = 0;
 1280 
 1281         /*
 1282          * RFC 1813 3.3.21: if count is 0, a flush from offset to the end of
 1283          * file is done.  At this time VOP_FSYNC does not accept offset and
 1284          * byte count parameters so call VOP_FSYNC the whole file for now.
 1285          * The same is true for NFSv4: RFC 3530 Sec. 14.2.3.
 1286          * File systems that do not use the buffer cache (as indicated
 1287          * by MNTK_USES_BCACHE not being set) must use VOP_FSYNC().
 1288          */
 1289         if (cnt == 0 || cnt > MAX_COMMIT_COUNT ||
 1290             (vp->v_mount->mnt_kern_flag & MNTK_USES_BCACHE) == 0) {
 1291                 /*
 1292                  * Give up and do the whole thing
 1293                  */
 1294                 if (vp->v_object &&
 1295                    (vp->v_object->flags & OBJ_MIGHTBEDIRTY)) {
 1296                         VM_OBJECT_WLOCK(vp->v_object);
 1297                         vm_object_page_clean(vp->v_object, 0, 0, OBJPC_SYNC);
 1298                         VM_OBJECT_WUNLOCK(vp->v_object);
 1299                 }
 1300                 error = VOP_FSYNC(vp, MNT_WAIT, td);
 1301         } else {
 1302                 /*
 1303                  * Locate and synchronously write any buffers that fall
 1304                  * into the requested range.  Note:  we are assuming that
 1305                  * f_iosize is a power of 2.
 1306                  */
 1307                 int iosize = vp->v_mount->mnt_stat.f_iosize;
 1308                 int iomask = iosize - 1;
 1309                 struct bufobj *bo;
 1310                 daddr_t lblkno;
 1311 
 1312                 /*
 1313                  * Align to iosize boundary, super-align to page boundary.
 1314                  */
 1315                 if (off & iomask) {
 1316                         cnt += off & iomask;
 1317                         off &= ~(u_quad_t)iomask;
 1318                 }
 1319                 if (off & PAGE_MASK) {
 1320                         cnt += off & PAGE_MASK;
 1321                         off &= ~(u_quad_t)PAGE_MASK;
 1322                 }
 1323                 lblkno = off / iosize;
 1324 
 1325                 if (vp->v_object &&
 1326                    (vp->v_object->flags & OBJ_MIGHTBEDIRTY)) {
 1327                         VM_OBJECT_WLOCK(vp->v_object);
 1328                         vm_object_page_clean(vp->v_object, off, off + cnt,
 1329                             OBJPC_SYNC);
 1330                         VM_OBJECT_WUNLOCK(vp->v_object);
 1331                 }
 1332 
 1333                 bo = &vp->v_bufobj;
 1334                 BO_LOCK(bo);
 1335                 while (cnt > 0) {
 1336                         struct buf *bp;
 1337 
 1338                         /*
 1339                          * If we have a buffer and it is marked B_DELWRI we
 1340                          * have to lock and write it.  Otherwise the prior
 1341                          * write is assumed to have already been committed.
 1342                          *
 1343                          * gbincore() can return invalid buffers now so we
 1344                          * have to check that bit as well (though B_DELWRI
 1345                          * should not be set if B_INVAL is set there could be
 1346                          * a race here since we haven't locked the buffer).
 1347                          */
 1348                         if ((bp = gbincore(&vp->v_bufobj, lblkno)) != NULL) {
 1349                                 if (BUF_LOCK(bp, LK_EXCLUSIVE | LK_SLEEPFAIL |
 1350                                     LK_INTERLOCK, BO_LOCKPTR(bo)) == ENOLCK) {
 1351                                         BO_LOCK(bo);
 1352                                         continue; /* retry */
 1353                                 }
 1354                                 if ((bp->b_flags & (B_DELWRI|B_INVAL)) ==
 1355                                     B_DELWRI) {
 1356                                         bremfree(bp);
 1357                                         bp->b_flags &= ~B_ASYNC;
 1358                                         bwrite(bp);
 1359                                         ++nfs_commit_miss;
 1360                                 } else
 1361                                         BUF_UNLOCK(bp);
 1362                                 BO_LOCK(bo);
 1363                         }
 1364                         ++nfs_commit_blks;
 1365                         if (cnt < iosize)
 1366                                 break;
 1367                         cnt -= iosize;
 1368                         ++lblkno;
 1369                 }
 1370                 BO_UNLOCK(bo);
 1371         }
 1372         NFSEXITCODE(error);
 1373         return (error);
 1374 }
 1375 
 1376 /*
 1377  * Statfs vnode op.
 1378  */
 1379 int
 1380 nfsvno_statfs(struct vnode *vp, struct statfs *sf)
 1381 {
 1382         int error;
 1383 
 1384         error = VFS_STATFS(vp->v_mount, sf);
 1385         if (error == 0) {
 1386                 /*
 1387                  * Since NFS handles these values as unsigned on the
 1388                  * wire, there is no way to represent negative values,
 1389                  * so set them to 0. Without this, they will appear
 1390                  * to be very large positive values for clients like
 1391                  * Solaris10.
 1392                  */
 1393                 if (sf->f_bavail < 0)
 1394                         sf->f_bavail = 0;
 1395                 if (sf->f_ffree < 0)
 1396                         sf->f_ffree = 0;
 1397         }
 1398         NFSEXITCODE(error);
 1399         return (error);
 1400 }
 1401 
 1402 /*
 1403  * Do the vnode op stuff for Open. Similar to nfsvno_createsub(), but
 1404  * must handle nfsrv_opencheck() calls after any other access checks.
 1405  */
 1406 void
 1407 nfsvno_open(struct nfsrv_descript *nd, struct nameidata *ndp,
 1408     nfsquad_t clientid, nfsv4stateid_t *stateidp, struct nfsstate *stp,
 1409     int *exclusive_flagp, struct nfsvattr *nvap, int32_t *cverf, int create,
 1410     NFSACL_T *aclp, nfsattrbit_t *attrbitp, struct ucred *cred, struct thread *p,
 1411     struct nfsexstuff *exp, struct vnode **vpp)
 1412 {
 1413         struct vnode *vp = NULL;
 1414         u_quad_t tempsize;
 1415         struct nfsexstuff nes;
 1416 
 1417         if (ndp->ni_vp == NULL)
 1418                 nd->nd_repstat = nfsrv_opencheck(clientid,
 1419                     stateidp, stp, NULL, nd, p, nd->nd_repstat);
 1420         if (!nd->nd_repstat) {
 1421                 if (ndp->ni_vp == NULL) {
 1422                         vrele(ndp->ni_startdir);
 1423                         nd->nd_repstat = VOP_CREATE(ndp->ni_dvp,
 1424                             &ndp->ni_vp, &ndp->ni_cnd, &nvap->na_vattr);
 1425                         vput(ndp->ni_dvp);
 1426                         nfsvno_relpathbuf(ndp);
 1427                         if (!nd->nd_repstat) {
 1428                                 if (*exclusive_flagp) {
 1429                                         *exclusive_flagp = 0;
 1430                                         NFSVNO_ATTRINIT(nvap);
 1431                                         nvap->na_atime.tv_sec = cverf[0];
 1432                                         nvap->na_atime.tv_nsec = cverf[1];
 1433                                         nd->nd_repstat = VOP_SETATTR(ndp->ni_vp,
 1434                                             &nvap->na_vattr, cred);
 1435                                         if (nd->nd_repstat != 0) {
 1436                                                 vput(ndp->ni_vp);
 1437                                                 ndp->ni_vp = NULL;
 1438                                                 nd->nd_repstat = NFSERR_NOTSUPP;
 1439                                         } else
 1440                                                 NFSSETBIT_ATTRBIT(attrbitp,
 1441                                                     NFSATTRBIT_TIMEACCESS);
 1442                                 } else {
 1443                                         nfsrv_fixattr(nd, ndp->ni_vp, nvap,
 1444                                             aclp, p, attrbitp, exp);
 1445                                 }
 1446                         }
 1447                         vp = ndp->ni_vp;
 1448                 } else {
 1449                         if (ndp->ni_startdir)
 1450                                 vrele(ndp->ni_startdir);
 1451                         nfsvno_relpathbuf(ndp);
 1452                         vp = ndp->ni_vp;
 1453                         if (create == NFSV4OPEN_CREATE) {
 1454                                 if (ndp->ni_dvp == vp)
 1455                                         vrele(ndp->ni_dvp);
 1456                                 else
 1457                                         vput(ndp->ni_dvp);
 1458                         }
 1459                         if (NFSVNO_ISSETSIZE(nvap) && vp->v_type == VREG) {
 1460                                 if (ndp->ni_cnd.cn_flags & RDONLY)
 1461                                         NFSVNO_SETEXRDONLY(&nes);
 1462                                 else
 1463                                         NFSVNO_EXINIT(&nes);
 1464                                 nd->nd_repstat = nfsvno_accchk(vp, 
 1465                                     VWRITE, cred, &nes, p,
 1466                                     NFSACCCHK_NOOVERRIDE,
 1467                                     NFSACCCHK_VPISLOCKED, NULL);
 1468                                 nd->nd_repstat = nfsrv_opencheck(clientid,
 1469                                     stateidp, stp, vp, nd, p, nd->nd_repstat);
 1470                                 if (!nd->nd_repstat) {
 1471                                         tempsize = nvap->na_size;
 1472                                         NFSVNO_ATTRINIT(nvap);
 1473                                         nvap->na_size = tempsize;
 1474                                         nd->nd_repstat = VOP_SETATTR(vp,
 1475                                             &nvap->na_vattr, cred);
 1476                                 }
 1477                         } else if (vp->v_type == VREG) {
 1478                                 nd->nd_repstat = nfsrv_opencheck(clientid,
 1479                                     stateidp, stp, vp, nd, p, nd->nd_repstat);
 1480                         }
 1481                 }
 1482         } else {
 1483                 if (ndp->ni_cnd.cn_flags & HASBUF)
 1484                         nfsvno_relpathbuf(ndp);
 1485                 if (ndp->ni_startdir && create == NFSV4OPEN_CREATE) {
 1486                         vrele(ndp->ni_startdir);
 1487                         if (ndp->ni_dvp == ndp->ni_vp)
 1488                                 vrele(ndp->ni_dvp);
 1489                         else
 1490                                 vput(ndp->ni_dvp);
 1491                         if (ndp->ni_vp)
 1492                                 vput(ndp->ni_vp);
 1493                 }
 1494         }
 1495         *vpp = vp;
 1496 
 1497         NFSEXITCODE2(0, nd);
 1498 }
 1499 
 1500 /*
 1501  * Updates the file rev and sets the mtime and ctime
 1502  * to the current clock time, returning the va_filerev and va_Xtime
 1503  * values.
 1504  * Return ESTALE to indicate the vnode is VI_DOOMED.
 1505  */
 1506 int
 1507 nfsvno_updfilerev(struct vnode *vp, struct nfsvattr *nvap,
 1508     struct ucred *cred, struct thread *p)
 1509 {
 1510         struct vattr va;
 1511 
 1512         VATTR_NULL(&va);
 1513         vfs_timestamp(&va.va_mtime);
 1514         if (NFSVOPISLOCKED(vp) != LK_EXCLUSIVE) {
 1515                 NFSVOPLOCK(vp, LK_UPGRADE | LK_RETRY);
 1516                 if ((vp->v_iflag & VI_DOOMED) != 0)
 1517                         return (ESTALE);
 1518         }
 1519         (void) VOP_SETATTR(vp, &va, cred);
 1520         (void) nfsvno_getattr(vp, nvap, cred, p, 1);
 1521         return (0);
 1522 }
 1523 
 1524 /*
 1525  * Glue routine to nfsv4_fillattr().
 1526  */
 1527 int
 1528 nfsvno_fillattr(struct nfsrv_descript *nd, struct mount *mp, struct vnode *vp,
 1529     struct nfsvattr *nvap, fhandle_t *fhp, int rderror, nfsattrbit_t *attrbitp,
 1530     struct ucred *cred, struct thread *p, int isdgram, int reterr,
 1531     int supports_nfsv4acls, int at_root, uint64_t mounted_on_fileno)
 1532 {
 1533         int error;
 1534 
 1535         error = nfsv4_fillattr(nd, mp, vp, NULL, &nvap->na_vattr, fhp, rderror,
 1536             attrbitp, cred, p, isdgram, reterr, supports_nfsv4acls, at_root,
 1537             mounted_on_fileno);
 1538         NFSEXITCODE2(0, nd);
 1539         return (error);
 1540 }
 1541 
 1542 /* Since the Readdir vnode ops vary, put the entire functions in here. */
 1543 /*
 1544  * nfs readdir service
 1545  * - mallocs what it thinks is enough to read
 1546  *      count rounded up to a multiple of DIRBLKSIZ <= NFS_MAXREADDIR
 1547  * - calls VOP_READDIR()
 1548  * - loops around building the reply
 1549  *      if the output generated exceeds count break out of loop
 1550  *      The NFSM_CLGET macro is used here so that the reply will be packed
 1551  *      tightly in mbuf clusters.
 1552  * - it trims out records with d_fileno == 0
 1553  *      this doesn't matter for Unix clients, but they might confuse clients
 1554  *      for other os'.
 1555  * - it trims out records with d_type == DT_WHT
 1556  *      these cannot be seen through NFS (unless we extend the protocol)
 1557  *     The alternate call nfsrvd_readdirplus() does lookups as well.
 1558  * PS: The NFS protocol spec. does not clarify what the "count" byte
 1559  *      argument is a count of.. just name strings and file id's or the
 1560  *      entire reply rpc or ...
 1561  *      I tried just file name and id sizes and it confused the Sun client,
 1562  *      so I am using the full rpc size now. The "paranoia.." comment refers
 1563  *      to including the status longwords that are not a part of the dir.
 1564  *      "entry" structures, but are in the rpc.
 1565  */
 1566 int
 1567 nfsrvd_readdir(struct nfsrv_descript *nd, int isdgram,
 1568     struct vnode *vp, struct thread *p, struct nfsexstuff *exp)
 1569 {
 1570         struct dirent *dp;
 1571         u_int32_t *tl;
 1572         int dirlen;
 1573         char *cpos, *cend, *rbuf;
 1574         struct nfsvattr at;
 1575         int nlen, error = 0, getret = 1;
 1576         int siz, cnt, fullsiz, eofflag, ncookies;
 1577         u_int64_t off, toff, verf;
 1578         u_long *cookies = NULL, *cookiep;
 1579         struct uio io;
 1580         struct iovec iv;
 1581         int is_ufs;
 1582 
 1583         if (nd->nd_repstat) {
 1584                 nfsrv_postopattr(nd, getret, &at);
 1585                 goto out;
 1586         }
 1587         if (nd->nd_flag & ND_NFSV2) {
 1588                 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
 1589                 off = fxdr_unsigned(u_quad_t, *tl++);
 1590         } else {
 1591                 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
 1592                 off = fxdr_hyper(tl);
 1593                 tl += 2;
 1594                 verf = fxdr_hyper(tl);
 1595                 tl += 2;
 1596         }
 1597         toff = off;
 1598         cnt = fxdr_unsigned(int, *tl);
 1599         if (cnt > NFS_SRVMAXDATA(nd) || cnt < 0)
 1600                 cnt = NFS_SRVMAXDATA(nd);
 1601         siz = ((cnt + DIRBLKSIZ - 1) & ~(DIRBLKSIZ - 1));
 1602         fullsiz = siz;
 1603         if (nd->nd_flag & ND_NFSV3) {
 1604                 nd->nd_repstat = getret = nfsvno_getattr(vp, &at, nd->nd_cred,
 1605                     p, 1);
 1606 #if 0
 1607                 /*
 1608                  * va_filerev is not sufficient as a cookie verifier,
 1609                  * since it is not supposed to change when entries are
 1610                  * removed/added unless that offset cookies returned to
 1611                  * the client are no longer valid.
 1612                  */
 1613                 if (!nd->nd_repstat && toff && verf != at.na_filerev)
 1614                         nd->nd_repstat = NFSERR_BAD_COOKIE;
 1615 #endif
 1616         }
 1617         if (!nd->nd_repstat && vp->v_type != VDIR)
 1618                 nd->nd_repstat = NFSERR_NOTDIR;
 1619         if (nd->nd_repstat == 0 && cnt == 0) {
 1620                 if (nd->nd_flag & ND_NFSV2)
 1621                         /* NFSv2 does not have NFSERR_TOOSMALL */
 1622                         nd->nd_repstat = EPERM;
 1623                 else
 1624                         nd->nd_repstat = NFSERR_TOOSMALL;
 1625         }
 1626         if (!nd->nd_repstat)
 1627                 nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
 1628                     nd->nd_cred, exp, p, NFSACCCHK_NOOVERRIDE,
 1629                     NFSACCCHK_VPISLOCKED, NULL);
 1630         if (nd->nd_repstat) {
 1631                 vput(vp);
 1632                 if (nd->nd_flag & ND_NFSV3)
 1633                         nfsrv_postopattr(nd, getret, &at);
 1634                 goto out;
 1635         }
 1636         is_ufs = strcmp(vp->v_mount->mnt_vfc->vfc_name, "ufs") == 0;
 1637         MALLOC(rbuf, caddr_t, siz, M_TEMP, M_WAITOK);
 1638 again:
 1639         eofflag = 0;
 1640         if (cookies) {
 1641                 free((caddr_t)cookies, M_TEMP);
 1642                 cookies = NULL;
 1643         }
 1644 
 1645         iv.iov_base = rbuf;
 1646         iv.iov_len = siz;
 1647         io.uio_iov = &iv;
 1648         io.uio_iovcnt = 1;
 1649         io.uio_offset = (off_t)off;
 1650         io.uio_resid = siz;
 1651         io.uio_segflg = UIO_SYSSPACE;
 1652         io.uio_rw = UIO_READ;
 1653         io.uio_td = NULL;
 1654         nd->nd_repstat = VOP_READDIR(vp, &io, nd->nd_cred, &eofflag, &ncookies,
 1655             &cookies);
 1656         off = (u_int64_t)io.uio_offset;
 1657         if (io.uio_resid)
 1658                 siz -= io.uio_resid;
 1659 
 1660         if (!cookies && !nd->nd_repstat)
 1661                 nd->nd_repstat = NFSERR_PERM;
 1662         if (nd->nd_flag & ND_NFSV3) {
 1663                 getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 1);
 1664                 if (!nd->nd_repstat)
 1665                         nd->nd_repstat = getret;
 1666         }
 1667 
 1668         /*
 1669          * Handles the failed cases. nd->nd_repstat == 0 past here.
 1670          */
 1671         if (nd->nd_repstat) {
 1672                 vput(vp);
 1673                 free((caddr_t)rbuf, M_TEMP);
 1674                 if (cookies)
 1675                         free((caddr_t)cookies, M_TEMP);
 1676                 if (nd->nd_flag & ND_NFSV3)
 1677                         nfsrv_postopattr(nd, getret, &at);
 1678                 goto out;
 1679         }
 1680         /*
 1681          * If nothing read, return eof
 1682          * rpc reply
 1683          */
 1684         if (siz == 0) {
 1685                 vput(vp);
 1686                 if (nd->nd_flag & ND_NFSV2) {
 1687                         NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
 1688                 } else {
 1689                         nfsrv_postopattr(nd, getret, &at);
 1690                         NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
 1691                         txdr_hyper(at.na_filerev, tl);
 1692                         tl += 2;
 1693                 }
 1694                 *tl++ = newnfs_false;
 1695                 *tl = newnfs_true;
 1696                 FREE((caddr_t)rbuf, M_TEMP);
 1697                 FREE((caddr_t)cookies, M_TEMP);
 1698                 goto out;
 1699         }
 1700 
 1701         /*
 1702          * Check for degenerate cases of nothing useful read.
 1703          * If so go try again
 1704          */
 1705         cpos = rbuf;
 1706         cend = rbuf + siz;
 1707         dp = (struct dirent *)cpos;
 1708         cookiep = cookies;
 1709 
 1710         /*
 1711          * For some reason FreeBSD's ufs_readdir() chooses to back the
 1712          * directory offset up to a block boundary, so it is necessary to
 1713          * skip over the records that precede the requested offset. This
 1714          * requires the assumption that file offset cookies monotonically
 1715          * increase.
 1716          */
 1717         while (cpos < cend && ncookies > 0 &&
 1718             (dp->d_fileno == 0 || dp->d_type == DT_WHT ||
 1719              (is_ufs == 1 && ((u_quad_t)(*cookiep)) <= toff))) {
 1720                 cpos += dp->d_reclen;
 1721                 dp = (struct dirent *)cpos;
 1722                 cookiep++;
 1723                 ncookies--;
 1724         }
 1725         if (cpos >= cend || ncookies == 0) {
 1726                 siz = fullsiz;
 1727                 toff = off;
 1728                 goto again;
 1729         }
 1730         vput(vp);
 1731 
 1732         /*
 1733          * dirlen is the size of the reply, including all XDR and must
 1734          * not exceed cnt. For NFSv2, RFC1094 didn't clearly indicate
 1735          * if the XDR should be included in "count", but to be safe, we do.
 1736          * (Include the two booleans at the end of the reply in dirlen now.)
 1737          */
 1738         if (nd->nd_flag & ND_NFSV3) {
 1739                 nfsrv_postopattr(nd, getret, &at);
 1740                 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
 1741                 txdr_hyper(at.na_filerev, tl);
 1742                 dirlen = NFSX_V3POSTOPATTR + NFSX_VERF + 2 * NFSX_UNSIGNED;
 1743         } else {
 1744                 dirlen = 2 * NFSX_UNSIGNED;
 1745         }
 1746 
 1747         /* Loop through the records and build reply */
 1748         while (cpos < cend && ncookies > 0) {
 1749                 nlen = dp->d_namlen;
 1750                 if (dp->d_fileno != 0 && dp->d_type != DT_WHT &&
 1751                         nlen <= NFS_MAXNAMLEN) {
 1752                         if (nd->nd_flag & ND_NFSV3)
 1753                                 dirlen += (6*NFSX_UNSIGNED + NFSM_RNDUP(nlen));
 1754                         else
 1755                                 dirlen += (4*NFSX_UNSIGNED + NFSM_RNDUP(nlen));
 1756                         if (dirlen > cnt) {
 1757                                 eofflag = 0;
 1758                                 break;
 1759                         }
 1760 
 1761                         /*
 1762                          * Build the directory record xdr from
 1763                          * the dirent entry.
 1764                          */
 1765                         if (nd->nd_flag & ND_NFSV3) {
 1766                                 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
 1767                                 *tl++ = newnfs_true;
 1768                                 *tl++ = 0;
 1769                         } else {
 1770                                 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
 1771                                 *tl++ = newnfs_true;
 1772                         }
 1773                         *tl = txdr_unsigned(dp->d_fileno);
 1774                         (void) nfsm_strtom(nd, dp->d_name, nlen);
 1775                         if (nd->nd_flag & ND_NFSV3) {
 1776                                 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
 1777                                 *tl++ = 0;
 1778                         } else
 1779                                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 1780                         *tl = txdr_unsigned(*cookiep);
 1781                 }
 1782                 cpos += dp->d_reclen;
 1783                 dp = (struct dirent *)cpos;
 1784                 cookiep++;
 1785                 ncookies--;
 1786         }
 1787         if (cpos < cend)
 1788                 eofflag = 0;
 1789         NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
 1790         *tl++ = newnfs_false;
 1791         if (eofflag)
 1792                 *tl = newnfs_true;
 1793         else
 1794                 *tl = newnfs_false;
 1795         FREE((caddr_t)rbuf, M_TEMP);
 1796         FREE((caddr_t)cookies, M_TEMP);
 1797 
 1798 out:
 1799         NFSEXITCODE2(0, nd);
 1800         return (0);
 1801 nfsmout:
 1802         vput(vp);
 1803         NFSEXITCODE2(error, nd);
 1804         return (error);
 1805 }
 1806 
 1807 /*
 1808  * Readdirplus for V3 and Readdir for V4.
 1809  */
 1810 int
 1811 nfsrvd_readdirplus(struct nfsrv_descript *nd, int isdgram,
 1812     struct vnode *vp, struct thread *p, struct nfsexstuff *exp)
 1813 {
 1814         struct dirent *dp;
 1815         u_int32_t *tl;
 1816         int dirlen;
 1817         char *cpos, *cend, *rbuf;
 1818         struct vnode *nvp;
 1819         fhandle_t nfh;
 1820         struct nfsvattr nva, at, *nvap = &nva;
 1821         struct mbuf *mb0, *mb1;
 1822         struct nfsreferral *refp;
 1823         int nlen, r, error = 0, getret = 1, usevget = 1;
 1824         int siz, cnt, fullsiz, eofflag, ncookies, entrycnt;
 1825         caddr_t bpos0, bpos1;
 1826         u_int64_t off, toff, verf;
 1827         u_long *cookies = NULL, *cookiep;
 1828         nfsattrbit_t attrbits, rderrbits, savbits;
 1829         struct uio io;
 1830         struct iovec iv;
 1831         struct componentname cn;
 1832         int at_root, is_ufs, is_zfs, needs_unbusy, supports_nfsv4acls;
 1833         struct mount *mp, *new_mp;
 1834         uint64_t mounted_on_fileno;
 1835 
 1836         if (nd->nd_repstat) {
 1837                 nfsrv_postopattr(nd, getret, &at);
 1838                 goto out;
 1839         }
 1840         NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED);
 1841         off = fxdr_hyper(tl);
 1842         toff = off;
 1843         tl += 2;
 1844         verf = fxdr_hyper(tl);
 1845         tl += 2;
 1846         siz = fxdr_unsigned(int, *tl++);
 1847         cnt = fxdr_unsigned(int, *tl);
 1848 
 1849         /*
 1850          * Use the server's maximum data transfer size as the upper bound
 1851          * on reply datalen.
 1852          */
 1853         if (cnt > NFS_SRVMAXDATA(nd) || cnt < 0)
 1854                 cnt = NFS_SRVMAXDATA(nd);
 1855 
 1856         /*
 1857          * siz is a "hint" of how much directory information (name, fileid,
 1858          * cookie) should be in the reply. At least one client "hints" 0,
 1859          * so I set it to cnt for that case. I also round it up to the
 1860          * next multiple of DIRBLKSIZ.
 1861          * Since the size of a Readdirplus directory entry reply will always
 1862          * be greater than a directory entry returned by VOP_READDIR(), it
 1863          * does not make sense to read more than NFS_SRVMAXDATA() via
 1864          * VOP_READDIR().
 1865          */
 1866         if (siz <= 0)
 1867                 siz = cnt;
 1868         else if (siz > NFS_SRVMAXDATA(nd))
 1869                 siz = NFS_SRVMAXDATA(nd);
 1870         siz = ((siz + DIRBLKSIZ - 1) & ~(DIRBLKSIZ - 1));
 1871 
 1872         if (nd->nd_flag & ND_NFSV4) {
 1873                 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
 1874                 if (error)
 1875                         goto nfsmout;
 1876                 NFSSET_ATTRBIT(&savbits, &attrbits);
 1877                 NFSCLRNOTFILLABLE_ATTRBIT(&attrbits, nd);
 1878                 NFSZERO_ATTRBIT(&rderrbits);
 1879                 NFSSETBIT_ATTRBIT(&rderrbits, NFSATTRBIT_RDATTRERROR);
 1880         } else {
 1881                 NFSZERO_ATTRBIT(&attrbits);
 1882         }
 1883         fullsiz = siz;
 1884         nd->nd_repstat = getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 1);
 1885 #if 0
 1886         if (!nd->nd_repstat) {
 1887             if (off && verf != at.na_filerev) {
 1888                 /*
 1889                  * va_filerev is not sufficient as a cookie verifier,
 1890                  * since it is not supposed to change when entries are
 1891                  * removed/added unless that offset cookies returned to
 1892                  * the client are no longer valid.
 1893                  */
 1894                 if (nd->nd_flag & ND_NFSV4) {
 1895                         nd->nd_repstat = NFSERR_NOTSAME;
 1896                 } else {
 1897                         nd->nd_repstat = NFSERR_BAD_COOKIE;
 1898                 }
 1899             }
 1900         }
 1901 #endif
 1902         if (!nd->nd_repstat && vp->v_type != VDIR)
 1903                 nd->nd_repstat = NFSERR_NOTDIR;
 1904         if (!nd->nd_repstat && cnt == 0)
 1905                 nd->nd_repstat = NFSERR_TOOSMALL;
 1906         if (!nd->nd_repstat)
 1907                 nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
 1908                     nd->nd_cred, exp, p, NFSACCCHK_NOOVERRIDE,
 1909                     NFSACCCHK_VPISLOCKED, NULL);
 1910         if (nd->nd_repstat) {
 1911                 vput(vp);
 1912                 if (nd->nd_flag & ND_NFSV3)
 1913                         nfsrv_postopattr(nd, getret, &at);
 1914                 goto out;
 1915         }
 1916         is_ufs = strcmp(vp->v_mount->mnt_vfc->vfc_name, "ufs") == 0;
 1917         is_zfs = strcmp(vp->v_mount->mnt_vfc->vfc_name, "zfs") == 0;
 1918 
 1919         MALLOC(rbuf, caddr_t, siz, M_TEMP, M_WAITOK);
 1920 again:
 1921         eofflag = 0;
 1922         if (cookies) {
 1923                 free((caddr_t)cookies, M_TEMP);
 1924                 cookies = NULL;
 1925         }
 1926 
 1927         iv.iov_base = rbuf;
 1928         iv.iov_len = siz;
 1929         io.uio_iov = &iv;
 1930         io.uio_iovcnt = 1;
 1931         io.uio_offset = (off_t)off;
 1932         io.uio_resid = siz;
 1933         io.uio_segflg = UIO_SYSSPACE;
 1934         io.uio_rw = UIO_READ;
 1935         io.uio_td = NULL;
 1936         nd->nd_repstat = VOP_READDIR(vp, &io, nd->nd_cred, &eofflag, &ncookies,
 1937             &cookies);
 1938         off = (u_int64_t)io.uio_offset;
 1939         if (io.uio_resid)
 1940                 siz -= io.uio_resid;
 1941 
 1942         getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 1);
 1943 
 1944         if (!cookies && !nd->nd_repstat)
 1945                 nd->nd_repstat = NFSERR_PERM;
 1946         if (!nd->nd_repstat)
 1947                 nd->nd_repstat = getret;
 1948         if (nd->nd_repstat) {
 1949                 vput(vp);
 1950                 if (cookies)
 1951                         free((caddr_t)cookies, M_TEMP);
 1952                 free((caddr_t)rbuf, M_TEMP);
 1953                 if (nd->nd_flag & ND_NFSV3)
 1954                         nfsrv_postopattr(nd, getret, &at);
 1955                 goto out;
 1956         }
 1957         /*
 1958          * If nothing read, return eof
 1959          * rpc reply
 1960          */
 1961         if (siz == 0) {
 1962                 vput(vp);
 1963                 if (nd->nd_flag & ND_NFSV3)
 1964                         nfsrv_postopattr(nd, getret, &at);
 1965                 NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
 1966                 txdr_hyper(at.na_filerev, tl);
 1967                 tl += 2;
 1968                 *tl++ = newnfs_false;
 1969                 *tl = newnfs_true;
 1970                 free((caddr_t)cookies, M_TEMP);
 1971                 free((caddr_t)rbuf, M_TEMP);
 1972                 goto out;
 1973         }
 1974 
 1975         /*
 1976          * Check for degenerate cases of nothing useful read.
 1977          * If so go try again
 1978          */
 1979         cpos = rbuf;
 1980         cend = rbuf + siz;
 1981         dp = (struct dirent *)cpos;
 1982         cookiep = cookies;
 1983 
 1984         /*
 1985          * For some reason FreeBSD's ufs_readdir() chooses to back the
 1986          * directory offset up to a block boundary, so it is necessary to
 1987          * skip over the records that precede the requested offset. This
 1988          * requires the assumption that file offset cookies monotonically
 1989          * increase.
 1990          */
 1991         while (cpos < cend && ncookies > 0 &&
 1992           (dp->d_fileno == 0 || dp->d_type == DT_WHT ||
 1993            (is_ufs == 1 && ((u_quad_t)(*cookiep)) <= toff) ||
 1994            ((nd->nd_flag & ND_NFSV4) &&
 1995             ((dp->d_namlen == 1 && dp->d_name[0] == '.') ||
 1996              (dp->d_namlen==2 && dp->d_name[0]=='.' && dp->d_name[1]=='.'))))) {
 1997                 cpos += dp->d_reclen;
 1998                 dp = (struct dirent *)cpos;
 1999                 cookiep++;
 2000                 ncookies--;
 2001         }
 2002         if (cpos >= cend || ncookies == 0) {
 2003                 siz = fullsiz;
 2004                 toff = off;
 2005                 goto again;
 2006         }
 2007 
 2008         /*
 2009          * Busy the file system so that the mount point won't go away
 2010          * and, as such, VFS_VGET() can be used safely.
 2011          */
 2012         mp = vp->v_mount;
 2013         vfs_ref(mp);
 2014         NFSVOPUNLOCK(vp, 0);
 2015         nd->nd_repstat = vfs_busy(mp, 0);
 2016         vfs_rel(mp);
 2017         if (nd->nd_repstat != 0) {
 2018                 vrele(vp);
 2019                 free(cookies, M_TEMP);
 2020                 free(rbuf, M_TEMP);
 2021                 if (nd->nd_flag & ND_NFSV3)
 2022                         nfsrv_postopattr(nd, getret, &at);
 2023                 goto out;
 2024         }
 2025 
 2026         /*
 2027          * For now ZFS requires VOP_LOOKUP as a workaround.  Until ino_t is changed
 2028          * to 64 bit type a ZFS filesystem with over 1 billion files in it
 2029          * will suffer from 64bit -> 32bit truncation.
 2030          */
 2031         if (is_zfs == 1)
 2032                 usevget = 0;
 2033 
 2034         cn.cn_nameiop = LOOKUP;
 2035         cn.cn_lkflags = LK_SHARED | LK_RETRY;
 2036         cn.cn_cred = nd->nd_cred;
 2037         cn.cn_thread = p;
 2038 
 2039         /*
 2040          * Save this position, in case there is an error before one entry
 2041          * is created.
 2042          */
 2043         mb0 = nd->nd_mb;
 2044         bpos0 = nd->nd_bpos;
 2045 
 2046         /*
 2047          * Fill in the first part of the reply.
 2048          * dirlen is the reply length in bytes and cannot exceed cnt.
 2049          * (Include the two booleans at the end of the reply in dirlen now,
 2050          *  so we recognize when we have exceeded cnt.)
 2051          */
 2052         if (nd->nd_flag & ND_NFSV3) {
 2053                 dirlen = NFSX_V3POSTOPATTR + NFSX_VERF + 2 * NFSX_UNSIGNED;
 2054                 nfsrv_postopattr(nd, getret, &at);
 2055         } else {
 2056                 dirlen = NFSX_VERF + 2 * NFSX_UNSIGNED;
 2057         }
 2058         NFSM_BUILD(tl, u_int32_t *, NFSX_VERF);
 2059         txdr_hyper(at.na_filerev, tl);
 2060 
 2061         /*
 2062          * Save this position, in case there is an empty reply needed.
 2063          */
 2064         mb1 = nd->nd_mb;
 2065         bpos1 = nd->nd_bpos;
 2066 
 2067         /* Loop through the records and build reply */
 2068         entrycnt = 0;
 2069         while (cpos < cend && ncookies > 0 && dirlen < cnt) {
 2070                 nlen = dp->d_namlen;
 2071                 if (dp->d_fileno != 0 && dp->d_type != DT_WHT &&
 2072                     nlen <= NFS_MAXNAMLEN &&
 2073                     ((nd->nd_flag & ND_NFSV3) || nlen > 2 ||
 2074                      (nlen==2 && (dp->d_name[0]!='.' || dp->d_name[1]!='.'))
 2075                       || (nlen == 1 && dp->d_name[0] != '.'))) {
 2076                         /*
 2077                          * Save the current position in the reply, in case
 2078                          * this entry exceeds cnt.
 2079                          */
 2080                         mb1 = nd->nd_mb;
 2081                         bpos1 = nd->nd_bpos;
 2082         
 2083                         /*
 2084                          * For readdir_and_lookup get the vnode using
 2085                          * the file number.
 2086                          */
 2087                         nvp = NULL;
 2088                         refp = NULL;
 2089                         r = 0;
 2090                         at_root = 0;
 2091                         needs_unbusy = 0;
 2092                         new_mp = mp;
 2093                         mounted_on_fileno = (uint64_t)dp->d_fileno;
 2094                         if ((nd->nd_flag & ND_NFSV3) ||
 2095                             NFSNONZERO_ATTRBIT(&savbits)) {
 2096                                 if (nd->nd_flag & ND_NFSV4)
 2097                                         refp = nfsv4root_getreferral(NULL,
 2098                                             vp, dp->d_fileno);
 2099                                 if (refp == NULL) {
 2100                                         if (usevget)
 2101                                                 r = VFS_VGET(mp, dp->d_fileno,
 2102                                                     LK_SHARED, &nvp);
 2103                                         else
 2104                                                 r = EOPNOTSUPP;
 2105                                         if (r == EOPNOTSUPP) {
 2106                                                 usevget = 0;
 2107                                                 cn.cn_nameptr = dp->d_name;
 2108                                                 cn.cn_namelen = nlen;
 2109                                                 cn.cn_flags = ISLASTCN |
 2110                                                     NOFOLLOW | LOCKLEAF;
 2111                                                 if (nlen == 2 &&
 2112                                                     dp->d_name[0] == '.' &&
 2113                                                     dp->d_name[1] == '.')
 2114                                                         cn.cn_flags |=
 2115                                                             ISDOTDOT;
 2116                                                 if (NFSVOPLOCK(vp, LK_SHARED)
 2117                                                     != 0) {
 2118                                                         nd->nd_repstat = EPERM;
 2119                                                         break;
 2120                                                 }
 2121                                                 if ((vp->v_vflag & VV_ROOT) != 0
 2122                                                     && (cn.cn_flags & ISDOTDOT)
 2123                                                     != 0) {
 2124                                                         vref(vp);
 2125                                                         nvp = vp;
 2126                                                         r = 0;
 2127                                                 } else {
 2128                                                         r = VOP_LOOKUP(vp, &nvp,
 2129                                                             &cn);
 2130                                                         if (vp != nvp)
 2131                                                                 NFSVOPUNLOCK(vp,
 2132                                                                     0);
 2133                                                 }
 2134                                         }
 2135 
 2136                                         /*
 2137                                          * For NFSv4, check to see if nvp is
 2138                                          * a mount point and get the mount
 2139                                          * point vnode, as required.
 2140                                          */
 2141                                         if (r == 0 &&
 2142                                             nfsrv_enable_crossmntpt != 0 &&
 2143                                             (nd->nd_flag & ND_NFSV4) != 0 &&
 2144                                             nvp->v_type == VDIR &&
 2145                                             nvp->v_mountedhere != NULL) {
 2146                                                 new_mp = nvp->v_mountedhere;
 2147                                                 r = vfs_busy(new_mp, 0);
 2148                                                 vput(nvp);
 2149                                                 nvp = NULL;
 2150                                                 if (r == 0) {
 2151                                                         r = VFS_ROOT(new_mp,
 2152                                                             LK_SHARED, &nvp);
 2153                                                         needs_unbusy = 1;
 2154                                                         if (r == 0)
 2155                                                                 at_root = 1;
 2156                                                 }
 2157                                         }
 2158                                 }
 2159 
 2160                                 /*
 2161                                  * If we failed to look up the entry, then it
 2162                                  * has become invalid, most likely removed.
 2163                                  */
 2164                                 if (r != 0) {
 2165                                         if (needs_unbusy)
 2166                                                 vfs_unbusy(new_mp);
 2167                                         goto invalid;
 2168                                 }
 2169                                 KASSERT(refp != NULL || nvp != NULL,
 2170                                     ("%s: undetected lookup error", __func__));
 2171 
 2172                                 if (refp == NULL &&
 2173                                     ((nd->nd_flag & ND_NFSV3) ||
 2174                                      NFSNONZERO_ATTRBIT(&attrbits))) {
 2175                                         r = nfsvno_getfh(nvp, &nfh, p);
 2176                                         if (!r)
 2177                                             r = nfsvno_getattr(nvp, nvap,
 2178                                                 nd->nd_cred, p, 1);
 2179                                         if (r == 0 && is_zfs == 1 &&
 2180                                             nfsrv_enable_crossmntpt != 0 &&
 2181                                             (nd->nd_flag & ND_NFSV4) != 0 &&
 2182                                             nvp->v_type == VDIR &&
 2183                                             vp->v_mount != nvp->v_mount) {
 2184                                             /*
 2185                                              * For a ZFS snapshot, there is a
 2186                                              * pseudo mount that does not set
 2187                                              * v_mountedhere, so it needs to
 2188                                              * be detected via a different
 2189                                              * mount structure.
 2190                                              */
 2191                                             at_root = 1;
 2192                                             if (new_mp == mp)
 2193                                                 new_mp = nvp->v_mount;
 2194                                         }
 2195                                 }
 2196 
 2197                                 /*
 2198                                  * If we failed to get attributes of the entry,
 2199                                  * then just skip it for NFSv3 (the traditional
 2200                                  * behavior in the old NFS server).
 2201                                  * For NFSv4 the behavior is controlled by
 2202                                  * RDATTRERROR: we either ignore the error or
 2203                                  * fail the request.
 2204                                  * Note that RDATTRERROR is never set for NFSv3.
 2205                                  */
 2206                                 if (r != 0) {
 2207                                         if (!NFSISSET_ATTRBIT(&attrbits,
 2208                                             NFSATTRBIT_RDATTRERROR)) {
 2209                                                 vput(nvp);
 2210                                                 if (needs_unbusy != 0)
 2211                                                         vfs_unbusy(new_mp);
 2212                                                 if ((nd->nd_flag & ND_NFSV3))
 2213                                                         goto invalid;
 2214                                                 nd->nd_repstat = r;
 2215                                                 break;
 2216                                         }
 2217                                 }
 2218                         }
 2219 
 2220                         /*
 2221                          * Build the directory record xdr
 2222                          */
 2223                         if (nd->nd_flag & ND_NFSV3) {
 2224                                 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
 2225                                 *tl++ = newnfs_true;
 2226                                 *tl++ = 0;
 2227                                 *tl = txdr_unsigned(dp->d_fileno);
 2228                                 dirlen += nfsm_strtom(nd, dp->d_name, nlen);
 2229                                 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
 2230                                 *tl++ = 0;
 2231                                 *tl = txdr_unsigned(*cookiep);
 2232                                 nfsrv_postopattr(nd, 0, nvap);
 2233                                 dirlen += nfsm_fhtom(nd,(u_int8_t *)&nfh,0,1);
 2234                                 dirlen += (5*NFSX_UNSIGNED+NFSX_V3POSTOPATTR);
 2235                                 if (nvp != NULL)
 2236                                         vput(nvp);
 2237                         } else {
 2238                                 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
 2239                                 *tl++ = newnfs_true;
 2240                                 *tl++ = 0;
 2241                                 *tl = txdr_unsigned(*cookiep);
 2242                                 dirlen += nfsm_strtom(nd, dp->d_name, nlen);
 2243                                 if (nvp != NULL) {
 2244                                         supports_nfsv4acls =
 2245                                             nfs_supportsnfsv4acls(nvp);
 2246                                         NFSVOPUNLOCK(nvp, 0);
 2247                                 } else
 2248                                         supports_nfsv4acls = 0;
 2249                                 if (refp != NULL) {
 2250                                         dirlen += nfsrv_putreferralattr(nd,
 2251                                             &savbits, refp, 0,
 2252                                             &nd->nd_repstat);
 2253                                         if (nd->nd_repstat) {
 2254                                                 if (nvp != NULL)
 2255                                                         vrele(nvp);
 2256                                                 if (needs_unbusy != 0)
 2257                                                         vfs_unbusy(new_mp);
 2258                                                 break;
 2259                                         }
 2260                                 } else if (r) {
 2261                                         dirlen += nfsvno_fillattr(nd, new_mp,
 2262                                             nvp, nvap, &nfh, r, &rderrbits,
 2263                                             nd->nd_cred, p, isdgram, 0,
 2264                                             supports_nfsv4acls, at_root,
 2265                                             mounted_on_fileno);
 2266                                 } else {
 2267                                         dirlen += nfsvno_fillattr(nd, new_mp,
 2268                                             nvp, nvap, &nfh, r, &attrbits,
 2269                                             nd->nd_cred, p, isdgram, 0,
 2270                                             supports_nfsv4acls, at_root,
 2271                                             mounted_on_fileno);
 2272                                 }
 2273                                 if (nvp != NULL)
 2274                                         vrele(nvp);
 2275                                 dirlen += (3 * NFSX_UNSIGNED);
 2276                         }
 2277                         if (needs_unbusy != 0)
 2278                                 vfs_unbusy(new_mp);
 2279                         if (dirlen <= cnt)
 2280                                 entrycnt++;
 2281                 }
 2282 invalid:
 2283                 cpos += dp->d_reclen;
 2284                 dp = (struct dirent *)cpos;
 2285                 cookiep++;
 2286                 ncookies--;
 2287         }
 2288         vrele(vp);
 2289         vfs_unbusy(mp);
 2290 
 2291         /*
 2292          * If dirlen > cnt, we must strip off the last entry. If that
 2293          * results in an empty reply, report NFSERR_TOOSMALL.
 2294          */
 2295         if (dirlen > cnt || nd->nd_repstat) {
 2296                 if (!nd->nd_repstat && entrycnt == 0)
 2297                         nd->nd_repstat = NFSERR_TOOSMALL;
 2298                 if (nd->nd_repstat) {
 2299                         newnfs_trimtrailing(nd, mb0, bpos0);
 2300                         if (nd->nd_flag & ND_NFSV3)
 2301                                 nfsrv_postopattr(nd, getret, &at);
 2302                 } else
 2303                         newnfs_trimtrailing(nd, mb1, bpos1);
 2304                 eofflag = 0;
 2305         } else if (cpos < cend)
 2306                 eofflag = 0;
 2307         if (!nd->nd_repstat) {
 2308                 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
 2309                 *tl++ = newnfs_false;
 2310                 if (eofflag)
 2311                         *tl = newnfs_true;
 2312                 else
 2313                         *tl = newnfs_false;
 2314         }
 2315         FREE((caddr_t)cookies, M_TEMP);
 2316         FREE((caddr_t)rbuf, M_TEMP);
 2317 
 2318 out:
 2319         NFSEXITCODE2(0, nd);
 2320         return (0);
 2321 nfsmout:
 2322         vput(vp);
 2323         NFSEXITCODE2(error, nd);
 2324         return (error);
 2325 }
 2326 
 2327 /*
 2328  * Get the settable attributes out of the mbuf list.
 2329  * (Return 0 or EBADRPC)
 2330  */
 2331 int
 2332 nfsrv_sattr(struct nfsrv_descript *nd, vnode_t vp, struct nfsvattr *nvap,
 2333     nfsattrbit_t *attrbitp, NFSACL_T *aclp, struct thread *p)
 2334 {
 2335         u_int32_t *tl;
 2336         struct nfsv2_sattr *sp;
 2337         int error = 0, toclient = 0;
 2338 
 2339         switch (nd->nd_flag & (ND_NFSV2 | ND_NFSV3 | ND_NFSV4)) {
 2340         case ND_NFSV2:
 2341                 NFSM_DISSECT(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
 2342                 /*
 2343                  * Some old clients didn't fill in the high order 16bits.
 2344                  * --> check the low order 2 bytes for 0xffff
 2345                  */
 2346                 if ((fxdr_unsigned(int, sp->sa_mode) & 0xffff) != 0xffff)
 2347                         nvap->na_mode = nfstov_mode(sp->sa_mode);
 2348                 if (sp->sa_uid != newnfs_xdrneg1)
 2349                         nvap->na_uid = fxdr_unsigned(uid_t, sp->sa_uid);
 2350                 if (sp->sa_gid != newnfs_xdrneg1)
 2351                         nvap->na_gid = fxdr_unsigned(gid_t, sp->sa_gid);
 2352                 if (sp->sa_size != newnfs_xdrneg1)
 2353                         nvap->na_size = fxdr_unsigned(u_quad_t, sp->sa_size);
 2354                 if (sp->sa_atime.nfsv2_sec != newnfs_xdrneg1) {
 2355 #ifdef notyet
 2356                         fxdr_nfsv2time(&sp->sa_atime, &nvap->na_atime);
 2357 #else
 2358                         nvap->na_atime.tv_sec =
 2359                                 fxdr_unsigned(u_int32_t,sp->sa_atime.nfsv2_sec);
 2360                         nvap->na_atime.tv_nsec = 0;
 2361 #endif
 2362                 }
 2363                 if (sp->sa_mtime.nfsv2_sec != newnfs_xdrneg1)
 2364                         fxdr_nfsv2time(&sp->sa_mtime, &nvap->na_mtime);
 2365                 break;
 2366         case ND_NFSV3:
 2367                 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 2368                 if (*tl == newnfs_true) {
 2369                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 2370                         nvap->na_mode = nfstov_mode(*tl);
 2371                 }
 2372                 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 2373                 if (*tl == newnfs_true) {
 2374                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 2375                         nvap->na_uid = fxdr_unsigned(uid_t, *tl);
 2376                 }
 2377                 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 2378                 if (*tl == newnfs_true) {
 2379                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 2380                         nvap->na_gid = fxdr_unsigned(gid_t, *tl);
 2381                 }
 2382                 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 2383                 if (*tl == newnfs_true) {
 2384                         NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
 2385                         nvap->na_size = fxdr_hyper(tl);
 2386                 }
 2387                 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 2388                 switch (fxdr_unsigned(int, *tl)) {
 2389                 case NFSV3SATTRTIME_TOCLIENT:
 2390                         NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
 2391                         fxdr_nfsv3time(tl, &nvap->na_atime);
 2392                         toclient = 1;
 2393                         break;
 2394                 case NFSV3SATTRTIME_TOSERVER:
 2395                         vfs_timestamp(&nvap->na_atime);
 2396                         nvap->na_vaflags |= VA_UTIMES_NULL;
 2397                         break;
 2398                 }
 2399                 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 2400                 switch (fxdr_unsigned(int, *tl)) {
 2401                 case NFSV3SATTRTIME_TOCLIENT:
 2402                         NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
 2403                         fxdr_nfsv3time(tl, &nvap->na_mtime);
 2404                         nvap->na_vaflags &= ~VA_UTIMES_NULL;
 2405                         break;
 2406                 case NFSV3SATTRTIME_TOSERVER:
 2407                         vfs_timestamp(&nvap->na_mtime);
 2408                         if (!toclient)
 2409                                 nvap->na_vaflags |= VA_UTIMES_NULL;
 2410                         break;
 2411                 }
 2412                 break;
 2413         case ND_NFSV4:
 2414                 error = nfsv4_sattr(nd, vp, nvap, attrbitp, aclp, p);
 2415         }
 2416 nfsmout:
 2417         NFSEXITCODE2(error, nd);
 2418         return (error);
 2419 }
 2420 
 2421 /*
 2422  * Handle the setable attributes for V4.
 2423  * Returns NFSERR_BADXDR if it can't be parsed, 0 otherwise.
 2424  */
 2425 int
 2426 nfsv4_sattr(struct nfsrv_descript *nd, vnode_t vp, struct nfsvattr *nvap,
 2427     nfsattrbit_t *attrbitp, NFSACL_T *aclp, struct thread *p)
 2428 {
 2429         u_int32_t *tl;
 2430         int attrsum = 0;
 2431         int i, j;
 2432         int error, attrsize, bitpos, aclsize, aceerr, retnotsup = 0;
 2433         int moderet, toclient = 0;
 2434         u_char *cp, namestr[NFSV4_SMALLSTR + 1];
 2435         uid_t uid;
 2436         gid_t gid;
 2437         u_short mode, mask;             /* Same type as va_mode. */
 2438         struct vattr va;
 2439 
 2440         error = nfsrv_getattrbits(nd, attrbitp, NULL, &retnotsup);
 2441         if (error)
 2442                 goto nfsmout;
 2443         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 2444         attrsize = fxdr_unsigned(int, *tl);
 2445 
 2446         /*
 2447          * Loop around getting the setable attributes. If an unsupported
 2448          * one is found, set nd_repstat == NFSERR_ATTRNOTSUPP and return.
 2449          */
 2450         if (retnotsup) {
 2451                 nd->nd_repstat = NFSERR_ATTRNOTSUPP;
 2452                 bitpos = NFSATTRBIT_MAX;
 2453         } else {
 2454                 bitpos = 0;
 2455         }
 2456         moderet = 0;
 2457         for (; bitpos < NFSATTRBIT_MAX; bitpos++) {
 2458             if (attrsum > attrsize) {
 2459                 error = NFSERR_BADXDR;
 2460                 goto nfsmout;
 2461             }
 2462             if (NFSISSET_ATTRBIT(attrbitp, bitpos))
 2463                 switch (bitpos) {
 2464                 case NFSATTRBIT_SIZE:
 2465                         NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
 2466                      if (vp != NULL && vp->v_type != VREG) {
 2467                             error = (vp->v_type == VDIR) ? NFSERR_ISDIR :
 2468                                 NFSERR_INVAL;
 2469                             goto nfsmout;
 2470                         }
 2471                         nvap->na_size = fxdr_hyper(tl);
 2472                         attrsum += NFSX_HYPER;
 2473                         break;
 2474                 case NFSATTRBIT_ACL:
 2475                         error = nfsrv_dissectacl(nd, aclp, &aceerr, &aclsize,
 2476                             p);
 2477                         if (error)
 2478                                 goto nfsmout;
 2479                         if (aceerr && !nd->nd_repstat)
 2480                                 nd->nd_repstat = aceerr;
 2481                         attrsum += aclsize;
 2482                         break;
 2483                 case NFSATTRBIT_ARCHIVE:
 2484                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 2485                         if (!nd->nd_repstat)
 2486                                 nd->nd_repstat = NFSERR_ATTRNOTSUPP;
 2487                         attrsum += NFSX_UNSIGNED;
 2488                         break;
 2489                 case NFSATTRBIT_HIDDEN:
 2490                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 2491                         if (!nd->nd_repstat)
 2492                                 nd->nd_repstat = NFSERR_ATTRNOTSUPP;
 2493                         attrsum += NFSX_UNSIGNED;
 2494                         break;
 2495                 case NFSATTRBIT_MIMETYPE:
 2496                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 2497                         i = fxdr_unsigned(int, *tl);
 2498                         error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
 2499                         if (error)
 2500                                 goto nfsmout;
 2501                         if (!nd->nd_repstat)
 2502                                 nd->nd_repstat = NFSERR_ATTRNOTSUPP;
 2503                         attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(i));
 2504                         break;
 2505                 case NFSATTRBIT_MODE:
 2506                         moderet = NFSERR_INVAL; /* Can't do MODESETMASKED. */
 2507                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 2508                         nvap->na_mode = nfstov_mode(*tl);
 2509                         attrsum += NFSX_UNSIGNED;
 2510                         break;
 2511                 case NFSATTRBIT_OWNER:
 2512                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 2513                         j = fxdr_unsigned(int, *tl);
 2514                         if (j < 0) {
 2515                                 error = NFSERR_BADXDR;
 2516                                 goto nfsmout;
 2517                         }
 2518                         if (j > NFSV4_SMALLSTR)
 2519                                 cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
 2520                         else
 2521                                 cp = namestr;
 2522                         error = nfsrv_mtostr(nd, cp, j);
 2523                         if (error) {
 2524                                 if (j > NFSV4_SMALLSTR)
 2525                                         free(cp, M_NFSSTRING);
 2526                                 goto nfsmout;
 2527                         }
 2528                         if (!nd->nd_repstat) {
 2529                                 nd->nd_repstat = nfsv4_strtouid(nd, cp, j, &uid,
 2530                                     p);
 2531                                 if (!nd->nd_repstat)
 2532                                         nvap->na_uid = uid;
 2533                         }
 2534                         if (j > NFSV4_SMALLSTR)
 2535                                 free(cp, M_NFSSTRING);
 2536                         attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
 2537                         break;
 2538                 case NFSATTRBIT_OWNERGROUP:
 2539                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 2540                         j = fxdr_unsigned(int, *tl);
 2541                         if (j < 0) {
 2542                                 error = NFSERR_BADXDR;
 2543                                 goto nfsmout;
 2544                         }
 2545                         if (j > NFSV4_SMALLSTR)
 2546                                 cp = malloc(j + 1, M_NFSSTRING, M_WAITOK);
 2547                         else
 2548                                 cp = namestr;
 2549                         error = nfsrv_mtostr(nd, cp, j);
 2550                         if (error) {
 2551                                 if (j > NFSV4_SMALLSTR)
 2552                                         free(cp, M_NFSSTRING);
 2553                                 goto nfsmout;
 2554                         }
 2555                         if (!nd->nd_repstat) {
 2556                                 nd->nd_repstat = nfsv4_strtogid(nd, cp, j, &gid,
 2557                                     p);
 2558                                 if (!nd->nd_repstat)
 2559                                         nvap->na_gid = gid;
 2560                         }
 2561                         if (j > NFSV4_SMALLSTR)
 2562                                 free(cp, M_NFSSTRING);
 2563                         attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j));
 2564                         break;
 2565                 case NFSATTRBIT_SYSTEM:
 2566                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 2567                         if (!nd->nd_repstat)
 2568                                 nd->nd_repstat = NFSERR_ATTRNOTSUPP;
 2569                         attrsum += NFSX_UNSIGNED;
 2570                         break;
 2571                 case NFSATTRBIT_TIMEACCESSSET:
 2572                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 2573                         attrsum += NFSX_UNSIGNED;
 2574                         if (fxdr_unsigned(int, *tl)==NFSV4SATTRTIME_TOCLIENT) {
 2575                             NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
 2576                             fxdr_nfsv4time(tl, &nvap->na_atime);
 2577                             toclient = 1;
 2578                             attrsum += NFSX_V4TIME;
 2579                         } else {
 2580                             vfs_timestamp(&nvap->na_atime);
 2581                             nvap->na_vaflags |= VA_UTIMES_NULL;
 2582                         }
 2583                         break;
 2584                 case NFSATTRBIT_TIMEBACKUP:
 2585                         NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
 2586                         if (!nd->nd_repstat)
 2587                                 nd->nd_repstat = NFSERR_ATTRNOTSUPP;
 2588                         attrsum += NFSX_V4TIME;
 2589                         break;
 2590                 case NFSATTRBIT_TIMECREATE:
 2591                         NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
 2592                         if (!nd->nd_repstat)
 2593                                 nd->nd_repstat = NFSERR_ATTRNOTSUPP;
 2594                         attrsum += NFSX_V4TIME;
 2595                         break;
 2596                 case NFSATTRBIT_TIMEMODIFYSET:
 2597                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 2598                         attrsum += NFSX_UNSIGNED;
 2599                         if (fxdr_unsigned(int, *tl)==NFSV4SATTRTIME_TOCLIENT) {
 2600                             NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME);
 2601                             fxdr_nfsv4time(tl, &nvap->na_mtime);
 2602                             nvap->na_vaflags &= ~VA_UTIMES_NULL;
 2603                             attrsum += NFSX_V4TIME;
 2604                         } else {
 2605                             vfs_timestamp(&nvap->na_mtime);
 2606                             if (!toclient)
 2607                                 nvap->na_vaflags |= VA_UTIMES_NULL;
 2608                         }
 2609                         break;
 2610                 case NFSATTRBIT_MODESETMASKED:
 2611                         NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
 2612                         mode = fxdr_unsigned(u_short, *tl++);
 2613                         mask = fxdr_unsigned(u_short, *tl);
 2614                         /*
 2615                          * vp == NULL implies an Open/Create operation.
 2616                          * This attribute can only be used for Setattr and
 2617                          * only for NFSv4.1 or higher.
 2618                          * If moderet != 0, a mode attribute has also been
 2619                          * specified and this attribute cannot be done in the
 2620                          * same Setattr operation.
 2621                          */
 2622                         if ((nd->nd_flag & ND_NFSV41) == 0)
 2623                                 nd->nd_repstat = NFSERR_ATTRNOTSUPP;
 2624                         else if ((mode & ~07777) != 0 || (mask & ~07777) != 0 ||
 2625                             vp == NULL)
 2626                                 nd->nd_repstat = NFSERR_INVAL;
 2627                         else if (moderet == 0)
 2628                                 moderet = VOP_GETATTR(vp, &va, nd->nd_cred);
 2629                         if (moderet == 0)
 2630                                 nvap->na_mode = (mode & mask) |
 2631                                     (va.va_mode & ~mask);
 2632                         else
 2633                                 nd->nd_repstat = moderet;
 2634                         attrsum += 2 * NFSX_UNSIGNED;
 2635                         break;
 2636                 default:
 2637                         nd->nd_repstat = NFSERR_ATTRNOTSUPP;
 2638                         /*
 2639                          * set bitpos so we drop out of the loop.
 2640                          */
 2641                         bitpos = NFSATTRBIT_MAX;
 2642                         break;
 2643                 }
 2644         }
 2645 
 2646         /*
 2647          * some clients pad the attrlist, so we need to skip over the
 2648          * padding.
 2649          */
 2650         if (attrsum > attrsize) {
 2651                 error = NFSERR_BADXDR;
 2652         } else {
 2653                 attrsize = NFSM_RNDUP(attrsize);
 2654                 if (attrsum < attrsize)
 2655                         error = nfsm_advance(nd, attrsize - attrsum, -1);
 2656         }
 2657 nfsmout:
 2658         NFSEXITCODE2(error, nd);
 2659         return (error);
 2660 }
 2661 
 2662 /*
 2663  * Check/setup export credentials.
 2664  */
 2665 int
 2666 nfsd_excred(struct nfsrv_descript *nd, struct nfsexstuff *exp,
 2667     struct ucred *credanon)
 2668 {
 2669         int error = 0;
 2670 
 2671         /*
 2672          * Check/setup credentials.
 2673          */
 2674         if (nd->nd_flag & ND_GSS)
 2675                 exp->nes_exflag &= ~MNT_EXPORTANON;
 2676 
 2677         /*
 2678          * Check to see if the operation is allowed for this security flavor.
 2679          * RFC2623 suggests that the NFSv3 Fsinfo RPC be allowed to
 2680          * AUTH_NONE or AUTH_SYS for file systems requiring RPCSEC_GSS.
 2681          * Also, allow Secinfo, so that it can acquire the correct flavor(s).
 2682          */
 2683         if (nfsvno_testexp(nd, exp) &&
 2684             nd->nd_procnum != NFSV4OP_SECINFO &&
 2685             nd->nd_procnum != NFSPROC_FSINFO) {
 2686                 if (nd->nd_flag & ND_NFSV4)
 2687                         error = NFSERR_WRONGSEC;
 2688                 else
 2689                         error = (NFSERR_AUTHERR | AUTH_TOOWEAK);
 2690                 goto out;
 2691         }
 2692 
 2693         /*
 2694          * Check to see if the file system is exported V4 only.
 2695          */
 2696         if (NFSVNO_EXV4ONLY(exp) && !(nd->nd_flag & ND_NFSV4)) {
 2697                 error = NFSERR_PROGNOTV4;
 2698                 goto out;
 2699         }
 2700 
 2701         /*
 2702          * Now, map the user credentials.
 2703          * (Note that ND_AUTHNONE will only be set for an NFSv3
 2704          *  Fsinfo RPC. If set for anything else, this code might need
 2705          *  to change.)
 2706          */
 2707         if (NFSVNO_EXPORTED(exp)) {
 2708                 if (((nd->nd_flag & ND_GSS) == 0 && nd->nd_cred->cr_uid == 0) ||
 2709                      NFSVNO_EXPORTANON(exp) ||
 2710                      (nd->nd_flag & ND_AUTHNONE) != 0) {
 2711                         nd->nd_cred->cr_uid = credanon->cr_uid;
 2712                         nd->nd_cred->cr_gid = credanon->cr_gid;
 2713                         crsetgroups(nd->nd_cred, credanon->cr_ngroups,
 2714                             credanon->cr_groups);
 2715                 } else if ((nd->nd_flag & ND_GSS) == 0) {
 2716                         /*
 2717                          * If using AUTH_SYS, call nfsrv_getgrpscred() to see
 2718                          * if there is a replacement credential with a group
 2719                          * list set up by "nfsuserd -manage-gids".
 2720                          * If there is no replacement, nfsrv_getgrpscred()
 2721                          * simply returns its argument.
 2722                          */
 2723                         nd->nd_cred = nfsrv_getgrpscred(nd->nd_cred);
 2724                 }
 2725         }
 2726 
 2727 out:
 2728         NFSEXITCODE2(error, nd);
 2729         return (error);
 2730 }
 2731 
 2732 /*
 2733  * Check exports.
 2734  */
 2735 int
 2736 nfsvno_checkexp(struct mount *mp, struct sockaddr *nam, struct nfsexstuff *exp,
 2737     struct ucred **credp)
 2738 {
 2739         int i, error, *secflavors;
 2740 
 2741         error = VFS_CHECKEXP(mp, nam, &exp->nes_exflag, credp,
 2742             &exp->nes_numsecflavor, &secflavors);
 2743         if (error) {
 2744                 if (nfs_rootfhset) {
 2745                         exp->nes_exflag = 0;
 2746                         exp->nes_numsecflavor = 0;
 2747                         error = 0;
 2748                 }
 2749         } else if (exp->nes_numsecflavor < 1 || exp->nes_numsecflavor >
 2750             MAXSECFLAVORS) {
 2751                 printf("nfsvno_checkexp: numsecflavors out of range\n");
 2752                 exp->nes_numsecflavor = 0;
 2753                 error = EACCES;
 2754         } else {
 2755                 /* Copy the security flavors. */
 2756                 for (i = 0; i < exp->nes_numsecflavor; i++)
 2757                         exp->nes_secflavors[i] = secflavors[i];
 2758         }
 2759         NFSEXITCODE(error);
 2760         return (error);
 2761 }
 2762 
 2763 /*
 2764  * Get a vnode for a file handle and export stuff.
 2765  */
 2766 int
 2767 nfsvno_fhtovp(struct mount *mp, fhandle_t *fhp, struct sockaddr *nam,
 2768     int lktype, struct vnode **vpp, struct nfsexstuff *exp,
 2769     struct ucred **credp)
 2770 {
 2771         int i, error, *secflavors;
 2772 
 2773         *credp = NULL;
 2774         exp->nes_numsecflavor = 0;
 2775         error = VFS_FHTOVP(mp, &fhp->fh_fid, lktype, vpp);
 2776         if (error != 0)
 2777                 /* Make sure the server replies ESTALE to the client. */
 2778                 error = ESTALE;
 2779         if (nam && !error) {
 2780                 error = VFS_CHECKEXP(mp, nam, &exp->nes_exflag, credp,
 2781                     &exp->nes_numsecflavor, &secflavors);
 2782                 if (error) {
 2783                         if (nfs_rootfhset) {
 2784                                 exp->nes_exflag = 0;
 2785                                 exp->nes_numsecflavor = 0;
 2786                                 error = 0;
 2787                         } else {
 2788                                 vput(*vpp);
 2789                         }
 2790                 } else if (exp->nes_numsecflavor < 1 || exp->nes_numsecflavor >
 2791                     MAXSECFLAVORS) {
 2792                         printf("nfsvno_fhtovp: numsecflavors out of range\n");
 2793                         exp->nes_numsecflavor = 0;
 2794                         error = EACCES;
 2795                         vput(*vpp);
 2796                 } else {
 2797                         /* Copy the security flavors. */
 2798                         for (i = 0; i < exp->nes_numsecflavor; i++)
 2799                                 exp->nes_secflavors[i] = secflavors[i];
 2800                 }
 2801         }
 2802         NFSEXITCODE(error);
 2803         return (error);
 2804 }
 2805 
 2806 /*
 2807  * nfsd_fhtovp() - convert a fh to a vnode ptr
 2808  *      - look up fsid in mount list (if not found ret error)
 2809  *      - get vp and export rights by calling nfsvno_fhtovp()
 2810  *      - if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon
 2811  *        for AUTH_SYS
 2812  *      - if mpp != NULL, return the mount point so that it can
 2813  *        be used for vn_finished_write() by the caller
 2814  */
 2815 void
 2816 nfsd_fhtovp(struct nfsrv_descript *nd, struct nfsrvfh *nfp, int lktype,
 2817     struct vnode **vpp, struct nfsexstuff *exp,
 2818     struct mount **mpp, int startwrite, struct thread *p)
 2819 {
 2820         struct mount *mp;
 2821         struct ucred *credanon;
 2822         fhandle_t *fhp;
 2823 
 2824         fhp = (fhandle_t *)nfp->nfsrvfh_data;
 2825         /*
 2826          * Check for the special case of the nfsv4root_fh.
 2827          */
 2828         mp = vfs_busyfs(&fhp->fh_fsid);
 2829         if (mpp != NULL)
 2830                 *mpp = mp;
 2831         if (mp == NULL) {
 2832                 *vpp = NULL;
 2833                 nd->nd_repstat = ESTALE;
 2834                 goto out;
 2835         }
 2836 
 2837         if (startwrite) {
 2838                 vn_start_write(NULL, mpp, V_WAIT);
 2839                 if (lktype == LK_SHARED && !(MNT_SHARED_WRITES(mp)))
 2840                         lktype = LK_EXCLUSIVE;
 2841         }
 2842         nd->nd_repstat = nfsvno_fhtovp(mp, fhp, nd->nd_nam, lktype, vpp, exp,
 2843             &credanon);
 2844         vfs_unbusy(mp);
 2845 
 2846         /*
 2847          * For NFSv4 without a pseudo root fs, unexported file handles
 2848          * can be returned, so that Lookup works everywhere.
 2849          */
 2850         if (!nd->nd_repstat && exp->nes_exflag == 0 &&
 2851             !(nd->nd_flag & ND_NFSV4)) {
 2852                 vput(*vpp);
 2853                 nd->nd_repstat = EACCES;
 2854         }
 2855 
 2856         /*
 2857          * Personally, I've never seen any point in requiring a
 2858          * reserved port#, since only in the rare case where the
 2859          * clients are all boxes with secure system privileges,
 2860          * does it provide any enhanced security, but... some people
 2861          * believe it to be useful and keep putting this code back in.
 2862          * (There is also some "security checker" out there that
 2863          *  complains if the nfs server doesn't enforce this.)
 2864          * However, note the following:
 2865          * RFC3530 (NFSv4) specifies that a reserved port# not be
 2866          *      required.
 2867          * RFC2623 recommends that, if a reserved port# is checked for,
 2868          *      that there be a way to turn that off--> ifdef'd.
 2869          */
 2870 #ifdef NFS_REQRSVPORT
 2871         if (!nd->nd_repstat) {
 2872                 struct sockaddr_in *saddr;
 2873                 struct sockaddr_in6 *saddr6;
 2874 
 2875                 saddr = NFSSOCKADDR(nd->nd_nam, struct sockaddr_in *);
 2876                 saddr6 = NFSSOCKADDR(nd->nd_nam, struct sockaddr_in6 *);
 2877                 if (!(nd->nd_flag & ND_NFSV4) &&
 2878                     ((saddr->sin_family == AF_INET &&
 2879                       ntohs(saddr->sin_port) >= IPPORT_RESERVED) ||
 2880                      (saddr6->sin6_family == AF_INET6 &&
 2881                       ntohs(saddr6->sin6_port) >= IPPORT_RESERVED))) {
 2882                         vput(*vpp);
 2883                         nd->nd_repstat = (NFSERR_AUTHERR | AUTH_TOOWEAK);
 2884                 }
 2885         }
 2886 #endif  /* NFS_REQRSVPORT */
 2887 
 2888         /*
 2889          * Check/setup credentials.
 2890          */
 2891         if (!nd->nd_repstat) {
 2892                 nd->nd_saveduid = nd->nd_cred->cr_uid;
 2893                 nd->nd_repstat = nfsd_excred(nd, exp, credanon);
 2894                 if (nd->nd_repstat)
 2895                         vput(*vpp);
 2896         }
 2897         if (credanon != NULL)
 2898                 crfree(credanon);
 2899         if (nd->nd_repstat) {
 2900                 if (startwrite)
 2901                         vn_finished_write(mp);
 2902                 *vpp = NULL;
 2903                 if (mpp != NULL)
 2904                         *mpp = NULL;
 2905         }
 2906 
 2907 out:
 2908         NFSEXITCODE2(0, nd);
 2909 }
 2910 
 2911 /*
 2912  * glue for fp.
 2913  */
 2914 static int
 2915 fp_getfvp(struct thread *p, int fd, struct file **fpp, struct vnode **vpp)
 2916 {
 2917         struct filedesc *fdp;
 2918         struct file *fp;
 2919         int error = 0;
 2920 
 2921         fdp = p->td_proc->p_fd;
 2922         if (fd < 0 || fd >= fdp->fd_nfiles ||
 2923             (fp = fdp->fd_ofiles[fd].fde_file) == NULL) {
 2924                 error = EBADF;
 2925                 goto out;
 2926         }
 2927         *fpp = fp;
 2928 
 2929 out:
 2930         NFSEXITCODE(error);
 2931         return (error);
 2932 }
 2933 
 2934 /*
 2935  * Called from nfssvc() to update the exports list. Just call
 2936  * vfs_export(). This has to be done, since the v4 root fake fs isn't
 2937  * in the mount list.
 2938  */
 2939 int
 2940 nfsrv_v4rootexport(void *argp, struct ucred *cred, struct thread *p)
 2941 {
 2942         struct nfsex_args *nfsexargp = (struct nfsex_args *)argp;
 2943         int error = 0;
 2944         struct nameidata nd;
 2945         fhandle_t fh;
 2946 
 2947         error = vfs_export(&nfsv4root_mnt, &nfsexargp->export);
 2948         if ((nfsexargp->export.ex_flags & MNT_DELEXPORT) != 0)
 2949                 nfs_rootfhset = 0;
 2950         else if (error == 0) {
 2951                 if (nfsexargp->fspec == NULL) {
 2952                         error = EPERM;
 2953                         goto out;
 2954                 }
 2955                 /*
 2956                  * If fspec != NULL, this is the v4root path.
 2957                  */
 2958                 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE,
 2959                     nfsexargp->fspec, p);
 2960                 if ((error = namei(&nd)) != 0)
 2961                         goto out;
 2962                 error = nfsvno_getfh(nd.ni_vp, &fh, p);
 2963                 vrele(nd.ni_vp);
 2964                 if (!error) {
 2965                         nfs_rootfh.nfsrvfh_len = NFSX_MYFH;
 2966                         NFSBCOPY((caddr_t)&fh,
 2967                             nfs_rootfh.nfsrvfh_data,
 2968                             sizeof (fhandle_t));
 2969                         nfs_rootfhset = 1;
 2970                 }
 2971         }
 2972 
 2973 out:
 2974         NFSEXITCODE(error);
 2975         return (error);
 2976 }
 2977 
 2978 /*
 2979  * This function needs to test to see if the system is near its limit
 2980  * for memory allocation via malloc() or mget() and return True iff
 2981  * either of these resources are near their limit.
 2982  * XXX (For now, this is just a stub.)
 2983  */
 2984 int nfsrv_testmalloclimit = 0;
 2985 int
 2986 nfsrv_mallocmget_limit(void)
 2987 {
 2988         static int printmesg = 0;
 2989         static int testval = 1;
 2990 
 2991         if (nfsrv_testmalloclimit && (testval++ % 1000) == 0) {
 2992                 if ((printmesg++ % 100) == 0)
 2993                         printf("nfsd: malloc/mget near limit\n");
 2994                 return (1);
 2995         }
 2996         return (0);
 2997 }
 2998 
 2999 /*
 3000  * BSD specific initialization of a mount point.
 3001  */
 3002 void
 3003 nfsd_mntinit(void)
 3004 {
 3005         static int inited = 0;
 3006 
 3007         if (inited)
 3008                 return;
 3009         inited = 1;
 3010         nfsv4root_mnt.mnt_flag = (MNT_RDONLY | MNT_EXPORTED);
 3011         TAILQ_INIT(&nfsv4root_mnt.mnt_nvnodelist);
 3012         TAILQ_INIT(&nfsv4root_mnt.mnt_activevnodelist);
 3013         nfsv4root_mnt.mnt_export = NULL;
 3014         TAILQ_INIT(&nfsv4root_opt);
 3015         TAILQ_INIT(&nfsv4root_newopt);
 3016         nfsv4root_mnt.mnt_opt = &nfsv4root_opt;
 3017         nfsv4root_mnt.mnt_optnew = &nfsv4root_newopt;
 3018         nfsv4root_mnt.mnt_nvnodelistsize = 0;
 3019         nfsv4root_mnt.mnt_activevnodelistsize = 0;
 3020 }
 3021 
 3022 /*
 3023  * Get a vnode for a file handle, without checking exports, etc.
 3024  */
 3025 struct vnode *
 3026 nfsvno_getvp(fhandle_t *fhp)
 3027 {
 3028         struct mount *mp;
 3029         struct vnode *vp;
 3030         int error;
 3031 
 3032         mp = vfs_busyfs(&fhp->fh_fsid);
 3033         if (mp == NULL)
 3034                 return (NULL);
 3035         error = VFS_FHTOVP(mp, &fhp->fh_fid, LK_EXCLUSIVE, &vp);
 3036         vfs_unbusy(mp);
 3037         if (error)
 3038                 return (NULL);
 3039         return (vp);
 3040 }
 3041 
 3042 /*
 3043  * Do a local VOP_ADVLOCK().
 3044  */
 3045 int
 3046 nfsvno_advlock(struct vnode *vp, int ftype, u_int64_t first,
 3047     u_int64_t end, struct thread *td)
 3048 {
 3049         int error = 0;
 3050         struct flock fl;
 3051         u_int64_t tlen;
 3052 
 3053         if (nfsrv_dolocallocks == 0)
 3054                 goto out;
 3055         ASSERT_VOP_UNLOCKED(vp, "nfsvno_advlock: vp locked");
 3056 
 3057         fl.l_whence = SEEK_SET;
 3058         fl.l_type = ftype;
 3059         fl.l_start = (off_t)first;
 3060         if (end == NFS64BITSSET) {
 3061                 fl.l_len = 0;
 3062         } else {
 3063                 tlen = end - first;
 3064                 fl.l_len = (off_t)tlen;
 3065         }
 3066         /*
 3067          * For FreeBSD8, the l_pid and l_sysid must be set to the same
 3068          * values for all calls, so that all locks will be held by the
 3069          * nfsd server. (The nfsd server handles conflicts between the
 3070          * various clients.)
 3071          * Since an NFSv4 lockowner is a ClientID plus an array of up to 1024
 3072          * bytes, so it can't be put in l_sysid.
 3073          */
 3074         if (nfsv4_sysid == 0)
 3075                 nfsv4_sysid = nlm_acquire_next_sysid();
 3076         fl.l_pid = (pid_t)0;
 3077         fl.l_sysid = (int)nfsv4_sysid;
 3078 
 3079         if (ftype == F_UNLCK)
 3080                 error = VOP_ADVLOCK(vp, (caddr_t)td->td_proc, F_UNLCK, &fl,
 3081                     (F_POSIX | F_REMOTE));
 3082         else
 3083                 error = VOP_ADVLOCK(vp, (caddr_t)td->td_proc, F_SETLK, &fl,
 3084                     (F_POSIX | F_REMOTE));
 3085 
 3086 out:
 3087         NFSEXITCODE(error);
 3088         return (error);
 3089 }
 3090 
 3091 /*
 3092  * Check the nfsv4 root exports.
 3093  */
 3094 int
 3095 nfsvno_v4rootexport(struct nfsrv_descript *nd)
 3096 {
 3097         struct ucred *credanon;
 3098         int exflags, error = 0, numsecflavor, *secflavors, i;
 3099 
 3100         error = vfs_stdcheckexp(&nfsv4root_mnt, nd->nd_nam, &exflags,
 3101             &credanon, &numsecflavor, &secflavors);
 3102         if (error) {
 3103                 error = NFSERR_PROGUNAVAIL;
 3104                 goto out;
 3105         }
 3106         if (credanon != NULL)
 3107                 crfree(credanon);
 3108         for (i = 0; i < numsecflavor; i++) {
 3109                 if (secflavors[i] == AUTH_SYS)
 3110                         nd->nd_flag |= ND_EXAUTHSYS;
 3111                 else if (secflavors[i] == RPCSEC_GSS_KRB5)
 3112                         nd->nd_flag |= ND_EXGSS;
 3113                 else if (secflavors[i] == RPCSEC_GSS_KRB5I)
 3114                         nd->nd_flag |= ND_EXGSSINTEGRITY;
 3115                 else if (secflavors[i] == RPCSEC_GSS_KRB5P)
 3116                         nd->nd_flag |= ND_EXGSSPRIVACY;
 3117         }
 3118 
 3119 out:
 3120         NFSEXITCODE(error);
 3121         return (error);
 3122 }
 3123 
 3124 /*
 3125  * Nfs server pseudo system call for the nfsd's
 3126  */
 3127 /*
 3128  * MPSAFE
 3129  */
 3130 static int
 3131 nfssvc_nfsd(struct thread *td, struct nfssvc_args *uap)
 3132 {
 3133         struct file *fp;
 3134         struct nfsd_addsock_args sockarg;
 3135         struct nfsd_nfsd_args nfsdarg;
 3136         cap_rights_t rights;
 3137         int error;
 3138 
 3139         if (uap->flag & NFSSVC_NFSDADDSOCK) {
 3140                 error = copyin(uap->argp, (caddr_t)&sockarg, sizeof (sockarg));
 3141                 if (error)
 3142                         goto out;
 3143                 /*
 3144                  * Since we don't know what rights might be required,
 3145                  * pretend that we need them all. It is better to be too
 3146                  * careful than too reckless.
 3147                  */
 3148                 error = fget(td, sockarg.sock,
 3149                     cap_rights_init(&rights, CAP_SOCK_SERVER), &fp);
 3150                 if (error != 0)
 3151                         goto out;
 3152                 if (fp->f_type != DTYPE_SOCKET) {
 3153                         fdrop(fp, td);
 3154                         error = EPERM;
 3155                         goto out;
 3156                 }
 3157                 error = nfsrvd_addsock(fp);
 3158                 fdrop(fp, td);
 3159         } else if (uap->flag & NFSSVC_NFSDNFSD) {
 3160                 if (uap->argp == NULL) {
 3161                         error = EINVAL;
 3162                         goto out;
 3163                 }
 3164                 error = copyin(uap->argp, (caddr_t)&nfsdarg,
 3165                     sizeof (nfsdarg));
 3166                 if (error)
 3167                         goto out;
 3168                 error = nfsrvd_nfsd(td, &nfsdarg);
 3169         } else {
 3170                 error = nfssvc_srvcall(td, uap, td->td_ucred);
 3171         }
 3172 
 3173 out:
 3174         NFSEXITCODE(error);
 3175         return (error);
 3176 }
 3177 
 3178 static int
 3179 nfssvc_srvcall(struct thread *p, struct nfssvc_args *uap, struct ucred *cred)
 3180 {
 3181         struct nfsex_args export;
 3182         struct file *fp = NULL;
 3183         int stablefd, len;
 3184         struct nfsd_clid adminrevoke;
 3185         struct nfsd_dumplist dumplist;
 3186         struct nfsd_dumpclients *dumpclients;
 3187         struct nfsd_dumplocklist dumplocklist;
 3188         struct nfsd_dumplocks *dumplocks;
 3189         struct nameidata nd;
 3190         vnode_t vp;
 3191         int error = EINVAL, igotlock;
 3192         struct proc *procp;
 3193         static int suspend_nfsd = 0;
 3194 
 3195         if (uap->flag & NFSSVC_PUBLICFH) {
 3196                 NFSBZERO((caddr_t)&nfs_pubfh.nfsrvfh_data,
 3197                     sizeof (fhandle_t));
 3198                 error = copyin(uap->argp,
 3199                     &nfs_pubfh.nfsrvfh_data, sizeof (fhandle_t));
 3200                 if (!error)
 3201                         nfs_pubfhset = 1;
 3202         } else if (uap->flag & NFSSVC_V4ROOTEXPORT) {
 3203                 error = copyin(uap->argp,(caddr_t)&export,
 3204                     sizeof (struct nfsex_args));
 3205                 if (!error)
 3206                         error = nfsrv_v4rootexport(&export, cred, p);
 3207         } else if (uap->flag & NFSSVC_NOPUBLICFH) {
 3208                 nfs_pubfhset = 0;
 3209                 error = 0;
 3210         } else if (uap->flag & NFSSVC_STABLERESTART) {
 3211                 error = copyin(uap->argp, (caddr_t)&stablefd,
 3212                     sizeof (int));
 3213                 if (!error)
 3214                         error = fp_getfvp(p, stablefd, &fp, &vp);
 3215                 if (!error && (NFSFPFLAG(fp) & (FREAD | FWRITE)) != (FREAD | FWRITE))
 3216                         error = EBADF;
 3217                 if (!error && newnfs_numnfsd != 0)
 3218                         error = EPERM;
 3219                 if (!error) {
 3220                         nfsrv_stablefirst.nsf_fp = fp;
 3221                         nfsrv_setupstable(p);
 3222                 }
 3223         } else if (uap->flag & NFSSVC_ADMINREVOKE) {
 3224                 error = copyin(uap->argp, (caddr_t)&adminrevoke,
 3225                     sizeof (struct nfsd_clid));
 3226                 if (!error)
 3227                         error = nfsrv_adminrevoke(&adminrevoke, p);
 3228         } else if (uap->flag & NFSSVC_DUMPCLIENTS) {
 3229                 error = copyin(uap->argp, (caddr_t)&dumplist,
 3230                     sizeof (struct nfsd_dumplist));
 3231                 if (!error && (dumplist.ndl_size < 1 ||
 3232                         dumplist.ndl_size > NFSRV_MAXDUMPLIST))
 3233                         error = EPERM;
 3234                 if (!error) {
 3235                     len = sizeof (struct nfsd_dumpclients) * dumplist.ndl_size;
 3236                     dumpclients = malloc(len, M_TEMP, M_WAITOK | M_ZERO);
 3237                     nfsrv_dumpclients(dumpclients, dumplist.ndl_size);
 3238                     error = copyout(dumpclients,
 3239                         CAST_USER_ADDR_T(dumplist.ndl_list), len);
 3240                     free((caddr_t)dumpclients, M_TEMP);
 3241                 }
 3242         } else if (uap->flag & NFSSVC_DUMPLOCKS) {
 3243                 error = copyin(uap->argp, (caddr_t)&dumplocklist,
 3244                     sizeof (struct nfsd_dumplocklist));
 3245                 if (!error && (dumplocklist.ndllck_size < 1 ||
 3246                         dumplocklist.ndllck_size > NFSRV_MAXDUMPLIST))
 3247                         error = EPERM;
 3248                 if (!error)
 3249                         error = nfsrv_lookupfilename(&nd,
 3250                                 dumplocklist.ndllck_fname, p);
 3251                 if (!error) {
 3252                         len = sizeof (struct nfsd_dumplocks) *
 3253                                 dumplocklist.ndllck_size;
 3254                         dumplocks = malloc(len, M_TEMP, M_WAITOK | M_ZERO);
 3255                         nfsrv_dumplocks(nd.ni_vp, dumplocks,
 3256                             dumplocklist.ndllck_size, p);
 3257                         vput(nd.ni_vp);
 3258                         error = copyout(dumplocks,
 3259                             CAST_USER_ADDR_T(dumplocklist.ndllck_list), len);
 3260                         free((caddr_t)dumplocks, M_TEMP);
 3261                 }
 3262         } else if (uap->flag & NFSSVC_BACKUPSTABLE) {
 3263                 procp = p->td_proc;
 3264                 PROC_LOCK(procp);
 3265                 nfsd_master_pid = procp->p_pid;
 3266                 bcopy(procp->p_comm, nfsd_master_comm, MAXCOMLEN + 1);
 3267                 nfsd_master_start = procp->p_stats->p_start;
 3268                 nfsd_master_proc = procp;
 3269                 PROC_UNLOCK(procp);
 3270         } else if ((uap->flag & NFSSVC_SUSPENDNFSD) != 0) {
 3271                 NFSLOCKV4ROOTMUTEX();
 3272                 if (suspend_nfsd == 0) {
 3273                         /* Lock out all nfsd threads */
 3274                         do {
 3275                                 igotlock = nfsv4_lock(&nfsd_suspend_lock, 1,
 3276                                     NULL, NFSV4ROOTLOCKMUTEXPTR, NULL);
 3277                         } while (igotlock == 0 && suspend_nfsd == 0);
 3278                         suspend_nfsd = 1;
 3279                 }
 3280                 NFSUNLOCKV4ROOTMUTEX();
 3281                 error = 0;
 3282         } else if ((uap->flag & NFSSVC_RESUMENFSD) != 0) {
 3283                 NFSLOCKV4ROOTMUTEX();
 3284                 if (suspend_nfsd != 0) {
 3285                         nfsv4_unlock(&nfsd_suspend_lock, 0);
 3286                         suspend_nfsd = 0;
 3287                 }
 3288                 NFSUNLOCKV4ROOTMUTEX();
 3289                 error = 0;
 3290         }
 3291 
 3292         NFSEXITCODE(error);
 3293         return (error);
 3294 }
 3295 
 3296 /*
 3297  * Check exports.
 3298  * Returns 0 if ok, 1 otherwise.
 3299  */
 3300 int
 3301 nfsvno_testexp(struct nfsrv_descript *nd, struct nfsexstuff *exp)
 3302 {
 3303         int i;
 3304 
 3305         /*
 3306          * This seems odd, but allow the case where the security flavor
 3307          * list is empty. This happens when NFSv4 is traversing non-exported
 3308          * file systems. Exported file systems should always have a non-empty
 3309          * security flavor list.
 3310          */
 3311         if (exp->nes_numsecflavor == 0)
 3312                 return (0);
 3313 
 3314         for (i = 0; i < exp->nes_numsecflavor; i++) {
 3315                 /*
 3316                  * The tests for privacy and integrity must be first,
 3317                  * since ND_GSS is set for everything but AUTH_SYS.
 3318                  */
 3319                 if (exp->nes_secflavors[i] == RPCSEC_GSS_KRB5P &&
 3320                     (nd->nd_flag & ND_GSSPRIVACY))
 3321                         return (0);
 3322                 if (exp->nes_secflavors[i] == RPCSEC_GSS_KRB5I &&
 3323                     (nd->nd_flag & ND_GSSINTEGRITY))
 3324                         return (0);
 3325                 if (exp->nes_secflavors[i] == RPCSEC_GSS_KRB5 &&
 3326                     (nd->nd_flag & ND_GSS))
 3327                         return (0);
 3328                 if (exp->nes_secflavors[i] == AUTH_SYS &&
 3329                     (nd->nd_flag & ND_GSS) == 0)
 3330                         return (0);
 3331         }
 3332         return (1);
 3333 }
 3334 
 3335 /*
 3336  * Calculate a hash value for the fid in a file handle.
 3337  */
 3338 uint32_t
 3339 nfsrv_hashfh(fhandle_t *fhp)
 3340 {
 3341         uint32_t hashval;
 3342 
 3343         hashval = hash32_buf(&fhp->fh_fid, sizeof(struct fid), 0);
 3344         return (hashval);
 3345 }
 3346 
 3347 /*
 3348  * Calculate a hash value for the sessionid.
 3349  */
 3350 uint32_t
 3351 nfsrv_hashsessionid(uint8_t *sessionid)
 3352 {
 3353         uint32_t hashval;
 3354 
 3355         hashval = hash32_buf(sessionid, NFSX_V4SESSIONID, 0);
 3356         return (hashval);
 3357 }
 3358 
 3359 /*
 3360  * Signal the userland master nfsd to backup the stable restart file.
 3361  */
 3362 void
 3363 nfsrv_backupstable(void)
 3364 {
 3365         struct proc *procp;
 3366 
 3367         if (nfsd_master_proc != NULL) {
 3368                 procp = pfind(nfsd_master_pid);
 3369                 /* Try to make sure it is the correct process. */
 3370                 if (procp == nfsd_master_proc &&
 3371                     procp->p_stats->p_start.tv_sec ==
 3372                     nfsd_master_start.tv_sec &&
 3373                     procp->p_stats->p_start.tv_usec ==
 3374                     nfsd_master_start.tv_usec &&
 3375                     strcmp(procp->p_comm, nfsd_master_comm) == 0)
 3376                         kern_psignal(procp, SIGUSR2);
 3377                 else
 3378                         nfsd_master_proc = NULL;
 3379 
 3380                 if (procp != NULL)
 3381                         PROC_UNLOCK(procp);
 3382         }
 3383 }
 3384 
 3385 extern int (*nfsd_call_nfsd)(struct thread *, struct nfssvc_args *);
 3386 
 3387 /*
 3388  * Called once to initialize data structures...
 3389  */
 3390 static int
 3391 nfsd_modevent(module_t mod, int type, void *data)
 3392 {
 3393         int error = 0, i;
 3394         static int loaded = 0;
 3395 
 3396         switch (type) {
 3397         case MOD_LOAD:
 3398                 if (loaded)
 3399                         goto out;
 3400                 newnfs_portinit();
 3401                 for (i = 0; i < NFSRVCACHE_HASHSIZE; i++) {
 3402                         mtx_init(&nfsrchash_table[i].mtx, "nfsrtc", NULL,
 3403                             MTX_DEF);
 3404                         mtx_init(&nfsrcahash_table[i].mtx, "nfsrtca", NULL,
 3405                             MTX_DEF);
 3406                 }
 3407                 mtx_init(&nfsrc_udpmtx, "nfsuc", NULL, MTX_DEF);
 3408                 mtx_init(&nfs_v4root_mutex, "nfs4rt", NULL, MTX_DEF);
 3409                 mtx_init(&nfsv4root_mnt.mnt_mtx, "nfs4mnt", NULL, MTX_DEF);
 3410                 lockinit(&nfsv4root_mnt.mnt_explock, PVFS, "explock", 0, 0);
 3411                 nfsrvd_initcache();
 3412                 nfsd_init();
 3413                 NFSD_LOCK();
 3414                 nfsrvd_init(0);
 3415                 NFSD_UNLOCK();
 3416                 nfsd_mntinit();
 3417 #ifdef VV_DISABLEDELEG
 3418                 vn_deleg_ops.vndeleg_recall = nfsd_recalldelegation;
 3419                 vn_deleg_ops.vndeleg_disable = nfsd_disabledelegation;
 3420 #endif
 3421                 nfsd_call_servertimer = nfsrv_servertimer;
 3422                 nfsd_call_nfsd = nfssvc_nfsd;
 3423                 loaded = 1;
 3424                 break;
 3425 
 3426         case MOD_UNLOAD:
 3427                 if (newnfs_numnfsd != 0) {
 3428                         error = EBUSY;
 3429                         break;
 3430                 }
 3431 
 3432 #ifdef VV_DISABLEDELEG
 3433                 vn_deleg_ops.vndeleg_recall = NULL;
 3434                 vn_deleg_ops.vndeleg_disable = NULL;
 3435 #endif
 3436                 nfsd_call_servertimer = NULL;
 3437                 nfsd_call_nfsd = NULL;
 3438 
 3439                 /* Clean out all NFSv4 state. */
 3440                 nfsrv_throwawayallstate(curthread);
 3441 
 3442                 /* Clean the NFS server reply cache */
 3443                 nfsrvd_cleancache();
 3444 
 3445                 /* Free up the krpc server pool. */
 3446                 if (nfsrvd_pool != NULL)
 3447                         svcpool_destroy(nfsrvd_pool);
 3448 
 3449                 /* and get rid of the locks */
 3450                 for (i = 0; i < NFSRVCACHE_HASHSIZE; i++) {
 3451                         mtx_destroy(&nfsrchash_table[i].mtx);
 3452                         mtx_destroy(&nfsrcahash_table[i].mtx);
 3453                 }
 3454                 mtx_destroy(&nfsrc_udpmtx);
 3455                 mtx_destroy(&nfs_v4root_mutex);
 3456                 mtx_destroy(&nfsv4root_mnt.mnt_mtx);
 3457                 for (i = 0; i < nfsrv_sessionhashsize; i++)
 3458                         mtx_destroy(&nfssessionhash[i].mtx);
 3459                 lockdestroy(&nfsv4root_mnt.mnt_explock);
 3460                 free(nfsclienthash, M_NFSDCLIENT);
 3461                 free(nfslockhash, M_NFSDLOCKFILE);
 3462                 free(nfssessionhash, M_NFSDSESSION);
 3463                 loaded = 0;
 3464                 break;
 3465         default:
 3466                 error = EOPNOTSUPP;
 3467                 break;
 3468         }
 3469 
 3470 out:
 3471         NFSEXITCODE(error);
 3472         return (error);
 3473 }
 3474 static moduledata_t nfsd_mod = {
 3475         "nfsd",
 3476         nfsd_modevent,
 3477         NULL,
 3478 };
 3479 DECLARE_MODULE(nfsd, nfsd_mod, SI_SUB_VFS, SI_ORDER_ANY);
 3480 
 3481 /* So that loader and kldload(2) can find us, wherever we are.. */
 3482 MODULE_VERSION(nfsd, 1);
 3483 MODULE_DEPEND(nfsd, nfscommon, 1, 1, 1);
 3484 MODULE_DEPEND(nfsd, nfslock, 1, 1, 1);
 3485 MODULE_DEPEND(nfsd, nfslockd, 1, 1, 1);
 3486 MODULE_DEPEND(nfsd, krpc, 1, 1, 1);
 3487 MODULE_DEPEND(nfsd, nfssvc, 1, 1, 1);
 3488 

Cache object: d90713b2c23eea79dc4373d24cdb232f


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