1a9148abdSDoug Rabson /*- 2a9148abdSDoug Rabson * Copyright (c) 2008 Isilon Inc http://www.isilon.com/ 3a9148abdSDoug Rabson * Authors: Doug Rabson <dfr@rabson.org> 4a9148abdSDoug Rabson * Developed with Red Inc: Alfred Perlstein <alfred@freebsd.org> 5a9148abdSDoug Rabson * 6a9148abdSDoug Rabson * Redistribution and use in source and binary forms, with or without 7a9148abdSDoug Rabson * modification, are permitted provided that the following conditions 8a9148abdSDoug Rabson * are met: 9a9148abdSDoug Rabson * 1. Redistributions of source code must retain the above copyright 10a9148abdSDoug Rabson * notice, this list of conditions and the following disclaimer. 11a9148abdSDoug Rabson * 2. Redistributions in binary form must reproduce the above copyright 12a9148abdSDoug Rabson * notice, this list of conditions and the following disclaimer in the 13a9148abdSDoug Rabson * documentation and/or other materials provided with the distribution. 14a9148abdSDoug Rabson * 15a9148abdSDoug Rabson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16a9148abdSDoug Rabson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17a9148abdSDoug Rabson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18a9148abdSDoug Rabson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19a9148abdSDoug Rabson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20a9148abdSDoug Rabson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21a9148abdSDoug Rabson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22a9148abdSDoug Rabson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23a9148abdSDoug Rabson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24a9148abdSDoug Rabson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25a9148abdSDoug Rabson * SUCH DAMAGE. 26a9148abdSDoug Rabson */ 27a9148abdSDoug Rabson 28a9148abdSDoug Rabson #include <sys/cdefs.h> 29a9148abdSDoug Rabson __FBSDID("$FreeBSD$"); 30a9148abdSDoug Rabson 31a9148abdSDoug Rabson #include <sys/param.h> 32a9148abdSDoug Rabson #include <sys/hash.h> 33a9148abdSDoug Rabson #include <sys/kernel.h> 34a9148abdSDoug Rabson #include <sys/lock.h> 35a9148abdSDoug Rabson #include <sys/mbuf.h> 36a9148abdSDoug Rabson #include <sys/mutex.h> 37a9148abdSDoug Rabson #include <sys/queue.h> 38a9148abdSDoug Rabson 39a9148abdSDoug Rabson #include <rpc/rpc.h> 40a9148abdSDoug Rabson #include <rpc/replay.h> 41a9148abdSDoug Rabson 42a9148abdSDoug Rabson struct replay_cache_entry { 43a9148abdSDoug Rabson int rce_hash; 44a9148abdSDoug Rabson struct rpc_msg rce_msg; 45a9148abdSDoug Rabson struct sockaddr_storage rce_addr; 46a9148abdSDoug Rabson struct rpc_msg rce_repmsg; 47a9148abdSDoug Rabson struct mbuf *rce_repbody; 48a9148abdSDoug Rabson 49a9148abdSDoug Rabson TAILQ_ENTRY(replay_cache_entry) rce_link; 50a9148abdSDoug Rabson TAILQ_ENTRY(replay_cache_entry) rce_alllink; 51a9148abdSDoug Rabson }; 52a9148abdSDoug Rabson TAILQ_HEAD(replay_cache_list, replay_cache_entry); 53a9148abdSDoug Rabson 54a9148abdSDoug Rabson static struct replay_cache_entry * 55a9148abdSDoug Rabson replay_alloc(struct replay_cache *rc, struct rpc_msg *msg, 56a9148abdSDoug Rabson struct sockaddr *addr, int h); 57a9148abdSDoug Rabson static void replay_free(struct replay_cache *rc, 58a9148abdSDoug Rabson struct replay_cache_entry *rce); 59a9148abdSDoug Rabson static void replay_prune(struct replay_cache *rc); 60a9148abdSDoug Rabson 61a9148abdSDoug Rabson #define REPLAY_HASH_SIZE 256 62a9148abdSDoug Rabson #define REPLAY_MAX 1024 63a9148abdSDoug Rabson 64a9148abdSDoug Rabson struct replay_cache { 65a9148abdSDoug Rabson struct replay_cache_list rc_cache[REPLAY_HASH_SIZE]; 66a9148abdSDoug Rabson struct replay_cache_list rc_all; 67a9148abdSDoug Rabson struct mtx rc_lock; 68a9148abdSDoug Rabson int rc_count; 69a9148abdSDoug Rabson size_t rc_size; 70a9148abdSDoug Rabson size_t rc_maxsize; 71a9148abdSDoug Rabson }; 72a9148abdSDoug Rabson 73a9148abdSDoug Rabson struct replay_cache * 74a9148abdSDoug Rabson replay_newcache(size_t maxsize) 75a9148abdSDoug Rabson { 76a9148abdSDoug Rabson struct replay_cache *rc; 77a9148abdSDoug Rabson int i; 78a9148abdSDoug Rabson 79a9148abdSDoug Rabson rc = malloc(sizeof(*rc), M_RPC, M_WAITOK|M_ZERO); 80a9148abdSDoug Rabson for (i = 0; i < REPLAY_HASH_SIZE; i++) 81a9148abdSDoug Rabson TAILQ_INIT(&rc->rc_cache[i]); 82a9148abdSDoug Rabson TAILQ_INIT(&rc->rc_all); 83a9148abdSDoug Rabson mtx_init(&rc->rc_lock, "rc_lock", NULL, MTX_DEF); 84a9148abdSDoug Rabson rc->rc_maxsize = maxsize; 85a9148abdSDoug Rabson 86a9148abdSDoug Rabson return (rc); 87a9148abdSDoug Rabson } 88a9148abdSDoug Rabson 89a9148abdSDoug Rabson void 90a9148abdSDoug Rabson replay_setsize(struct replay_cache *rc, size_t newmaxsize) 91a9148abdSDoug Rabson { 92a9148abdSDoug Rabson 93*d7dc2db4SRick Macklem mtx_lock(&rc->rc_lock); 94a9148abdSDoug Rabson rc->rc_maxsize = newmaxsize; 95a9148abdSDoug Rabson replay_prune(rc); 96*d7dc2db4SRick Macklem mtx_unlock(&rc->rc_lock); 97a9148abdSDoug Rabson } 98a9148abdSDoug Rabson 99a9148abdSDoug Rabson void 100a9148abdSDoug Rabson replay_freecache(struct replay_cache *rc) 101a9148abdSDoug Rabson { 102a9148abdSDoug Rabson 103a9148abdSDoug Rabson mtx_lock(&rc->rc_lock); 104a9148abdSDoug Rabson while (TAILQ_FIRST(&rc->rc_all)) 105a9148abdSDoug Rabson replay_free(rc, TAILQ_FIRST(&rc->rc_all)); 106a9148abdSDoug Rabson mtx_destroy(&rc->rc_lock); 107a9148abdSDoug Rabson free(rc, M_RPC); 108a9148abdSDoug Rabson } 109a9148abdSDoug Rabson 110a9148abdSDoug Rabson static struct replay_cache_entry * 111a9148abdSDoug Rabson replay_alloc(struct replay_cache *rc, 112a9148abdSDoug Rabson struct rpc_msg *msg, struct sockaddr *addr, int h) 113a9148abdSDoug Rabson { 114a9148abdSDoug Rabson struct replay_cache_entry *rce; 115a9148abdSDoug Rabson 116a9148abdSDoug Rabson rc->rc_count++; 117a9148abdSDoug Rabson rce = malloc(sizeof(*rce), M_RPC, M_NOWAIT|M_ZERO); 118a9148abdSDoug Rabson rce->rce_hash = h; 119a9148abdSDoug Rabson rce->rce_msg = *msg; 120a9148abdSDoug Rabson bcopy(addr, &rce->rce_addr, addr->sa_len); 121a9148abdSDoug Rabson 122a9148abdSDoug Rabson TAILQ_INSERT_HEAD(&rc->rc_cache[h], rce, rce_link); 123a9148abdSDoug Rabson TAILQ_INSERT_HEAD(&rc->rc_all, rce, rce_alllink); 124a9148abdSDoug Rabson 125a9148abdSDoug Rabson return (rce); 126a9148abdSDoug Rabson } 127a9148abdSDoug Rabson 128a9148abdSDoug Rabson static void 129a9148abdSDoug Rabson replay_free(struct replay_cache *rc, struct replay_cache_entry *rce) 130a9148abdSDoug Rabson { 131a9148abdSDoug Rabson 132a9148abdSDoug Rabson rc->rc_count--; 133a9148abdSDoug Rabson TAILQ_REMOVE(&rc->rc_cache[rce->rce_hash], rce, rce_link); 134a9148abdSDoug Rabson TAILQ_REMOVE(&rc->rc_all, rce, rce_alllink); 135a9148abdSDoug Rabson if (rce->rce_repbody) { 136a9148abdSDoug Rabson rc->rc_size -= m_length(rce->rce_repbody, NULL); 137a9148abdSDoug Rabson m_freem(rce->rce_repbody); 138a9148abdSDoug Rabson } 139a9148abdSDoug Rabson free(rce, M_RPC); 140a9148abdSDoug Rabson } 141a9148abdSDoug Rabson 142a9148abdSDoug Rabson static void 143a9148abdSDoug Rabson replay_prune(struct replay_cache *rc) 144a9148abdSDoug Rabson { 145a9148abdSDoug Rabson struct replay_cache_entry *rce; 146a9148abdSDoug Rabson bool_t freed_one; 147a9148abdSDoug Rabson 148a9148abdSDoug Rabson if (rc->rc_count >= REPLAY_MAX || rc->rc_size > rc->rc_maxsize) { 149a9148abdSDoug Rabson do { 15012731c31SRick Macklem freed_one = FALSE; 151a9148abdSDoug Rabson /* 152a9148abdSDoug Rabson * Try to free an entry. Don't free in-progress entries 153a9148abdSDoug Rabson */ 154a9148abdSDoug Rabson TAILQ_FOREACH_REVERSE(rce, &rc->rc_all, 155a9148abdSDoug Rabson replay_cache_list, rce_alllink) { 156a9148abdSDoug Rabson if (rce->rce_repmsg.rm_xid) { 157a9148abdSDoug Rabson replay_free(rc, rce); 158a9148abdSDoug Rabson freed_one = TRUE; 159a9148abdSDoug Rabson break; 160a9148abdSDoug Rabson } 161a9148abdSDoug Rabson } 162a9148abdSDoug Rabson } while (freed_one 163a9148abdSDoug Rabson && (rc->rc_count >= REPLAY_MAX 164a9148abdSDoug Rabson || rc->rc_size > rc->rc_maxsize)); 165a9148abdSDoug Rabson } 166a9148abdSDoug Rabson } 167a9148abdSDoug Rabson 168a9148abdSDoug Rabson enum replay_state 169a9148abdSDoug Rabson replay_find(struct replay_cache *rc, struct rpc_msg *msg, 170a9148abdSDoug Rabson struct sockaddr *addr, struct rpc_msg *repmsg, struct mbuf **mp) 171a9148abdSDoug Rabson { 172a9148abdSDoug Rabson int h = HASHSTEP(HASHINIT, msg->rm_xid) % REPLAY_HASH_SIZE; 173a9148abdSDoug Rabson struct replay_cache_entry *rce; 174a9148abdSDoug Rabson 175a9148abdSDoug Rabson mtx_lock(&rc->rc_lock); 176a9148abdSDoug Rabson TAILQ_FOREACH(rce, &rc->rc_cache[h], rce_link) { 177a9148abdSDoug Rabson if (rce->rce_msg.rm_xid == msg->rm_xid 178a9148abdSDoug Rabson && rce->rce_msg.rm_call.cb_prog == msg->rm_call.cb_prog 179a9148abdSDoug Rabson && rce->rce_msg.rm_call.cb_vers == msg->rm_call.cb_vers 180a9148abdSDoug Rabson && rce->rce_msg.rm_call.cb_proc == msg->rm_call.cb_proc 181a9148abdSDoug Rabson && rce->rce_addr.ss_len == addr->sa_len 182a9148abdSDoug Rabson && bcmp(&rce->rce_addr, addr, addr->sa_len) == 0) { 183a9148abdSDoug Rabson if (rce->rce_repmsg.rm_xid) { 184a9148abdSDoug Rabson /* 185a9148abdSDoug Rabson * We have a reply for this 186a9148abdSDoug Rabson * message. Copy it and return. Keep 187a9148abdSDoug Rabson * replay_all LRU sorted 188a9148abdSDoug Rabson */ 189a9148abdSDoug Rabson TAILQ_REMOVE(&rc->rc_all, rce, rce_alllink); 190a9148abdSDoug Rabson TAILQ_INSERT_HEAD(&rc->rc_all, rce, 191a9148abdSDoug Rabson rce_alllink); 192a9148abdSDoug Rabson *repmsg = rce->rce_repmsg; 193a9148abdSDoug Rabson if (rce->rce_repbody) { 194a9148abdSDoug Rabson *mp = m_copym(rce->rce_repbody, 195a9148abdSDoug Rabson 0, M_COPYALL, M_NOWAIT); 196a9148abdSDoug Rabson mtx_unlock(&rc->rc_lock); 197a9148abdSDoug Rabson if (!*mp) 198a9148abdSDoug Rabson return (RS_ERROR); 199a9148abdSDoug Rabson } else { 200a9148abdSDoug Rabson mtx_unlock(&rc->rc_lock); 201a9148abdSDoug Rabson } 202a9148abdSDoug Rabson return (RS_DONE); 203a9148abdSDoug Rabson } else { 204a9148abdSDoug Rabson mtx_unlock(&rc->rc_lock); 205a9148abdSDoug Rabson return (RS_INPROGRESS); 206a9148abdSDoug Rabson } 207a9148abdSDoug Rabson } 208a9148abdSDoug Rabson } 209a9148abdSDoug Rabson 210a9148abdSDoug Rabson replay_prune(rc); 211a9148abdSDoug Rabson 212a9148abdSDoug Rabson rce = replay_alloc(rc, msg, addr, h); 213a9148abdSDoug Rabson 214a9148abdSDoug Rabson mtx_unlock(&rc->rc_lock); 215a9148abdSDoug Rabson 216a9148abdSDoug Rabson if (!rce) 217a9148abdSDoug Rabson return (RS_ERROR); 218a9148abdSDoug Rabson else 219a9148abdSDoug Rabson return (RS_NEW); 220a9148abdSDoug Rabson } 221a9148abdSDoug Rabson 222a9148abdSDoug Rabson void 223a9148abdSDoug Rabson replay_setreply(struct replay_cache *rc, 224a9148abdSDoug Rabson struct rpc_msg *repmsg, struct sockaddr *addr, struct mbuf *m) 225a9148abdSDoug Rabson { 226a9148abdSDoug Rabson int h = HASHSTEP(HASHINIT, repmsg->rm_xid) % REPLAY_HASH_SIZE; 227a9148abdSDoug Rabson struct replay_cache_entry *rce; 228a9148abdSDoug Rabson 229a9148abdSDoug Rabson /* 230a9148abdSDoug Rabson * Copy the reply before the lock so we can sleep. 231a9148abdSDoug Rabson */ 232a9148abdSDoug Rabson if (m) 233a9148abdSDoug Rabson m = m_copym(m, 0, M_COPYALL, M_WAITOK); 234a9148abdSDoug Rabson 235a9148abdSDoug Rabson mtx_lock(&rc->rc_lock); 236a9148abdSDoug Rabson TAILQ_FOREACH(rce, &rc->rc_cache[h], rce_link) { 237a9148abdSDoug Rabson if (rce->rce_msg.rm_xid == repmsg->rm_xid 238a9148abdSDoug Rabson && rce->rce_addr.ss_len == addr->sa_len 239a9148abdSDoug Rabson && bcmp(&rce->rce_addr, addr, addr->sa_len) == 0) { 240a9148abdSDoug Rabson break; 241a9148abdSDoug Rabson } 242a9148abdSDoug Rabson } 243a9148abdSDoug Rabson if (rce) { 244a9148abdSDoug Rabson rce->rce_repmsg = *repmsg; 245a9148abdSDoug Rabson rce->rce_repbody = m; 246a9148abdSDoug Rabson if (m) 247a9148abdSDoug Rabson rc->rc_size += m_length(m, NULL); 248a9148abdSDoug Rabson } 249a9148abdSDoug Rabson mtx_unlock(&rc->rc_lock); 250a9148abdSDoug Rabson } 251