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

Cache object: 8c71680578f11b0b30c871d2f4995b2c


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