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/nfsserver/nfs_serv.c

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

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

Cache object: 39bb75b6410ef96b1732bc14c620ddc8


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