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

Cache object: 9a92ecab62224eeb7fe33a1d15cd8977


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