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

Cache object: 13c60d63179ca45ad2235a652beae4cb


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