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

Cache object: fd749b4a10797491cd856f78e65124b6


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