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/nfsserver/nfs_serv.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  *      @(#)nfs_serv.c  8.8 (Berkeley) 7/31/95
   33  */
   34 
   35 #include <sys/cdefs.h>
   36 __FBSDID("$FreeBSD: releng/8.0/sys/nfsserver/nfs_serv.c 197613 2009-09-29 10:53:06Z pjd $");
   37 
   38 /*
   39  * nfs version 2 and 3 server calls to vnode ops
   40  * - these routines generally have 3 phases
   41  *   1 - break down and validate rpc request in mbuf list
   42  *   2 - do the vnode ops for the request
   43  *       (surprisingly ?? many are very similar to syscalls in vfs_syscalls.c)
   44  *   3 - build the rpc reply in an mbuf list
   45  *   nb:
   46  *      - do not mix the phases, since the nfsm_?? macros can return failures
   47  *        on a bad rpc or similar and do not do any vrele() or vput()'s
   48  *
   49  *      - the nfsm_reply() macro generates an nfs rpc reply with the nfs
   50  *      error number iff error != 0 whereas
   51  *      returning an error from the server function implies a fatal error
   52  *      such as a badly constructed rpc request that should be dropped without
   53  *      a reply.
   54  *      For nfsm_reply(), the case where error == EBADRPC is treated
   55  *      specially; after constructing a reply, it does an immediate
   56  *      `goto nfsmout' to avoid getting any V3 post-op status appended.
   57  *
   58  * Other notes:
   59  *      Warning: always pay careful attention to resource cleanup on return
   60  *      and note that nfsm_*() macros can terminate a procedure on certain
   61  *      errors.
   62  *
   63  *      lookup() and namei()
   64  *      may return garbage in various structural fields/return elements
   65  *      if an error is returned, and may garbage up nd.ni_dvp even if no
   66  *      error is returned and you did not request LOCKPARENT or WANTPARENT.
   67  *
   68  *      We use the ni_cnd.cn_flags 'HASBUF' flag to track whether the name
   69  *      buffer has been freed or not.
   70  */
   71 
   72 #include <sys/param.h>
   73 #include <sys/systm.h>
   74 #include <sys/proc.h>
   75 #include <sys/namei.h>
   76 #include <sys/unistd.h>
   77 #include <sys/vnode.h>
   78 #include <sys/mount.h>
   79 #include <sys/socket.h>
   80 #include <sys/socketvar.h>
   81 #include <sys/malloc.h>
   82 #include <sys/mbuf.h>
   83 #include <sys/priv.h>
   84 #include <sys/dirent.h>
   85 #include <sys/stat.h>
   86 #include <sys/kernel.h>
   87 #include <sys/sysctl.h>
   88 #include <sys/bio.h>
   89 #include <sys/buf.h>
   90 
   91 #include <vm/vm.h>
   92 #include <vm/vm_extern.h>
   93 #include <vm/vm_object.h>
   94 
   95 #include <nfs/nfsproto.h>
   96 #include <nfsserver/nfs.h>
   97 #include <nfs/xdr_subs.h>
   98 #include <nfsserver/nfsm_subs.h>
   99 
  100 #ifdef NFSRV_DEBUG
  101 #define nfsdbprintf(info)       printf info
  102 #else
  103 #define nfsdbprintf(info)
  104 #endif
  105 
  106 #define MAX_COMMIT_COUNT        (1024 * 1024)
  107 
  108 #define NUM_HEURISTIC           1017
  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_nextr;         /* next offset for sequential detection */
  116         int nh_use;             /* use count for selection */
  117         int nh_seqcount;        /* heuristic */
  118 } nfsheur[NUM_HEURISTIC];
  119 
  120 /* Global vars */
  121 
  122 int nfsrvw_procrastinate = NFS_GATHERDELAY * 1000;
  123 int nfsrvw_procrastinate_v3 = 0;
  124 
  125 static struct timeval   nfsver = { 0 };
  126 
  127 SYSCTL_NODE(_vfs, OID_AUTO, nfsrv, CTLFLAG_RW, 0, "NFS server");
  128 
  129 static int nfs_async;
  130 static int nfs_commit_blks;
  131 static int nfs_commit_miss;
  132 SYSCTL_INT(_vfs_nfsrv, OID_AUTO, async, CTLFLAG_RW, &nfs_async, 0,
  133     "Tell client that writes were synced even though they were not");
  134 SYSCTL_INT(_vfs_nfsrv, OID_AUTO, commit_blks, CTLFLAG_RW, &nfs_commit_blks, 0,
  135     "Number of completed commits");
  136 SYSCTL_INT(_vfs_nfsrv, OID_AUTO, commit_miss, CTLFLAG_RW, &nfs_commit_miss, 0, "");
  137 
  138 struct nfsrvstats nfsrvstats;
  139 SYSCTL_STRUCT(_vfs_nfsrv, NFS_NFSRVSTATS, nfsrvstats, CTLFLAG_RW,
  140         &nfsrvstats, nfsrvstats, "S,nfsrvstats");
  141 
  142 static int      nfsrv_access(struct vnode *, accmode_t, struct ucred *,
  143                     int, int);
  144 
  145 /*
  146  * Clear nameidata fields that are tested in nsfmout cleanup code prior
  147  * to using first nfsm macro (that might jump to the cleanup code).
  148  */
  149 
  150 static __inline void
  151 ndclear(struct nameidata *nd)
  152 {
  153 
  154         nd->ni_cnd.cn_flags = 0;
  155         nd->ni_vp = NULL;
  156         nd->ni_dvp = NULL;
  157         nd->ni_startdir = NULL;
  158 }
  159 
  160 /*
  161  * Takes two vfslocked integers and returns with at most one
  162  * reference to giant.  The return value indicates whether giant
  163  * is held by either lock.  This simplifies nfsrv ops by allowing
  164  * them to track only one vfslocked var.
  165  */
  166 static __inline int
  167 nfsrv_lockedpair(int vfs1, int vfs2)
  168 {
  169 
  170         if (vfs1 && vfs2)
  171                 VFS_UNLOCK_GIANT(vfs2);
  172 
  173         return (vfs1 | vfs2);
  174 }
  175 
  176 static __inline int
  177 nfsrv_lockedpair_nd(int vfs1, struct nameidata *nd)
  178 {
  179         int vfs2;
  180 
  181         vfs2 = NDHASGIANT(nd);
  182 
  183         return nfsrv_lockedpair(vfs1, vfs2);
  184 }
  185 
  186 /*
  187  * nfs v3 access service
  188  */
  189 int
  190 nfsrv3_access(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
  191     struct mbuf **mrq)
  192 {
  193         struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
  194         struct sockaddr *nam = nfsd->nd_nam;
  195         caddr_t dpos = nfsd->nd_dpos;
  196         struct ucred *cred = nfsd->nd_cr;
  197         struct vnode *vp = NULL;
  198         nfsfh_t nfh;
  199         fhandle_t *fhp;
  200         u_int32_t *tl;
  201         caddr_t bpos;
  202         int error = 0, rdonly, getret;
  203         struct mbuf *mb, *mreq;
  204         struct vattr vattr, *vap = &vattr;
  205         u_long testmode, nfsmode;
  206         int v3 = (nfsd->nd_flag & ND_NFSV3);
  207         int vfslocked;
  208 
  209         nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
  210         if (!v3)
  211                 panic("nfsrv3_access: v3 proc called on a v2 connection");
  212         vfslocked = 0;
  213         fhp = &nfh.fh_generic;
  214         nfsm_srvmtofh(fhp);
  215         tl = nfsm_dissect_nonblock(u_int32_t *, NFSX_UNSIGNED);
  216         error = nfsrv_fhtovp(fhp, 1, &vp, &vfslocked, nfsd, slp,
  217             nam, &rdonly, TRUE);
  218         if (error) {
  219                 nfsm_reply(NFSX_UNSIGNED);
  220                 nfsm_srvpostop_attr(1, NULL);
  221                 error = 0;
  222                 goto nfsmout;
  223         }
  224         nfsmode = fxdr_unsigned(u_int32_t, *tl);
  225         if ((nfsmode & NFSV3ACCESS_READ) &&
  226                 nfsrv_access(vp, VREAD, cred, rdonly, 0))
  227                 nfsmode &= ~NFSV3ACCESS_READ;
  228         if (vp->v_type == VDIR)
  229                 testmode = (NFSV3ACCESS_MODIFY | NFSV3ACCESS_EXTEND |
  230                         NFSV3ACCESS_DELETE);
  231         else
  232                 testmode = (NFSV3ACCESS_MODIFY | NFSV3ACCESS_EXTEND);
  233         if ((nfsmode & testmode) &&
  234                 nfsrv_access(vp, VWRITE, cred, rdonly, 0))
  235                 nfsmode &= ~testmode;
  236         if (vp->v_type == VDIR)
  237                 testmode = NFSV3ACCESS_LOOKUP;
  238         else
  239                 testmode = NFSV3ACCESS_EXECUTE;
  240         if ((nfsmode & testmode) &&
  241                 nfsrv_access(vp, VEXEC, cred, rdonly, 0))
  242                 nfsmode &= ~testmode;
  243         getret = VOP_GETATTR(vp, vap, cred);
  244         vput(vp);
  245         vp = NULL;
  246         nfsm_reply(NFSX_POSTOPATTR(1) + NFSX_UNSIGNED);
  247         nfsm_srvpostop_attr(getret, vap);
  248         tl = nfsm_build(u_int32_t *, NFSX_UNSIGNED);
  249         *tl = txdr_unsigned(nfsmode);
  250 nfsmout:
  251         if (vp)
  252                 vput(vp);
  253         VFS_UNLOCK_GIANT(vfslocked);
  254         return(error);
  255 }
  256 
  257 /*
  258  * nfs getattr service
  259  */
  260 int
  261 nfsrv_getattr(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
  262     struct mbuf **mrq)
  263 {
  264         struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
  265         struct sockaddr *nam = nfsd->nd_nam;
  266         caddr_t dpos = nfsd->nd_dpos;
  267         struct ucred *cred = nfsd->nd_cr;
  268         struct nfs_fattr *fp;
  269         struct vattr va;
  270         struct vattr *vap = &va;
  271         struct vnode *vp = NULL;
  272         nfsfh_t nfh;
  273         fhandle_t *fhp;
  274         caddr_t bpos;
  275         int error = 0, rdonly;
  276         struct mbuf *mb, *mreq;
  277         int vfslocked;
  278 
  279         nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
  280         vfslocked = 0;
  281         fhp = &nfh.fh_generic;
  282         nfsm_srvmtofh(fhp);
  283         error = nfsrv_fhtovp(fhp, 1, &vp, &vfslocked, nfsd, slp, nam,
  284             &rdonly, TRUE);
  285         if (error) {
  286                 nfsm_reply(0);
  287                 error = 0;
  288                 goto nfsmout;
  289         }
  290         error = VOP_GETATTR(vp, vap, cred);
  291         vput(vp);
  292         vp = NULL;
  293         nfsm_reply(NFSX_FATTR(nfsd->nd_flag & ND_NFSV3));
  294         if (error) {
  295                 error = 0;
  296                 goto nfsmout;
  297         }
  298         fp = nfsm_build(struct nfs_fattr *,
  299             NFSX_FATTR(nfsd->nd_flag & ND_NFSV3));
  300         nfsm_srvfillattr(vap, fp);
  301         /* fall through */
  302 
  303 nfsmout:
  304         if (vp)
  305                 vput(vp);
  306         VFS_UNLOCK_GIANT(vfslocked);
  307         return(error);
  308 }
  309 
  310 /*
  311  * nfs setattr service
  312  */
  313 int
  314 nfsrv_setattr(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
  315     struct mbuf **mrq)
  316 {
  317         struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
  318         struct sockaddr *nam = nfsd->nd_nam;
  319         caddr_t dpos = nfsd->nd_dpos;
  320         struct ucred *cred = nfsd->nd_cr;
  321         struct vattr va, preat;
  322         struct vattr *vap = &va;
  323         struct nfsv2_sattr *sp;
  324         struct nfs_fattr *fp;
  325         struct vnode *vp = NULL;
  326         nfsfh_t nfh;
  327         fhandle_t *fhp;
  328         u_int32_t *tl;
  329         caddr_t bpos;
  330         int error = 0, rdonly, preat_ret = 1, postat_ret = 1;
  331         int v3 = (nfsd->nd_flag & ND_NFSV3), gcheck = 0;
  332         struct mbuf *mb, *mreq;
  333         struct timespec guard = { 0, 0 };
  334         struct mount *mp = NULL;
  335         int tvfslocked;
  336         int vfslocked;
  337 
  338         nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
  339         vfslocked = 0;
  340         fhp = &nfh.fh_generic;
  341         nfsm_srvmtofh(fhp);
  342         if ((mp = vfs_getvfs(&fhp->fh_fsid)) == NULL) {
  343                 error = ESTALE;
  344                 goto out;
  345         }
  346         vfslocked = VFS_LOCK_GIANT(mp);
  347         (void) vn_start_write(NULL, &mp, V_WAIT);
  348         vfs_rel(mp);            /* The write holds a ref. */
  349         VATTR_NULL(vap);
  350         if (v3) {
  351                 nfsm_srvsattr(vap);
  352                 tl = nfsm_dissect_nonblock(u_int32_t *, NFSX_UNSIGNED);
  353                 gcheck = fxdr_unsigned(int, *tl);
  354                 if (gcheck) {
  355                         tl = nfsm_dissect_nonblock(u_int32_t *, 2 * NFSX_UNSIGNED);
  356                         fxdr_nfsv3time(tl, &guard);
  357                 }
  358         } else {
  359                 sp = nfsm_dissect_nonblock(struct nfsv2_sattr *, NFSX_V2SATTR);
  360                 /*
  361                  * Nah nah nah nah na nah
  362                  * There is a bug in the Sun client that puts 0xffff in the mode
  363                  * field of sattr when it should put in 0xffffffff. The u_short
  364                  * doesn't sign extend.
  365                  * --> check the low order 2 bytes for 0xffff
  366                  */
  367                 if ((fxdr_unsigned(int, sp->sa_mode) & 0xffff) != 0xffff)
  368                         vap->va_mode = nfstov_mode(sp->sa_mode);
  369                 if (sp->sa_uid != nfsrv_nfs_xdrneg1)
  370                         vap->va_uid = fxdr_unsigned(uid_t, sp->sa_uid);
  371                 if (sp->sa_gid != nfsrv_nfs_xdrneg1)
  372                         vap->va_gid = fxdr_unsigned(gid_t, sp->sa_gid);
  373                 if (sp->sa_size != nfsrv_nfs_xdrneg1)
  374                         vap->va_size = fxdr_unsigned(u_quad_t, sp->sa_size);
  375                 if (sp->sa_atime.nfsv2_sec != nfsrv_nfs_xdrneg1) {
  376 #ifdef notyet
  377                         fxdr_nfsv2time(&sp->sa_atime, &vap->va_atime);
  378 #else
  379                         vap->va_atime.tv_sec =
  380                                 fxdr_unsigned(int32_t, sp->sa_atime.nfsv2_sec);
  381                         vap->va_atime.tv_nsec = 0;
  382 #endif
  383                 }
  384                 if (sp->sa_mtime.nfsv2_sec != nfsrv_nfs_xdrneg1)
  385                         fxdr_nfsv2time(&sp->sa_mtime, &vap->va_mtime);
  386 
  387         }
  388 
  389         /*
  390          * Now that we have all the fields, lets do it.
  391          */
  392         error = nfsrv_fhtovp(fhp, 1, &vp, &tvfslocked, nfsd, slp,
  393             nam, &rdonly, TRUE);
  394         vfslocked = nfsrv_lockedpair(vfslocked, tvfslocked);
  395         if (error) {
  396                 nfsm_reply(2 * NFSX_UNSIGNED);
  397                 if (v3)
  398                         nfsm_srvwcc_data(preat_ret, &preat, postat_ret, vap);
  399                 error = 0;
  400                 goto nfsmout;
  401         }
  402 
  403         /*
  404          * vp now an active resource, pay careful attention to cleanup
  405          */
  406         if (v3) {
  407                 error = preat_ret = VOP_GETATTR(vp, &preat, cred);
  408                 if (!error && gcheck &&
  409                         (preat.va_ctime.tv_sec != guard.tv_sec ||
  410                          preat.va_ctime.tv_nsec != guard.tv_nsec))
  411                         error = NFSERR_NOT_SYNC;
  412                 if (error) {
  413                         vput(vp);
  414                         vp = NULL;
  415                         nfsm_reply(NFSX_WCCDATA(v3));
  416                         if (v3)
  417                                 nfsm_srvwcc_data(preat_ret, &preat, postat_ret, vap);
  418                         error = 0;
  419                         goto nfsmout;
  420                 }
  421         }
  422 
  423         /*
  424          * If the size is being changed write acces is required, otherwise
  425          * just check for a read only filesystem.
  426          */
  427         if (vap->va_size == ((u_quad_t)((quad_t) -1))) {
  428                 if (rdonly || (vp->v_mount->mnt_flag & MNT_RDONLY)) {
  429                         error = EROFS;
  430                         goto out;
  431                 }
  432         } else {
  433                 if (vp->v_type == VDIR) {
  434                         error = EISDIR;
  435                         goto out;
  436                 } else if ((error = nfsrv_access(vp, VWRITE, cred, rdonly,
  437                     0)) != 0)
  438                         goto out;
  439         }
  440         error = VOP_SETATTR(vp, vap, cred);
  441         postat_ret = VOP_GETATTR(vp, vap, cred);
  442         if (!error)
  443                 error = postat_ret;
  444 out:
  445         if (vp != NULL)
  446                 vput(vp);
  447 
  448         vp = NULL;
  449         nfsm_reply(NFSX_WCCORFATTR(v3));
  450         if (v3) {
  451                 nfsm_srvwcc_data(preat_ret, &preat, postat_ret, vap);
  452         } else if (!error) {
  453                 /* v2 non-error case. */
  454                 fp = nfsm_build(struct nfs_fattr *, NFSX_V2FATTR);
  455                 nfsm_srvfillattr(vap, fp);
  456         }
  457         error = 0;
  458         /* fall through */
  459 
  460 nfsmout:
  461         if (vp)
  462                 vput(vp);
  463         vn_finished_write(mp);
  464         VFS_UNLOCK_GIANT(vfslocked);
  465         return(error);
  466 }
  467 
  468 /*
  469  * nfs lookup rpc
  470  */
  471 int
  472 nfsrv_lookup(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
  473     struct mbuf **mrq)
  474 {
  475         struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
  476         struct sockaddr *nam = nfsd->nd_nam;
  477         caddr_t dpos = nfsd->nd_dpos;
  478         struct ucred *cred = nfsd->nd_cr;
  479         struct nfs_fattr *fp;
  480         struct nameidata nd, ind, *ndp = &nd;
  481         struct vnode *vp, *dirp = NULL;
  482         nfsfh_t nfh;
  483         fhandle_t *fhp;
  484         caddr_t bpos;
  485         int error = 0, len, dirattr_ret = 1;
  486         int v3 = (nfsd->nd_flag & ND_NFSV3), pubflag;
  487         struct mbuf *mb, *mreq;
  488         struct vattr va, dirattr, *vap = &va;
  489         int tvfslocked;
  490         int vfslocked;
  491 
  492         nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
  493         ndclear(&nd);
  494         vfslocked = 0;
  495 
  496         fhp = &nfh.fh_generic;
  497         nfsm_srvmtofh(fhp);
  498         nfsm_srvnamesiz(len);
  499 
  500         pubflag = nfs_ispublicfh(fhp);
  501 
  502         nd.ni_cnd.cn_cred = cred;
  503         nd.ni_cnd.cn_nameiop = LOOKUP;
  504         nd.ni_cnd.cn_flags = LOCKLEAF | SAVESTART | MPSAFE;
  505         error = nfs_namei(&nd, nfsd, fhp, len, slp, nam, &md, &dpos,
  506                 &dirp, v3, &dirattr, &dirattr_ret, pubflag);
  507         vfslocked = NDHASGIANT(&nd);
  508 
  509         /*
  510          * namei failure, only dirp to cleanup.  Clear out garbarge from
  511          * structure in case macros jump to nfsmout.
  512          */
  513 
  514         if (error) {
  515                 if (dirp) {
  516                         vrele(dirp);
  517                         dirp = NULL;
  518                 }
  519                 nfsm_reply(NFSX_POSTOPATTR(v3));
  520                 if (v3)
  521                         nfsm_srvpostop_attr(dirattr_ret, &dirattr);
  522                 error = 0;
  523                 goto nfsmout;
  524         }
  525 
  526         /*
  527          * Locate index file for public filehandle
  528          *
  529          * error is 0 on entry and 0 on exit from this block.
  530          */
  531 
  532         if (pubflag) {
  533                 if (nd.ni_vp->v_type == VDIR && nfs_pub.np_index != NULL) {
  534                         /*
  535                          * Setup call to lookup() to see if we can find
  536                          * the index file. Arguably, this doesn't belong
  537                          * in a kernel.. Ugh.  If an error occurs, do not
  538                          * try to install an index file and then clear the
  539                          * error.
  540                          *
  541                          * When we replace nd with ind and redirect ndp,
  542                          * maintenance of ni_startdir and ni_vp shift to
  543                          * ind and we have to clean them up in the old nd.
  544                          * However, the cnd resource continues to be maintained
  545                          * via the original nd.  Confused?  You aren't alone!
  546                          */
  547                         ind = nd;
  548                         VOP_UNLOCK(nd.ni_vp, 0);
  549                         ind.ni_pathlen = strlen(nfs_pub.np_index);
  550                         ind.ni_cnd.cn_nameptr = ind.ni_cnd.cn_pnbuf =
  551                             nfs_pub.np_index;
  552                         ind.ni_startdir = nd.ni_vp;
  553                         VREF(ind.ni_startdir);
  554                         ind.ni_cnd.cn_flags &= ~GIANTHELD;
  555                         tvfslocked = VFS_LOCK_GIANT(ind.ni_startdir->v_mount);
  556                         if (tvfslocked)
  557                                 nd.ni_cnd.cn_flags |= GIANTHELD;
  558                         error = lookup(&ind);
  559                         ind.ni_dvp = NULL;
  560                         vfslocked = nfsrv_lockedpair_nd(vfslocked, &ind);
  561                         ind.ni_cnd.cn_flags &= ~GIANTHELD;
  562 
  563                         if (error == 0) {
  564                                 /*
  565                                  * Found an index file. Get rid of
  566                                  * the old references.  transfer nd.ni_vp'
  567                                  */
  568                                 if (dirp)
  569                                         vrele(dirp);
  570                                 dirp = nd.ni_vp;
  571                                 nd.ni_vp = NULL;
  572                                 vrele(nd.ni_startdir);
  573                                 nd.ni_startdir = NULL;
  574                                 ndp = &ind;
  575                         }
  576                         error = 0;
  577                 }
  578                 /*
  579                  * If the public filehandle was used, check that this lookup
  580                  * didn't result in a filehandle outside the publicly exported
  581                  * filesystem.  We clear the poor vp here to avoid lockups due
  582                  * to NFS I/O.
  583                  */
  584 
  585                 if (ndp->ni_vp->v_mount != nfs_pub.np_mount) {
  586                         vput(nd.ni_vp);
  587                         nd.ni_vp = NULL;
  588                         error = EPERM;
  589                 }
  590         }
  591 
  592         /*
  593          * Resources at this point:
  594          *      ndp->ni_vp      may not be NULL
  595          */
  596 
  597         if (error) {
  598                 nfsm_reply(NFSX_POSTOPATTR(v3));
  599                 if (v3)
  600                         nfsm_srvpostop_attr(dirattr_ret, &dirattr);
  601                 error = 0;
  602                 goto nfsmout;
  603         }
  604 
  605         /*
  606          * Get underlying attribute, then release remaining resources ( for
  607          * the same potential blocking reason ) and reply.
  608          */
  609         vp = ndp->ni_vp;
  610         bzero((caddr_t)fhp, sizeof(nfh));
  611         fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid;
  612         error = VOP_VPTOFH(vp, &fhp->fh_fid);
  613         if (!error)
  614                 error = VOP_GETATTR(vp, vap, cred);
  615 
  616         vput(vp);
  617         vrele(ndp->ni_startdir);
  618         vrele(dirp);
  619         ndp->ni_vp = NULL;
  620         ndp->ni_startdir = NULL;
  621         dirp = NULL;
  622         nfsm_reply(NFSX_SRVFH(v3) + NFSX_POSTOPORFATTR(v3) + NFSX_POSTOPATTR(v3));
  623         if (error) {
  624                 if (v3)
  625                         nfsm_srvpostop_attr(dirattr_ret, &dirattr);
  626                 error = 0;
  627                 goto nfsmout;
  628         }
  629         nfsm_srvfhtom(fhp, v3);
  630         if (v3) {
  631                 nfsm_srvpostop_attr(0, vap);
  632                 nfsm_srvpostop_attr(dirattr_ret, &dirattr);
  633         } else {
  634                 fp = nfsm_build(struct nfs_fattr *, NFSX_V2FATTR);
  635                 nfsm_srvfillattr(vap, fp);
  636         }
  637 
  638 nfsmout:
  639         if (ndp->ni_vp || dirp || ndp->ni_startdir) {
  640                 if (ndp->ni_vp)
  641                         vput(ndp->ni_vp);
  642                 if (dirp)
  643                         vrele(dirp);
  644                 if (ndp->ni_startdir)
  645                         vrele(ndp->ni_startdir);
  646         }
  647         NDFREE(&nd, NDF_ONLY_PNBUF);
  648         VFS_UNLOCK_GIANT(vfslocked);
  649         return (error);
  650 }
  651 
  652 /*
  653  * nfs readlink service
  654  */
  655 int
  656 nfsrv_readlink(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
  657     struct mbuf **mrq)
  658 {
  659         struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
  660         struct sockaddr *nam = nfsd->nd_nam;
  661         caddr_t dpos = nfsd->nd_dpos;
  662         struct ucred *cred = nfsd->nd_cr;
  663         struct iovec iv[(NFS_MAXPATHLEN+MLEN-1)/MLEN];
  664         struct iovec *ivp = iv;
  665         struct mbuf *mp;
  666         u_int32_t *tl;
  667         caddr_t bpos;
  668         int error = 0, rdonly, i, tlen, len, getret;
  669         int v3 = (nfsd->nd_flag & ND_NFSV3);
  670         struct mbuf *mb, *mp3, *nmp, *mreq;
  671         struct vnode *vp = NULL;
  672         struct vattr attr;
  673         nfsfh_t nfh;
  674         fhandle_t *fhp;
  675         struct uio io, *uiop = &io;
  676         int vfslocked;
  677 
  678         nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
  679         vfslocked = 0;
  680 #ifndef nolint
  681         mp = NULL;
  682 #endif
  683         mp3 = NULL;
  684         fhp = &nfh.fh_generic;
  685         nfsm_srvmtofh(fhp);
  686         len = 0;
  687         i = 0;
  688         while (len < NFS_MAXPATHLEN) {
  689                 MGET(nmp, M_WAIT, MT_DATA);
  690                 MCLGET(nmp, M_WAIT);
  691                 nmp->m_len = NFSMSIZ(nmp);
  692                 if (len == 0)
  693                         mp3 = mp = nmp;
  694                 else {
  695                         mp->m_next = nmp;
  696                         mp = nmp;
  697                 }
  698                 if ((len + mp->m_len) > NFS_MAXPATHLEN) {
  699                         mp->m_len = NFS_MAXPATHLEN - len;
  700                         len = NFS_MAXPATHLEN;
  701                 } else
  702                         len += mp->m_len;
  703                 ivp->iov_base = mtod(mp, caddr_t);
  704                 ivp->iov_len = mp->m_len;
  705                 i++;
  706                 ivp++;
  707         }
  708         uiop->uio_iov = iv;
  709         uiop->uio_iovcnt = i;
  710         uiop->uio_offset = 0;
  711         uiop->uio_resid = len;
  712         uiop->uio_rw = UIO_READ;
  713         uiop->uio_segflg = UIO_SYSSPACE;
  714         uiop->uio_td = NULL;
  715         error = nfsrv_fhtovp(fhp, 1, &vp, &vfslocked, nfsd, slp,
  716             nam, &rdonly, TRUE);
  717         if (error) {
  718                 nfsm_reply(2 * NFSX_UNSIGNED);
  719                 if (v3)
  720                         nfsm_srvpostop_attr(1, NULL);
  721                 error = 0;
  722                 goto nfsmout;
  723         }
  724         if (vp->v_type != VLNK) {
  725                 if (v3)
  726                         error = EINVAL;
  727                 else
  728                         error = ENXIO;
  729         } else 
  730                 error = VOP_READLINK(vp, uiop, cred);
  731         getret = VOP_GETATTR(vp, &attr, cred);
  732         vput(vp);
  733         vp = NULL;
  734         nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_UNSIGNED);
  735         if (v3)
  736                 nfsm_srvpostop_attr(getret, &attr);
  737         if (error) {
  738                 error = 0;
  739                 goto nfsmout;
  740         }
  741         if (uiop->uio_resid > 0) {
  742                 len -= uiop->uio_resid;
  743                 tlen = nfsm_rndup(len);
  744                 nfsm_adj(mp3, NFS_MAXPATHLEN-tlen, tlen-len);
  745         }
  746         tl = nfsm_build(u_int32_t *, NFSX_UNSIGNED);
  747         *tl = txdr_unsigned(len);
  748         mb->m_next = mp3;
  749         mp3 = NULL;
  750 nfsmout:
  751         if (mp3)
  752                 m_freem(mp3);
  753         if (vp)
  754                 vput(vp);
  755         VFS_UNLOCK_GIANT(vfslocked);
  756         return(error);
  757 }
  758 
  759 /*
  760  * nfs read service
  761  */
  762 int
  763 nfsrv_read(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
  764     struct mbuf **mrq)
  765 {
  766         struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
  767         struct sockaddr *nam = nfsd->nd_nam;
  768         caddr_t dpos = nfsd->nd_dpos;
  769         struct ucred *cred = nfsd->nd_cr;
  770         struct iovec *iv;
  771         struct iovec *iv2;
  772         struct mbuf *m;
  773         struct nfs_fattr *fp;
  774         u_int32_t *tl;
  775         int i;
  776         caddr_t bpos;
  777         int error = 0, rdonly, cnt, len, left, siz, tlen, getret;
  778         int v3 = (nfsd->nd_flag & ND_NFSV3), reqlen;
  779         struct mbuf *mb, *mreq;
  780         struct mbuf *m2;
  781         struct vnode *vp = NULL;
  782         nfsfh_t nfh;
  783         fhandle_t *fhp;
  784         struct uio io, *uiop = &io;
  785         struct vattr va, *vap = &va;
  786         struct nfsheur *nh;
  787         off_t off;
  788         int ioflag = 0;
  789         int vfslocked;
  790 
  791 
  792         nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
  793         vfslocked = 0;
  794         fhp = &nfh.fh_generic;
  795         nfsm_srvmtofh(fhp);
  796         if (v3) {
  797                 tl = nfsm_dissect_nonblock(u_int32_t *, 2 * NFSX_UNSIGNED);
  798                 off = fxdr_hyper(tl);
  799         } else {
  800                 tl = nfsm_dissect_nonblock(u_int32_t *, NFSX_UNSIGNED);
  801                 off = (off_t)fxdr_unsigned(u_int32_t, *tl);
  802         }
  803         nfsm_srvstrsiz(reqlen, NFS_SRVMAXDATA(nfsd));
  804 
  805         /*
  806          * Reference vp.  If an error occurs, vp will be invalid, but we
  807          * have to NULL it just in case.  The macros might goto nfsmout
  808          * as well.
  809          */
  810 
  811         error = nfsrv_fhtovp(fhp, 1, &vp, &vfslocked, nfsd, slp,
  812             nam, &rdonly, TRUE);
  813         if (error) {
  814                 vp = NULL;
  815                 nfsm_reply(2 * NFSX_UNSIGNED);
  816                 if (v3)
  817                         nfsm_srvpostop_attr(1, NULL);
  818                 error = 0;
  819                 goto nfsmout;
  820         }
  821 
  822         if (vp->v_type != VREG) {
  823                 if (v3)
  824                         error = EINVAL;
  825                 else
  826                         error = (vp->v_type == VDIR) ? EISDIR : EACCES;
  827         }
  828         if (!error) {
  829                 if ((error = nfsrv_access(vp, VREAD, cred, rdonly, 1)) != 0)
  830                         error = nfsrv_access(vp, VEXEC, cred, rdonly, 1);
  831         }
  832         getret = VOP_GETATTR(vp, vap, cred);
  833         if (!error)
  834                 error = getret;
  835         if (error) {
  836                 vput(vp);
  837                 vp = NULL;
  838                 nfsm_reply(NFSX_POSTOPATTR(v3));
  839                 if (v3)
  840                         nfsm_srvpostop_attr(getret, vap);
  841                 error = 0;
  842                 goto nfsmout;
  843         }
  844 
  845         /*
  846          * Calculate byte count to read
  847          */
  848 
  849         if (off >= vap->va_size)
  850                 cnt = 0;
  851         else if ((off + reqlen) > vap->va_size)
  852                 cnt = vap->va_size - off;
  853         else
  854                 cnt = reqlen;
  855 
  856         /*
  857          * Calculate seqcount for heuristic
  858          */
  859 
  860         {
  861                 int hi;
  862                 int try = 32;
  863 
  864                 /*
  865                  * Locate best candidate
  866                  */
  867 
  868                 hi = ((int)(vm_offset_t)vp / sizeof(struct vnode)) % NUM_HEURISTIC;
  869                 nh = &nfsheur[hi];
  870 
  871                 while (try--) {
  872                         if (nfsheur[hi].nh_vp == vp) {
  873                                 nh = &nfsheur[hi];
  874                                 break;
  875                         }
  876                         if (nfsheur[hi].nh_use > 0)
  877                                 --nfsheur[hi].nh_use;
  878                         hi = (hi + 1) % NUM_HEURISTIC;
  879                         if (nfsheur[hi].nh_use < nh->nh_use)
  880                                 nh = &nfsheur[hi];
  881                 }
  882 
  883                 if (nh->nh_vp != vp) {
  884                         nh->nh_vp = vp;
  885                         nh->nh_nextr = off;
  886                         nh->nh_use = NHUSE_INIT;
  887                         if (off == 0)
  888                                 nh->nh_seqcount = 4;
  889                         else
  890                                 nh->nh_seqcount = 1;
  891                 }
  892 
  893                 /*
  894                  * Calculate heuristic
  895                  */
  896 
  897                 if ((off == 0 && nh->nh_seqcount > 0) || off == nh->nh_nextr) {
  898                         if (++nh->nh_seqcount > IO_SEQMAX)
  899                                 nh->nh_seqcount = IO_SEQMAX;
  900                 } else if (nh->nh_seqcount > 1) {
  901                         nh->nh_seqcount = 1;
  902                 } else {
  903                         nh->nh_seqcount = 0;
  904                 }
  905                 nh->nh_use += NHUSE_INC;
  906                 if (nh->nh_use > NHUSE_MAX)
  907                         nh->nh_use = NHUSE_MAX;
  908                 ioflag |= nh->nh_seqcount << IO_SEQSHIFT;
  909         }
  910 
  911         nfsm_reply(NFSX_POSTOPORFATTR(v3) + 3 * NFSX_UNSIGNED+nfsm_rndup(cnt));
  912         if (v3) {
  913                 tl = nfsm_build(u_int32_t *, NFSX_V3FATTR + 4 * NFSX_UNSIGNED);
  914                 *tl++ = nfsrv_nfs_true;
  915                 fp = (struct nfs_fattr *)tl;
  916                 tl += (NFSX_V3FATTR / sizeof (u_int32_t));
  917         } else {
  918                 tl = nfsm_build(u_int32_t *, NFSX_V2FATTR + NFSX_UNSIGNED);
  919                 fp = (struct nfs_fattr *)tl;
  920                 tl += (NFSX_V2FATTR / sizeof (u_int32_t));
  921         }
  922         len = left = nfsm_rndup(cnt);
  923         if (cnt > 0) {
  924                 /*
  925                  * Generate the mbuf list with the uio_iov ref. to it.
  926                  */
  927                 i = 0;
  928                 m = m2 = mb;
  929                 while (left > 0) {
  930                         siz = min(M_TRAILINGSPACE(m), left);
  931                         if (siz > 0) {
  932                                 left -= siz;
  933                                 i++;
  934                         }
  935                         if (left > 0) {
  936                                 MGET(m, M_WAIT, MT_DATA);
  937                                 MCLGET(m, M_WAIT);
  938                                 m->m_len = 0;
  939                                 m2->m_next = m;
  940                                 m2 = m;
  941                         }
  942                 }
  943                 iv = malloc(i * sizeof (struct iovec),
  944                        M_TEMP, M_WAITOK);
  945                 uiop->uio_iov = iv2 = iv;
  946                 m = mb;
  947                 left = len;
  948                 i = 0;
  949                 while (left > 0) {
  950                         if (m == NULL)
  951                                 panic("nfsrv_read iov");
  952                         siz = min(M_TRAILINGSPACE(m), left);
  953                         if (siz > 0) {
  954                                 iv->iov_base = mtod(m, caddr_t) + m->m_len;
  955                                 iv->iov_len = siz;
  956                                 m->m_len += siz;
  957                                 left -= siz;
  958                                 iv++;
  959                                 i++;
  960                         }
  961                         m = m->m_next;
  962                 }
  963                 uiop->uio_iovcnt = i;
  964                 uiop->uio_offset = off;
  965                 uiop->uio_resid = len;
  966                 uiop->uio_rw = UIO_READ;
  967                 uiop->uio_segflg = UIO_SYSSPACE;
  968                 error = VOP_READ(vp, uiop, IO_NODELOCKED | ioflag, cred);
  969                 off = uiop->uio_offset;
  970                 nh->nh_nextr = off;
  971                 free((caddr_t)iv2, M_TEMP);
  972                 if (error || (getret = VOP_GETATTR(vp, vap, cred))) {
  973                         if (!error)
  974                                 error = getret;
  975                         m_freem(mreq);
  976                         vput(vp);
  977                         vp = NULL;
  978                         nfsm_reply(NFSX_POSTOPATTR(v3));
  979                         if (v3)
  980                                 nfsm_srvpostop_attr(getret, vap);
  981                         error = 0;
  982                         goto nfsmout;
  983                 }
  984         } else
  985                 uiop->uio_resid = 0;
  986         vput(vp);
  987         vp = NULL;
  988         nfsm_srvfillattr(vap, fp);
  989         tlen = len - uiop->uio_resid;
  990         cnt = cnt < tlen ? cnt : tlen;
  991         tlen = nfsm_rndup(cnt);
  992         if (len != tlen || tlen != cnt)
  993                 nfsm_adj(mb, len - tlen, tlen - cnt);
  994         if (v3) {
  995                 *tl++ = txdr_unsigned(cnt);
  996                 if (cnt < reqlen)
  997                         *tl++ = nfsrv_nfs_true;
  998                 else
  999                         *tl++ = nfsrv_nfs_false;
 1000         }
 1001         *tl = txdr_unsigned(cnt);
 1002 nfsmout:
 1003         if (vp)
 1004                 vput(vp);
 1005         VFS_UNLOCK_GIANT(vfslocked);
 1006         return(error);
 1007 }
 1008 
 1009 /*
 1010  * nfs write service
 1011  */
 1012 int
 1013 nfsrv_write(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
 1014     struct mbuf **mrq)
 1015 {
 1016         struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
 1017         struct sockaddr *nam = nfsd->nd_nam;
 1018         caddr_t dpos = nfsd->nd_dpos;
 1019         struct ucred *cred = nfsd->nd_cr;
 1020         struct iovec *ivp;
 1021         int i, cnt;
 1022         struct mbuf *mp;
 1023         struct nfs_fattr *fp;
 1024         struct iovec *iv;
 1025         struct vattr va, forat;
 1026         struct vattr *vap = &va;
 1027         u_int32_t *tl;
 1028         caddr_t bpos;
 1029         int error = 0, rdonly, len, forat_ret = 1;
 1030         int ioflags, aftat_ret = 1, retlen = 0, zeroing, adjust;
 1031         int stable = NFSV3WRITE_FILESYNC;
 1032         int v3 = (nfsd->nd_flag & ND_NFSV3);
 1033         struct mbuf *mb, *mreq;
 1034         struct vnode *vp = NULL;
 1035         nfsfh_t nfh;
 1036         fhandle_t *fhp;
 1037         struct uio io, *uiop = &io;
 1038         off_t off;
 1039         struct mount *mntp = NULL;
 1040         int tvfslocked;
 1041         int vfslocked;
 1042 
 1043         nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
 1044         vfslocked = 0;
 1045         if (mrep == NULL) {
 1046                 *mrq = NULL;
 1047                 error = 0;
 1048                 goto nfsmout;
 1049         }
 1050         fhp = &nfh.fh_generic;
 1051         nfsm_srvmtofh(fhp);
 1052         if ((mntp = vfs_getvfs(&fhp->fh_fsid)) == NULL) {
 1053                 error = ESTALE;
 1054                 goto ereply;
 1055         }
 1056         vfslocked = VFS_LOCK_GIANT(mntp);
 1057         (void) vn_start_write(NULL, &mntp, V_WAIT);
 1058         vfs_rel(mntp);          /* The write holds a ref. */
 1059         if (v3) {
 1060                 tl = nfsm_dissect_nonblock(u_int32_t *, 5 * NFSX_UNSIGNED);
 1061                 off = fxdr_hyper(tl);
 1062                 tl += 3;
 1063                 stable = fxdr_unsigned(int, *tl++);
 1064         } else {
 1065                 tl = nfsm_dissect_nonblock(u_int32_t *, 4 * NFSX_UNSIGNED);
 1066                 off = (off_t)fxdr_unsigned(u_int32_t, *++tl);
 1067                 tl += 2;
 1068                 if (nfs_async)
 1069                         stable = NFSV3WRITE_UNSTABLE;
 1070         }
 1071         retlen = len = fxdr_unsigned(int32_t, *tl);
 1072         cnt = i = 0;
 1073 
 1074         /*
 1075          * For NFS Version 2, it is not obvious what a write of zero length
 1076          * should do, but I might as well be consistent with Version 3,
 1077          * which is to return ok so long as there are no permission problems.
 1078          */
 1079         if (len > 0) {
 1080             zeroing = 1;
 1081             mp = mrep;
 1082             while (mp) {
 1083                 if (mp == md) {
 1084                         zeroing = 0;
 1085                         adjust = dpos - mtod(mp, caddr_t);
 1086                         mp->m_len -= adjust;
 1087                         if (mp->m_len > 0 && adjust > 0)
 1088                                 mp->m_data += adjust;
 1089                 }
 1090                 if (zeroing)
 1091                         mp->m_len = 0;
 1092                 else if (mp->m_len > 0) {
 1093                         i += mp->m_len;
 1094                         if (i > len) {
 1095                                 mp->m_len -= (i - len);
 1096                                 zeroing = 1;
 1097                         }
 1098                         if (mp->m_len > 0)
 1099                                 cnt++;
 1100                 }
 1101                 mp = mp->m_next;
 1102             }
 1103         }
 1104         if (len > NFS_MAXDATA || len < 0 || i < len) {
 1105                 error = EIO;
 1106                 nfsm_reply(2 * NFSX_UNSIGNED);
 1107                 if (v3)
 1108                         nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, vap);
 1109                 error = 0;
 1110                 goto nfsmout;
 1111         }
 1112         error = nfsrv_fhtovp(fhp, 1, &vp, &tvfslocked, nfsd, slp,
 1113             nam, &rdonly, TRUE);
 1114         vfslocked = nfsrv_lockedpair(vfslocked, tvfslocked);
 1115         if (error) {
 1116                 vp = NULL;
 1117                 nfsm_reply(2 * NFSX_UNSIGNED);
 1118                 if (v3)
 1119                         nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, vap);
 1120                 error = 0;
 1121                 goto nfsmout;
 1122         }
 1123         if (v3)
 1124                 forat_ret = VOP_GETATTR(vp, &forat, cred);
 1125         if (vp->v_type != VREG) {
 1126                 if (v3)
 1127                         error = EINVAL;
 1128                 else
 1129                         error = (vp->v_type == VDIR) ? EISDIR : EACCES;
 1130         }
 1131         if (!error)
 1132                 error = nfsrv_access(vp, VWRITE, cred, rdonly, 1);
 1133         if (error) {
 1134                 vput(vp);
 1135                 vp = NULL;
 1136                 nfsm_reply(NFSX_WCCDATA(v3));
 1137                 if (v3)
 1138                         nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, vap);
 1139                 error = 0;
 1140                 goto nfsmout;
 1141         }
 1142 
 1143         if (len > 0) {
 1144             ivp = malloc(cnt * sizeof (struct iovec), M_TEMP,
 1145                 M_WAITOK);
 1146             uiop->uio_iov = iv = ivp;
 1147             uiop->uio_iovcnt = cnt;
 1148             mp = mrep;
 1149             while (mp) {
 1150                 if (mp->m_len > 0) {
 1151                         ivp->iov_base = mtod(mp, caddr_t);
 1152                         ivp->iov_len = mp->m_len;
 1153                         ivp++;
 1154                 }
 1155                 mp = mp->m_next;
 1156             }
 1157 
 1158             /*
 1159              * XXX
 1160              * The IO_METASYNC flag indicates that all metadata (and not just
 1161              * enough to ensure data integrity) mus be written to stable storage
 1162              * synchronously.
 1163              * (IO_METASYNC is not yet implemented in 4.4BSD-Lite.)
 1164              */
 1165             if (stable == NFSV3WRITE_UNSTABLE)
 1166                 ioflags = IO_NODELOCKED;
 1167             else if (stable == NFSV3WRITE_DATASYNC)
 1168                 ioflags = (IO_SYNC | IO_NODELOCKED);
 1169             else
 1170                 ioflags = (IO_METASYNC | IO_SYNC | IO_NODELOCKED);
 1171             uiop->uio_resid = len;
 1172             uiop->uio_rw = UIO_WRITE;
 1173             uiop->uio_segflg = UIO_SYSSPACE;
 1174             uiop->uio_td = NULL;
 1175             uiop->uio_offset = off;
 1176             error = VOP_WRITE(vp, uiop, ioflags, cred);
 1177             /* Unlocked write. */
 1178             nfsrvstats.srvvop_writes++;
 1179             free((caddr_t)iv, M_TEMP);
 1180         }
 1181         aftat_ret = VOP_GETATTR(vp, vap, cred);
 1182         vput(vp);
 1183         vp = NULL;
 1184         if (!error)
 1185                 error = aftat_ret;
 1186 ereply:
 1187         nfsm_reply(NFSX_PREOPATTR(v3) + NFSX_POSTOPORFATTR(v3) +
 1188                 2 * NFSX_UNSIGNED + NFSX_WRITEVERF(v3));
 1189         if (v3) {
 1190                 nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, vap);
 1191                 if (error) {
 1192                         error = 0;
 1193                         goto nfsmout;
 1194                 }
 1195                 tl = nfsm_build(u_int32_t *, 4 * NFSX_UNSIGNED);
 1196                 *tl++ = txdr_unsigned(retlen);
 1197                 /*
 1198                  * If nfs_async is set, then pretend the write was FILESYNC.
 1199                  */
 1200                 if (stable == NFSV3WRITE_UNSTABLE && !nfs_async)
 1201                         *tl++ = txdr_unsigned(stable);
 1202                 else
 1203                         *tl++ = txdr_unsigned(NFSV3WRITE_FILESYNC);
 1204                 /*
 1205                  * Actually, there is no need to txdr these fields,
 1206                  * but it may make the values more human readable,
 1207                  * for debugging purposes.
 1208                  */
 1209                 if (nfsver.tv_sec == 0)
 1210                         nfsver = boottime;
 1211                 *tl++ = txdr_unsigned(nfsver.tv_sec);
 1212                 *tl = txdr_unsigned(nfsver.tv_usec);
 1213         } else if (!error) {
 1214                 /* v2 non-error case. */
 1215                 fp = nfsm_build(struct nfs_fattr *, NFSX_V2FATTR);
 1216                 nfsm_srvfillattr(vap, fp);
 1217         }
 1218         error = 0;
 1219 nfsmout:
 1220         if (vp)
 1221                 vput(vp);
 1222         vn_finished_write(mntp);
 1223         VFS_UNLOCK_GIANT(vfslocked);
 1224         return(error);
 1225 }
 1226 
 1227 /*
 1228  * nfs create service
 1229  * now does a truncate to 0 length via. setattr if it already exists
 1230  */
 1231 int
 1232 nfsrv_create(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
 1233     struct mbuf **mrq)
 1234 {
 1235         struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
 1236         struct sockaddr *nam = nfsd->nd_nam;
 1237         caddr_t dpos = nfsd->nd_dpos;
 1238         struct ucred *cred = nfsd->nd_cr;
 1239         struct nfs_fattr *fp;
 1240         struct vattr va, dirfor, diraft;
 1241         struct vattr *vap = &va;
 1242         struct nfsv2_sattr *sp;
 1243         u_int32_t *tl;
 1244         struct nameidata nd;
 1245         caddr_t bpos;
 1246         int error = 0, rdev, len, tsize, dirfor_ret = 1, diraft_ret = 1;
 1247         int v3 = (nfsd->nd_flag & ND_NFSV3), how, exclusive_flag = 0;
 1248         struct mbuf *mb, *mreq;
 1249         struct vnode *dirp = NULL;
 1250         nfsfh_t nfh;
 1251         fhandle_t *fhp;
 1252         u_quad_t tempsize;
 1253         struct timespec cverf;
 1254         struct mount *mp = NULL;
 1255         int tvfslocked;
 1256         int vfslocked;
 1257 
 1258         nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
 1259         vfslocked = 0;
 1260 #ifndef nolint
 1261         rdev = 0;
 1262 #endif
 1263         ndclear(&nd);
 1264 
 1265         fhp = &nfh.fh_generic;
 1266         nfsm_srvmtofh(fhp);
 1267         if ((mp = vfs_getvfs(&fhp->fh_fsid)) == NULL) {
 1268                 error = ESTALE;
 1269                 goto ereply;
 1270         }
 1271         vfslocked = VFS_LOCK_GIANT(mp);
 1272         (void) vn_start_write(NULL, &mp, V_WAIT);
 1273         vfs_rel(mp);            /* The write holds a ref. */
 1274         nfsm_srvnamesiz(len);
 1275 
 1276         nd.ni_cnd.cn_cred = cred;
 1277         nd.ni_cnd.cn_nameiop = CREATE;
 1278         nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF | SAVESTART | MPSAFE;
 1279 
 1280         /*
 1281          * Call namei and do initial cleanup to get a few things
 1282          * out of the way.  If we get an initial error we cleanup
 1283          * and return here to avoid special-casing the invalid nd
 1284          * structure through the rest of the case.  dirp may be
 1285          * set even if an error occurs, but the nd structure will not
 1286          * be valid at all if an error occurs so we have to invalidate it
 1287          * prior to calling nfsm_reply ( which might goto nfsmout ).
 1288          */
 1289         error = nfs_namei(&nd, nfsd, fhp, len, slp, nam, &md, &dpos,
 1290                 &dirp, v3, &dirfor, &dirfor_ret, FALSE);
 1291         vfslocked = nfsrv_lockedpair_nd(vfslocked, &nd);
 1292         if (dirp && !v3) {
 1293                 vrele(dirp);
 1294                 dirp = NULL;
 1295         }
 1296         if (error) {
 1297                 nfsm_reply(NFSX_WCCDATA(v3));
 1298                 if (v3)
 1299                         nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
 1300                 error = 0;
 1301                 goto nfsmout;
 1302         }
 1303 
 1304         /*
 1305          * No error.  Continue.  State:
 1306          *
 1307          *      startdir        is valid ( we release this immediately )
 1308          *      dirp            may be valid
 1309          *      nd.ni_vp        may be valid
 1310          *      nd.ni_dvp       is valid
 1311          *
 1312          * The error state is set through the code and we may also do some
 1313          * opportunistic releasing of vnodes to avoid holding locks through
 1314          * NFS I/O.  The cleanup at the end is a catch-all
 1315          */
 1316 
 1317         VATTR_NULL(vap);
 1318         if (v3) {
 1319                 tl = nfsm_dissect_nonblock(u_int32_t *, NFSX_UNSIGNED);
 1320                 how = fxdr_unsigned(int, *tl);
 1321                 switch (how) {
 1322                 case NFSV3CREATE_GUARDED:
 1323                         if (nd.ni_vp) {
 1324                                 error = EEXIST;
 1325                                 break;
 1326                         }
 1327                         /* fall through */
 1328                 case NFSV3CREATE_UNCHECKED:
 1329                         nfsm_srvsattr(vap);
 1330                         break;
 1331                 case NFSV3CREATE_EXCLUSIVE:
 1332                         tl = nfsm_dissect_nonblock(u_int32_t *,
 1333                             NFSX_V3CREATEVERF);
 1334                         /* Unique bytes, endianness is not important. */
 1335                         cverf.tv_sec  = (int32_t)tl[0];
 1336                         cverf.tv_nsec = tl[1];
 1337                         exclusive_flag = 1;
 1338                         break;
 1339                 };
 1340                 vap->va_type = VREG;
 1341         } else {
 1342                 sp = nfsm_dissect_nonblock(struct nfsv2_sattr *, NFSX_V2SATTR);
 1343                 vap->va_type = IFTOVT(fxdr_unsigned(u_int32_t, sp->sa_mode));
 1344                 if (vap->va_type == VNON)
 1345                         vap->va_type = VREG;
 1346                 vap->va_mode = nfstov_mode(sp->sa_mode);
 1347                 switch (vap->va_type) {
 1348                 case VREG:
 1349                         tsize = fxdr_unsigned(int32_t, sp->sa_size);
 1350                         if (tsize != -1)
 1351                                 vap->va_size = (u_quad_t)tsize;
 1352                         break;
 1353                 case VCHR:
 1354                 case VBLK:
 1355                 case VFIFO:
 1356                         rdev = fxdr_unsigned(long, sp->sa_size);
 1357                         break;
 1358                 default:
 1359                         break;
 1360                 };
 1361         }
 1362 
 1363         /*
 1364          * Iff doesn't exist, create it
 1365          * otherwise just truncate to 0 length
 1366          *   should I set the mode too ?
 1367          *
 1368          * The only possible error we can have at this point is EEXIST.
 1369          * nd.ni_vp will also be non-NULL in that case.
 1370          */
 1371         if (nd.ni_vp == NULL) {
 1372                 if (vap->va_mode == (mode_t)VNOVAL)
 1373                         vap->va_mode = 0;
 1374                 if (vap->va_type == VREG || vap->va_type == VSOCK) {
 1375                         error = VOP_CREATE(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap);
 1376                         if (error)
 1377                                 NDFREE(&nd, NDF_ONLY_PNBUF);
 1378                         else {
 1379                                 if (exclusive_flag) {
 1380                                         exclusive_flag = 0;
 1381                                         VATTR_NULL(vap);
 1382                                         vap->va_atime = cverf;
 1383                                         error = VOP_SETATTR(nd.ni_vp, vap,
 1384                                             cred);
 1385                                 }
 1386                         }
 1387                 } else if (vap->va_type == VCHR || vap->va_type == VBLK ||
 1388                     vap->va_type == VFIFO) {
 1389                         /*
 1390                          * NFSv2-specific code for creating device nodes
 1391                          * and fifos.
 1392                          *
 1393                          * Handle SysV FIFO node special cases.  All other
 1394                          * devices require super user to access.
 1395                          */
 1396                         if (vap->va_type == VCHR && rdev == 0xffffffff)
 1397                                 vap->va_type = VFIFO;
 1398                         if (vap->va_type != VFIFO &&
 1399                             (error = priv_check_cred(cred, PRIV_VFS_MKNOD_DEV,
 1400                             0))) {
 1401                                 goto ereply;
 1402                         }
 1403                         vap->va_rdev = rdev;
 1404                         error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap);
 1405                         if (error) {
 1406                                 NDFREE(&nd, NDF_ONLY_PNBUF);
 1407                                 goto ereply;
 1408                         }
 1409                         vput(nd.ni_vp);
 1410                         nd.ni_vp = NULL;
 1411 
 1412                         /*
 1413                          * release dvp prior to lookup
 1414                          */
 1415                         vput(nd.ni_dvp);
 1416                         nd.ni_dvp = NULL;
 1417                         /*
 1418                          * Setup for lookup.
 1419                          *
 1420                          * Even though LOCKPARENT was cleared, ni_dvp may
 1421                          * be garbage.
 1422                          */
 1423                         nd.ni_cnd.cn_nameiop = LOOKUP;
 1424                         nd.ni_cnd.cn_flags &= ~(LOCKPARENT);
 1425                         nd.ni_cnd.cn_thread = curthread;
 1426                         nd.ni_cnd.cn_cred = cred;
 1427                         tvfslocked = VFS_LOCK_GIANT(nd.ni_startdir->v_mount);
 1428                         if (tvfslocked)
 1429                                 nd.ni_cnd.cn_flags |= GIANTHELD;
 1430                         error = lookup(&nd);
 1431                         nd.ni_dvp = NULL;
 1432                         vfslocked = nfsrv_lockedpair_nd(vfslocked, &nd);
 1433                         nd.ni_cnd.cn_flags &= ~GIANTHELD;
 1434                         if (error)
 1435                                 goto ereply;
 1436 
 1437                         if (nd.ni_cnd.cn_flags & ISSYMLINK) {
 1438                                 error = EINVAL;
 1439                                 goto ereply;
 1440                         }
 1441                 } else {
 1442                         error = ENXIO;
 1443                 }
 1444         } else {
 1445                 if (vap->va_size != -1) {
 1446                         error = nfsrv_access(nd.ni_vp, VWRITE,
 1447                             cred, (nd.ni_cnd.cn_flags & RDONLY), 0);
 1448                         if (!error) {
 1449                                 tempsize = vap->va_size;
 1450                                 VATTR_NULL(vap);
 1451                                 vap->va_size = tempsize;
 1452                                 error = VOP_SETATTR(nd.ni_vp, vap, cred);
 1453                         }
 1454                 }
 1455         }
 1456 
 1457         if (!error) {
 1458                 bzero((caddr_t)fhp, sizeof(nfh));
 1459                 fhp->fh_fsid = nd.ni_vp->v_mount->mnt_stat.f_fsid;
 1460                 error = VOP_VPTOFH(nd.ni_vp, &fhp->fh_fid);
 1461                 if (!error)
 1462                         error = VOP_GETATTR(nd.ni_vp, vap, cred);
 1463         }
 1464         if (v3) {
 1465                 if (exclusive_flag && !error &&
 1466                     bcmp(&cverf, &vap->va_atime, sizeof (cverf)))
 1467                         error = EEXIST;
 1468                 if (dirp == nd.ni_dvp)
 1469                         diraft_ret = VOP_GETATTR(dirp, &diraft, cred);
 1470                 else {
 1471                         /* Drop the other locks to avoid deadlock. */
 1472                         if (nd.ni_dvp) {
 1473                                 if (nd.ni_dvp == nd.ni_vp)
 1474                                         vrele(nd.ni_dvp);
 1475                                 else
 1476                                         vput(nd.ni_dvp);
 1477                         }
 1478                         if (nd.ni_vp)
 1479                                 vput(nd.ni_vp);
 1480                         nd.ni_dvp = NULL;
 1481                         nd.ni_vp = NULL;
 1482 
 1483                         vn_lock(dirp, LK_EXCLUSIVE | LK_RETRY);
 1484                         diraft_ret = VOP_GETATTR(dirp, &diraft, cred);
 1485                         VOP_UNLOCK(dirp, 0);
 1486                 }
 1487         }
 1488 ereply:
 1489         nfsm_reply(NFSX_SRVFH(v3) + NFSX_FATTR(v3) + NFSX_WCCDATA(v3));
 1490         if (v3) {
 1491                 if (!error) {
 1492                         nfsm_srvpostop_fh(fhp);
 1493                         nfsm_srvpostop_attr(0, vap);
 1494                 }
 1495                 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
 1496         } else if (!error) {
 1497                 /* v2 non-error case. */
 1498                 nfsm_srvfhtom(fhp, v3);
 1499                 fp = nfsm_build(struct nfs_fattr *, NFSX_V2FATTR);
 1500                 nfsm_srvfillattr(vap, fp);
 1501         }
 1502         error = 0;
 1503 
 1504 nfsmout:
 1505         if (nd.ni_dvp) {
 1506                 if (nd.ni_dvp == nd.ni_vp)
 1507                         vrele(nd.ni_dvp);
 1508                 else
 1509                         vput(nd.ni_dvp);
 1510         }
 1511         if (nd.ni_vp)
 1512                 vput(nd.ni_vp);
 1513         if (nd.ni_startdir) {
 1514                 vrele(nd.ni_startdir);
 1515                 nd.ni_startdir = NULL;
 1516         }
 1517         if (dirp)
 1518                 vrele(dirp);
 1519         NDFREE(&nd, NDF_ONLY_PNBUF);
 1520         vn_finished_write(mp);
 1521         VFS_UNLOCK_GIANT(vfslocked);
 1522         return (error);
 1523 }
 1524 
 1525 /*
 1526  * nfs v3 mknod service
 1527  */
 1528 int
 1529 nfsrv_mknod(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
 1530     struct mbuf **mrq)
 1531 {
 1532         struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
 1533         struct sockaddr *nam = nfsd->nd_nam;
 1534         caddr_t dpos = nfsd->nd_dpos;
 1535         struct ucred *cred = nfsd->nd_cr;
 1536         struct vattr va, dirfor, diraft;
 1537         struct vattr *vap = &va;
 1538         struct thread *td = curthread;
 1539         u_int32_t *tl;
 1540         struct nameidata nd;
 1541         caddr_t bpos;
 1542         int error = 0, len, dirfor_ret = 1, diraft_ret = 1;
 1543         u_int32_t major, minor;
 1544         enum vtype vtyp;
 1545         struct mbuf *mb, *mreq;
 1546         struct vnode *vp, *dirp = NULL;
 1547         nfsfh_t nfh;
 1548         fhandle_t *fhp;
 1549         struct mount *mp = NULL;
 1550         int v3 = (nfsd->nd_flag & ND_NFSV3);
 1551         int tvfslocked;
 1552         int vfslocked;
 1553 
 1554         nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
 1555         vfslocked = 0;
 1556         if (!v3)
 1557                 panic("nfsrv_mknod: v3 proc called on a v2 connection");
 1558         ndclear(&nd);
 1559 
 1560         fhp = &nfh.fh_generic;
 1561         nfsm_srvmtofh(fhp);
 1562         if ((mp = vfs_getvfs(&fhp->fh_fsid)) == NULL) {
 1563                 error = ESTALE;
 1564                 goto ereply;
 1565         }
 1566         vfslocked = VFS_LOCK_GIANT(mp);
 1567         (void) vn_start_write(NULL, &mp, V_WAIT);
 1568         vfs_rel(mp);            /* The write holds a ref. */
 1569         nfsm_srvnamesiz(len);
 1570 
 1571         nd.ni_cnd.cn_cred = cred;
 1572         nd.ni_cnd.cn_nameiop = CREATE;
 1573         nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF | SAVESTART | MPSAFE;
 1574 
 1575         /*
 1576          * Handle nfs_namei() call.  If an error occurs, the nd structure
 1577          * is not valid.  However, nfsm_*() routines may still jump to
 1578          * nfsmout.
 1579          */
 1580 
 1581         error = nfs_namei(&nd, nfsd, fhp, len, slp, nam, &md, &dpos,
 1582                 &dirp, v3, &dirfor, &dirfor_ret, FALSE);
 1583         vfslocked = nfsrv_lockedpair_nd(vfslocked, &nd);
 1584         if (error) {
 1585                 nfsm_reply(NFSX_WCCDATA(1));
 1586                 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
 1587                 error = 0;
 1588                 goto nfsmout;
 1589         }
 1590         tl = nfsm_dissect_nonblock(u_int32_t *, NFSX_UNSIGNED);
 1591         vtyp = nfsv3tov_type(*tl);
 1592         if (vtyp != VCHR && vtyp != VBLK && vtyp != VSOCK && vtyp != VFIFO) {
 1593                 error = NFSERR_BADTYPE;
 1594                 goto out;
 1595         }
 1596         VATTR_NULL(vap);
 1597         nfsm_srvsattr(vap);
 1598         if (vtyp == VCHR || vtyp == VBLK) {
 1599                 tl = nfsm_dissect_nonblock(u_int32_t *, 2 * NFSX_UNSIGNED);
 1600                 major = fxdr_unsigned(u_int32_t, *tl++);
 1601                 minor = fxdr_unsigned(u_int32_t, *tl);
 1602                 vap->va_rdev = makedev(major, minor);
 1603         }
 1604 
 1605         /*
 1606          * Iff doesn't exist, create it.
 1607          */
 1608         if (nd.ni_vp) {
 1609                 error = EEXIST;
 1610                 goto out;
 1611         }
 1612         vap->va_type = vtyp;
 1613         if (vap->va_mode == (mode_t)VNOVAL)
 1614                 vap->va_mode = 0;
 1615         if (vtyp == VSOCK) {
 1616                 vrele(nd.ni_startdir);
 1617                 nd.ni_startdir = NULL;
 1618                 error = VOP_CREATE(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap);
 1619                 if (error)
 1620                         NDFREE(&nd, NDF_ONLY_PNBUF);
 1621         } else {
 1622                 if (vtyp != VFIFO && (error = priv_check_cred(cred,
 1623                     PRIV_VFS_MKNOD_DEV, 0)))
 1624                         goto out;
 1625                 error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap);
 1626                 if (error) {
 1627                         NDFREE(&nd, NDF_ONLY_PNBUF);
 1628                         goto out;
 1629                 }
 1630                 vput(nd.ni_vp);
 1631                 nd.ni_vp = NULL;
 1632 
 1633                 /*
 1634                  * Release dvp prior to lookup
 1635                  */
 1636                 vput(nd.ni_dvp);
 1637                 nd.ni_dvp = NULL;
 1638 
 1639                 nd.ni_cnd.cn_nameiop = LOOKUP;
 1640                 nd.ni_cnd.cn_flags &= ~(LOCKPARENT);
 1641                 nd.ni_cnd.cn_thread = td;
 1642                 nd.ni_cnd.cn_cred = td->td_ucred;
 1643                 tvfslocked = VFS_LOCK_GIANT(nd.ni_startdir->v_mount);
 1644                 if (tvfslocked)
 1645                         nd.ni_cnd.cn_flags |= GIANTHELD;
 1646                 error = lookup(&nd);
 1647                 nd.ni_dvp = NULL;
 1648                 vfslocked = nfsrv_lockedpair_nd(vfslocked, &nd);
 1649                 nd.ni_cnd.cn_flags &= ~GIANTHELD;
 1650 
 1651                 if (error)
 1652                         goto out;
 1653                 if (nd.ni_cnd.cn_flags & ISSYMLINK)
 1654                         error = EINVAL;
 1655         }
 1656 
 1657         /*
 1658          * send response, cleanup, return.
 1659          */
 1660 out:
 1661         vp = nd.ni_vp;
 1662         if (!error) {
 1663                 bzero((caddr_t)fhp, sizeof(nfh));
 1664                 fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid;
 1665                 error = VOP_VPTOFH(vp, &fhp->fh_fid);
 1666                 if (!error)
 1667                         error = VOP_GETATTR(vp, vap, cred);
 1668         }
 1669         if (nd.ni_dvp) {
 1670                 if (nd.ni_dvp == nd.ni_vp)
 1671                         vrele(nd.ni_dvp);
 1672                 else
 1673                         vput(nd.ni_dvp);
 1674                 nd.ni_dvp = NULL;
 1675         }
 1676         if (vp) {
 1677                 vput(vp);
 1678                 vp = NULL;
 1679                 nd.ni_vp = NULL;
 1680         }
 1681         if (nd.ni_startdir) {
 1682                 vrele(nd.ni_startdir);
 1683                 nd.ni_startdir = NULL;
 1684         }
 1685         NDFREE(&nd, NDF_ONLY_PNBUF);
 1686         if (dirp) {
 1687                 vn_lock(dirp, LK_EXCLUSIVE | LK_RETRY);
 1688                 diraft_ret = VOP_GETATTR(dirp, &diraft, cred);
 1689                 vput(dirp);
 1690         }
 1691 ereply:
 1692         nfsm_reply(NFSX_SRVFH(1) + NFSX_POSTOPATTR(1) + NFSX_WCCDATA(1));
 1693         if (v3) {
 1694                 if (!error) {
 1695                         nfsm_srvpostop_fh(fhp);
 1696                         nfsm_srvpostop_attr(0, vap);
 1697                 }
 1698                 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
 1699         }
 1700         vn_finished_write(mp);
 1701         VFS_UNLOCK_GIANT(vfslocked);
 1702         return (0);
 1703 nfsmout:
 1704         if (nd.ni_dvp) {
 1705                 if (nd.ni_dvp == nd.ni_vp)
 1706                         vrele(nd.ni_dvp);
 1707                 else
 1708                         vput(nd.ni_dvp);
 1709         }
 1710         if (nd.ni_vp)
 1711                 vput(nd.ni_vp);
 1712         if (dirp)
 1713                 vrele(dirp);
 1714         if (nd.ni_startdir)
 1715                 vrele(nd.ni_startdir);
 1716         NDFREE(&nd, NDF_ONLY_PNBUF);
 1717         vn_finished_write(mp);
 1718         VFS_UNLOCK_GIANT(vfslocked);
 1719         return (error);
 1720 }
 1721 
 1722 /*
 1723  * nfs remove service
 1724  */
 1725 int
 1726 nfsrv_remove(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
 1727     struct mbuf **mrq)
 1728 {
 1729         struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
 1730         struct sockaddr *nam = nfsd->nd_nam;
 1731         caddr_t dpos = nfsd->nd_dpos;
 1732         struct ucred *cred = nfsd->nd_cr;
 1733         struct nameidata nd;
 1734         caddr_t bpos;
 1735         int error = 0, len, dirfor_ret = 1, diraft_ret = 1;
 1736         int v3 = (nfsd->nd_flag & ND_NFSV3);
 1737         struct mbuf *mb, *mreq;
 1738         struct vnode *dirp;
 1739         struct vattr dirfor, diraft;
 1740         nfsfh_t nfh;
 1741         fhandle_t *fhp;
 1742         struct mount *mp = NULL;
 1743         int vfslocked;
 1744 
 1745         nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
 1746         ndclear(&nd);
 1747         vfslocked = 0;
 1748 
 1749         fhp = &nfh.fh_generic;
 1750         nfsm_srvmtofh(fhp);
 1751         if ((mp = vfs_getvfs(&fhp->fh_fsid)) == NULL) {
 1752                 error = ESTALE;
 1753                 goto ereply;
 1754         }
 1755         vfslocked = VFS_LOCK_GIANT(mp);
 1756         (void) vn_start_write(NULL, &mp, V_WAIT);
 1757         vfs_rel(mp);            /* The write holds a ref. */
 1758         nfsm_srvnamesiz(len);
 1759 
 1760         nd.ni_cnd.cn_cred = cred;
 1761         nd.ni_cnd.cn_nameiop = DELETE;
 1762         nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF | MPSAFE;
 1763         error = nfs_namei(&nd, nfsd, fhp, len, slp, nam, &md, &dpos,
 1764                 &dirp, v3,  &dirfor, &dirfor_ret, FALSE);
 1765         vfslocked = nfsrv_lockedpair_nd(vfslocked, &nd);
 1766         if (dirp && !v3) {
 1767                 vrele(dirp);
 1768                 dirp = NULL;
 1769         }
 1770         if (error == 0) {
 1771                 if (nd.ni_vp->v_type == VDIR) {
 1772                         error = EPERM;          /* POSIX */
 1773                         goto out;
 1774                 }
 1775                 /*
 1776                  * The root of a mounted filesystem cannot be deleted.
 1777                  */
 1778                 if (nd.ni_vp->v_vflag & VV_ROOT) {
 1779                         error = EBUSY;
 1780                         goto out;
 1781                 }
 1782 out:
 1783                 if (!error) {
 1784                         error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
 1785                         NDFREE(&nd, NDF_ONLY_PNBUF);
 1786                 }
 1787         }
 1788         if (dirp && v3) {
 1789                 if (dirp == nd.ni_dvp)
 1790                         diraft_ret = VOP_GETATTR(dirp, &diraft, cred);
 1791                 else {
 1792                         /* Drop the other locks to avoid deadlock. */
 1793                         if (nd.ni_dvp) {
 1794                                 if (nd.ni_dvp == nd.ni_vp)
 1795                                         vrele(nd.ni_dvp);
 1796                                 else
 1797                                         vput(nd.ni_dvp);
 1798                         }
 1799                         if (nd.ni_vp)
 1800                                 vput(nd.ni_vp);
 1801                         nd.ni_dvp = NULL;
 1802                         nd.ni_vp = NULL;
 1803 
 1804                         vn_lock(dirp, LK_EXCLUSIVE | LK_RETRY);
 1805                         diraft_ret = VOP_GETATTR(dirp, &diraft, cred);
 1806                         VOP_UNLOCK(dirp, 0);
 1807                 }
 1808                 vrele(dirp);
 1809                 dirp = NULL;
 1810         }
 1811 ereply:
 1812         nfsm_reply(NFSX_WCCDATA(v3));
 1813         if (v3) {
 1814                 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
 1815                 error = 0;
 1816         }
 1817 nfsmout:
 1818         NDFREE(&nd, NDF_ONLY_PNBUF);
 1819         if (nd.ni_dvp) {
 1820                 if (nd.ni_dvp == nd.ni_vp)
 1821                         vrele(nd.ni_dvp);
 1822                 else
 1823                         vput(nd.ni_dvp);
 1824         }
 1825         if (nd.ni_vp)
 1826                 vput(nd.ni_vp);
 1827         vn_finished_write(mp);
 1828         VFS_UNLOCK_GIANT(vfslocked);
 1829         return(error);
 1830 }
 1831 
 1832 /*
 1833  * nfs rename service
 1834  */
 1835 int
 1836 nfsrv_rename(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
 1837     struct mbuf **mrq)
 1838 {
 1839         struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
 1840         struct sockaddr *nam = nfsd->nd_nam;
 1841         caddr_t dpos = nfsd->nd_dpos;
 1842         struct ucred *cred = nfsd->nd_cr;
 1843         caddr_t bpos;
 1844         int error = 0, len, len2, fdirfor_ret = 1, fdiraft_ret = 1;
 1845         int tdirfor_ret = 1, tdiraft_ret = 1;
 1846         int v3 = (nfsd->nd_flag & ND_NFSV3);
 1847         struct mbuf *mb, *mreq;
 1848         struct nameidata fromnd, tond;
 1849         struct vnode *fvp, *tvp, *tdvp, *fdirp = NULL;
 1850         struct vnode *tdirp = NULL;
 1851         struct vattr fdirfor, fdiraft, tdirfor, tdiraft;
 1852         nfsfh_t fnfh, tnfh;
 1853         fhandle_t *ffhp, *tfhp;
 1854         uid_t saved_uid;
 1855         struct mount *mp = NULL;
 1856         int vfslocked;
 1857 
 1858         nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
 1859         vfslocked = 0;
 1860 #ifndef nolint
 1861         fvp = NULL;
 1862 #endif
 1863         ffhp = &fnfh.fh_generic;
 1864         tfhp = &tnfh.fh_generic;
 1865 
 1866         /*
 1867          * Clear fields incase goto nfsmout occurs from macro.
 1868          */
 1869 
 1870         ndclear(&fromnd);
 1871         ndclear(&tond);
 1872 
 1873         nfsm_srvmtofh(ffhp);
 1874         if ((mp = vfs_getvfs(&ffhp->fh_fsid)) == NULL) {
 1875                 error = ESTALE;
 1876                 goto out1;
 1877         }
 1878         vfslocked = VFS_LOCK_GIANT(mp);
 1879         (void) vn_start_write(NULL, &mp, V_WAIT);
 1880         vfs_rel(mp);            /* The write holds a ref. */
 1881         nfsm_srvnamesiz(len);
 1882         /*
 1883          * Remember our original uid so that we can reset cr_uid before
 1884          * the second nfs_namei() call, in case it is remapped.
 1885          */
 1886         saved_uid = cred->cr_uid;
 1887         fromnd.ni_cnd.cn_cred = cred;
 1888         fromnd.ni_cnd.cn_nameiop = DELETE;
 1889         fromnd.ni_cnd.cn_flags = WANTPARENT | SAVESTART | MPSAFE;
 1890         error = nfs_namei(&fromnd, nfsd, ffhp, len, slp, nam, &md,
 1891                 &dpos, &fdirp, v3, &fdirfor, &fdirfor_ret, FALSE);
 1892         vfslocked = nfsrv_lockedpair_nd(vfslocked, &fromnd);
 1893         if (fdirp && !v3) {
 1894                 vrele(fdirp);
 1895                 fdirp = NULL;
 1896         }
 1897         if (error) {
 1898                 nfsm_reply(2 * NFSX_WCCDATA(v3));
 1899                 if (v3) {
 1900                         nfsm_srvwcc_data(fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
 1901                         nfsm_srvwcc_data(tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
 1902                 }
 1903                 error = 0;
 1904                 goto nfsmout;
 1905         }
 1906         fvp = fromnd.ni_vp;
 1907         nfsm_srvmtofh(tfhp);
 1908         nfsm_srvnamesiz(len2);
 1909         cred->cr_uid = saved_uid;
 1910         tond.ni_cnd.cn_cred = cred;
 1911         tond.ni_cnd.cn_nameiop = RENAME;
 1912         tond.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART | MPSAFE;
 1913         error = nfs_namei(&tond, nfsd, tfhp, len2, slp, nam, &md,
 1914                 &dpos, &tdirp, v3, &tdirfor, &tdirfor_ret, FALSE);
 1915         vfslocked = nfsrv_lockedpair_nd(vfslocked, &tond);
 1916         if (tdirp && !v3) {
 1917                 vrele(tdirp);
 1918                 tdirp = NULL;
 1919         }
 1920         if (error)
 1921                 goto out1;
 1922 
 1923         tdvp = tond.ni_dvp;
 1924         tvp = tond.ni_vp;
 1925         if (tvp != NULL) {
 1926                 if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
 1927                         if (v3)
 1928                                 error = EEXIST;
 1929                         else
 1930                                 error = EISDIR;
 1931                         goto out;
 1932                 } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
 1933                         if (v3)
 1934                                 error = EEXIST;
 1935                         else
 1936                                 error = ENOTDIR;
 1937                         goto out;
 1938                 }
 1939                 if (tvp->v_type == VDIR && tvp->v_mountedhere) {
 1940                         if (v3)
 1941                                 error = EXDEV;
 1942                         else
 1943                                 error = ENOTEMPTY;
 1944                         goto out;
 1945                 }
 1946         }
 1947         if (fvp->v_type == VDIR && fvp->v_mountedhere) {
 1948                 if (v3)
 1949                         error = EXDEV;
 1950                 else
 1951                         error = ENOTEMPTY;
 1952                 goto out;
 1953         }
 1954         if (fvp->v_mount != tdvp->v_mount) {
 1955                 if (v3)
 1956                         error = EXDEV;
 1957                 else
 1958                         error = ENOTEMPTY;
 1959                 goto out;
 1960         }
 1961         if (fvp == tdvp) {
 1962                 if (v3)
 1963                         error = EINVAL;
 1964                 else
 1965                         error = ENOTEMPTY;
 1966         }
 1967         /*
 1968          * If source is the same as the destination (that is the
 1969          * same vnode with the same name in the same directory),
 1970          * then there is nothing to do.
 1971          */
 1972         if (fvp == tvp && fromnd.ni_dvp == tdvp &&
 1973             fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen &&
 1974             !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr,
 1975               fromnd.ni_cnd.cn_namelen))
 1976                 error = -1;
 1977 out:
 1978         if (!error) {
 1979                 /*
 1980                  * The VOP_RENAME function releases all vnode references &
 1981                  * locks prior to returning so we need to clear the pointers
 1982                  * to bypass cleanup code later on.
 1983                  */
 1984                 error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd,
 1985                                    tond.ni_dvp, tond.ni_vp, &tond.ni_cnd);
 1986                 fromnd.ni_dvp = NULL;
 1987                 fromnd.ni_vp = NULL;
 1988                 tond.ni_dvp = NULL;
 1989                 tond.ni_vp = NULL;
 1990                 if (error) {
 1991                         NDFREE(&fromnd, NDF_ONLY_PNBUF);
 1992                         NDFREE(&tond, NDF_ONLY_PNBUF);
 1993                 }
 1994         } else {
 1995                 if (error == -1)
 1996                         error = 0;
 1997         }
 1998         /* fall through */
 1999 out1:
 2000         nfsm_reply(2 * NFSX_WCCDATA(v3));
 2001         if (v3) {
 2002                 /* Release existing locks to prevent deadlock. */
 2003                 if (tond.ni_dvp) {
 2004                         if (tond.ni_dvp == tond.ni_vp)
 2005                                 vrele(tond.ni_dvp);
 2006                         else
 2007                                 vput(tond.ni_dvp);
 2008                 }
 2009                 if (tond.ni_vp)
 2010                         vput(tond.ni_vp);
 2011                 tond.ni_dvp = NULL;
 2012                 tond.ni_vp = NULL;
 2013 
 2014                 if (fdirp) {
 2015                         vn_lock(fdirp, LK_EXCLUSIVE | LK_RETRY);
 2016                         fdiraft_ret = VOP_GETATTR(fdirp, &fdiraft, cred);
 2017                         VOP_UNLOCK(fdirp, 0);
 2018                 }
 2019                 if (tdirp) {
 2020                         vn_lock(tdirp, LK_EXCLUSIVE | LK_RETRY);
 2021                         tdiraft_ret = VOP_GETATTR(tdirp, &tdiraft, cred);
 2022                         VOP_UNLOCK(tdirp, 0);
 2023                 }
 2024                 nfsm_srvwcc_data(fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
 2025                 nfsm_srvwcc_data(tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
 2026         }
 2027         error = 0;
 2028         /* fall through */
 2029 
 2030 nfsmout:
 2031         /*
 2032          * Clear out tond related fields
 2033          */
 2034         if (tond.ni_dvp) {
 2035                 if (tond.ni_dvp == tond.ni_vp)
 2036                         vrele(tond.ni_dvp);
 2037                 else
 2038                         vput(tond.ni_dvp);
 2039         }
 2040         if (tond.ni_vp)
 2041                 vput(tond.ni_vp);
 2042         if (tdirp)
 2043                 vrele(tdirp);
 2044         if (tond.ni_startdir)
 2045                 vrele(tond.ni_startdir);
 2046         NDFREE(&tond, NDF_ONLY_PNBUF);
 2047         /*
 2048          * Clear out fromnd related fields
 2049          */
 2050         if (fdirp)
 2051                 vrele(fdirp);
 2052         if (fromnd.ni_startdir)
 2053                 vrele(fromnd.ni_startdir);
 2054         NDFREE(&fromnd, NDF_ONLY_PNBUF);
 2055         if (fromnd.ni_dvp)
 2056                 vrele(fromnd.ni_dvp);
 2057         if (fromnd.ni_vp)
 2058                 vrele(fromnd.ni_vp);
 2059 
 2060         vn_finished_write(mp);
 2061         VFS_UNLOCK_GIANT(vfslocked);
 2062         return (error);
 2063 }
 2064 
 2065 /*
 2066  * nfs link service
 2067  */
 2068 int
 2069 nfsrv_link(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
 2070     struct mbuf **mrq)
 2071 {
 2072         struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
 2073         struct sockaddr *nam = nfsd->nd_nam;
 2074         caddr_t dpos = nfsd->nd_dpos;
 2075         struct ucred *cred = nfsd->nd_cr;
 2076         struct nameidata nd;
 2077         caddr_t bpos;
 2078         int error = 0, rdonly, len, dirfor_ret = 1, diraft_ret = 1;
 2079         int getret = 1, v3 = (nfsd->nd_flag & ND_NFSV3);
 2080         struct mbuf *mb, *mreq;
 2081         struct vnode *vp = NULL, *xp, *dirp = NULL;
 2082         struct vattr dirfor, diraft, at;
 2083         nfsfh_t nfh, dnfh;
 2084         fhandle_t *fhp, *dfhp;
 2085         struct mount *mp = NULL;
 2086         int tvfslocked;
 2087         int vfslocked;
 2088 
 2089         nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
 2090         ndclear(&nd);
 2091         vfslocked = 0;
 2092 
 2093         fhp = &nfh.fh_generic;
 2094         dfhp = &dnfh.fh_generic;
 2095         nfsm_srvmtofh(fhp);
 2096         if ((mp = vfs_getvfs(&fhp->fh_fsid)) == NULL) {
 2097                 error = ESTALE;
 2098                 goto ereply;
 2099         }
 2100         vfslocked = VFS_LOCK_GIANT(mp);
 2101         (void) vn_start_write(NULL, &mp, V_WAIT);
 2102         vfs_rel(mp);            /* The write holds a ref. */
 2103         nfsm_srvmtofh(dfhp);
 2104         nfsm_srvnamesiz(len);
 2105 
 2106         error = nfsrv_fhtovp(fhp, TRUE, &vp, &tvfslocked, nfsd, slp,
 2107             nam, &rdonly, TRUE);
 2108         vfslocked = nfsrv_lockedpair(vfslocked, tvfslocked);
 2109         if (error) {
 2110                 nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3));
 2111                 if (v3) {
 2112                         nfsm_srvpostop_attr(getret, &at);
 2113                         nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
 2114                 }
 2115                 vp = NULL;
 2116                 error = 0;
 2117                 goto nfsmout;
 2118         }
 2119         if (v3)
 2120                 getret = VOP_GETATTR(vp, &at, cred);
 2121         if (vp->v_type == VDIR) {
 2122                 error = EPERM;          /* POSIX */
 2123                 goto out1;
 2124         }
 2125         VOP_UNLOCK(vp, 0);
 2126         nd.ni_cnd.cn_cred = cred;
 2127         nd.ni_cnd.cn_nameiop = CREATE;
 2128         nd.ni_cnd.cn_flags = LOCKPARENT | MPSAFE | MPSAFE;
 2129         error = nfs_namei(&nd, nfsd, dfhp, len, slp, nam, &md, &dpos,
 2130                 &dirp, v3, &dirfor, &dirfor_ret, FALSE);
 2131         vfslocked = nfsrv_lockedpair_nd(vfslocked, &nd);
 2132         if (dirp && !v3) {
 2133                 vrele(dirp);
 2134                 dirp = NULL;
 2135         }
 2136         if (error) {
 2137                 vrele(vp);
 2138                 vp = NULL;
 2139                 goto out2;
 2140         }
 2141         xp = nd.ni_vp;
 2142         if (xp != NULL) {
 2143                 error = EEXIST;
 2144                 vrele(vp);
 2145                 vp = NULL;
 2146                 goto out2;
 2147         }
 2148         xp = nd.ni_dvp;
 2149         if (vp->v_mount != xp->v_mount) {
 2150                 error = EXDEV;
 2151                 vrele(vp);
 2152                 vp = NULL;
 2153                 goto out2;
 2154         }
 2155         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
 2156         error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd);
 2157         NDFREE(&nd, NDF_ONLY_PNBUF);
 2158         /* fall through */
 2159 
 2160 out1:
 2161         if (v3)
 2162                 getret = VOP_GETATTR(vp, &at, cred);
 2163 out2:
 2164         if (dirp) {
 2165                 if (dirp == nd.ni_dvp)
 2166                         diraft_ret = VOP_GETATTR(dirp, &diraft, cred);
 2167                 else {
 2168                         /* Release existing locks to prevent deadlock. */
 2169                         if (nd.ni_dvp) {
 2170                                 if (nd.ni_dvp == nd.ni_vp)
 2171                                         vrele(nd.ni_dvp);
 2172                                 else
 2173                                         vput(nd.ni_dvp);
 2174                         }
 2175                         if (nd.ni_vp)
 2176                                 vrele(nd.ni_vp);
 2177                         nd.ni_dvp = NULL;
 2178                         nd.ni_vp = NULL;
 2179 
 2180                         vn_lock(dirp, LK_EXCLUSIVE | LK_RETRY);
 2181                         diraft_ret = VOP_GETATTR(dirp, &diraft, cred);
 2182                         VOP_UNLOCK(dirp, 0);
 2183                 }
 2184         }
 2185 ereply:
 2186         nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3));
 2187         if (v3) {
 2188                 nfsm_srvpostop_attr(getret, &at);
 2189                 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
 2190                 error = 0;
 2191         }
 2192         /* fall through */
 2193 
 2194 nfsmout:
 2195         NDFREE(&nd, NDF_ONLY_PNBUF);
 2196         if (vp)
 2197                 vput(vp);
 2198         if (nd.ni_dvp) {
 2199                 if (nd.ni_dvp == nd.ni_vp)
 2200                         vrele(nd.ni_dvp);
 2201                 else
 2202                         vput(nd.ni_dvp);
 2203         }
 2204         if (dirp)
 2205                 vrele(dirp);
 2206         if (nd.ni_vp)
 2207                 vrele(nd.ni_vp);
 2208         vn_finished_write(mp);
 2209         VFS_UNLOCK_GIANT(vfslocked);
 2210         return(error);
 2211 }
 2212 
 2213 /*
 2214  * nfs symbolic link service
 2215  */
 2216 int
 2217 nfsrv_symlink(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
 2218     struct mbuf **mrq)
 2219 {
 2220         struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
 2221         struct sockaddr *nam = nfsd->nd_nam;
 2222         caddr_t dpos = nfsd->nd_dpos;
 2223         struct ucred *cred = nfsd->nd_cr;
 2224         struct vattr va, dirfor, diraft;
 2225         struct nameidata nd;
 2226         struct vattr *vap = &va;
 2227         struct nfsv2_sattr *sp;
 2228         char *bpos, *pathcp = NULL;
 2229         struct uio io;
 2230         struct iovec iv;
 2231         int error = 0, len, len2, dirfor_ret = 1, diraft_ret = 1;
 2232         int v3 = (nfsd->nd_flag & ND_NFSV3);
 2233         struct mbuf *mb, *mreq;
 2234         struct vnode *dirp = NULL;
 2235         nfsfh_t nfh;
 2236         fhandle_t *fhp;
 2237         struct mount *mp = NULL;
 2238         int tvfslocked;
 2239         int vfslocked;
 2240 
 2241         nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
 2242         ndclear(&nd);
 2243         vfslocked = 0;
 2244 
 2245         fhp = &nfh.fh_generic;
 2246         nfsm_srvmtofh(fhp);
 2247         if ((mp = vfs_getvfs(&fhp->fh_fsid)) == NULL) {
 2248                 error = ESTALE;
 2249                 goto out;
 2250         }
 2251         vfslocked = VFS_LOCK_GIANT(mp);
 2252         (void) vn_start_write(NULL, &mp, V_WAIT);
 2253         vfs_rel(mp);            /* The write holds a ref. */
 2254         nfsm_srvnamesiz(len);
 2255         nd.ni_cnd.cn_cred = cred;
 2256         nd.ni_cnd.cn_nameiop = CREATE;
 2257         nd.ni_cnd.cn_flags = LOCKPARENT | SAVESTART | MPSAFE;
 2258         error = nfs_namei(&nd, nfsd, fhp, len, slp, nam, &md, &dpos,
 2259                 &dirp, v3, &dirfor, &dirfor_ret, FALSE);
 2260         vfslocked = nfsrv_lockedpair_nd(vfslocked, &nd);
 2261         if (error == 0) {
 2262                 VATTR_NULL(vap);
 2263                 if (v3)
 2264                         nfsm_srvsattr(vap);
 2265                 nfsm_srvpathsiz(len2);
 2266         }
 2267         if (dirp && !v3) {
 2268                 vrele(dirp);
 2269                 dirp = NULL;
 2270         }
 2271         if (error)
 2272                 goto out;
 2273         pathcp = malloc(len2 + 1, M_TEMP, M_WAITOK);
 2274         iv.iov_base = pathcp;
 2275         iv.iov_len = len2;
 2276         io.uio_resid = len2;
 2277         io.uio_offset = 0;
 2278         io.uio_iov = &iv;
 2279         io.uio_iovcnt = 1;
 2280         io.uio_segflg = UIO_SYSSPACE;
 2281         io.uio_rw = UIO_READ;
 2282         io.uio_td = NULL;
 2283         nfsm_mtouio(&io, len2);
 2284         if (!v3) {
 2285                 sp = nfsm_dissect_nonblock(struct nfsv2_sattr *, NFSX_V2SATTR);
 2286                 vap->va_mode = nfstov_mode(sp->sa_mode);
 2287         }
 2288         *(pathcp + len2) = '\0';
 2289         if (nd.ni_vp) {
 2290                 error = EEXIST;
 2291                 goto out;
 2292         }
 2293 
 2294         /*
 2295          * issue symlink op.  SAVESTART is set so the underlying path component
 2296          * is only freed by the VOP if an error occurs.
 2297          */
 2298         if (vap->va_mode == (mode_t)VNOVAL)
 2299                 vap->va_mode = 0;
 2300         error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap, pathcp);
 2301         if (error)
 2302                 NDFREE(&nd, NDF_ONLY_PNBUF);
 2303         else
 2304                 vput(nd.ni_vp);
 2305         nd.ni_vp = NULL;
 2306         /*
 2307          * releases directory prior to potential lookup op.
 2308          */
 2309         vput(nd.ni_dvp);
 2310         nd.ni_dvp = NULL;
 2311 
 2312         if (error == 0) {
 2313             if (v3) {
 2314                 /*
 2315                  * Issue lookup.  Leave SAVESTART set so we can easily free
 2316                  * the name buffer later on.
 2317                  *
 2318                  * since LOCKPARENT is not set, ni_dvp will be garbage on
 2319                  * return whether an error occurs or not.
 2320                  */
 2321                 nd.ni_cnd.cn_nameiop = LOOKUP;
 2322                 nd.ni_cnd.cn_flags &= ~(LOCKPARENT | FOLLOW);
 2323                 nd.ni_cnd.cn_flags |= (NOFOLLOW | LOCKLEAF);
 2324                 nd.ni_cnd.cn_thread = curthread;
 2325                 nd.ni_cnd.cn_cred = cred;
 2326                 tvfslocked = VFS_LOCK_GIANT(nd.ni_startdir->v_mount);
 2327                 if (tvfslocked)
 2328                         nd.ni_cnd.cn_flags |= GIANTHELD;
 2329                 error = lookup(&nd);
 2330                 nd.ni_dvp = NULL;
 2331                 vfslocked = nfsrv_lockedpair_nd(vfslocked, &nd);
 2332                 nd.ni_cnd.cn_flags &= ~GIANTHELD;
 2333 
 2334                 if (error == 0) {
 2335                         bzero((caddr_t)fhp, sizeof(nfh));
 2336                         fhp->fh_fsid = nd.ni_vp->v_mount->mnt_stat.f_fsid;
 2337                         error = VOP_VPTOFH(nd.ni_vp, &fhp->fh_fid);
 2338                         if (!error)
 2339                                 error = VOP_GETATTR(nd.ni_vp, vap, cred);
 2340                         vput(nd.ni_vp);
 2341                         nd.ni_vp = NULL;
 2342                 }
 2343             }
 2344         }
 2345 out:
 2346         /*
 2347          * These releases aren't strictly required, does even doing them
 2348          * make any sense? XXX can nfsm_reply() block?
 2349          */
 2350         if (pathcp) {
 2351                 free(pathcp, M_TEMP);
 2352                 pathcp = NULL;
 2353         }
 2354         if (dirp) {
 2355                 vn_lock(dirp, LK_EXCLUSIVE | LK_RETRY);
 2356                 diraft_ret = VOP_GETATTR(dirp, &diraft, cred);
 2357                 VOP_UNLOCK(dirp, 0);
 2358         }
 2359         if (nd.ni_startdir) {
 2360                 vrele(nd.ni_startdir);
 2361                 nd.ni_startdir = NULL;
 2362         }
 2363         nfsm_reply(NFSX_SRVFH(v3) + NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3));
 2364         if (v3) {
 2365                 if (!error) {
 2366                         nfsm_srvpostop_fh(fhp);
 2367                         nfsm_srvpostop_attr(0, vap);
 2368                 }
 2369                 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
 2370         }
 2371         error = 0;
 2372         /* fall through */
 2373 
 2374 nfsmout:
 2375         NDFREE(&nd, NDF_ONLY_PNBUF);
 2376         if (nd.ni_dvp) {
 2377                 if (nd.ni_dvp == nd.ni_vp)
 2378                         vrele(nd.ni_dvp);
 2379                 else
 2380                         vput(nd.ni_dvp);
 2381         }
 2382         if (nd.ni_vp)
 2383                 vrele(nd.ni_vp);
 2384         if (nd.ni_startdir)
 2385                 vrele(nd.ni_startdir);
 2386         if (dirp)
 2387                 vrele(dirp);
 2388         if (pathcp)
 2389                 free(pathcp, M_TEMP);
 2390 
 2391         vn_finished_write(mp);
 2392         VFS_UNLOCK_GIANT(vfslocked);
 2393         return (error);
 2394 }
 2395 
 2396 /*
 2397  * nfs mkdir service
 2398  */
 2399 int
 2400 nfsrv_mkdir(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
 2401     struct mbuf **mrq)
 2402 {
 2403         struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
 2404         struct sockaddr *nam = nfsd->nd_nam;
 2405         caddr_t dpos = nfsd->nd_dpos;
 2406         struct ucred *cred = nfsd->nd_cr;
 2407         struct vattr va, dirfor, diraft;
 2408         struct vattr *vap = &va;
 2409         struct nfs_fattr *fp;
 2410         struct nameidata nd;
 2411         u_int32_t *tl;
 2412         caddr_t bpos;
 2413         int error = 0, len, dirfor_ret = 1, diraft_ret = 1;
 2414         int v3 = (nfsd->nd_flag & ND_NFSV3);
 2415         struct mbuf *mb, *mreq;
 2416         struct vnode *dirp = NULL;
 2417         int vpexcl = 0;
 2418         nfsfh_t nfh;
 2419         fhandle_t *fhp;
 2420         struct mount *mp = NULL;
 2421         int vfslocked;
 2422 
 2423         nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
 2424         ndclear(&nd);
 2425         vfslocked = 0;
 2426 
 2427         fhp = &nfh.fh_generic;
 2428         nfsm_srvmtofh(fhp);
 2429         if ((mp = vfs_getvfs(&fhp->fh_fsid)) == NULL) {
 2430                 error = ESTALE;
 2431                 goto out;
 2432         }
 2433         vfslocked = VFS_LOCK_GIANT(mp);
 2434         (void) vn_start_write(NULL, &mp, V_WAIT);
 2435         vfs_rel(mp);            /* The write holds a ref. */
 2436         nfsm_srvnamesiz(len);
 2437         nd.ni_cnd.cn_cred = cred;
 2438         nd.ni_cnd.cn_nameiop = CREATE;
 2439         nd.ni_cnd.cn_flags = LOCKPARENT | MPSAFE;
 2440 
 2441         error = nfs_namei(&nd, nfsd, fhp, len, slp, nam, &md, &dpos,
 2442                 &dirp, v3, &dirfor, &dirfor_ret, FALSE);
 2443         vfslocked = nfsrv_lockedpair_nd(vfslocked, &nd);
 2444         if (dirp && !v3) {
 2445                 vrele(dirp);
 2446                 dirp = NULL;
 2447         }
 2448         if (error) {
 2449                 nfsm_reply(NFSX_WCCDATA(v3));
 2450                 if (v3)
 2451                         nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
 2452                 error = 0;
 2453                 goto nfsmout;
 2454         }
 2455         VATTR_NULL(vap);
 2456         if (v3) {
 2457                 nfsm_srvsattr(vap);
 2458         } else {
 2459                 tl = nfsm_dissect_nonblock(u_int32_t *, NFSX_UNSIGNED);
 2460                 vap->va_mode = nfstov_mode(*tl++);
 2461         }
 2462 
 2463         /*
 2464          * At this point nd.ni_dvp is referenced and exclusively locked and
 2465          * nd.ni_vp, if it exists, is referenced but not locked.
 2466          */
 2467 
 2468         vap->va_type = VDIR;
 2469         if (nd.ni_vp != NULL) {
 2470                 NDFREE(&nd, NDF_ONLY_PNBUF);
 2471                 error = EEXIST;
 2472                 goto out;
 2473         }
 2474 
 2475         /*
 2476          * Issue mkdir op.  Since SAVESTART is not set, the pathname
 2477          * component is freed by the VOP call.  This will fill-in
 2478          * nd.ni_vp, reference, and exclusively lock it.
 2479          */
 2480         if (vap->va_mode == (mode_t)VNOVAL)
 2481                 vap->va_mode = 0;
 2482         error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap);
 2483         NDFREE(&nd, NDF_ONLY_PNBUF);
 2484         vpexcl = 1;
 2485 
 2486         vput(nd.ni_dvp);
 2487         nd.ni_dvp = NULL;
 2488 
 2489         if (!error) {
 2490                 bzero((caddr_t)fhp, sizeof(nfh));
 2491                 fhp->fh_fsid = nd.ni_vp->v_mount->mnt_stat.f_fsid;
 2492                 error = VOP_VPTOFH(nd.ni_vp, &fhp->fh_fid);
 2493                 if (!error)
 2494                         error = VOP_GETATTR(nd.ni_vp, vap, cred);
 2495         }
 2496 out:
 2497         if (dirp) {
 2498                 if (dirp == nd.ni_dvp) {
 2499                         diraft_ret = VOP_GETATTR(dirp, &diraft, cred);
 2500                 } else {
 2501                         /* Release existing locks to prevent deadlock. */
 2502                         if (nd.ni_dvp) {
 2503                                 NDFREE(&nd, NDF_ONLY_PNBUF);
 2504                                 if (nd.ni_dvp == nd.ni_vp && vpexcl)
 2505                                         vrele(nd.ni_dvp);
 2506                                 else
 2507                                         vput(nd.ni_dvp);
 2508                         }
 2509                         if (nd.ni_vp) {
 2510                                 if (vpexcl)
 2511                                         vput(nd.ni_vp);
 2512                                 else
 2513                                         vrele(nd.ni_vp);
 2514                         }
 2515                         nd.ni_dvp = NULL;
 2516                         nd.ni_vp = NULL;
 2517                         vn_lock(dirp, LK_EXCLUSIVE | LK_RETRY);
 2518                         diraft_ret = VOP_GETATTR(dirp, &diraft, cred);
 2519                         VOP_UNLOCK(dirp, 0);
 2520                 }
 2521         }
 2522         nfsm_reply(NFSX_SRVFH(v3) + NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3));
 2523         if (v3) {
 2524                 if (!error) {
 2525                         nfsm_srvpostop_fh(fhp);
 2526                         nfsm_srvpostop_attr(0, vap);
 2527                 }
 2528                 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
 2529         } else if (!error) {
 2530                 /* v2 non-error case. */
 2531                 nfsm_srvfhtom(fhp, v3);
 2532                 fp = nfsm_build(struct nfs_fattr *, NFSX_V2FATTR);
 2533                 nfsm_srvfillattr(vap, fp);
 2534         }
 2535         error = 0;
 2536         /* fall through */
 2537 
 2538 nfsmout:
 2539         if (nd.ni_dvp) {
 2540                 NDFREE(&nd, NDF_ONLY_PNBUF);
 2541                 if (nd.ni_dvp == nd.ni_vp && vpexcl)
 2542                         vrele(nd.ni_dvp);
 2543                 else
 2544                         vput(nd.ni_dvp);
 2545         }
 2546         if (nd.ni_vp) {
 2547                 if (vpexcl)
 2548                         vput(nd.ni_vp);
 2549                 else
 2550                         vrele(nd.ni_vp);
 2551         }
 2552         if (dirp)
 2553                 vrele(dirp);
 2554         vn_finished_write(mp);
 2555         VFS_UNLOCK_GIANT(vfslocked);
 2556         return (error);
 2557 }
 2558 
 2559 /*
 2560  * nfs rmdir service
 2561  */
 2562 int
 2563 nfsrv_rmdir(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
 2564     struct mbuf **mrq)
 2565 {
 2566         struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
 2567         struct sockaddr *nam = nfsd->nd_nam;
 2568         caddr_t dpos = nfsd->nd_dpos;
 2569         struct ucred *cred = nfsd->nd_cr;
 2570         caddr_t bpos;
 2571         int error = 0, len, dirfor_ret = 1, diraft_ret = 1;
 2572         int v3 = (nfsd->nd_flag & ND_NFSV3);
 2573         struct mbuf *mb, *mreq;
 2574         struct vnode *vp, *dirp = NULL;
 2575         struct vattr dirfor, diraft;
 2576         nfsfh_t nfh;
 2577         fhandle_t *fhp;
 2578         struct nameidata nd;
 2579         struct mount *mp = NULL;
 2580         int vfslocked;
 2581 
 2582         nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
 2583         ndclear(&nd);
 2584         vfslocked = 0;
 2585 
 2586         fhp = &nfh.fh_generic;
 2587         nfsm_srvmtofh(fhp);
 2588         if ((mp = vfs_getvfs(&fhp->fh_fsid)) == NULL) {
 2589                 error = ESTALE;
 2590                 goto out;
 2591         }
 2592         vfslocked = VFS_LOCK_GIANT(mp);
 2593         (void) vn_start_write(NULL, &mp, V_WAIT);
 2594         vfs_rel(mp);            /* The write holds a ref. */
 2595         nfsm_srvnamesiz(len);
 2596         nd.ni_cnd.cn_cred = cred;
 2597         nd.ni_cnd.cn_nameiop = DELETE;
 2598         nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF | MPSAFE;
 2599         error = nfs_namei(&nd, nfsd, fhp, len, slp, nam, &md, &dpos,
 2600                 &dirp, v3, &dirfor, &dirfor_ret, FALSE);
 2601         vfslocked = nfsrv_lockedpair_nd(vfslocked, &nd);
 2602         if (dirp && !v3) {
 2603                 vrele(dirp);
 2604                 dirp = NULL;
 2605         }
 2606         if (error) {
 2607                 nfsm_reply(NFSX_WCCDATA(v3));
 2608                 if (v3)
 2609                         nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
 2610                 error = 0;
 2611                 goto nfsmout;
 2612         }
 2613         vp = nd.ni_vp;
 2614         if (vp->v_type != VDIR) {
 2615                 error = ENOTDIR;
 2616                 goto out;
 2617         }
 2618         /*
 2619          * No rmdir "." please.
 2620          */
 2621         if (nd.ni_dvp == vp) {
 2622                 error = EINVAL;
 2623                 goto out;
 2624         }
 2625         /*
 2626          * The root of a mounted filesystem cannot be deleted.
 2627          */
 2628         if (vp->v_vflag & VV_ROOT)
 2629                 error = EBUSY;
 2630 out:
 2631         /*
 2632          * Issue or abort op.  Since SAVESTART is not set, path name
 2633          * component is freed by the VOP after either.
 2634          */
 2635         if (!error)
 2636                 error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
 2637         NDFREE(&nd, NDF_ONLY_PNBUF);
 2638 
 2639         if (dirp) {
 2640                 if (dirp == nd.ni_dvp)
 2641                         diraft_ret = VOP_GETATTR(dirp, &diraft, cred);
 2642                 else {
 2643                         /* Release existing locks to prevent deadlock. */
 2644                         if (nd.ni_dvp) {
 2645                                 if (nd.ni_dvp == nd.ni_vp)
 2646                                         vrele(nd.ni_dvp);
 2647                                 else
 2648                                         vput(nd.ni_dvp);
 2649                         }
 2650                         if (nd.ni_vp)
 2651                                 vput(nd.ni_vp);
 2652                         nd.ni_dvp = NULL;
 2653                         nd.ni_vp = NULL;
 2654                         vn_lock(dirp, LK_EXCLUSIVE | LK_RETRY);
 2655                         diraft_ret = VOP_GETATTR(dirp, &diraft, cred);
 2656                         VOP_UNLOCK(dirp, 0);
 2657                 }
 2658         }
 2659         nfsm_reply(NFSX_WCCDATA(v3));
 2660         error = 0;
 2661         if (v3)
 2662                 nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
 2663         /* fall through */
 2664 
 2665 nfsmout:
 2666         NDFREE(&nd, NDF_ONLY_PNBUF);
 2667         if (nd.ni_dvp) {
 2668                 if (nd.ni_dvp == nd.ni_vp)
 2669                         vrele(nd.ni_dvp);
 2670                 else
 2671                         vput(nd.ni_dvp);
 2672         }
 2673         if (nd.ni_vp)
 2674                 vput(nd.ni_vp);
 2675         if (dirp)
 2676                 vrele(dirp);
 2677 
 2678         vn_finished_write(mp);
 2679         VFS_UNLOCK_GIANT(vfslocked);
 2680         return(error);
 2681 }
 2682 
 2683 /*
 2684  * nfs readdir service
 2685  * - mallocs what it thinks is enough to read
 2686  *      count rounded up to a multiple of NFS_DIRBLKSIZ <= NFS_MAXREADDIR
 2687  * - calls VOP_READDIR()
 2688  * - loops around building the reply
 2689  *      if the output generated exceeds count break out of loop
 2690  *      The nfsm_clget macro is used here so that the reply will be packed
 2691  *      tightly in mbuf clusters.
 2692  * - it only knows that it has encountered eof when the VOP_READDIR()
 2693  *      reads nothing
 2694  * - as such one readdir rpc will return eof false although you are there
 2695  *      and then the next will return eof
 2696  * - it trims out records with d_fileno == 0
 2697  *      this doesn't matter for Unix clients, but they might confuse clients
 2698  *      for other os'.
 2699  * NB: It is tempting to set eof to true if the VOP_READDIR() reads less
 2700  *      than requested, but this may not apply to all filesystems. For
 2701  *      example, client NFS does not { although it is never remote mounted
 2702  *      anyhow }
 2703  *     The alternate call nfsrv_readdirplus() does lookups as well.
 2704  * PS: The NFS protocol spec. does not clarify what the "count" byte
 2705  *      argument is a count of.. just name strings and file id's or the
 2706  *      entire reply rpc or ...
 2707  *      I tried just file name and id sizes and it confused the Sun client,
 2708  *      so I am using the full rpc size now. The "paranoia.." comment refers
 2709  *      to including the status longwords that are not a part of the dir.
 2710  *      "entry" structures, but are in the rpc.
 2711  */
 2712 struct flrep {
 2713         nfsuint64       fl_off;
 2714         u_int32_t       fl_postopok;
 2715         u_int32_t       fl_fattr[NFSX_V3FATTR / sizeof (u_int32_t)];
 2716         u_int32_t       fl_fhok;
 2717         u_int32_t       fl_fhsize;
 2718         u_int32_t       fl_nfh[NFSX_V3FH / sizeof (u_int32_t)];
 2719 };
 2720 
 2721 int
 2722 nfsrv_readdir(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
 2723     struct mbuf **mrq)
 2724 {
 2725         struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
 2726         struct sockaddr *nam = nfsd->nd_nam;
 2727         caddr_t dpos = nfsd->nd_dpos;
 2728         struct ucred *cred = nfsd->nd_cr;
 2729         char *bp, *be;
 2730         struct mbuf *mp;
 2731         struct dirent *dp;
 2732         caddr_t cp;
 2733         u_int32_t *tl;
 2734         caddr_t bpos;
 2735         struct mbuf *mb, *mreq;
 2736         char *cpos, *cend, *rbuf;
 2737         struct vnode *vp = NULL;
 2738         struct vattr at;
 2739         nfsfh_t nfh;
 2740         fhandle_t *fhp;
 2741         struct uio io;
 2742         struct iovec iv;
 2743         int len, nlen, rem, xfer, tsiz, i, error = 0, getret = 1;
 2744         int siz, cnt, fullsiz, eofflag, rdonly, ncookies;
 2745         int v3 = (nfsd->nd_flag & ND_NFSV3);
 2746         u_quad_t off, toff, verf;
 2747         u_long *cookies = NULL, *cookiep; /* needs to be int64_t or off_t */
 2748         int vfslocked;
 2749 
 2750         nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
 2751         vfslocked = 0;
 2752         fhp = &nfh.fh_generic;
 2753         nfsm_srvmtofh(fhp);
 2754         if (v3) {
 2755                 tl = nfsm_dissect_nonblock(u_int32_t *, 5 * NFSX_UNSIGNED);
 2756                 toff = fxdr_hyper(tl);
 2757                 tl += 2;
 2758                 verf = fxdr_hyper(tl);
 2759                 tl += 2;
 2760         } else {
 2761                 tl = nfsm_dissect_nonblock(u_int32_t *, 2 * NFSX_UNSIGNED);
 2762                 toff = fxdr_unsigned(u_quad_t, *tl++);
 2763                 verf = 0;       /* shut up gcc */
 2764         }
 2765         off = toff;
 2766         cnt = fxdr_unsigned(int, *tl);
 2767         siz = ((cnt + DIRBLKSIZ - 1) & ~(DIRBLKSIZ - 1));
 2768         xfer = NFS_SRVMAXDATA(nfsd);
 2769         if (cnt > xfer)
 2770                 cnt = xfer;
 2771         if (siz > xfer)
 2772                 siz = xfer;
 2773         fullsiz = siz;
 2774         error = nfsrv_fhtovp(fhp, 1, &vp, &vfslocked, nfsd, slp,
 2775             nam, &rdonly, TRUE);
 2776         if (!error && vp->v_type != VDIR) {
 2777                 error = ENOTDIR;
 2778                 vput(vp);
 2779                 vp = NULL;
 2780         }
 2781         if (error) {
 2782                 nfsm_reply(NFSX_UNSIGNED);
 2783                 if (v3)
 2784                         nfsm_srvpostop_attr(getret, &at);
 2785                 error = 0;
 2786                 goto nfsmout;
 2787         }
 2788 
 2789         /*
 2790          * Obtain lock on vnode for this section of the code
 2791          */
 2792         if (v3) {
 2793                 error = getret = VOP_GETATTR(vp, &at, cred);
 2794 #if 0
 2795                 /*
 2796                  * XXX This check may be too strict for Solaris 2.5 clients.
 2797                  */
 2798                 if (!error && toff && verf && verf != at.va_filerev)
 2799                         error = NFSERR_BAD_COOKIE;
 2800 #endif
 2801         }
 2802         if (!error)
 2803                 error = nfsrv_access(vp, VEXEC, cred, rdonly, 0);
 2804         if (error) {
 2805                 vput(vp);
 2806                 vp = NULL;
 2807                 nfsm_reply(NFSX_POSTOPATTR(v3));
 2808                 if (v3)
 2809                         nfsm_srvpostop_attr(getret, &at);
 2810                 error = 0;
 2811                 goto nfsmout;
 2812         }
 2813         VOP_UNLOCK(vp, 0);
 2814 
 2815         /*
 2816          * end section.  Allocate rbuf and continue
 2817          */
 2818         rbuf = malloc(siz, M_TEMP, M_WAITOK);
 2819 again:
 2820         iv.iov_base = rbuf;
 2821         iv.iov_len = fullsiz;
 2822         io.uio_iov = &iv;
 2823         io.uio_iovcnt = 1;
 2824         io.uio_offset = (off_t)off;
 2825         io.uio_resid = fullsiz;
 2826         io.uio_segflg = UIO_SYSSPACE;
 2827         io.uio_rw = UIO_READ;
 2828         io.uio_td = NULL;
 2829         eofflag = 0;
 2830         vn_lock(vp, LK_SHARED | LK_RETRY);
 2831         if (cookies) {
 2832                 free((caddr_t)cookies, M_TEMP);
 2833                 cookies = NULL;
 2834         }
 2835         error = VOP_READDIR(vp, &io, cred, &eofflag, &ncookies, &cookies);
 2836         off = (off_t)io.uio_offset;
 2837         if (!cookies && !error)
 2838                 error = NFSERR_PERM;
 2839         if (v3) {
 2840                 getret = VOP_GETATTR(vp, &at, cred);
 2841                 if (!error)
 2842                         error = getret;
 2843         }
 2844         VOP_UNLOCK(vp, 0);
 2845         if (error) {
 2846                 vrele(vp);
 2847                 vp = NULL;
 2848                 free((caddr_t)rbuf, M_TEMP);
 2849                 if (cookies)
 2850                         free((caddr_t)cookies, M_TEMP);
 2851                 nfsm_reply(NFSX_POSTOPATTR(v3));
 2852                 if (v3)
 2853                         nfsm_srvpostop_attr(getret, &at);
 2854                 error = 0;
 2855                 goto nfsmout;
 2856         }
 2857         if (io.uio_resid) {
 2858                 siz -= io.uio_resid;
 2859 
 2860                 /*
 2861                  * If nothing read, return eof
 2862                  * rpc reply
 2863                  */
 2864                 if (siz == 0) {
 2865                         vrele(vp);
 2866                         vp = NULL;
 2867                         nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_COOKIEVERF(v3) +
 2868                                 2 * NFSX_UNSIGNED);
 2869                         if (v3) {
 2870                                 nfsm_srvpostop_attr(getret, &at);
 2871                                 tl = nfsm_build(u_int32_t *, 4 * NFSX_UNSIGNED);
 2872                                 txdr_hyper(at.va_filerev, tl);
 2873                                 tl += 2;
 2874                         } else
 2875                                 tl = nfsm_build(u_int32_t *, 2 * NFSX_UNSIGNED);
 2876                         *tl++ = nfsrv_nfs_false;
 2877                         *tl = nfsrv_nfs_true;
 2878                         free((caddr_t)rbuf, M_TEMP);
 2879                         free((caddr_t)cookies, M_TEMP);
 2880                         error = 0;
 2881                         goto nfsmout;
 2882                 }
 2883         }
 2884 
 2885         /*
 2886          * Check for degenerate cases of nothing useful read.
 2887          * If so go try again
 2888          */
 2889         cpos = rbuf;
 2890         cend = rbuf + siz;
 2891         dp = (struct dirent *)cpos;
 2892         cookiep = cookies;
 2893         /*
 2894          * For some reason FreeBSD's ufs_readdir() chooses to back the
 2895          * directory offset up to a block boundary, so it is necessary to
 2896          * skip over the records that precede the requested offset. This
 2897          * requires the assumption that file offset cookies monotonically
 2898          * increase.
 2899          */
 2900         while (cpos < cend && ncookies > 0 &&
 2901                 (dp->d_fileno == 0 || dp->d_type == DT_WHT ||
 2902                  ((u_quad_t)(*cookiep)) <= toff)) {
 2903                 cpos += dp->d_reclen;
 2904                 dp = (struct dirent *)cpos;
 2905                 cookiep++;
 2906                 ncookies--;
 2907         }
 2908         if (cpos >= cend || ncookies == 0) {
 2909                 toff = off;
 2910                 siz = fullsiz;
 2911                 goto again;
 2912         }
 2913 
 2914         len = 3 * NFSX_UNSIGNED;        /* paranoia, probably can be 0 */
 2915         nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_COOKIEVERF(v3) + siz);
 2916         if (v3) {
 2917                 nfsm_srvpostop_attr(getret, &at);
 2918                 tl = nfsm_build(u_int32_t *, 2 * NFSX_UNSIGNED);
 2919                 txdr_hyper(at.va_filerev, tl);
 2920         }
 2921         mp = mb;
 2922         bp = bpos;
 2923         be = bp + M_TRAILINGSPACE(mp);
 2924 
 2925         /* Loop through the records and build reply */
 2926         while (cpos < cend && ncookies > 0) {
 2927                 if (dp->d_fileno != 0 && dp->d_type != DT_WHT) {
 2928                         nlen = dp->d_namlen;
 2929                         rem = nfsm_rndup(nlen) - nlen;
 2930                         len += (4 * NFSX_UNSIGNED + nlen + rem);
 2931                         if (v3)
 2932                                 len += 2 * NFSX_UNSIGNED;
 2933                         if (len > cnt) {
 2934                                 eofflag = 0;
 2935                                 break;
 2936                         }
 2937                         /*
 2938                          * Build the directory record xdr from
 2939                          * the dirent entry.
 2940                          */
 2941                         nfsm_clget;
 2942                         *tl = nfsrv_nfs_true;
 2943                         bp += NFSX_UNSIGNED;
 2944                         if (v3) {
 2945                                 nfsm_clget;
 2946                                 *tl = 0;
 2947                                 bp += NFSX_UNSIGNED;
 2948                         }
 2949                         nfsm_clget;
 2950                         *tl = txdr_unsigned(dp->d_fileno);
 2951                         bp += NFSX_UNSIGNED;
 2952                         nfsm_clget;
 2953                         *tl = txdr_unsigned(nlen);
 2954                         bp += NFSX_UNSIGNED;
 2955 
 2956                         /* And loop around copying the name */
 2957                         xfer = nlen;
 2958                         cp = dp->d_name;
 2959                         while (xfer > 0) {
 2960                                 nfsm_clget;
 2961                                 if ((bp+xfer) > be)
 2962                                         tsiz = be-bp;
 2963                                 else
 2964                                         tsiz = xfer;
 2965                                 bcopy(cp, bp, tsiz);
 2966                                 bp += tsiz;
 2967                                 xfer -= tsiz;
 2968                                 if (xfer > 0)
 2969                                         cp += tsiz;
 2970                         }
 2971                         /* And null pad to an int32_t boundary. */
 2972                         for (i = 0; i < rem; i++)
 2973                                 *bp++ = '\0';
 2974                         nfsm_clget;
 2975 
 2976                         /* Finish off the record */
 2977                         if (v3) {
 2978                                 *tl = 0;
 2979                                 bp += NFSX_UNSIGNED;
 2980                                 nfsm_clget;
 2981                         }
 2982                         *tl = txdr_unsigned(*cookiep);
 2983                         bp += NFSX_UNSIGNED;
 2984                 }
 2985                 cpos += dp->d_reclen;
 2986                 dp = (struct dirent *)cpos;
 2987                 cookiep++;
 2988                 ncookies--;
 2989         }
 2990         vrele(vp);
 2991         vp = NULL;
 2992         nfsm_clget;
 2993         *tl = nfsrv_nfs_false;
 2994         bp += NFSX_UNSIGNED;
 2995         nfsm_clget;
 2996         if (eofflag)
 2997                 *tl = nfsrv_nfs_true;
 2998         else
 2999                 *tl = nfsrv_nfs_false;
 3000         bp += NFSX_UNSIGNED;
 3001         if (mp != mb) {
 3002                 if (bp < be)
 3003                         mp->m_len = bp - mtod(mp, caddr_t);
 3004         } else
 3005                 mp->m_len += bp - bpos;
 3006         free((caddr_t)rbuf, M_TEMP);
 3007         free((caddr_t)cookies, M_TEMP);
 3008 
 3009 nfsmout:
 3010         if (vp)
 3011                 vrele(vp);
 3012         VFS_UNLOCK_GIANT(vfslocked);
 3013         return(error);
 3014 }
 3015 
 3016 int
 3017 nfsrv_readdirplus(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
 3018     struct mbuf **mrq)
 3019 {
 3020         struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
 3021         struct sockaddr *nam = nfsd->nd_nam;
 3022         caddr_t dpos = nfsd->nd_dpos;
 3023         struct ucred *cred = nfsd->nd_cr;
 3024         char *bp, *be;
 3025         struct mbuf *mp;
 3026         struct dirent *dp;
 3027         caddr_t cp;
 3028         u_int32_t *tl;
 3029         caddr_t bpos;
 3030         struct mbuf *mb, *mreq;
 3031         char *cpos, *cend, *rbuf;
 3032         struct vnode *vp = NULL, *nvp;
 3033         struct flrep fl;
 3034         nfsfh_t nfh;
 3035         fhandle_t *fhp, *nfhp = (fhandle_t *)fl.fl_nfh;
 3036         struct uio io;
 3037         struct iovec iv;
 3038         struct vattr va, at, *vap = &va;
 3039         struct nfs_fattr *fp;
 3040         int len, nlen, rem, xfer, tsiz, i, error = 0, getret = 1;
 3041         int siz, cnt, fullsiz, eofflag, rdonly, dirlen, ncookies;
 3042         u_quad_t off, toff, verf;
 3043         u_long *cookies = NULL, *cookiep; /* needs to be int64_t or off_t */
 3044         int v3 = (nfsd->nd_flag & ND_NFSV3);
 3045         int vfslocked;
 3046 
 3047         nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
 3048         vfslocked = 0;
 3049         if (!v3)
 3050                 panic("nfsrv_readdirplus: v3 proc called on a v2 connection");
 3051         fhp = &nfh.fh_generic;
 3052         nfsm_srvmtofh(fhp);
 3053         tl = nfsm_dissect_nonblock(u_int32_t *, 6 * NFSX_UNSIGNED);
 3054         toff = fxdr_hyper(tl);
 3055         tl += 2;
 3056         verf = fxdr_hyper(tl);
 3057         tl += 2;
 3058         siz = fxdr_unsigned(int, *tl++);
 3059         cnt = fxdr_unsigned(int, *tl);
 3060         off = toff;
 3061         siz = ((siz + DIRBLKSIZ - 1) & ~(DIRBLKSIZ - 1));
 3062         xfer = NFS_SRVMAXDATA(nfsd);
 3063         if (cnt > xfer)
 3064                 cnt = xfer;
 3065         if (siz > xfer)
 3066                 siz = xfer;
 3067         fullsiz = siz;
 3068         error = nfsrv_fhtovp(fhp, 1, &vp, &vfslocked, nfsd, slp,
 3069             nam, &rdonly, TRUE);
 3070         if (!error && vp->v_type != VDIR) {
 3071                 error = ENOTDIR;
 3072                 vput(vp);
 3073                 vp = NULL;
 3074         }
 3075         if (error) {
 3076                 nfsm_reply(NFSX_UNSIGNED);
 3077                 nfsm_srvpostop_attr(getret, &at);
 3078                 error = 0;
 3079                 goto nfsmout;
 3080         }
 3081         error = getret = VOP_GETATTR(vp, &at, cred);
 3082 #if 0
 3083         /*
 3084          * XXX This check may be too strict for Solaris 2.5 clients.
 3085          */
 3086         if (!error && toff && verf && verf != at.va_filerev)
 3087                 error = NFSERR_BAD_COOKIE;
 3088 #endif
 3089         if (!error)
 3090                 error = nfsrv_access(vp, VEXEC, cred, rdonly, 0);
 3091         if (error) {
 3092                 vput(vp);
 3093                 vp = NULL;
 3094                 nfsm_reply(NFSX_V3POSTOPATTR);
 3095                 nfsm_srvpostop_attr(getret, &at);
 3096                 error = 0;
 3097                 goto nfsmout;
 3098         }
 3099         VOP_UNLOCK(vp, 0);
 3100         rbuf = malloc(siz, M_TEMP, M_WAITOK);
 3101 again:
 3102         iv.iov_base = rbuf;
 3103         iv.iov_len = fullsiz;
 3104         io.uio_iov = &iv;
 3105         io.uio_iovcnt = 1;
 3106         io.uio_offset = (off_t)off;
 3107         io.uio_resid = fullsiz;
 3108         io.uio_segflg = UIO_SYSSPACE;
 3109         io.uio_rw = UIO_READ;
 3110         io.uio_td = NULL;
 3111         eofflag = 0;
 3112         vn_lock(vp, LK_SHARED | LK_RETRY);
 3113         if (cookies) {
 3114                 free((caddr_t)cookies, M_TEMP);
 3115                 cookies = NULL;
 3116         }
 3117         error = VOP_READDIR(vp, &io, cred, &eofflag, &ncookies, &cookies);
 3118         off = (u_quad_t)io.uio_offset;
 3119         getret = VOP_GETATTR(vp, &at, cred);
 3120         VOP_UNLOCK(vp, 0);
 3121         if (!cookies && !error)
 3122                 error = NFSERR_PERM;
 3123         if (!error)
 3124                 error = getret;
 3125         if (error) {
 3126                 vrele(vp);
 3127                 vp = NULL;
 3128                 if (cookies)
 3129                         free((caddr_t)cookies, M_TEMP);
 3130                 free((caddr_t)rbuf, M_TEMP);
 3131                 nfsm_reply(NFSX_V3POSTOPATTR);
 3132                 nfsm_srvpostop_attr(getret, &at);
 3133                 error = 0;
 3134                 goto nfsmout;
 3135         }
 3136         if (io.uio_resid) {
 3137                 siz -= io.uio_resid;
 3138 
 3139                 /*
 3140                  * If nothing read, return eof
 3141                  * rpc reply
 3142                  */
 3143                 if (siz == 0) {
 3144                         vrele(vp);
 3145                         vp = NULL;
 3146                         nfsm_reply(NFSX_V3POSTOPATTR + NFSX_V3COOKIEVERF +
 3147                                 2 * NFSX_UNSIGNED);
 3148                         nfsm_srvpostop_attr(getret, &at);
 3149                         tl = nfsm_build(u_int32_t *, 4 * NFSX_UNSIGNED);
 3150                         txdr_hyper(at.va_filerev, tl);
 3151                         tl += 2;
 3152                         *tl++ = nfsrv_nfs_false;
 3153                         *tl = nfsrv_nfs_true;
 3154                         free((caddr_t)cookies, M_TEMP);
 3155                         free((caddr_t)rbuf, M_TEMP);
 3156                         error = 0;
 3157                         goto nfsmout;
 3158                 }
 3159         }
 3160 
 3161         /*
 3162          * Check for degenerate cases of nothing useful read.
 3163          * If so go try again
 3164          */
 3165         cpos = rbuf;
 3166         cend = rbuf + siz;
 3167         dp = (struct dirent *)cpos;
 3168         cookiep = cookies;
 3169         /*
 3170          * For some reason FreeBSD's ufs_readdir() chooses to back the
 3171          * directory offset up to a block boundary, so it is necessary to
 3172          * skip over the records that precede the requested offset. This
 3173          * requires the assumption that file offset cookies monotonically
 3174          * increase.
 3175          */
 3176         while (cpos < cend && ncookies > 0 &&
 3177                 (dp->d_fileno == 0 || dp->d_type == DT_WHT ||
 3178                  ((u_quad_t)(*cookiep)) <= toff)) {
 3179                 cpos += dp->d_reclen;
 3180                 dp = (struct dirent *)cpos;
 3181                 cookiep++;
 3182                 ncookies--;
 3183         }
 3184         if (cpos >= cend || ncookies == 0) {
 3185                 toff = off;
 3186                 siz = fullsiz;
 3187                 goto again;
 3188         }
 3189 
 3190         /*
 3191          * Probe one of the directory entries to see if the filesystem
 3192          * supports VGET.
 3193          */
 3194         error = VFS_VGET(vp->v_mount, dp->d_fileno, LK_EXCLUSIVE, &nvp);
 3195         if (error) {
 3196                 if (error == EOPNOTSUPP)
 3197                         error = NFSERR_NOTSUPP;
 3198                 else
 3199                         error = NFSERR_SERVERFAULT;
 3200                 vrele(vp);
 3201                 vp = NULL;
 3202                 free((caddr_t)cookies, M_TEMP);
 3203                 free((caddr_t)rbuf, M_TEMP);
 3204                 nfsm_reply(NFSX_V3POSTOPATTR);
 3205                 nfsm_srvpostop_attr(getret, &at);
 3206                 error = 0;
 3207                 goto nfsmout;
 3208         }
 3209         vput(nvp);
 3210         nvp = NULL;
 3211 
 3212         dirlen = len = NFSX_V3POSTOPATTR + NFSX_V3COOKIEVERF +
 3213             2 * NFSX_UNSIGNED;
 3214         nfsm_reply(cnt);
 3215         nfsm_srvpostop_attr(getret, &at);
 3216         tl = nfsm_build(u_int32_t *, 2 * NFSX_UNSIGNED);
 3217         txdr_hyper(at.va_filerev, tl);
 3218         mp = mb;
 3219         bp = bpos;
 3220         be = bp + M_TRAILINGSPACE(mp);
 3221 
 3222         /* Loop through the records and build reply */
 3223         while (cpos < cend && ncookies > 0) {
 3224                 if (dp->d_fileno != 0 && dp->d_type != DT_WHT) {
 3225                         nlen = dp->d_namlen;
 3226                         rem = nfsm_rndup(nlen)-nlen;
 3227 
 3228                         /*
 3229                          * For readdir_and_lookup get the vnode using
 3230                          * the file number.
 3231                          */
 3232                         if (VFS_VGET(vp->v_mount, dp->d_fileno, LK_EXCLUSIVE,
 3233                             &nvp))
 3234                                 goto invalid;
 3235                         bzero((caddr_t)nfhp, NFSX_V3FH);
 3236                         nfhp->fh_fsid =
 3237                                 nvp->v_mount->mnt_stat.f_fsid;
 3238                         /*
 3239                          * XXXRW: Assert the mountpoints are the same so that
 3240                          * we know that acquiring Giant based on the
 3241                          * directory is the right thing for the child.
 3242                          */
 3243                         KASSERT(nvp->v_mount == vp->v_mount,
 3244                             ("nfsrv_readdirplus: nvp mount != vp mount"));
 3245                         if (VOP_VPTOFH(nvp, &nfhp->fh_fid)) {
 3246                                 vput(nvp);
 3247                                 nvp = NULL;
 3248                                 goto invalid;
 3249                         }
 3250                         if (VOP_GETATTR(nvp, vap, cred)) {
 3251                                 vput(nvp);
 3252                                 nvp = NULL;
 3253                                 goto invalid;
 3254                         }
 3255                         vput(nvp);
 3256                         nvp = NULL;
 3257 
 3258                         /*
 3259                          * If either the dircount or maxcount will be
 3260                          * exceeded, get out now. Both of these lengths
 3261                          * are calculated conservatively, including all
 3262                          * XDR overheads.
 3263                          */
 3264                         len += (8 * NFSX_UNSIGNED + nlen + rem + NFSX_V3FH +
 3265                                 NFSX_V3POSTOPATTR);
 3266                         dirlen += (6 * NFSX_UNSIGNED + nlen + rem);
 3267                         if (len > cnt || dirlen > fullsiz) {
 3268                                 eofflag = 0;
 3269                                 break;
 3270                         }
 3271 
 3272                         /*
 3273                          * Build the directory record xdr from
 3274                          * the dirent entry.
 3275                          */
 3276                         fp = (struct nfs_fattr *)&fl.fl_fattr;
 3277                         nfsm_srvfillattr(vap, fp);
 3278                         fl.fl_fhsize = txdr_unsigned(NFSX_V3FH);
 3279                         fl.fl_fhok = nfsrv_nfs_true;
 3280                         fl.fl_postopok = nfsrv_nfs_true;
 3281                         fl.fl_off.nfsuquad[0] = 0;
 3282                         fl.fl_off.nfsuquad[1] = txdr_unsigned(*cookiep);
 3283 
 3284                         nfsm_clget;
 3285                         *tl = nfsrv_nfs_true;
 3286                         bp += NFSX_UNSIGNED;
 3287                         nfsm_clget;
 3288                         *tl = 0;
 3289                         bp += NFSX_UNSIGNED;
 3290                         nfsm_clget;
 3291                         *tl = txdr_unsigned(dp->d_fileno);
 3292                         bp += NFSX_UNSIGNED;
 3293                         nfsm_clget;
 3294                         *tl = txdr_unsigned(nlen);
 3295                         bp += NFSX_UNSIGNED;
 3296 
 3297                         /* And loop around copying the name */
 3298                         xfer = nlen;
 3299                         cp = dp->d_name;
 3300                         while (xfer > 0) {
 3301                                 nfsm_clget;
 3302                                 if ((bp + xfer) > be)
 3303                                         tsiz = be - bp;
 3304                                 else
 3305                                         tsiz = xfer;
 3306                                 bcopy(cp, bp, tsiz);
 3307                                 bp += tsiz;
 3308                                 xfer -= tsiz;
 3309                                 if (xfer > 0)
 3310                                         cp += tsiz;
 3311                         }
 3312                         /* And null pad to an int32_t boundary. */
 3313                         for (i = 0; i < rem; i++)
 3314                                 *bp++ = '\0';
 3315 
 3316                         /*
 3317                          * Now copy the flrep structure out.
 3318                          */
 3319                         xfer = sizeof (struct flrep);
 3320                         cp = (caddr_t)&fl;
 3321                         while (xfer > 0) {
 3322                                 nfsm_clget;
 3323                                 if ((bp + xfer) > be)
 3324                                         tsiz = be - bp;
 3325                                 else
 3326                                         tsiz = xfer;
 3327                                 bcopy(cp, bp, tsiz);
 3328                                 bp += tsiz;
 3329                                 xfer -= tsiz;
 3330                                 if (xfer > 0)
 3331                                         cp += tsiz;
 3332                         }
 3333                 }
 3334 invalid:
 3335                 cpos += dp->d_reclen;
 3336                 dp = (struct dirent *)cpos;
 3337                 cookiep++;
 3338                 ncookies--;
 3339         }
 3340         vrele(vp);
 3341         vp = NULL;
 3342         nfsm_clget;
 3343         *tl = nfsrv_nfs_false;
 3344         bp += NFSX_UNSIGNED;
 3345         nfsm_clget;
 3346         if (eofflag)
 3347                 *tl = nfsrv_nfs_true;
 3348         else
 3349                 *tl = nfsrv_nfs_false;
 3350         bp += NFSX_UNSIGNED;
 3351         if (mp != mb) {
 3352                 if (bp < be)
 3353                         mp->m_len = bp - mtod(mp, caddr_t);
 3354         } else
 3355                 mp->m_len += bp - bpos;
 3356         free((caddr_t)cookies, M_TEMP);
 3357         free((caddr_t)rbuf, M_TEMP);
 3358 nfsmout:
 3359         if (vp)
 3360                 vrele(vp);
 3361         VFS_UNLOCK_GIANT(vfslocked);
 3362         return(error);
 3363 }
 3364 
 3365 /*
 3366  * nfs commit service
 3367  */
 3368 int
 3369 nfsrv_commit(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
 3370     struct mbuf **mrq)
 3371 {
 3372         struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
 3373         struct sockaddr *nam = nfsd->nd_nam;
 3374         caddr_t dpos = nfsd->nd_dpos;
 3375         struct ucred *cred = nfsd->nd_cr;
 3376         struct vattr bfor, aft;
 3377         struct vnode *vp = NULL;
 3378         nfsfh_t nfh;
 3379         fhandle_t *fhp;
 3380         u_int32_t *tl;
 3381         caddr_t bpos;
 3382         int error = 0, rdonly, for_ret = 1, aft_ret = 1, cnt;
 3383         struct mbuf *mb, *mreq;
 3384         u_quad_t off;
 3385         struct mount *mp = NULL;
 3386         int v3 = (nfsd->nd_flag & ND_NFSV3);
 3387         int tvfslocked;
 3388         int vfslocked;
 3389 
 3390         nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
 3391         vfslocked = 0;
 3392         if (!v3)
 3393                 panic("nfsrv_commit: v3 proc called on a v2 connection");
 3394         fhp = &nfh.fh_generic;
 3395         nfsm_srvmtofh(fhp);
 3396         if ((mp = vfs_getvfs(&fhp->fh_fsid)) == NULL) {
 3397                 error = ESTALE;
 3398                 goto ereply;
 3399         }
 3400         vfslocked = VFS_LOCK_GIANT(mp);
 3401         (void) vn_start_write(NULL, &mp, V_WAIT);
 3402         vfs_rel(mp);            /* The write holds a ref. */
 3403         tl = nfsm_dissect_nonblock(u_int32_t *, 3 * NFSX_UNSIGNED);
 3404 
 3405         /*
 3406          * XXX At this time VOP_FSYNC() does not accept offset and byte
 3407          * count parameters, so these arguments are useless (someday maybe).
 3408          */
 3409         off = fxdr_hyper(tl);
 3410         tl += 2;
 3411         cnt = fxdr_unsigned(int, *tl);
 3412         error = nfsrv_fhtovp(fhp, 1, &vp, &tvfslocked, nfsd, slp,
 3413             nam, &rdonly, TRUE);
 3414         vfslocked = nfsrv_lockedpair(vfslocked, tvfslocked);
 3415         if (error) {
 3416                 nfsm_reply(2 * NFSX_UNSIGNED);
 3417                 nfsm_srvwcc_data(for_ret, &bfor, aft_ret, &aft);
 3418                 error = 0;
 3419                 goto nfsmout;
 3420         }
 3421         for_ret = VOP_GETATTR(vp, &bfor, cred);
 3422 
 3423         if (cnt > MAX_COMMIT_COUNT) {
 3424                 /*
 3425                  * Give up and do the whole thing
 3426                  */
 3427                 if (vp->v_object &&
 3428                    (vp->v_object->flags & OBJ_MIGHTBEDIRTY)) {
 3429                         VM_OBJECT_LOCK(vp->v_object);
 3430                         vm_object_page_clean(vp->v_object, 0, 0, OBJPC_SYNC);
 3431                         VM_OBJECT_UNLOCK(vp->v_object);
 3432                 }
 3433                 error = VOP_FSYNC(vp, MNT_WAIT, curthread);
 3434         } else {
 3435                 /*
 3436                  * Locate and synchronously write any buffers that fall
 3437                  * into the requested range.  Note:  we are assuming that
 3438                  * f_iosize is a power of 2.
 3439                  */
 3440                 int iosize = vp->v_mount->mnt_stat.f_iosize;
 3441                 int iomask = iosize - 1;
 3442                 struct bufobj *bo;
 3443                 daddr_t lblkno;
 3444 
 3445                 /*
 3446                  * Align to iosize boundry, super-align to page boundry.
 3447                  */
 3448                 if (off & iomask) {
 3449                         cnt += off & iomask;
 3450                         off &= ~(u_quad_t)iomask;
 3451                 }
 3452                 if (off & PAGE_MASK) {
 3453                         cnt += off & PAGE_MASK;
 3454                         off &= ~(u_quad_t)PAGE_MASK;
 3455                 }
 3456                 lblkno = off / iosize;
 3457 
 3458                 if (vp->v_object &&
 3459                    (vp->v_object->flags & OBJ_MIGHTBEDIRTY)) {
 3460                         VM_OBJECT_LOCK(vp->v_object);
 3461                         vm_object_page_clean(vp->v_object, off / PAGE_SIZE, (cnt + PAGE_MASK) / PAGE_SIZE, OBJPC_SYNC);
 3462                         VM_OBJECT_UNLOCK(vp->v_object);
 3463                 }
 3464 
 3465                 bo = &vp->v_bufobj;
 3466                 BO_LOCK(bo);
 3467                 while (cnt > 0) {
 3468                         struct buf *bp;
 3469 
 3470                         /*
 3471                          * If we have a buffer and it is marked B_DELWRI we
 3472                          * have to lock and write it.  Otherwise the prior
 3473                          * write is assumed to have already been committed.
 3474                          *
 3475                          * gbincore() can return invalid buffers now so we
 3476                          * have to check that bit as well (though B_DELWRI
 3477                          * should not be set if B_INVAL is set there could be
 3478                          * a race here since we haven't locked the buffer).
 3479                          */
 3480                         if ((bp = gbincore(&vp->v_bufobj, lblkno)) != NULL) {
 3481                                 if (BUF_LOCK(bp, LK_EXCLUSIVE | LK_SLEEPFAIL |
 3482                                     LK_INTERLOCK, BO_MTX(bo)) == ENOLCK) {
 3483                                         BO_LOCK(bo);
 3484                                         continue; /* retry */
 3485                                 }
 3486                                 if ((bp->b_flags & (B_DELWRI|B_INVAL)) ==
 3487                                     B_DELWRI) {
 3488                                         bremfree(bp);
 3489                                         bp->b_flags &= ~B_ASYNC;
 3490                                         bwrite(bp);
 3491                                         ++nfs_commit_miss;
 3492                                 } else
 3493                                         BUF_UNLOCK(bp);
 3494                                 BO_LOCK(bo);
 3495                         }
 3496                         ++nfs_commit_blks;
 3497                         if (cnt < iosize)
 3498                                 break;
 3499                         cnt -= iosize;
 3500                         ++lblkno;
 3501                 }
 3502                 BO_UNLOCK(bo);
 3503         }
 3504 
 3505         aft_ret = VOP_GETATTR(vp, &aft, cred);
 3506         vput(vp);
 3507         vp = NULL;
 3508 ereply:
 3509         nfsm_reply(NFSX_V3WCCDATA + NFSX_V3WRITEVERF);
 3510         nfsm_srvwcc_data(for_ret, &bfor, aft_ret, &aft);
 3511         if (!error) {
 3512                 tl = nfsm_build(u_int32_t *, NFSX_V3WRITEVERF);
 3513                 if (nfsver.tv_sec == 0)
 3514                         nfsver = boottime;
 3515                 *tl++ = txdr_unsigned(nfsver.tv_sec);
 3516                 *tl = txdr_unsigned(nfsver.tv_usec);
 3517         } else {
 3518                 error = 0;
 3519         }
 3520 nfsmout:
 3521         if (vp)
 3522                 vput(vp);
 3523         vn_finished_write(mp);
 3524         VFS_UNLOCK_GIANT(vfslocked);
 3525         return(error);
 3526 }
 3527 
 3528 /*
 3529  * nfs statfs service
 3530  */
 3531 int
 3532 nfsrv_statfs(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
 3533     struct mbuf **mrq)
 3534 {
 3535         struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
 3536         struct sockaddr *nam = nfsd->nd_nam;
 3537         caddr_t dpos = nfsd->nd_dpos;
 3538         struct ucred *cred = nfsd->nd_cr;
 3539         struct statfs *sf;
 3540         struct nfs_statfs *sfp;
 3541         caddr_t bpos;
 3542         int error = 0, rdonly, getret = 1;
 3543         int v3 = (nfsd->nd_flag & ND_NFSV3);
 3544         struct mbuf *mb, *mreq;
 3545         struct vnode *vp = NULL;
 3546         struct vattr at;
 3547         nfsfh_t nfh;
 3548         fhandle_t *fhp;
 3549         struct statfs statfs;
 3550         u_quad_t tval;
 3551         int vfslocked;
 3552 
 3553         nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
 3554         vfslocked = 0;
 3555         fhp = &nfh.fh_generic;
 3556         nfsm_srvmtofh(fhp);
 3557         error = nfsrv_fhtovp(fhp, 1, &vp, &vfslocked, nfsd, slp,
 3558             nam, &rdonly, TRUE);
 3559         if (error) {
 3560                 nfsm_reply(NFSX_UNSIGNED);
 3561                 if (v3)
 3562                         nfsm_srvpostop_attr(getret, &at);
 3563                 error = 0;
 3564                 goto nfsmout;
 3565         }
 3566         sf = &statfs;
 3567         error = VFS_STATFS(vp->v_mount, sf);
 3568         getret = VOP_GETATTR(vp, &at, cred);
 3569         vput(vp);
 3570         vp = NULL;
 3571         nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_STATFS(v3));
 3572         if (v3)
 3573                 nfsm_srvpostop_attr(getret, &at);
 3574         if (error) {
 3575                 error = 0;
 3576                 goto nfsmout;
 3577         }
 3578         sfp = nfsm_build(struct nfs_statfs *, NFSX_STATFS(v3));
 3579         if (v3) {
 3580                 tval = (u_quad_t)sf->f_blocks;
 3581                 tval *= (u_quad_t)sf->f_bsize;
 3582                 txdr_hyper(tval, &sfp->sf_tbytes);
 3583                 tval = (u_quad_t)sf->f_bfree;
 3584                 tval *= (u_quad_t)sf->f_bsize;
 3585                 txdr_hyper(tval, &sfp->sf_fbytes);
 3586                 /*
 3587                  * Don't send negative values for available space,
 3588                  * since this field is unsigned in the NFS protocol.
 3589                  * Otherwise, the client would see absurdly high
 3590                  * numbers for free space.
 3591                  */
 3592                 if (sf->f_bavail < 0)
 3593                         tval = 0;
 3594                 else
 3595                         tval = (u_quad_t)sf->f_bavail;
 3596                 tval *= (u_quad_t)sf->f_bsize;
 3597                 txdr_hyper(tval, &sfp->sf_abytes);
 3598                 sfp->sf_tfiles.nfsuquad[0] = 0;
 3599                 sfp->sf_tfiles.nfsuquad[1] = txdr_unsigned(sf->f_files);
 3600                 sfp->sf_ffiles.nfsuquad[0] = 0;
 3601                 sfp->sf_ffiles.nfsuquad[1] = txdr_unsigned(sf->f_ffree);
 3602                 sfp->sf_afiles.nfsuquad[0] = 0;
 3603                 sfp->sf_afiles.nfsuquad[1] = txdr_unsigned(sf->f_ffree);
 3604                 sfp->sf_invarsec = 0;
 3605         } else {
 3606                 sfp->sf_tsize = txdr_unsigned(NFS_MAXDGRAMDATA);
 3607                 sfp->sf_bsize = txdr_unsigned(sf->f_bsize);
 3608                 sfp->sf_blocks = txdr_unsigned(sf->f_blocks);
 3609                 sfp->sf_bfree = txdr_unsigned(sf->f_bfree);
 3610                 if (sf->f_bavail < 0)
 3611                         sfp->sf_bavail = 0;
 3612                 else
 3613                         sfp->sf_bavail = txdr_unsigned(sf->f_bavail);
 3614         }
 3615 nfsmout:
 3616         if (vp)
 3617                 vput(vp);
 3618         VFS_UNLOCK_GIANT(vfslocked);
 3619         return(error);
 3620 }
 3621 
 3622 /*
 3623  * nfs fsinfo service
 3624  */
 3625 int
 3626 nfsrv_fsinfo(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
 3627     struct mbuf **mrq)
 3628 {
 3629         struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
 3630         struct sockaddr *nam = nfsd->nd_nam;
 3631         caddr_t dpos = nfsd->nd_dpos;
 3632         struct ucred *cred = nfsd->nd_cr;
 3633         struct nfsv3_fsinfo *sip;
 3634         caddr_t bpos;
 3635         int error = 0, rdonly, getret = 1, pref;
 3636         struct mbuf *mb, *mreq;
 3637         struct vnode *vp = NULL;
 3638         struct vattr at;
 3639         nfsfh_t nfh;
 3640         fhandle_t *fhp;
 3641         u_quad_t maxfsize;
 3642         struct statfs sb;
 3643         int v3 = (nfsd->nd_flag & ND_NFSV3);
 3644         int vfslocked;
 3645 
 3646         nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
 3647         if (!v3)
 3648                 panic("nfsrv_fsinfo: v3 proc called on a v2 connection");
 3649         fhp = &nfh.fh_generic;
 3650         vfslocked = 0;
 3651         nfsm_srvmtofh(fhp);
 3652         error = nfsrv_fhtovp(fhp, 1, &vp, &vfslocked, nfsd, slp,
 3653             nam, &rdonly, TRUE);
 3654         if (error) {
 3655                 nfsm_reply(NFSX_UNSIGNED);
 3656                 nfsm_srvpostop_attr(getret, &at);
 3657                 error = 0;
 3658                 goto nfsmout;
 3659         }
 3660 
 3661         /* XXX Try to make a guess on the max file size. */
 3662         VFS_STATFS(vp->v_mount, &sb);
 3663         maxfsize = (u_quad_t)0x80000000 * sb.f_bsize - 1;
 3664 
 3665         getret = VOP_GETATTR(vp, &at, cred);
 3666         vput(vp);
 3667         vp = NULL;
 3668         nfsm_reply(NFSX_V3POSTOPATTR + NFSX_V3FSINFO);
 3669         nfsm_srvpostop_attr(getret, &at);
 3670         sip = nfsm_build(struct nfsv3_fsinfo *, NFSX_V3FSINFO);
 3671 
 3672         /*
 3673          * XXX
 3674          * There should be filesystem VFS OP(s) to get this information.
 3675          * For now, assume ufs.
 3676          */
 3677         pref = NFS_SRVMAXDATA(nfsd);
 3678         sip->fs_rtmax = txdr_unsigned(pref);
 3679         sip->fs_rtpref = txdr_unsigned(pref);
 3680         sip->fs_rtmult = txdr_unsigned(NFS_FABLKSIZE);
 3681         sip->fs_wtmax = txdr_unsigned(pref);
 3682         sip->fs_wtpref = txdr_unsigned(pref);
 3683         sip->fs_wtmult = txdr_unsigned(NFS_FABLKSIZE);
 3684         sip->fs_dtpref = txdr_unsigned(pref);
 3685         txdr_hyper(maxfsize, &sip->fs_maxfilesize);
 3686         sip->fs_timedelta.nfsv3_sec = 0;
 3687         sip->fs_timedelta.nfsv3_nsec = txdr_unsigned(1);
 3688         sip->fs_properties = txdr_unsigned(NFSV3FSINFO_LINK |
 3689                 NFSV3FSINFO_SYMLINK | NFSV3FSINFO_HOMOGENEOUS |
 3690                 NFSV3FSINFO_CANSETTIME);
 3691 nfsmout:
 3692         if (vp)
 3693                 vput(vp);
 3694         VFS_UNLOCK_GIANT(vfslocked);
 3695         return(error);
 3696 }
 3697 
 3698 /*
 3699  * nfs pathconf service
 3700  */
 3701 int
 3702 nfsrv_pathconf(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
 3703     struct mbuf **mrq)
 3704 {
 3705         struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
 3706         struct sockaddr *nam = nfsd->nd_nam;
 3707         caddr_t dpos = nfsd->nd_dpos;
 3708         struct ucred *cred = nfsd->nd_cr;
 3709         struct nfsv3_pathconf *pc;
 3710         caddr_t bpos;
 3711         int error = 0, rdonly, getret = 1;
 3712         register_t linkmax, namemax, chownres, notrunc;
 3713         struct mbuf *mb, *mreq;
 3714         struct vnode *vp = NULL;
 3715         struct vattr at;
 3716         nfsfh_t nfh;
 3717         fhandle_t *fhp;
 3718         int v3 = (nfsd->nd_flag & ND_NFSV3);
 3719         int vfslocked;
 3720 
 3721         nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
 3722         if (!v3)
 3723                 panic("nfsrv_pathconf: v3 proc called on a v2 connection");
 3724         vfslocked = 0;
 3725         fhp = &nfh.fh_generic;
 3726         nfsm_srvmtofh(fhp);
 3727         error = nfsrv_fhtovp(fhp, 1, &vp, &vfslocked, nfsd, slp,
 3728             nam, &rdonly, TRUE);
 3729         if (error) {
 3730                 nfsm_reply(NFSX_UNSIGNED);
 3731                 nfsm_srvpostop_attr(getret, &at);
 3732                 error = 0;
 3733                 goto nfsmout;
 3734         }
 3735         error = VOP_PATHCONF(vp, _PC_LINK_MAX, &linkmax);
 3736         if (!error)
 3737                 error = VOP_PATHCONF(vp, _PC_NAME_MAX, &namemax);
 3738         if (!error)
 3739                 error = VOP_PATHCONF(vp, _PC_CHOWN_RESTRICTED, &chownres);
 3740         if (!error)
 3741                 error = VOP_PATHCONF(vp, _PC_NO_TRUNC, &notrunc);
 3742         getret = VOP_GETATTR(vp, &at, cred);
 3743         vput(vp);
 3744         vp = NULL;
 3745         nfsm_reply(NFSX_V3POSTOPATTR + NFSX_V3PATHCONF);
 3746         nfsm_srvpostop_attr(getret, &at);
 3747         if (error) {
 3748                 error = 0;
 3749                 goto nfsmout;
 3750         }
 3751         pc = nfsm_build(struct nfsv3_pathconf *, NFSX_V3PATHCONF);
 3752 
 3753         pc->pc_linkmax = txdr_unsigned(linkmax);
 3754         pc->pc_namemax = txdr_unsigned(namemax);
 3755         pc->pc_notrunc = txdr_unsigned(notrunc);
 3756         pc->pc_chownrestricted = txdr_unsigned(chownres);
 3757 
 3758         /*
 3759          * These should probably be supported by VOP_PATHCONF(), but
 3760          * until msdosfs is exportable (why would you want to?), the
 3761          * Unix defaults should be ok.
 3762          */
 3763         pc->pc_caseinsensitive = nfsrv_nfs_false;
 3764         pc->pc_casepreserving = nfsrv_nfs_true;
 3765 nfsmout:
 3766         if (vp)
 3767                 vput(vp);
 3768         VFS_UNLOCK_GIANT(vfslocked);
 3769         return(error);
 3770 }
 3771 
 3772 /*
 3773  * Null operation, used by clients to ping server
 3774  */
 3775 /* ARGSUSED */
 3776 int
 3777 nfsrv_null(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
 3778     struct mbuf **mrq)
 3779 {
 3780         struct mbuf *mrep = nfsd->nd_mrep;
 3781         caddr_t bpos;
 3782         int error = NFSERR_RETVOID;
 3783         struct mbuf *mb, *mreq;
 3784 
 3785         nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
 3786         nfsm_reply(0);
 3787 nfsmout:
 3788         return (error);
 3789 }
 3790 
 3791 /*
 3792  * No operation, used for obsolete procedures
 3793  */
 3794 /* ARGSUSED */
 3795 int
 3796 nfsrv_noop(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
 3797     struct mbuf **mrq)
 3798 {
 3799         struct mbuf *mrep = nfsd->nd_mrep;
 3800         caddr_t bpos;
 3801         int error;
 3802         struct mbuf *mb, *mreq;
 3803 
 3804         nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
 3805         if (nfsd->nd_repstat)
 3806                 error = nfsd->nd_repstat;
 3807         else
 3808                 error = EPROCUNAVAIL;
 3809         nfsm_reply(0);
 3810         error = 0;
 3811 nfsmout:
 3812         return (error);
 3813 }
 3814 
 3815 /*
 3816  * Perform access checking for vnodes obtained from file handles that would
 3817  * refer to files already opened by a Unix client. You cannot just use
 3818  * vn_writechk() and VOP_ACCESS() for two reasons.
 3819  * 1 - You must check for exported rdonly as well as MNT_RDONLY for the write
 3820  *     case.
 3821  * 2 - The owner is to be given access irrespective of mode bits for some
 3822  *     operations, so that processes that chmod after opening a file don't
 3823  *     break. I don't like this because it opens a security hole, but since
 3824  *     the nfs server opens a security hole the size of a barn door anyhow,
 3825  *     what the heck.
 3826  *
 3827  * The exception to rule 2 is EPERM. If a file is IMMUTABLE, VOP_ACCESS()
 3828  * will return EPERM instead of EACCES. EPERM is always an error.
 3829  */
 3830 static int
 3831 nfsrv_access(struct vnode *vp, accmode_t accmode, struct ucred *cred,
 3832     int rdonly, int override)
 3833 {
 3834         struct vattr vattr;
 3835         int error;
 3836 
 3837         VFS_ASSERT_GIANT(vp->v_mount);
 3838 
 3839         nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
 3840 
 3841         if (accmode & VWRITE) {
 3842                 /* Just vn_writechk() changed to check rdonly */
 3843                 /*
 3844                  * Disallow write attempts on read-only filesystems;
 3845                  * unless the file is a socket or a block or character
 3846                  * device resident on the filesystem.
 3847                  */
 3848                 if (rdonly || (vp->v_mount->mnt_flag & MNT_RDONLY)) {
 3849                         switch (vp->v_type) {
 3850                         case VREG:
 3851                         case VDIR:
 3852                         case VLNK:
 3853                                 return (EROFS);
 3854                         default:
 3855                                 break;
 3856                         }
 3857                 }
 3858                 /*
 3859                  * If there's shared text associated with
 3860                  * the inode, we can't allow writing.
 3861                  */
 3862                 if (vp->v_vflag & VV_TEXT)
 3863                         return (ETXTBSY);
 3864         }
 3865 
 3866         error = VOP_GETATTR(vp, &vattr, cred);
 3867         if (error)
 3868                 return (error);
 3869         error = VOP_ACCESS(vp, accmode, cred, curthread);
 3870         /*
 3871          * Allow certain operations for the owner (reads and writes
 3872          * on files that are already open).
 3873          */
 3874         if (override && error == EACCES && cred->cr_uid == vattr.va_uid)
 3875                 error = 0;
 3876         return (error);
 3877 }

Cache object: 86a1aff8d68c05b97a9a028c44a363c2


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