2
0
mirror of https://gitlab.isc.org/isc-projects/bind9 synced 2025-08-31 14:35:26 +00:00

Reintroduced separate internal/external reference counts for zones,

reversing part of the changes made on 2000/05/17.  Doing an explicit
zone shutdown on destruction of the zone table caused the zone to
be shut down prematurely on server reload when the zone table was
destroyed but the zone had already been attached to a new zone table.
An external reference count is needed to correctly handle this situation.
This commit is contained in:
Andreas Gustafsson
2000-05-22 17:23:15 +00:00
parent cb726f24e7
commit cd01c9716f
5 changed files with 151 additions and 136 deletions

View File

@@ -200,6 +200,32 @@ 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:
* The caller is running in the context of the zone's task.
* '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:
* The caller is running in the context of the zone's task.
* 'zonep' to point to a valid initalised zone.
*/
void
dns_zone_setflag(dns_zone_t *zone, unsigned int flags, isc_boolean_t value);
/*
@@ -787,12 +813,6 @@ 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,

View File

@@ -134,15 +134,6 @@ 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

@@ -224,7 +224,6 @@ destroy(dns_view_t *view) {
dns_acl_detach(&view->queryacl);
if (view->recursionacl != NULL)
dns_acl_detach(&view->recursionacl);
dns_zt_detach(&view->zonetable);
dns_keytable_detach(&view->trustedkeys);
dns_keytable_detach(&view->secroots);
isc_mutex_destroy(&view->lock);
@@ -282,7 +281,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);
dns_zt_detach(&view->zonetable);
done = all_done(view);
}
UNLOCK(&view->lock);

View File

@@ -15,7 +15,7 @@
* SOFTWARE.
*/
/* $Id: zone.c,v 1.121 2000/05/20 21:24:41 gson Exp $ */
/* $Id: zone.c,v 1.122 2000/05/22 17:23:11 gson Exp $ */
#include <config.h>
@@ -90,7 +90,8 @@ struct dns_zone {
dns_zonemgr_t *zmgr;
ISC_LINK(dns_zone_t) link; /* Used by zmgr. */
isc_timer_t *timer;
unsigned int refs;
unsigned int erefs;
unsigned int irefs;
dns_name_t origin;
char *dbname;
char *journal;
@@ -257,8 +258,8 @@ zone_get_from_db(dns_db_t *db, dns_name_t *origin, unsigned int *nscount,
isc_result_t r; \
r = dns_zone_tostr(zone, zone->mctx, &s); \
if (r == ISC_R_SUCCESS) { \
printf("%p: %s: refs = %d\n", zone, s, \
zone->refs); \
printf("%p: %s: erefs=%d irefs=%d\n", zone, s, \
zone->erefs, zone->irefs); \
isc_mem_free(zone->mctx, s); \
} \
} while (0)
@@ -305,7 +306,8 @@ dns_zone_create(dns_zone_t **zonep, isc_mem_t *mctx) {
zone->db = NULL;
zone->zmgr = NULL;
ISC_LINK_INIT(zone, link);
zone->refs = 1; /* Implicit attach. */
zone->erefs = 1; /* Implicit attach. */
zone->irefs = 0;
dns_name_init(&zone->origin, NULL);
zone->dbname = NULL;
zone->journalsize = -1;
@@ -360,27 +362,25 @@ dns_zone_create(dns_zone_t **zonep, isc_mem_t *mctx) {
return (ISC_R_SUCCESS);
}
/*
* Free a zone. Because we require that there be no more
* outstanding events or references, no locking is necessary.
*/
static void
zone_free(dns_zone_t *zone) {
isc_mem_t *mctx = NULL;
REQUIRE(DNS_ZONE_VALID(zone));
LOCK(&zone->lock);
REQUIRE(zone->refs == 0);
zone->flags |= DNS_ZONE_F_EXITING;
UNLOCK(&zone->lock);
REQUIRE(zone->erefs == 0);
REQUIRE(zone->irefs == 0);
/*
* Managed objects. Order is important.
*/
if (DNS_ZONE_FLAG(zone, DNS_ZONE_F_REFRESH))
cancel_refresh(zone);
if (zone->timer != NULL)
isc_timer_detach(&zone->timer);
if (zone->request != NULL) {
dns_request_cancel(zone->request); /* XXXMPA */
dns_request_destroy(&zone->request); /* XXXMPA */
}
if (zone->request != NULL)
dns_request_destroy(&zone->request); /* XXXMPA */
INSIST(zone->statelist == NULL);
@@ -832,8 +832,15 @@ dns_zone_load(dns_zone_t *zone) {
static void
exit_check(dns_zone_t *zone) {
if (zone->refs == 0)
if (DNS_ZONE_FLAG(zone, DNS_ZONE_F_EXITING) &&
zone->irefs == 0)
{
/*
* DNS_ZONE_F_EXITING can only be set if erefs == 0.
*/
INSIST(zone->erefs == 0);
zone_free(zone);
}
}
static isc_result_t
@@ -971,71 +978,83 @@ zone_get_from_db(dns_db_t *db, dns_name_t *origin, unsigned int *nscount,
return (result);
}
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);
zone_attach(source, target);
REQUIRE(source->erefs > 0);
source->erefs++;
INSIST(source->erefs != 0);
UNLOCK(&source->lock);
}
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;
*target = source;
}
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) {
/*
* We just detached the last external reference.
*/
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.
*/
/*
* 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);
free_now = ISC_TRUE;
}
}
UNLOCK(&zone->lock);
*zonep = NULL;
if (free_now)
zone_free(zone);
}
void
dns_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 != 0);
*target = source;
}
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_detach(zonep);
UNLOCK(&zone->lock);
REQUIRE(zone->irefs > 0);
zone->irefs--;
*zonep = NULL;
exit_check(zone);
}
@@ -1411,14 +1430,14 @@ dns_zone_refresh(dns_zone_t *zone) {
REQUIRE(DNS_ZONE_VALID(zone));
isc_stdtime_get(&now);
if (DNS_ZONE_FLAG(zone, DNS_ZONE_F_EXITING))
return;
isc_stdtime_get(&now);
/*
* Set DNS_ZONE_F_REFRESH so that there is only one refresh operation
* in progress at the one time.
* in progress at a time.
*/
LOCK(&zone->lock);
@@ -1595,8 +1614,7 @@ notify_destroy(notify_t *notify) {
if (notify->zone != NULL) {
if (ISC_LINK_LINKED(notify, link))
ISC_LIST_UNLINK(notify->zone->notifies, notify, link);
zone_detach(&notify->zone);
/* XXXAG exit_check */
dns_zone_idetach(&notify->zone);
}
if (notify->find != NULL)
dns_adb_destroyfind(&notify->find);
@@ -1632,6 +1650,9 @@ notify_create(isc_mem_t *mctx, notify_t **notifyp) {
return (ISC_R_SUCCESS);
}
/*
* XXXAG should check for DNS_ZONE_F_EXITING
*/
static void
process_adb_event(isc_task_t *task, isc_event_t *ev) {
notify_t *notify;
@@ -1644,7 +1665,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_attach(notify->zone, &zone);
dns_zone_iattach(notify->zone, &zone);
if (result == DNS_EVENT_ADBNOMOREADDRESSES) {
LOCK(&notify->zone->lock);
notify_send(notify);
@@ -1660,7 +1681,7 @@ process_adb_event(isc_task_t *task, isc_event_t *ev) {
notify_destroy(notify);
UNLOCK(&zone->lock);
detach:
dns_zone_detach(&zone);
dns_zone_idetach(&zone);
}
static void
@@ -1673,7 +1694,7 @@ notify_find_address(notify_t *notify) {
options = DNS_ADBFIND_WANTEVENT | DNS_ADBFIND_INET |
DNS_ADBFIND_INET6 | DNS_ADBFIND_RETURNLAME;
dns_zone_attach(notify->zone, &zone);
dns_zone_iattach(notify->zone, &zone);
result = dns_adb_createfind(zone->view->adb,
zone->task,
process_adb_event, notify,
@@ -1685,13 +1706,13 @@ notify_find_address(notify_t *notify) {
LOCK(&zone->lock);
notify_destroy(notify);
UNLOCK(&zone->lock);
dns_zone_detach(&zone);
dns_zone_idetach(&zone);
return;
}
/* More addresses pending? */
if ((notify->find->options & DNS_ADBFIND_WANTEVENT) != 0) {
dns_zone_detach(&zone);
dns_zone_idetach(&zone);
return;
}
@@ -1699,7 +1720,7 @@ notify_find_address(notify_t *notify) {
LOCK(&zone->lock);
notify_send(notify);
UNLOCK(&zone->lock);
dns_zone_detach(&zone);
dns_zone_idetach(&zone);
}
@@ -1736,7 +1757,7 @@ notify_send_toaddr(isc_task_t *task, isc_event_t *event) {
UNUSED(task);
LOCK(&notify->zone->lock);
zone_attach(notify->zone, &zone);
dns_zone_iattach(notify->zone, &zone);
if ((event->ev_attributes & ISC_EVENTATTR_CANCELED) != 0 ||
DNS_ZONE_FLAG(notify->zone, DNS_ZONE_F_EXITING)) {
result = ISC_R_CANCELED;
@@ -1755,7 +1776,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_detach(&zone);
dns_zone_idetach(&zone);
isc_event_free(&event);
}
@@ -1788,7 +1809,7 @@ notify_send(notify_t *notify) {
result = notify_create(notify->mctx, &new);
if (result != ISC_R_SUCCESS)
goto cleanup;
zone_attach(notify->zone, &new->zone);
dns_zone_iattach(notify->zone, &new->zone);
ISC_LIST_APPEND(new->zone->notifies, new, link);
new->dst = dst;
result = notify_send_queue(new);
@@ -1848,7 +1869,7 @@ dns_zone_notify(dns_zone_t *zone) {
UNLOCK(&zone->lock);
return;
}
zone_attach(zone, &notify->zone);
dns_zone_iattach(zone, &notify->zone);
notify->dst = dst;
ISC_LIST_APPEND(zone->notifies, notify, link);
result = notify_send_queue(notify);
@@ -1928,7 +1949,7 @@ dns_zone_notify(dns_zone_t *zone) {
result = notify_create(zone->mctx, &notify);
if (result != ISC_R_SUCCESS)
continue;
dns_zone_attach(zone, &notify->zone);
dns_zone_iattach(zone, &notify->zone);
result = dns_name_dup(&ns.name, zone->mctx, &notify->ns);
if (result != ISC_R_SUCCESS) {
LOCK(&zone->lock);
@@ -2174,15 +2195,18 @@ queue_soa_query(dns_zone_t *zone) {
cancel_refresh(zone);
return;
}
dns_zone_attach(zone, &dummy); /*
* Attach so that we won't clean up
* until the event is delivered.
*/
/*
* Attach so that we won't clean up
* until the event is delivered.
*/
dns_zone_iattach(zone, &dummy);
e->ev_arg = zone;
e->ev_sender = NULL;
result = isc_ratelimiter_enqueue(zone->zmgr->rl, zone->task, &e);
if (result != ISC_R_SUCCESS) {
dns_zone_detach(&dummy);
dns_zone_idetach(&dummy);
isc_event_free(&e);
cancel_refresh(zone);
}
@@ -2208,7 +2232,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_detach(&zone);
dns_zone_idetach(&zone);
return;
}
@@ -2263,7 +2287,7 @@ soa_query(isc_task_t *task, isc_event_t *event) {
}
dns_message_destroy(&message);
isc_event_free(&event);
dns_zone_detach(&zone);
dns_zone_idetach(&zone);
return;
cleanup:
@@ -2275,7 +2299,7 @@ soa_query(isc_task_t *task, isc_event_t *event) {
dns_message_destroy(&message);
cancel_refresh(zone);
isc_event_free(&event);
dns_zone_detach(&zone);
dns_zone_idetach(&zone);
return;
}
@@ -2292,6 +2316,7 @@ 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;
@@ -2995,13 +3020,13 @@ notify_done(isc_task_t *task, isc_event_t *event) {
notify = event->ev_arg;
REQUIRE(DNS_NOTIFY_VALID(notify));
dns_zone_attach(notify->zone, &zone);
dns_zone_iattach(notify->zone, &zone);
DNS_ENTER;
isc_event_free(&event);
LOCK(&zone->lock);
notify_destroy(notify);
UNLOCK(&zone->lock);
dns_zone_detach(&zone);
dns_zone_idetach(&zone);
}
@@ -3425,7 +3450,7 @@ got_transfer_quota(isc_task_t *task, isc_event_t *event) {
isc_event_free(&event);
dns_zone_detach(&zone);
dns_zone_detach(&zone); /* XXXAG */
return;
}
@@ -3795,8 +3820,11 @@ zmgr_start_xfrin_ifquota(dns_zonemgr_t *zmgr, dns_zone_t *zone) {
/*
* Make sure the zone does not go away before it has processed
* the event; in effect, the event is attached to the zone.
*
* XXXAG This should be done as soon as the zone goes on the
* queue, using irefs.
*/
zone->refs++;
zone->erefs++;
isc_task_send(zone->task, &e);
UNLOCK(&zone->lock);

View File

@@ -35,7 +35,6 @@ struct dns_zt {
/* Locked by lock. */
isc_uint32_t references;
dns_rbt_t *table;
isc_boolean_t shutdown; /* Has been shut down. */
};
#define ZTMAGIC 0x5a54626cU /* ZTbl */
@@ -47,9 +46,6 @@ 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;
@@ -78,7 +74,6 @@ 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;
@@ -245,24 +240,6 @@ load(dns_zone_t *zone, void *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)