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


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

FreeBSD/Linux Kernel Cross Reference
sys/nfsserver/nfs_serv.c

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

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

Cache object: 4f0815142f27366118004f0ddec4bd86


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