Home | History | Annotate | Line # | Download | only in nfs
nfs_srvcache.c revision 1.7
      1  1.1      cgd /*
      2  1.7  mycroft  * Copyright (c) 1989, 1993
      3  1.7  mycroft  *	The Regents of the University of California.  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.7  mycroft  *	from: @(#)nfs_srvcache.c	8.1 (Berkeley) 6/10/93
     37  1.7  mycroft  *	$Id: nfs_srvcache.c,v 1.7 1994/06/08 11:36:59 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.7  mycroft  *		of an NFS Server", in Proc. Winter 1989 USENIX Conference,
     43  1.7  mycroft  *		pages 53-63. San Diego, February 1989.
     44  1.1      cgd  */
     45  1.6  mycroft #include <sys/param.h>
     46  1.6  mycroft #include <sys/vnode.h>
     47  1.6  mycroft #include <sys/mount.h>
     48  1.6  mycroft #include <sys/kernel.h>
     49  1.6  mycroft #include <sys/systm.h>
     50  1.7  mycroft #include <sys/proc.h>
     51  1.6  mycroft #include <sys/mbuf.h>
     52  1.7  mycroft #include <sys/malloc.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.7  mycroft #ifdef ISO
     58  1.7  mycroft #include <netiso/iso.h>
     59  1.7  mycroft #endif
     60  1.6  mycroft #include <nfs/nfsm_subs.h>
     61  1.7  mycroft #include <nfs/rpcv2.h>
     62  1.6  mycroft #include <nfs/nfsv2.h>
     63  1.7  mycroft #include <nfs/nfs.h>
     64  1.6  mycroft #include <nfs/nfsrvcache.h>
     65  1.7  mycroft #include <nfs/nqnfs.h>
     66  1.2    glass 
     67  1.7  mycroft long numnfsrvcache, desirednfsrvcache = NFSRVCACHESIZ;
     68  1.1      cgd 
     69  1.7  mycroft #define	NFSRCHASH(xid)		(((xid) + ((xid) >> 24)) & rheadhash)
     70  1.7  mycroft static struct nfsrvcache *nfsrvlruhead, **nfsrvlrutail = &nfsrvlruhead;
     71  1.7  mycroft static struct nfsrvcache **rheadhtbl;
     72  1.7  mycroft static u_long rheadhash;
     73  1.1      cgd 
     74  1.1      cgd #define TRUE	1
     75  1.1      cgd #define	FALSE	0
     76  1.1      cgd 
     77  1.7  mycroft #define	NETFAMILY(rp) \
     78  1.7  mycroft 		(((rp)->rc_flag & RC_INETADDR) ? AF_INET : AF_ISO)
     79  1.7  mycroft 
     80  1.7  mycroft /*
     81  1.7  mycroft  * Static array that defines which nfs rpc's are nonidempotent
     82  1.7  mycroft  */
     83  1.7  mycroft int nonidempotent[NFS_NPROCS] = {
     84  1.7  mycroft 	FALSE,
     85  1.7  mycroft 	FALSE,
     86  1.7  mycroft 	TRUE,
     87  1.7  mycroft 	FALSE,
     88  1.7  mycroft 	FALSE,
     89  1.7  mycroft 	FALSE,
     90  1.7  mycroft 	FALSE,
     91  1.7  mycroft 	FALSE,
     92  1.7  mycroft 	TRUE,
     93  1.7  mycroft 	TRUE,
     94  1.7  mycroft 	TRUE,
     95  1.7  mycroft 	TRUE,
     96  1.7  mycroft 	TRUE,
     97  1.7  mycroft 	TRUE,
     98  1.7  mycroft 	TRUE,
     99  1.7  mycroft 	TRUE,
    100  1.7  mycroft 	FALSE,
    101  1.7  mycroft 	FALSE,
    102  1.7  mycroft 	FALSE,
    103  1.7  mycroft 	FALSE,
    104  1.7  mycroft 	FALSE,
    105  1.7  mycroft 	FALSE,
    106  1.7  mycroft 	FALSE,
    107  1.7  mycroft };
    108  1.1      cgd 
    109  1.1      cgd /* True iff the rpc reply is an nfs status ONLY! */
    110  1.1      cgd static int repliesstatus[NFS_NPROCS] = {
    111  1.1      cgd 	FALSE,
    112  1.1      cgd 	FALSE,
    113  1.1      cgd 	FALSE,
    114  1.1      cgd 	FALSE,
    115  1.1      cgd 	FALSE,
    116  1.1      cgd 	FALSE,
    117  1.1      cgd 	FALSE,
    118  1.1      cgd 	FALSE,
    119  1.1      cgd 	FALSE,
    120  1.1      cgd 	FALSE,
    121  1.1      cgd 	TRUE,
    122  1.1      cgd 	TRUE,
    123  1.1      cgd 	TRUE,
    124  1.1      cgd 	TRUE,
    125  1.1      cgd 	FALSE,
    126  1.1      cgd 	TRUE,
    127  1.1      cgd 	FALSE,
    128  1.1      cgd 	FALSE,
    129  1.7  mycroft 	FALSE,
    130  1.7  mycroft 	FALSE,
    131  1.7  mycroft 	FALSE,
    132  1.7  mycroft 	FALSE,
    133  1.7  mycroft 	TRUE,
    134  1.1      cgd };
    135  1.1      cgd 
    136  1.1      cgd /*
    137  1.1      cgd  * Initialize the server request cache list
    138  1.1      cgd  */
    139  1.1      cgd nfsrv_initcache()
    140  1.1      cgd {
    141  1.7  mycroft 
    142  1.7  mycroft 	rheadhtbl = hashinit(desirednfsrvcache, M_NFSD, &rheadhash);
    143  1.1      cgd }
    144  1.1      cgd 
    145  1.1      cgd /*
    146  1.1      cgd  * Look for the request in the cache
    147  1.1      cgd  * If found then
    148  1.1      cgd  *    return action and optionally reply
    149  1.1      cgd  * else
    150  1.1      cgd  *    insert it in the cache
    151  1.1      cgd  *
    152  1.1      cgd  * The rules are as follows:
    153  1.1      cgd  * - if in progress, return DROP request
    154  1.1      cgd  * - if completed within DELAY of the current time, return DROP it
    155  1.1      cgd  * - if completed a longer time ago return REPLY if the reply was cached or
    156  1.1      cgd  *   return DOIT
    157  1.1      cgd  * Update/add new request at end of lru list
    158  1.1      cgd  */
    159  1.7  mycroft nfsrv_getcache(nam, nd, repp)
    160  1.1      cgd 	struct mbuf *nam;
    161  1.7  mycroft 	register struct nfsd *nd;
    162  1.1      cgd 	struct mbuf **repp;
    163  1.1      cgd {
    164  1.7  mycroft 	register struct nfsrvcache *rp, *rq, **rpp;
    165  1.1      cgd 	struct mbuf *mb;
    166  1.7  mycroft 	struct sockaddr_in *saddr;
    167  1.1      cgd 	caddr_t bpos;
    168  1.1      cgd 	int ret;
    169  1.1      cgd 
    170  1.7  mycroft 	if (nd->nd_nqlflag != NQL_NOVAL)
    171  1.7  mycroft 		return (RC_DOIT);
    172  1.7  mycroft 	rpp = &rheadhtbl[NFSRCHASH(nd->nd_retxid)];
    173  1.1      cgd loop:
    174  1.7  mycroft 	for (rp = *rpp; rp; rp = rp->rc_forw) {
    175  1.7  mycroft 	    if (nd->nd_retxid == rp->rc_xid && nd->nd_procnum == rp->rc_proc &&
    176  1.7  mycroft 		netaddr_match(NETFAMILY(rp), &rp->rc_haddr, nam)) {
    177  1.1      cgd 			if ((rp->rc_flag & RC_LOCKED) != 0) {
    178  1.1      cgd 				rp->rc_flag |= RC_WANTED;
    179  1.1      cgd 				(void) tsleep((caddr_t)rp, PZERO-1, "nfsrc", 0);
    180  1.1      cgd 				goto loop;
    181  1.1      cgd 			}
    182  1.1      cgd 			rp->rc_flag |= RC_LOCKED;
    183  1.7  mycroft 			/* If not at end of LRU chain, move it there */
    184  1.7  mycroft 			if (rp->rc_next) {
    185  1.7  mycroft 				/* remove from LRU chain */
    186  1.7  mycroft 				*rp->rc_prev = rp->rc_next;
    187  1.7  mycroft 				rp->rc_next->rc_prev = rp->rc_prev;
    188  1.7  mycroft 				/* and replace at end of it */
    189  1.7  mycroft 				rp->rc_next = NULL;
    190  1.7  mycroft 				rp->rc_prev = nfsrvlrutail;
    191  1.7  mycroft 				*nfsrvlrutail = rp;
    192  1.7  mycroft 				nfsrvlrutail = &rp->rc_next;
    193  1.7  mycroft 			}
    194  1.1      cgd 			if (rp->rc_state == RC_UNUSED)
    195  1.1      cgd 				panic("nfsrv cache");
    196  1.7  mycroft 			if (rp->rc_state == RC_INPROG) {
    197  1.1      cgd 				nfsstats.srvcache_inproghits++;
    198  1.1      cgd 				ret = RC_DROPIT;
    199  1.1      cgd 			} else if (rp->rc_flag & RC_REPSTATUS) {
    200  1.7  mycroft 				nfsstats.srvcache_nonidemdonehits++;
    201  1.7  mycroft 				nfs_rephead(0, nd, rp->rc_status,
    202  1.7  mycroft 				   0, (u_quad_t *)0, repp, &mb, &bpos);
    203  1.1      cgd 				ret = RC_REPLY;
    204  1.1      cgd 			} else if (rp->rc_flag & RC_REPMBUF) {
    205  1.7  mycroft 				nfsstats.srvcache_nonidemdonehits++;
    206  1.1      cgd 				*repp = m_copym(rp->rc_reply, 0, M_COPYALL,
    207  1.1      cgd 						M_WAIT);
    208  1.1      cgd 				ret = RC_REPLY;
    209  1.1      cgd 			} else {
    210  1.7  mycroft 				nfsstats.srvcache_idemdonehits++;
    211  1.1      cgd 				rp->rc_state = RC_INPROG;
    212  1.1      cgd 				ret = RC_DOIT;
    213  1.1      cgd 			}
    214  1.1      cgd 			rp->rc_flag &= ~RC_LOCKED;
    215  1.1      cgd 			if (rp->rc_flag & RC_WANTED) {
    216  1.1      cgd 				rp->rc_flag &= ~RC_WANTED;
    217  1.1      cgd 				wakeup((caddr_t)rp);
    218  1.1      cgd 			}
    219  1.1      cgd 			return (ret);
    220  1.1      cgd 		}
    221  1.1      cgd 	}
    222  1.1      cgd 	nfsstats.srvcache_misses++;
    223  1.7  mycroft 	if (numnfsrvcache < desirednfsrvcache) {
    224  1.7  mycroft 		rp = (struct nfsrvcache *)malloc((u_long)sizeof *rp,
    225  1.7  mycroft 		    M_NFSD, M_WAITOK);
    226  1.7  mycroft 		bzero((char *)rp, sizeof *rp);
    227  1.7  mycroft 		numnfsrvcache++;
    228  1.7  mycroft 		rp->rc_flag = RC_LOCKED;
    229  1.7  mycroft 	} else {
    230  1.7  mycroft 		rp = nfsrvlruhead;
    231  1.7  mycroft 		while ((rp->rc_flag & RC_LOCKED) != 0) {
    232  1.7  mycroft 			rp->rc_flag |= RC_WANTED;
    233  1.7  mycroft 			(void) tsleep((caddr_t)rp, PZERO-1, "nfsrc", 0);
    234  1.7  mycroft 			rp = nfsrvlruhead;
    235  1.7  mycroft 		}
    236  1.7  mycroft 		rp->rc_flag |= RC_LOCKED;
    237  1.7  mycroft 		/* remove from hash chain */
    238  1.7  mycroft 		if (rq = rp->rc_forw)
    239  1.7  mycroft 			rq->rc_back = rp->rc_back;
    240  1.7  mycroft 		*rp->rc_back = rq;
    241  1.7  mycroft 		/* remove from LRU chain */
    242  1.7  mycroft 		*rp->rc_prev = rp->rc_next;
    243  1.7  mycroft 		rp->rc_next->rc_prev = rp->rc_prev;
    244  1.7  mycroft 		if (rp->rc_flag & RC_REPMBUF)
    245  1.7  mycroft 			m_freem(rp->rc_reply);
    246  1.7  mycroft 		if (rp->rc_flag & RC_NAM)
    247  1.7  mycroft 			MFREE(rp->rc_nam, mb);
    248  1.7  mycroft 		rp->rc_flag &= (RC_LOCKED | RC_WANTED);
    249  1.1      cgd 	}
    250  1.7  mycroft 	/* place at end of LRU list */
    251  1.7  mycroft 	rp->rc_next = NULL;
    252  1.7  mycroft 	rp->rc_prev = nfsrvlrutail;
    253  1.7  mycroft 	*nfsrvlrutail = rp;
    254  1.7  mycroft 	nfsrvlrutail = &rp->rc_next;
    255  1.1      cgd 	rp->rc_state = RC_INPROG;
    256  1.7  mycroft 	rp->rc_xid = nd->nd_retxid;
    257  1.7  mycroft 	saddr = mtod(nam, struct sockaddr_in *);
    258  1.7  mycroft 	switch (saddr->sin_family) {
    259  1.7  mycroft 	case AF_INET:
    260  1.7  mycroft 		rp->rc_flag |= RC_INETADDR;
    261  1.7  mycroft 		rp->rc_inetaddr = saddr->sin_addr.s_addr;
    262  1.7  mycroft 		break;
    263  1.7  mycroft 	case AF_ISO:
    264  1.7  mycroft 	default:
    265  1.7  mycroft 		rp->rc_flag |= RC_NAM;
    266  1.7  mycroft 		rp->rc_nam = m_copym(nam, 0, M_COPYALL, M_WAIT);
    267  1.7  mycroft 		break;
    268  1.7  mycroft 	};
    269  1.7  mycroft 	rp->rc_proc = nd->nd_procnum;
    270  1.7  mycroft 	/* insert into hash chain */
    271  1.7  mycroft 	if (rq = *rpp)
    272  1.7  mycroft 		rq->rc_back = &rp->rc_forw;
    273  1.7  mycroft 	rp->rc_forw = rq;
    274  1.7  mycroft 	rp->rc_back = rpp;
    275  1.7  mycroft 	*rpp = rp;
    276  1.7  mycroft 	rp->rc_flag &= ~RC_LOCKED;
    277  1.7  mycroft 	if (rp->rc_flag & RC_WANTED) {
    278  1.7  mycroft 		rp->rc_flag &= ~RC_WANTED;
    279  1.7  mycroft 		wakeup((caddr_t)rp);
    280  1.7  mycroft 	}
    281  1.1      cgd 	return (RC_DOIT);
    282  1.1      cgd }
    283  1.1      cgd 
    284  1.1      cgd /*
    285  1.1      cgd  * Update a request cache entry after the rpc has been done
    286  1.1      cgd  */
    287  1.7  mycroft void
    288  1.7  mycroft nfsrv_updatecache(nam, nd, repvalid, repmbuf)
    289  1.1      cgd 	struct mbuf *nam;
    290  1.7  mycroft 	register struct nfsd *nd;
    291  1.1      cgd 	int repvalid;
    292  1.1      cgd 	struct mbuf *repmbuf;
    293  1.1      cgd {
    294  1.1      cgd 	register struct nfsrvcache *rp;
    295  1.1      cgd 
    296  1.7  mycroft 	if (nd->nd_nqlflag != NQL_NOVAL)
    297  1.7  mycroft 		return;
    298  1.1      cgd loop:
    299  1.7  mycroft 	for (rp = rheadhtbl[NFSRCHASH(nd->nd_retxid)]; rp; rp = rp->rc_forw) {
    300  1.7  mycroft 	    if (nd->nd_retxid == rp->rc_xid && nd->nd_procnum == rp->rc_proc &&
    301  1.7  mycroft 		netaddr_match(NETFAMILY(rp), &rp->rc_haddr, nam)) {
    302  1.1      cgd 			if ((rp->rc_flag & RC_LOCKED) != 0) {
    303  1.1      cgd 				rp->rc_flag |= RC_WANTED;
    304  1.1      cgd 				(void) tsleep((caddr_t)rp, PZERO-1, "nfsrc", 0);
    305  1.1      cgd 				goto loop;
    306  1.1      cgd 			}
    307  1.1      cgd 			rp->rc_flag |= RC_LOCKED;
    308  1.1      cgd 			rp->rc_state = RC_DONE;
    309  1.1      cgd 			/*
    310  1.1      cgd 			 * If we have a valid reply update status and save
    311  1.1      cgd 			 * the reply for non-idempotent rpc's.
    312  1.1      cgd 			 */
    313  1.7  mycroft 			if (repvalid && nonidempotent[nd->nd_procnum]) {
    314  1.7  mycroft 				if (repliesstatus[nd->nd_procnum]) {
    315  1.7  mycroft 					rp->rc_status = nd->nd_repstat;
    316  1.7  mycroft 					rp->rc_flag |= RC_REPSTATUS;
    317  1.7  mycroft 				} else {
    318  1.7  mycroft 					rp->rc_reply = m_copym(repmbuf,
    319  1.7  mycroft 						0, M_COPYALL, M_WAIT);
    320  1.7  mycroft 					rp->rc_flag |= RC_REPMBUF;
    321  1.1      cgd 				}
    322  1.1      cgd 			}
    323  1.1      cgd 			rp->rc_flag &= ~RC_LOCKED;
    324  1.1      cgd 			if (rp->rc_flag & RC_WANTED) {
    325  1.1      cgd 				rp->rc_flag &= ~RC_WANTED;
    326  1.1      cgd 				wakeup((caddr_t)rp);
    327  1.1      cgd 			}
    328  1.1      cgd 			return;
    329  1.1      cgd 		}
    330  1.1      cgd 	}
    331  1.7  mycroft }
    332  1.7  mycroft 
    333  1.7  mycroft /*
    334  1.7  mycroft  * Clean out the cache. Called when the last nfsd terminates.
    335  1.7  mycroft  */
    336  1.7  mycroft void
    337  1.7  mycroft nfsrv_cleancache()
    338  1.7  mycroft {
    339  1.7  mycroft 	register struct nfsrvcache *rp, *nextrp;
    340  1.7  mycroft 
    341  1.7  mycroft 	for (rp = nfsrvlruhead; rp; rp = nextrp) {
    342  1.7  mycroft 		nextrp = rp->rc_next;
    343  1.7  mycroft 		free(rp, M_NFSD);
    344  1.7  mycroft 	}
    345  1.7  mycroft 	bzero((char *)rheadhtbl, (rheadhash + 1) * sizeof(void *));
    346  1.7  mycroft 	nfsrvlruhead = NULL;
    347  1.7  mycroft 	nfsrvlrutail = &nfsrvlruhead;
    348  1.7  mycroft 	numnfsrvcache = 0;
    349  1.1      cgd }
    350