diff options
Diffstat (limited to 'lib/dns/rbtdb.c')
| -rw-r--r-- | lib/dns/rbtdb.c | 127 | 
1 files changed, 66 insertions, 61 deletions
| diff --git a/lib/dns/rbtdb.c b/lib/dns/rbtdb.c index d5b5b5c8194f..f841ebea5e94 100644 --- a/lib/dns/rbtdb.c +++ b/lib/dns/rbtdb.c @@ -15,7 +15,7 @@   * PERFORMANCE OF THIS SOFTWARE.   */ -/* $Id: rbtdb.c,v 1.270.12.6.10.2 2009/12/31 21:44:36 each Exp $ */ +/* $Id: rbtdb.c,v 1.270.12.16 2009/12/30 08:34:30 jinmei Exp $ */  /*! \file */ @@ -258,21 +258,8 @@ typedef struct rdatasetheader {  	dns_rbtnode_t                   *node;  	isc_stdtime_t                   last_used; -	ISC_LINK(struct rdatasetheader) lru_link; -	/*%< -	 * Used for LRU-based cache management.  We should probably make -	 * these cache-DB specific.  We might also make it a pointer and -	 * ensure only the top header has a valid link to save memory. -	 * The linked-list is locked by the rbtdb->lrulock. -	 */ +	ISC_LINK(struct rdatasetheader) link; -	/* -	 * It's possible this should not be here anymore, but instead -	 * referenced from the bucket's heap directly. -	 */ -#if 0 -	isc_heap_t                      *heap; -#endif  	unsigned int                    heap_index;  	/*%<  	 * Used for TTL-based cache cleaning. @@ -396,7 +383,7 @@ typedef struct rbtdb_version {  	isc_uint8_t			flags;  	isc_uint16_t			iterations;  	isc_uint8_t			salt_length; -	unsigned char			salt[NSEC3_MAX_HASH_LENGTH]; +	unsigned char			salt[DNS_NSEC3_SALTSIZE];  } rbtdb_version_t;  typedef ISC_LIST(rbtdb_version_t)       rbtdb_versionlist_t; @@ -1227,7 +1214,7 @@ free_noqname(isc_mem_t *mctx, struct noqname **noqname) {  static inline void  init_rdataset(dns_rbtdb_t *rbtdb, rdatasetheader_t *h)  { -	ISC_LINK_INIT(h, lru_link); +	ISC_LINK_INIT(h, link);  	h->heap_index = 0;  #if TRACE_HEADER @@ -1267,8 +1254,10 @@ free_rdataset(dns_rbtdb_t *rbtdb, isc_mem_t *mctx, rdatasetheader_t *rdataset)  	}  	idx = rdataset->node->locknum; -	if (ISC_LINK_LINKED(rdataset, lru_link)) -		ISC_LIST_UNLINK(rbtdb->rdatasets[idx], rdataset, lru_link); +	if (ISC_LINK_LINKED(rdataset, link)) { +		INSIST(IS_CACHE(rbtdb)); +		ISC_LIST_UNLINK(rbtdb->rdatasets[idx], rdataset, link); +	}  	if (rdataset->heap_index != 0)  		isc_heap_delete(rbtdb->heaps[idx], rdataset->heap_index);  	rdataset->heap_index = 0; @@ -2075,8 +2064,6 @@ setnsec3parameters(dns_db_t *db, rbtdb_version_t *version,  					continue;  #endif -				INSIST(nsec3param.salt_length <= -				       sizeof(version->salt));  				memcpy(version->salt, nsec3param.salt,  				       nsec3param.salt_length);  				version->hash = nsec3param.hash; @@ -2284,17 +2271,18 @@ closeversion(dns_db_t *db, dns_dbversion_t **versionp, isc_boolean_t commit) {  	for (header = HEAD(resigned_list);  	     header != NULL;  	     header = HEAD(resigned_list)) { -		ISC_LIST_UNLINK(resigned_list, header, lru_link); -		if (rollback) { -			nodelock_t *lock; -			lock = &rbtdb->node_locks[header->node->locknum].lock; -			NODE_LOCK(lock, isc_rwlocktype_write); +		nodelock_t *lock; + +		ISC_LIST_UNLINK(resigned_list, header, link); + +		lock = &rbtdb->node_locks[header->node->locknum].lock; +		NODE_LOCK(lock, isc_rwlocktype_write); +		if (rollback)  			resign_insert(rbtdb, header->node->locknum, header); -			NODE_UNLOCK(lock, isc_rwlocktype_write); -		}  		decrement_reference(rbtdb, header->node, least_serial,  				    isc_rwlocktype_write, isc_rwlocktype_none,  				    ISC_FALSE); +		NODE_UNLOCK(lock, isc_rwlocktype_write);  	}  	if (!EMPTY(cleanup_list)) { @@ -3524,11 +3512,17 @@ zone_find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version,  		/*  		 * The node may be a zone cut itself.  If it might be one,  		 * make sure we check for it later. +		 * +		 * DS records live above the zone cut in ordinary zone so +		 * we want to ignore any referral. +		 * +		 * Stub zones don't have anything "above" the delgation so +		 * we always return a referral.  		 */  		if (node->find_callback && -		    (node != search.rbtdb->origin_node || -		     IS_STUB(search.rbtdb)) && -		    !dns_rdatatype_atparent(type)) +		    ((node != search.rbtdb->origin_node && +		      !dns_rdatatype_atparent(type)) || +		     IS_STUB(search.rbtdb)))  			maybe_zonecut = ISC_TRUE;  	} @@ -3546,8 +3540,8 @@ zone_find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version,  	 * We now go looking for rdata...  	 */ -	NODE_LOCK(&(search.rbtdb->node_locks[node->locknum].lock), -		  isc_rwlocktype_read); +	lock = &search.rbtdb->node_locks[node->locknum].lock; +	NODE_LOCK(lock, isc_rwlocktype_read);  	found = NULL;  	foundsig = NULL; @@ -3625,8 +3619,10 @@ zone_find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version,  			 * we are using behave as if it isn't here.  			 */  			if (header->type == dns_rdatatype_nsec3 && -			    !matchparams(header, &search)) +			   !matchparams(header, &search)) { +				NODE_UNLOCK(lock, isc_rwlocktype_read);  				goto partial_match; +			}  			/*  			 * If we found a type we were looking for,  			 * remember it. @@ -3705,7 +3701,6 @@ zone_find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version,  		 * we really have a partial match.  		 */  		if (!wild) { -			lock = &search.rbtdb->node_locks[node->locknum].lock;  			NODE_UNLOCK(lock, isc_rwlocktype_read);  			goto partial_match;  		} @@ -3722,7 +3717,6 @@ zone_find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version,  			 *  			 * Return the delegation.  			 */ -			lock = &search.rbtdb->node_locks[node->locknum].lock;  			NODE_UNLOCK(lock, isc_rwlocktype_read);  			result = setup_delegation(&search, nodep, foundname,  						  rdataset, sigrdataset); @@ -3744,7 +3738,6 @@ zone_find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version,  				goto node_exit;  			} -			lock = &search.rbtdb->node_locks[node->locknum].lock;  			NODE_UNLOCK(lock, isc_rwlocktype_read);  			result = find_closest_nsec(&search, nodep, foundname,  						   rdataset, sigrdataset, @@ -3829,7 +3822,6 @@ zone_find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version,  		if (result == DNS_R_GLUE &&  		    (search.options & DNS_DBFIND_VALIDATEGLUE) != 0 &&  		    !valid_glue(&search, foundname, type, node)) { -			lock = &search.rbtdb->node_locks[node->locknum].lock;  			NODE_UNLOCK(lock, isc_rwlocktype_read);  			result = setup_delegation(&search, nodep, foundname,  						  rdataset, sigrdataset); @@ -3861,8 +3853,7 @@ zone_find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version,  		foundname->attributes |= DNS_NAMEATTR_WILDCARD;   node_exit: -	NODE_UNLOCK(&(search.rbtdb->node_locks[node->locknum].lock), -		    isc_rwlocktype_read); +	NODE_UNLOCK(lock, isc_rwlocktype_read);   tree_exit:  	RWUNLOCK(&search.rbtdb->tree_lock, isc_rwlocktype_read); @@ -5408,8 +5399,10 @@ static isc_result_t  resign_insert(dns_rbtdb_t *rbtdb, int idx, rdatasetheader_t *newheader) {  	isc_result_t result; +	INSIST(!IS_CACHE(rbtdb));  	INSIST(newheader->heap_index == 0); -	INSIST(!ISC_LINK_LINKED(newheader, lru_link)); +	INSIST(!ISC_LINK_LINKED(newheader, link)); +  	result = isc_heap_insert(rbtdb->heaps[idx], newheader);  	return (result);  } @@ -5735,7 +5728,7 @@ add(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion,  			idx = newheader->node->locknum;  			if (IS_CACHE(rbtdb)) {  				ISC_LIST_PREPEND(rbtdb->rdatasets[idx], -						 newheader, lru_link); +						 newheader, link);  				/*  				 * XXXMLG We don't check the return value  				 * here.  If it fails, we will not do TTL @@ -5794,7 +5787,7 @@ add(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion,  		idx = newheader->node->locknum;  		if (IS_CACHE(rbtdb)) {  			ISC_LIST_PREPEND(rbtdb->rdatasets[idx], -					 newheader, lru_link); +					 newheader, link);  			isc_heap_insert(rbtdb->heaps[idx], newheader);  		} else if (RESIGN(newheader)) {  			resign_insert(rbtdb, idx, newheader); @@ -6519,11 +6512,17 @@ static void  delete_callback(void *data, void *arg) {  	dns_rbtdb_t *rbtdb = arg;  	rdatasetheader_t *current, *next; +	unsigned int locknum; -	for (current = data; current != NULL; current = next) { +	current = data; +	locknum = current->node->locknum; +	NODE_LOCK(&rbtdb->node_locks[locknum].lock, isc_rwlocktype_write); +	while (current != NULL) {  		next = current->next;  		free_rdataset(rbtdb, rbtdb->common.mctx, current); +		current = next;  	} +	NODE_UNLOCK(&rbtdb->node_locks[locknum].lock, isc_rwlocktype_write);  }  static isc_boolean_t @@ -6642,8 +6641,8 @@ getnsec3parameters(dns_db_t *db, dns_dbversion_t *version, dns_hash_t *hash,  	if (rbtversion->havensec3) {  		if (hash != NULL)  			*hash = rbtversion->hash; -		if (salt != NULL && salt_length != 0) { -			REQUIRE(*salt_length > rbtversion->salt_length); +		if (salt != NULL && salt_length != NULL) { +			REQUIRE(*salt_length >= rbtversion->salt_length);  			memcpy(salt, rbtversion->salt, rbtversion->salt_length);  		}  		if (salt_length != NULL) @@ -6707,27 +6706,35 @@ getsigningtime(dns_db_t *db, dns_rdataset_t *rdataset,  	rdatasetheader_t *header = NULL, *this;  	unsigned int i;  	isc_result_t result = ISC_R_NOTFOUND; +	unsigned int locknum;  	REQUIRE(VALID_RBTDB(rbtdb));  	RBTDB_LOCK(&rbtdb->lock, isc_rwlocktype_read);  	for (i = 0; i < rbtdb->node_lock_count; i++) { +		NODE_LOCK(&rbtdb->node_locks[i].lock, isc_rwlocktype_read);  		this = isc_heap_element(rbtdb->heaps[i], 1); -		if (this == NULL) +		if (this == NULL) { +			NODE_UNLOCK(&rbtdb->node_locks[i].lock, +				    isc_rwlocktype_read);  			continue; +		}  		if (header == NULL)  			header = this; -		else if (isc_serial_lt(this->resign, header->resign)) +		else if (isc_serial_lt(this->resign, header->resign)) { +			locknum = header->node->locknum; +			NODE_UNLOCK(&rbtdb->node_locks[locknum].lock, +				    isc_rwlocktype_read);  			header = this; +		} else +			NODE_UNLOCK(&rbtdb->node_locks[i].lock, +				    isc_rwlocktype_read);  	}  	if (header == NULL)  		goto unlock; -	NODE_LOCK(&rbtdb->node_locks[header->node->locknum].lock, -		  isc_rwlocktype_read); -  	bind_rdataset(rbtdb, header->node, header, 0, rdataset);  	if (foundname != NULL) @@ -6761,7 +6768,7 @@ resigned(dns_db_t *db, dns_rdataset_t *rdataset, dns_dbversion_t *version)  	header = rdataset->private3;  	header--; -	RBTDB_LOCK(&rbtdb->lock, isc_rwlocktype_read); +	RBTDB_LOCK(&rbtdb->lock, isc_rwlocktype_write);  	NODE_LOCK(&rbtdb->node_locks[node->locknum].lock,  		  isc_rwlocktype_write);  	/* @@ -6771,11 +6778,11 @@ resigned(dns_db_t *db, dns_rdataset_t *rdataset, dns_dbversion_t *version)  	new_reference(rbtdb, node);  	isc_heap_delete(rbtdb->heaps[node->locknum], header->heap_index);  	header->heap_index = 0; -	ISC_LIST_APPEND(rbtversion->resigned_list, header, lru_link); +	ISC_LIST_APPEND(rbtversion->resigned_list, header, link);  	NODE_UNLOCK(&rbtdb->node_locks[node->locknum].lock,  		    isc_rwlocktype_write); -	RBTDB_UNLOCK(&rbtdb->lock, isc_rwlocktype_read); +	RBTDB_UNLOCK(&rbtdb->lock, isc_rwlocktype_write);  }  static dns_stats_t * @@ -8497,13 +8504,11 @@ update_header(dns_rbtdb_t *rbtdb, rdatasetheader_t *header,  	INSIST(IS_CACHE(rbtdb));  	/* To be checked: can we really assume this? XXXMLG */ -	INSIST(ISC_LINK_LINKED(header, lru_link)); +	INSIST(ISC_LINK_LINKED(header, link)); -	ISC_LIST_UNLINK(rbtdb->rdatasets[header->node->locknum], -			header, lru_link); +	ISC_LIST_UNLINK(rbtdb->rdatasets[header->node->locknum], header, link);  	header->last_used = now; -	ISC_LIST_PREPEND(rbtdb->rdatasets[header->node->locknum], -			 header, lru_link); +	ISC_LIST_PREPEND(rbtdb->rdatasets[header->node->locknum], header, link);  }  /*% @@ -8539,7 +8544,7 @@ overmem_purge(dns_rbtdb_t *rbtdb, unsigned int locknum_start,  		for (header = ISC_LIST_TAIL(rbtdb->rdatasets[locknum]);  		     header != NULL && purgecount > 0;  		     header = header_prev) { -			header_prev = ISC_LIST_PREV(header, lru_link); +			header_prev = ISC_LIST_PREV(header, link);  			/*  			 * Unlink the entry at this point to avoid checking it  			 * again even if it's currently used someone else and @@ -8548,7 +8553,7 @@ overmem_purge(dns_rbtdb_t *rbtdb, unsigned int locknum_start,  			 * TTL was reset to 0.  			 */  			ISC_LIST_UNLINK(rbtdb->rdatasets[locknum], header, -					lru_link); +					link);  			expire_header(rbtdb, header, tree_locked);  			purgecount--;  		} | 
