The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/nfs/nfs_serv.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: ec67cb4e01f0a498180546c74ced15c5


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.