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

Cache object: ec17e54ee2c3f5da25b8fa5ac2808cc7


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