root/nfs/nfs_srvcache.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. nfsrv_initcache
  2. nfsrv_getcache
  3. nfsrv_updatecache
  4. nfsrv_cleancache

    1 /*      $OpenBSD: nfs_srvcache.c,v 1.12 2004/12/26 21:22:14 miod Exp $  */
    2 /*      $NetBSD: nfs_srvcache.c,v 1.12 1996/02/18 11:53:49 fvdl Exp $   */
    3 
    4 /*
    5  * Copyright (c) 1989, 1993
    6  *      The Regents of the University of California.  All rights reserved.
    7  *
    8  * This code is derived from software contributed to Berkeley by
    9  * Rick Macklem at The University of Guelph.
   10  *
   11  * Redistribution and use in source and binary forms, with or without
   12  * modification, are permitted provided that the following conditions
   13  * are met:
   14  * 1. Redistributions of source code must retain the above copyright
   15  *    notice, this list of conditions and the following disclaimer.
   16  * 2. Redistributions in binary form must reproduce the above copyright
   17  *    notice, this list of conditions and the following disclaimer in the
   18  *    documentation and/or other materials provided with the distribution.
   19  * 3. Neither the name of the University nor the names of its contributors
   20  *    may be used to endorse or promote products derived from this software
   21  *    without specific prior written permission.
   22  *
   23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   33  * SUCH DAMAGE.
   34  *
   35  *      @(#)nfs_srvcache.c      8.3 (Berkeley) 3/30/95
   36  */
   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/vnode.h>
   45 #include <sys/mount.h>
   46 #include <sys/kernel.h>
   47 #include <sys/systm.h>
   48 #include <sys/proc.h>
   49 #include <sys/mbuf.h>
   50 #include <sys/malloc.h>
   51 #include <sys/socket.h>
   52 #include <sys/socketvar.h>
   53 
   54 #include <netinet/in.h>
   55 #include <nfs/nfsm_subs.h>
   56 #include <nfs/rpcv2.h>
   57 #include <nfs/nfsproto.h>
   58 #include <nfs/nfs.h>
   59 #include <nfs/nfsrvcache.h>
   60 #include <nfs/nfs_var.h>
   61 
   62 extern struct nfsstats nfsstats;
   63 extern int nfsv2_procid[NFS_NPROCS];
   64 long numnfsrvcache, desirednfsrvcache = NFSRVCACHESIZ;
   65 
   66 #define NFSRCHASH(xid) \
   67         (&nfsrvhashtbl[((xid) + ((xid) >> 24)) & nfsrvhash])
   68 LIST_HEAD(nfsrvhash, nfsrvcache) *nfsrvhashtbl;
   69 TAILQ_HEAD(nfsrvlru, nfsrvcache) nfsrvlruhead;
   70 u_long nfsrvhash;
   71 
   72 #define TRUE    1
   73 #define FALSE   0
   74 
   75 #define NETFAMILY(rp) \
   76                 (((rp)->rc_flag & RC_INETADDR) ? AF_INET : AF_UNSPEC)
   77 
   78 /*
   79  * Static array that defines which nfs rpc's are nonidempotent
   80  */
   81 int nonidempotent[NFS_NPROCS] = {
   82         FALSE,
   83         FALSE,
   84         TRUE,
   85         FALSE,
   86         FALSE,
   87         FALSE,
   88         FALSE,
   89         TRUE,
   90         TRUE,
   91         TRUE,
   92         TRUE,
   93         TRUE,
   94         TRUE,
   95         TRUE,
   96         TRUE,
   97         TRUE,
   98         FALSE,
   99         FALSE,
  100         FALSE,
  101         FALSE,
  102         FALSE,
  103         FALSE,
  104         FALSE,
  105         FALSE,
  106         FALSE,
  107         FALSE,
  108 };
  109 
  110 /* True iff the rpc reply is an nfs status ONLY! */
  111 static int nfsv2_repstat[NFS_NPROCS] = {
  112         FALSE,
  113         FALSE,
  114         FALSE,
  115         FALSE,
  116         FALSE,
  117         FALSE,
  118         FALSE,
  119         FALSE,
  120         FALSE,
  121         FALSE,
  122         TRUE,
  123         TRUE,
  124         TRUE,
  125         TRUE,
  126         FALSE,
  127         TRUE,
  128         FALSE,
  129         FALSE,
  130 };
  131 
  132 /*
  133  * Initialize the server request cache list
  134  */
  135 void
  136 nfsrv_initcache()
  137 {
  138 
  139         nfsrvhashtbl = hashinit(desirednfsrvcache, M_NFSD, M_WAITOK, &nfsrvhash);
  140         TAILQ_INIT(&nfsrvlruhead);
  141 }
  142 
  143 /*
  144  * Look for the request in the cache
  145  * If found then
  146  *    return action and optionally reply
  147  * else
  148  *    insert it in the cache
  149  *
  150  * The rules are as follows:
  151  * - if in progress, return DROP request
  152  * - if completed within DELAY of the current time, return DROP it
  153  * - if completed a longer time ago return REPLY if the reply was cached or
  154  *   return DOIT
  155  * Update/add new request at end of lru list
  156  */
  157 int
  158 nfsrv_getcache(nd, slp, repp)
  159         struct nfsrv_descript *nd;
  160         struct nfssvc_sock *slp;
  161         struct mbuf **repp;
  162 {
  163         struct nfsrvcache *rp;
  164         struct mbuf *mb;
  165         struct sockaddr_in *saddr;
  166         caddr_t bpos;
  167         int ret;
  168 
  169         /*
  170          * Don't cache recent requests for reliable transport protocols.
  171          * (Maybe we should for the case of a reconnect, but..)
  172          */
  173         if (!nd->nd_nam2)
  174                 return (RC_DOIT);
  175 loop:
  176         LIST_FOREACH(rp, NFSRCHASH(nd->nd_retxid), rc_hash) {
  177             if (nd->nd_retxid == rp->rc_xid && nd->nd_procnum == rp->rc_proc &&
  178                 netaddr_match(NETFAMILY(rp), &rp->rc_haddr, nd->nd_nam)) {
  179                         if ((rp->rc_flag & RC_LOCKED) != 0) {
  180                                 rp->rc_flag |= RC_WANTED;
  181                                 (void) tsleep((caddr_t)rp, PZERO-1, "nfsrc", 0);
  182                                 goto loop;
  183                         }
  184                         rp->rc_flag |= RC_LOCKED;
  185                         /* If not at end of LRU chain, move it there */
  186                         if (TAILQ_NEXT(rp, rc_lru)) {
  187                                 TAILQ_REMOVE(&nfsrvlruhead, rp, rc_lru);
  188                                 TAILQ_INSERT_TAIL(&nfsrvlruhead, rp, rc_lru);
  189                         }
  190                         if (rp->rc_state == RC_UNUSED)
  191                                 panic("nfsrv cache");
  192                         if (rp->rc_state == RC_INPROG) {
  193                                 nfsstats.srvcache_inproghits++;
  194                                 ret = RC_DROPIT;
  195                         } else if (rp->rc_flag & RC_REPSTATUS) {
  196                                 nfsstats.srvcache_nonidemdonehits++;
  197                                 nfs_rephead(0, nd, slp, rp->rc_status,
  198                                    (u_quad_t *)0, repp, &mb, &bpos);
  199                                 ret = RC_REPLY;
  200                         } else if (rp->rc_flag & RC_REPMBUF) {
  201                                 nfsstats.srvcache_nonidemdonehits++;
  202                                 *repp = m_copym(rp->rc_reply, 0, M_COPYALL,
  203                                                 M_WAIT);
  204                                 ret = RC_REPLY;
  205                         } else {
  206                                 nfsstats.srvcache_idemdonehits++;
  207                                 rp->rc_state = RC_INPROG;
  208                                 ret = RC_DOIT;
  209                         }
  210                         rp->rc_flag &= ~RC_LOCKED;
  211                         if (rp->rc_flag & RC_WANTED) {
  212                                 rp->rc_flag &= ~RC_WANTED;
  213                                 wakeup((caddr_t)rp);
  214                         }
  215                         return (ret);
  216                 }
  217         }
  218         nfsstats.srvcache_misses++;
  219         if (numnfsrvcache < desirednfsrvcache) {
  220                 rp = (struct nfsrvcache *)malloc((u_long)sizeof *rp,
  221                     M_NFSD, M_WAITOK);
  222                 bzero((char *)rp, sizeof *rp);
  223                 numnfsrvcache++;
  224                 rp->rc_flag = RC_LOCKED;
  225         } else {
  226                 rp = TAILQ_FIRST(&nfsrvlruhead);
  227                 while ((rp->rc_flag & RC_LOCKED) != 0) {
  228                         rp->rc_flag |= RC_WANTED;
  229                         (void) tsleep((caddr_t)rp, PZERO-1, "nfsrc", 0);
  230                         rp = TAILQ_FIRST(&nfsrvlruhead);
  231                 }
  232                 rp->rc_flag |= RC_LOCKED;
  233                 LIST_REMOVE(rp, rc_hash);
  234                 TAILQ_REMOVE(&nfsrvlruhead, rp, rc_lru);
  235                 if (rp->rc_flag & RC_REPMBUF)
  236                         m_freem(rp->rc_reply);
  237                 if (rp->rc_flag & RC_NAM)
  238                         MFREE(rp->rc_nam, mb);
  239                 rp->rc_flag &= (RC_LOCKED | RC_WANTED);
  240         }
  241         TAILQ_INSERT_TAIL(&nfsrvlruhead, rp, rc_lru);
  242         rp->rc_state = RC_INPROG;
  243         rp->rc_xid = nd->nd_retxid;
  244         saddr = mtod(nd->nd_nam, struct sockaddr_in *);
  245         switch (saddr->sin_family) {
  246         case AF_INET:
  247                 rp->rc_flag |= RC_INETADDR;
  248                 rp->rc_inetaddr = saddr->sin_addr.s_addr;
  249                 break;
  250         default:
  251                 rp->rc_flag |= RC_NAM;
  252                 rp->rc_nam = m_copym(nd->nd_nam, 0, M_COPYALL, M_WAIT);
  253                 break;
  254         };
  255         rp->rc_proc = nd->nd_procnum;
  256         LIST_INSERT_HEAD(NFSRCHASH(nd->nd_retxid), rp, rc_hash);
  257         rp->rc_flag &= ~RC_LOCKED;
  258         if (rp->rc_flag & RC_WANTED) {
  259                 rp->rc_flag &= ~RC_WANTED;
  260                 wakeup((caddr_t)rp);
  261         }
  262         return (RC_DOIT);
  263 }
  264 
  265 /*
  266  * Update a request cache entry after the rpc has been done
  267  */
  268 void
  269 nfsrv_updatecache(nd, repvalid, repmbuf)
  270         struct nfsrv_descript *nd;
  271         int repvalid;
  272         struct mbuf *repmbuf;
  273 {
  274         struct nfsrvcache *rp;
  275 
  276         if (!nd->nd_nam2)
  277                 return;
  278 loop:
  279         LIST_FOREACH(rp, NFSRCHASH(nd->nd_retxid), rc_hash) {
  280             if (nd->nd_retxid == rp->rc_xid && nd->nd_procnum == rp->rc_proc &&
  281                 netaddr_match(NETFAMILY(rp), &rp->rc_haddr, nd->nd_nam)) {
  282                         if ((rp->rc_flag & RC_LOCKED) != 0) {
  283                                 rp->rc_flag |= RC_WANTED;
  284                                 (void) tsleep((caddr_t)rp, PZERO-1, "nfsrc", 0);
  285                                 goto loop;
  286                         }
  287                         rp->rc_flag |= RC_LOCKED;
  288                         rp->rc_state = RC_DONE;
  289                         /*
  290                          * If we have a valid reply update status and save
  291                          * the reply for non-idempotent rpc's.
  292                          */
  293                         if (repvalid && nonidempotent[nd->nd_procnum]) {
  294                                 if ((nd->nd_flag & ND_NFSV3) == 0 &&
  295                                   nfsv2_repstat[nfsv2_procid[nd->nd_procnum]]) {
  296                                         rp->rc_status = nd->nd_repstat;
  297                                         rp->rc_flag |= RC_REPSTATUS;
  298                                 } else {
  299                                         rp->rc_reply = m_copym(repmbuf,
  300                                                 0, M_COPYALL, M_WAIT);
  301                                         rp->rc_flag |= RC_REPMBUF;
  302                                 }
  303                         }
  304                         rp->rc_flag &= ~RC_LOCKED;
  305                         if (rp->rc_flag & RC_WANTED) {
  306                                 rp->rc_flag &= ~RC_WANTED;
  307                                 wakeup((caddr_t)rp);
  308                         }
  309                         return;
  310                 }
  311         }
  312 }
  313 
  314 /*
  315  * Clean out the cache. Called when the last nfsd terminates.
  316  */
  317 void
  318 nfsrv_cleancache()
  319 {
  320         struct nfsrvcache *rp, *nextrp;
  321 
  322         for (rp = TAILQ_FIRST(&nfsrvlruhead); rp != NULL; rp = nextrp) {
  323                 nextrp = TAILQ_NEXT(rp, rc_lru);
  324                 LIST_REMOVE(rp, rc_hash);
  325                 TAILQ_REMOVE(&nfsrvlruhead, rp, rc_lru);
  326                 free(rp, M_NFSD);
  327         }
  328         numnfsrvcache = 0;
  329 }

/* [<][>][^][v][top][bottom][index][help] */