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

Cache object: 18dc4d80660f267d31f915f227ad8989


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