bool broken;
isc_refcount_t references;
+ isc_mutex_t lock;
};
static void
dns_catz_options_init(&catz->defoptions);
}
-isc_result_t
-dns_catz_zones_merge(dns_catz_zone_t *catz, dns_catz_zone_t *newcatz) {
+/*%<
+ * Merge 'newcatz' into 'catz', calling addzone/delzone/modzone
+ * (from catz->catzs->zmm) for appropriate member zones.
+ *
+ * Requires:
+ * \li 'catz' is a valid dns_catz_zone_t.
+ * \li 'newcatz' is a valid dns_catz_zone_t.
+ *
+ */
+static isc_result_t
+dns__catz_zones_merge(dns_catz_zone_t *catz, dns_catz_zone_t *newcatz) {
isc_result_t result;
isc_ht_iter_t *iter1 = NULL, *iter2 = NULL;
isc_ht_iter_t *iteradd = NULL, *itermod = NULL;
REQUIRE(DNS_CATZ_ZONE_VALID(catz));
REQUIRE(DNS_CATZ_ZONE_VALID(newcatz));
+ LOCK(&catz->lock);
+
/* TODO verify the new zone first! */
addzone = catz->catzs->zmm->addzone;
if (zt_find_result == ISC_R_SUCCESS) {
dns_catz_coo_t *coo = NULL;
char pczname[DNS_NAME_FORMATSIZE];
+ bool parentcatz_locked = false;
/*
* Change of ownership (coo) processing, if required
*/
parentcatz = dns_zone_get_parentcatz(zone);
- if (parentcatz != NULL && parentcatz != catz &&
+ if (parentcatz != NULL && parentcatz != catz) {
+ UNLOCK(&catz->lock);
+ LOCK(&parentcatz->lock);
+ parentcatz_locked = true;
+ }
+ if (parentcatz_locked &&
isc_ht_find(parentcatz->coos, nentry->name.ndata,
nentry->name.length,
(void **)&coo) == ISC_R_SUCCESS &&
zname, pczname,
isc_result_totext(result));
}
+ if (parentcatz_locked) {
+ UNLOCK(&parentcatz->lock);
+ LOCK(&catz->lock);
+ }
}
if (zt_find_result == ISC_R_SUCCESS ||
zt_find_result == DNS_R_PARTIALMATCH)
isc_ht_destroy(&toadd);
isc_ht_destroy(&tomod);
+ UNLOCK(&catz->lock);
+
return (result);
}
.version = DNS_CATZ_VERSION_UNDEFINED,
.magic = DNS_CATZ_ZONE_MAGIC };
+ isc_mutex_init(&catz->lock);
isc_refcount_init(&catz->references, 1);
isc_ht_init(&catz->entries, catzs->mctx, 4, ISC_HT_CASE_SENSITIVE);
isc_ht_init(&catz->coos, catzs->mctx, 4, ISC_HT_CASE_INSENSITIVE);
isc_ht_destroy(&catz->coos);
}
catz->magic = 0;
+ isc_mutex_destroy(&catz->lock);
if (catz->updatetimer != NULL) {
isc_timer_async_destroy(&catz->updatetimer);
}
}
-isc_result_t
-dns_catz_update_process(dns_catz_zone_t *catz, const dns_name_t *src_name,
- dns_rdataset_t *rdataset) {
+/*%<
+ * Process a single rdataset from a catalog zone 'catz' update, src_name is the
+ * record name.
+ *
+ * Requires:
+ * \li 'catz' is a valid dns_catz_zone_t.
+ * \li 'src_name' is a valid dns_name_t.
+ * \li 'rdataset' is valid rdataset.
+ */
+static isc_result_t
+dns__catz_update_process(dns_catz_zone_t *catz, const dns_name_t *src_name,
+ dns_rdataset_t *rdataset) {
isc_result_t result;
int order;
unsigned int nlabels;
goto next;
}
- result = dns_catz_update_process(newcatz, name,
- &rdataset);
+ /*
+ * Although newcatz->coos is accessed in
+ * catz_process_coo() in the call-chain below, we don't
+ * need to hold the newcatz->lock, because the newcatz
+ * is still local to this thread and function and
+ * newcatz->coos can't be accessed from the outside
+ * until dns__catz_zones_merge() has been called.
+ */
+ result = dns__catz_update_process(newcatz, name,
+ &rdataset);
if (result != ISC_R_SUCCESS) {
char typebuf[DNS_RDATATYPE_FORMATSIZE];
char classbuf[DNS_RDATACLASS_FORMATSIZE];
/*
* Finally merge new zone into old zone.
*/
- result = dns_catz_zones_merge(oldcatz, newcatz);
+ result = dns__catz_zones_merge(oldcatz, newcatz);
dns_catz_detach_catz(&newcatz);
if (result != ISC_R_SUCCESS) {
isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
result = dns_catz_new_zone(catzs, &newcatz,
&catz->name);
INSIST(result == ISC_R_SUCCESS);
- dns_catz_zones_merge(catz, newcatz);
+ dns__catz_zones_merge(catz, newcatz);
dns_catz_detach_catz(&newcatz);
/* Make sure that we have an empty catalog zone. */