Annotation of kernel/bsd/nfs/nfs_srvcache.c, revision 1.1.1.1

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.