139742Smckusick /* 239742Smckusick * Copyright (c) 1989 The Regents of the University of California. 339742Smckusick * All rights reserved. 439742Smckusick * 539742Smckusick * This code is derived from software contributed to Berkeley by 639742Smckusick * Rick Macklem at The University of Guelph. 739742Smckusick * 839742Smckusick * Redistribution and use in source and binary forms are permitted 939742Smckusick * provided that the above copyright notice and this paragraph are 1039742Smckusick * duplicated in all such forms and that any documentation, 1139742Smckusick * advertising materials, and other materials related to such 1239742Smckusick * distribution and use acknowledge that the software was developed 1339742Smckusick * by the University of California, Berkeley. The name of the 1439742Smckusick * University may not be used to endorse or promote products derived 1539742Smckusick * from this software without specific prior written permission. 1639742Smckusick * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1739742Smckusick * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1839742Smckusick * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1939742Smckusick * 20*39759Smckusick * @(#)nfs_srvcache.c 7.2 (Berkeley) 12/20/89 2139742Smckusick */ 2239742Smckusick 2339742Smckusick #include "param.h" 2439742Smckusick #include "user.h" 2539742Smckusick #include "vnode.h" 2639742Smckusick #include "mount.h" 2739742Smckusick #include "kernel.h" 28*39759Smckusick #include "systm.h" 2939742Smckusick #include "mbuf.h" 3039742Smckusick #include "socket.h" 3139742Smckusick #include "socketvar.h" 3239742Smckusick #include "netinet/in.h" 3339742Smckusick #include "nfsm_subs.h" 3439742Smckusick #include "nfsv2.h" 3539742Smckusick #include "nfsrvcache.h" 3639742Smckusick #include "nfs.h" 3739742Smckusick 3839742Smckusick #if ((NFSRCHSZ&(NFSRCHSZ-1)) == 0) 3939742Smckusick #define NFSRCHASH(xid) (((xid)+((xid)>>16))&(NFSRCHSZ-1)) 4039742Smckusick #else 4139742Smckusick #define NFSRCHASH(xid) (((unsigned)((xid)+((xid)>>16)))%NFSRCHSZ) 4239742Smckusick #endif 4339742Smckusick 4439742Smckusick union rhead { 4539742Smckusick union rhead *rh_head[2]; 4639742Smckusick struct nfsrvcache *rh_chain[2]; 4739742Smckusick } rhead[NFSRCHSZ]; 4839742Smckusick 4939742Smckusick static struct nfsrvcache nfsrvcachehead; 5039742Smckusick static struct nfsrvcache nfsrvcache[NFSRVCACHESIZ]; 5139742Smckusick 5239742Smckusick #define TRUE 1 5339742Smckusick #define FALSE 0 5439742Smckusick 5539742Smckusick /* 5639742Smckusick * Static array that defines which nfs rpc's are nonidempotent 5739742Smckusick */ 5839742Smckusick static int nonidempotent[NFS_NPROCS] = { 5939742Smckusick FALSE, 6039742Smckusick FALSE, 6139742Smckusick TRUE, 6239742Smckusick FALSE, 6339742Smckusick FALSE, 6439742Smckusick FALSE, 6539742Smckusick FALSE, 6639742Smckusick FALSE, 6739742Smckusick TRUE, 6839742Smckusick TRUE, 6939742Smckusick TRUE, 7039742Smckusick TRUE, 7139742Smckusick TRUE, 7239742Smckusick TRUE, 7339742Smckusick TRUE, 7439742Smckusick TRUE, 7539742Smckusick FALSE, 7639742Smckusick FALSE, 7739742Smckusick }; 7839742Smckusick 7939742Smckusick /* True iff the rpc reply is an nfs status ONLY! */ 8039742Smckusick static int repliesstatus[NFS_NPROCS] = { 8139742Smckusick FALSE, 8239742Smckusick FALSE, 8339742Smckusick FALSE, 8439742Smckusick FALSE, 8539742Smckusick FALSE, 8639742Smckusick FALSE, 8739742Smckusick FALSE, 8839742Smckusick FALSE, 8939742Smckusick FALSE, 9039742Smckusick FALSE, 9139742Smckusick TRUE, 9239742Smckusick TRUE, 9339742Smckusick TRUE, 9439742Smckusick TRUE, 9539742Smckusick FALSE, 9639742Smckusick TRUE, 9739742Smckusick FALSE, 9839742Smckusick FALSE, 9939742Smckusick }; 10039742Smckusick 10139742Smckusick /* 10239742Smckusick * Initialize the server request cache list 10339742Smckusick */ 10439742Smckusick nfsrv_initcache() 10539742Smckusick { 10639742Smckusick register int i; 10739742Smckusick register struct nfsrvcache *rp = nfsrvcache; 10839742Smckusick register struct nfsrvcache *hp = &nfsrvcachehead; 10939742Smckusick register union rhead *rh = rhead; 11039742Smckusick 11139742Smckusick for (i = NFSRCHSZ; --i >= 0; rh++) { 11239742Smckusick rh->rh_head[0] = rh; 11339742Smckusick rh->rh_head[1] = rh; 11439742Smckusick } 11539742Smckusick hp->rc_next = hp->rc_prev = hp; 11639742Smckusick for (i = NFSRVCACHESIZ; i-- > 0; ) { 11739742Smckusick rp->rc_state = RC_UNUSED; 11839742Smckusick rp->rc_flag = 0; 11939742Smckusick rp->rc_forw = rp; 12039742Smckusick rp->rc_back = rp; 12139742Smckusick rp->rc_next = hp->rc_next; 12239742Smckusick hp->rc_next->rc_prev = rp; 12339742Smckusick rp->rc_prev = hp; 12439742Smckusick hp->rc_next = rp; 12539742Smckusick rp++; 12639742Smckusick } 12739742Smckusick } 12839742Smckusick 12939742Smckusick /* 13039742Smckusick * Look for the request in the cache 13139742Smckusick * If found then 13239742Smckusick * return action and optionally reply 13339742Smckusick * else 13439742Smckusick * insert it in the cache 13539742Smckusick * 13639742Smckusick * The rules are as follows: 13739742Smckusick * - if in progress, return DROP request 13839742Smckusick * - if completed within DELAY of the current time, return DROP it 13939742Smckusick * - if completed a longer time ago return REPLY if the reply was cached or 14039742Smckusick * return DOIT 14139742Smckusick * Update/add new request at end of lru list 14239742Smckusick */ 14339742Smckusick nfsrv_getcache(nam, xid, proc, repp) 14439742Smckusick struct mbuf *nam; 14539742Smckusick u_long xid; 14639742Smckusick int proc; 14739742Smckusick struct mbuf **repp; 14839742Smckusick { 14939742Smckusick register struct nfsrvcache *rp; 15039742Smckusick register union rhead *rh; 15139742Smckusick register u_long saddr; 15239742Smckusick struct mbuf *mb; 15339742Smckusick caddr_t bpos; 15439742Smckusick int ret; 15539742Smckusick 15639742Smckusick rh = &rhead[NFSRCHASH(xid)]; 15739742Smckusick saddr = mtod(nam, struct sockaddr_in *)->sin_addr.s_addr; 15839742Smckusick loop: 15939742Smckusick for (rp = rh->rh_chain[0]; rp != (struct nfsrvcache *)rh; rp = rp->rc_forw) { 16039742Smckusick if (xid == rp->rc_xid && saddr == rp->rc_saddr && 16139742Smckusick proc == rp->rc_proc) { 16239742Smckusick if ((rp->rc_flag & RC_LOCKED) != 0) { 16339742Smckusick rp->rc_flag |= RC_WANTED; 16439742Smckusick sleep((caddr_t)rp, PZERO-1); 16539742Smckusick goto loop; 16639742Smckusick } 16739742Smckusick rp->rc_flag |= RC_LOCKED; 16839742Smckusick put_at_head(rp); 16939742Smckusick if (rp->rc_state == RC_UNUSED) 17039742Smckusick panic("nfsrv cache"); 17139742Smckusick if (rp->rc_state == RC_INPROG || 17239742Smckusick (time.tv_sec - rp->rc_timestamp) < RC_DELAY) { 17339742Smckusick nfsstats.srvcache_inproghits++; 17439742Smckusick ret = RC_DROPIT; 17539742Smckusick } else if (rp->rc_flag & RC_REPSTATUS) { 17639742Smckusick nfsstats.srvcache_idemdonehits++; 17739742Smckusick nfs_rephead(0, xid, rp->rc_status, repp, &mb, 17839742Smckusick &bpos); 17939742Smckusick rp->rc_timestamp = time.tv_sec; 18039742Smckusick ret = RC_REPLY; 18139742Smckusick } else if (rp->rc_flag & RC_REPMBUF) { 18239742Smckusick nfsstats.srvcache_idemdonehits++; 18339742Smckusick *repp = NFSMCOPY(rp->rc_reply, 0, M_COPYALL, 18439742Smckusick M_WAIT); 18539742Smckusick rp->rc_timestamp = time.tv_sec; 18639742Smckusick ret = RC_REPLY; 18739742Smckusick } else { 18839742Smckusick nfsstats.srvcache_nonidemdonehits++; 18939742Smckusick rp->rc_state = RC_INPROG; 19039742Smckusick ret = RC_DOIT; 19139742Smckusick } 19239742Smckusick rp->rc_flag &= ~RC_LOCKED; 19339742Smckusick if (rp->rc_flag & RC_WANTED) { 19439742Smckusick rp->rc_flag &= ~RC_WANTED; 19539742Smckusick wakeup((caddr_t)rp); 19639742Smckusick } 19739742Smckusick return (ret); 19839742Smckusick } 19939742Smckusick } 20039742Smckusick nfsstats.srvcache_misses++; 20139742Smckusick rp = nfsrvcachehead.rc_prev; 20239742Smckusick while ((rp->rc_flag & RC_LOCKED) != 0) { 20339742Smckusick rp->rc_flag |= RC_WANTED; 20439742Smckusick sleep((caddr_t)rp, PZERO-1); 20539742Smckusick } 20639742Smckusick remque(rp); 20739742Smckusick put_at_head(rp); 20839742Smckusick if (rp->rc_flag & RC_REPMBUF) 20939742Smckusick mb = rp->rc_reply; 21039742Smckusick else 21139742Smckusick mb = (struct mbuf *)0; 21239742Smckusick rp->rc_flag = 0; 21339742Smckusick rp->rc_state = RC_INPROG; 21439742Smckusick rp->rc_xid = xid; 21539742Smckusick rp->rc_saddr = saddr; 21639742Smckusick rp->rc_proc = proc; 21739742Smckusick insque(rp, rh); 21839742Smckusick if (mb) 21939742Smckusick m_freem(mb); 22039742Smckusick return (RC_DOIT); 22139742Smckusick } 22239742Smckusick 22339742Smckusick /* 22439742Smckusick * Update a request cache entry after the rpc has been done 22539742Smckusick */ 22639742Smckusick nfsrv_updatecache(nam, xid, proc, repstat, repmbuf) 22739742Smckusick struct mbuf *nam; 22839742Smckusick u_long xid; 22939742Smckusick int proc; 23039742Smckusick int repstat; 23139742Smckusick struct mbuf *repmbuf; 23239742Smckusick { 23339742Smckusick register struct nfsrvcache *rp; 23439742Smckusick register union rhead *rh; 23539742Smckusick register u_long saddr; 23639742Smckusick 23739742Smckusick rh = &rhead[NFSRCHASH(xid)]; 23839742Smckusick saddr = mtod(nam, struct sockaddr_in *)->sin_addr.s_addr; 23939742Smckusick loop: 24039742Smckusick for (rp = rh->rh_chain[0]; rp != (struct nfsrvcache *)rh; rp = rp->rc_forw) { 24139742Smckusick if (xid == rp->rc_xid && saddr == rp->rc_saddr && 24239742Smckusick proc == rp->rc_proc) { 24339742Smckusick if ((rp->rc_flag & RC_LOCKED) != 0) { 24439742Smckusick rp->rc_flag |= RC_WANTED; 24539742Smckusick sleep((caddr_t)rp, PZERO-1); 24639742Smckusick goto loop; 24739742Smckusick } 24839742Smckusick rp->rc_flag |= RC_LOCKED; 24939742Smckusick rp->rc_state = RC_DONE; 25039742Smckusick rp->rc_timestamp = time.tv_sec; 25139742Smckusick if (nonidempotent[proc]) { 25239742Smckusick if (repliesstatus[proc]) { 25339742Smckusick rp->rc_status = repstat; 25439742Smckusick rp->rc_flag |= RC_REPSTATUS; 25539742Smckusick } else { 25639742Smckusick rp->rc_reply = NFSMCOPY(repmbuf, 0, 25739742Smckusick M_COPYALL, M_WAIT); 25839742Smckusick rp->rc_flag |= RC_REPMBUF; 25939742Smckusick } 26039742Smckusick } 26139742Smckusick rp->rc_flag &= ~RC_LOCKED; 26239742Smckusick if (rp->rc_flag & RC_WANTED) { 26339742Smckusick rp->rc_flag &= ~RC_WANTED; 26439742Smckusick wakeup((caddr_t)rp); 26539742Smckusick } 26639742Smckusick return; 26739742Smckusick } 26839742Smckusick } 26939742Smckusick } 270