Home | History | Annotate | Line # | Download | only in nfs
nfs_srvcache.c revision 1.6
      1  1.1      cgd /*
      2  1.1      cgd  * Copyright (c) 1989 The Regents of the University of California.
      3  1.1      cgd  * All rights reserved.
      4  1.1      cgd  *
      5  1.1      cgd  * This code is derived from software contributed to Berkeley by
      6  1.1      cgd  * Rick Macklem at The University of Guelph.
      7  1.1      cgd  *
      8  1.1      cgd  * Redistribution and use in source and binary forms, with or without
      9  1.1      cgd  * modification, are permitted provided that the following conditions
     10  1.1      cgd  * are met:
     11  1.1      cgd  * 1. Redistributions of source code must retain the above copyright
     12  1.1      cgd  *    notice, this list of conditions and the following disclaimer.
     13  1.1      cgd  * 2. Redistributions in binary form must reproduce the above copyright
     14  1.1      cgd  *    notice, this list of conditions and the following disclaimer in the
     15  1.1      cgd  *    documentation and/or other materials provided with the distribution.
     16  1.1      cgd  * 3. All advertising materials mentioning features or use of this software
     17  1.1      cgd  *    must display the following acknowledgement:
     18  1.1      cgd  *	This product includes software developed by the University of
     19  1.1      cgd  *	California, Berkeley and its contributors.
     20  1.1      cgd  * 4. Neither the name of the University nor the names of its contributors
     21  1.1      cgd  *    may be used to endorse or promote products derived from this software
     22  1.1      cgd  *    without specific prior written permission.
     23  1.1      cgd  *
     24  1.1      cgd  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     25  1.1      cgd  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     26  1.1      cgd  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     27  1.1      cgd  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     28  1.1      cgd  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     29  1.1      cgd  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     30  1.1      cgd  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     31  1.1      cgd  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     32  1.1      cgd  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     33  1.1      cgd  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     34  1.1      cgd  * SUCH DAMAGE.
     35  1.1      cgd  *
     36  1.3      cgd  *	from: @(#)nfs_srvcache.c	7.11 (Berkeley) 4/16/91
     37  1.6  mycroft  *	$Id: nfs_srvcache.c,v 1.6 1993/12/18 00:45:20 mycroft Exp $
     38  1.1      cgd  */
     39  1.1      cgd 
     40  1.1      cgd /*
     41  1.1      cgd  * Reference: Chet Juszczak, "Improving the Performance and Correctness
     42  1.1      cgd  *            of an NFS Server", in Proc. Winter 1989 USENIX Conference,
     43  1.1      cgd  *            pages 53-63. San Diego, February 1989.
     44  1.1      cgd  */
     45  1.1      cgd 
     46  1.6  mycroft #include <sys/param.h>
     47  1.6  mycroft #include <sys/namei.h>
     48  1.6  mycroft #include <sys/vnode.h>
     49  1.6  mycroft #include <sys/mount.h>
     50  1.6  mycroft #include <sys/kernel.h>
     51  1.6  mycroft #include <sys/systm.h>
     52  1.6  mycroft #include <sys/mbuf.h>
     53  1.6  mycroft #include <sys/socket.h>
     54  1.6  mycroft #include <sys/socketvar.h>
     55  1.1      cgd 
     56  1.6  mycroft #include <netinet/in.h>
     57  1.1      cgd 
     58  1.6  mycroft #include <nfs/nfsm_subs.h>
     59  1.6  mycroft #include <nfs/nfsv2.h>
     60  1.6  mycroft #include <nfs/nfsrvcache.h>
     61  1.6  mycroft #include <nfs/nfs.h>
     62  1.1      cgd 
     63  1.1      cgd #if	((NFSRCHSZ&(NFSRCHSZ-1)) == 0)
     64  1.1      cgd #define	NFSRCHASH(xid)		(((xid)+((xid)>>16))&(NFSRCHSZ-1))
     65  1.1      cgd #else
     66  1.1      cgd #define	NFSRCHASH(xid)		(((unsigned)((xid)+((xid)>>16)))%NFSRCHSZ)
     67  1.1      cgd #endif
     68  1.1      cgd 
     69  1.2    glass extern int nonidempotent[NFS_NPROCS];
     70  1.2    glass 
     71  1.1      cgd union rhead {
     72  1.1      cgd 	union  rhead *rh_head[2];
     73  1.1      cgd 	struct nfsrvcache *rh_chain[2];
     74  1.1      cgd } rhead[NFSRCHSZ];
     75  1.1      cgd 
     76  1.1      cgd static struct nfsrvcache nfsrvcachehead;
     77  1.1      cgd static struct nfsrvcache nfsrvcache[NFSRVCACHESIZ];
     78  1.1      cgd 
     79  1.1      cgd #define TRUE	1
     80  1.1      cgd #define	FALSE	0
     81  1.1      cgd 
     82  1.1      cgd 
     83  1.1      cgd /* True iff the rpc reply is an nfs status ONLY! */
     84  1.1      cgd static int repliesstatus[NFS_NPROCS] = {
     85  1.1      cgd 	FALSE,
     86  1.1      cgd 	FALSE,
     87  1.1      cgd 	FALSE,
     88  1.1      cgd 	FALSE,
     89  1.1      cgd 	FALSE,
     90  1.1      cgd 	FALSE,
     91  1.1      cgd 	FALSE,
     92  1.1      cgd 	FALSE,
     93  1.1      cgd 	FALSE,
     94  1.1      cgd 	FALSE,
     95  1.1      cgd 	TRUE,
     96  1.1      cgd 	TRUE,
     97  1.1      cgd 	TRUE,
     98  1.1      cgd 	TRUE,
     99  1.1      cgd 	FALSE,
    100  1.1      cgd 	TRUE,
    101  1.1      cgd 	FALSE,
    102  1.1      cgd 	FALSE,
    103  1.1      cgd };
    104  1.1      cgd 
    105  1.1      cgd /*
    106  1.1      cgd  * Initialize the server request cache list
    107  1.1      cgd  */
    108  1.1      cgd nfsrv_initcache()
    109  1.1      cgd {
    110  1.1      cgd 	register int i;
    111  1.1      cgd 	register struct nfsrvcache *rp = nfsrvcache;
    112  1.1      cgd 	register struct nfsrvcache *hp = &nfsrvcachehead;
    113  1.1      cgd 	register union  rhead *rh = rhead;
    114  1.1      cgd 
    115  1.1      cgd 	for (i = NFSRCHSZ; --i >= 0; rh++) {
    116  1.1      cgd 		rh->rh_head[0] = rh;
    117  1.1      cgd 		rh->rh_head[1] = rh;
    118  1.1      cgd 	}
    119  1.1      cgd 	hp->rc_next = hp->rc_prev = hp;
    120  1.1      cgd 	for (i = NFSRVCACHESIZ; i-- > 0; ) {
    121  1.1      cgd 		rp->rc_state = RC_UNUSED;
    122  1.1      cgd 		rp->rc_flag = 0;
    123  1.1      cgd 		rp->rc_forw = rp;
    124  1.1      cgd 		rp->rc_back = rp;
    125  1.1      cgd 		rp->rc_next = hp->rc_next;
    126  1.1      cgd 		hp->rc_next->rc_prev = rp;
    127  1.1      cgd 		rp->rc_prev = hp;
    128  1.1      cgd 		hp->rc_next = rp;
    129  1.1      cgd 		rp++;
    130  1.1      cgd 	}
    131  1.1      cgd }
    132  1.1      cgd 
    133  1.1      cgd /*
    134  1.1      cgd  * Look for the request in the cache
    135  1.1      cgd  * If found then
    136  1.1      cgd  *    return action and optionally reply
    137  1.1      cgd  * else
    138  1.1      cgd  *    insert it in the cache
    139  1.1      cgd  *
    140  1.1      cgd  * The rules are as follows:
    141  1.1      cgd  * - if in progress, return DROP request
    142  1.1      cgd  * - if completed within DELAY of the current time, return DROP it
    143  1.1      cgd  * - if completed a longer time ago return REPLY if the reply was cached or
    144  1.1      cgd  *   return DOIT
    145  1.1      cgd  * Update/add new request at end of lru list
    146  1.1      cgd  */
    147  1.1      cgd nfsrv_getcache(nam, xid, proc, repp)
    148  1.1      cgd 	struct mbuf *nam;
    149  1.1      cgd 	u_long xid;
    150  1.1      cgd 	int proc;
    151  1.1      cgd 	struct mbuf **repp;
    152  1.1      cgd {
    153  1.1      cgd 	register struct nfsrvcache *rp;
    154  1.1      cgd 	register union  rhead *rh;
    155  1.1      cgd 	struct mbuf *mb;
    156  1.1      cgd 	caddr_t bpos;
    157  1.1      cgd 	int ret;
    158  1.1      cgd 
    159  1.1      cgd 	rh = &rhead[NFSRCHASH(xid)];
    160  1.1      cgd loop:
    161  1.1      cgd 	for (rp = rh->rh_chain[0]; rp != (struct nfsrvcache *)rh; rp = rp->rc_forw) {
    162  1.1      cgd 		if (xid == rp->rc_xid && proc == rp->rc_proc &&
    163  1.1      cgd 		    nfs_netaddr_match(nam, &rp->rc_nam)) {
    164  1.1      cgd 			if ((rp->rc_flag & RC_LOCKED) != 0) {
    165  1.1      cgd 				rp->rc_flag |= RC_WANTED;
    166  1.1      cgd 				(void) tsleep((caddr_t)rp, PZERO-1, "nfsrc", 0);
    167  1.1      cgd 				goto loop;
    168  1.1      cgd 			}
    169  1.1      cgd 			rp->rc_flag |= RC_LOCKED;
    170  1.1      cgd 			put_at_head(rp);
    171  1.1      cgd 			if (rp->rc_state == RC_UNUSED)
    172  1.1      cgd 				panic("nfsrv cache");
    173  1.1      cgd 			if (rp->rc_state == RC_INPROG ||
    174  1.1      cgd 			   (time.tv_sec - rp->rc_timestamp) < RC_DELAY) {
    175  1.1      cgd 				nfsstats.srvcache_inproghits++;
    176  1.1      cgd 				ret = RC_DROPIT;
    177  1.1      cgd 			} else if (rp->rc_flag & RC_REPSTATUS) {
    178  1.1      cgd 				nfsstats.srvcache_idemdonehits++;
    179  1.1      cgd 				nfs_rephead(0, xid, rp->rc_status, repp, &mb,
    180  1.1      cgd 					&bpos);
    181  1.1      cgd 				rp->rc_timestamp = time.tv_sec;
    182  1.1      cgd 				ret = RC_REPLY;
    183  1.1      cgd 			} else if (rp->rc_flag & RC_REPMBUF) {
    184  1.1      cgd 				nfsstats.srvcache_idemdonehits++;
    185  1.1      cgd 				*repp = m_copym(rp->rc_reply, 0, M_COPYALL,
    186  1.1      cgd 						M_WAIT);
    187  1.1      cgd 				rp->rc_timestamp = time.tv_sec;
    188  1.1      cgd 				ret = RC_REPLY;
    189  1.1      cgd 			} else {
    190  1.1      cgd 				nfsstats.srvcache_nonidemdonehits++;
    191  1.1      cgd 				rp->rc_state = RC_INPROG;
    192  1.1      cgd 				ret = RC_DOIT;
    193  1.1      cgd 			}
    194  1.1      cgd 			rp->rc_flag &= ~RC_LOCKED;
    195  1.1      cgd 			if (rp->rc_flag & RC_WANTED) {
    196  1.1      cgd 				rp->rc_flag &= ~RC_WANTED;
    197  1.1      cgd 				wakeup((caddr_t)rp);
    198  1.1      cgd 			}
    199  1.1      cgd 			return (ret);
    200  1.1      cgd 		}
    201  1.1      cgd 	}
    202  1.1      cgd 	nfsstats.srvcache_misses++;
    203  1.1      cgd 	rp = nfsrvcachehead.rc_prev;
    204  1.1      cgd 	while ((rp->rc_flag & RC_LOCKED) != 0) {
    205  1.1      cgd 		rp->rc_flag |= RC_WANTED;
    206  1.1      cgd 		(void) tsleep((caddr_t)rp, PZERO-1, "nfsrc", 0);
    207  1.1      cgd 	}
    208  1.1      cgd 	remque(rp);
    209  1.1      cgd 	put_at_head(rp);
    210  1.1      cgd 	if (rp->rc_flag & RC_REPMBUF)
    211  1.1      cgd 		mb = rp->rc_reply;
    212  1.1      cgd 	else
    213  1.1      cgd 		mb = (struct mbuf *)0;
    214  1.1      cgd 	rp->rc_flag = 0;
    215  1.1      cgd 	rp->rc_state = RC_INPROG;
    216  1.1      cgd 	rp->rc_xid = xid;
    217  1.1      cgd 	bcopy((caddr_t)nam, (caddr_t)&rp->rc_nam, sizeof (struct mbuf));
    218  1.5       ws 	rp->rc_nam.m_data = rp->rc_nam.m_dat; /* for now; hopefully correct? certainly better */
    219  1.1      cgd 	rp->rc_proc = proc;
    220  1.1      cgd 	insque(rp, rh);
    221  1.1      cgd 	if (mb)
    222  1.1      cgd 		m_freem(mb);
    223  1.1      cgd 	return (RC_DOIT);
    224  1.1      cgd }
    225  1.1      cgd 
    226  1.1      cgd /*
    227  1.1      cgd  * Update a request cache entry after the rpc has been done
    228  1.1      cgd  */
    229  1.1      cgd nfsrv_updatecache(nam, xid, proc, repvalid, repstat, repmbuf)
    230  1.1      cgd 	struct mbuf *nam;
    231  1.1      cgd 	u_long xid;
    232  1.1      cgd 	int proc;
    233  1.1      cgd 	int repvalid;
    234  1.1      cgd 	int repstat;
    235  1.1      cgd 	struct mbuf *repmbuf;
    236  1.1      cgd {
    237  1.1      cgd 	register struct nfsrvcache *rp;
    238  1.1      cgd 	register union	rhead *rh;
    239  1.1      cgd 
    240  1.1      cgd 	rh = &rhead[NFSRCHASH(xid)];
    241  1.1      cgd loop:
    242  1.1      cgd 	for (rp = rh->rh_chain[0]; rp != (struct nfsrvcache *)rh; rp = rp->rc_forw) {
    243  1.1      cgd 		if (xid == rp->rc_xid && proc == rp->rc_proc &&
    244  1.1      cgd 		    nfs_netaddr_match(nam, &rp->rc_nam)) {
    245  1.1      cgd 			if ((rp->rc_flag & RC_LOCKED) != 0) {
    246  1.1      cgd 				rp->rc_flag |= RC_WANTED;
    247  1.1      cgd 				(void) tsleep((caddr_t)rp, PZERO-1, "nfsrc", 0);
    248  1.1      cgd 				goto loop;
    249  1.1      cgd 			}
    250  1.1      cgd 			rp->rc_flag |= RC_LOCKED;
    251  1.1      cgd 			rp->rc_state = RC_DONE;
    252  1.1      cgd 			/*
    253  1.1      cgd 			 * If we have a valid reply update status and save
    254  1.1      cgd 			 * the reply for non-idempotent rpc's.
    255  1.1      cgd 			 * Otherwise invalidate entry by setting the timestamp
    256  1.1      cgd 			 * to nil.
    257  1.1      cgd 			 */
    258  1.1      cgd 			if (repvalid) {
    259  1.1      cgd 				rp->rc_timestamp = time.tv_sec;
    260  1.1      cgd 				if (nonidempotent[proc]) {
    261  1.1      cgd 					if (repliesstatus[proc]) {
    262  1.1      cgd 						rp->rc_status = repstat;
    263  1.1      cgd 						rp->rc_flag |= RC_REPSTATUS;
    264  1.1      cgd 					} else {
    265  1.1      cgd 						rp->rc_reply = m_copym(repmbuf,
    266  1.1      cgd 							0, M_COPYALL, M_WAIT);
    267  1.1      cgd 						rp->rc_flag |= RC_REPMBUF;
    268  1.1      cgd 					}
    269  1.1      cgd 				}
    270  1.1      cgd 			} else {
    271  1.1      cgd 				rp->rc_timestamp = 0;
    272  1.1      cgd 			}
    273  1.1      cgd 			rp->rc_flag &= ~RC_LOCKED;
    274  1.1      cgd 			if (rp->rc_flag & RC_WANTED) {
    275  1.1      cgd 				rp->rc_flag &= ~RC_WANTED;
    276  1.1      cgd 				wakeup((caddr_t)rp);
    277  1.1      cgd 			}
    278  1.1      cgd 			return;
    279  1.1      cgd 		}
    280  1.1      cgd 	}
    281  1.1      cgd }
    282