mirror of
https://gitlab.isc.org/isc-projects/bind9
synced 2025-08-31 06:25:31 +00:00
3053. [bug] Under a sustained high query load with a finite
max-cache-size, it was possible for cache memory to be exhausted and not recovered. [RT #23371]
This commit is contained in:
@@ -15,7 +15,7 @@
|
||||
* PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/* $Id: cache.c,v 1.87 2009/11/12 23:43:02 each Exp $ */
|
||||
/* $Id: cache.c,v 1.88 2011/03/03 04:42:25 each Exp $ */
|
||||
|
||||
/*! \file */
|
||||
|
||||
@@ -40,6 +40,8 @@
|
||||
#include <dns/rdatasetiter.h>
|
||||
#include <dns/result.h>
|
||||
|
||||
#include "rbtdb.h"
|
||||
|
||||
#define CACHE_MAGIC ISC_MAGIC('$', '$', '$', '$')
|
||||
#define VALID_CACHE(cache) ISC_MAGIC_VALID(cache, CACHE_MAGIC)
|
||||
|
||||
@@ -121,7 +123,8 @@ struct dns_cache {
|
||||
unsigned int magic;
|
||||
isc_mutex_t lock;
|
||||
isc_mutex_t filelock;
|
||||
isc_mem_t *mctx;
|
||||
isc_mem_t *mctx; /* Main cache memory */
|
||||
isc_mem_t *hmctx; /* Heap memory */
|
||||
char *name;
|
||||
|
||||
/* Locked by 'lock'. */
|
||||
@@ -168,41 +171,54 @@ cache_create_db(dns_cache_t *cache, dns_db_t **db) {
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
dns_cache_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr,
|
||||
dns_cache_create(isc_mem_t *cmctx, isc_taskmgr_t *taskmgr,
|
||||
isc_timermgr_t *timermgr, dns_rdataclass_t rdclass,
|
||||
const char *db_type, unsigned int db_argc, char **db_argv,
|
||||
dns_cache_t **cachep)
|
||||
{
|
||||
return (dns_cache_create2(mctx, taskmgr, timermgr, rdclass, "",
|
||||
return (dns_cache_create3(cmctx, cmctx, taskmgr, timermgr, rdclass, "",
|
||||
db_type, db_argc, db_argv, cachep));
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
dns_cache_create2(isc_mem_t *mctx, isc_taskmgr_t *taskmgr,
|
||||
dns_cache_create2(isc_mem_t *cmctx, isc_taskmgr_t *taskmgr,
|
||||
isc_timermgr_t *timermgr, dns_rdataclass_t rdclass,
|
||||
const char *cachename, const char *db_type,
|
||||
unsigned int db_argc, char **db_argv, dns_cache_t **cachep)
|
||||
{
|
||||
return (dns_cache_create3(cmctx, cmctx, taskmgr, timermgr, rdclass,
|
||||
cachename, db_type, db_argc, db_argv,
|
||||
cachep));
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
dns_cache_create3(isc_mem_t *cmctx, isc_mem_t *hmctx, isc_taskmgr_t *taskmgr,
|
||||
isc_timermgr_t *timermgr, dns_rdataclass_t rdclass,
|
||||
const char *cachename, const char *db_type,
|
||||
unsigned int db_argc, char **db_argv, dns_cache_t **cachep)
|
||||
{
|
||||
isc_result_t result;
|
||||
dns_cache_t *cache;
|
||||
int i;
|
||||
int i, extra = 0;
|
||||
isc_task_t *dbtask;
|
||||
|
||||
REQUIRE(cachep != NULL);
|
||||
REQUIRE(*cachep == NULL);
|
||||
REQUIRE(mctx != NULL);
|
||||
REQUIRE(cmctx != NULL);
|
||||
REQUIRE(hmctx != NULL);
|
||||
REQUIRE(cachename != NULL);
|
||||
|
||||
cache = isc_mem_get(mctx, sizeof(*cache));
|
||||
cache = isc_mem_get(cmctx, sizeof(*cache));
|
||||
if (cache == NULL)
|
||||
return (ISC_R_NOMEMORY);
|
||||
|
||||
cache->mctx = NULL;
|
||||
isc_mem_attach(mctx, &cache->mctx);
|
||||
cache->mctx = cache->hmctx = NULL;
|
||||
isc_mem_attach(cmctx, &cache->mctx);
|
||||
isc_mem_attach(hmctx, &cache->hmctx);
|
||||
|
||||
cache->name = NULL;
|
||||
if (cachename != NULL) {
|
||||
cache->name = isc_mem_strdup(mctx, cachename);
|
||||
cache->name = isc_mem_strdup(cmctx, cachename);
|
||||
if (cache->name == NULL) {
|
||||
result = ISC_R_NOMEMORY;
|
||||
goto cleanup_mem;
|
||||
@@ -221,26 +237,38 @@ dns_cache_create2(isc_mem_t *mctx, isc_taskmgr_t *taskmgr,
|
||||
cache->live_tasks = 0;
|
||||
cache->rdclass = rdclass;
|
||||
|
||||
cache->db_type = isc_mem_strdup(mctx, db_type);
|
||||
cache->db_type = isc_mem_strdup(cmctx, db_type);
|
||||
if (cache->db_type == NULL) {
|
||||
result = ISC_R_NOMEMORY;
|
||||
goto cleanup_filelock;
|
||||
}
|
||||
|
||||
cache->db_argc = db_argc;
|
||||
if (cache->db_argc == 0)
|
||||
cache->db_argv = NULL;
|
||||
else {
|
||||
cache->db_argv = isc_mem_get(mctx,
|
||||
/*
|
||||
* For databases of type "rbt" we pass hmctx to dns_db_create()
|
||||
* via cache->db_argv, followed by the rest of the arguments in
|
||||
* db_argv (of which there really shouldn't be any).
|
||||
*/
|
||||
if (strcmp(cache->db_type, "rbt") == 0)
|
||||
extra = 1;
|
||||
|
||||
cache->db_argc = db_argc + extra;
|
||||
cache->db_argv = NULL;
|
||||
|
||||
if (cache->db_argc != 0) {
|
||||
cache->db_argv = isc_mem_get(cmctx,
|
||||
cache->db_argc * sizeof(char *));
|
||||
if (cache->db_argv == NULL) {
|
||||
result = ISC_R_NOMEMORY;
|
||||
goto cleanup_dbtype;
|
||||
}
|
||||
|
||||
for (i = 0; i < cache->db_argc; i++)
|
||||
cache->db_argv[i] = NULL;
|
||||
for (i = 0; i < cache->db_argc; i++) {
|
||||
cache->db_argv[i] = isc_mem_strdup(mctx, db_argv[i]);
|
||||
|
||||
cache->db_argv[0] = (char *) hmctx;
|
||||
for (i = extra; i < cache->db_argc; i++) {
|
||||
cache->db_argv[i] = isc_mem_strdup(cmctx,
|
||||
db_argv[i - extra]);
|
||||
if (cache->db_argv[i] == NULL) {
|
||||
result = ISC_R_NOMEMORY;
|
||||
goto cleanup_dbargv;
|
||||
@@ -248,6 +276,9 @@ dns_cache_create2(isc_mem_t *mctx, isc_taskmgr_t *taskmgr,
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Create the database
|
||||
*/
|
||||
cache->db = NULL;
|
||||
result = cache_create_db(cache, &cache->db);
|
||||
if (result != ISC_R_SUCCESS)
|
||||
@@ -284,29 +315,28 @@ dns_cache_create2(isc_mem_t *mctx, isc_taskmgr_t *taskmgr,
|
||||
cleanup_db:
|
||||
dns_db_detach(&cache->db);
|
||||
cleanup_dbargv:
|
||||
for (i = 0; i < cache->db_argc; i++)
|
||||
for (i = extra; i < cache->db_argc; i++)
|
||||
if (cache->db_argv[i] != NULL)
|
||||
isc_mem_free(mctx, cache->db_argv[i]);
|
||||
isc_mem_free(cmctx, cache->db_argv[i]);
|
||||
if (cache->db_argv != NULL)
|
||||
isc_mem_put(mctx, cache->db_argv,
|
||||
isc_mem_put(cmctx, cache->db_argv,
|
||||
cache->db_argc * sizeof(char *));
|
||||
cleanup_dbtype:
|
||||
isc_mem_free(mctx, cache->db_type);
|
||||
isc_mem_free(cmctx, cache->db_type);
|
||||
cleanup_filelock:
|
||||
DESTROYLOCK(&cache->filelock);
|
||||
cleanup_lock:
|
||||
DESTROYLOCK(&cache->lock);
|
||||
cleanup_mem:
|
||||
if (cache->name != NULL)
|
||||
isc_mem_free(mctx, cache->name);
|
||||
isc_mem_put(mctx, cache, sizeof(*cache));
|
||||
isc_mem_detach(&mctx);
|
||||
isc_mem_free(cmctx, cache->name);
|
||||
isc_mem_detach(&cache->hmctx);
|
||||
isc_mem_putanddetach(&cache->mctx, cache, sizeof(*cache));
|
||||
return (result);
|
||||
}
|
||||
|
||||
static void
|
||||
cache_free(dns_cache_t *cache) {
|
||||
isc_mem_t *mctx;
|
||||
int i;
|
||||
|
||||
REQUIRE(VALID_CACHE(cache));
|
||||
@@ -337,7 +367,14 @@ cache_free(dns_cache_t *cache) {
|
||||
dns_db_detach(&cache->db);
|
||||
|
||||
if (cache->db_argv != NULL) {
|
||||
for (i = 0; i < cache->db_argc; i++)
|
||||
/*
|
||||
* We don't free db_argv[0] in "rbt" cache databases
|
||||
* as it's a pointer to hmctx
|
||||
*/
|
||||
int extra = 0;
|
||||
if (strcmp(cache->db_type, "rbt") == 0)
|
||||
extra = 1;
|
||||
for (i = extra; i < cache->db_argc; i++)
|
||||
if (cache->db_argv[i] != NULL)
|
||||
isc_mem_free(cache->mctx, cache->db_argv[i]);
|
||||
isc_mem_put(cache->mctx, cache->db_argv,
|
||||
@@ -352,10 +389,10 @@ cache_free(dns_cache_t *cache) {
|
||||
|
||||
DESTROYLOCK(&cache->lock);
|
||||
DESTROYLOCK(&cache->filelock);
|
||||
|
||||
cache->magic = 0;
|
||||
mctx = cache->mctx;
|
||||
isc_mem_put(cache->mctx, cache, sizeof(*cache));
|
||||
isc_mem_detach(&mctx);
|
||||
isc_mem_detach(&cache->hmctx);
|
||||
isc_mem_putanddetach(&cache->mctx, cache, sizeof(*cache));
|
||||
}
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user