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

Cache object: 7c3372acc153b4d99416a6e169f93781


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