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


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

FreeBSD/Linux Kernel Cross Reference
sys/nfsserver/nfs_srvcache.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_srvcache.c      8.3 (Berkeley) 3/30/95
   37  */
   38 
   39 #include <sys/cdefs.h>
   40 __FBSDID("$FreeBSD: releng/5.0/sys/nfsserver/nfs_srvcache.c 100134 2002-07-15 19:40:23Z alfred $");
   41 
   42 /*
   43  * Reference: Chet Juszczak, "Improving the Performance and Correctness
   44  *              of an NFS Server", in Proc. Winter 1989 USENIX Conference,
   45  *              pages 53-63. San Diego, February 1989.
   46  */
   47 #include <sys/param.h>
   48 #include <sys/malloc.h>
   49 #include <sys/mount.h>
   50 #include <sys/systm.h>
   51 #include <sys/mbuf.h>
   52 #include <sys/socket.h>
   53 #include <sys/socketvar.h>      /* for dup_sockaddr */
   54 
   55 #include <netinet/in.h>
   56 #include <nfs/rpcv2.h>
   57 #include <nfs/nfsproto.h>
   58 #include <nfsserver/nfs.h>
   59 #include <nfsserver/nfsrvcache.h>
   60 
   61 static long numnfsrvcache;
   62 static long desirednfsrvcache = NFSRVCACHESIZ;
   63 
   64 #define NFSRCHASH(xid) \
   65         (&nfsrvhashtbl[((xid) + ((xid) >> 24)) & nfsrvhash])
   66 static LIST_HEAD(nfsrvhash, nfsrvcache) *nfsrvhashtbl;
   67 static TAILQ_HEAD(nfsrvlru, nfsrvcache) nfsrvlruhead;
   68 static u_long nfsrvhash;
   69 
   70 #define TRUE    1
   71 #define FALSE   0
   72 
   73 #define NETFAMILY(rp) \
   74                 (((rp)->rc_flag & RC_NAM) ? (rp)->rc_nam->sa_family : AF_INET)
   75 
   76 /*
   77  * Static array that defines which nfs rpc's are nonidempotent
   78  */
   79 static int nonidempotent[NFS_NPROCS] = {
   80         FALSE,
   81         FALSE,
   82         TRUE,
   83         FALSE,
   84         FALSE,
   85         FALSE,
   86         FALSE,
   87         TRUE,
   88         TRUE,
   89         TRUE,
   90         TRUE,
   91         TRUE,
   92         TRUE,
   93         TRUE,
   94         TRUE,
   95         TRUE,
   96         FALSE,
   97         FALSE,
   98         FALSE,
   99         FALSE,
  100         FALSE,
  101         FALSE,
  102         FALSE,
  103 };
  104 
  105 /* True iff the rpc reply is an nfs status ONLY! */
  106 static int nfsv2_repstat[NFS_NPROCS] = {
  107         FALSE,
  108         FALSE,
  109         FALSE,
  110         FALSE,
  111         FALSE,
  112         FALSE,
  113         FALSE,
  114         FALSE,
  115         FALSE,
  116         FALSE,
  117         TRUE,
  118         TRUE,
  119         TRUE,
  120         TRUE,
  121         FALSE,
  122         TRUE,
  123         FALSE,
  124         FALSE,
  125 };
  126 
  127 /*
  128  * Initialize the server request cache list
  129  */
  130 void
  131 nfsrv_initcache(void)
  132 {
  133 
  134         nfsrvhashtbl = hashinit(desirednfsrvcache, M_NFSD, &nfsrvhash);
  135         TAILQ_INIT(&nfsrvlruhead);
  136 }
  137 
  138 /*
  139  * Look for the request in the cache
  140  * If found then
  141  *    return action and optionally reply
  142  * else
  143  *    insert it in the cache
  144  *
  145  * The rules are as follows:
  146  * - if in progress, return DROP request
  147  * - if completed within DELAY of the current time, return DROP it
  148  * - if completed a longer time ago return REPLY if the reply was cached or
  149  *   return DOIT
  150  * Update/add new request at end of lru list
  151  */
  152 int
  153 nfsrv_getcache(struct nfsrv_descript *nd, struct mbuf **repp)
  154 {
  155         struct nfsrvcache *rp;
  156         struct mbuf *mb;
  157         struct sockaddr_in *saddr;
  158         caddr_t bpos;
  159         int ret;
  160 
  161         /*
  162          * Don't cache recent requests for reliable transport protocols.
  163          * (Maybe we should for the case of a reconnect, but..)
  164          */
  165         if (!nd->nd_nam2)
  166                 return (RC_DOIT);
  167 loop:
  168         LIST_FOREACH(rp, NFSRCHASH(nd->nd_retxid), rc_hash) {
  169             if (nd->nd_retxid == rp->rc_xid && nd->nd_procnum == rp->rc_proc &&
  170                 netaddr_match(NETFAMILY(rp), &rp->rc_haddr, nd->nd_nam)) {
  171                         NFS_DPF(RC, ("H%03x", rp->rc_xid & 0xfff));
  172                         if ((rp->rc_flag & RC_LOCKED) != 0) {
  173                                 rp->rc_flag |= RC_WANTED;
  174                                 (void) tsleep((caddr_t)rp, PZERO-1, "nfsrc", 0);
  175                                 goto loop;
  176                         }
  177                         rp->rc_flag |= RC_LOCKED;
  178                         /* If not at end of LRU chain, move it there */
  179                         if (TAILQ_NEXT(rp, rc_lru)) {
  180                                 TAILQ_REMOVE(&nfsrvlruhead, rp, rc_lru);
  181                                 TAILQ_INSERT_TAIL(&nfsrvlruhead, rp, rc_lru);
  182                         }
  183                         if (rp->rc_state == RC_UNUSED)
  184                                 panic("nfsrv cache");
  185                         if (rp->rc_state == RC_INPROG) {
  186                                 nfsrvstats.srvcache_inproghits++;
  187                                 ret = RC_DROPIT;
  188                         } else if (rp->rc_flag & RC_REPSTATUS) {
  189                                 nfsrvstats.srvcache_nonidemdonehits++;
  190                                 *repp = nfs_rephead(0, nd, rp->rc_status,
  191                                     &mb, &bpos);
  192                                 ret = RC_REPLY;
  193                         } else if (rp->rc_flag & RC_REPMBUF) {
  194                                 nfsrvstats.srvcache_nonidemdonehits++;
  195                                 *repp = m_copym(rp->rc_reply, 0, M_COPYALL,
  196                                                 M_TRYWAIT);
  197                                 ret = RC_REPLY;
  198                         } else {
  199                                 nfsrvstats.srvcache_idemdonehits++;
  200                                 rp->rc_state = RC_INPROG;
  201                                 ret = RC_DOIT;
  202                         }
  203                         rp->rc_flag &= ~RC_LOCKED;
  204                         if (rp->rc_flag & RC_WANTED) {
  205                                 rp->rc_flag &= ~RC_WANTED;
  206                                 wakeup((caddr_t)rp);
  207                         }
  208                         return (ret);
  209                 }
  210         }
  211         nfsrvstats.srvcache_misses++;
  212         NFS_DPF(RC, ("M%03x", nd->nd_retxid & 0xfff));
  213         if (numnfsrvcache < desirednfsrvcache) {
  214                 rp = (struct nfsrvcache *)malloc((u_long)sizeof *rp,
  215                     M_NFSD, M_WAITOK | M_ZERO);
  216                 numnfsrvcache++;
  217                 rp->rc_flag = RC_LOCKED;
  218         } else {
  219                 rp = TAILQ_FIRST(&nfsrvlruhead);
  220                 while ((rp->rc_flag & RC_LOCKED) != 0) {
  221                         rp->rc_flag |= RC_WANTED;
  222                         (void) tsleep((caddr_t)rp, PZERO-1, "nfsrc", 0);
  223                         rp = TAILQ_FIRST(&nfsrvlruhead);
  224                 }
  225                 rp->rc_flag |= RC_LOCKED;
  226                 LIST_REMOVE(rp, rc_hash);
  227                 TAILQ_REMOVE(&nfsrvlruhead, rp, rc_lru);
  228                 if (rp->rc_flag & RC_REPMBUF)
  229                         m_freem(rp->rc_reply);
  230                 if (rp->rc_flag & RC_NAM)
  231                         FREE(rp->rc_nam, M_SONAME);
  232                 rp->rc_flag &= (RC_LOCKED | RC_WANTED);
  233         }
  234         TAILQ_INSERT_TAIL(&nfsrvlruhead, rp, rc_lru);
  235         rp->rc_state = RC_INPROG;
  236         rp->rc_xid = nd->nd_retxid;
  237         saddr = (struct sockaddr_in *)nd->nd_nam;
  238         switch (saddr->sin_family) {
  239         case AF_INET:
  240                 rp->rc_flag |= RC_INETADDR;
  241                 rp->rc_inetaddr = saddr->sin_addr.s_addr;
  242                 break;
  243 /*      case AF_INET6:  */
  244 /*      case AF_ISO:    */
  245         default:
  246                 rp->rc_flag |= RC_NAM;
  247                 rp->rc_nam = dup_sockaddr(nd->nd_nam, 1);
  248                 break;
  249         };
  250         rp->rc_proc = nd->nd_procnum;
  251         LIST_INSERT_HEAD(NFSRCHASH(nd->nd_retxid), rp, rc_hash);
  252         rp->rc_flag &= ~RC_LOCKED;
  253         if (rp->rc_flag & RC_WANTED) {
  254                 rp->rc_flag &= ~RC_WANTED;
  255                 wakeup((caddr_t)rp);
  256         }
  257         return (RC_DOIT);
  258 }
  259 
  260 /*
  261  * Update a request cache entry after the rpc has been done
  262  */
  263 void
  264 nfsrv_updatecache(struct nfsrv_descript *nd, int repvalid, struct mbuf *repmbuf)
  265 {
  266         struct nfsrvcache *rp;
  267 
  268         if (!nd->nd_nam2)
  269                 return;
  270 loop:
  271         LIST_FOREACH(rp, NFSRCHASH(nd->nd_retxid), rc_hash) {
  272             if (nd->nd_retxid == rp->rc_xid && nd->nd_procnum == rp->rc_proc &&
  273                 netaddr_match(NETFAMILY(rp), &rp->rc_haddr, nd->nd_nam)) {
  274                         NFS_DPF(RC, ("U%03x", rp->rc_xid & 0xfff));
  275                         if ((rp->rc_flag & RC_LOCKED) != 0) {
  276                                 rp->rc_flag |= RC_WANTED;
  277                                 (void) tsleep((caddr_t)rp, PZERO-1, "nfsrc", 0);
  278                                 goto loop;
  279                         }
  280                         rp->rc_flag |= RC_LOCKED;
  281                         if (rp->rc_state == RC_DONE) {
  282                                 /*
  283                                  * This can occur if the cache is too small.
  284                                  * Retransmits of the same request aren't
  285                                  * dropped so we may see the operation
  286                                  * complete more then once.
  287                                  */
  288                                 if (rp->rc_flag & RC_REPMBUF) {
  289                                         m_freem(rp->rc_reply);
  290                                         rp->rc_flag &= ~RC_REPMBUF;
  291                                 }
  292                         }
  293                         rp->rc_state = RC_DONE;
  294                         /*
  295                          * If we have a valid reply update status and save
  296                          * the reply for non-idempotent rpc's.
  297                          */
  298                         if (repvalid && nonidempotent[nd->nd_procnum]) {
  299                                 if ((nd->nd_flag & ND_NFSV3) == 0 &&
  300                                     nfsv2_repstat[
  301                                     nfsrvv2_procid[nd->nd_procnum]]) {
  302                                         rp->rc_status = nd->nd_repstat;
  303                                         rp->rc_flag |= RC_REPSTATUS;
  304                                 } else {
  305                                         rp->rc_reply = m_copym(repmbuf,
  306                                                 0, M_COPYALL, M_TRYWAIT);
  307                                         rp->rc_flag |= RC_REPMBUF;
  308                                 }
  309                         }
  310                         rp->rc_flag &= ~RC_LOCKED;
  311                         if (rp->rc_flag & RC_WANTED) {
  312                                 rp->rc_flag &= ~RC_WANTED;
  313                                 wakeup((caddr_t)rp);
  314                         }
  315                         return;
  316                 }
  317         }
  318         NFS_DPF(RC, ("L%03x", nd->nd_retxid & 0xfff));
  319 }
  320 
  321 /*
  322  * Clean out the cache. Called when the last nfsd terminates.
  323  */
  324 void
  325 nfsrv_cleancache(void)
  326 {
  327         struct nfsrvcache *rp, *nextrp;
  328 
  329         for (rp = TAILQ_FIRST(&nfsrvlruhead); rp != 0; rp = nextrp) {
  330                 nextrp = TAILQ_NEXT(rp, rc_lru);
  331                 LIST_REMOVE(rp, rc_hash);
  332                 TAILQ_REMOVE(&nfsrvlruhead, rp, rc_lru);
  333                 if (rp->rc_flag & RC_REPMBUF)
  334                         m_freem(rp->rc_reply);
  335                 if (rp->rc_flag & RC_NAM)
  336                         free(rp->rc_nam, M_SONAME);
  337                 free(rp, M_NFSD);
  338         }
  339         numnfsrvcache = 0;
  340 }

Cache object: aebea74fc26f881e09bd6283c771722d


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