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

Cache object: 693cc7346331069eeee088790180a04c


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