📄 adb.c
字号:
dns_adbname_t *name; dns_adbname_t *next_name; isc_result_t result = ISC_FALSE; DP(CLEAN_LEVEL, "cleaning name bucket %d", bucket); LOCK(&adb->namelocks[bucket]); if (adb->name_sd[bucket]) { UNLOCK(&adb->namelocks[bucket]); return (result); } name = ISC_LIST_HEAD(adb->names[bucket]); while (name != NULL) { next_name = ISC_LIST_NEXT(name, plink); INSIST(result == ISC_FALSE); result = check_expire_namehooks(name, now); if (!result) result = check_expire_name(&name, now); name = next_name; } UNLOCK(&adb->namelocks[bucket]); return (result);}/* * ADB must be locked, and no other locks held. */static isc_boolean_tcleanup_entries(dns_adb_t *adb, int bucket, isc_stdtime_t now) { dns_adbentry_t *entry, *next_entry; isc_boolean_t result = ISC_FALSE; DP(CLEAN_LEVEL, "cleaning entry bucket %d", bucket); LOCK(&adb->entrylocks[bucket]); entry = ISC_LIST_HEAD(adb->entries[bucket]); while (entry != NULL) { next_entry = ISC_LIST_NEXT(entry, plink); INSIST(result == ISC_FALSE); result = check_expire_entry(adb, &entry, now); entry = next_entry; } UNLOCK(&adb->entrylocks[bucket]); return (result);}static voidtimer_cleanup(isc_task_t *task, isc_event_t *ev) { dns_adb_t *adb; isc_stdtime_t now; unsigned int i; UNUSED(task); adb = ev->ev_arg; INSIST(DNS_ADB_VALID(adb)); LOCK(&adb->lock); isc_stdtime_get(&now); for (i = 0 ; i < CLEAN_BUCKETS ; i++) { /* * Call our cleanup routines. */ RUNTIME_CHECK(cleanup_names(adb, adb->next_cleanbucket, now) == ISC_FALSE); RUNTIME_CHECK(cleanup_entries(adb, adb->next_cleanbucket, now) == ISC_FALSE); /* * Set the next bucket to be cleaned. */ adb->next_cleanbucket++; if (adb->next_cleanbucket >= NBUCKETS) { adb->next_cleanbucket = 0;#ifdef DUMP_ADB_AFTER_CLEANING dump_adb(adb, stdout, ISC_TRUE);#endif } } /* * Reset the timer. * XXXDCL isc_timer_reset might return ISC_R_UNEXPECTED or * ISC_R_NOMEMORY, but it isn't clear what could be done here * if either one of those things happened. */ (void)isc_timer_reset(adb->timer, isc_timertype_once, NULL, &adb->tick_interval, ISC_FALSE); UNLOCK(&adb->lock); isc_event_free(&ev);}static voiddestroy(dns_adb_t *adb) { adb->magic = 0; /* * The timer is already dead, from the task's shutdown callback. */ isc_task_detach(&adb->task); isc_mempool_destroy(&adb->nmp); isc_mempool_destroy(&adb->nhmp); isc_mempool_destroy(&adb->zimp); isc_mempool_destroy(&adb->emp); isc_mempool_destroy(&adb->ahmp); isc_mempool_destroy(&adb->aimp); isc_mempool_destroy(&adb->afmp); isc_mempool_destroy(&adb->af6mp); isc_mutexblock_destroy(adb->entrylocks, NBUCKETS); isc_mutexblock_destroy(adb->namelocks, NBUCKETS); DESTROYLOCK(&adb->reflock); DESTROYLOCK(&adb->lock); DESTROYLOCK(&adb->mplock); isc_mem_put(adb->mctx, adb, sizeof (dns_adb_t));}/* * Public functions. */isc_result_tdns_adb_create(isc_mem_t *mem, dns_view_t *view, isc_timermgr_t *timermgr, isc_taskmgr_t *taskmgr, dns_adb_t **newadb){ dns_adb_t *adb; isc_result_t result; int i; REQUIRE(mem != NULL); REQUIRE(view != NULL); REQUIRE(timermgr != NULL); REQUIRE(taskmgr != NULL); REQUIRE(newadb != NULL && *newadb == NULL); adb = isc_mem_get(mem, sizeof (dns_adb_t)); if (adb == NULL) return (ISC_R_NOMEMORY); /* * Initialize things here that cannot fail, and especially things * that must be NULL for the error return to work properly. */ adb->magic = 0; adb->erefcnt = 1; adb->irefcnt = 0; adb->nmp = NULL; adb->nhmp = NULL; adb->zimp = NULL; adb->emp = NULL; adb->ahmp = NULL; adb->aimp = NULL; adb->afmp = NULL; adb->af6mp = NULL; adb->task = NULL; adb->timer = NULL; adb->mctx = mem; adb->view = view; adb->timermgr = timermgr; adb->taskmgr = taskmgr; adb->next_cleanbucket = 0; ISC_EVENT_INIT(&adb->cevent, sizeof adb->cevent, 0, NULL, DNS_EVENT_ADBCONTROL, shutdown_task, adb, adb, NULL, NULL); adb->cevent_sent = ISC_FALSE; adb->shutting_down = ISC_FALSE; ISC_LIST_INIT(adb->whenshutdown); result = isc_mutex_init(&adb->lock); if (result != ISC_R_SUCCESS) goto fail0b; result = isc_mutex_init(&adb->mplock); if (result != ISC_R_SUCCESS) goto fail0c; result = isc_mutex_init(&adb->reflock); if (result != ISC_R_SUCCESS) goto fail0d; /* * Initialize the bucket locks for names and elements. * May as well initialize the list heads, too. */ result = isc_mutexblock_init(adb->namelocks, NBUCKETS); if (result != ISC_R_SUCCESS) goto fail1; for (i = 0 ; i < NBUCKETS ; i++) { ISC_LIST_INIT(adb->names[i]); adb->name_sd[i] = ISC_FALSE; adb->name_refcnt[i] = 0; adb->irefcnt++; } for (i = 0 ; i < NBUCKETS ; i++) { ISC_LIST_INIT(adb->entries[i]); adb->entry_sd[i] = ISC_FALSE; adb->entry_refcnt[i] = 0; adb->irefcnt++; } result = isc_mutexblock_init(adb->entrylocks, NBUCKETS); if (result != ISC_R_SUCCESS) goto fail2; /* * Memory pools */#define MPINIT(t, p, n) do { \ result = isc_mempool_create(mem, sizeof (t), &(p)); \ if (result != ISC_R_SUCCESS) \ goto fail3; \ isc_mempool_setfreemax((p), FREE_ITEMS); \ isc_mempool_setfillcount((p), FILL_COUNT); \ isc_mempool_setname((p), n); \ isc_mempool_associatelock((p), &adb->mplock); \} while (0) MPINIT(dns_adbname_t, adb->nmp, "adbname"); MPINIT(dns_adbnamehook_t, adb->nhmp, "adbnamehook"); MPINIT(dns_adbzoneinfo_t, adb->zimp, "adbzoneinfo"); MPINIT(dns_adbentry_t, adb->emp, "adbentry"); MPINIT(dns_adbfind_t, adb->ahmp, "adbfind"); MPINIT(dns_adbaddrinfo_t, adb->aimp, "adbaddrinfo"); MPINIT(dns_adbfetch_t, adb->afmp, "adbfetch"); MPINIT(dns_adbfetch6_t, adb->af6mp, "adbfetch6");#undef MPINIT /* * Allocate a timer and a task for our periodic cleanup. */ result = isc_task_create(adb->taskmgr, 0, &adb->task); if (result != ISC_R_SUCCESS) goto fail3; isc_task_setname(adb->task, "ADB", adb); /* * XXXMLG When this is changed to be a config file option, */ isc_interval_set(&adb->tick_interval, CLEAN_SECONDS, 0); result = isc_timer_create(adb->timermgr, isc_timertype_once, NULL, &adb->tick_interval, adb->task, timer_cleanup, adb, &adb->timer); if (result != ISC_R_SUCCESS) goto fail3; DP(5, "Cleaning interval for adb: " "%u buckets every %u seconds, %u buckets in system, %u cl.interval", CLEAN_BUCKETS, CLEAN_SECONDS, NBUCKETS, CLEAN_PERIOD); /* * Normal return. */ adb->magic = DNS_ADB_MAGIC; *newadb = adb; return (ISC_R_SUCCESS); fail3: if (adb->task != NULL) isc_task_detach(&adb->task); if (adb->timer != NULL) isc_timer_detach(&adb->timer); /* clean up entrylocks */ isc_mutexblock_destroy(adb->entrylocks, NBUCKETS); fail2: /* clean up namelocks */ isc_mutexblock_destroy(adb->namelocks, NBUCKETS); fail1: /* clean up only allocated memory */ if (adb->nmp != NULL) isc_mempool_destroy(&adb->nmp); if (adb->nhmp != NULL) isc_mempool_destroy(&adb->nhmp); if (adb->zimp != NULL) isc_mempool_destroy(&adb->zimp); if (adb->emp != NULL) isc_mempool_destroy(&adb->emp); if (adb->ahmp != NULL) isc_mempool_destroy(&adb->ahmp); if (adb->aimp != NULL) isc_mempool_destroy(&adb->aimp); if (adb->afmp != NULL) isc_mempool_destroy(&adb->afmp); if (adb->af6mp != NULL) isc_mempool_destroy(&adb->af6mp); DESTROYLOCK(&adb->reflock); fail0d: DESTROYLOCK(&adb->mplock); fail0c: DESTROYLOCK(&adb->lock); fail0b: isc_mem_put(mem, adb, sizeof (dns_adb_t)); return (result);}voiddns_adb_attach(dns_adb_t *adb, dns_adb_t **adbx) { REQUIRE(DNS_ADB_VALID(adb)); REQUIRE(adbx != NULL && *adbx == NULL); inc_adb_erefcnt(adb); *adbx = adb;}voiddns_adb_detach(dns_adb_t **adbx) { dns_adb_t *adb; isc_boolean_t need_exit_check; REQUIRE(adbx != NULL && DNS_ADB_VALID(*adbx)); adb = *adbx; *adbx = NULL; INSIST(adb->erefcnt > 0); LOCK(&adb->reflock); adb->erefcnt--; need_exit_check = ISC_TF(adb->erefcnt == 0 && adb->irefcnt == 0); UNLOCK(&adb->reflock); if (need_exit_check) { LOCK(&adb->lock); INSIST(adb->shutting_down); check_exit(adb); UNLOCK(&adb->lock); }}voiddns_adb_whenshutdown(dns_adb_t *adb, isc_task_t *task, isc_event_t **eventp) { isc_task_t *clone; isc_event_t *event; isc_boolean_t zeroirefcnt = ISC_FALSE; /* * Send '*eventp' to 'task' when 'adb' has shutdown. */ REQUIRE(DNS_ADB_VALID(adb)); REQUIRE(eventp != NULL); event = *eventp; *eventp = NULL; LOCK(&adb->lock); LOCK(&adb->reflock); zeroirefcnt = ISC_TF(adb->irefcnt == 0); if (adb->shutting_down && zeroirefcnt && isc_mempool_getallocated(adb->ahmp) == 0) { /* * We're already shutdown. Send the event. */ event->ev_sender = adb; isc_task_send(task, &event); } else { clone = NULL; isc_task_attach(task, &clone); event->ev_sender = clone; ISC_LIST_APPEND(adb->whenshutdown, event, ev_link); } UNLOCK(&adb->reflock); UNLOCK(&adb->lock);}voiddns_adb_shutdown(dns_adb_t *adb) { isc_boolean_t need_check_exit; /* * Shutdown 'adb'. */ LOCK(&adb->lock); if (!adb->shutting_down) { adb->shutting_down = ISC_TRUE; need_check_exit = shutdown_names(adb); if (!need_check_exit) need_check_exit = shutdown_entries(adb); if (need_check_exit) check_exit(adb); } UNLOCK(&adb->lock);}isc_result_tdns_adb_createfind(dns_adb_t *adb, isc_task_t *task, isc_taskaction_t action, void *arg, dns_name_t *name, dns_name_t *zone, unsigned int options, isc_stdtime_t now, dns_name_t *target, in_port_t port, dns_adbfind_t **findp){ dns_adbfind_t *find; dns_adbname_t *adbname; int bucket; isc_boolean_t want_event, start_at_zone, alias, have_address; isc_result_t result; unsigned int wanted_addresses; unsigned int wanted_fetches; unsigned int query_pending; REQUIRE(DNS_ADB_VALID(adb)); if (task != NULL) { REQUIRE(action != NULL); } REQUIRE(name != NULL); REQUIRE(zone != NULL); REQUIRE(findp != NULL && *findp == NULL); REQUIRE(target == NULL || dns_name_hasbuffer(target)); REQUIRE((options & DNS_ADBFIND_ADDRESSMASK) != 0); result = ISC_R_UNEXPECTED; wanted_addresses = (options & DNS_ADBFIND_ADDRESSMASK); wanted_fetches = 0; query_pending = 0; want_event = ISC_FALSE; start_at_zone = ISC_FALSE; alias = ISC_FALSE; if (now == 0) isc_stdtime_get(&now); /* * XXXMLG Move this comment somewhere else! * * Look up the name in our internal database. * * Possibilities: Note that these are not always exclusive. * * No name found. In this case, allocate a new name header and * an initial namehook or two. If any of these allocations * fail, clean up and return ISC_R_NOMEMORY. * * Name found, valid addresses present. Allocate one addrinfo * structure for each found and append it to the linked list * of addresses for this header. * * Name found, queries pending. In this case, if a task was * passed in, allocate a job id, attach it to the name's job * list and remember to tell the caller that there will be * more info coming later. */ find = new_adbfind(adb); if (find == NULL) return (ISC_R_NOMEMORY); find->port = port; /* * Remember what types of addresses we are interested in. */ find->options = options; find->flags |= wanted_addresses; if (FIND_WANTEVENT(find)) { REQUIRE(task != NULL); } /* * Try to see if we know anything about this name at all. */ bucket = DNS_ADB_INVALIDBUCKET; adbname = find_name_and_lock(adb, name, find->options, &bucket); if (adb->name_sd[bucket]) { DP(DEF_LEVEL, "dns_adb_createfind: returning ISC_R_SHUTTINGDOWN"); RUNTIME_CHECK(free_adbfind(adb, &find) == ISC_FALSE); result = ISC_R_SHUTTINGDOWN; goto out; } /* * Nothing found. Allocate a new adbname structure for this name. */ if (adbname == NULL) { adbname = new_adbname(adb, name); if (adbname == NULL) { RUNTIME_CHECK(free_adbfind(adb, &find) == ISC_FALSE); result = ISC_R_NOMEMORY; goto out; } link_name(adb, bucket, adbname); if (FIND_HINTOK(find)) adbname->flags |= NAME_HINT_OK; if (FIND_GLUEOK(find)) adbname->flags |= NAME_GLUE_OK; if (FIND_STARTATZONE(find)) adbname->flags |= NAME_STARTATZONE; } /* * Expire old entries, etc. */ RUNTIME_CHECK(check_expire_namehook
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -