commit 93c211afc97e7a072c12ef346581065e4065ff15
Author: Evan Hunt <each@isc.org>
Date:   Fri Feb 12 00:22:45 2016 -0800

    [master] fixed a regression in dyndb due to change #4277

diff --git a/bin/named/server.c b/bin/named/server.c
index 554e241..5a1a5ca 100644
--- a/bin/named/server.c
+++ b/bin/named/server.c
@@ -3960,12 +3960,14 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist,
 	{
 		const cfg_obj_t *dyndb = cfg_listelt_value(element);
 
-		if (dctx == NULL)
-			CHECK(dns_dyndb_createctx(mctx, isc_hashctx,
+		if (dctx == NULL) {
+			const void *hashinit = isc_hash_get_initializer();
+			CHECK(dns_dyndb_createctx(mctx, hashinit,
 						  ns_g_lctx, view,
 						  ns_g_server->zonemgr,
 						  ns_g_server->task,
 						  ns_g_timermgr, &dctx));
+		}
 
 		CHECK(configure_dyndb(dyndb, mctx, dctx));
 	}
diff --git a/bin/tests/system/conf.sh.in b/bin/tests/system/conf.sh.in
index 4ab0f91..d76ff66 100644
--- a/bin/tests/system/conf.sh.in
+++ b/bin/tests/system/conf.sh.in
@@ -68,7 +68,7 @@ RANDFILE=$TOP/bin/tests/system/random.data
 SUBDIRS="acl additional allow_query addzone autosign builtin
 	 cacheclean case checkconf @CHECKDS@ checknames checkzone
 	 cookie @COVERAGE@ database digdelv dlv dlvauto dlz dlzexternal
-	 dname dns64 dnssec dsdigest dscp @DNSTAP@ ecdsa ednscompliance
+	 dname dns64 dnssec dsdigest dscp @DNSTAP@ dyndb ecdsa ednscompliance
 	 emptyzones fetchlimit filter-aaaa formerr forward geoip glue gost
 	 ixfr inline legacy limits logfileconfig lwresd masterfile
 	 masterformat metadata mkeys names notify nslookup nsupdate
diff --git a/bin/tests/system/dyndb/driver/db.c b/bin/tests/system/dyndb/driver/db.c
index 317674b..3abecd2 100644
--- a/bin/tests/system/dyndb/driver/db.c
+++ b/bin/tests/system/dyndb/driver/db.c
@@ -439,9 +439,9 @@ transfernode(dns_db_t *db, dns_dbnode_t **sourcep, dns_dbnode_t **targetp) {
 
 static isc_result_t
 getnsec3parameters(dns_db_t *db, dns_dbversion_t *version,
-			  dns_hash_t *hash, isc_uint8_t *flags,
-			  isc_uint16_t *iterations,
-			  unsigned char *salt, size_t *salt_length)
+		   dns_hash_t *hash, isc_uint8_t *flags,
+		   isc_uint16_t *iterations,
+		   unsigned char *salt, size_t *salt_length)
 {
 	sampledb_t *sampledb = (sampledb_t *) db;
 
@@ -465,8 +465,7 @@ findnsec3node(dns_db_t *db, dns_name_t *name, isc_boolean_t create,
 }
 
 static isc_result_t
-setsigningtime(dns_db_t *db, dns_rdataset_t *rdataset, isc_stdtime_t resign)
-{
+setsigningtime(dns_db_t *db, dns_rdataset_t *rdataset, isc_stdtime_t resign) {
 	sampledb_t *sampledb = (sampledb_t *) db;
 
 	REQUIRE(VALID_SAMPLEDB(sampledb));
@@ -475,8 +474,7 @@ setsigningtime(dns_db_t *db, dns_rdataset_t *rdataset, isc_stdtime_t resign)
 }
 
 static isc_result_t
-getsigningtime(dns_db_t *db, dns_rdataset_t *rdataset, dns_name_t *name)
-{
+getsigningtime(dns_db_t *db, dns_rdataset_t *rdataset, dns_name_t *name) {
 	sampledb_t *sampledb = (sampledb_t *) db;
 
 	REQUIRE(VALID_SAMPLEDB(sampledb));
diff --git a/bin/tests/system/dyndb/driver/driver.c b/bin/tests/system/dyndb/driver/driver.c
index 1d0274e..317c814 100644
--- a/bin/tests/system/dyndb/driver/driver.c
+++ b/bin/tests/system/dyndb/driver/driver.c
@@ -81,9 +81,7 @@ dyndb_init(isc_mem_t *mctx, const char *name, const char *parameters,
 		dns_log_setcontext(dctx->lctx);
 	}
 
-	if (isc_hashctx != NULL && isc_hashctx != dctx->hctx)
-		isc_hash_ctxdetach(&isc_hashctx);
-	isc_hashctx = dctx->hctx;
+	isc_hash_set_initializer(dctx->hashinit);
 
 	s = isc_mem_strdup(mctx, parameters);
 	if (s == NULL) {
diff --git a/lib/dns/dyndb.c b/lib/dns/dyndb.c
index 1d6a7c0..450bf83 100644
--- a/lib/dns/dyndb.c
+++ b/lib/dns/dyndb.c
@@ -415,10 +415,10 @@ dns_dyndb_cleanup(isc_boolean_t exiting) {
 }
 
 isc_result_t
-dns_dyndb_createctx(isc_mem_t *mctx, isc_hash_t *hctx, isc_log_t *lctx,
-		    dns_view_t *view, dns_zonemgr_t *zmgr,
-		    isc_task_t *task, isc_timermgr_t *tmgr,
-		    dns_dyndbctx_t **dctxp) {
+dns_dyndb_createctx(isc_mem_t *mctx, const void *hashinit, isc_log_t *lctx,
+		    dns_view_t *view, dns_zonemgr_t *zmgr, isc_task_t *task,
+		    isc_timermgr_t *tmgr, dns_dyndbctx_t **dctxp)
+{
 	dns_dyndbctx_t *dctx;
 
 	REQUIRE(dctxp != NULL && *dctxp == NULL);
@@ -435,7 +435,7 @@ dns_dyndb_createctx(isc_mem_t *mctx, isc_hash_t *hctx, isc_log_t *lctx,
 	if (task != NULL)
 		isc_task_attach(task, &dctx->task);
 	dctx->timermgr = tmgr;
-	dctx->hctx = hctx;
+	dctx->hashinit = hashinit;
 	dctx->lctx = lctx;
 	dctx->refvar = &isc_bind9;
 
diff --git a/lib/dns/include/dns/dyndb.h b/lib/dns/include/dns/dyndb.h
index fdc2c54..07de8b9 100644
--- a/lib/dns/include/dns/dyndb.h
+++ b/lib/dns/include/dns/dyndb.h
@@ -27,17 +27,17 @@ ISC_LANG_BEGINDECLS
  * \brief
  * Context for intializing a dyndb module.
  *
- * This structure passes pointers to globals to which a dyndb
+ * This structure passes global server data to which a dyndb
  * module will need access -- the server memory context, hash
- * context, log context, etc.  The structure doesn't persist
+ * initializer, log context, etc.  The structure doesn't persist
  * beyond configuring the dyndb module. The module's register function
  * should attach to all reference-counted variables and its destroy
  * function should detach from them.
  */
 struct dns_dyndbctx {
 	unsigned int	magic;
+	const void	*hashinit;
 	isc_mem_t	*mctx;
-	isc_hash_t	*hctx;
 	isc_log_t	*lctx;
 	dns_view_t	*view;
 	dns_zonemgr_t	*zmgr;
@@ -128,14 +128,13 @@ dns_dyndb_cleanup(isc_boolean_t exiting);
  */
 
 isc_result_t
-dns_dyndb_createctx(isc_mem_t *mctx, isc_hash_t *hctx, isc_log_t *lctx,
-		    dns_view_t *view, dns_zonemgr_t *zmgr,
-		    isc_task_t *task, isc_timermgr_t *tmgr,
-		    dns_dyndbctx_t **dctxp);
+dns_dyndb_createctx(isc_mem_t *mctx, const void *hashinit, isc_log_t *lctx,
+		    dns_view_t *view, dns_zonemgr_t *zmgr, isc_task_t *task,
+		    isc_timermgr_t *tmgr, dns_dyndbctx_t **dctxp);
 /*%
  * Create a dyndb initialization context structure, with
  * pointers to structures in the server that the dyndb module will
- * need to access (view, zone manager, memory context, hash context,
+ * need to access (view, zone manager, memory context, hash initializer,
  * etc). This structure is expected to last only until all dyndb
  * modules have been loaded and initialized; after that it will be
  * destroyed with dns_dyndb_destroyctx().
diff --git a/lib/isc/hash.c b/lib/isc/hash.c
index 96a7904..da8c448 100644
--- a/lib/isc/hash.c
+++ b/lib/isc/hash.c
@@ -419,6 +419,26 @@ fnv_initialize(void) {
 	}
 }
 
+const void *
+isc_hash_get_initializer(void) {
+	RUNTIME_CHECK(isc_once_do(&fnv_once, fnv_initialize) == ISC_R_SUCCESS);
+
+	return (&fnv_offset_basis);
+}
+
+void
+isc_hash_set_initializer(const void *initializer) {
+	REQUIRE(initializer != NULL);
+
+	/*
+	 * Ensure that fnv_initialize() is not called after
+	 * isc_hash_set_initializer() is called.
+	 */
+	RUNTIME_CHECK(isc_once_do(&fnv_once, fnv_initialize) == ISC_R_SUCCESS);
+
+	fnv_offset_basis = *((const unsigned int *) initializer);
+}
+
 unsigned int
 isc_hash_function(const void *data, size_t length,
 		  isc_boolean_t case_sensitive,
@@ -442,7 +462,7 @@ isc_hash_function(const void *data, size_t length,
 	/*
 	 * Fowler-Noll-Vo FNV-1a hash function.
 	 *
-	 * NOTE: A random fnv_offset_basis is used by default to avoid
+	 * NOTE: A random FNV offset basis is used by default to avoid
 	 * collision attacks as the hash function is reversible. This
 	 * makes the mapping non-deterministic, but the distribution in
 	 * the domain is still uniform.
@@ -497,7 +517,7 @@ isc_hash_function_reverse(const void *data, size_t length,
 	INSIST(data == NULL || length > 0);
 	RUNTIME_CHECK(isc_once_do(&fnv_once, fnv_initialize) == ISC_R_SUCCESS);
 
-	hval = ISC_UNLIKELY(previous_hashp != NULL) ? *previous_hashp : fnv_offset_basis;
+	hval = previous_hashp != NULL ? *previous_hashp : fnv_offset_basis;
 
 	if (length == 0)
 		return (hval);
@@ -508,7 +528,7 @@ isc_hash_function_reverse(const void *data, size_t length,
 	/*
 	 * Fowler-Noll-Vo FNV-1a hash function.
 	 *
-	 * NOTE: A random fnv_offset_basis is used by default to avoid
+	 * NOTE: A random FNV offset basis is used by default to avoid
 	 * collision attacks as the hash function is reversible. This
 	 * makes the mapping non-deterministic, but the distribution in
 	 * the domain is still uniform.
diff --git a/lib/isc/include/isc/hash.h b/lib/isc/include/isc/hash.h
index 8904e59..8cd23c5 100644
--- a/lib/isc/include/isc/hash.h
+++ b/lib/isc/include/isc/hash.h
@@ -198,6 +198,12 @@ isc__hash_setvec(const isc_uint16_t *vec);
  * doing before using this function.
  */
 
+const void *
+isc_hash_get_initializer(void);
+
+void
+isc_hash_set_initializer(const void *initializer);
+
 unsigned int
 isc_hash_function(const void *data, size_t length,
 		  isc_boolean_t case_sensitive,
diff --git a/lib/isc/tests/hash_test.c b/lib/isc/tests/hash_test.c
index ff572d4..ab3f926 100644
--- a/lib/isc/tests/hash_test.c
+++ b/lib/isc/tests/hash_test.c
@@ -1895,7 +1895,6 @@ ATF_TC_BODY(isc_hash_function, tc) {
 	ATF_CHECK(h1 != h2);
 }
 
-
 ATF_TC(isc_hash_function_reverse);
 ATF_TC_HEAD(isc_hash_function_reverse, tc) {
 	atf_tc_set_md_var(tc, "descr", "Reverse hash function test");
@@ -1943,6 +1942,29 @@ ATF_TC_BODY(isc_hash_function_reverse, tc) {
 	ATF_CHECK(h1 != h2);
 }
 
+ATF_TC(isc_hash_initializer);
+ATF_TC_HEAD(isc_hash_initializer, tc) {
+	atf_tc_set_md_var(tc, "descr", "Hash function initializer test");
+}
+ATF_TC_BODY(isc_hash_initializer, tc) {
+	unsigned int h1;
+	unsigned int h2;
+
+	UNUSED(tc);
+
+	h1 = isc_hash_function("Hello world", 12, ISC_TRUE, NULL);
+	h2 = isc_hash_function("Hello world", 12, ISC_TRUE, NULL);
+
+	ATF_CHECK_EQ(h1, h2);
+
+	isc_hash_set_initializer(isc_hash_get_initializer());
+
+	/* Hash value must not change */
+	h2 = isc_hash_function("Hello world", 12, ISC_TRUE, NULL);
+
+	ATF_CHECK_EQ(h1, h2);
+}
+
 /*
  * Main
  */
@@ -1953,6 +1975,7 @@ ATF_TP_ADD_TCS(tp) {
 	 */
 	ATF_TP_ADD_TC(tp, isc_hash_function);
 	ATF_TP_ADD_TC(tp, isc_hash_function_reverse);
+	ATF_TP_ADD_TC(tp, isc_hash_initializer);
 	ATF_TP_ADD_TC(tp, isc_hmacmd5);
 	ATF_TP_ADD_TC(tp, isc_hmacsha1);
 	ATF_TP_ADD_TC(tp, isc_hmacsha224);
