|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1989 The Regents of the University of California. ! 3: * 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 7.11 (Berkeley) 4/16/91 ! 37: */ ! 38: ! 39: /* ! 40: * Reference: Chet Juszczak, "Improving the Performance and Correctness ! 41: * of an NFS Server", in Proc. Winter 1989 USENIX Conference, ! 42: * pages 53-63. San Diego, February 1989. ! 43: */ ! 44: ! 45: #include "param.h" ! 46: #include "namei.h" ! 47: #include "vnode.h" ! 48: #include "mount.h" ! 49: #include "kernel.h" ! 50: #include "systm.h" ! 51: #include "mbuf.h" ! 52: #include "socket.h" ! 53: #include "socketvar.h" ! 54: ! 55: #include "../netinet/in.h" ! 56: ! 57: #include "nfsm_subs.h" ! 58: #include "nfsv2.h" ! 59: #include "nfsrvcache.h" ! 60: #include "nfs.h" ! 61: ! 62: #if ((NFSRCHSZ&(NFSRCHSZ-1)) == 0) ! 63: #define NFSRCHASH(xid) (((xid)+((xid)>>16))&(NFSRCHSZ-1)) ! 64: #else ! 65: #define NFSRCHASH(xid) (((unsigned)((xid)+((xid)>>16)))%NFSRCHSZ) ! 66: #endif ! 67: ! 68: union rhead { ! 69: union rhead *rh_head[2]; ! 70: struct nfsrvcache *rh_chain[2]; ! 71: } rhead[NFSRCHSZ]; ! 72: ! 73: static struct nfsrvcache nfsrvcachehead; ! 74: static struct nfsrvcache nfsrvcache[NFSRVCACHESIZ]; ! 75: ! 76: #define TRUE 1 ! 77: #define FALSE 0 ! 78: ! 79: /* ! 80: * Static array that defines which nfs rpc's are nonidempotent ! 81: */ ! 82: int nonidempotent[NFS_NPROCS] = { ! 83: FALSE, ! 84: FALSE, ! 85: TRUE, ! 86: FALSE, ! 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: FALSE, ! 100: FALSE, ! 101: }; ! 102: ! 103: /* True iff the rpc reply is an nfs status ONLY! */ ! 104: static int repliesstatus[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: nfsrv_initcache() ! 129: { ! 130: register int i; ! 131: register struct nfsrvcache *rp = nfsrvcache; ! 132: register struct nfsrvcache *hp = &nfsrvcachehead; ! 133: register union rhead *rh = rhead; ! 134: ! 135: for (i = NFSRCHSZ; --i >= 0; rh++) { ! 136: rh->rh_head[0] = rh; ! 137: rh->rh_head[1] = rh; ! 138: } ! 139: hp->rc_next = hp->rc_prev = hp; ! 140: for (i = NFSRVCACHESIZ; i-- > 0; ) { ! 141: rp->rc_state = RC_UNUSED; ! 142: rp->rc_flag = 0; ! 143: rp->rc_forw = rp; ! 144: rp->rc_back = rp; ! 145: rp->rc_next = hp->rc_next; ! 146: hp->rc_next->rc_prev = rp; ! 147: rp->rc_prev = hp; ! 148: hp->rc_next = rp; ! 149: rp++; ! 150: } ! 151: } ! 152: ! 153: /* ! 154: * Look for the request in the cache ! 155: * If found then ! 156: * return action and optionally reply ! 157: * else ! 158: * insert it in the cache ! 159: * ! 160: * The rules are as follows: ! 161: * - if in progress, return DROP request ! 162: * - if completed within DELAY of the current time, return DROP it ! 163: * - if completed a longer time ago return REPLY if the reply was cached or ! 164: * return DOIT ! 165: * Update/add new request at end of lru list ! 166: */ ! 167: nfsrv_getcache(nam, xid, proc, repp) ! 168: struct mbuf *nam; ! 169: u_long xid; ! 170: int proc; ! 171: struct mbuf **repp; ! 172: { ! 173: register struct nfsrvcache *rp; ! 174: register union rhead *rh; ! 175: struct mbuf *mb; ! 176: caddr_t bpos; ! 177: int ret; ! 178: ! 179: rh = &rhead[NFSRCHASH(xid)]; ! 180: loop: ! 181: for (rp = rh->rh_chain[0]; rp != (struct nfsrvcache *)rh; rp = rp->rc_forw) { ! 182: if (xid == rp->rc_xid && proc == rp->rc_proc && ! 183: nfs_netaddr_match(nam, &rp->rc_nam)) { ! 184: if ((rp->rc_flag & RC_LOCKED) != 0) { ! 185: rp->rc_flag |= RC_WANTED; ! 186: (void) tsleep((caddr_t)rp, PZERO-1, "nfsrc", 0); ! 187: goto loop; ! 188: } ! 189: rp->rc_flag |= RC_LOCKED; ! 190: put_at_head(rp); ! 191: if (rp->rc_state == RC_UNUSED) ! 192: panic("nfsrv cache"); ! 193: if (rp->rc_state == RC_INPROG || ! 194: (time.tv_sec - rp->rc_timestamp) < RC_DELAY) { ! 195: nfsstats.srvcache_inproghits++; ! 196: ret = RC_DROPIT; ! 197: } else if (rp->rc_flag & RC_REPSTATUS) { ! 198: nfsstats.srvcache_idemdonehits++; ! 199: nfs_rephead(0, xid, rp->rc_status, repp, &mb, ! 200: &bpos); ! 201: rp->rc_timestamp = time.tv_sec; ! 202: ret = RC_REPLY; ! 203: } else if (rp->rc_flag & RC_REPMBUF) { ! 204: nfsstats.srvcache_idemdonehits++; ! 205: *repp = m_copym(rp->rc_reply, 0, M_COPYALL, ! 206: M_WAIT); ! 207: rp->rc_timestamp = time.tv_sec; ! 208: ret = RC_REPLY; ! 209: } else { ! 210: nfsstats.srvcache_nonidemdonehits++; ! 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: rp = nfsrvcachehead.rc_prev; ! 224: while ((rp->rc_flag & RC_LOCKED) != 0) { ! 225: rp->rc_flag |= RC_WANTED; ! 226: (void) tsleep((caddr_t)rp, PZERO-1, "nfsrc", 0); ! 227: } ! 228: remque(rp); ! 229: put_at_head(rp); ! 230: if (rp->rc_flag & RC_REPMBUF) ! 231: mb = rp->rc_reply; ! 232: else ! 233: mb = (struct mbuf *)0; ! 234: rp->rc_flag = 0; ! 235: rp->rc_state = RC_INPROG; ! 236: rp->rc_xid = xid; ! 237: bcopy((caddr_t)nam, (caddr_t)&rp->rc_nam, sizeof (struct mbuf)); ! 238: rp->rc_proc = proc; ! 239: insque(rp, rh); ! 240: if (mb) ! 241: m_freem(mb); ! 242: return (RC_DOIT); ! 243: } ! 244: ! 245: /* ! 246: * Update a request cache entry after the rpc has been done ! 247: */ ! 248: nfsrv_updatecache(nam, xid, proc, repvalid, repstat, repmbuf) ! 249: struct mbuf *nam; ! 250: u_long xid; ! 251: int proc; ! 252: int repvalid; ! 253: int repstat; ! 254: struct mbuf *repmbuf; ! 255: { ! 256: register struct nfsrvcache *rp; ! 257: register union rhead *rh; ! 258: ! 259: rh = &rhead[NFSRCHASH(xid)]; ! 260: loop: ! 261: for (rp = rh->rh_chain[0]; rp != (struct nfsrvcache *)rh; rp = rp->rc_forw) { ! 262: if (xid == rp->rc_xid && proc == rp->rc_proc && ! 263: nfs_netaddr_match(nam, &rp->rc_nam)) { ! 264: if ((rp->rc_flag & RC_LOCKED) != 0) { ! 265: rp->rc_flag |= RC_WANTED; ! 266: (void) tsleep((caddr_t)rp, PZERO-1, "nfsrc", 0); ! 267: goto loop; ! 268: } ! 269: rp->rc_flag |= RC_LOCKED; ! 270: rp->rc_state = RC_DONE; ! 271: /* ! 272: * If we have a valid reply update status and save ! 273: * the reply for non-idempotent rpc's. ! 274: * Otherwise invalidate entry by setting the timestamp ! 275: * to nil. ! 276: */ ! 277: if (repvalid) { ! 278: rp->rc_timestamp = time.tv_sec; ! 279: if (nonidempotent[proc]) { ! 280: if (repliesstatus[proc]) { ! 281: rp->rc_status = repstat; ! 282: rp->rc_flag |= RC_REPSTATUS; ! 283: } else { ! 284: rp->rc_reply = m_copym(repmbuf, ! 285: 0, M_COPYALL, M_WAIT); ! 286: rp->rc_flag |= RC_REPMBUF; ! 287: } ! 288: } ! 289: } else { ! 290: rp->rc_timestamp = 0; ! 291: } ! 292: rp->rc_flag &= ~RC_LOCKED; ! 293: if (rp->rc_flag & RC_WANTED) { ! 294: rp->rc_flag &= ~RC_WANTED; ! 295: wakeup((caddr_t)rp); ! 296: } ! 297: return; ! 298: } ! 299: } ! 300: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.