|
|
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 is only permitted until one year after the first shipment ! 9: * of 4.4BSD by the Regents. Otherwise, redistribution and use in source and ! 10: * binary forms are permitted provided that: (1) source distributions retain ! 11: * this entire copyright notice and comment, and (2) distributions including ! 12: * binaries display the following acknowledgement: This product includes ! 13: * software developed by the University of California, Berkeley and its ! 14: * contributors'' in the documentation or other materials provided with the ! 15: * distribution and in all advertising materials mentioning features or use ! 16: * of this software. Neither the name of the University nor the names of ! 17: * its contributors may be used to endorse or promote products derived from ! 18: * this software without specific prior written permission. ! 19: * THIS SOFTWARE IS PROVIDED AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED ! 20: * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF ! 21: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. ! 22: * ! 23: * @(#)nfs_srvcache.c 7.9 (Berkeley) 6/28/90 ! 24: */ ! 25: ! 26: /* ! 27: * Reference: Chet Juszczak, "Improving the Performance and Correctness ! 28: * of an NFS Server", in Proc. Winter 1989 USENIX Conference, ! 29: * pages 53-63. San Diego, February 1989. ! 30: */ ! 31: ! 32: #include "param.h" ! 33: #include "user.h" ! 34: #include "vnode.h" ! 35: #include "mount.h" ! 36: #include "kernel.h" ! 37: #include "systm.h" ! 38: #include "mbuf.h" ! 39: #include "socket.h" ! 40: #include "socketvar.h" ! 41: #include "../netinet/in.h" ! 42: #include "nfsm_subs.h" ! 43: #include "nfsv2.h" ! 44: #include "nfsrvcache.h" ! 45: #include "nfs.h" ! 46: ! 47: #if ((NFSRCHSZ&(NFSRCHSZ-1)) == 0) ! 48: #define NFSRCHASH(xid) (((xid)+((xid)>>16))&(NFSRCHSZ-1)) ! 49: #else ! 50: #define NFSRCHASH(xid) (((unsigned)((xid)+((xid)>>16)))%NFSRCHSZ) ! 51: #endif ! 52: ! 53: union rhead { ! 54: union rhead *rh_head[2]; ! 55: struct nfsrvcache *rh_chain[2]; ! 56: } rhead[NFSRCHSZ]; ! 57: ! 58: static struct nfsrvcache nfsrvcachehead; ! 59: static struct nfsrvcache nfsrvcache[NFSRVCACHESIZ]; ! 60: ! 61: #define TRUE 1 ! 62: #define FALSE 0 ! 63: ! 64: /* ! 65: * Static array that defines which nfs rpc's are nonidempotent ! 66: */ ! 67: int nonidempotent[NFS_NPROCS] = { ! 68: FALSE, ! 69: FALSE, ! 70: TRUE, ! 71: FALSE, ! 72: FALSE, ! 73: FALSE, ! 74: FALSE, ! 75: FALSE, ! 76: TRUE, ! 77: TRUE, ! 78: TRUE, ! 79: TRUE, ! 80: TRUE, ! 81: TRUE, ! 82: TRUE, ! 83: TRUE, ! 84: FALSE, ! 85: FALSE, ! 86: }; ! 87: ! 88: /* True iff the rpc reply is an nfs status ONLY! */ ! 89: static int repliesstatus[NFS_NPROCS] = { ! 90: FALSE, ! 91: FALSE, ! 92: FALSE, ! 93: FALSE, ! 94: FALSE, ! 95: FALSE, ! 96: FALSE, ! 97: FALSE, ! 98: FALSE, ! 99: FALSE, ! 100: TRUE, ! 101: TRUE, ! 102: TRUE, ! 103: TRUE, ! 104: FALSE, ! 105: TRUE, ! 106: FALSE, ! 107: FALSE, ! 108: }; ! 109: ! 110: /* ! 111: * Initialize the server request cache list ! 112: */ ! 113: nfsrv_initcache() ! 114: { ! 115: register int i; ! 116: register struct nfsrvcache *rp = nfsrvcache; ! 117: register struct nfsrvcache *hp = &nfsrvcachehead; ! 118: register union rhead *rh = rhead; ! 119: ! 120: for (i = NFSRCHSZ; --i >= 0; rh++) { ! 121: rh->rh_head[0] = rh; ! 122: rh->rh_head[1] = rh; ! 123: } ! 124: hp->rc_next = hp->rc_prev = hp; ! 125: for (i = NFSRVCACHESIZ; i-- > 0; ) { ! 126: rp->rc_state = RC_UNUSED; ! 127: rp->rc_flag = 0; ! 128: rp->rc_forw = rp; ! 129: rp->rc_back = rp; ! 130: rp->rc_next = hp->rc_next; ! 131: hp->rc_next->rc_prev = rp; ! 132: rp->rc_prev = hp; ! 133: hp->rc_next = rp; ! 134: rp++; ! 135: } ! 136: } ! 137: ! 138: /* ! 139: * Look for the request in the cache ! 140: * If found then ! 141: * return action and optionally reply ! 142: * else ! 143: * insert it in the cache ! 144: * ! 145: * The rules are as follows: ! 146: * - if in progress, return DROP request ! 147: * - if completed within DELAY of the current time, return DROP it ! 148: * - if completed a longer time ago return REPLY if the reply was cached or ! 149: * return DOIT ! 150: * Update/add new request at end of lru list ! 151: */ ! 152: nfsrv_getcache(nam, xid, proc, repp) ! 153: struct mbuf *nam; ! 154: u_long xid; ! 155: int proc; ! 156: struct mbuf **repp; ! 157: { ! 158: register struct nfsrvcache *rp; ! 159: register union rhead *rh; ! 160: struct mbuf *mb; ! 161: caddr_t bpos; ! 162: int ret; ! 163: ! 164: rh = &rhead[NFSRCHASH(xid)]; ! 165: loop: ! 166: for (rp = rh->rh_chain[0]; rp != (struct nfsrvcache *)rh; rp = rp->rc_forw) { ! 167: if (xid == rp->rc_xid && proc == rp->rc_proc && ! 168: nfs_netaddr_match(nam, &rp->rc_nam)) { ! 169: if ((rp->rc_flag & RC_LOCKED) != 0) { ! 170: rp->rc_flag |= RC_WANTED; ! 171: (void) tsleep((caddr_t)rp, PZERO-1, "nfsrc", 0); ! 172: goto loop; ! 173: } ! 174: rp->rc_flag |= RC_LOCKED; ! 175: put_at_head(rp); ! 176: if (rp->rc_state == RC_UNUSED) ! 177: panic("nfsrv cache"); ! 178: if (rp->rc_state == RC_INPROG || ! 179: (time.tv_sec - rp->rc_timestamp) < RC_DELAY) { ! 180: nfsstats.srvcache_inproghits++; ! 181: ret = RC_DROPIT; ! 182: } else if (rp->rc_flag & RC_REPSTATUS) { ! 183: nfsstats.srvcache_idemdonehits++; ! 184: nfs_rephead(0, xid, rp->rc_status, repp, &mb, ! 185: &bpos); ! 186: rp->rc_timestamp = time.tv_sec; ! 187: ret = RC_REPLY; ! 188: } else if (rp->rc_flag & RC_REPMBUF) { ! 189: nfsstats.srvcache_idemdonehits++; ! 190: *repp = m_copym(rp->rc_reply, 0, M_COPYALL, ! 191: M_WAIT); ! 192: rp->rc_timestamp = time.tv_sec; ! 193: ret = RC_REPLY; ! 194: } else { ! 195: nfsstats.srvcache_nonidemdonehits++; ! 196: rp->rc_state = RC_INPROG; ! 197: ret = RC_DOIT; ! 198: } ! 199: rp->rc_flag &= ~RC_LOCKED; ! 200: if (rp->rc_flag & RC_WANTED) { ! 201: rp->rc_flag &= ~RC_WANTED; ! 202: wakeup((caddr_t)rp); ! 203: } ! 204: return (ret); ! 205: } ! 206: } ! 207: nfsstats.srvcache_misses++; ! 208: rp = nfsrvcachehead.rc_prev; ! 209: while ((rp->rc_flag & RC_LOCKED) != 0) { ! 210: rp->rc_flag |= RC_WANTED; ! 211: (void) tsleep((caddr_t)rp, PZERO-1, "nfsrc", 0); ! 212: } ! 213: remque(rp); ! 214: put_at_head(rp); ! 215: if (rp->rc_flag & RC_REPMBUF) ! 216: mb = rp->rc_reply; ! 217: else ! 218: mb = (struct mbuf *)0; ! 219: rp->rc_flag = 0; ! 220: rp->rc_state = RC_INPROG; ! 221: rp->rc_xid = xid; ! 222: bcopy((caddr_t)nam, (caddr_t)&rp->rc_nam, sizeof (struct mbuf)); ! 223: rp->rc_proc = proc; ! 224: insque(rp, rh); ! 225: if (mb) ! 226: m_freem(mb); ! 227: return (RC_DOIT); ! 228: } ! 229: ! 230: /* ! 231: * Update a request cache entry after the rpc has been done ! 232: */ ! 233: nfsrv_updatecache(nam, xid, proc, repvalid, repstat, repmbuf) ! 234: struct mbuf *nam; ! 235: u_long xid; ! 236: int proc; ! 237: int repvalid; ! 238: int repstat; ! 239: struct mbuf *repmbuf; ! 240: { ! 241: register struct nfsrvcache *rp; ! 242: register union rhead *rh; ! 243: ! 244: rh = &rhead[NFSRCHASH(xid)]; ! 245: loop: ! 246: for (rp = rh->rh_chain[0]; rp != (struct nfsrvcache *)rh; rp = rp->rc_forw) { ! 247: if (xid == rp->rc_xid && proc == rp->rc_proc && ! 248: nfs_netaddr_match(nam, &rp->rc_nam)) { ! 249: if ((rp->rc_flag & RC_LOCKED) != 0) { ! 250: rp->rc_flag |= RC_WANTED; ! 251: (void) tsleep((caddr_t)rp, PZERO-1, "nfsrc", 0); ! 252: goto loop; ! 253: } ! 254: rp->rc_flag |= RC_LOCKED; ! 255: rp->rc_state = RC_DONE; ! 256: /* ! 257: * If we have a valid reply update status and save ! 258: * the reply for non-idempotent rpc's. ! 259: * Otherwise invalidate entry by setting the timestamp ! 260: * to nil. ! 261: */ ! 262: if (repvalid) { ! 263: rp->rc_timestamp = time.tv_sec; ! 264: if (nonidempotent[proc]) { ! 265: if (repliesstatus[proc]) { ! 266: rp->rc_status = repstat; ! 267: rp->rc_flag |= RC_REPSTATUS; ! 268: } else { ! 269: rp->rc_reply = m_copym(repmbuf, ! 270: 0, M_COPYALL, M_WAIT); ! 271: rp->rc_flag |= RC_REPMBUF; ! 272: } ! 273: } ! 274: } else { ! 275: rp->rc_timestamp = 0; ! 276: } ! 277: rp->rc_flag &= ~RC_LOCKED; ! 278: if (rp->rc_flag & RC_WANTED) { ! 279: rp->rc_flag &= ~RC_WANTED; ! 280: wakeup((caddr_t)rp); ! 281: } ! 282: return; ! 283: } ! 284: } ! 285: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.