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

Cache object: 970d45defe39f6f35de454efbaed9f59


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