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/nfsclient/nfs_subs.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_subs.c  8.8 (Berkeley) 5/22/95
   33  */
   34 
   35 #include <sys/cdefs.h>
   36 __FBSDID("$FreeBSD$");
   37 
   38 /*
   39  * These functions support the macros and help fiddle mbuf chains for
   40  * the nfs op functions. They do things like create the rpc header and
   41  * copy data between mbuf chains and uio lists.
   42  */
   43 
   44 #include <sys/param.h>
   45 #include <sys/systm.h>
   46 #include <sys/kernel.h>
   47 #include <sys/bio.h>
   48 #include <sys/buf.h>
   49 #include <sys/proc.h>
   50 #include <sys/mount.h>
   51 #include <sys/vnode.h>
   52 #include <sys/namei.h>
   53 #include <sys/mbuf.h>
   54 #include <sys/socket.h>
   55 #include <sys/stat.h>
   56 #include <sys/malloc.h>
   57 #include <sys/sysent.h>
   58 #include <sys/syscall.h>
   59 #include <sys/sysproto.h>
   60 #include <sys/taskqueue.h>
   61 
   62 #include <vm/vm.h>
   63 #include <vm/vm_object.h>
   64 #include <vm/vm_extern.h>
   65 #include <vm/uma.h>
   66 
   67 #include <rpc/rpcclnt.h>
   68 
   69 #include <nfs/rpcv2.h>
   70 #include <nfs/nfsproto.h>
   71 #include <nfsclient/nfs.h>
   72 #include <nfsclient/nfsnode.h>
   73 #include <nfs/xdr_subs.h>
   74 #include <nfsclient/nfsm_subs.h>
   75 #include <nfsclient/nfsmount.h>
   76 
   77 #include <netinet/in.h>
   78 
   79 /*
   80  * Note that stdarg.h and the ANSI style va_start macro is used for both
   81  * ANSI and traditional C compilers.
   82  */
   83 #include <machine/stdarg.h>
   84 
   85 /*
   86  * Data items converted to xdr at startup, since they are constant
   87  * This is kinda hokey, but may save a little time doing byte swaps
   88  */
   89 u_int32_t       nfs_xdrneg1;
   90 u_int32_t       rpc_call, rpc_vers, rpc_reply, rpc_msgdenied, rpc_autherr,
   91                     rpc_mismatch, rpc_auth_unix, rpc_msgaccepted;
   92 u_int32_t       nfs_true, nfs_false;
   93 
   94 /* And other global data */
   95 static u_int32_t nfs_xid = 0;
   96 static enum vtype nv2tov_type[8]= {
   97         VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON,  VNON
   98 };
   99 
  100 int             nfs_ticks;
  101 int             nfs_pbuf_freecnt = -1;  /* start out unlimited */
  102 
  103 struct nfs_reqq nfs_reqq;
  104 struct mtx nfs_reqq_mtx;
  105 struct nfs_bufq nfs_bufq;
  106 static struct mtx nfs_xid_mtx;
  107 struct task     nfs_nfsiodnew_task;
  108 
  109 /*
  110  * and the reverse mapping from generic to Version 2 procedure numbers
  111  */
  112 int nfsv2_procid[NFS_NPROCS] = {
  113         NFSV2PROC_NULL,
  114         NFSV2PROC_GETATTR,
  115         NFSV2PROC_SETATTR,
  116         NFSV2PROC_LOOKUP,
  117         NFSV2PROC_NOOP,
  118         NFSV2PROC_READLINK,
  119         NFSV2PROC_READ,
  120         NFSV2PROC_WRITE,
  121         NFSV2PROC_CREATE,
  122         NFSV2PROC_MKDIR,
  123         NFSV2PROC_SYMLINK,
  124         NFSV2PROC_CREATE,
  125         NFSV2PROC_REMOVE,
  126         NFSV2PROC_RMDIR,
  127         NFSV2PROC_RENAME,
  128         NFSV2PROC_LINK,
  129         NFSV2PROC_READDIR,
  130         NFSV2PROC_NOOP,
  131         NFSV2PROC_STATFS,
  132         NFSV2PROC_NOOP,
  133         NFSV2PROC_NOOP,
  134         NFSV2PROC_NOOP,
  135         NFSV2PROC_NOOP,
  136 };
  137 
  138 LIST_HEAD(nfsnodehashhead, nfsnode);
  139 
  140 u_int32_t
  141 nfs_xid_gen(void)
  142 {
  143         uint32_t xid;
  144 
  145         mtx_lock(&nfs_xid_mtx);
  146 
  147         /* Get a pretty random xid to start with */
  148         if (!nfs_xid)
  149                 nfs_xid = random();
  150         /*
  151          * Skip zero xid if it should ever happen.
  152          */
  153         if (++nfs_xid == 0)
  154                 nfs_xid++;
  155         xid = nfs_xid;
  156         mtx_unlock(&nfs_xid_mtx);
  157         return xid;
  158 }
  159 
  160 /*
  161  * Create the header for an rpc request packet
  162  * The hsiz is the size of the rest of the nfs request header.
  163  * (just used to decide if a cluster is a good idea)
  164  */
  165 struct mbuf *
  166 nfsm_reqhead(struct vnode *vp, u_long procid, int hsiz)
  167 {
  168         struct mbuf *mb;
  169 
  170         MGET(mb, M_TRYWAIT, MT_DATA);
  171         if (hsiz >= MINCLSIZE)
  172                 MCLGET(mb, M_TRYWAIT);
  173         mb->m_len = 0;
  174         return (mb);
  175 }
  176 
  177 /*
  178  * Build the RPC header and fill in the authorization info.
  179  * The authorization string argument is only used when the credentials
  180  * come from outside of the kernel.
  181  * Returns the head of the mbuf list.
  182  */
  183 struct mbuf *
  184 nfsm_rpchead(struct ucred *cr, int nmflag, int procid, int auth_type,
  185     int auth_len, struct mbuf *mrest, int mrest_len, struct mbuf **mbp,
  186     u_int32_t **xidpp)
  187 {
  188         struct mbuf *mb;
  189         u_int32_t *tl;
  190         caddr_t bpos;
  191         int i;
  192         struct mbuf *mreq;
  193         int grpsiz, authsiz;
  194 
  195         authsiz = nfsm_rndup(auth_len);
  196         MGETHDR(mb, M_TRYWAIT, MT_DATA);
  197         if ((authsiz + 10 * NFSX_UNSIGNED) >= MINCLSIZE) {
  198                 MCLGET(mb, M_TRYWAIT);
  199         } else if ((authsiz + 10 * NFSX_UNSIGNED) < MHLEN) {
  200                 MH_ALIGN(mb, authsiz + 10 * NFSX_UNSIGNED);
  201         } else {
  202                 MH_ALIGN(mb, 8 * NFSX_UNSIGNED);
  203         }
  204         mb->m_len = 0;
  205         mreq = mb;
  206         bpos = mtod(mb, caddr_t);
  207 
  208         /*
  209          * First the RPC header.
  210          */
  211         tl = nfsm_build(u_int32_t *, 8 * NFSX_UNSIGNED);
  212 
  213         *xidpp = tl;
  214         *tl++ = txdr_unsigned(nfs_xid_gen());
  215         *tl++ = rpc_call;
  216         *tl++ = rpc_vers;
  217         *tl++ = txdr_unsigned(NFS_PROG);
  218         if (nmflag & NFSMNT_NFSV3) {
  219                 *tl++ = txdr_unsigned(NFS_VER3);
  220                 *tl++ = txdr_unsigned(procid);
  221         } else {
  222                 *tl++ = txdr_unsigned(NFS_VER2);
  223                 *tl++ = txdr_unsigned(nfsv2_procid[procid]);
  224         }
  225 
  226         /*
  227          * And then the authorization cred.
  228          */
  229         *tl++ = txdr_unsigned(auth_type);
  230         *tl = txdr_unsigned(authsiz);
  231         switch (auth_type) {
  232         case RPCAUTH_UNIX:
  233                 tl = nfsm_build(u_int32_t *, auth_len);
  234                 *tl++ = 0;              /* stamp ?? */
  235                 *tl++ = 0;              /* NULL hostname */
  236                 *tl++ = txdr_unsigned(cr->cr_uid);
  237                 *tl++ = txdr_unsigned(cr->cr_groups[0]);
  238                 grpsiz = (auth_len >> 2) - 5;
  239                 *tl++ = txdr_unsigned(grpsiz);
  240                 for (i = 1; i <= grpsiz; i++)
  241                         *tl++ = txdr_unsigned(cr->cr_groups[i]);
  242                 break;
  243         }
  244 
  245         /*
  246          * And the verifier...
  247          */
  248         tl = nfsm_build(u_int32_t *, 2 * NFSX_UNSIGNED);
  249         *tl++ = txdr_unsigned(RPCAUTH_NULL);
  250         *tl = 0;
  251         mb->m_next = mrest;
  252         mreq->m_pkthdr.len = authsiz + 10 * NFSX_UNSIGNED + mrest_len;
  253         mreq->m_pkthdr.rcvif = NULL;
  254         *mbp = mb;
  255         return (mreq);
  256 }
  257 
  258 /*
  259  * copies a uio scatter/gather list to an mbuf chain.
  260  * NOTE: can ony handle iovcnt == 1
  261  */
  262 int
  263 nfsm_uiotombuf(struct uio *uiop, struct mbuf **mq, int siz, caddr_t *bpos)
  264 {
  265         char *uiocp;
  266         struct mbuf *mp, *mp2;
  267         int xfer, left, mlen;
  268         int uiosiz, clflg, rem;
  269         char *cp;
  270 
  271 #ifdef DIAGNOSTIC
  272         if (uiop->uio_iovcnt != 1)
  273                 panic("nfsm_uiotombuf: iovcnt != 1");
  274 #endif
  275 
  276         if (siz > MLEN)         /* or should it >= MCLBYTES ?? */
  277                 clflg = 1;
  278         else
  279                 clflg = 0;
  280         rem = nfsm_rndup(siz)-siz;
  281         mp = mp2 = *mq;
  282         while (siz > 0) {
  283                 left = uiop->uio_iov->iov_len;
  284                 uiocp = uiop->uio_iov->iov_base;
  285                 if (left > siz)
  286                         left = siz;
  287                 uiosiz = left;
  288                 while (left > 0) {
  289                         mlen = M_TRAILINGSPACE(mp);
  290                         if (mlen == 0) {
  291                                 MGET(mp, M_TRYWAIT, MT_DATA);
  292                                 if (clflg)
  293                                         MCLGET(mp, M_TRYWAIT);
  294                                 mp->m_len = 0;
  295                                 mp2->m_next = mp;
  296                                 mp2 = mp;
  297                                 mlen = M_TRAILINGSPACE(mp);
  298                         }
  299                         xfer = (left > mlen) ? mlen : left;
  300 #ifdef notdef
  301                         /* Not Yet.. */
  302                         if (uiop->uio_iov->iov_op != NULL)
  303                                 (*(uiop->uio_iov->iov_op))
  304                                 (uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
  305                         else
  306 #endif
  307                         if (uiop->uio_segflg == UIO_SYSSPACE)
  308                                 bcopy(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
  309                         else
  310                                 copyin(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
  311                         mp->m_len += xfer;
  312                         left -= xfer;
  313                         uiocp += xfer;
  314                         uiop->uio_offset += xfer;
  315                         uiop->uio_resid -= xfer;
  316                 }
  317                 uiop->uio_iov->iov_base =
  318                     (char *)uiop->uio_iov->iov_base + uiosiz;
  319                 uiop->uio_iov->iov_len -= uiosiz;
  320                 siz -= uiosiz;
  321         }
  322         if (rem > 0) {
  323                 if (rem > M_TRAILINGSPACE(mp)) {
  324                         MGET(mp, M_TRYWAIT, MT_DATA);
  325                         mp->m_len = 0;
  326                         mp2->m_next = mp;
  327                 }
  328                 cp = mtod(mp, caddr_t)+mp->m_len;
  329                 for (left = 0; left < rem; left++)
  330                         *cp++ = '\0';
  331                 mp->m_len += rem;
  332                 *bpos = cp;
  333         } else
  334                 *bpos = mtod(mp, caddr_t)+mp->m_len;
  335         *mq = mp;
  336         return (0);
  337 }
  338 
  339 /*
  340  * Copy a string into mbufs for the hard cases...
  341  */
  342 int
  343 nfsm_strtmbuf(struct mbuf **mb, char **bpos, const char *cp, long siz)
  344 {
  345         struct mbuf *m1 = NULL, *m2;
  346         long left, xfer, len, tlen;
  347         u_int32_t *tl;
  348         int putsize;
  349 
  350         putsize = 1;
  351         m2 = *mb;
  352         left = M_TRAILINGSPACE(m2);
  353         if (left > 0) {
  354                 tl = ((u_int32_t *)(*bpos));
  355                 *tl++ = txdr_unsigned(siz);
  356                 putsize = 0;
  357                 left -= NFSX_UNSIGNED;
  358                 m2->m_len += NFSX_UNSIGNED;
  359                 if (left > 0) {
  360                         bcopy(cp, (caddr_t) tl, left);
  361                         siz -= left;
  362                         cp += left;
  363                         m2->m_len += left;
  364                         left = 0;
  365                 }
  366         }
  367         /* Loop around adding mbufs */
  368         while (siz > 0) {
  369                 MGET(m1, M_TRYWAIT, MT_DATA);
  370                 if (siz > MLEN)
  371                         MCLGET(m1, M_TRYWAIT);
  372                 m1->m_len = NFSMSIZ(m1);
  373                 m2->m_next = m1;
  374                 m2 = m1;
  375                 tl = mtod(m1, u_int32_t *);
  376                 tlen = 0;
  377                 if (putsize) {
  378                         *tl++ = txdr_unsigned(siz);
  379                         m1->m_len -= NFSX_UNSIGNED;
  380                         tlen = NFSX_UNSIGNED;
  381                         putsize = 0;
  382                 }
  383                 if (siz < m1->m_len) {
  384                         len = nfsm_rndup(siz);
  385                         xfer = siz;
  386                         if (xfer < len)
  387                                 *(tl+(xfer>>2)) = 0;
  388                 } else {
  389                         xfer = len = m1->m_len;
  390                 }
  391                 bcopy(cp, (caddr_t) tl, xfer);
  392                 m1->m_len = len+tlen;
  393                 siz -= xfer;
  394                 cp += xfer;
  395         }
  396         *mb = m1;
  397         *bpos = mtod(m1, caddr_t)+m1->m_len;
  398         return (0);
  399 }
  400 
  401 /*
  402  * Called once to initialize data structures...
  403  */
  404 int
  405 nfs_init(struct vfsconf *vfsp)
  406 {
  407         int i;
  408 
  409         nfsmount_zone = uma_zcreate("NFSMOUNT", sizeof(struct nfsmount),
  410             NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0);
  411         rpc_vers = txdr_unsigned(RPC_VER2);
  412         rpc_call = txdr_unsigned(RPC_CALL);
  413         rpc_reply = txdr_unsigned(RPC_REPLY);
  414         rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED);
  415         rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED);
  416         rpc_mismatch = txdr_unsigned(RPC_MISMATCH);
  417         rpc_autherr = txdr_unsigned(RPC_AUTHERR);
  418         rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX);
  419         nfs_true = txdr_unsigned(TRUE);
  420         nfs_false = txdr_unsigned(FALSE);
  421         nfs_xdrneg1 = txdr_unsigned(-1);
  422         nfs_ticks = (hz * NFS_TICKINTVL + 500) / 1000;
  423         if (nfs_ticks < 1)
  424                 nfs_ticks = 1;
  425         /* Ensure async daemons disabled */
  426         for (i = 0; i < NFS_MAXASYNCDAEMON; i++) {
  427                 nfs_iodwant[i] = NFSIOD_NOT_AVAILABLE;
  428                 nfs_iodmount[i] = NULL;
  429         }
  430         nfs_nhinit();                   /* Init the nfsnode table */
  431 
  432         /*
  433          * Initialize reply list and start timer
  434          */
  435         TAILQ_INIT(&nfs_reqq);
  436         callout_init(&nfs_callout, CALLOUT_MPSAFE);
  437         mtx_init(&nfs_reqq_mtx, "NFS reqq lock", NULL, MTX_DEF);
  438         mtx_init(&nfs_iod_mtx, "NFS iod lock", NULL, MTX_DEF);
  439         mtx_init(&nfs_xid_mtx, "NFS xid lock", NULL, MTX_DEF);
  440         TASK_INIT(&nfs_nfsiodnew_task, 0, nfs_nfsiodnew_tq, NULL);
  441 
  442         nfs_pbuf_freecnt = nswbuf / 2 + 1;
  443 
  444         return (0);
  445 }
  446 
  447 int
  448 nfs_uninit(struct vfsconf *vfsp)
  449 {
  450         int i;
  451 
  452         callout_stop(&nfs_callout);
  453 
  454         KASSERT(TAILQ_EMPTY(&nfs_reqq),
  455             ("nfs_uninit: request queue not empty"));
  456 
  457         /*
  458          * Tell all nfsiod processes to exit. Clear nfs_iodmax, and wakeup
  459          * any sleeping nfsiods so they check nfs_iodmax and exit.
  460          * Drain nfsiodnew task before we wait for them to finish.
  461          */
  462         mtx_lock(&nfs_iod_mtx);
  463         nfs_iodmax = 0;
  464         mtx_unlock(&nfs_iod_mtx);
  465         taskqueue_drain(taskqueue_thread, &nfs_nfsiodnew_task);
  466         mtx_lock(&nfs_iod_mtx);
  467         for (i = 0; i < nfs_numasync; i++)
  468                 if (nfs_iodwant[i] == NFSIOD_AVAILABLE)
  469                         wakeup(&nfs_iodwant[i]);
  470         /* The last nfsiod to exit will wake us up when nfs_numasync hits 0 */
  471         while (nfs_numasync)
  472                 msleep(&nfs_numasync, &nfs_iod_mtx, PWAIT, "ioddie", 0);
  473         mtx_unlock(&nfs_iod_mtx);
  474         nfs_nhuninit();
  475         uma_zdestroy(nfsmount_zone);
  476         return (0);
  477 }
  478 
  479 void 
  480 nfs_dircookie_lock(struct nfsnode *np)
  481 {
  482         mtx_lock(&np->n_mtx);
  483         while (np->n_flag & NDIRCOOKIELK)
  484                 (void) msleep(&np->n_flag, &np->n_mtx, PZERO, "nfsdirlk", 0);
  485         np->n_flag |= NDIRCOOKIELK;
  486         mtx_unlock(&np->n_mtx);
  487 }
  488 
  489 void 
  490 nfs_dircookie_unlock(struct nfsnode *np)
  491 {
  492         mtx_lock(&np->n_mtx);
  493         np->n_flag &= ~NDIRCOOKIELK;
  494         wakeup(&np->n_flag);
  495         mtx_unlock(&np->n_mtx);
  496 }
  497 
  498 int
  499 nfs_upgrade_vnlock(struct vnode *vp, struct thread *td)
  500 {
  501         int old_lock;
  502         
  503         if ((old_lock = VOP_ISLOCKED(vp, td)) != LK_EXCLUSIVE) {
  504                 if (old_lock == LK_SHARED) {
  505                         /* Upgrade to exclusive lock, this might block */
  506                         vn_lock(vp, LK_UPGRADE | LK_RETRY, td);
  507                 } else {
  508                         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
  509                 }
  510         }
  511         return old_lock;
  512 }
  513 
  514 void
  515 nfs_downgrade_vnlock(struct vnode *vp, struct thread *td, int old_lock)
  516 {
  517         if (old_lock != LK_EXCLUSIVE) {
  518                 if (old_lock == LK_SHARED) {
  519                         /* Downgrade from exclusive lock, this might block */
  520                         vn_lock(vp, LK_DOWNGRADE, td);
  521                 } else {
  522                         VOP_UNLOCK(vp, 0, td);
  523                 }
  524         }
  525 }
  526 
  527 void
  528 nfs_printf(const char *fmt, ...)
  529 {
  530         va_list ap;
  531 
  532         mtx_lock(&Giant);
  533         va_start(ap, fmt);
  534         printf(fmt, ap);
  535         va_end(ap);
  536         mtx_unlock(&Giant);
  537 }
  538 
  539 /*
  540  * Attribute cache routines.
  541  * nfs_loadattrcache() - loads or updates the cache contents from attributes
  542  *      that are on the mbuf list
  543  * nfs_getattrcache() - returns valid attributes if found in cache, returns
  544  *      error otherwise
  545  */
  546 
  547 /*
  548  * Load the attribute cache (that lives in the nfsnode entry) with
  549  * the values on the mbuf list and
  550  * Iff vap not NULL
  551  *    copy the attributes to *vaper
  552  */
  553 int
  554 nfs_loadattrcache(struct vnode **vpp, struct mbuf **mdp, caddr_t *dposp,
  555                   struct vattr *vaper, int dontshrink)
  556 {
  557         struct vnode *vp = *vpp;
  558         struct vattr *vap;
  559         struct nfs_fattr *fp;
  560         struct nfsnode *np;
  561         int32_t t1;
  562         caddr_t cp2;
  563         int rdev;
  564         struct mbuf *md;
  565         enum vtype vtyp;
  566         u_short vmode;
  567         struct timespec mtime, mtime_save;
  568         int v3 = NFS_ISV3(vp);
  569 
  570         md = *mdp;
  571         t1 = (mtod(md, caddr_t) + md->m_len) - *dposp;
  572         cp2 = nfsm_disct(mdp, dposp, NFSX_FATTR(v3), t1, M_TRYWAIT);
  573         if (cp2 == NULL)
  574                 return EBADRPC;
  575         fp = (struct nfs_fattr *)cp2;
  576         if (v3) {
  577                 vtyp = nfsv3tov_type(fp->fa_type);
  578                 vmode = fxdr_unsigned(u_short, fp->fa_mode);
  579                 rdev = makedev(fxdr_unsigned(int, fp->fa3_rdev.specdata1),
  580                         fxdr_unsigned(int, fp->fa3_rdev.specdata2));
  581                 fxdr_nfsv3time(&fp->fa3_mtime, &mtime);
  582         } else {
  583                 vtyp = nfsv2tov_type(fp->fa_type);
  584                 vmode = fxdr_unsigned(u_short, fp->fa_mode);
  585                 /*
  586                  * XXX
  587                  *
  588                  * The duplicate information returned in fa_type and fa_mode
  589                  * is an ambiguity in the NFS version 2 protocol.
  590                  *
  591                  * VREG should be taken literally as a regular file.  If a
  592                  * server intents to return some type information differently
  593                  * in the upper bits of the mode field (e.g. for sockets, or
  594                  * FIFOs), NFSv2 mandates fa_type to be VNON.  Anyway, we
  595                  * leave the examination of the mode bits even in the VREG
  596                  * case to avoid breakage for bogus servers, but we make sure
  597                  * that there are actually type bits set in the upper part of
  598                  * fa_mode (and failing that, trust the va_type field).
  599                  *
  600                  * NFSv3 cleared the issue, and requires fa_mode to not
  601                  * contain any type information (while also introduing sockets
  602                  * and FIFOs for fa_type).
  603                  */
  604                 if (vtyp == VNON || (vtyp == VREG && (vmode & S_IFMT) != 0))
  605                         vtyp = IFTOVT(vmode);
  606                 rdev = fxdr_unsigned(int32_t, fp->fa2_rdev);
  607                 fxdr_nfsv2time(&fp->fa2_mtime, &mtime);
  608 
  609                 /*
  610                  * Really ugly NFSv2 kludge.
  611                  */
  612                 if (vtyp == VCHR && rdev == 0xffffffff)
  613                         vtyp = VFIFO;
  614         }
  615 
  616         /*
  617          * If v_type == VNON it is a new node, so fill in the v_type,
  618          * n_mtime fields. Check to see if it represents a special
  619          * device, and if so, check for a possible alias. Once the
  620          * correct vnode has been obtained, fill in the rest of the
  621          * information.
  622          */
  623         np = VTONFS(vp);
  624         mtx_lock(&np->n_mtx);
  625         if (vp->v_type != vtyp) {
  626                 vp->v_type = vtyp;
  627                 if (vp->v_type == VFIFO)
  628                         vp->v_op = &nfs_fifoops;
  629                 np->n_mtime = mtime;
  630         }
  631         vap = &np->n_vattr;
  632         vap->va_type = vtyp;
  633         vap->va_mode = (vmode & 07777);
  634         vap->va_rdev = rdev;
  635         mtime_save = vap->va_mtime;
  636         vap->va_mtime = mtime;
  637         vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0];
  638         if (v3) {
  639                 vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink);
  640                 vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid);
  641                 vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid);
  642                 vap->va_size = fxdr_hyper(&fp->fa3_size);
  643                 vap->va_blocksize = NFS_FABLKSIZE;
  644                 vap->va_bytes = fxdr_hyper(&fp->fa3_used);
  645                 vap->va_fileid = fxdr_unsigned(int32_t,
  646                     fp->fa3_fileid.nfsuquad[1]);
  647                 fxdr_nfsv3time(&fp->fa3_atime, &vap->va_atime);
  648                 fxdr_nfsv3time(&fp->fa3_ctime, &vap->va_ctime);
  649                 vap->va_flags = 0;
  650                 vap->va_filerev = 0;
  651         } else {
  652                 vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink);
  653                 vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid);
  654                 vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid);
  655                 vap->va_size = fxdr_unsigned(u_int32_t, fp->fa2_size);
  656                 vap->va_blocksize = fxdr_unsigned(int32_t, fp->fa2_blocksize);
  657                 vap->va_bytes = (u_quad_t)fxdr_unsigned(int32_t, fp->fa2_blocks)
  658                     * NFS_FABLKSIZE;
  659                 vap->va_fileid = fxdr_unsigned(int32_t, fp->fa2_fileid);
  660                 fxdr_nfsv2time(&fp->fa2_atime, &vap->va_atime);
  661                 vap->va_flags = 0;
  662                 vap->va_ctime.tv_sec = fxdr_unsigned(u_int32_t,
  663                     fp->fa2_ctime.nfsv2_sec);
  664                 vap->va_ctime.tv_nsec = 0;
  665                 vap->va_gen = fxdr_unsigned(u_int32_t, fp->fa2_ctime.nfsv2_usec);
  666                 vap->va_filerev = 0;
  667         }
  668         np->n_attrstamp = time_second;
  669         if (vap->va_size != np->n_size) {
  670                 if (vap->va_type == VREG) {
  671                         if (dontshrink && vap->va_size < np->n_size) {
  672                                 /*
  673                                  * We've been told not to shrink the file;
  674                                  * zero np->n_attrstamp to indicate that
  675                                  * the attributes are stale.
  676                                  */
  677                                 vap->va_size = np->n_size;
  678                                 np->n_attrstamp = 0;
  679                         } else if (np->n_flag & NMODIFIED) {
  680                                 /*
  681                                  * We've modified the file: Use the larger
  682                                  * of our size, and the server's size.
  683                                  */
  684                                 if (vap->va_size < np->n_size) {
  685                                         vap->va_size = np->n_size;
  686                                 } else {
  687                                         np->n_size = vap->va_size;
  688                                         np->n_flag |= NSIZECHANGED;
  689                                 }
  690                         } else {
  691                                 np->n_size = vap->va_size;
  692                                 np->n_flag |= NSIZECHANGED;
  693                         }
  694                         vnode_pager_setsize(vp, np->n_size);
  695                 } else {
  696                         np->n_size = vap->va_size;
  697                 }
  698         }
  699         /*
  700          * The following checks are added to prevent a race between (say)
  701          * a READDIR+ and a WRITE. 
  702          * READDIR+, WRITE requests sent out.
  703          * READDIR+ resp, WRITE resp received on client.
  704          * However, the WRITE resp was handled before the READDIR+ resp
  705          * causing the post op attrs from the write to be loaded first
  706          * and the attrs from the READDIR+ to be loaded later. If this 
  707          * happens, we have stale attrs loaded into the attrcache.
  708          * We detect this by for the mtime moving back. We invalidate the 
  709          * attrcache when this happens.
  710          */
  711         if (timespeccmp(&mtime_save, &vap->va_mtime, >))
  712                 /* Size changed or mtime went backwards */
  713                 np->n_attrstamp = 0;
  714         if (vaper != NULL) {
  715                 bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(*vap));
  716                 if (np->n_flag & NCHG) {
  717                         if (np->n_flag & NACC)
  718                                 vaper->va_atime = np->n_atim;
  719                         if (np->n_flag & NUPD)
  720                                 vaper->va_mtime = np->n_mtim;
  721                 }
  722         }
  723         mtx_unlock(&np->n_mtx);
  724         return (0);
  725 }
  726 
  727 #ifdef NFS_ACDEBUG
  728 #include <sys/sysctl.h>
  729 SYSCTL_DECL(_vfs_nfs);
  730 static int nfs_acdebug;
  731 SYSCTL_INT(_vfs_nfs, OID_AUTO, acdebug, CTLFLAG_RW, &nfs_acdebug, 0, "");
  732 #endif
  733 
  734 /*
  735  * Check the time stamp
  736  * If the cache is valid, copy contents to *vap and return 0
  737  * otherwise return an error
  738  */
  739 int
  740 nfs_getattrcache(struct vnode *vp, struct vattr *vaper)
  741 {
  742         struct nfsnode *np;
  743         struct vattr *vap;
  744         struct nfsmount *nmp;
  745         int timeo;
  746         
  747         np = VTONFS(vp);
  748         vap = &np->n_vattr;
  749         nmp = VFSTONFS(vp->v_mount);
  750 #ifdef NFS_ACDEBUG
  751         mtx_lock(&Giant);       /* nfs_printf() */
  752 #endif
  753         mtx_lock(&np->n_mtx);
  754         /* XXX n_mtime doesn't seem to be updated on a miss-and-reload */
  755         timeo = (time_second - np->n_mtime.tv_sec) / 10;
  756 
  757 #ifdef NFS_ACDEBUG
  758         if (nfs_acdebug>1)
  759                 nfs_printf("nfs_getattrcache: initial timeo = %d\n", timeo);
  760 #endif
  761 
  762         if (vap->va_type == VDIR) {
  763                 if ((np->n_flag & NMODIFIED) || timeo < nmp->nm_acdirmin)
  764                         timeo = nmp->nm_acdirmin;
  765                 else if (timeo > nmp->nm_acdirmax)
  766                         timeo = nmp->nm_acdirmax;
  767         } else {
  768                 if ((np->n_flag & NMODIFIED) || timeo < nmp->nm_acregmin)
  769                         timeo = nmp->nm_acregmin;
  770                 else if (timeo > nmp->nm_acregmax)
  771                         timeo = nmp->nm_acregmax;
  772         }
  773 
  774 #ifdef NFS_ACDEBUG
  775         if (nfs_acdebug > 2)
  776                 nfs_printf("acregmin %d; acregmax %d; acdirmin %d; acdirmax %d\n",
  777                            nmp->nm_acregmin, nmp->nm_acregmax,
  778                            nmp->nm_acdirmin, nmp->nm_acdirmax);
  779 
  780         if (nfs_acdebug)
  781                 nfs_printf("nfs_getattrcache: age = %d; final timeo = %d\n",
  782                            (time_second - np->n_attrstamp), timeo);
  783 #endif
  784 
  785         if ((time_second - np->n_attrstamp) >= timeo) {
  786                 nfsstats.attrcache_misses++;
  787                 mtx_unlock(&np->n_mtx);
  788                 return( ENOENT);
  789         }
  790         nfsstats.attrcache_hits++;
  791         if (vap->va_size != np->n_size) {
  792                 if (vap->va_type == VREG) {
  793                         if (np->n_flag & NMODIFIED) {
  794                                 if (vap->va_size < np->n_size)
  795                                         vap->va_size = np->n_size;
  796                                 else
  797                                         np->n_size = vap->va_size;
  798                         } else {
  799                                 np->n_size = vap->va_size;
  800                         }
  801                         vnode_pager_setsize(vp, np->n_size);
  802                 } else {
  803                         np->n_size = vap->va_size;
  804                 }
  805         }
  806         bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(struct vattr));
  807         if (np->n_flag & NCHG) {
  808                 if (np->n_flag & NACC)
  809                         vaper->va_atime = np->n_atim;
  810                 if (np->n_flag & NUPD)
  811                         vaper->va_mtime = np->n_mtim;
  812         }
  813         mtx_unlock(&np->n_mtx);
  814 #ifdef NFS_ACDEBUG
  815         mtx_unlock(&Giant);     /* nfs_printf() */
  816 #endif
  817         return (0);
  818 }
  819 
  820 static nfsuint64 nfs_nullcookie = { { 0, 0 } };
  821 /*
  822  * This function finds the directory cookie that corresponds to the
  823  * logical byte offset given.
  824  */
  825 nfsuint64 *
  826 nfs_getcookie(struct nfsnode *np, off_t off, int add)
  827 {
  828         struct nfsdmap *dp, *dp2;
  829         int pos;
  830         nfsuint64 *retval = NULL;
  831         
  832         pos = (uoff_t)off / NFS_DIRBLKSIZ;
  833         if (pos == 0 || off < 0) {
  834 #ifdef DIAGNOSTIC
  835                 if (add)
  836                         panic("nfs getcookie add at <= 0");
  837 #endif
  838                 return (&nfs_nullcookie);
  839         }
  840         pos--;
  841         dp = LIST_FIRST(&np->n_cookies);
  842         if (!dp) {
  843                 if (add) {
  844                         MALLOC(dp, struct nfsdmap *, sizeof (struct nfsdmap),
  845                                 M_NFSDIROFF, M_WAITOK);
  846                         dp->ndm_eocookie = 0;
  847                         LIST_INSERT_HEAD(&np->n_cookies, dp, ndm_list);
  848                 } else
  849                         goto out;
  850         }
  851         while (pos >= NFSNUMCOOKIES) {
  852                 pos -= NFSNUMCOOKIES;
  853                 if (LIST_NEXT(dp, ndm_list)) {
  854                         if (!add && dp->ndm_eocookie < NFSNUMCOOKIES &&
  855                             pos >= dp->ndm_eocookie)
  856                                 goto out;
  857                         dp = LIST_NEXT(dp, ndm_list);
  858                 } else if (add) {
  859                         MALLOC(dp2, struct nfsdmap *, sizeof (struct nfsdmap),
  860                                 M_NFSDIROFF, M_WAITOK);
  861                         dp2->ndm_eocookie = 0;
  862                         LIST_INSERT_AFTER(dp, dp2, ndm_list);
  863                         dp = dp2;
  864                 } else
  865                         goto out;
  866         }
  867         if (pos >= dp->ndm_eocookie) {
  868                 if (add)
  869                         dp->ndm_eocookie = pos + 1;
  870                 else
  871                         goto out;
  872         }
  873         retval = &dp->ndm_cookies[pos];
  874 out:
  875         return (retval);
  876 }
  877 
  878 /*
  879  * Invalidate cached directory information, except for the actual directory
  880  * blocks (which are invalidated separately).
  881  * Done mainly to avoid the use of stale offset cookies.
  882  */
  883 void
  884 nfs_invaldir(struct vnode *vp)
  885 {
  886         struct nfsnode *np = VTONFS(vp);
  887 
  888 #ifdef DIAGNOSTIC
  889         if (vp->v_type != VDIR)
  890                 panic("nfs: invaldir not dir");
  891 #endif
  892         nfs_dircookie_lock(np);
  893         np->n_direofoffset = 0;
  894         np->n_cookieverf.nfsuquad[0] = 0;
  895         np->n_cookieverf.nfsuquad[1] = 0;
  896         if (LIST_FIRST(&np->n_cookies))
  897                 LIST_FIRST(&np->n_cookies)->ndm_eocookie = 0;
  898         nfs_dircookie_unlock(np);
  899 }
  900 
  901 /*
  902  * The write verifier has changed (probably due to a server reboot), so all
  903  * B_NEEDCOMMIT blocks will have to be written again. Since they are on the
  904  * dirty block list as B_DELWRI, all this takes is clearing the B_NEEDCOMMIT
  905  * and B_CLUSTEROK flags.  Once done the new write verifier can be set for the
  906  * mount point.
  907  *
  908  * B_CLUSTEROK must be cleared along with B_NEEDCOMMIT because stage 1 data
  909  * writes are not clusterable.
  910  */
  911 void
  912 nfs_clearcommit(struct mount *mp)
  913 {
  914         struct vnode *vp, *nvp;
  915         struct buf *bp, *nbp;
  916         int s;
  917 
  918         s = splbio();
  919         MNT_ILOCK(mp);
  920         MNT_VNODE_FOREACH(vp, mp, nvp) {
  921                 VI_LOCK(vp);
  922                 if (vp->v_iflag & VI_DOOMED) {
  923                         VI_UNLOCK(vp);
  924                         continue;
  925                 }
  926                 MNT_IUNLOCK(mp);
  927                 TAILQ_FOREACH_SAFE(bp, &vp->v_bufobj.bo_dirty.bv_hd, b_bobufs, nbp) {
  928                         if (BUF_REFCNT(bp) == 0 &&
  929                             (bp->b_flags & (B_DELWRI | B_NEEDCOMMIT))
  930                                 == (B_DELWRI | B_NEEDCOMMIT))
  931                                 bp->b_flags &= ~(B_NEEDCOMMIT | B_CLUSTEROK);
  932                 }
  933                 VI_UNLOCK(vp);
  934                 MNT_ILOCK(mp);
  935         }
  936         MNT_IUNLOCK(mp);
  937         splx(s);
  938 }
  939 
  940 /*
  941  * Helper functions for former macros.  Some of these should be
  942  * moved to their callers.
  943  */
  944 
  945 int
  946 nfsm_mtofh_xx(struct vnode *d, struct vnode **v, int v3, int *f,
  947     struct mbuf **md, caddr_t *dpos)
  948 {
  949         struct nfsnode *ttnp;
  950         struct vnode *ttvp;
  951         nfsfh_t *ttfhp;
  952         u_int32_t *tl;
  953         int ttfhsize;
  954         int t1;
  955 
  956         if (v3) {
  957                 tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
  958                 if (tl == NULL)
  959                         return EBADRPC;
  960                 *f = fxdr_unsigned(int, *tl);
  961         } else
  962                 *f = 1;
  963         if (*f) {
  964                 t1 = nfsm_getfh_xx(&ttfhp, &ttfhsize, (v3), md, dpos);
  965                 if (t1 != 0)
  966                         return t1;
  967                 t1 = nfs_nget(d->v_mount, ttfhp, ttfhsize, &ttnp, LK_EXCLUSIVE);
  968                 if (t1 != 0)
  969                         return t1;
  970                 *v = NFSTOV(ttnp);
  971         }
  972         if (v3) {
  973                 tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
  974                 if (tl == NULL)
  975                         return EBADRPC;
  976                 if (*f)
  977                         *f = fxdr_unsigned(int, *tl);
  978                 else if (fxdr_unsigned(int, *tl))
  979                         nfsm_adv_xx(NFSX_V3FATTR, md, dpos);
  980         }
  981         if (*f) {
  982                 ttvp = *v;
  983                 t1 = nfs_loadattrcache(&ttvp, md, dpos, NULL, 0);
  984                 if (t1)
  985                         return t1;
  986                 *v = ttvp;
  987         }
  988         return 0;
  989 }
  990 
  991 int
  992 nfsm_getfh_xx(nfsfh_t **f, int *s, int v3, struct mbuf **md, caddr_t *dpos)
  993 {
  994         u_int32_t *tl;
  995 
  996         if (v3) {
  997                 tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
  998                 if (tl == NULL)
  999                         return EBADRPC;
 1000                 *s = fxdr_unsigned(int, *tl);
 1001                 if (*s <= 0 || *s > NFSX_V3FHMAX)
 1002                         return EBADRPC;
 1003         } else
 1004                 *s = NFSX_V2FH;
 1005         *f = nfsm_dissect_xx(nfsm_rndup(*s), md, dpos);
 1006         if (*f == NULL)
 1007                 return EBADRPC;
 1008         else
 1009                 return 0;
 1010 }
 1011 
 1012 
 1013 int
 1014 nfsm_loadattr_xx(struct vnode **v, struct vattr *va, struct mbuf **md,
 1015                  caddr_t *dpos)
 1016 {
 1017         int t1;
 1018 
 1019         struct vnode *ttvp = *v;
 1020         t1 = nfs_loadattrcache(&ttvp, md, dpos, va, 0);
 1021         if (t1 != 0)
 1022                 return t1;
 1023         *v = ttvp;
 1024         return 0;
 1025 }
 1026 
 1027 int
 1028 nfsm_postop_attr_xx(struct vnode **v, int *f, struct vattr *va,
 1029                     struct mbuf **md, caddr_t *dpos)
 1030 {
 1031         u_int32_t *tl;
 1032         int t1;
 1033 
 1034         struct vnode *ttvp = *v;
 1035         tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
 1036         if (tl == NULL)
 1037                 return EBADRPC;
 1038         *f = fxdr_unsigned(int, *tl);
 1039         if (*f != 0) {
 1040                 t1 = nfs_loadattrcache(&ttvp, md, dpos, va, 1);
 1041                 if (t1 != 0) {
 1042                         *f = 0;
 1043                         return t1;
 1044                 }
 1045                 *v = ttvp;
 1046         }
 1047         return 0;
 1048 }
 1049 
 1050 int
 1051 nfsm_wcc_data_xx(struct vnode **v, int *f, struct mbuf **md, caddr_t *dpos)
 1052 {
 1053         u_int32_t *tl;
 1054         int ttattrf, ttretf = 0;
 1055         int t1;
 1056 
 1057         tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
 1058         if (tl == NULL)
 1059                 return EBADRPC;
 1060         if (*tl == nfs_true) {
 1061                 tl = nfsm_dissect_xx(6 * NFSX_UNSIGNED, md, dpos);
 1062                 if (tl == NULL)
 1063                         return EBADRPC;
 1064                 mtx_lock(&(VTONFS(*v))->n_mtx);
 1065                 if (*f)
 1066                         ttretf = (VTONFS(*v)->n_mtime.tv_sec == fxdr_unsigned(u_int32_t, *(tl + 2)) && 
 1067                                   VTONFS(*v)->n_mtime.tv_nsec == fxdr_unsigned(u_int32_t, *(tl + 3))); 
 1068                 mtx_unlock(&(VTONFS(*v))->n_mtx);
 1069         }
 1070         t1 = nfsm_postop_attr_xx(v, &ttattrf, NULL, md, dpos);
 1071         if (t1)
 1072                 return t1;
 1073         if (*f)
 1074                 *f = ttretf;
 1075         else
 1076                 *f = ttattrf;
 1077         return 0;
 1078 }
 1079 
 1080 int
 1081 nfsm_strtom_xx(const char *a, int s, int m, struct mbuf **mb, caddr_t *bpos)
 1082 {
 1083         u_int32_t *tl;
 1084         int t1;
 1085 
 1086         if (s > m)
 1087                 return ENAMETOOLONG;
 1088         t1 = nfsm_rndup(s) + NFSX_UNSIGNED;
 1089         if (t1 <= M_TRAILINGSPACE(*mb)) {
 1090                 tl = nfsm_build_xx(t1, mb, bpos);
 1091                 *tl++ = txdr_unsigned(s);
 1092                 *(tl + ((t1 >> 2) - 2)) = 0;
 1093                 bcopy(a, tl, s);
 1094         } else {
 1095                 t1 = nfsm_strtmbuf(mb, bpos, a, s);
 1096                 if (t1 != 0)
 1097                         return t1;
 1098         }
 1099         return 0;
 1100 }
 1101 
 1102 int
 1103 nfsm_fhtom_xx(struct vnode *v, int v3, struct mbuf **mb, caddr_t *bpos)
 1104 {
 1105         u_int32_t *tl;
 1106         int t1;
 1107         caddr_t cp;
 1108 
 1109         if (v3) {
 1110                 t1 = nfsm_rndup(VTONFS(v)->n_fhsize) + NFSX_UNSIGNED;
 1111                 if (t1 < M_TRAILINGSPACE(*mb)) {
 1112                         tl = nfsm_build_xx(t1, mb, bpos);
 1113                         *tl++ = txdr_unsigned(VTONFS(v)->n_fhsize);
 1114                         *(tl + ((t1 >> 2) - 2)) = 0;
 1115                         bcopy(VTONFS(v)->n_fhp, tl, VTONFS(v)->n_fhsize);
 1116                 } else {
 1117                         t1 = nfsm_strtmbuf(mb, bpos,
 1118                             (const char *)VTONFS(v)->n_fhp,
 1119                             VTONFS(v)->n_fhsize);
 1120                         if (t1 != 0)
 1121                                 return t1;
 1122                 }
 1123         } else {
 1124                 cp = nfsm_build_xx(NFSX_V2FH, mb, bpos);
 1125                 bcopy(VTONFS(v)->n_fhp, cp, NFSX_V2FH);
 1126         }
 1127         return 0;
 1128 }
 1129 
 1130 void
 1131 nfsm_v3attrbuild_xx(struct vattr *va, int full, struct mbuf **mb,
 1132     caddr_t *bpos)
 1133 {
 1134         u_int32_t *tl;
 1135 
 1136         if (va->va_mode != (mode_t)VNOVAL) {
 1137                 tl = nfsm_build_xx(2 * NFSX_UNSIGNED, mb, bpos);
 1138                 *tl++ = nfs_true;
 1139                 *tl = txdr_unsigned(va->va_mode);
 1140         } else {
 1141                 tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos);
 1142                 *tl = nfs_false;
 1143         }
 1144         if (full && va->va_uid != (uid_t)VNOVAL) {
 1145                 tl = nfsm_build_xx(2 * NFSX_UNSIGNED, mb, bpos);
 1146                 *tl++ = nfs_true;
 1147                 *tl = txdr_unsigned(va->va_uid);
 1148         } else {
 1149                 tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos);
 1150                 *tl = nfs_false;
 1151         }
 1152         if (full && va->va_gid != (gid_t)VNOVAL) {
 1153                 tl = nfsm_build_xx(2 * NFSX_UNSIGNED, mb, bpos);
 1154                 *tl++ = nfs_true;
 1155                 *tl = txdr_unsigned(va->va_gid);
 1156         } else {
 1157                 tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos);
 1158                 *tl = nfs_false;
 1159         }
 1160         if (full && va->va_size != VNOVAL) {
 1161                 tl = nfsm_build_xx(3 * NFSX_UNSIGNED, mb, bpos);
 1162                 *tl++ = nfs_true;
 1163                 txdr_hyper(va->va_size, tl);
 1164         } else {
 1165                 tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos);
 1166                 *tl = nfs_false;
 1167         }
 1168         if (va->va_atime.tv_sec != VNOVAL) {
 1169                 if (va->va_atime.tv_sec != time_second) {
 1170                         tl = nfsm_build_xx(3 * NFSX_UNSIGNED, mb, bpos);
 1171                         *tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT);
 1172                         txdr_nfsv3time(&va->va_atime, tl);
 1173                 } else {
 1174                         tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos);
 1175                         *tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER);
 1176                 }
 1177         } else {
 1178                 tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos);
 1179                 *tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE);
 1180         }
 1181         if (va->va_mtime.tv_sec != VNOVAL) {
 1182                 if (va->va_mtime.tv_sec != time_second) {
 1183                         tl = nfsm_build_xx(3 * NFSX_UNSIGNED, mb, bpos);
 1184                         *tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT);
 1185                         txdr_nfsv3time(&va->va_mtime, tl);
 1186                 } else {
 1187                         tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos);
 1188                         *tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER);
 1189                 }
 1190         } else {
 1191                 tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos);
 1192                 *tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE);
 1193         }
 1194 }

Cache object: 8648df9a495e824f499baa53af8ea87e


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