|
|
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 */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.