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


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

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

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

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

Cache object: 16ce14fa3a5d5648968a2b59d7fe525e


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