2
0
mirror of https://gitlab.isc.org/isc-projects/bind9 synced 2025-08-29 05:28:00 +00:00

Fixed multiple shutdown cleanup bugs in the zone object. This

involved extensive restructuring of the reference counting of
zones and related objects.

Zones now attach to their views.  To avoid a circular dependency that
would keep views from ever shutting down, this is done using the new
functions dns_view_weakattach() / dns_view_weakdetach() which
guarantee that the view will not be freed but still allow it
to be shut down.

The zones themselves now only have a single reference count, with
similar "weak" semantics.  Managed zones must now be shut down
explicitly by calling dns_zone_shutdown().  To shut down all
zones in a zone table, call dns_zt_shutdown().

The zone manager is now reference counted, weakly. To shut down the
zone manager, you must explicitly call dns_zonemgr_shutdown().
This commit is contained in:
Andreas Gustafsson 2000-05-17 19:45:36 +00:00
parent bc436be071
commit 22608315e8
8 changed files with 304 additions and 219 deletions

View File

@ -524,7 +524,8 @@ configure_view(dns_view_t *view, dns_c_ctx_t *cctx, dns_c_view_t *cview,
* there is no "version" configuration option.
*/
static isc_result_t
create_version_view(dns_c_ctx_t *cctx, dns_view_t **viewp) {
create_version_view(dns_c_ctx_t *cctx, dns_zonemgr_t *zmgr, dns_view_t **viewp)
{
isc_result_t result;
dns_db_t *db = NULL;
dns_zone_t *zone = NULL;
@ -564,6 +565,7 @@ create_version_view(dns_c_ctx_t *cctx, dns_view_t **viewp) {
CHECK(dns_zone_create(&zone, ns_g_mctx));
CHECK(dns_zone_setorigin(zone, &origin));
CHECK(dns_zonemgr_managezone(zmgr, zone));
CHECK(dns_db_create(ns_g_mctx, "rbt", &origin, ISC_FALSE,
dns_rdataclass_ch, 0, NULL, &db));
@ -1253,7 +1255,7 @@ load_configuration(const char *filename, ns_server_t *server,
* Create (or recreate) the version view.
*/
view = NULL;
CHECK(create_version_view(cctx, &view));
CHECK(create_version_view(cctx, server->zonemgr, &view));
ISC_LIST_APPEND(lctx.viewlist, view, link);
view = NULL;
@ -1447,9 +1449,12 @@ shutdown_server(isc_task_t *task, isc_event_t *event) {
dns_dispatch_detach(&server->querysrc_dispatchv6);
ns_clientmgr_destroy(&server->clientmgr);
isc_timer_detach(&server->interface_timer);
ns_interfacemgr_shutdown(server->interfacemgr);
ns_interfacemgr_detach(&server->interfacemgr);
dns_zonemgr_shutdown(server->zonemgr);
dns_zonemgr_detach(&server->zonemgr);
isc_task_detach(&server->task);
@ -1551,9 +1556,6 @@ ns_server_destroy(ns_server_t **serverp) {
INSIST(ISC_LIST_EMPTY(server->viewlist));
dns_zonemgr_destroy(&server->zonemgr);
server->zonemgr = NULL;
dns_db_detach(&server->in_roothints);
dns_aclenv_destroy(&server->aclenv);

View File

@ -110,6 +110,7 @@ struct dns_view {
dns_acl_t * matchclients;
/* Locked by lock. */
unsigned int references;
unsigned int weakrefs;
unsigned int attributes;
/* Under owner's locking control. */
ISC_LINK(struct dns_view) link;
@ -165,10 +166,44 @@ dns_view_attach(dns_view_t *source, dns_view_t **targetp);
* Ensures:
*
* *targetp is attached to source.
*
* While *targetp is attached, the view will not shut down.
*/
void
dns_view_detach(dns_view_t **viewp);
/*
* Detach '*viewp' from its view.
*
* Requires:
*
* 'viewp' points to a valid dns_view_t *
*
* Ensures:
*
* *viewp is NULL.
*/
void
dns_view_weakattach(dns_view_t *source, dns_view_t **targetp);
/*
* Weakly attach '*targetp' to 'source'.
*
* Requires:
*
* 'source' is a valid, frozen view.
*
* 'targetp' points to a NULL dns_view_t *.
*
* Ensures:
*
* *targetp is attached to source.
*
* While *targetp is attached, the view will not be freed.
*/
void
dns_view_weakdetach(dns_view_t **targetp);
/*
* Detach '*viewp' from its view.
*
@ -179,10 +214,6 @@ dns_view_detach(dns_view_t **viewp);
* Ensures:
*
* *viewp is NULL.
*
* If '*viewp' is the last reference to the view,
*
* All resources used by the view will be freed.
*/
isc_result_t

View File

@ -200,30 +200,6 @@ dns_zone_detach(dns_zone_t **zonep);
* 'zonep' to point to a valid initalised zone.
*/
void
dns_zone_iattach(dns_zone_t *source, dns_zone_t **target);
/*
* Attach 'zone' to 'target' incrementing its internal
* reference count. This is intended for use by operations
* such as zone transfers that need to prevent the zone
* object from being freed but not from shutting down.
*
* Require:
* 'zone' to be a valid initalised zone.
* 'target' to be non NULL and '*target' to be NULL.
*/
void
dns_zone_idetach(dns_zone_t **zonep);
/*
* Detach from a zone decrementing its internal reference count.
* If there are no more internal or external references to the
* zone, it will be freed.
*
* Require:
* 'zonep' to point to a valid initalised zone.
*/
void
dns_zone_setflag(dns_zone_t *zone, unsigned int flags, isc_boolean_t value);
/*
@ -811,6 +787,12 @@ dns_zone_getmctx(dns_zone_t *zone);
dns_zonemgr_t *
dns_zone_getmgr(dns_zone_t *zone);
void
dns_zone_shutdown(dns_zone_t *zone);
/*
* Initiate shutdown for a zone.
*/
isc_result_t
dns_zonemgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr,
isc_timermgr_t *timermgr, isc_socketmgr_t *socketmgr,
@ -845,15 +827,16 @@ dns_zonemgr_forcemaint(dns_zonemgr_t *zmgr);
void
dns_zonemgr_shutdown(dns_zonemgr_t *zmgr);
/*
* Shut down and detach the task of the zone manager.
* Shut down the zone manager.
*/
void
dns_zonemgr_destroy(dns_zonemgr_t **zmgrp);
dns_zonemgr_detach(dns_zonemgr_t **zmgrp);
/*
* Destroy a zone manager.
* Detach from a zone manager.
*
* Requires:
*
* '*zmgrp' is a valid, non-NULL zone manager pointer.
* Ensures:
* '*zmgrp' is NULL.

View File

@ -134,6 +134,15 @@ dns_zt_print(dns_zt_t *zt);
* 'zt' to be valid.
*/
void
dns_zt_shutdown(dns_zt_t *zt);
/*
* Shut down all zones in the table.
*
* Requires
* 'zt' to be valid.
*/
isc_result_t
dns_zt_apply(dns_zt_t *zt, isc_boolean_t stop,
isc_result_t (*action)(dns_zone_t *, void *), void *uap);

View File

@ -121,6 +121,7 @@ dns_view_create(isc_mem_t *mctx, dns_rdataclass_t rdclass,
view->frozen = ISC_FALSE;
view->task = NULL;
view->references = 1;
view->weakrefs = 0;
view->attributes = (DNS_VIEWATTR_RESSHUTDOWN|DNS_VIEWATTR_ADBSHUTDOWN|
DNS_VIEWATTR_REQSHUTDOWN);
view->statickeys = NULL;
@ -188,31 +189,11 @@ dns_view_create(isc_mem_t *mctx, dns_rdataclass_t rdclass,
return (result);
}
void
dns_view_attach(dns_view_t *source, dns_view_t **targetp) {
/*
* Attach '*targetp' to 'source'.
*/
REQUIRE(DNS_VIEW_VALID(source));
REQUIRE(targetp != NULL && *targetp == NULL);
LOCK(&source->lock);
INSIST(source->references > 0);
source->references++;
INSIST(source->references != 0);
UNLOCK(&source->lock);
*targetp = source;
}
static inline void
destroy(dns_view_t *view) {
REQUIRE(!ISC_LINK_LINKED(view, link));
REQUIRE(view->references == 0);
REQUIRE(view->weakrefs == 0);
REQUIRE(RESSHUTDOWN(view));
REQUIRE(ADBSHUTDOWN(view));
REQUIRE(REQSHUTDOWN(view));
@ -257,22 +238,35 @@ all_done(dns_view_t *view) {
* Caller must be holding the view lock.
*/
if (view->references == 0 && RESSHUTDOWN(view) &&
ADBSHUTDOWN(view) && REQSHUTDOWN(view))
if (view->references == 0 && view->weakrefs == 0 &&
RESSHUTDOWN(view) && ADBSHUTDOWN(view) && REQSHUTDOWN(view))
return (ISC_TRUE);
return (ISC_FALSE);
}
void
dns_view_attach(dns_view_t *source, dns_view_t **targetp) {
REQUIRE(DNS_VIEW_VALID(source));
REQUIRE(targetp != NULL && *targetp == NULL);
LOCK(&source->lock);
INSIST(source->references > 0);
source->references++;
INSIST(source->references != 0);
UNLOCK(&source->lock);
*targetp = source;
}
void
dns_view_detach(dns_view_t **viewp) {
dns_view_t *view;
isc_boolean_t done = ISC_FALSE;
/*
* Detach '*viewp' from its view.
*/
REQUIRE(viewp != NULL);
view = *viewp;
REQUIRE(DNS_VIEW_VALID(view));
@ -288,6 +282,7 @@ dns_view_detach(dns_view_t **viewp) {
dns_adb_shutdown(view->adb);
if (!REQSHUTDOWN(view))
dns_requestmgr_shutdown(view->requestmgr);
dns_zt_shutdown(view->zonetable);
done = all_done(view);
}
UNLOCK(&view->lock);
@ -298,6 +293,42 @@ dns_view_detach(dns_view_t **viewp) {
destroy(view);
}
void
dns_view_weakattach(dns_view_t *source, dns_view_t **targetp) {
REQUIRE(DNS_VIEW_VALID(source));
REQUIRE(targetp != NULL && *targetp == NULL);
LOCK(&source->lock);
source->weakrefs++;
UNLOCK(&source->lock);
*targetp = source;
}
void
dns_view_weakdetach(dns_view_t **viewp) {
dns_view_t *view;
isc_boolean_t done = ISC_FALSE;
REQUIRE(viewp != NULL);
view = *viewp;
REQUIRE(DNS_VIEW_VALID(view));
LOCK(&view->lock);
INSIST(view->weakrefs > 0);
view->weakrefs--;
done = all_done(view);
UNLOCK(&view->lock);
*viewp = NULL;
if (done)
destroy(view);
}
static void
resolver_shutdown(isc_task_t *task, isc_event_t *event) {
dns_view_t *view = event->ev_arg;

View File

@ -15,7 +15,7 @@
* SOFTWARE.
*/
/* $Id: xfrin.c,v 1.69 2000/05/14 20:01:27 gson Exp $ */
/* $Id: xfrin.c,v 1.70 2000/05/17 19:45:29 gson Exp $ */
#include <config.h>
@ -605,7 +605,7 @@ xfrin_create(isc_mem_t *mctx,
xfr->mctx = mctx;
xfr->refcount = 0;
xfr->zone = NULL;
dns_zone_iattach(zone, &xfr->zone);
dns_zone_attach(zone, &xfr->zone);
xfr->task = NULL;
isc_task_attach(task, &xfr->task);
xfr->timer = NULL;
@ -1180,7 +1180,7 @@ maybe_free(dns_xfrin_ctx_t *xfr) {
dns_db_detach(&xfr->db);
if (xfr->zone != NULL)
dns_zone_idetach(&xfr->zone);
dns_zone_detach(&xfr->zone);
isc_mem_put(xfr->mctx, xfr, sizeof(*xfr));
}

View File

@ -15,7 +15,7 @@
* SOFTWARE.
*/
/* $Id: zone.c,v 1.115 2000/05/14 23:23:37 gson Exp $ */
/* $Id: zone.c,v 1.116 2000/05/17 19:45:31 gson Exp $ */
#include <config.h>
@ -93,8 +93,7 @@ struct dns_zone {
dns_zonemgr_t *zmgr;
ISC_LINK(dns_zone_t) link; /* Used by zmgr. */
isc_timer_t *timer;
unsigned int erefs;
unsigned int irefs;
unsigned int refs;
dns_name_t origin;
char *dbname;
char *journal;
@ -178,6 +177,7 @@ struct dns_zone {
struct dns_zonemgr {
isc_mem_t * mctx;
int refs;
isc_taskmgr_t * taskmgr;
isc_timermgr_t * timermgr;
isc_socketmgr_t * socketmgr;
@ -223,7 +223,6 @@ static void zone_expire(dns_zone_t *zone);
static isc_result_t zone_replacedb(dns_zone_t *zone, dns_db_t *db,
isc_boolean_t dump);
static isc_result_t default_journal(dns_zone_t *zone);
static void releasezone(dns_zonemgr_t *zmgr, dns_zone_t *zone);
static void xfrdone(dns_zone_t *zone, isc_result_t result);
static void zone_shutdown(isc_task_t *, isc_event_t *);
@ -247,15 +246,18 @@ static isc_result_t zone_dump(dns_zone_t *);
static void got_transfer_quota(isc_task_t *task, isc_event_t *event);
static isc_result_t zmgr_start_xfrin_ifquota(dns_zonemgr_t *zmgr, dns_zone_t *zone);
static void zmgr_resume_xfrs(dns_zonemgr_t *zmgr);
static void zonemgr_free(dns_zonemgr_t *zmgr);
#define PRINT_ZONE_REF(zone) \
do { \
char *s = NULL; \
isc_result_t r; \
r = dns_zone_tostr(zone, zone->mctx, &s); \
if (r == ISC_R_SUCCESS) { \
printf("%p: %s: erefs = %d\n", zone, s, \
zone->erefs); \
printf("%p: %s: refs = %d\n", zone, s, \
zone->refs); \
isc_mem_free(zone->mctx, s); \
} \
} while (0)
@ -302,8 +304,7 @@ dns_zone_create(dns_zone_t **zonep, isc_mem_t *mctx) {
zone->db = NULL;
zone->zmgr = NULL;
ISC_LINK_INIT(zone, link);
zone->erefs = 1; /* Implicit attach. */
zone->irefs = 0;
zone->refs = 1; /* Implicit attach. */
dns_name_init(&zone->origin, NULL);
zone->dbname = NULL;
zone->journalsize = -1;
@ -364,7 +365,7 @@ zone_free(dns_zone_t *zone) {
REQUIRE(DNS_ZONE_VALID(zone));
LOCK(&zone->lock);
REQUIRE(zone->erefs == 0);
REQUIRE(zone->refs == 0);
zone->flags |= DNS_ZONE_F_EXITING;
UNLOCK(&zone->lock);
@ -379,13 +380,14 @@ zone_free(dns_zone_t *zone) {
dns_request_cancel(zone->request); /* XXXMPA */
dns_request_destroy(&zone->request); /* XXXMPA */
}
INSIST(zone->statelist == NULL);
if (zone->task != NULL)
isc_task_detach(&zone->task);
if (zone->zmgr)
dns_zonemgr_releasezone(zone->zmgr, zone);
INSIST(zone->statelist == NULL);
/* Unmanaged objects */
if (zone->dbname != NULL)
isc_mem_free(zone->mctx, zone->dbname);
@ -484,7 +486,7 @@ dns_zone_setdbtype(dns_zone_t *zone, char *db_type) {
void
dns_zone_setview(dns_zone_t *zone, dns_view_t *view) {
zone->view = view;
dns_view_weakattach(view, &zone->view);
}
@ -856,93 +858,74 @@ dns_zone_load(dns_zone_t *zone) {
static void
exit_check(dns_zone_t *zone) {
if (zone->irefs == 0 && DNS_ZONE_FLAG(zone, DNS_ZONE_F_EXITING))
if (zone->refs == 0)
zone_free(zone);
}
void
dns_zone_shutdown(dns_zone_t *zone) {
REQUIRE(DNS_ZONE_VALID(zone));
LOCK(&zone->lock);
REQUIRE(zone->refs > 0);
if (zone->task != NULL) {
/*
* This zone is being managed. Post
* its control event and let it clean
* up synchronously in the context of
* its task.
*/
isc_event_t *ev = &zone->ctlevent;
isc_task_send(zone->task, &ev);
} else {
/*
* Unmanaged zones should not have non-null views;
* we have no way of detaching from the view here
* without causing deadlock because this code is called
* with the view already locked.
*/
INSIST(zone->view != NULL);
}
UNLOCK(&zone->lock);
}
static void
zone_attach(dns_zone_t *source, dns_zone_t **target) {
REQUIRE(DNS_ZONE_VALID(source));
REQUIRE(target != NULL && *target == NULL);
source->refs++;
INSIST(source->refs != 0xffffffffU);
*target = source;
}
void
dns_zone_attach(dns_zone_t *source, dns_zone_t **target) {
REQUIRE(DNS_ZONE_VALID(source));
REQUIRE(target != NULL && *target == NULL);
LOCK(&source->lock);
REQUIRE(source->erefs > 0);
source->erefs++;
INSIST(source->erefs != 0xffffffffU);
zone_attach(source, target);
UNLOCK(&source->lock);
*target = source;
}
static void
zone_detach(dns_zone_t **zonep) {
dns_zone_t *zone;
REQUIRE(zonep != NULL && DNS_ZONE_VALID(*zonep));
zone = *zonep;
REQUIRE(zone->refs > 0);
zone->refs--;
*zonep = NULL;
}
void
dns_zone_detach(dns_zone_t **zonep) {
dns_zone_t *zone;
isc_boolean_t free_now = ISC_FALSE;
REQUIRE(zonep != NULL && DNS_ZONE_VALID(*zonep));
zone = *zonep;
LOCK(&zone->lock);
REQUIRE(zone->erefs > 0);
zone->erefs--;
if (zone->erefs == 0) {
if (zone->task != NULL) {
/*
* This zone is being managed. Post
* its control event and let it clean
* up synchronously in the context of
* its task.
*/
isc_event_t *ev = &zone->ctlevent;
isc_task_send(zone->task, &ev);
} else {
/*
* This zone is not being managed; it has
* no task and can have no outstanding
* events. Free it immediately.
*/
free_now = ISC_TRUE;
}
}
UNLOCK(&zone->lock);
if (free_now)
zone_free(zone);
*zonep = NULL;
}
static void
zone_iattach(dns_zone_t *source, dns_zone_t **target) {
REQUIRE(DNS_ZONE_VALID(source));
REQUIRE(target != NULL && *target == NULL);
source->irefs++;
INSIST(source->irefs != 0xffffffffU);
*target = source;
}
void
dns_zone_iattach(dns_zone_t *source, dns_zone_t **target) {
REQUIRE(DNS_ZONE_VALID(source));
LOCK(&source->lock);
zone_iattach(source, target);
UNLOCK(&source->lock);
}
static void
zone_idetach(dns_zone_t **zonep) {
dns_zone_t *zone;
REQUIRE(zonep != NULL && DNS_ZONE_VALID(*zonep));
zone = *zonep;
REQUIRE(zone->irefs > 0);
zone->irefs--;
*zonep = NULL;
}
void
dns_zone_idetach(dns_zone_t **zonep) {
dns_zone_t *zone;
REQUIRE(zonep != NULL && DNS_ZONE_VALID(*zonep));
zone = *zonep;
LOCK(&zone->lock);
zone_idetach(zonep);
zone_detach(zonep);
UNLOCK(&zone->lock);
exit_check(zone);
}
@ -1483,7 +1466,8 @@ notify_destroy(notify_t *notify) {
if (notify->zone != NULL) {
if (ISC_LINK_LINKED(notify, link))
ISC_LIST_UNLINK(notify->zone->notifies, notify, link);
zone_idetach(&notify->zone);
zone_detach(&notify->zone);
/* XXXAG exit_check */
}
if (notify->find != NULL)
dns_adb_destroyfind(&notify->find);
@ -1530,7 +1514,7 @@ process_adb_event(isc_task_t *task, isc_event_t *ev) {
REQUIRE(DNS_NOTIFY_VALID(notify));
result = ev->ev_type;
isc_event_free(&ev);
dns_zone_iattach(notify->zone, &zone);
dns_zone_attach(notify->zone, &zone);
if (result == DNS_EVENT_ADBNOMOREADDRESSES) {
LOCK(&notify->zone->lock);
notify_send(notify);
@ -1546,7 +1530,7 @@ process_adb_event(isc_task_t *task, isc_event_t *ev) {
notify_destroy(notify);
UNLOCK(&zone->lock);
detach:
dns_zone_idetach(&zone);
dns_zone_detach(&zone);
}
static void
@ -1559,7 +1543,7 @@ notify_find_address(notify_t *notify) {
options = DNS_ADBFIND_WANTEVENT | DNS_ADBFIND_INET |
DNS_ADBFIND_INET6 | DNS_ADBFIND_RETURNLAME;
dns_zone_iattach(notify->zone, &zone);
dns_zone_attach(notify->zone, &zone);
result = dns_adb_createfind(zone->view->adb,
zone->task,
process_adb_event, notify,
@ -1571,13 +1555,13 @@ notify_find_address(notify_t *notify) {
LOCK(&zone->lock);
notify_destroy(notify);
UNLOCK(&zone->lock);
dns_zone_idetach(&zone);
dns_zone_detach(&zone);
return;
}
/* More addresses pending? */
if ((notify->find->options & DNS_ADBFIND_WANTEVENT) != 0) {
dns_zone_idetach(&zone);
dns_zone_detach(&zone);
return;
}
@ -1585,7 +1569,7 @@ notify_find_address(notify_t *notify) {
LOCK(&zone->lock);
notify_send(notify);
UNLOCK(&zone->lock);
dns_zone_idetach(&zone);
dns_zone_detach(&zone);
}
@ -1621,7 +1605,7 @@ notify_send_toaddr(isc_task_t *task, isc_event_t *event) {
UNUSED(task);
LOCK(&notify->zone->lock);
zone_iattach(notify->zone, &zone);
zone_attach(notify->zone, &zone);
if ((event->ev_attributes & ISC_EVENTATTR_CANCELED) != 0 ||
DNS_ZONE_FLAG(notify->zone, DNS_ZONE_F_EXITING)) {
result = ISC_R_CANCELED;
@ -1640,7 +1624,7 @@ notify_send_toaddr(isc_task_t *task, isc_event_t *event) {
if (result != ISC_R_SUCCESS)
notify_destroy(notify);
UNLOCK(&zone->lock);
dns_zone_idetach(&zone);
dns_zone_detach(&zone);
isc_event_free(&event);
}
@ -1670,7 +1654,7 @@ notify_send(notify_t *notify) {
result = notify_create(notify->mctx, &new);
if (result != ISC_R_SUCCESS)
goto cleanup;
zone_iattach(notify->zone, &new->zone);
zone_attach(notify->zone, &new->zone);
ISC_LIST_APPEND(new->zone->notifies, new, link);
new->dst = dst;
result = notify_send_queue(new);
@ -1729,7 +1713,7 @@ dns_zone_notify(dns_zone_t *zone) {
result = notify_create(zone->mctx, &notify);
if (result != ISC_R_SUCCESS)
goto cleanup0;
dns_zone_iattach(zone, &notify->zone);
dns_zone_attach(zone, &notify->zone);
notify->dst = zone->notify[i];
if (isc_sockaddr_getport(&notify->dst) == 0)
isc_sockaddr_setport(&notify->dst, 53); /* XXX */
@ -1810,7 +1794,7 @@ dns_zone_notify(dns_zone_t *zone) {
dns_rdata_freestruct(&ns);
continue;
}
dns_zone_iattach(zone, &notify->zone);
dns_zone_attach(zone, &notify->zone);
result = dns_name_dup(&ns.name, zone->mctx, &notify->ns);
dns_rdata_freestruct(&ns);
if (result != ISC_R_SUCCESS) {
@ -2050,7 +2034,7 @@ queue_soa_query(dns_zone_t *zone) {
cancel_refresh(zone);
return;
}
dns_zone_iattach(zone, &dummy); /*
dns_zone_attach(zone, &dummy); /*
* Attach so that we won't clean up
* until the event is delivered.
*/
@ -2058,7 +2042,7 @@ queue_soa_query(dns_zone_t *zone) {
e->ev_sender = zone;
result = isc_ratelimiter_enqueue(zone->zmgr->rl, &e);
if (result != ISC_R_SUCCESS) {
dns_zone_idetach(&dummy);
dns_zone_detach(&dummy);
isc_event_free(&e);
cancel_refresh(zone);
}
@ -2084,7 +2068,7 @@ soa_query(isc_task_t *task, isc_event_t *event) {
if (!DNS_ZONE_FLAG(zone, DNS_ZONE_F_EXITING))
cancel_refresh(zone);
isc_event_free(&event);
dns_zone_idetach(&zone);
dns_zone_detach(&zone);
return;
}
@ -2139,7 +2123,7 @@ soa_query(isc_task_t *task, isc_event_t *event) {
}
dns_message_destroy(&message);
isc_event_free(&event);
dns_zone_idetach(&zone);
dns_zone_detach(&zone);
return;
cleanup:
@ -2151,7 +2135,7 @@ soa_query(isc_task_t *task, isc_event_t *event) {
dns_message_destroy(&message);
cancel_refresh(zone);
isc_event_free(&event);
dns_zone_idetach(&zone);
dns_zone_detach(&zone);
return;
}
@ -2167,7 +2151,6 @@ zone_shutdown(isc_task_t *task, isc_event_t *event) {
UNUSED(task);
REQUIRE(DNS_ZONE_VALID(zone));
INSIST(event->ev_type == DNS_EVENT_ZONECONTROL);
INSIST(zone->erefs == 0);
zone_log(zone, "zone_shutdown", ISC_LOG_DEBUG(3), "shutting down");
LOCK(&zone->lock);
zone->flags |= DNS_ZONE_F_EXITING;
@ -2199,6 +2182,10 @@ zone_shutdown(isc_task_t *task, isc_event_t *event) {
if (notify->request != NULL)
dns_request_cancel(notify->request);
}
if (zone->view != NULL)
dns_view_weakdetach(&zone->view);
exit_check(zone);
}
@ -2862,13 +2849,13 @@ notify_done(isc_task_t *task, isc_event_t *event) {
notify = event->ev_arg;
REQUIRE(DNS_NOTIFY_VALID(notify));
dns_zone_iattach(notify->zone, &zone);
dns_zone_attach(notify->zone, &zone);
DNS_ENTER;
isc_event_free(&event);
LOCK(&zone->lock);
notify_destroy(notify);
UNLOCK(&zone->lock);
dns_zone_idetach(&zone);
dns_zone_detach(&zone);
}
@ -3091,13 +3078,14 @@ xfrdone(dns_zone_t *zone, isc_result_t result) {
RWLOCK(&zone->zmgr->rwlock, isc_rwlocktype_write);
ISC_LIST_UNLINK(zone->zmgr->xfrin_in_progress, zone, statelink);
zone->statelist = NULL;
zmgr_resume_xfrs(zone->zmgr);
if (!DNS_ZONE_FLAG(zone, DNS_ZONE_F_EXITING))
zmgr_resume_xfrs(zone->zmgr);
RWUNLOCK(&zone->zmgr->rwlock, isc_rwlocktype_write);
/*
* Retry with a different server if necessary.
*/
if (again)
if (again && !DNS_ZONE_FLAG(zone, DNS_ZONE_F_EXITING))
queue_soa_query(zone);
}
@ -3226,10 +3214,15 @@ got_transfer_quota(isc_task_t *task, isc_event_t *event) {
tsigkey, zone->mctx,
zone->zmgr->timermgr, zone->zmgr->socketmgr,
zone->task, xfrdone, &zone->xfr);
cleanup:
/*
* Any failure in this function is handled like a failed
* zone transfer. This ensures that we get removed from
* zmgr->xfrin_in_progress.
*/
if (result != ISC_R_SUCCESS)
xfrdone(zone, result);
cleanup:
isc_event_free(&event);
dns_zone_detach(&zone);
@ -3254,6 +3247,7 @@ dns_zonemgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr,
if (zmgr == NULL)
return (ISC_R_NOMEMORY);
zmgr->mctx = NULL;
zmgr->refs = 1;
isc_mem_attach(mctx, &zmgr->mctx);
zmgr->taskmgr = taskmgr;
zmgr->timermgr = timermgr;
@ -3339,6 +3333,13 @@ dns_zonemgr_managezone(dns_zonemgr_t *zmgr, dns_zone_t *zone) {
ISC_FALSE),
&zone->task);
/*
* Set the task name. The tag will arbitrarily point to one
* of the zones sharing the task (in practice, the one
* to be managed last).
*/
isc_task_setname(zone->task, "zone", zone);
result = isc_timer_create(zmgr->timermgr, isc_timertype_inactive,
NULL, NULL,
zmgr->task, zone_timer, zone,
@ -3346,8 +3347,9 @@ dns_zonemgr_managezone(dns_zonemgr_t *zmgr, dns_zone_t *zone) {
if (result != ISC_R_SUCCESS)
goto cleanup_task;
zone->zmgr = zmgr;
ISC_LIST_APPEND(zmgr->zones, zone, link);
zone->zmgr = zmgr;
zmgr->refs++;
goto unlock;
@ -3360,24 +3362,41 @@ dns_zonemgr_managezone(dns_zonemgr_t *zmgr, dns_zone_t *zone) {
return (result);
}
static void
releasezone(dns_zonemgr_t *zmgr, dns_zone_t *zone) {
/*
* Caller to lock zone and zmgr
*/
ISC_LIST_UNLINK(zmgr->zones, zone, link);
zone->zmgr = NULL;
}
void
dns_zonemgr_releasezone(dns_zonemgr_t *zmgr, dns_zone_t *zone) {
isc_boolean_t free_now = ISC_FALSE;
REQUIRE(DNS_ZONE_VALID(zone));
RWLOCK(&zmgr->rwlock, isc_rwlocktype_write);
LOCK(&zone->lock);
releasezone(zmgr, zone);
ISC_LIST_UNLINK(zmgr->zones, zone, link);
zone->zmgr = NULL;
zmgr->refs--;
if (zmgr->refs == 0)
free_now = ISC_TRUE;
UNLOCK(&zone->lock);
RWUNLOCK(&zmgr->rwlock, isc_rwlocktype_write);
if (free_now)
zonemgr_free(zmgr);
}
void
dns_zonemgr_detach(dns_zonemgr_t **zmgrp) {
dns_zonemgr_t *zmgr = *zmgrp;
isc_boolean_t free_now = ISC_FALSE;
RWLOCK(&zmgr->rwlock, isc_rwlocktype_write);
zmgr->refs--;
if (zmgr->refs == 0)
free_now = ISC_TRUE;
RWUNLOCK(&zmgr->rwlock, isc_rwlocktype_write);
if (free_now)
zonemgr_free(zmgr);
}
isc_result_t
@ -3397,39 +3416,28 @@ dns_zonemgr_forcemaint(dns_zonemgr_t *zmgr) {
void
dns_zonemgr_shutdown(dns_zonemgr_t *zmgr) {
if (zmgr->rl)
isc_ratelimiter_destroy(&zmgr->rl);
isc_ratelimiter_shutdown(zmgr->rl);
}
static void
zonemgr_free(dns_zonemgr_t *zmgr) {
isc_mem_t *mctx;
INSIST(zmgr->refs == 0);
INSIST(ISC_LIST_EMPTY(zmgr->zones));
if (zmgr->task != NULL)
isc_task_destroy(&zmgr->task);
if (zmgr->zonetasks != NULL)
isc_taskpool_destroy(&zmgr->zonetasks);
}
void
dns_zonemgr_destroy(dns_zonemgr_t **zmgrp) {
isc_mem_t *mctx;
dns_zonemgr_t *zmgr = *zmgrp;
dns_zone_t *zone;
RWLOCK(&zmgr->rwlock, isc_rwlocktype_write);
zone = ISC_LIST_HEAD(zmgr->zones);
while (zone != NULL) {
LOCK(&zone->lock);
releasezone(zmgr, zone);
UNLOCK(&zone->lock);
zone = ISC_LIST_HEAD(zmgr->zones);
}
RWUNLOCK(&zmgr->rwlock, isc_rwlocktype_write);
/* Probably done already, but does not hurt to repeat. */
dns_zonemgr_shutdown(zmgr);
isc_ratelimiter_destroy(&zmgr->rl);
isc_rwlock_destroy(&zmgr->conflock);
isc_rwlock_destroy(&zmgr->rwlock);
mctx = zmgr->mctx;
isc_mem_put(zmgr->mctx, zmgr, sizeof *zmgr);
isc_mem_detach(&mctx);
*zmgrp = NULL;
}
void
@ -3584,14 +3592,12 @@ zmgr_start_xfrin_ifquota(dns_zonemgr_t *zmgr, dns_zone_t *zone) {
ISC_LIST_UNLINK(zmgr->waiting_for_xfrin, zone, statelink);
ISC_LIST_APPEND(zmgr->xfrin_in_progress, zone, statelink);
zone->statelist = &zmgr->xfrin_in_progress;
isc_task_send(zone->task, &e);
/*
* Make sure the zone does not go away before it has processed
* the event; in effect, the event is attached to the zone.
* We must use erefs rather than irefs because accesses
* to irefs are not locked.
*/
zone->erefs++;
zone->refs++;
isc_task_send(zone->task, &e);
UNLOCK(&zone->lock);
return (ISC_R_SUCCESS);

View File

@ -34,7 +34,8 @@ struct dns_zt {
isc_rwlock_t rwlock;
/* Locked by lock. */
isc_uint32_t references;
dns_rbt_t *table;
dns_rbt_t *table;
isc_boolean_t shutdown; /* Has been shut down. */
};
#define ZTMAGIC 0x5a54626cU /* ZTbl */
@ -46,6 +47,9 @@ auto_detach(void *, void *);
static isc_result_t
load(dns_zone_t *zone, void *uap);
static isc_result_t
shutdown(dns_zone_t *zone, void *uap);
isc_result_t
dns_zt_create(isc_mem_t *mctx, dns_rdataclass_t rdclass, dns_zt_t **ztp) {
dns_zt_t *zt;
@ -58,7 +62,7 @@ dns_zt_create(isc_mem_t *mctx, dns_rdataclass_t rdclass, dns_zt_t **ztp) {
return (ISC_R_NOMEMORY);
zt->table = NULL;
result = dns_rbt_create(mctx, auto_detach, NULL, &zt->table);
result = dns_rbt_create(mctx, auto_detach, zt, &zt->table);
if (result != ISC_R_SUCCESS)
goto cleanup_zt;
@ -74,6 +78,7 @@ dns_zt_create(isc_mem_t *mctx, dns_rdataclass_t rdclass, dns_zt_t **ztp) {
zt->mctx = mctx;
zt->references = 1;
zt->rdclass = rdclass;
zt->shutdown = ISC_FALSE;
zt->magic = ZTMAGIC;
*ztp = zt;
@ -227,15 +232,37 @@ dns_zt_print(dns_zt_t *zt) {
isc_result_t
dns_zt_load(dns_zt_t *zt, isc_boolean_t stop) {
return (dns_zt_apply(zt, stop, load, NULL));
isc_result_t result;
RWLOCK(&zt->rwlock, isc_rwlocktype_read);
result = dns_zt_apply(zt, stop, load, NULL);
RWUNLOCK(&zt->rwlock, isc_rwlocktype_read);
return (result);
}
static isc_result_t
load(dns_zone_t *zone, void *uap) {
uap = uap;
UNUSED(uap);
return (dns_zone_load(zone));
}
void
dns_zt_shutdown(dns_zt_t *zt) {
RWLOCK(&zt->rwlock, isc_rwlocktype_write);
if (! zt->shutdown) {
(void)dns_zt_apply(zt, ISC_FALSE, shutdown, NULL);
zt->shutdown = ISC_TRUE;
}
RWUNLOCK(&zt->rwlock, isc_rwlocktype_write);
}
static isc_result_t
shutdown(dns_zone_t *zone, void *uap) {
UNUSED(uap);
dns_zone_shutdown(zone);
return (ISC_R_SUCCESS);
}
isc_result_t
dns_zt_apply(dns_zt_t *zt, isc_boolean_t stop,
isc_result_t (*action)(dns_zone_t *, void *), void *uap)
@ -248,8 +275,6 @@ dns_zt_apply(dns_zt_t *zt, isc_boolean_t stop,
REQUIRE(VALID_ZT(zt));
REQUIRE(action != NULL);
RWLOCK(&zt->rwlock, isc_rwlocktype_read);
dns_rbtnodechain_init(&chain, zt->mctx);
result = dns_rbtnodechain_first(&chain, zt->table, NULL, NULL);
if (result == ISC_R_NOTFOUND) {
@ -276,8 +301,6 @@ dns_zt_apply(dns_zt_t *zt, isc_boolean_t stop,
cleanup:
dns_rbtnodechain_invalidate(&chain);
RWUNLOCK(&zt->rwlock, isc_rwlocktype_read);
return (result);
}
@ -290,6 +313,6 @@ auto_detach(void *data, void *arg) {
dns_zone_t *zone = data;
UNUSED(arg);
dns_zone_detach(&zone);
}