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

Cache object: 986586022143f745a668390e55a9cafe


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