* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: zone.c,v 1.283 2000/12/28 01:29:06 marka Exp $ */
+/* $Id: zone.c,v 1.283.2.1 2000/12/29 19:13:56 gson Exp $ */
#include <config.h>
#define DNS_ZONEFLG_NOREFRESH 0x00010000U
#define DNS_ZONEFLG_DIALNOTIFY 0x00020000U
#define DNS_ZONEFLG_DIALREFRESH 0x00040000U
+#define DNS_ZONEFLG_SHUTDOWN 0x00080000U
#define DNS_ZONE_OPTION(z,o) (((z)->options & (o)) != 0)
return (result);
}
-static void
+static isc_boolean_t
exit_check(dns_zone_t *zone) {
- if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_EXITING) &&
+
+ REQUIRE(LOCKED_ZONE(zone));
+
+ if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_SHUTDOWN) &&
zone->irefs == 0)
{
/*
- * DNS_ZONEFLG_EXITING can only be set if erefs == 0.
+ * DNS_ZONEFLG_SHUTDOWN can only be set if erefs == 0.
*/
INSIST(zone->erefs == 0);
- zone_free(zone);
+ return (ISC_TRUE);
}
+ return (ISC_FALSE);
}
static isc_result_t
void
dns_zone_idetach(dns_zone_t **zonep) {
dns_zone_t *zone;
+ isc_boolean_t free_needed;
REQUIRE(zonep != NULL && DNS_ZONE_VALID(*zonep));
zone = *zonep;
zone->irefs--;
zone_log(zone, "dns_zone_idetach", ISC_LOG_DEBUG(10),
"eref = %d, irefs = %d", zone->erefs, zone->irefs);
+ free_needed = exit_check(zone);
UNLOCK_ZONE(zone);
- exit_check(zone);
+ if (free_needed)
+ zone_free(zone);
}
isc_mem_t *
zone_shutdown(isc_task_t *task, isc_event_t *event) {
dns_zone_t *zone = (dns_zone_t *) event->ev_arg;
isc_result_t result;
+ isc_boolean_t free_needed;
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");
+
+ /*
+ * Stop things being restarted after we cancel them below.
+ */
LOCK_ZONE(zone);
DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_EXITING);
UNLOCK_ZONE(zone);
* If we were waiting for xfrin quota, step out of
* the queue.
*/
+ RWLOCK(&zone->zmgr->rwlock, isc_rwlocktype_write);
if (zone->statelist == &zone->zmgr->waiting_for_xfrin) {
- RWLOCK(&zone->zmgr->rwlock, isc_rwlocktype_write);
ISC_LIST_UNLINK(zone->zmgr->waiting_for_xfrin, zone,
statelink);
- RWUNLOCK(&zone->zmgr->rwlock, isc_rwlocktype_write);
zone->statelist = NULL;
}
+ RWUNLOCK(&zone->zmgr->rwlock, isc_rwlocktype_write);
+
+ LOCK_ZONE(zone);
if (zone->xfr != NULL)
dns_xfrin_shutdown(zone->xfr);
- LOCK_ZONE(zone);
if (zone->request != NULL) {
dns_request_cancel(zone->request);
}
- UNLOCK_ZONE(zone);
if (zone->readio != NULL)
zonemgr_cancelio(zone->readio);
- LOCK_ZONE(zone);
notify_cancel(zone);
- UNLOCK_ZONE(zone);
if (zone->timer != NULL) {
result = isc_timer_reset(zone->timer, isc_timertype_inactive,
if (zone->view != NULL)
dns_view_weakdetach(&zone->view);
- exit_check(zone);
+ /*
+ * We have now canceled everything set the flag to allow exit_check()
+ * to succeed. We must not unlock between setting this flag and
+ * calling exit_check().
+ */
+ DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_SHUTDOWN);
+ free_needed = exit_check(zone);
+ UNLOCK_ZONE(zone);
+ if (free_needed)
+ zone_free(zone);
}
static void