xref: /csrg-svn/sys/nfs/nfs_srvcache.c (revision 67708)
139742Smckusick /*
263234Sbostic  * Copyright (c) 1989, 1993
363234Sbostic  *	The Regents of the University of California.  All rights reserved.
439742Smckusick  *
539742Smckusick  * This code is derived from software contributed to Berkeley by
639742Smckusick  * Rick Macklem at The University of Guelph.
739742Smckusick  *
844512Sbostic  * %sccs.include.redist.c%
939742Smckusick  *
10*67708Smckusick  *	@(#)nfs_srvcache.c	8.2 (Berkeley) 08/18/94
1139742Smckusick  */
1239742Smckusick 
1343431Smckusick /*
1443431Smckusick  * Reference: Chet Juszczak, "Improving the Performance and Correctness
1552196Smckusick  *		of an NFS Server", in Proc. Winter 1989 USENIX Conference,
1652196Smckusick  *		pages 53-63. San Diego, February 1989.
1743431Smckusick  */
1854874Smckusick #include <sys/param.h>
1954874Smckusick #include <sys/vnode.h>
2054874Smckusick #include <sys/mount.h>
2154874Smckusick #include <sys/kernel.h>
2254874Smckusick #include <sys/systm.h>
2354874Smckusick #include <sys/proc.h>
2454874Smckusick #include <sys/mbuf.h>
2555520Smckusick #include <sys/malloc.h>
2654874Smckusick #include <sys/socket.h>
2754874Smckusick #include <sys/socketvar.h>
2856535Sbostic 
2954874Smckusick #include <netinet/in.h>
3052196Smckusick #ifdef ISO
3154874Smckusick #include <netiso/iso.h>
3252196Smckusick #endif
3354874Smckusick #include <nfs/nfsm_subs.h>
3454874Smckusick #include <nfs/rpcv2.h>
3554874Smckusick #include <nfs/nfsv2.h>
3654874Smckusick #include <nfs/nfs.h>
3754874Smckusick #include <nfs/nfsrvcache.h>
3854874Smckusick #include <nfs/nqnfs.h>
3939742Smckusick 
4055520Smckusick long numnfsrvcache, desirednfsrvcache = NFSRVCACHESIZ;
4139742Smckusick 
42*67708Smckusick #define	NFSRCHASH(xid) \
43*67708Smckusick 	(&nfsrvhashtbl[((xid) + ((xid) >> 24)) & nfsrvhash])
44*67708Smckusick LIST_HEAD(nfsrvhash, nfsrvcache) *nfsrvhashtbl;
45*67708Smckusick TAILQ_HEAD(nfsrvlru, nfsrvcache) nfsrvlruhead;
46*67708Smckusick u_long nfsrvhash;
4739742Smckusick 
4839742Smckusick #define TRUE	1
4939742Smckusick #define	FALSE	0
5039742Smckusick 
5152196Smckusick #define	NETFAMILY(rp) \
5252196Smckusick 		(((rp)->rc_flag & RC_INETADDR) ? AF_INET : AF_ISO)
5352196Smckusick 
5439742Smckusick /*
5539742Smckusick  * Static array that defines which nfs rpc's are nonidempotent
5639742Smckusick  */
5740118Smckusick int nonidempotent[NFS_NPROCS] = {
5839742Smckusick 	FALSE,
5939742Smckusick 	FALSE,
6039742Smckusick 	TRUE,
6139742Smckusick 	FALSE,
6239742Smckusick 	FALSE,
6339742Smckusick 	FALSE,
6439742Smckusick 	FALSE,
6539742Smckusick 	FALSE,
6639742Smckusick 	TRUE,
6739742Smckusick 	TRUE,
6839742Smckusick 	TRUE,
6939742Smckusick 	TRUE,
7039742Smckusick 	TRUE,
7139742Smckusick 	TRUE,
7239742Smckusick 	TRUE,
7339742Smckusick 	TRUE,
7439742Smckusick 	FALSE,
7539742Smckusick 	FALSE,
7652196Smckusick 	FALSE,
7752196Smckusick 	FALSE,
7852196Smckusick 	FALSE,
7952196Smckusick 	FALSE,
8056362Smckusick 	FALSE,
8139742Smckusick };
8239742Smckusick 
8339742Smckusick /* True iff the rpc reply is an nfs status ONLY! */
8439742Smckusick static int repliesstatus[NFS_NPROCS] = {
8539742Smckusick 	FALSE,
8639742Smckusick 	FALSE,
8739742Smckusick 	FALSE,
8839742Smckusick 	FALSE,
8939742Smckusick 	FALSE,
9039742Smckusick 	FALSE,
9139742Smckusick 	FALSE,
9239742Smckusick 	FALSE,
9339742Smckusick 	FALSE,
9439742Smckusick 	FALSE,
9539742Smckusick 	TRUE,
9639742Smckusick 	TRUE,
9739742Smckusick 	TRUE,
9839742Smckusick 	TRUE,
9939742Smckusick 	FALSE,
10039742Smckusick 	TRUE,
10139742Smckusick 	FALSE,
10239742Smckusick 	FALSE,
10352196Smckusick 	FALSE,
10452196Smckusick 	FALSE,
10552196Smckusick 	FALSE,
10652196Smckusick 	FALSE,
10756362Smckusick 	TRUE,
10839742Smckusick };
10939742Smckusick 
11039742Smckusick /*
11139742Smckusick  * Initialize the server request cache list
11239742Smckusick  */
11339742Smckusick nfsrv_initcache()
11439742Smckusick {
11539742Smckusick 
116*67708Smckusick 	nfsrvhashtbl = hashinit(desirednfsrvcache, M_NFSD, &nfsrvhash);
117*67708Smckusick 	TAILQ_INIT(&nfsrvlruhead);
11839742Smckusick }
11939742Smckusick 
12039742Smckusick /*
12139742Smckusick  * Look for the request in the cache
12239742Smckusick  * If found then
12339742Smckusick  *    return action and optionally reply
12439742Smckusick  * else
12539742Smckusick  *    insert it in the cache
12639742Smckusick  *
12739742Smckusick  * The rules are as follows:
12839742Smckusick  * - if in progress, return DROP request
12939742Smckusick  * - if completed within DELAY of the current time, return DROP it
13039742Smckusick  * - if completed a longer time ago return REPLY if the reply was cached or
13139742Smckusick  *   return DOIT
13239742Smckusick  * Update/add new request at end of lru list
13339742Smckusick  */
13452196Smckusick nfsrv_getcache(nam, nd, repp)
13539742Smckusick 	struct mbuf *nam;
13652196Smckusick 	register struct nfsd *nd;
13739742Smckusick 	struct mbuf **repp;
13839742Smckusick {
139*67708Smckusick 	register struct nfsrvcache *rp;
14039742Smckusick 	struct mbuf *mb;
14152196Smckusick 	struct sockaddr_in *saddr;
14239742Smckusick 	caddr_t bpos;
14339742Smckusick 	int ret;
14439742Smckusick 
14552196Smckusick 	if (nd->nd_nqlflag != NQL_NOVAL)
14652196Smckusick 		return (RC_DOIT);
14739742Smckusick loop:
148*67708Smckusick 	for (rp = NFSRCHASH(nd->nd_retxid)->lh_first; rp != 0;
149*67708Smckusick 	    rp = rp->rc_hash.le_next) {
15052196Smckusick 	    if (nd->nd_retxid == rp->rc_xid && nd->nd_procnum == rp->rc_proc &&
15156362Smckusick 		netaddr_match(NETFAMILY(rp), &rp->rc_haddr, nam)) {
15239742Smckusick 			if ((rp->rc_flag & RC_LOCKED) != 0) {
15339742Smckusick 				rp->rc_flag |= RC_WANTED;
15443352Smckusick 				(void) tsleep((caddr_t)rp, PZERO-1, "nfsrc", 0);
15539742Smckusick 				goto loop;
15639742Smckusick 			}
15739742Smckusick 			rp->rc_flag |= RC_LOCKED;
15855520Smckusick 			/* If not at end of LRU chain, move it there */
159*67708Smckusick 			if (rp->rc_lru.tqe_next) {
160*67708Smckusick 				TAILQ_REMOVE(&nfsrvlruhead, rp, rc_lru);
161*67708Smckusick 				TAILQ_INSERT_TAIL(&nfsrvlruhead, rp, rc_lru);
16252196Smckusick 			}
16339742Smckusick 			if (rp->rc_state == RC_UNUSED)
16439742Smckusick 				panic("nfsrv cache");
16560155Smckusick 			if (rp->rc_state == RC_INPROG) {
16639742Smckusick 				nfsstats.srvcache_inproghits++;
16739742Smckusick 				ret = RC_DROPIT;
16839742Smckusick 			} else if (rp->rc_flag & RC_REPSTATUS) {
16960155Smckusick 				nfsstats.srvcache_nonidemdonehits++;
17052196Smckusick 				nfs_rephead(0, nd, rp->rc_status,
17152196Smckusick 				   0, (u_quad_t *)0, repp, &mb, &bpos);
17239742Smckusick 				ret = RC_REPLY;
17339742Smckusick 			} else if (rp->rc_flag & RC_REPMBUF) {
17460155Smckusick 				nfsstats.srvcache_nonidemdonehits++;
17541901Smckusick 				*repp = m_copym(rp->rc_reply, 0, M_COPYALL,
17639742Smckusick 						M_WAIT);
17739742Smckusick 				ret = RC_REPLY;
17839742Smckusick 			} else {
17960155Smckusick 				nfsstats.srvcache_idemdonehits++;
18039742Smckusick 				rp->rc_state = RC_INPROG;
18139742Smckusick 				ret = RC_DOIT;
18239742Smckusick 			}
18339742Smckusick 			rp->rc_flag &= ~RC_LOCKED;
18439742Smckusick 			if (rp->rc_flag & RC_WANTED) {
18539742Smckusick 				rp->rc_flag &= ~RC_WANTED;
18639742Smckusick 				wakeup((caddr_t)rp);
18739742Smckusick 			}
18839742Smckusick 			return (ret);
18939742Smckusick 		}
19039742Smckusick 	}
19139742Smckusick 	nfsstats.srvcache_misses++;
19255520Smckusick 	if (numnfsrvcache < desirednfsrvcache) {
19355520Smckusick 		rp = (struct nfsrvcache *)malloc((u_long)sizeof *rp,
19455520Smckusick 		    M_NFSD, M_WAITOK);
19555520Smckusick 		bzero((char *)rp, sizeof *rp);
19655520Smckusick 		numnfsrvcache++;
19755520Smckusick 		rp->rc_flag = RC_LOCKED;
19855520Smckusick 	} else {
199*67708Smckusick 		rp = nfsrvlruhead.tqh_first;
20055520Smckusick 		while ((rp->rc_flag & RC_LOCKED) != 0) {
20155520Smckusick 			rp->rc_flag |= RC_WANTED;
20255520Smckusick 			(void) tsleep((caddr_t)rp, PZERO-1, "nfsrc", 0);
203*67708Smckusick 			rp = nfsrvlruhead.tqh_first;
20455520Smckusick 		}
20555520Smckusick 		rp->rc_flag |= RC_LOCKED;
206*67708Smckusick 		LIST_REMOVE(rp, rc_hash);
207*67708Smckusick 		TAILQ_REMOVE(&nfsrvlruhead, rp, rc_lru);
20855520Smckusick 		if (rp->rc_flag & RC_REPMBUF)
20955520Smckusick 			m_freem(rp->rc_reply);
21055520Smckusick 		if (rp->rc_flag & RC_NAM)
21155520Smckusick 			MFREE(rp->rc_nam, mb);
21255520Smckusick 		rp->rc_flag &= (RC_LOCKED | RC_WANTED);
21352196Smckusick 	}
214*67708Smckusick 	TAILQ_INSERT_TAIL(&nfsrvlruhead, rp, rc_lru);
21539742Smckusick 	rp->rc_state = RC_INPROG;
21652196Smckusick 	rp->rc_xid = nd->nd_retxid;
21752196Smckusick 	saddr = mtod(nam, struct sockaddr_in *);
21852196Smckusick 	switch (saddr->sin_family) {
21952196Smckusick 	case AF_INET:
22052196Smckusick 		rp->rc_flag |= RC_INETADDR;
22152196Smckusick 		rp->rc_inetaddr = saddr->sin_addr.s_addr;
22252196Smckusick 		break;
22352196Smckusick 	case AF_ISO:
22452196Smckusick 	default:
22552196Smckusick 		rp->rc_flag |= RC_NAM;
22652196Smckusick 		rp->rc_nam = m_copym(nam, 0, M_COPYALL, M_WAIT);
22752196Smckusick 		break;
22852196Smckusick 	};
22952196Smckusick 	rp->rc_proc = nd->nd_procnum;
230*67708Smckusick 	LIST_INSERT_HEAD(NFSRCHASH(nd->nd_retxid), rp, rc_hash);
23152196Smckusick 	rp->rc_flag &= ~RC_LOCKED;
23252196Smckusick 	if (rp->rc_flag & RC_WANTED) {
23352196Smckusick 		rp->rc_flag &= ~RC_WANTED;
23452196Smckusick 		wakeup((caddr_t)rp);
23552196Smckusick 	}
23639742Smckusick 	return (RC_DOIT);
23739742Smckusick }
23839742Smckusick 
23939742Smckusick /*
24039742Smckusick  * Update a request cache entry after the rpc has been done
24139742Smckusick  */
24252196Smckusick void
24352196Smckusick nfsrv_updatecache(nam, nd, repvalid, repmbuf)
24439742Smckusick 	struct mbuf *nam;
24552196Smckusick 	register struct nfsd *nd;
24640253Smckusick 	int repvalid;
24739742Smckusick 	struct mbuf *repmbuf;
24839742Smckusick {
24939742Smckusick 	register struct nfsrvcache *rp;
25039742Smckusick 
25152196Smckusick 	if (nd->nd_nqlflag != NQL_NOVAL)
25252196Smckusick 		return;
25339742Smckusick loop:
254*67708Smckusick 	for (rp = NFSRCHASH(nd->nd_retxid)->lh_first; rp != 0;
255*67708Smckusick 	    rp = rp->rc_hash.le_next) {
25652196Smckusick 	    if (nd->nd_retxid == rp->rc_xid && nd->nd_procnum == rp->rc_proc &&
25756362Smckusick 		netaddr_match(NETFAMILY(rp), &rp->rc_haddr, nam)) {
25839742Smckusick 			if ((rp->rc_flag & RC_LOCKED) != 0) {
25939742Smckusick 				rp->rc_flag |= RC_WANTED;
26043352Smckusick 				(void) tsleep((caddr_t)rp, PZERO-1, "nfsrc", 0);
26139742Smckusick 				goto loop;
26239742Smckusick 			}
26339742Smckusick 			rp->rc_flag |= RC_LOCKED;
26439742Smckusick 			rp->rc_state = RC_DONE;
26540253Smckusick 			/*
26640253Smckusick 			 * If we have a valid reply update status and save
26741901Smckusick 			 * the reply for non-idempotent rpc's.
26840253Smckusick 			 */
26960155Smckusick 			if (repvalid && nonidempotent[nd->nd_procnum]) {
27060155Smckusick 				if (repliesstatus[nd->nd_procnum]) {
27160155Smckusick 					rp->rc_status = nd->nd_repstat;
27260155Smckusick 					rp->rc_flag |= RC_REPSTATUS;
27360155Smckusick 				} else {
27460155Smckusick 					rp->rc_reply = m_copym(repmbuf,
27560155Smckusick 						0, M_COPYALL, M_WAIT);
27660155Smckusick 					rp->rc_flag |= RC_REPMBUF;
27739742Smckusick 				}
27839742Smckusick 			}
27939742Smckusick 			rp->rc_flag &= ~RC_LOCKED;
28039742Smckusick 			if (rp->rc_flag & RC_WANTED) {
28139742Smckusick 				rp->rc_flag &= ~RC_WANTED;
28239742Smckusick 				wakeup((caddr_t)rp);
28339742Smckusick 			}
28439742Smckusick 			return;
28539742Smckusick 		}
28639742Smckusick 	}
28739742Smckusick }
28852196Smckusick 
28952196Smckusick /*
29052196Smckusick  * Clean out the cache. Called when the last nfsd terminates.
29152196Smckusick  */
29252196Smckusick void
29352196Smckusick nfsrv_cleancache()
29452196Smckusick {
29555520Smckusick 	register struct nfsrvcache *rp, *nextrp;
29652196Smckusick 
297*67708Smckusick 	for (rp = nfsrvlruhead.tqh_first; rp != 0; rp = nextrp) {
298*67708Smckusick 		nextrp = rp->rc_lru.tqe_next;
299*67708Smckusick 		LIST_REMOVE(rp, rc_hash);
300*67708Smckusick 		TAILQ_REMOVE(&nfsrvlruhead, rp, rc_lru);
30155520Smckusick 		free(rp, M_NFSD);
30252196Smckusick 	}
30355520Smckusick 	numnfsrvcache = 0;
30452196Smckusick }
305