1 /* 2 * Request reply cache. This is currently a global cache, but this may 3 * change in the future and be a per-client cache. 4 * 5 * This code is heavily inspired by the 44BSD implementation, although 6 * it does things a bit differently. 7 * 8 * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de> 9 */ 10 11 #include "nfsd.h" 12 #include "cache.h" 13 14 /* Size of reply cache. Common values are: 15 * 4.3BSD: 128 16 * 4.4BSD: 256 17 * Solaris2: 1024 18 * DEC Unix: 512-4096 19 */ 20 #define CACHESIZE 1024 21 #define HASHSIZE 64 22 23 static struct hlist_head * cache_hash; 24 static struct list_head lru_head; 25 static int cache_disabled = 1; 26 27 /* 28 * Calculate the hash index from an XID. 29 */ 30 static inline u32 request_hash(u32 xid) 31 { 32 u32 h = xid; 33 h ^= (xid >> 24); 34 return h & (HASHSIZE-1); 35 } 36 37 static int nfsd_cache_append(struct svc_rqst *rqstp, struct kvec *vec); 38 39 /* 40 * locking for the reply cache: 41 * A cache entry is "single use" if c_state == RC_INPROG 42 * Otherwise, it when accessing _prev or _next, the lock must be held. 43 */ 44 static DEFINE_SPINLOCK(cache_lock); 45 46 int nfsd_reply_cache_init(void) 47 { 48 struct svc_cacherep *rp; 49 int i; 50 51 INIT_LIST_HEAD(&lru_head); 52 i = CACHESIZE; 53 while (i) { 54 rp = kmalloc(sizeof(*rp), GFP_KERNEL); 55 if (!rp) 56 goto out_nomem; 57 list_add(&rp->c_lru, &lru_head); 58 rp->c_state = RC_UNUSED; 59 rp->c_type = RC_NOCACHE; 60 INIT_HLIST_NODE(&rp->c_hash); 61 i--; 62 } 63 64 cache_hash = kcalloc (HASHSIZE, sizeof(struct hlist_head), GFP_KERNEL); 65 if (!cache_hash) 66 goto out_nomem; 67 68 cache_disabled = 0; 69 return 0; 70 out_nomem: 71 printk(KERN_ERR "nfsd: failed to allocate reply cache\n"); 72 nfsd_reply_cache_shutdown(); 73 return -ENOMEM; 74 } 75 76 void nfsd_reply_cache_shutdown(void) 77 { 78 struct svc_cacherep *rp; 79 80 while (!list_empty(&lru_head)) { 81 rp = list_entry(lru_head.next, struct svc_cacherep, c_lru); 82 if (rp->c_state == RC_DONE && rp->c_type == RC_REPLBUFF) 83 kfree(rp->c_replvec.iov_base); 84 list_del(&rp->c_lru); 85 kfree(rp); 86 } 87 88 cache_disabled = 1; 89 90 kfree (cache_hash); 91 cache_hash = NULL; 92 } 93 94 /* 95 * Move cache entry to end of LRU list 96 */ 97 static void 98 lru_put_end(struct svc_cacherep *rp) 99 { 100 list_move_tail(&rp->c_lru, &lru_head); 101 } 102 103 /* 104 * Move a cache entry from one hash list to another 105 */ 106 static void 107 hash_refile(struct svc_cacherep *rp) 108 { 109 hlist_del_init(&rp->c_hash); 110 hlist_add_head(&rp->c_hash, cache_hash + request_hash(rp->c_xid)); 111 } 112 113 /* 114 * Try to find an entry matching the current call in the cache. When none 115 * is found, we grab the oldest unlocked entry off the LRU list. 116 * Note that no operation within the loop may sleep. 117 */ 118 int 119 nfsd_cache_lookup(struct svc_rqst *rqstp, int type) 120 { 121 struct hlist_node *hn; 122 struct hlist_head *rh; 123 struct svc_cacherep *rp; 124 __be32 xid = rqstp->rq_xid; 125 u32 proto = rqstp->rq_prot, 126 vers = rqstp->rq_vers, 127 proc = rqstp->rq_proc; 128 unsigned long age; 129 int rtn; 130 131 rqstp->rq_cacherep = NULL; 132 if (cache_disabled || type == RC_NOCACHE) { 133 nfsdstats.rcnocache++; 134 return RC_DOIT; 135 } 136 137 spin_lock(&cache_lock); 138 rtn = RC_DOIT; 139 140 rh = &cache_hash[request_hash(xid)]; 141 hlist_for_each_entry(rp, hn, rh, c_hash) { 142 if (rp->c_state != RC_UNUSED && 143 xid == rp->c_xid && proc == rp->c_proc && 144 proto == rp->c_prot && vers == rp->c_vers && 145 time_before(jiffies, rp->c_timestamp + 120*HZ) && 146 memcmp((char*)&rqstp->rq_addr, (char*)&rp->c_addr, sizeof(rp->c_addr))==0) { 147 nfsdstats.rchits++; 148 goto found_entry; 149 } 150 } 151 nfsdstats.rcmisses++; 152 153 /* This loop shouldn't take more than a few iterations normally */ 154 { 155 int safe = 0; 156 list_for_each_entry(rp, &lru_head, c_lru) { 157 if (rp->c_state != RC_INPROG) 158 break; 159 if (safe++ > CACHESIZE) { 160 printk("nfsd: loop in repcache LRU list\n"); 161 cache_disabled = 1; 162 goto out; 163 } 164 } 165 } 166 167 /* All entries on the LRU are in-progress. This should not happen */ 168 if (&rp->c_lru == &lru_head) { 169 static int complaints; 170 171 printk(KERN_WARNING "nfsd: all repcache entries locked!\n"); 172 if (++complaints > 5) { 173 printk(KERN_WARNING "nfsd: disabling repcache.\n"); 174 cache_disabled = 1; 175 } 176 goto out; 177 } 178 179 rqstp->rq_cacherep = rp; 180 rp->c_state = RC_INPROG; 181 rp->c_xid = xid; 182 rp->c_proc = proc; 183 memcpy(&rp->c_addr, svc_addr_in(rqstp), sizeof(rp->c_addr)); 184 rp->c_prot = proto; 185 rp->c_vers = vers; 186 rp->c_timestamp = jiffies; 187 188 hash_refile(rp); 189 190 /* release any buffer */ 191 if (rp->c_type == RC_REPLBUFF) { 192 kfree(rp->c_replvec.iov_base); 193 rp->c_replvec.iov_base = NULL; 194 } 195 rp->c_type = RC_NOCACHE; 196 out: 197 spin_unlock(&cache_lock); 198 return rtn; 199 200 found_entry: 201 /* We found a matching entry which is either in progress or done. */ 202 age = jiffies - rp->c_timestamp; 203 rp->c_timestamp = jiffies; 204 lru_put_end(rp); 205 206 rtn = RC_DROPIT; 207 /* Request being processed or excessive rexmits */ 208 if (rp->c_state == RC_INPROG || age < RC_DELAY) 209 goto out; 210 211 /* From the hall of fame of impractical attacks: 212 * Is this a user who tries to snoop on the cache? */ 213 rtn = RC_DOIT; 214 if (!rqstp->rq_secure && rp->c_secure) 215 goto out; 216 217 /* Compose RPC reply header */ 218 switch (rp->c_type) { 219 case RC_NOCACHE: 220 break; 221 case RC_REPLSTAT: 222 svc_putu32(&rqstp->rq_res.head[0], rp->c_replstat); 223 rtn = RC_REPLY; 224 break; 225 case RC_REPLBUFF: 226 if (!nfsd_cache_append(rqstp, &rp->c_replvec)) 227 goto out; /* should not happen */ 228 rtn = RC_REPLY; 229 break; 230 default: 231 printk(KERN_WARNING "nfsd: bad repcache type %d\n", rp->c_type); 232 rp->c_state = RC_UNUSED; 233 } 234 235 goto out; 236 } 237 238 /* 239 * Update a cache entry. This is called from nfsd_dispatch when 240 * the procedure has been executed and the complete reply is in 241 * rqstp->rq_res. 242 * 243 * We're copying around data here rather than swapping buffers because 244 * the toplevel loop requires max-sized buffers, which would be a waste 245 * of memory for a cache with a max reply size of 100 bytes (diropokres). 246 * 247 * If we should start to use different types of cache entries tailored 248 * specifically for attrstat and fh's, we may save even more space. 249 * 250 * Also note that a cachetype of RC_NOCACHE can legally be passed when 251 * nfsd failed to encode a reply that otherwise would have been cached. 252 * In this case, nfsd_cache_update is called with statp == NULL. 253 */ 254 void 255 nfsd_cache_update(struct svc_rqst *rqstp, int cachetype, __be32 *statp) 256 { 257 struct svc_cacherep *rp; 258 struct kvec *resv = &rqstp->rq_res.head[0], *cachv; 259 int len; 260 261 if (!(rp = rqstp->rq_cacherep) || cache_disabled) 262 return; 263 264 len = resv->iov_len - ((char*)statp - (char*)resv->iov_base); 265 len >>= 2; 266 267 /* Don't cache excessive amounts of data and XDR failures */ 268 if (!statp || len > (256 >> 2)) { 269 rp->c_state = RC_UNUSED; 270 return; 271 } 272 273 switch (cachetype) { 274 case RC_REPLSTAT: 275 if (len != 1) 276 printk("nfsd: RC_REPLSTAT/reply len %d!\n",len); 277 rp->c_replstat = *statp; 278 break; 279 case RC_REPLBUFF: 280 cachv = &rp->c_replvec; 281 cachv->iov_base = kmalloc(len << 2, GFP_KERNEL); 282 if (!cachv->iov_base) { 283 spin_lock(&cache_lock); 284 rp->c_state = RC_UNUSED; 285 spin_unlock(&cache_lock); 286 return; 287 } 288 cachv->iov_len = len << 2; 289 memcpy(cachv->iov_base, statp, len << 2); 290 break; 291 } 292 spin_lock(&cache_lock); 293 lru_put_end(rp); 294 rp->c_secure = rqstp->rq_secure; 295 rp->c_type = cachetype; 296 rp->c_state = RC_DONE; 297 rp->c_timestamp = jiffies; 298 spin_unlock(&cache_lock); 299 return; 300 } 301 302 /* 303 * Copy cached reply to current reply buffer. Should always fit. 304 * FIXME as reply is in a page, we should just attach the page, and 305 * keep a refcount.... 306 */ 307 static int 308 nfsd_cache_append(struct svc_rqst *rqstp, struct kvec *data) 309 { 310 struct kvec *vec = &rqstp->rq_res.head[0]; 311 312 if (vec->iov_len + data->iov_len > PAGE_SIZE) { 313 printk(KERN_WARNING "nfsd: cached reply too large (%Zd).\n", 314 data->iov_len); 315 return 0; 316 } 317 memcpy((char*)vec->iov_base + vec->iov_len, data->iov_base, data->iov_len); 318 vec->iov_len += data->iov_len; 319 return 1; 320 } 321