xref: /csrg-svn/sys/nfs/nfs_srvcache.c (revision 39759)
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