From cd01c9716ff3d995b2be1f0d053dfe81ce9335b6 Mon Sep 17 00:00:00 2001 From: Andreas Gustafsson Date: Mon, 22 May 2000 17:23:15 +0000 Subject: [PATCH] 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. --- lib/dns/include/dns/zone.h | 32 +++++- lib/dns/include/dns/zt.h | 9 -- lib/dns/view.c | 3 +- lib/dns/zone.c | 220 +++++++++++++++++++++---------------- lib/dns/zt.c | 23 ---- 5 files changed, 151 insertions(+), 136 deletions(-) diff --git a/lib/dns/include/dns/zone.h b/lib/dns/include/dns/zone.h index 9c90b7ab4a..34bd2cf9a7 100644 --- a/lib/dns/include/dns/zone.h +++ b/lib/dns/include/dns/zone.h @@ -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, diff --git a/lib/dns/include/dns/zt.h b/lib/dns/include/dns/zt.h index fd62eb1e48..b2a8050757 100644 --- a/lib/dns/include/dns/zt.h +++ b/lib/dns/include/dns/zt.h @@ -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); diff --git a/lib/dns/view.c b/lib/dns/view.c index a4a53fa90f..30b87a0125 100644 --- a/lib/dns/view.c +++ b/lib/dns/view.c @@ -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); diff --git a/lib/dns/zone.c b/lib/dns/zone.c index c6cabc9328..ac230027a3 100644 --- a/lib/dns/zone.c +++ b/lib/dns/zone.c @@ -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 @@ -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(¬ify->zone); - /* XXXAG exit_check */ + dns_zone_idetach(¬ify->zone); } if (notify->find != NULL) dns_adb_destroyfind(¬ify->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(¬ify->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(¬ify->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, ¬ify->zone); + dns_zone_iattach(zone, ¬ify->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, ¬ify); if (result != ISC_R_SUCCESS) continue; - dns_zone_attach(zone, ¬ify->zone); + dns_zone_iattach(zone, ¬ify->zone); result = dns_name_dup(&ns.name, zone->mctx, ¬ify->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); diff --git a/lib/dns/zt.c b/lib/dns/zt.c index 5a14ce308d..c2ca2a3969 100644 --- a/lib/dns/zt.c +++ b/lib/dns/zt.c @@ -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)