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

Cache object: d01ed2406a74cc8af79733cb7ebbc5c1


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