lib/dns/resolver.c: Convert (dns_view_t *)->weakrefs to isc_refcount_t
There's a deadlock in BIND 9 code where (dns_view_t){ .lock } and
(dns_resolver_t){ .buckets[i].lock } gets locked in different order. When
view->weakrefs gets converted to a reference counting we can reduce the locking
in dns_view_weakdetach only to cases where it's the last instance of the
dns_view_t object.
This commit is contained in:
@@ -193,9 +193,9 @@ struct dns_view {
|
|||||||
|
|
||||||
/* Locked by themselves. */
|
/* Locked by themselves. */
|
||||||
isc_refcount_t references;
|
isc_refcount_t references;
|
||||||
|
isc_refcount_t weakrefs;
|
||||||
|
|
||||||
/* Locked by lock. */
|
/* Locked by lock. */
|
||||||
unsigned int weakrefs;
|
|
||||||
unsigned int attributes;
|
unsigned int attributes;
|
||||||
/* Under owner's locking control. */
|
/* Under owner's locking control. */
|
||||||
ISC_LINK(struct dns_view) link;
|
ISC_LINK(struct dns_view) link;
|
||||||
|
|||||||
@@ -157,9 +157,13 @@ dns_view_create(isc_mem_t *mctx, dns_rdataclass_t rdclass,
|
|||||||
view->frozen = false;
|
view->frozen = false;
|
||||||
view->task = NULL;
|
view->task = NULL;
|
||||||
result = isc_refcount_init(&view->references, 1);
|
result = isc_refcount_init(&view->references, 1);
|
||||||
if (result != ISC_R_SUCCESS)
|
if (result != ISC_R_SUCCESS) {
|
||||||
goto cleanup_fwdtable;
|
goto cleanup_fwdtable;
|
||||||
view->weakrefs = 0;
|
}
|
||||||
|
result = isc_refcount_init(&view->weakrefs, 0);
|
||||||
|
if (result != ISC_R_SUCCESS) {
|
||||||
|
goto cleanup_references;
|
||||||
|
}
|
||||||
view->attributes = (DNS_VIEWATTR_RESSHUTDOWN|DNS_VIEWATTR_ADBSHUTDOWN|
|
view->attributes = (DNS_VIEWATTR_RESSHUTDOWN|DNS_VIEWATTR_ADBSHUTDOWN|
|
||||||
DNS_VIEWATTR_REQSHUTDOWN);
|
DNS_VIEWATTR_REQSHUTDOWN);
|
||||||
view->statickeys = NULL;
|
view->statickeys = NULL;
|
||||||
@@ -169,7 +173,7 @@ dns_view_create(isc_mem_t *mctx, dns_rdataclass_t rdclass,
|
|||||||
view->matchrecursiveonly = false;
|
view->matchrecursiveonly = false;
|
||||||
result = dns_tsigkeyring_create(view->mctx, &view->dynamickeys);
|
result = dns_tsigkeyring_create(view->mctx, &view->dynamickeys);
|
||||||
if (result != ISC_R_SUCCESS)
|
if (result != ISC_R_SUCCESS)
|
||||||
goto cleanup_references;
|
goto cleanup_weakrefs;
|
||||||
view->peers = NULL;
|
view->peers = NULL;
|
||||||
view->order = NULL;
|
view->order = NULL;
|
||||||
view->delonly = NULL;
|
view->delonly = NULL;
|
||||||
@@ -318,6 +322,9 @@ dns_view_create(isc_mem_t *mctx, dns_rdataclass_t rdclass,
|
|||||||
dns_tsigkeyring_detach(&view->dynamickeys);
|
dns_tsigkeyring_detach(&view->dynamickeys);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cleanup_weakrefs:
|
||||||
|
isc_refcount_destroy(&view->weakrefs);
|
||||||
|
|
||||||
cleanup_references:
|
cleanup_references:
|
||||||
isc_refcount_decrement(&view->references, NULL);
|
isc_refcount_decrement(&view->references, NULL);
|
||||||
isc_refcount_destroy(&view->references);
|
isc_refcount_destroy(&view->references);
|
||||||
@@ -354,12 +361,13 @@ destroy(dns_view_t *view) {
|
|||||||
dns_dlzdb_t *dlzdb;
|
dns_dlzdb_t *dlzdb;
|
||||||
|
|
||||||
REQUIRE(!ISC_LINK_LINKED(view, link));
|
REQUIRE(!ISC_LINK_LINKED(view, link));
|
||||||
REQUIRE(isc_refcount_current(&view->references) == 0);
|
|
||||||
REQUIRE(view->weakrefs == 0);
|
|
||||||
REQUIRE(RESSHUTDOWN(view));
|
REQUIRE(RESSHUTDOWN(view));
|
||||||
REQUIRE(ADBSHUTDOWN(view));
|
REQUIRE(ADBSHUTDOWN(view));
|
||||||
REQUIRE(REQSHUTDOWN(view));
|
REQUIRE(REQSHUTDOWN(view));
|
||||||
|
|
||||||
|
isc_refcount_destroy(&view->references);
|
||||||
|
isc_refcount_destroy(&view->weakrefs);
|
||||||
|
|
||||||
if (view->order != NULL)
|
if (view->order != NULL)
|
||||||
dns_order_detach(&view->order);
|
dns_order_detach(&view->order);
|
||||||
if (view->peers != NULL)
|
if (view->peers != NULL)
|
||||||
@@ -554,6 +562,7 @@ destroy(dns_view_t *view) {
|
|||||||
DESTROYLOCK(&view->new_zone_lock);
|
DESTROYLOCK(&view->new_zone_lock);
|
||||||
DESTROYLOCK(&view->lock);
|
DESTROYLOCK(&view->lock);
|
||||||
isc_refcount_destroy(&view->references);
|
isc_refcount_destroy(&view->references);
|
||||||
|
isc_refcount_destroy(&view->weakrefs);
|
||||||
isc_mem_free(view->mctx, view->nta_file);
|
isc_mem_free(view->mctx, view->nta_file);
|
||||||
isc_mem_free(view->mctx, view->name);
|
isc_mem_free(view->mctx, view->name);
|
||||||
isc_mem_putanddetach(&view->mctx, view, sizeof(*view));
|
isc_mem_putanddetach(&view->mctx, view, sizeof(*view));
|
||||||
@@ -567,9 +576,11 @@ static bool
|
|||||||
all_done(dns_view_t *view) {
|
all_done(dns_view_t *view) {
|
||||||
|
|
||||||
if (isc_refcount_current(&view->references) == 0 &&
|
if (isc_refcount_current(&view->references) == 0 &&
|
||||||
view->weakrefs == 0 &&
|
isc_refcount_current(&view->weakrefs) == 0 &&
|
||||||
RESSHUTDOWN(view) && ADBSHUTDOWN(view) && REQSHUTDOWN(view))
|
RESSHUTDOWN(view) && ADBSHUTDOWN(view) && REQSHUTDOWN(view))
|
||||||
|
{
|
||||||
return (true);
|
return (true);
|
||||||
|
}
|
||||||
|
|
||||||
return (false);
|
return (false);
|
||||||
}
|
}
|
||||||
@@ -679,9 +690,7 @@ dns_view_weakattach(dns_view_t *source, dns_view_t **targetp) {
|
|||||||
REQUIRE(DNS_VIEW_VALID(source));
|
REQUIRE(DNS_VIEW_VALID(source));
|
||||||
REQUIRE(targetp != NULL && *targetp == NULL);
|
REQUIRE(targetp != NULL && *targetp == NULL);
|
||||||
|
|
||||||
LOCK(&source->lock);
|
isc_refcount_increment0(&source->weakrefs, NULL);
|
||||||
source->weakrefs++;
|
|
||||||
UNLOCK(&source->lock);
|
|
||||||
|
|
||||||
*targetp = source;
|
*targetp = source;
|
||||||
}
|
}
|
||||||
@@ -689,24 +698,23 @@ dns_view_weakattach(dns_view_t *source, dns_view_t **targetp) {
|
|||||||
void
|
void
|
||||||
dns_view_weakdetach(dns_view_t **viewp) {
|
dns_view_weakdetach(dns_view_t **viewp) {
|
||||||
dns_view_t *view;
|
dns_view_t *view;
|
||||||
bool done = false;
|
unsigned int weakrefs;
|
||||||
|
|
||||||
REQUIRE(viewp != NULL);
|
REQUIRE(viewp != NULL);
|
||||||
view = *viewp;
|
view = *viewp;
|
||||||
REQUIRE(DNS_VIEW_VALID(view));
|
REQUIRE(DNS_VIEW_VALID(view));
|
||||||
|
|
||||||
LOCK(&view->lock);
|
|
||||||
|
|
||||||
INSIST(view->weakrefs > 0);
|
|
||||||
view->weakrefs--;
|
|
||||||
done = all_done(view);
|
|
||||||
|
|
||||||
UNLOCK(&view->lock);
|
|
||||||
|
|
||||||
*viewp = NULL;
|
*viewp = NULL;
|
||||||
|
|
||||||
if (done)
|
isc_refcount_decrement(&view->weakrefs, &weakrefs);
|
||||||
destroy(view);
|
if (weakrefs == 0) {
|
||||||
|
bool done = false;
|
||||||
|
LOCK(&view->lock);
|
||||||
|
done = all_done(view);
|
||||||
|
UNLOCK(&view->lock);
|
||||||
|
if (done) {
|
||||||
|
destroy(view);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|||||||
Reference in New Issue
Block a user