root/nfs/nfs_serv.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. nfsrv3_access
  2. nfsrv_getattr
  3. nfsrv_setattr
  4. nfsrv_lookup
  5. nfsrv_readlink
  6. nfsrv_read
  7. nfsrv_write
  8. nfsrv_writegather
  9. nfsrvw_coalesce
  10. nfsrv_create
  11. nfsrv_mknod
  12. nfsrv_remove
  13. nfsrv_rename
  14. nfsrv_link
  15. nfsrv_symlink
  16. nfsrv_mkdir
  17. nfsrv_rmdir
  18. nfsrv_readdir
  19. nfsrv_readdirplus
  20. nfsrv_commit
  21. nfsrv_statfs
  22. nfsrv_fsinfo
  23. nfsrv_pathconf
  24. nfsrv_null
  25. nfsrv_noop
  26. nfsrv_access

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

/* [<][>][^][v][top][bottom][index][help] */