diff options
author | wpaul <wpaul@FreeBSD.org> | 1998-03-07 05:06:10 +0000 |
---|---|---|
committer | wpaul <wpaul@FreeBSD.org> | 1998-03-07 05:06:10 +0000 |
commit | b5a6d61144d61bee4a3f4e2af816065ad84fc974 (patch) | |
tree | 52fbfb312c63d6429cd611e7b24da83d478deff8 /lib/libc/yp | |
parent | a7987039c367704a1ecc2d84b9161863b0a63b85 (diff) | |
download | FreeBSD-src-b5a6d61144d61bee4a3f4e2af816065ad84fc974.zip FreeBSD-src-b5a6d61144d61bee4a3f4e2af816065ad84fc974.tar.gz |
Fix resource allocation problems:
- Completely recoded the ypmatch cache code. The old code could leak
memory: it would allow the cache to grow, but never
shrink. The new code imposes the following limits:
o The cache is capped at a limit of 5 entries.
o Each entry expires after five seconds, at which point
its slot is freed.
o If an insertion is to be done and all five slots
are filled, the oldest entry is forcibly expired
to release its slot.
Also, the cache is implemented on a per-binding basis rather than
having a global cache covering all bindings. This means that each
bound domain has its own 5 slot cache.
- Changed clntudp_create() to clntudp_bufcreate() so that the
xmit/recv message buffer sizes can be set explicitly. NIS transactions
are rarely much larger than 1024 bytes since YPMAXRECORD is 1024.
The defaults chosen by clntudb_create() are actually much larger
than needed. I set the xmit buffer to a little over 1024 and the
recv buffer to a little over 2048. This saves a few Kbytes for each
NIS binding.
- Add my name to the copyright. I think I've made enough changes to
this file to merit it. :)
Note: these changes should go into the 2.2.x branch, but I'm waiting
on feedback from a tester to see if the cache fixes solve the reported
memory leak problem.
Diffstat (limited to 'lib/libc/yp')
-rw-r--r-- | lib/libc/yp/yplib.c | 270 |
1 files changed, 176 insertions, 94 deletions
diff --git a/lib/libc/yp/yplib.c b/lib/libc/yp/yplib.c index 2e0223d..c464b1c 100644 --- a/lib/libc/yp/yplib.c +++ b/lib/libc/yp/yplib.c @@ -1,5 +1,6 @@ /* * Copyright (c) 1992/3 Theo de Raadt <deraadt@fsa.ca> + * Copyright (c) 1998 Bill Paul <wpaul@ctr.columbia.edu> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -28,7 +29,7 @@ */ #ifndef LINT -static char *rcsid = "$Id: yplib.c,v 1.28 1997/02/22 15:05:02 peter Exp $"; +static char *rcsid = "$Id: yplib.c,v 1.29 1997/04/10 20:26:04 wpaul Exp $"; #endif #include <sys/param.h> @@ -45,21 +46,38 @@ static char *rcsid = "$Id: yplib.c,v 1.28 1997/02/22 15:05:02 peter Exp $"; #include <rpc/xdr.h> #include <rpcsvc/yp.h> - /* * We have to define these here due to clashes between yp_prot.h and * yp.h. */ +#define YPMATCHCACHE + +#ifdef YPMATCHCACHE +struct ypmatch_ent { + char *ypc_map; + keydat ypc_key; + valdat ypc_val; + time_t ypc_expire_t; + struct ypmatch_ent *ypc_next; +}; +#define YPLIB_MAXCACHE 5 /* At most 5 entries */ +#define YPLIB_EXPIRE 5 /* Expire after 5 seconds */ +#endif + struct dom_binding { - struct dom_binding *dom_pnext; - char dom_domain[YPMAXDOMAIN + 1]; - struct sockaddr_in dom_server_addr; - u_short dom_server_port; - int dom_socket; - CLIENT *dom_client; - u_short dom_local_port; /* now I finally know what this is for. */ - long dom_vers; + struct dom_binding *dom_pnext; + char dom_domain[YPMAXDOMAIN + 1]; + struct sockaddr_in dom_server_addr; + u_short dom_server_port; + int dom_socket; + CLIENT *dom_client; + u_short dom_local_port; /* now I finally know what this is for. */ + long dom_vers; +#ifdef YPMATCHCACHE + struct ypmatch_ent *cache; + int ypmatch_cachecnt; +#endif }; #include <rpcsvc/ypclnt.h> @@ -67,7 +85,6 @@ struct dom_binding { #ifndef BINDINGDIR #define BINDINGDIR "/var/yp/binding" #endif -#define YPMATCHCACHE #define MAX_RETRIES 20 extern bool_t xdr_domainname(), xdr_ypbind_resp(); @@ -85,106 +102,163 @@ static char _yp_domain[MAXHOSTNAMELEN]; int _yplib_timeout = 10; #ifdef YPMATCHCACHE -int _yplib_cache = 5; +static void ypmatch_cache_delete(ypdb, prev, cur) + struct dom_binding *ypdb; + struct ypmatch_ent *prev; + struct ypmatch_ent *cur; +{ + if (prev == NULL) + ypdb->cache = cur->ypc_next; + else + prev->ypc_next = cur->ypc_next; -static struct ypmatch_ent { - struct ypmatch_ent *next; - char *map, *key, *val; - int keylen, vallen; - time_t expire_t; -} *ypmc; + free(cur->ypc_map); + free(cur->ypc_key.keydat_val); + free(cur->ypc_val.valdat_val); + free(cur); -static void -ypmatch_add(map, key, keylen, val, vallen) - char *map; - char *key; - int keylen; - char *val; - int vallen; + ypdb->ypmatch_cachecnt--; + + return; +} + +static void ypmatch_cache_flush(ypdb) + struct dom_binding *ypdb; { - struct ypmatch_ent *ep; - time_t t; + struct ypmatch_ent *n, *c = ypdb->cache; + + while (c != NULL) { + n = c->ypc_next; + ypmatch_cache_delete(ypdb, NULL, c); + c = n; + } + + return; +} + +static void ypmatch_cache_expire(ypdb) + struct dom_binding *ypdb; +{ + struct ypmatch_ent *c = ypdb->cache; + struct ypmatch_ent *n, *p = NULL; + time_t t; time(&t); - for(ep=ypmc; ep; ep=ep->next) - if(ep->expire_t < t) - break; - if(ep==NULL) { - ep = (struct ypmatch_ent *)malloc(sizeof *ep); - bzero((char *)ep, sizeof *ep); - if(ypmc) - ep->next = ypmc; - ypmc = ep; + while (c != NULL) { + if (t >= c->ypc_expire_t) { + n = c->ypc_next; + ypmatch_cache_delete(ypdb, p, c); + c = n; + } else { + p = c; + c = c->ypc_next; + } } - if(ep->key) - free(ep->key); - if(ep->val) - free(ep->val); + return; +} + +static void ypmatch_cache_insert(ypdb, map, key, val) + struct dom_binding *ypdb; + char *map; + keydat *key; + valdat *val; +{ + struct ypmatch_ent *new; + + /* Do an expire run to maybe open up a slot. */ + if (ypdb->ypmatch_cachecnt) + ypmatch_cache_expire(ypdb); + + /* + * If there are no slots free, then force an expire of + * the least recently used entry. + */ + if (ypdb->ypmatch_cachecnt >= YPLIB_MAXCACHE) { + struct ypmatch_ent *o = NULL, *c = ypdb->cache; + time_t oldest = 0; + + oldest = ~oldest; + + while(c != NULL) { + if (c->ypc_expire_t < oldest) { + oldest = c->ypc_expire_t; + o = c; + } + c = c->ypc_next; + } - ep->key = NULL; - ep->val = NULL; + if (o == NULL) + return; + o->ypc_expire_t = 0; + ypmatch_cache_expire(ypdb); + } - ep->key = (char *)malloc(keylen); - if(ep->key==NULL) + new = malloc(sizeof(struct ypmatch_ent)); + if (new == NULL) return; - ep->val = (char *)malloc(vallen); - if(ep->key==NULL) { - free(ep->key); - ep->key = NULL; + new->ypc_map = strdup(map); + if (new->ypc_map == NULL) { + free(new); + return; + } + new->ypc_key.keydat_val = malloc(key->keydat_len); + if (new->ypc_key.keydat_val == NULL) { + free(new->ypc_map); + free(new); + return; + } + new->ypc_val.valdat_val = malloc(val->valdat_len); + if (new->ypc_val.valdat_val == NULL) { + free(new->ypc_val.valdat_val); + free(new->ypc_map); + free(new); return; } - ep->keylen = keylen; - ep->vallen = vallen; - bcopy(key, ep->key, ep->keylen); - bcopy(val, ep->val, ep->vallen); + new->ypc_expire_t = time(NULL) + YPLIB_EXPIRE; + new->ypc_key.keydat_len = key->keydat_len; + new->ypc_val.valdat_len = val->valdat_len; + bcopy(key->keydat_val, new->ypc_key.keydat_val, key->keydat_len); + bcopy(val->valdat_val, new->ypc_val.valdat_val, val->valdat_len); - if(ep->map) { - if( strcmp(ep->map, map) ) { - free(ep->map); - ep->map = strdup(map); - } - } else { - ep->map = strdup(map); - } + new->ypc_next = ypdb->cache; + ypdb->cache = new; - ep->expire_t = t + _yplib_cache; + ypdb->ypmatch_cachecnt++; + + return; } -static bool_t -ypmatch_find(map, key, keylen, val, vallen) - char *map; - char *key; - int keylen; - char **val; - int *vallen; +static bool_t ypmatch_cache_lookup(ypdb, map, key, val) + struct dom_binding *ypdb; + char *map; + keydat *key; + valdat *val; { - struct ypmatch_ent *ep; - time_t t; + struct ypmatch_ent *c = ypdb->cache; - if(ypmc==NULL) - return 0; - - time(&t); + ypmatch_cache_expire(ypdb); - for(ep=ypmc; ep; ep=ep->next) { - if(ep->keylen != keylen) + for (c = ypdb->cache; c != NULL; c = c->ypc_next) { + if (strcmp(map, c->ypc_map)) continue; - if(strcmp(ep->map, map)) + if (key->keydat_len != c->ypc_key.keydat_len) continue; - if(bcmp(ep->key, key, keylen)) + if (bcmp(key->keydat_val, c->ypc_key.keydat_val, + key->keydat_len)) continue; - if(t > ep->expire_t) - continue; - - *val = ep->val; - *vallen = ep->vallen; - return 1; } - return 0; + + if (c == NULL) + return(FALSE); + + val->valdat_len = c->ypc_val.valdat_len; + val->valdat_val = c->ypc_val.valdat_val; + + return(TRUE); } #endif @@ -437,8 +511,8 @@ gotit: tv.tv_sec = _yplib_timeout/2; tv.tv_usec = 0; ysd->dom_socket = RPC_ANYSOCK; - ysd->dom_client = clntudp_create(&ysd->dom_server_addr, - YPPROG, YPVERS, tv, &ysd->dom_socket); + ysd->dom_client = clntudp_bufcreate(&ysd->dom_server_addr, + YPPROG, YPVERS, tv, &ysd->dom_socket, 1280, 2304); if(ysd->dom_client==NULL) { clnt_pcreateerror("clntudp_create"); ysd->dom_vers = -1; @@ -501,6 +575,9 @@ _yp_unbind(ypb) ypb->dom_client = NULL; ypb->dom_socket = -1; ypb->dom_vers = -1; +#ifdef YPMATCHCACHE + ypmatch_cache_flush(ypb); +#endif } int @@ -557,9 +634,20 @@ yp_match(indomain, inmap, inkey, inkeylen, outval, outvallen) indomain == NULL || !strlen(indomain)) return YPERR_BADARGS; + if (_yp_dobind(indomain, &ysd) != 0) + return(YPERR_DOMAIN); + + yprk.domain = indomain; + yprk.map = inmap; + yprk.key.keydat_val = (char *)inkey; + yprk.key.keydat_len = inkeylen; + #ifdef YPMATCHCACHE + if (ypmatch_cache_lookup(ysd, yprk.map, &yprk.key, &yprv.val) == TRUE) { +/* if( !strcmp(_yp_domain, indomain) && ypmatch_find(inmap, inkey, inkeylen, &yprv.val.valdat_val, &yprv.val.valdat_len)) { +*/ *outvallen = yprv.val.valdat_len; *outval = (char *)malloc(*outvallen+1); bcopy(yprv.val.valdat_val, *outval, *outvallen); @@ -575,11 +663,6 @@ again: tv.tv_sec = _yplib_timeout; tv.tv_usec = 0; - yprk.domain = indomain; - yprk.map = inmap; - yprk.key.keydat_val = (char *)inkey; - yprk.key.keydat_len = inkeylen; - bzero((char *)&yprv, sizeof yprv); r = clnt_call(ysd->dom_client, YPPROC_MATCH, @@ -596,8 +679,7 @@ again: bcopy(yprv.val.valdat_val, *outval, *outvallen); (*outval)[*outvallen] = '\0'; #ifdef YPMATCHCACHE - if( strcmp(_yp_domain, indomain)==0 ) - ypmatch_add(inmap, inkey, inkeylen, *outval, *outvallen); + ypmatch_cache_insert(ysd, yprk.map, &yprk.key, &yprv.val); #endif } |