xref: /csrg-svn/sys/nfs/nfs_srvcache.c (revision 41901)
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*41901Smckusick  *	@(#)nfs_srvcache.c	7.6 (Berkeley) 05/14/90
2139742Smckusick  */
2239742Smckusick 
2339742Smckusick #include "param.h"
2439742Smckusick #include "user.h"
2539742Smckusick #include "vnode.h"
2639742Smckusick #include "mount.h"
2739742Smckusick #include "kernel.h"
2839759Smckusick #include "systm.h"
2939742Smckusick #include "mbuf.h"
3039742Smckusick #include "socket.h"
3139742Smckusick #include "socketvar.h"
3240152Smckusick #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  */
5840118Smckusick 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 	struct mbuf *mb;
15239742Smckusick 	caddr_t bpos;
15339742Smckusick 	int ret;
15439742Smckusick 
15539742Smckusick 	rh = &rhead[NFSRCHASH(xid)];
15639742Smckusick loop:
15739742Smckusick 	for (rp = rh->rh_chain[0]; rp != (struct nfsrvcache *)rh; rp = rp->rc_forw) {
158*41901Smckusick 		if (xid == rp->rc_xid && proc == rp->rc_proc &&
159*41901Smckusick 		    nfs_netaddr_match(nam, &rp->rc_nam)) {
16039742Smckusick 			if ((rp->rc_flag & RC_LOCKED) != 0) {
16139742Smckusick 				rp->rc_flag |= RC_WANTED;
16239742Smckusick 				sleep((caddr_t)rp, PZERO-1);
16339742Smckusick 				goto loop;
16439742Smckusick 			}
16539742Smckusick 			rp->rc_flag |= RC_LOCKED;
16639742Smckusick 			put_at_head(rp);
16739742Smckusick 			if (rp->rc_state == RC_UNUSED)
16839742Smckusick 				panic("nfsrv cache");
16939742Smckusick 			if (rp->rc_state == RC_INPROG ||
17039742Smckusick 			   (time.tv_sec - rp->rc_timestamp) < RC_DELAY) {
17139742Smckusick 				nfsstats.srvcache_inproghits++;
17239742Smckusick 				ret = RC_DROPIT;
17339742Smckusick 			} else if (rp->rc_flag & RC_REPSTATUS) {
17439742Smckusick 				nfsstats.srvcache_idemdonehits++;
17539742Smckusick 				nfs_rephead(0, xid, rp->rc_status, repp, &mb,
17639742Smckusick 					&bpos);
17739742Smckusick 				rp->rc_timestamp = time.tv_sec;
17839742Smckusick 				ret = RC_REPLY;
17939742Smckusick 			} else if (rp->rc_flag & RC_REPMBUF) {
18039742Smckusick 				nfsstats.srvcache_idemdonehits++;
181*41901Smckusick 				*repp = m_copym(rp->rc_reply, 0, M_COPYALL,
18239742Smckusick 						M_WAIT);
18339742Smckusick 				rp->rc_timestamp = time.tv_sec;
18439742Smckusick 				ret = RC_REPLY;
18539742Smckusick 			} else {
18639742Smckusick 				nfsstats.srvcache_nonidemdonehits++;
18739742Smckusick 				rp->rc_state = RC_INPROG;
18839742Smckusick 				ret = RC_DOIT;
18939742Smckusick 			}
19039742Smckusick 			rp->rc_flag &= ~RC_LOCKED;
19139742Smckusick 			if (rp->rc_flag & RC_WANTED) {
19239742Smckusick 				rp->rc_flag &= ~RC_WANTED;
19339742Smckusick 				wakeup((caddr_t)rp);
19439742Smckusick 			}
19539742Smckusick 			return (ret);
19639742Smckusick 		}
19739742Smckusick 	}
19839742Smckusick 	nfsstats.srvcache_misses++;
19939742Smckusick 	rp = nfsrvcachehead.rc_prev;
20039742Smckusick 	while ((rp->rc_flag & RC_LOCKED) != 0) {
20139742Smckusick 		rp->rc_flag |= RC_WANTED;
20239742Smckusick 		sleep((caddr_t)rp, PZERO-1);
20339742Smckusick 	}
20439742Smckusick 	remque(rp);
20539742Smckusick 	put_at_head(rp);
20639742Smckusick 	if (rp->rc_flag & RC_REPMBUF)
20739742Smckusick 		mb = rp->rc_reply;
20839742Smckusick 	else
20939742Smckusick 		mb = (struct mbuf *)0;
21039742Smckusick 	rp->rc_flag = 0;
21139742Smckusick 	rp->rc_state = RC_INPROG;
21239742Smckusick 	rp->rc_xid = xid;
213*41901Smckusick 	bcopy((caddr_t)nam, (caddr_t)&rp->rc_nam, sizeof (struct mbuf));
21439742Smckusick 	rp->rc_proc = proc;
21539742Smckusick 	insque(rp, rh);
21639742Smckusick 	if (mb)
21739742Smckusick 		m_freem(mb);
21839742Smckusick 	return (RC_DOIT);
21939742Smckusick }
22039742Smckusick 
22139742Smckusick /*
22239742Smckusick  * Update a request cache entry after the rpc has been done
22339742Smckusick  */
22440253Smckusick nfsrv_updatecache(nam, xid, proc, repvalid, repstat, repmbuf)
22539742Smckusick 	struct mbuf *nam;
22639742Smckusick 	u_long xid;
22739742Smckusick 	int proc;
22840253Smckusick 	int repvalid;
22939742Smckusick 	int repstat;
23039742Smckusick 	struct mbuf *repmbuf;
23139742Smckusick {
23239742Smckusick 	register struct nfsrvcache *rp;
23339742Smckusick 	register union	rhead *rh;
23439742Smckusick 
23539742Smckusick 	rh = &rhead[NFSRCHASH(xid)];
23639742Smckusick loop:
23739742Smckusick 	for (rp = rh->rh_chain[0]; rp != (struct nfsrvcache *)rh; rp = rp->rc_forw) {
238*41901Smckusick 		if (xid == rp->rc_xid && proc == rp->rc_proc &&
239*41901Smckusick 		    nfs_netaddr_match(nam, &rp->rc_nam)) {
24039742Smckusick 			if ((rp->rc_flag & RC_LOCKED) != 0) {
24139742Smckusick 				rp->rc_flag |= RC_WANTED;
24239742Smckusick 				sleep((caddr_t)rp, PZERO-1);
24339742Smckusick 				goto loop;
24439742Smckusick 			}
24539742Smckusick 			rp->rc_flag |= RC_LOCKED;
24639742Smckusick 			rp->rc_state = RC_DONE;
24740253Smckusick 			/*
24840253Smckusick 			 * If we have a valid reply update status and save
249*41901Smckusick 			 * the reply for non-idempotent rpc's.
250*41901Smckusick 			 * Otherwise invalidate entry by setting the timestamp
251*41901Smckusick 			 * to nil.
25240253Smckusick 			 */
25340253Smckusick 			if (repvalid) {
25440253Smckusick 				rp->rc_timestamp = time.tv_sec;
25540253Smckusick 				if (nonidempotent[proc]) {
25640253Smckusick 					if (repliesstatus[proc]) {
25740253Smckusick 						rp->rc_status = repstat;
25840253Smckusick 						rp->rc_flag |= RC_REPSTATUS;
25940253Smckusick 					} else {
260*41901Smckusick 						rp->rc_reply = m_copym(repmbuf,
26140253Smckusick 							0, M_COPYALL, M_WAIT);
26240253Smckusick 						rp->rc_flag |= RC_REPMBUF;
26340253Smckusick 					}
26439742Smckusick 				}
26540253Smckusick 			} else {
26640253Smckusick 				rp->rc_timestamp = 0;
26739742Smckusick 			}
26839742Smckusick 			rp->rc_flag &= ~RC_LOCKED;
26939742Smckusick 			if (rp->rc_flag & RC_WANTED) {
27039742Smckusick 				rp->rc_flag &= ~RC_WANTED;
27139742Smckusick 				wakeup((caddr_t)rp);
27239742Smckusick 			}
27339742Smckusick 			return;
27439742Smckusick 		}
27539742Smckusick 	}
27639742Smckusick }
277