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/nfs/nfs_serv.c

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

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

Cache object: 2258d8a56414d598998ab25cdc60f5ce


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