Compare commits

...
Author SHA1 Message Date
Witold Kręcicki 2f9da7f225 Make ns_client_requests atomic. 2019-01-22 12:23:54 +01:00
Witold Kręcicki b7a76fad2b Proper lock ordering in dns_view_setviewcommit. Need to make sure it's correct. 2019-01-22 12:22:42 +01:00
Witold Kręcicki 5e5e8da953 TSAN: lock epoll_ctl calls to silence warnings 2019-01-22 11:51:38 +01:00
Witold Kręcicki 7b8757db45 Use atomics in rndc.c to silence TSAN 2019-01-22 10:59:09 +01:00
Witold Kręcicki dc2ca4fa8d lib/dns/adb.c:
- TSAN can't handle more than 64 locks in one thread,
   lock ADB bucket-by-bucket in TSAN mode. This means
   that the dump won't be consistent but it's good enough
   for testing
 - Use proper order when unlocking adb->namelocks
   and adb->entrylocks when dumping ADB.
2019-01-22 10:58:51 +01:00
Witold Kręcicki 6f89098e32 Use proper locking order in lib/dns/resolver.c to avoid deadlock 2019-01-22 10:46:13 +01:00
Witold Kręcicki 2f93fa320f Make booleans in unix/app.c atomic to prevent data races and silence TSAN 2019-01-22 10:45:36 +01:00
Witold Kręcicki 3d11d69ebf Add __SANITIZE_THREAD__ define, similiar to __SANITIZE_ADDRESS__ 2019-01-21 10:38:02 +01:00
Witold Kręcicki cb847810aa Use more atomics in rwlock code 2019-01-21 10:33:59 +01:00
Witold Kręcicki 2680c6d189 lib/dns/adb.c: check erefcnt under lock 2019-01-21 10:03:05 +01:00
Witold Kręcicki 2445c44f21 lib/isc/mem.c : make ctx->is_overmem atomic to avoid data races 2019-01-21 10:02:58 +01:00
Witold Kręcicki a1101c07fc Use isc_refcount for counting in lib/dns/zt.c 2019-01-21 10:00:38 +01:00
Witold Kręcicki ea2720cc00 lib/dns/dispatch.c data access races fixes, found by TSAN 2019-01-21 09:48:01 +01:00
Witold Kręcicki a6c53a015a More locking in socket code to avoid data races. 2019-01-21 09:47:49 +01:00
Witold Kręcicki e2102aabbe Fix a race in access to manager->tasks in taskmgr
Make taskmgr->mode and boolean state flags (exclusive, paused, exiting) atomic.
2019-01-21 09:47:32 +01:00
Witold Kręcicki e4e9930397 Add atomic_store_relaxed and atomic_load_relaxed macros to isc/atomic.h 2019-01-21 09:32:36 +01:00
Witold Kręcicki 58e1baba7a If possible don't use forwarders when priming the resolver.
If we try to fetch a record from cache and need to look into
hints database we assume that the resolver is not primed and
start dns_resolver_prime(). Priming query is supposed to return
NSes for "." in ANSWER section and glue records for them in
ADDITIONAL section, so that we can fill that info in 'regular'
cache and not use hints db anymore.
However, if we're using a forwarder the priming query goes through
it, and if it's configured to return minimal answers we won't get
the addresses of root servers in ADDITIONAL section. Since the
only records for root servers we have are in hints database we'll
try to prime the resolver with every single query.

This patch adds a DNS_FETCHOPT_NOFORWARD flag which avoids using
forwarders if possible (that is if we have forward-first policy).
Using this flag on priming fetch fixes the problem as we get the
proper glue. With forward-only policy the problem is non-existent,
as we'll never ask for root server addresses because we'll never
have a need to query them.

Also added a test to confirm priming queries are not forwarded.
2019-01-18 15:44:34 +01:00
Petr MenšíkandWitold Kręcicki 3ed794bb45 Make sure null atributes are never used
Add INSIST to pubattr fetching where null might occur in therory. Make
sure null is never dereferenced.
2019-01-18 15:44:33 +01:00
Witold Kręcicki 3e8838654d When a forwarder fails and we're not in a forward-only mode we
go back to regular resolution. When this happens the fetch timer is
already running, and we might end up in a situation where we we create
a fetch for qname-minimized query and after that the timer is triggered
and the query is retried (fctx_try) - which causes relaunching of
qname-minimization fetch - and since we already have a qmin fetch
for this fctx - assertion failure.

This fix stops the timer when doing qname minimization - qmin fetch
internal timer should take care of all the possible timeouts.
2019-01-18 15:44:33 +01:00
Michał KępieńandWitold Kręcicki fcb8aec700 Add CHANGES entry
5137.	[func]		named now logs messages whenever a mirror zone becomes
			usable or unusable for resolution purposes. [GL #818]
2019-01-18 15:44:33 +01:00
Michał KępieńandWitold Kręcicki 1565ee6c3d Log a message when a mirror zone becomes unusable
Log a message if a mirror zone becomes unusable for the resolver (most
usually due to the zone's expiration timer firing).  Ensure that
verification failures do not cause a mirror zone to be unloaded
(instead, its last successfully verified version should be served if it
is available).
2019-01-18 15:44:33 +01:00
Michał KępieńandWitold Kręcicki 527e540841 Log a message when a mirror zone loaded from disk comes into effect
Log a message when a mirror zone is successfully loaded from disk and
subsequently verified.

This could have been implemented in a simpler manner, e.g. by modifying
an earlier code branch inside zone_postload() which checks whether the
zone already has a database attached and calls attachdb() if it does
not, but that would cause the resulting logs to indicate that a mirror
zone comes into effect before the "loaded serial ..." message is logged,
which would be confusing.

Tweak some existing sed commands used in the "mirror" system test to
ensure that separate test cases comprising it do not break each other.
2019-01-18 15:44:33 +01:00
Michał KępieńandWitold Kręcicki 43ca8bc50a Log a message when a transferred mirror zone comes into effect
Log a message when a mirror zone is successfully transferred and
verified, but only if no database for that zone was yet loaded at the
time the transfer was initiated.

This could have been implemented in a simpler manner, e.g. by modifying
zone_replacedb(), but (due to the calling order of the functions
involved in finalizing a zone transfer) that would cause the resulting
logs to suggest that a mirror zone comes into effect before its transfer
is finished, which would be confusing given the nature of mirror zones
and the fact that no message is logged upon successful mirror zone
verification.

Once the dns_zone_replacedb() call in axfr_finalize() is made, it
becomes impossible to determine whether the transferred zone had a
database attached before the transfer was started.  Thus, that check is
instead performed when the transfer context is first created and the
result of this check is passed around in a field of the transfer context
structure.  If it turns out to be desired, the relevant log message is
then emitted just before the transfer context is freed.

Taking this approach means that the log message added by this commit is
not timed precisely, i.e. mirror zone data may be used before this
message is logged.  However, that can only be fixed by logging the
message inside zone_replacedb(), which causes arguably more dire issues
discussed above.

dns_zone_isloaded() is not used to double-check that transferred zone
data was correctly loaded since the 'shutdown_result' field of the zone
transfer context will not be set to ISC_R_SUCCESS unless axfr_finalize()
succeeds (and that in turn will not happen unless dns_zone_replacedb()
succeeds).
2019-01-18 15:44:33 +01:00
Evan HuntandWitold Kręcicki 733a3db7a5 CHANGES 2019-01-18 15:44:33 +01:00
Evan HuntandWitold Kręcicki 7b9f4cfc08 improved documentation 2019-01-18 15:44:33 +01:00
Evan HuntandWitold Kręcicki 258f1dc94c fix incorrect comments 2019-01-18 15:44:33 +01:00
Evan HuntandWitold Kręcicki b1c35f812a error on allow-update and allow-update-forwarding at options/view level 2019-01-18 15:44:33 +01:00
Mark AndrewsandWitold Kręcicki f65933d11a use smt_pause instead of pause on sparc 2019-01-18 15:44:33 +01:00
Mark AndrewsandWitold Kręcicki e1f80772b2 adjust timeout to allow for ECN negotiation failures 2019-01-18 15:44:33 +01:00
Mark AndrewsandWitold Kręcicki f880388607 add CHANGES 2019-01-18 15:44:33 +01:00
Mark AndrewsandWitold Kręcicki 3fa5684e19 ensure that WSAStartup is called before getservbyname 2019-01-18 15:44:33 +01:00
Mark AndrewsandWitold Kręcicki 28025720a8 add multi-view server and tests 2019-01-18 15:44:33 +01:00
Mark AndrewsandWitold Kręcicki e83e6be806 add CHANGES note 2019-01-18 15:44:33 +01:00
Tony FinchandWitold Kręcicki 505b88e1a3 Fix a few cosmetic issues with rndc managed-keys
The handling of class and view arguments was broken, because the code
didn't realise that next_token() would overwrite the class name when
it parsed the view name. The code was trying to implement a syntax
like `refresh [[class] view]`, but it was documented to have a syntax
like `refresh [class [view]]`. The latter is consistent with other rndc
commands, so that is how I have fixed it.

Before:

$ rndc managed-keys refresh in rec
rndc: 'managed-keys' failed: unknown class/type
unknown class 'rec'

After:

$ rndc managed-keys refresh in rec
refreshing managed keys for 'rec'

There were missing newlines in the output from `rndc managed-keys
refresh` and `rndc managed-keys destroy`.

Before:

$ rndc managed-keys refresh
refreshing managed keys for 'rec'refreshing managed keys for 'auth'

After:

$ rndc managed-keys refresh
refreshing managed keys for 'rec'
refreshing managed keys for 'auth'
2019-01-18 15:44:33 +01:00
Ondřej SurýandWitold Kręcicki b7a199184c b/t/s/dnssec/tests.sh: Cleanup showprivate() function 2019-01-18 15:44:33 +01:00
43 changed files with 887 additions and 349 deletions
+26
View File
@@ -1,3 +1,29 @@
5139. [bug] If possible, don't use forwarders when priming.
This ensures we can get root server IP addresses
from priming query response glue, which may not
be present if the forwarding server is returning
minimal responses. [GL #752]
5138. [bug] Under some circumstances named could hit an assertion
failure when doing qname minimization when using
forwarders. [GL #797]
5137. [func] named now logs messages whenever a mirror zone becomes
usable or unusable for resolution purposes. [GL #818]
5136. [cleanup] Check in named-checkconf that allow-update and
allow-update-forwarding are not set at the
view/options level; fix documentation. [GL #512]
5135. [port] sparc: Use smt_pause() instead of pause. [GL #816]
5134. [bug] win32: WSAStartup was not called before getservbyname
was called. [GL #590]
5133. [bug] 'rndc managed-keys' didn't handle class and view
correctly and failed to add new lines between each
view. [GL !1327]
5132. [bug] Fix race condition in cleanup part of dns_dt_create(). 5132. [bug] Fix race condition in cleanup part of dns_dt_create().
[GL !1323] [GL !1323]
+18 -25
View File
@@ -4995,16 +4995,10 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist,
&view->sortlist)); &view->sortlist));
/* /*
* Configure default allow-notify, allow-update * Configure default allow-update and allow-update-forwarding ACLs,
* and allow-update-forwarding ACLs, so they can be * so they can be inherited by zones. (Note these cannot be set at
* inherited by zones. (Note these cannot be set at
* options/view level.) * options/view level.)
*/ */
if (view->notifyacl == NULL) {
CHECK(configure_view_acl(vconfig, config, named_g_config,
"allow-notify", NULL, actx,
named_g_mctx, &view->notifyacl));
}
if (view->updateacl == NULL) { if (view->updateacl == NULL) {
CHECK(configure_view_acl(NULL, NULL, named_g_config, CHECK(configure_view_acl(NULL, NULL, named_g_config,
"allow-update", NULL, actx, "allow-update", NULL, actx,
@@ -5017,14 +5011,19 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist,
} }
/* /*
* Configure default allow-transer ACL so it can be inherited * Configure default allow-transfer and allow-notify ACLs so they
* by zones. (Note this *can* be set at options or view level.) * can be inherited by zones.
*/ */
if (view->transferacl == NULL) { if (view->transferacl == NULL) {
CHECK(configure_view_acl(vconfig, config, named_g_config, CHECK(configure_view_acl(vconfig, config, named_g_config,
"allow-transfer", NULL, actx, "allow-transfer", NULL, actx,
named_g_mctx, &view->transferacl)); named_g_mctx, &view->transferacl));
} }
if (view->notifyacl == NULL) {
CHECK(configure_view_acl(vconfig, config, named_g_config,
"allow-notify", NULL, actx,
named_g_mctx, &view->notifyacl));
}
obj = NULL; obj = NULL;
result = named_config_get(maps, "provide-ixfr", &obj); result = named_config_get(maps, "provide-ixfr", &obj);
@@ -6894,7 +6893,7 @@ tat_timer_tick(isc_task_t *task, isc_event_t *event) {
static void static void
pps_timer_tick(isc_task_t *task, isc_event_t *event) { pps_timer_tick(isc_task_t *task, isc_event_t *event) {
static unsigned int oldrequests = 0; static unsigned int oldrequests = 0;
unsigned int requests = ns_client_requests; unsigned int requests = atomic_load(&ns_client_requests);
UNUSED(task); UNUSED(task);
isc_event_free(&event); isc_event_free(&event);
@@ -15049,29 +15048,17 @@ named_server_mkeys(named_server_t *server, isc_lex_t *lex,
/* Look for the optional class name. */ /* Look for the optional class name. */
classtxt = next_token(lex, text); classtxt = next_token(lex, text);
if (classtxt != NULL) { if (classtxt != NULL) {
/* Look for the optional view name. */
viewtxt = next_token(lex, text);
}
if (classtxt == NULL) {
rdclass = dns_rdataclass_in;
} else {
isc_textregion_t r; isc_textregion_t r;
r.base = classtxt; r.base = classtxt;
r.length = strlen(classtxt); r.length = strlen(classtxt);
result = dns_rdataclass_fromtext(&rdclass, &r); result = dns_rdataclass_fromtext(&rdclass, &r);
if (result != ISC_R_SUCCESS) { if (result != ISC_R_SUCCESS) {
if (viewtxt == NULL) {
rdclass = dns_rdataclass_in;
viewtxt = classtxt;
result = ISC_R_SUCCESS;
} else {
snprintf(msg, sizeof(msg), snprintf(msg, sizeof(msg),
"unknown class '%s'", classtxt); "unknown class '%s'", classtxt);
(void) putstr(text, msg); (void) putstr(text, msg);
goto cleanup; goto cleanup;
} }
} viewtxt = next_token(lex, text);
} }
for (view = ISC_LIST_HEAD(server->viewlist); for (view = ISC_LIST_HEAD(server->viewlist);
@@ -15100,6 +15087,9 @@ named_server_mkeys(named_server_t *server, isc_lex_t *lex,
switch (opt) { switch (opt) {
case REFRESH: case REFRESH:
if (!first) {
CHECK(putstr(text, "\n"));
}
CHECK(mkey_refresh(view, text)); CHECK(mkey_refresh(view, text));
break; break;
case STATUS: case STATUS:
@@ -15107,12 +15097,14 @@ named_server_mkeys(named_server_t *server, isc_lex_t *lex,
CHECK(putstr(text, "\n\n")); CHECK(putstr(text, "\n\n"));
} }
CHECK(mkey_status(view, text)); CHECK(mkey_status(view, text));
first = false;
break; break;
case SYNC: case SYNC:
CHECK(dns_zone_flush(view->managed_keys)); CHECK(dns_zone_flush(view->managed_keys));
break; break;
case DESTROY: case DESTROY:
if (!first) {
CHECK(putstr(text, "\n"));
}
CHECK(mkey_destroy(server, view, text)); CHECK(mkey_destroy(server, view, text));
break; break;
default: default:
@@ -15123,6 +15115,7 @@ named_server_mkeys(named_server_t *server, isc_lex_t *lex,
if (viewtxt != NULL) { if (viewtxt != NULL) {
break; break;
} }
first = false;
} }
if (!found) { if (!found) {
+9 -7
View File
@@ -75,7 +75,7 @@ static isccc_region_t secret;
static bool failed = false; static bool failed = false;
static bool c_flag = false; static bool c_flag = false;
static isc_mem_t *rndc_mctx; static isc_mem_t *rndc_mctx;
static int sends, recvs, connects; static atomic_uint_fast32_t sends, recvs, connects;
static char *command; static char *command;
static char *args; static char *args;
static char program[256]; static char program[256];
@@ -273,11 +273,11 @@ rndc_senddone(isc_task_t *task, isc_event_t *event) {
UNUSED(task); UNUSED(task);
sends--; atomic_fetch_sub(&sends, 1);
if (sevent->result != ISC_R_SUCCESS) if (sevent->result != ISC_R_SUCCESS)
fatal("send failed: %s", isc_result_totext(sevent->result)); fatal("send failed: %s", isc_result_totext(sevent->result));
isc_event_free(&event); isc_event_free(&event);
if (sends == 0 && recvs == 0) { if (atomic_load(&sends) == 0 && atomic_load(&recvs) == 0) {
isc_socket_detach(&sock); isc_socket_detach(&sock);
isc_task_shutdown(task); isc_task_shutdown(task);
RUNTIME_CHECK(isc_app_shutdown() == ISC_R_SUCCESS); RUNTIME_CHECK(isc_app_shutdown() == ISC_R_SUCCESS);
@@ -346,7 +346,7 @@ rndc_recvdone(isc_task_t *task, isc_event_t *event) {
isc_event_free(&event); isc_event_free(&event);
isccc_sexpr_free(&response); isccc_sexpr_free(&response);
if (sends == 0 && recvs == 0) { if (atomic_load(&sends) == 0 && atomic_load(&recvs) == 0) {
isc_socket_detach(&sock); isc_socket_detach(&sock);
isc_task_shutdown(task); isc_task_shutdown(task);
RUNTIME_CHECK(isc_app_shutdown() == ISC_R_SUCCESS); RUNTIME_CHECK(isc_app_shutdown() == ISC_R_SUCCESS);
@@ -430,7 +430,7 @@ rndc_recvnonce(isc_task_t *task, isc_event_t *event) {
recvs++; recvs++;
DO("send message", isc_socket_send(sock, &r, task, rndc_senddone, DO("send message", isc_socket_send(sock, &r, task, rndc_senddone,
NULL)); NULL));
sends++; atomic_fetch_add(&sends, 1);
isc_event_free(&event); isc_event_free(&event);
isccc_sexpr_free(&response); isccc_sexpr_free(&response);
@@ -498,7 +498,7 @@ rndc_connected(isc_task_t *task, isc_event_t *event) {
recvs++; recvs++;
DO("send message", isc_socket_send(sock, &r, task, rndc_senddone, DO("send message", isc_socket_send(sock, &r, task, rndc_senddone,
NULL)); NULL));
sends++; atomic_fetch_add(&sends, 1);
isc_event_free(&event); isc_event_free(&event);
isccc_sexpr_free(&request); isccc_sexpr_free(&request);
} }
@@ -999,8 +999,10 @@ main(int argc, char **argv) {
if (result != ISC_R_SUCCESS) if (result != ISC_R_SUCCESS)
fatal("isc_app_run() failed: %s", isc_result_totext(result)); fatal("isc_app_run() failed: %s", isc_result_totext(result));
if (connects > 0 || sends > 0 || recvs > 0) if (atomic_load(&connects) > 0 || atomic_load(&sends) > 0 ||
atomic_load(&recvs) > 0) {
isc_socket_cancel(sock, task, ISC_SOCKCANCEL_ALL); isc_socket_cancel(sock, task, ISC_SOCKCANCEL_ALL);
}
isc_task_detach(&task); isc_task_detach(&task);
isc_taskmgr_destroy(&taskmgr); isc_taskmgr_destroy(&taskmgr);
@@ -0,0 +1,14 @@
/*
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* See the COPYRIGHT file distributed with this work for additional
* information regarding copyright ownership.
*/
view {
allow-update-forwarding { any; };
};
@@ -0,0 +1,14 @@
/*
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* See the COPYRIGHT file distributed with this work for additional
* information regarding copyright ownership.
*/
options {
allow-update-forwarding { any; };
};
@@ -0,0 +1,14 @@
/*
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* See the COPYRIGHT file distributed with this work for additional
* information regarding copyright ownership.
*/
view {
allow-update { any; };
};
@@ -0,0 +1,14 @@
/*
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* See the COPYRIGHT file distributed with this work for additional
* information regarding copyright ownership.
*/
options {
allow-update { any; };
};
+3 -3
View File
@@ -133,6 +133,9 @@ view "third" {
zone "dnssec" { zone "dnssec" {
type master; type master;
file "file"; file "file";
allow-update {
"any";
};
auto-dnssec maintain; auto-dnssec maintain;
}; };
zone "p" { zone "p" {
@@ -145,9 +148,6 @@ view "third" {
1.2.3.4; 1.2.3.4;
}; };
}; };
allow-update {
"any";
};
}; };
view "chaos" chaos { view "chaos" chaos {
zone "hostname.bind" chaos { zone "hostname.bind" chaos {
+3 -7
View File
@@ -57,18 +57,14 @@ showprivate () {
} }
# check that signing records are marked as complete # check that signing records are marked as complete
checkprivate () { ( checkprivate () {
for i in 1 2 3 4 5 6 7 8 9 10; do for i in 1 2 3 4 5 6 7 8 9 10; do
ret=0 showprivate "$@" | grep -q incomplete || return 0
showprivate "$@" | grep incomplete >/dev/null 2>&1 && { ret=1; sleep 1; continue; } sleep 1
break
done done
[ $ret -eq 1 ] && {
echo_d "$1 signing incomplete" echo_d "$1 signing incomplete"
return 1 return 1
} }
return 0
) }
# check that a zone file is raw format, version 0 # check that a zone file is raw format, version 0
israw0 () { israw0 () {
@@ -19,6 +19,7 @@ options {
listen-on-v6 { none; }; listen-on-v6 { none; };
recursion yes; recursion yes;
dnssec-validation yes; dnssec-validation yes;
minimal-responses yes;
}; };
zone "." { zone "." {
@@ -0,0 +1,28 @@
/*
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* See the COPYRIGHT file distributed with this work for additional
* information regarding copyright ownership.
*/
options {
query-source address 10.53.0.7;
notify-source 10.53.0.7;
transfer-source 10.53.0.7;
port @PORT@;
pid-file "named.pid";
listen-on { 10.53.0.7; };
listen-on-v6 { none; };
forwarders { 10.53.0.4; };
forward first;
dnssec-validation yes;
};
zone "." {
type hint;
file "root.db";
};
+28
View File
@@ -0,0 +1,28 @@
; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
;
; This Source Code Form is subject to the terms of the Mozilla Public
; License, v. 2.0. If a copy of the MPL was not distributed with this
; file, You can obtain one at http://mozilla.org/MPL/2.0/.
;
; See the COPYRIGHT file distributed with this work for additional
; information regarding copyright ownership.
$TTL 300
. IN SOA gson.nominum.com. a.root.servers.nil. (
2000042100 ; serial
600 ; refresh
600 ; retry
1200 ; expire
600 ; minimum
)
. NS a.root-servers.nil.
a.root-servers.nil. A 10.53.0.1
example1 NS ns.example1
ns.example1 A 10.53.0.1
example2 NS ns.example2
ns.example2 A 10.53.0.1
example3 NS ns.example3
ns.example3 A 10.53.0.1
+1
View File
@@ -18,3 +18,4 @@ copy_setports ns2/named.conf.in ns2/named.conf
copy_setports ns3/named.conf.in ns3/named.conf copy_setports ns3/named.conf.in ns3/named.conf
copy_setports ns4/named.conf.in ns4/named.conf copy_setports ns4/named.conf.in ns4/named.conf
copy_setports ns5/named.conf.in ns5/named.conf copy_setports ns5/named.conf.in ns5/named.conf
copy_setports ns7/named.conf.in ns7/named.conf
+12
View File
@@ -147,5 +147,17 @@ if [ $sent -ne 1 ]; then ret=1; fi
if [ $ret != 0 ]; then echo_i "failed"; fi if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret` status=`expr $status + $ret`
echo_i "checking that priming queries are not forwarded"
ret=0
$DIG $DIGOPTS +noadd +noauth txt.example1. txt @10.53.0.7 > dig.out.f7 || ret=1
sent=`sed -n '/sending packet to 10.53.0.1/,/^$/p' ns7/named.run | grep ";.*IN.*NS" | wc -l`
[ $sent -eq 1 ] || ret=1
sent=`grep "10.53.0.7#.* (.): query '\./NS/IN' approved" ns4/named.run | wc -l`
[ $sent -eq 0 ] || ret=1
sent=`grep "10.53.0.7#.* (.): query '\./NS/IN' approved" ns1/named.run | wc -l`
[ $sent -eq 1 ] || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
echo_i "exit status: $status" echo_i "exit status: $status"
[ $status -eq 0 ] || exit 1 [ $status -eq 0 ] || exit 1
@@ -59,6 +59,7 @@ zone "verify-ixfr" {
type master; type master;
file "verify-ixfr.db.signed"; file "verify-ixfr.db.signed";
ixfr-from-differences yes; ixfr-from-differences yes;
allow-transfer { 10.53.0.3; };
}; };
zone "verify-reconfig" { zone "verify-reconfig" {
+61 -11
View File
@@ -62,7 +62,8 @@ ret=0
wait_for_transfer verify-unsigned wait_for_transfer verify-unsigned
$DIG $DIGOPTS @10.53.0.3 +norec verify-unsigned SOA > dig.out.ns3.test$n 2>&1 || ret=1 $DIG $DIGOPTS @10.53.0.3 +norec verify-unsigned SOA > dig.out.ns3.test$n 2>&1 || ret=1
grep "${UPDATED_SERIAL_BAD}.*; serial" dig.out.ns3.test$n > /dev/null && ret=1 grep "${UPDATED_SERIAL_BAD}.*; serial" dig.out.ns3.test$n > /dev/null && ret=1
nextpart ns3/named.run | grep "verify-unsigned.*Zone contains no DNSSEC keys" > /dev/null || ret=1 nextpartpeek ns3/named.run | grep "verify-unsigned.*Zone contains no DNSSEC keys" > /dev/null || ret=1
nextpartpeek ns3/named.run | grep "verify-unsigned.*mirror zone is now in use" > /dev/null && ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret` status=`expr $status + $ret`
@@ -73,7 +74,8 @@ nextpartreset ns3/named.run
wait_for_transfer verify-untrusted wait_for_transfer verify-untrusted
$DIG $DIGOPTS @10.53.0.3 +norec verify-untrusted SOA > dig.out.ns3.test$n 2>&1 || ret=1 $DIG $DIGOPTS @10.53.0.3 +norec verify-untrusted SOA > dig.out.ns3.test$n 2>&1 || ret=1
grep "${UPDATED_SERIAL_BAD}.*; serial" dig.out.ns3.test$n > /dev/null && ret=1 grep "${UPDATED_SERIAL_BAD}.*; serial" dig.out.ns3.test$n > /dev/null && ret=1
nextpart ns3/named.run | grep "verify-untrusted.*No trusted KSK DNSKEY found" > /dev/null || ret=1 nextpartpeek ns3/named.run | grep "verify-untrusted.*No trusted KSK DNSKEY found" > /dev/null || ret=1
nextpartpeek ns3/named.run | grep "verify-untrusted.*mirror zone is now in use" > /dev/null && ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret` status=`expr $status + $ret`
@@ -84,7 +86,8 @@ nextpartreset ns3/named.run
wait_for_transfer verify-axfr wait_for_transfer verify-axfr
$DIG $DIGOPTS @10.53.0.3 +norec verify-axfr SOA > dig.out.ns3.test$n 2>&1 || ret=1 $DIG $DIGOPTS @10.53.0.3 +norec verify-axfr SOA > dig.out.ns3.test$n 2>&1 || ret=1
grep "${UPDATED_SERIAL_BAD}.*; serial" dig.out.ns3.test$n > /dev/null && ret=1 grep "${UPDATED_SERIAL_BAD}.*; serial" dig.out.ns3.test$n > /dev/null && ret=1
nextpart ns3/named.run | grep "No correct RSASHA256 signature for verify-axfr SOA" > /dev/null || ret=1 nextpartpeek ns3/named.run | grep "No correct RSASHA256 signature for verify-axfr SOA" > /dev/null || ret=1
nextpartpeek ns3/named.run | grep "verify-axfr.*mirror zone is now in use" > /dev/null && ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret` status=`expr $status + $ret`
@@ -98,6 +101,7 @@ $RNDCCMD 10.53.0.3 retransfer verify-axfr > /dev/null 2>&1
wait_for_transfer verify-axfr wait_for_transfer verify-axfr
$DIG $DIGOPTS @10.53.0.3 +norec verify-axfr SOA > dig.out.ns3.test$n 2>&1 || ret=1 $DIG $DIGOPTS @10.53.0.3 +norec verify-axfr SOA > dig.out.ns3.test$n 2>&1 || ret=1
grep "${UPDATED_SERIAL_GOOD}.*; serial" dig.out.ns3.test$n > /dev/null || ret=1 grep "${UPDATED_SERIAL_GOOD}.*; serial" dig.out.ns3.test$n > /dev/null || ret=1
nextpartpeek ns3/named.run | grep "verify-axfr.*mirror zone is now in use" > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret` status=`expr $status + $ret`
@@ -106,12 +110,23 @@ echo_i "checking that an IXFR of an incorrectly signed mirror zone is rejected (
nextpartreset ns3/named.run nextpartreset ns3/named.run
ret=0 ret=0
wait_for_transfer verify-ixfr wait_for_transfer verify-ixfr
nextpart ns3/named.run > /dev/null
# Make a copy of the original zone file for reuse in journal tests below. # Make a copy of the original zone file for reuse in journal tests below.
cp ns2/verify-ixfr.db.signed ns3/verify-journal.db.mirror cp ns2/verify-ixfr.db.signed ns3/verify-journal.db.mirror
# Wait 1 second so that the zone file timestamp changes and the subsequent # Wait 1 second so that the zone file timestamp changes and the subsequent
# invocation of "rndc reload" triggers a zone reload. # invocation of "rndc reload" triggers a zone reload. This should also be way
# more than enough for the log message announcing the mirror zone coming into
# effect to appear in the log (see below).
sleep 1 sleep 1
# Sanity check: the initial, properly signed version of the zone should have
# been announced as coming into effect. Note that we cannot check that
# immediately after wait_for_transfer() as the latter might return before the
# log message we are looking for here appears; we also cannot call nextpart()
# after we update the zone on ns2 since there is a possibility of periodic
# refreshes triggering an IXFR of the "verify-ixfr" zone before the "rndc
# refresh" call below and that possibility needs to be handled as proper
# behavior. Thus, we need to look for the log message now.
nextpart ns3/named.run | grep "verify-ixfr.*mirror zone is now in use" > /dev/null || ret=1
# Update the "verify-ixfr" zone on ns2.
cat ns2/verify-ixfr.db.bad.signed > ns2/verify-ixfr.db.signed cat ns2/verify-ixfr.db.bad.signed > ns2/verify-ixfr.db.signed
reload_zone verify-ixfr ${UPDATED_SERIAL_BAD} reload_zone verify-ixfr ${UPDATED_SERIAL_BAD}
# Make a copy of the bad zone journal for reuse in journal tests below. # Make a copy of the bad zone journal for reuse in journal tests below.
@@ -127,7 +142,10 @@ fi
# Ensure the new, bad version of the zone was not accepted. # Ensure the new, bad version of the zone was not accepted.
$DIG $DIGOPTS @10.53.0.3 +norec verify-ixfr SOA > dig.out.ns3.test$n 2>&1 || ret=1 $DIG $DIGOPTS @10.53.0.3 +norec verify-ixfr SOA > dig.out.ns3.test$n 2>&1 || ret=1
grep "${UPDATED_SERIAL_BAD}.*; serial" dig.out.ns3.test$n > /dev/null && ret=1 grep "${UPDATED_SERIAL_BAD}.*; serial" dig.out.ns3.test$n > /dev/null && ret=1
nextpart ns3/named.run | grep "No correct RSASHA256 signature for verify-ixfr SOA" > /dev/null || ret=1 nextpartpeek ns3/named.run | grep "No correct RSASHA256 signature for verify-ixfr SOA" > /dev/null || ret=1
# Despite the verification failure for this IXFR, this mirror zone should still
# be in use as its previous version should have been verified successfully.
nextpartpeek ns3/named.run | grep "verify-ixfr.*mirror zone is no longer in use" > /dev/null && ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret` status=`expr $status + $ret`
@@ -148,6 +166,10 @@ wait_for_transfer verify-ixfr
# Ensure the new, good version of the zone was accepted. # Ensure the new, good version of the zone was accepted.
$DIG $DIGOPTS @10.53.0.3 +norec verify-ixfr SOA > dig.out.ns3.test$n 2>&1 || ret=1 $DIG $DIGOPTS @10.53.0.3 +norec verify-ixfr SOA > dig.out.ns3.test$n 2>&1 || ret=1
grep "${UPDATED_SERIAL_GOOD}.*; serial" dig.out.ns3.test$n > /dev/null || ret=1 grep "${UPDATED_SERIAL_GOOD}.*; serial" dig.out.ns3.test$n > /dev/null || ret=1
# The log message announcing the mirror zone coming into effect should not have
# been logged this time since the mirror zone in question is expected to
# already be in use before this test case is checked.
nextpartpeek ns3/named.run | grep "verify-ixfr.*mirror zone is now in use" > /dev/null && ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret` status=`expr $status + $ret`
@@ -158,7 +180,8 @@ nextpartreset ns3/named.run
wait_for_load verify-load ${UPDATED_SERIAL_BAD} ns3/named.run wait_for_load verify-load ${UPDATED_SERIAL_BAD} ns3/named.run
$DIG $DIGOPTS @10.53.0.3 +norec verify-load SOA > dig.out.ns3.test$n 2>&1 || ret=1 $DIG $DIGOPTS @10.53.0.3 +norec verify-load SOA > dig.out.ns3.test$n 2>&1 || ret=1
grep "${UPDATED_SERIAL_BAD}.*; serial" dig.out.ns3.test$n > /dev/null && ret=1 grep "${UPDATED_SERIAL_BAD}.*; serial" dig.out.ns3.test$n > /dev/null && ret=1
nextpart ns3/named.run | grep "No correct RSASHA256 signature for verify-load SOA" > /dev/null || ret=1 nextpartpeek ns3/named.run | grep "No correct RSASHA256 signature for verify-load SOA" > /dev/null || ret=1
nextpartpeek ns3/named.run | grep "verify-load.*mirror zone is now in use" > /dev/null && ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret` status=`expr $status + $ret`
@@ -172,6 +195,7 @@ $PERL $SYSTEMTESTTOP/start.pl --noclean --restart --port ${PORT} mirror ns3
wait_for_load verify-load ${UPDATED_SERIAL_GOOD} ns3/named.run wait_for_load verify-load ${UPDATED_SERIAL_GOOD} ns3/named.run
$DIG $DIGOPTS @10.53.0.3 +norec verify-load SOA > dig.out.ns3.test$n 2>&1 || ret=1 $DIG $DIGOPTS @10.53.0.3 +norec verify-load SOA > dig.out.ns3.test$n 2>&1 || ret=1
grep "${UPDATED_SERIAL_GOOD}.*; serial" dig.out.ns3.test$n > /dev/null || ret=1 grep "${UPDATED_SERIAL_GOOD}.*; serial" dig.out.ns3.test$n > /dev/null || ret=1
nextpartpeek ns3/named.run | grep "verify-load.*mirror zone is now in use" > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret` status=`expr $status + $ret`
@@ -181,12 +205,31 @@ ret=0
$PERL $SYSTEMTESTTOP/stop.pl --use-rndc --port ${CONTROLPORT} mirror ns3 $PERL $SYSTEMTESTTOP/stop.pl --use-rndc --port ${CONTROLPORT} mirror ns3
cp ns3/verify-journal.db.mirror ns3/verify-ixfr.db.mirror cp ns3/verify-journal.db.mirror ns3/verify-ixfr.db.mirror
cp ns3/verify-journal.db.bad.mirror.jnl ns3/verify-ixfr.db.mirror.jnl cp ns3/verify-journal.db.bad.mirror.jnl ns3/verify-ixfr.db.mirror.jnl
# Temporarily disable transfers of the "verify-ixfr" zone on ns2. This is
# required to reliably test whether the message announcing the mirror zone
# coming into effect is not logged after a failed journal verification since
# otherwise a corrected version of the zone may be transferred after
# verification fails but before we look for the aforementioned log message.
# (NOTE: Keep the embedded newline in the sed function list below.)
sed '/^zone "verify-ixfr" {$/,/^};$/ {
s/10.53.0.3/10.53.0.254/
}' ns2/named.conf > ns2/named.conf.modified
mv ns2/named.conf.modified ns2/named.conf
rndc_reconfig ns2 10.53.0.2
nextpart ns3/named.run > /dev/null nextpart ns3/named.run > /dev/null
$PERL $SYSTEMTESTTOP/start.pl --noclean --restart --port ${PORT} mirror ns3 $PERL $SYSTEMTESTTOP/start.pl --noclean --restart --port ${PORT} mirror ns3
wait_for_load verify-ixfr ${UPDATED_SERIAL_BAD} ns3/named.run wait_for_load verify-ixfr ${UPDATED_SERIAL_BAD} ns3/named.run
$DIG $DIGOPTS @10.53.0.3 +norec verify-ixfr SOA > dig.out.ns3.test$n 2>&1 || ret=1 $DIG $DIGOPTS @10.53.0.3 +norec verify-ixfr SOA > dig.out.ns3.test$n 2>&1 || ret=1
grep "${UPDATED_SERIAL_BAD}.*; serial" dig.out.ns3.test$n > /dev/null && ret=1 grep "${UPDATED_SERIAL_BAD}.*; serial" dig.out.ns3.test$n > /dev/null && ret=1
nextpart ns3/named.run | grep "No correct RSASHA256 signature for verify-ixfr SOA" > /dev/null || ret=1 nextpartpeek ns3/named.run | grep "No correct RSASHA256 signature for verify-ixfr SOA" > /dev/null || ret=1
nextpartpeek ns3/named.run | grep "verify-ixfr.*mirror zone is now in use" > /dev/null && ret=1
# Restore transfers for the "verify-ixfr" zone on ns2.
# (NOTE: Keep the embedded newline in the sed function list below.)
sed '/^zone "verify-ixfr" {$/,/^};$/ {
s/10.53.0.254/10.53.0.3/
}' ns2/named.conf > ns2/named.conf.modified
mv ns2/named.conf.modified ns2/named.conf
rndc_reconfig ns2 10.53.0.2
if [ $ret != 0 ]; then echo_i "failed"; fi if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret` status=`expr $status + $ret`
@@ -201,6 +244,7 @@ $PERL $SYSTEMTESTTOP/start.pl --noclean --restart --port ${PORT} mirror ns3
wait_for_load verify-ixfr ${UPDATED_SERIAL_GOOD} ns3/named.run wait_for_load verify-ixfr ${UPDATED_SERIAL_GOOD} ns3/named.run
$DIG $DIGOPTS @10.53.0.3 +norec verify-ixfr SOA > dig.out.ns3.test$n 2>&1 || ret=1 $DIG $DIGOPTS @10.53.0.3 +norec verify-ixfr SOA > dig.out.ns3.test$n 2>&1 || ret=1
grep "${UPDATED_SERIAL_GOOD}.*; serial" dig.out.ns3.test$n > /dev/null || ret=1 grep "${UPDATED_SERIAL_GOOD}.*; serial" dig.out.ns3.test$n > /dev/null || ret=1
nextpartpeek ns3/named.run | grep "verify-ixfr.*mirror zone is now in use" > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret` status=`expr $status + $ret`
@@ -301,7 +345,9 @@ grep "flags:.* ad" dig.out.ns3.test$n.1 > /dev/null || ret=1
# Sanity check: the authoritative server should have been queried. # Sanity check: the authoritative server should have been queried.
nextpart ns2/named.run | grep "query 'foo.initially-unavailable/A/IN'" > /dev/null || ret=1 nextpart ns2/named.run | grep "query 'foo.initially-unavailable/A/IN'" > /dev/null || ret=1
# Reconfigure ns2 so that the zone can be mirrored on ns3. # Reconfigure ns2 so that the zone can be mirrored on ns3.
sed "s/10.53.0.254/10.53.0.3/;" ns2/named.conf > ns2/named.conf.modified sed '/^zone "initially-unavailable" {$/,/^};$/ {
s/10.53.0.254/10.53.0.3/
}' ns2/named.conf > ns2/named.conf.modified
mv ns2/named.conf.modified ns2/named.conf mv ns2/named.conf.modified ns2/named.conf
rndc_reconfig ns2 10.53.0.2 rndc_reconfig ns2 10.53.0.2
# Flush the cache on ns3 and retransfer the mirror zone. # Flush the cache on ns3 and retransfer the mirror zone.
@@ -324,7 +370,9 @@ echo_i "checking that resolution succeeds with expired mirror zone data ($n)"
ret=0 ret=0
# Reconfigure ns2 so that the zone from the previous test can no longer be # Reconfigure ns2 so that the zone from the previous test can no longer be
# mirrored on ns3. # mirrored on ns3.
sed "s/10.53.0.3/10.53.0.254/;" ns2/named.conf > ns2/named.conf.modified sed '/^zone "initially-unavailable" {$/,/^};$/ {
s/10.53.0.3/10.53.0.254/
}' ns2/named.conf > ns2/named.conf.modified
mv ns2/named.conf.modified ns2/named.conf mv ns2/named.conf.modified ns2/named.conf
rndc_reconfig ns2 10.53.0.2 rndc_reconfig ns2 10.53.0.2
# Stop ns3, update the timestamp of the zone file to one far in the past, then # Stop ns3, update the timestamp of the zone file to one far in the past, then
@@ -335,7 +383,9 @@ nextpart ns3/named.run > /dev/null
$PERL $SYSTEMTESTTOP/start.pl --noclean --restart --port ${PORT} mirror ns3 $PERL $SYSTEMTESTTOP/start.pl --noclean --restart --port ${PORT} mirror ns3
# Ensure named attempts to retransfer the zone due to its expiry. # Ensure named attempts to retransfer the zone due to its expiry.
wait_for_transfer initially-unavailable wait_for_transfer initially-unavailable
nextpart ns3/named.run | grep "initially-unavailable.*expired" > /dev/null || ret=1 # Ensure the expected messages were logged.
nextpartpeek ns3/named.run | grep "initially-unavailable.*expired" > /dev/null || ret=1
nextpartpeek ns3/named.run | grep "initially-unavailable.*mirror zone is no longer in use" > /dev/null || ret=1
# Query for a record in the expired zone. Resolution should still succeed. # Query for a record in the expired zone. Resolution should still succeed.
$DIG $DIGOPTS @10.53.0.3 foo.initially-unavailable. A > dig.out.ns3.test$n 2>&1 || ret=1 $DIG $DIGOPTS @10.53.0.3 foo.initially-unavailable. A > dig.out.ns3.test$n 2>&1 || ret=1
# Check response code and flags in the answer. # Check response code and flags in the answer.
+8 -7
View File
@@ -10,14 +10,15 @@
# information regarding copyright ownership. # information regarding copyright ownership.
rm -f */K* */*.signed */trusted.conf */*.jnl */*.bk rm -f */K* */*.signed */trusted.conf */*.jnl */*.bk
rm -f dsset-. ns1/dsset-.
rm -f ns*/named.lock
rm -f */managed-keys.bind* */named.secroots
rm -f */managed*.conf ns1/managed.key ns1/managed.key.id rm -f */managed*.conf ns1/managed.key ns1/managed.key.id
rm -f */managed-keys.bind* */named.secroots
rm -f */named.conf
rm -f */named.memstats */named.run */named.run.prev rm -f */named.memstats */named.run */named.run.prev
rm -f dig.out* delv.out* rndc.out* signer.out* rm -f dig.out* delv.out* rndc.out* signer.out*
rm -f ns1/named.secroots ns1/root.db.signed* ns1/root.db.tmp rm -f dsset-. ns1/dsset-.
rm -f */named.conf
rm -rf ns4/nope
rm -f ns5/named.args
rm -f ns*/managed-keys.bind* rm -f ns*/managed-keys.bind*
rm -f ns*/named.lock
rm -f ns1/named.secroots ns1/root.db.signed* ns1/root.db.tmp
rm -f ns5/named.args
rm -f ns6/view1.mkeys ns6/view2.mkeys
rm -rf ns4/nope
+50
View File
@@ -0,0 +1,50 @@
/*
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* See the COPYRIGHT file distributed with this work for additional
* information regarding copyright ownership.
*/
// NS6
options {
query-source address 10.53.0.6;
notify-source 10.53.0.6;
transfer-source 10.53.0.6;
port @PORT@;
pid-file "named.pid";
listen-on { 10.53.0.6; };
listen-on-v6 { none; };
recursion yes;
notify no;
dnssec-enable yes;
dnssec-validation auto;
bindkeys-file "managed.conf";
};
key rndc_key {
secret "1234abcd8765";
algorithm hmac-sha256;
};
controls {
inet 10.53.0.6 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
};
view view1 {
zone "." {
type hint;
file "../../common/root.hint";
};
};
view view2 {
zone "." {
type hint;
file "../../common/root.hint";
};
};
+1
View File
@@ -19,6 +19,7 @@ copy_setports ns2/named.conf.in ns2/named.conf
copy_setports ns3/named.conf.in ns3/named.conf copy_setports ns3/named.conf.in ns3/named.conf
copy_setports ns4/named.conf.in ns4/named.conf copy_setports ns4/named.conf.in ns4/named.conf
copy_setports ns5/named.conf.in ns5/named.conf copy_setports ns5/named.conf.in ns5/named.conf
copy_setports ns6/named.conf.in ns6/named.conf
cp ns5/named1.args ns5/named.args cp ns5/named1.args ns5/named.args
+15
View File
@@ -755,5 +755,20 @@ grep "status: NOERROR" dig.out.ns5.b.test$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret` status=`expr $status + $ret`
n=`expr $n + 1`
echo_i "check 'rndc managed-keys' and views ($n)"
ret=0
$RNDCCMD 10.53.0.6 managed-keys refresh in view1 > rndc.out.ns6.view1.test$n || ret=1
grep "refreshing managed keys for 'view1'" rndc.out.ns6.view1.test$n > /dev/null || ret=1
lines=`wc -l < rndc.out.ns6.view1.test$n`
[ $lines -eq 1 ] || ret=1
$RNDCCMD 10.53.0.6 managed-keys refresh > rndc.out.ns6.view2.test$n || ret=1
lines=`wc -l < rndc.out.ns6.view2.test$n`
grep "refreshing managed keys for 'view1'" rndc.out.ns6.view2.test$n > /dev/null || ret=1
grep "refreshing managed keys for 'view2'" rndc.out.ns6.view2.test$n > /dev/null || ret=1
[ $lines -eq 2 ] || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
echo_i "exit status: $status" echo_i "exit status: $status"
[ $status -eq 0 ] || exit 1 [ $status -eq 0 ] || exit 1
+56 -43
View File
@@ -7053,18 +7053,24 @@ options {
<term><command>allow-notify</command></term> <term><command>allow-notify</command></term>
<listitem> <listitem>
<para> <para>
Specifies which hosts are allowed to This ACL specifies which hosts may send NOTIFY messages
notify this server, a slave, of zone changes in addition to inform this server of changes to zones for which it
to the zone masters. is acting as a secondary server. This is only
<command>allow-notify</command> may also be applicable for secondary zones (i.e., type
specified in the <literal>secondary</literal> or <literal>slave</literal>).
<command>zone</command> statement, in which case </para>
it overrides the <para>
<command>options allow-notify</command> If this option is set in <command>view</command> or
statement. It is only meaningful <command>options</command>, it is globally applied to
for a slave zone. If not specified, the default is to all secondary zones. If set in the <command>zone</command>
process notify messages statement, the global value is overridden.
only from a zone's master. </para>
<para>
If not specified, the default is to process NOTIFY
messages only from the configured
<command>masters</command> for the zone.
<command>allow-notify</command> can be used to expand the
list of permitted hosts, not to reduce it.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
@@ -7199,11 +7205,16 @@ options {
<term><command>allow-update</command></term> <term><command>allow-update</command></term>
<listitem> <listitem>
<para> <para>
Specifies which hosts are allowed to When set in the <command>zone</command> statement for
submit Dynamic DNS updates for master zones. The default is a master zone, specifies which hosts are allowed to
to deny submit Dynamic DNS updates to that zone. The default
updates from all hosts. Note that allowing updates based is to deny updates from all hosts. This can only
on the requestor's IP address is insecure; see be set at the <command>zone</command> level, not in
<command>options</command> or <command>view</command>.
</para>
<para>
Note that allowing updates based on the
requestor's IP address is insecure; see
<xref linkend="dynamic_update_security"/> for details. <xref linkend="dynamic_update_security"/> for details.
</para> </para>
</listitem> </listitem>
@@ -7213,29 +7224,30 @@ options {
<term><command>allow-update-forwarding</command></term> <term><command>allow-update-forwarding</command></term>
<listitem> <listitem>
<para> <para>
Specifies which hosts are allowed to When set in the <command>zone</command> statement for
submit Dynamic DNS updates to slave zones to be forwarded to a slave zone, specifies which hosts are allowed to
the submit Dynamic DNS updates and have them be forwarded
master. The default is <userinput>{ none; }</userinput>, to the master. The default is
which <userinput>{ none; }</userinput>, which means that no
means that no update forwarding will be performed. To update forwarding will be performed. This can only be
enable set at the <command>zone</command> level, not in
update forwarding, specify <command>options</command> or <command>view</command>.
</para>
<para>
To enable update forwarding, specify
<userinput>allow-update-forwarding { any; };</userinput>. <userinput>allow-update-forwarding { any; };</userinput>.
Specifying values other than <userinput>{ none; }</userinput> or in the <command>zone</command> statement.
<userinput>{ any; }</userinput> is usually Specifying values other than <userinput>{ none; }</userinput>
counterproductive, since or <userinput>{ any; }</userinput> is usually
the responsibility for update access control should rest counterproductive; the responsibility for update
with the access control should rest with the master server, not
master server, not the slaves. the slave.
</para> </para>
<para> <para>
Note that enabling the update forwarding feature on a slave Note that enabling the update forwarding feature on a slave
server server may expose master servers to attacks if they rely
may expose master servers relying on insecure IP address on insecure IP-address-based access control; see
based <xref linkend="dynamic_update_security"/> for more details.
access control to attacks; see <xref linkend="dynamic_update_security"/>
for more details.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
@@ -7259,13 +7271,14 @@ options {
<term xml:id="allow_transfer_term"><command>allow-transfer</command></term> <term xml:id="allow_transfer_term"><command>allow-transfer</command></term>
<listitem> <listitem>
<para> <para>
Specifies which hosts are allowed to Specifies which hosts are allowed to receive zone
receive zone transfers from the server. <command>allow-transfer</command> may transfers from the server. <command>allow-transfer</command>
also be specified in the <command>zone</command> may also be specified in the <command>zone</command>
statement, in which statement, in which case it overrides the
case it overrides the <command>options allow-transfer</command> statement. <command>allow-transfer</command> statement set in
If not specified, the default is to allow transfers to all <command>options</command> or <command>view</command>.
hosts. If not specified, the default is to allow transfers to
all hosts.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
+42
View File
@@ -484,6 +484,43 @@ check_viewacls(cfg_aclconfctx_t *actx, const cfg_obj_t *voptions,
return (result); return (result);
} }
static isc_result_t
check_non_viewacls(const cfg_obj_t *voptions, const cfg_obj_t *config,
isc_log_t *logctx)
{
const cfg_obj_t *aclobj = NULL;
const cfg_obj_t *options;
const char *where = NULL;
int i;
static const char *acls[] = {
"allow-update", "allow-update-forwarding", NULL
};
for (i = 0; acls[i] != NULL; i++) {
if (voptions != NULL && aclobj == NULL) {
cfg_map_get(voptions, acls[i], &aclobj);
where = "view";
}
if (config != NULL && aclobj == NULL) {
options = NULL;
cfg_map_get(config, "options", &options);
if (options != NULL) {
cfg_map_get(options, acls[i], &aclobj);
where = "options";
}
}
if (aclobj != NULL) {
cfg_obj_log(aclobj, logctx, ISC_LOG_ERROR,
"'%s' can only be set per-zone, "
"not in '%s'", acls[i], where);
return (ISC_R_FAILURE);
}
}
return (ISC_R_SUCCESS);
}
static const unsigned char zeros[16]; static const unsigned char zeros[16];
static isc_result_t static isc_result_t
@@ -3692,6 +3729,11 @@ check_viewconf(const cfg_obj_t *config, const cfg_obj_t *voptions,
if (tresult != ISC_R_SUCCESS) if (tresult != ISC_R_SUCCESS)
result = tresult; result = tresult;
tresult = check_non_viewacls(voptions, config, logctx);
if (tresult != ISC_R_SUCCESS) {
result = tresult;
}
tresult = check_recursionacls(actx, voptions, viewname, tresult = check_recursionacls(actx, voptions, viewname,
config, logctx, mctx); config, logctx, mctx);
if (tresult != ISC_R_SUCCESS) if (tresult != ISC_R_SUCCESS)
+34 -8
View File
@@ -2791,9 +2791,8 @@ dns_adb_detach(dns_adb_t **adbx) {
adb = *adbx; adb = *adbx;
*adbx = NULL; *adbx = NULL;
INSIST(adb->erefcnt > 0);
LOCK(&adb->reflock); LOCK(&adb->reflock);
INSIST(adb->erefcnt > 0);
adb->erefcnt--; adb->erefcnt--;
need_exit_check = (adb->erefcnt == 0 && adb->irefcnt == 0); need_exit_check = (adb->erefcnt == 0 && adb->irefcnt == 0);
UNLOCK(&adb->reflock); UNLOCK(&adb->reflock);
@@ -3407,28 +3406,44 @@ dump_adb(dns_adb_t *adb, FILE *f, bool debug, isc_stdtime_t now) {
adb, adb->erefcnt, adb->irefcnt, adb, adb->erefcnt, adb->irefcnt,
isc_mempool_getallocated(adb->nhmp)); isc_mempool_getallocated(adb->nhmp));
/*
* In TSAN mode we need to lock the locks individually, as TSAN
* can't handle more than 64 locks locked by one thread.
* In regular mode we want a consistent dump so we need to
* lock everything.
*/
#ifndef __SANITIZE_THREAD__
for (i = 0; i < adb->nnames; i++) for (i = 0; i < adb->nnames; i++)
LOCK(&adb->namelocks[i]); LOCK(&adb->namelocks[i]);
for (i = 0; i < adb->nentries; i++) for (i = 0; i < adb->nentries; i++)
LOCK(&adb->entrylocks[i]); LOCK(&adb->entrylocks[i]);
#endif
/* /*
* Dump the names * Dump the names
*/ */
for (i = 0; i < adb->nnames; i++) { for (i = 0; i < adb->nnames; i++) {
#ifdef __SANITIZE_THREAD__
LOCK(&adb->namelocks[i]);
#endif
name = ISC_LIST_HEAD(adb->names[i]); name = ISC_LIST_HEAD(adb->names[i]);
if (name == NULL) if (name == NULL) {
#ifdef __SANITIZE_THREAD__
UNLOCK(&adb->namelocks[i]);
#endif
continue; continue;
if (debug) }
if (debug) {
fprintf(f, "; bucket %u\n", i); fprintf(f, "; bucket %u\n", i);
}
for (; for (;
name != NULL; name != NULL;
name = ISC_LIST_NEXT(name, plink)) name = ISC_LIST_NEXT(name, plink))
{ {
if (debug) if (debug) {
fprintf(f, "; name %p (flags %08x)\n", fprintf(f, "; name %p (flags %08x)\n",
name, name->flags); name, name->flags);
}
fprintf(f, "; "); fprintf(f, "; ");
print_dns_name(f, &name->name); print_dns_name(f, &name->name);
if (dns_name_countlabels(&name->target) > 0) { if (dns_name_countlabels(&name->target) > 0) {
@@ -3456,26 +3471,37 @@ dump_adb(dns_adb_t *adb, FILE *f, bool debug, isc_stdtime_t now) {
print_find_list(f, name); print_find_list(f, name);
} }
} }
#ifdef __SANITIZE_THREAD__
UNLOCK(&adb->namelocks[i]);
#endif
} }
fprintf(f, ";\n; Unassociated entries\n;\n"); fprintf(f, ";\n; Unassociated entries\n;\n");
for (i = 0; i < adb->nentries; i++) { for (i = 0; i < adb->nentries; i++) {
#ifdef __SANITIZE_THREAD__
LOCK(&adb->entrylocks[i]);
#endif
entry = ISC_LIST_HEAD(adb->entries[i]); entry = ISC_LIST_HEAD(adb->entries[i]);
while (entry != NULL) { while (entry != NULL) {
if (entry->nh == 0) if (entry->nh == 0)
dump_entry(f, adb, entry, debug, now); dump_entry(f, adb, entry, debug, now);
entry = ISC_LIST_NEXT(entry, plink); entry = ISC_LIST_NEXT(entry, plink);
} }
#ifdef __SANITIZE_THREAD__
UNLOCK(&adb->entrylocks[i]);
#endif
} }
#ifndef __SANITIZE_THREAD__
/* /*
* Unlock everything * Unlock everything
*/ */
for (i = 0; i < adb->nentries; i++) for (i = adb->nentries-1; i >= 0; i--)
UNLOCK(&adb->entrylocks[i]); UNLOCK(&adb->entrylocks[i]);
for (i = 0; i < adb->nnames; i++) for (i = adb->nnames-1; i >= 0; i--)
UNLOCK(&adb->namelocks[i]); UNLOCK(&adb->namelocks[i]);
#endif
} }
static void static void
+29 -22
View File
@@ -76,9 +76,10 @@ struct dns_dispatchmgr {
/* locked by buffer_lock */ /* locked by buffer_lock */
dns_qid_t *qid; dns_qid_t *qid;
isc_mutex_t buffer_lock; isc_mutex_t buffer_lock;
unsigned int buffers; /*%< allocated buffers */
unsigned int buffersize; /*%< size of each buffer */ unsigned int buffersize; /*%< size of each buffer */
unsigned int maxbuffers; /*%< max buffers */ /* not locked */
atomic_uint_fast32_t buffers; /*%< allocated buffers */
atomic_uint_fast32_t maxbuffers; /*%< max buffers */
/* Locked internally. */ /* Locked internally. */
isc_mutex_t depool_lock; isc_mutex_t depool_lock;
@@ -900,9 +901,8 @@ free_buffer(dns_dispatch_t *disp, void *buf, unsigned int len) {
break; break;
case isc_sockettype_udp: case isc_sockettype_udp:
LOCK(&disp->mgr->buffer_lock); LOCK(&disp->mgr->buffer_lock);
INSIST(disp->mgr->buffers > 0);
INSIST(len == disp->mgr->buffersize); INSIST(len == disp->mgr->buffersize);
disp->mgr->buffers--; INSIST(atomic_fetch_sub(&disp->mgr->buffers, 1) > 0);
bpool = disp->mgr->bpool; bpool = disp->mgr->bpool;
UNLOCK(&disp->mgr->buffer_lock); UNLOCK(&disp->mgr->buffer_lock);
isc_mempool_put(bpool, buf); isc_mempool_put(bpool, buf);
@@ -918,17 +918,15 @@ allocate_udp_buffer(dns_dispatch_t *disp) {
isc_mempool_t *bpool; isc_mempool_t *bpool;
void *temp; void *temp;
atomic_fetch_add(&disp->mgr->buffers, 1);
LOCK(&disp->mgr->buffer_lock); LOCK(&disp->mgr->buffer_lock);
bpool = disp->mgr->bpool; bpool = disp->mgr->bpool;
disp->mgr->buffers++;
UNLOCK(&disp->mgr->buffer_lock); UNLOCK(&disp->mgr->buffer_lock);
temp = isc_mempool_get(bpool); temp = isc_mempool_get(bpool);
if (temp == NULL) { if (temp == NULL) {
LOCK(&disp->mgr->buffer_lock); atomic_fetch_sub(&disp->mgr->buffers, 1);
disp->mgr->buffers--;
UNLOCK(&disp->mgr->buffer_lock);
} }
return (temp); return (temp);
@@ -1050,8 +1048,9 @@ udp_recv(isc_event_t *ev_in, dns_dispatch_t *disp, dispsocket_t *dispsock) {
qid = mgr->qid; qid = mgr->qid;
dispatch_log(disp, LVL(90), dispatch_log(disp, LVL(90),
"got packet: requests %d, buffers %d, recvs %d", "got packet: requests %d, buffers %lu, recvs %d",
disp->requests, disp->mgr->buffers, disp->recv_pending); disp->requests, atomic_load(&disp->mgr->buffers),
disp->recv_pending);
if (dispsock == NULL && ev->ev_type == ISC_SOCKEVENT_RECVDONE) { if (dispsock == NULL && ev->ev_type == ISC_SOCKEVENT_RECVDONE) {
/* /*
@@ -1338,12 +1337,13 @@ tcp_recv(isc_task_t *task, isc_event_t *ev_in) {
qid = disp->qid; qid = disp->qid;
LOCK(&disp->lock);
dispatch_log(disp, LVL(90), dispatch_log(disp, LVL(90),
"got TCP packet: requests %d, buffers %d, recvs %d", "got TCP packet: requests %d, buffers %d, recvs %d",
disp->requests, disp->tcpbuffers, disp->recv_pending); disp->requests, disp->tcpbuffers, disp->recv_pending);
LOCK(&disp->lock);
INSIST(disp->recv_pending != 0); INSIST(disp->recv_pending != 0);
disp->recv_pending = 0; disp->recv_pending = 0;
@@ -1493,26 +1493,33 @@ startrecv(dns_dispatch_t *disp, dispsocket_t *dispsock) {
isc_region_t region; isc_region_t region;
isc_socket_t *sock; isc_socket_t *sock;
if (disp->shutting_down == 1) if (disp->shutting_down == 1) {
return (ISC_R_SUCCESS); return (ISC_R_SUCCESS);
}
if ((disp->attributes & DNS_DISPATCHATTR_NOLISTEN) != 0) if ((disp->attributes & DNS_DISPATCHATTR_NOLISTEN) != 0) {
return (ISC_R_SUCCESS); return (ISC_R_SUCCESS);
}
if (disp->recv_pending != 0 && dispsock == NULL) if (disp->recv_pending != 0 && dispsock == NULL) {
return (ISC_R_SUCCESS); return (ISC_R_SUCCESS);
}
if (disp->mgr->buffers >= disp->mgr->maxbuffers) if (atomic_load(&disp->mgr->buffers) >=
atomic_load(&disp->mgr->maxbuffers)) {
return (ISC_R_NOMEMORY); return (ISC_R_NOMEMORY);
}
if ((disp->attributes & DNS_DISPATCHATTR_EXCLUSIVE) != 0 && if ((disp->attributes & DNS_DISPATCHATTR_EXCLUSIVE) != 0 &&
dispsock == NULL) dispsock == NULL) {
return (ISC_R_SUCCESS); return (ISC_R_SUCCESS);
}
if (dispsock != NULL) if (dispsock != NULL) {
sock = dispsock->socket; sock = dispsock->socket;
else } else {
sock = disp->socket; sock = disp->socket;
}
INSIST(sock != NULL); INSIST(sock != NULL);
switch (disp->socktype) { switch (disp->socktype) {
@@ -1807,9 +1814,9 @@ dns_dispatchmgr_create(isc_mem_t *mctx, dns_dispatchmgr_t **mgrp)
isc_mempool_associatelock(mgr->dpool, &mgr->dpool_lock); isc_mempool_associatelock(mgr->dpool, &mgr->dpool_lock);
isc_mempool_setfillcount(mgr->dpool, 32); isc_mempool_setfillcount(mgr->dpool, 32);
mgr->buffers = 0; atomic_store(&mgr->buffers, 0);
mgr->buffersize = 0; mgr->buffersize = 0;
mgr->maxbuffers = 0; atomic_store(&mgr->maxbuffers, 0);
mgr->bpool = NULL; mgr->bpool = NULL;
mgr->spool = NULL; mgr->spool = NULL;
mgr->qid = NULL; mgr->qid = NULL;
@@ -2043,7 +2050,7 @@ dns_dispatchmgr_setudp(dns_dispatchmgr_t *mgr,
goto cleanup; goto cleanup;
mgr->buffersize = buffersize; mgr->buffersize = buffersize;
mgr->maxbuffers = maxbuffers; atomic_store(&mgr->maxbuffers, maxbuffers);
UNLOCK(&mgr->buffer_lock); UNLOCK(&mgr->buffer_lock);
return (ISC_R_SUCCESS); return (ISC_R_SUCCESS);
+2
View File
@@ -118,6 +118,8 @@ typedef enum {
when doing qname when doing qname
minimization on minimization on
ip6.arpa. */ ip6.arpa. */
#define DNS_FETCHOPT_NOFORWARD 0x00080000 /*%< Do not use forwarders
if possible. */
/* Reserved in use by adb.c 0x00400000 */ /* Reserved in use by adb.c 0x00400000 */
#define DNS_FETCHOPT_EDNSVERSIONSET 0x00800000 #define DNS_FETCHOPT_EDNSVERSIONSET 0x00800000
+2
View File
@@ -837,6 +837,7 @@ pkcs11ecdsa_fetch(dst_key_t *key, const char *engine, const char *label,
attr->type = CKA_EC_PARAMS; attr->type = CKA_EC_PARAMS;
pubattr = pk11_attribute_bytype(pubec, CKA_EC_PARAMS); pubattr = pk11_attribute_bytype(pubec, CKA_EC_PARAMS);
INSIST(pubattr != NULL);
attr->pValue = isc_mem_get(key->mctx, pubattr->ulValueLen); attr->pValue = isc_mem_get(key->mctx, pubattr->ulValueLen);
if (attr->pValue == NULL) if (attr->pValue == NULL)
DST_RET(ISC_R_NOMEMORY); DST_RET(ISC_R_NOMEMORY);
@@ -846,6 +847,7 @@ pkcs11ecdsa_fetch(dst_key_t *key, const char *engine, const char *label,
attr->type = CKA_EC_POINT; attr->type = CKA_EC_POINT;
pubattr = pk11_attribute_bytype(pubec, CKA_EC_POINT); pubattr = pk11_attribute_bytype(pubec, CKA_EC_POINT);
INSIST(pubattr != NULL);
attr->pValue = isc_mem_get(key->mctx, pubattr->ulValueLen); attr->pValue = isc_mem_get(key->mctx, pubattr->ulValueLen);
if (attr->pValue == NULL) if (attr->pValue == NULL)
DST_RET(ISC_R_NOMEMORY); DST_RET(ISC_R_NOMEMORY);
+2
View File
@@ -1673,6 +1673,7 @@ pkcs11rsa_fetch(dst_key_t *key, const char *engine, const char *label,
attr->type = CKA_MODULUS; attr->type = CKA_MODULUS;
pubattr = pk11_attribute_bytype(pubrsa, CKA_MODULUS); pubattr = pk11_attribute_bytype(pubrsa, CKA_MODULUS);
INSIST(pubattr != NULL);
attr->pValue = isc_mem_get(key->mctx, pubattr->ulValueLen); attr->pValue = isc_mem_get(key->mctx, pubattr->ulValueLen);
if (attr->pValue == NULL) if (attr->pValue == NULL)
DST_RET(ISC_R_NOMEMORY); DST_RET(ISC_R_NOMEMORY);
@@ -1682,6 +1683,7 @@ pkcs11rsa_fetch(dst_key_t *key, const char *engine, const char *label,
attr->type = CKA_PUBLIC_EXPONENT; attr->type = CKA_PUBLIC_EXPONENT;
pubattr = pk11_attribute_bytype(pubrsa, CKA_PUBLIC_EXPONENT); pubattr = pk11_attribute_bytype(pubrsa, CKA_PUBLIC_EXPONENT);
INSIST(pubattr != NULL);
attr->pValue = isc_mem_get(key->mctx, pubattr->ulValueLen); attr->pValue = isc_mem_get(key->mctx, pubattr->ulValueLen);
if (attr->pValue == NULL) if (attr->pValue == NULL)
DST_RET(ISC_R_NOMEMORY); DST_RET(ISC_R_NOMEMORY);
+36 -15
View File
@@ -1919,6 +1919,15 @@ fctx_query(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo,
srtt = addrinfo->srtt; srtt = addrinfo->srtt;
/*
* Allow an additional second for the kernel to resend the SYN (or
* SYN without ECN in the case of stupid firewalls blocking ECN
* negotiation) over the current RTT estimate.
*/
if ((options & DNS_FETCHOPT_TCP) != 0) {
srtt += 1000000;
}
/* /*
* A forwarder needs to make multiple queries. Give it at least * A forwarder needs to make multiple queries. Give it at least
* a second to do these in. * a second to do these in.
@@ -3501,6 +3510,18 @@ fctx_getaddresses(fetchctx_t *fctx, bool badcache) {
INSIST(ISC_LIST_EMPTY(fctx->forwaddrs)); INSIST(ISC_LIST_EMPTY(fctx->forwaddrs));
INSIST(ISC_LIST_EMPTY(fctx->altaddrs)); INSIST(ISC_LIST_EMPTY(fctx->altaddrs));
/*
* If we have DNS_FETCHOPT_NOFORWARD set and forwarding policy
* allows us to not forward - skip forwarders and go straight
* to NSes. This is currently used to make sure that priming query
* gets root servers' IP addresses in ADDITIONAL section.
*/
if ((fctx->options & DNS_FETCHOPT_NOFORWARD) != 0 &&
(fctx->fwdpolicy != dns_fwdpolicy_only))
{
goto normal_nses;
}
/* /*
* If this fctx has forwarders, use them; otherwise use any * If this fctx has forwarders, use them; otherwise use any
* selective forwarders specified in the view; otherwise use the * selective forwarders specified in the view; otherwise use the
@@ -3586,7 +3607,7 @@ fctx_getaddresses(fetchctx_t *fctx, bool badcache) {
/* /*
* Normal nameservers. * Normal nameservers.
*/ */
normal_nses:
stdoptions = DNS_ADBFIND_WANTEVENT | DNS_ADBFIND_EMPTYEVENT; stdoptions = DNS_ADBFIND_WANTEVENT | DNS_ADBFIND_EMPTYEVENT;
if (fctx->restarts == 1) { if (fctx->restarts == 1) {
/* /*
@@ -4031,9 +4052,11 @@ fctx_try(fetchctx_t *fctx, bool retrying, bool badcache) {
options &= ~DNS_FETCHOPT_QMINIMIZE; options &= ~DNS_FETCHOPT_QMINIMIZE;
fctx_increference(fctx); fctx_increference(fctx);
task = res->buckets[bucketnum].task; task = res->buckets[bucketnum].task;
fctx_stoptimer(fctx);
result = dns_resolver_createfetch(fctx->res, &fctx->qminname, result = dns_resolver_createfetch(fctx->res, &fctx->qminname,
fctx->qmintype, &fctx->domain, fctx->qmintype, &fctx->domain,
&fctx->nameservers, NULL, NULL, 0, &fctx->nameservers,
NULL, NULL, 0,
options, 0, fctx->qc, task, options, 0, fctx->qc, task,
resume_qmin, fctx, resume_qmin, fctx,
&fctx->qminrrset, NULL, &fctx->qminrrset, NULL,
@@ -4362,14 +4385,13 @@ fctx_timeout(isc_task_t *task, isc_event_t *event) {
* timer. * timer.
*/ */
result = fctx_starttimer(fctx); result = fctx_starttimer(fctx);
if (result != ISC_R_SUCCESS) if (result != ISC_R_SUCCESS) {
fctx_done(fctx, result, __LINE__); fctx_done(fctx, result, __LINE__);
else } else {
/* /* Keep trying */
* Keep trying.
*/
fctx_try(fctx, true, false); fctx_try(fctx, true, false);
} }
}
isc_event_free(&event); isc_event_free(&event);
} }
@@ -10115,16 +10137,16 @@ prime_done(isc_task_t *task, isc_event_t *event) {
UNUSED(task); UNUSED(task);
LOCK(&res->primelock);
LOCK(&res->lock); LOCK(&res->lock);
INSIST(res->priming); INSIST(res->priming);
res->priming = false; res->priming = false;
LOCK(&res->primelock);
fetch = res->primefetch; fetch = res->primefetch;
res->primefetch = NULL; res->primefetch = NULL;
UNLOCK(&res->primelock);
UNLOCK(&res->lock); UNLOCK(&res->lock);
UNLOCK(&res->primelock);
if (fevent->result == ISC_R_SUCCESS && if (fevent->result == ISC_R_SUCCESS &&
res->view->cache != NULL && res->view->hints != NULL) { res->view->cache != NULL && res->view->hints != NULL) {
@@ -10192,12 +10214,11 @@ dns_resolver_prime(dns_resolver_t *res) {
LOCK(&res->primelock); LOCK(&res->primelock);
result = dns_resolver_createfetch(res, dns_rootname, result = dns_resolver_createfetch(res, dns_rootname,
dns_rdatatype_ns, dns_rdatatype_ns,
NULL, NULL, NULL, NULL, 0, 0, NULL, NULL, NULL, NULL, 0,
0, NULL, DNS_FETCHOPT_NOFORWARD, 0,
res->buckets[0].task, NULL, res->buckets[0].task,
prime_done, prime_done, res, rdataset,
res, rdataset, NULL, NULL, &res->primefetch);
&res->primefetch);
UNLOCK(&res->primelock); UNLOCK(&res->primelock);
if (result != ISC_R_SUCCESS) { if (result != ISC_R_SUCCESS) {
isc_mem_put(res->mctx, rdataset, sizeof(*rdataset)); isc_mem_put(res->mctx, rdataset, sizeof(*rdataset));
+15 -11
View File
@@ -2432,20 +2432,24 @@ dns_view_loadnta(dns_view_t *view) {
void void
dns_view_setviewcommit(dns_view_t *view) { dns_view_setviewcommit(dns_view_t *view) {
REQUIRE(DNS_VIEW_VALID(view)); REQUIRE(DNS_VIEW_VALID(view));
dns_zone_t *redirect, *managed_keys;
dns_zt_t *zonetable;
LOCK(&view->lock); LOCK(&view->lock);
redirect = view->redirect;
if (view->redirect != NULL) { managed_keys = view->managed_keys;
dns_zone_setviewcommit(view->redirect); zonetable = view->zonetable;
}
if (view->managed_keys != NULL) {
dns_zone_setviewcommit(view->managed_keys);
}
if (view->zonetable != NULL) {
dns_zt_setviewcommit(view->zonetable);
}
UNLOCK(&view->lock); UNLOCK(&view->lock);
if (redirect != NULL) {
dns_zone_setviewcommit(redirect);
}
if (managed_keys != NULL) {
dns_zone_setviewcommit(managed_keys);
}
if (zonetable != NULL) {
dns_zt_setviewcommit(zonetable);
}
} }
void void
+22 -1
View File
@@ -133,6 +133,13 @@ struct dns_xfrin_ctx {
dns_tcpmsg_t tcpmsg; dns_tcpmsg_t tcpmsg;
bool tcpmsg_valid; bool tcpmsg_valid;
/*%
* Whether the zone originally had a database attached at the time this
* transfer context was created. Used by maybe_free() when making
* logging decisions.
*/
bool zone_had_db;
dns_db_t *db; dns_db_t *db;
dns_dbversion_t *ver; dns_dbversion_t *ver;
dns_diff_t diff; /*%< Pending database changes */ dns_diff_t diff; /*%< Pending database changes */
@@ -657,6 +664,10 @@ dns_xfrin_create(dns_zone_t *zone, dns_rdatatype_t xfrtype,
dns_zone_getclass(zone), xfrtype, masteraddr, dns_zone_getclass(zone), xfrtype, masteraddr,
sourceaddr, dscp, tsigkey, &xfr)); sourceaddr, dscp, tsigkey, &xfr));
if (db != NULL) {
xfr->zone_had_db = true;
}
CHECK(xfrin_start(xfr)); CHECK(xfrin_start(xfr));
xfr->done = done; xfr->done = done;
@@ -821,6 +832,7 @@ xfrin_create(isc_mem_t *mctx,
/* tcpmsg */ /* tcpmsg */
xfr->tcpmsg_valid = false; xfr->tcpmsg_valid = false;
xfr->zone_had_db = false;
xfr->db = NULL; xfr->db = NULL;
if (db != NULL) if (db != NULL)
dns_db_attach(db, &xfr->db); dns_db_attach(db, &xfr->db);
@@ -1513,8 +1525,17 @@ maybe_free(dns_xfrin_ctx_t *xfr) {
if (xfr->db != NULL) if (xfr->db != NULL)
dns_db_detach(&xfr->db); dns_db_detach(&xfr->db);
if (xfr->zone != NULL) if (xfr->zone != NULL) {
if (!xfr->zone_had_db &&
xfr->shuttingdown &&
xfr->shutdown_result == ISC_R_SUCCESS &&
dns_zone_gettype(xfr->zone) == dns_zone_mirror)
{
dns_zone_log(xfr->zone, ISC_LOG_INFO,
"mirror zone is now in use");
}
dns_zone_idetach(&xfr->zone); dns_zone_idetach(&xfr->zone);
}
isc_mem_putanddetach(&xfr->mctx, xfr, sizeof(*xfr)); isc_mem_putanddetach(&xfr->mctx, xfr, sizeof(*xfr));
} }
+13
View File
@@ -4440,6 +4440,7 @@ zone_postload(dns_zone_t *zone, dns_db_t *db, isc_time_t loadtime,
bool needdump = false; bool needdump = false;
bool hasinclude = DNS_ZONE_FLAG(zone, DNS_ZONEFLG_HASINCLUDE); bool hasinclude = DNS_ZONE_FLAG(zone, DNS_ZONEFLG_HASINCLUDE);
bool nomaster = false; bool nomaster = false;
bool had_db = false;
unsigned int options; unsigned int options;
dns_include_t *inc; dns_include_t *inc;
@@ -4804,6 +4805,7 @@ zone_postload(dns_zone_t *zone, dns_db_t *db, isc_time_t loadtime,
ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_write); ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_write);
if (zone->db != NULL) { if (zone->db != NULL) {
had_db = true;
result = zone_replacedb(zone, db, false); result = zone_replacedb(zone, db, false);
ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_write); ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_write);
if (result != ISC_R_SUCCESS) if (result != ISC_R_SUCCESS)
@@ -4915,6 +4917,11 @@ zone_postload(dns_zone_t *zone, dns_db_t *db, isc_time_t loadtime,
dns_db_issecure(db) ? " (DNSSEC signed)" : ""); dns_db_issecure(db) ? " (DNSSEC signed)" : "");
} }
if (!had_db && zone->type == dns_zone_mirror) {
dns_zone_logc(zone, DNS_LOGCATEGORY_ZONELOAD, ISC_LOG_INFO,
"mirror zone is now in use");
}
zone->loadtime = loadtime; zone->loadtime = loadtime;
goto done; goto done;
@@ -10838,6 +10845,12 @@ zone_unload(dns_zone_t *zone) {
ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_write); ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_write);
DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_LOADED); DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_LOADED);
DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_NEEDDUMP); DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_NEEDDUMP);
if (zone->type == dns_zone_mirror) {
dns_zone_log(zone, ISC_LOG_INFO,
"mirror zone is no longer in use; "
"reverting to normal recursion");
}
} }
void void
+26 -28
View File
@@ -49,9 +49,10 @@ struct dns_zt {
struct zt_load_params *loadparams; struct zt_load_params *loadparams;
/* Locked by lock. */ /* Locked by lock. */
bool flush; bool flush;
uint32_t references;
unsigned int loads_pending;
dns_rbt_t *table; dns_rbt_t *table;
/* Atomic */
isc_refcount_t refs;
isc_refcount_t loads_pending;
}; };
#define ZTMAGIC ISC_MAGIC('Z', 'T', 'b', 'l') #define ZTMAGIC ISC_MAGIC('Z', 'T', 'b', 'l')
@@ -95,14 +96,14 @@ dns_zt_create(isc_mem_t *mctx, dns_rdataclass_t rdclass, dns_zt_t **ztp) {
zt->mctx = NULL; zt->mctx = NULL;
isc_mem_attach(mctx, &zt->mctx); isc_mem_attach(mctx, &zt->mctx);
zt->references = 1; isc_refcount_init(&zt->refs, 1);
zt->flush = false; zt->flush = false;
zt->rdclass = rdclass; zt->rdclass = rdclass;
zt->magic = ZTMAGIC; zt->magic = ZTMAGIC;
zt->loaddone = NULL; zt->loaddone = NULL;
zt->loaddone_arg = NULL; zt->loaddone_arg = NULL;
zt->loadparams = NULL; zt->loadparams = NULL;
zt->loads_pending = 0; isc_refcount_init(&zt->loads_pending, 0);
*ztp = zt; *ztp = zt;
return (ISC_R_SUCCESS); return (ISC_R_SUCCESS);
@@ -203,9 +204,7 @@ dns_zt_attach(dns_zt_t *zt, dns_zt_t **ztp) {
RWLOCK(&zt->rwlock, isc_rwlocktype_write); RWLOCK(&zt->rwlock, isc_rwlocktype_write);
INSIST(zt->references > 0); INSIST(isc_refcount_increment(&zt->refs) > 0);
zt->references++;
INSIST(zt->references != 0);
RWUNLOCK(&zt->rwlock, isc_rwlocktype_write); RWUNLOCK(&zt->rwlock, isc_rwlocktype_write);
@@ -231,6 +230,7 @@ zt_destroy(dns_zt_t *zt) {
static void static void
zt_flushanddetach(dns_zt_t **ztp, bool need_flush) { zt_flushanddetach(dns_zt_t **ztp, bool need_flush) {
bool destroy = false; bool destroy = false;
int refs;
dns_zt_t *zt; dns_zt_t *zt;
REQUIRE(ztp != NULL && VALID_ZT(*ztp)); REQUIRE(ztp != NULL && VALID_ZT(*ztp));
@@ -239,17 +239,16 @@ zt_flushanddetach(dns_zt_t **ztp, bool need_flush) {
RWLOCK(&zt->rwlock, isc_rwlocktype_write); RWLOCK(&zt->rwlock, isc_rwlocktype_write);
INSIST(zt->references > 0); refs = isc_refcount_decrement(&zt->refs);
zt->references--; INSIST(refs != 0);
if (zt->references == 0) destroy = (refs == 1);
destroy = true; zt->flush = need_flush;
if (need_flush)
zt->flush = true;
RWUNLOCK(&zt->rwlock, isc_rwlocktype_write); RWUNLOCK(&zt->rwlock, isc_rwlocktype_write);
if (destroy) if (destroy) {
zt_destroy(zt); zt_destroy(zt);
}
*ztp = NULL; *ztp = NULL;
} }
@@ -332,15 +331,14 @@ asyncload(dns_zone_t *zone, void *zt_) {
isc_result_t result; isc_result_t result;
struct dns_zt *zt = (dns_zt_t*) zt_; struct dns_zt *zt = (dns_zt_t*) zt_;
REQUIRE(zone != NULL); REQUIRE(zone != NULL);
INSIST(zt->references > 0); INSIST(isc_refcount_increment(&zt->refs) > 0);
zt->references++; isc_refcount_increment(&zt->loads_pending);
zt->loads_pending++;
result = dns_zone_asyncload(zone, zt->loadparams->newonly, *zt->loadparams->dl, zt); result = dns_zone_asyncload(zone, zt->loadparams->newonly,
*zt->loadparams->dl, zt);
if (result != ISC_R_SUCCESS) { if (result != ISC_R_SUCCESS) {
zt->references--; INSIST(isc_refcount_decrement(&zt->refs) > 1);
zt->loads_pending--; isc_refcount_decrement(&zt->loads_pending);
INSIST(zt->references > 0);
} }
return (ISC_R_SUCCESS); return (ISC_R_SUCCESS);
} }
@@ -530,6 +528,7 @@ dns_zt_apply(dns_zt_t *zt, bool stop, isc_result_t *sub,
static isc_result_t static isc_result_t
doneloading(dns_zt_t *zt, dns_zone_t *zone, isc_task_t *task) { doneloading(dns_zt_t *zt, dns_zone_t *zone, isc_task_t *task) {
bool destroy = false; bool destroy = false;
int refs;
dns_zt_allloaded_t alldone = NULL; dns_zt_allloaded_t alldone = NULL;
void *arg = NULL; void *arg = NULL;
@@ -539,13 +538,12 @@ doneloading(dns_zt_t *zt, dns_zone_t *zone, isc_task_t *task) {
REQUIRE(VALID_ZT(zt)); REQUIRE(VALID_ZT(zt));
RWLOCK(&zt->rwlock, isc_rwlocktype_write); RWLOCK(&zt->rwlock, isc_rwlocktype_write);
INSIST(zt->loads_pending != 0); INSIST(atomic_load(&zt->loads_pending) != 0);
INSIST(zt->references != 0); refs = isc_refcount_decrement(&zt->refs);
zt->references--; INSIST(refs > 0);
if (zt->references == 0) destroy = (refs == 1);
destroy = true;
zt->loads_pending--; if (isc_refcount_decrement(&zt->loads_pending) == 1) {
if (zt->loads_pending == 0) {
alldone = zt->loaddone; alldone = zt->loaddone;
arg = zt->loaddone_arg; arg = zt->loaddone_arg;
zt->loaddone = NULL; zt->loaddone = NULL;
+33 -7
View File
@@ -126,6 +126,12 @@
#include <string.h> #include <string.h>
#include <errno.h> #include <errno.h>
#ifdef _WIN32
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#endif
#include <isc/app.h> #include <isc/app.h>
#include <isc/buffer.h> #include <isc/buffer.h>
#include <isc/lib.h> #include <isc/lib.h>
@@ -339,25 +345,45 @@ getaddrinfo(const char *hostname, const char *servname,
port = strtol(servname, &e, 10); port = strtol(servname, &e, 10);
if (*e == '\0') { if (*e == '\0') {
if (socktype == 0) if (socktype == 0) {
return (EAI_SOCKTYPE); return (EAI_SOCKTYPE);
if (port < 0 || port > 65535) }
if (port < 0 || port > 65535) {
return (EAI_SERVICE); return (EAI_SERVICE);
}
port = htons((unsigned short) port); port = htons((unsigned short) port);
} else { } else {
#ifdef _WIN32
WORD wVersionRequested;
WSADATA wsaData;
wVersionRequested = MAKEWORD(2, 0);
err = WSAStartup(wVersionRequested, &wsaData );
if (err != 0) {
return (EAI_FAIL);
}
#endif
sp = getservbyname(servname, proto); sp = getservbyname(servname, proto);
if (sp == NULL) if (sp != NULL)
return (EAI_SERVICE);
port = sp->s_port; port = sp->s_port;
#ifdef _WIN32
WSACleanup();
#endif
if (sp == NULL) {
return (EAI_SERVICE);
}
if (socktype == 0) { if (socktype == 0) {
if (strcmp(sp->s_proto, "tcp") == 0) if (strcmp(sp->s_proto, "tcp") == 0) {
socktype = SOCK_STREAM; socktype = SOCK_STREAM;
else if (strcmp(sp->s_proto, "udp") == 0) } else if (strcmp(sp->s_proto, "udp") == 0) {
socktype = SOCK_DGRAM; socktype = SOCK_DGRAM;
} }
} }
} else }
} else {
port = 0; port = 0;
}
/* /*
* Next, deal with just a service name, and no hostname. * Next, deal with just a service name, and no hostname.
+9
View File
@@ -16,3 +16,12 @@
#else #else
#include <isc/stdatomic.h> #include <isc/stdatomic.h>
#endif #endif
/*
* We define a few additional macros to make things easier
*/
#define atomic_store_relaxed(o, v) atomic_store_explicit((o), \
(v), \
memory_order_relaxed)
#define atomic_load_relaxed(o) atomic_load_explicit((o), memory_order_relaxed)
+3 -3
View File
@@ -35,7 +35,6 @@ struct isc_rwlock {
/* Unlocked. */ /* Unlocked. */
unsigned int magic; unsigned int magic;
isc_mutex_t lock; isc_mutex_t lock;
int32_t spins;
/* /*
* When some atomic instructions with hardware assistance are * When some atomic instructions with hardware assistance are
@@ -51,6 +50,7 @@ struct isc_rwlock {
*/ */
/* Read or modified atomically. */ /* Read or modified atomically. */
atomic_int_fast32_t spins;
atomic_int_fast32_t write_requests; atomic_int_fast32_t write_requests;
atomic_int_fast32_t write_completions; atomic_int_fast32_t write_completions;
atomic_int_fast32_t cnt_and_flag; atomic_int_fast32_t cnt_and_flag;
@@ -60,8 +60,8 @@ struct isc_rwlock {
isc_condition_t writeable; isc_condition_t writeable;
unsigned int readers_waiting; unsigned int readers_waiting;
/* Locked by rwlock itself. */ /* Locked by rwlock itself, but sometimes accessed without lock */
unsigned int write_granted; atomic_int_fast32_t write_granted;
/* Unlocked. */ /* Unlocked. */
unsigned int write_quota; unsigned int write_quota;
+4
View File
@@ -186,6 +186,10 @@
#define __SANITIZE_ADDRESS__ 1 #define __SANITIZE_ADDRESS__ 1
#endif #endif
#if __has_feature(thread_sanitizer)
#define __SANITIZE_THREAD__ 1
#endif
#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR >= 6) #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR >= 6)
#define STATIC_ASSERT(cond, msg) _Static_assert(cond, msg) #define STATIC_ASSERT(cond, msg) _Static_assert(cond, msg)
#elif __has_feature(c_static_assert) #elif __has_feature(c_static_assert)
+9 -11
View File
@@ -142,7 +142,7 @@ struct isc__mem {
size_t hi_water; size_t hi_water;
size_t lo_water; size_t lo_water;
bool hi_called; bool hi_called;
bool is_overmem; atomic_bool is_overmem;
isc_mem_water_t water; isc_mem_water_t water;
void * water_arg; void * water_arg;
ISC_LIST(isc__mempool_t) pools; ISC_LIST(isc__mempool_t) pools;
@@ -770,7 +770,7 @@ isc_mem_createx(size_t init_max_size, size_t target_size,
ctx->hi_water = 0; ctx->hi_water = 0;
ctx->lo_water = 0; ctx->lo_water = 0;
ctx->hi_called = false; ctx->hi_called = false;
ctx->is_overmem = false; atomic_store_relaxed(&ctx->is_overmem, false);
ctx->water = NULL; ctx->water = NULL;
ctx->water_arg = NULL; ctx->water_arg = NULL;
ctx->common.impmagic = MEM_MAGIC; ctx->common.impmagic = MEM_MAGIC;
@@ -1043,7 +1043,7 @@ isc___mem_get(isc_mem_t *ctx0, size_t size FLARG) {
ADD_TRACE(ctx, ptr, size, file, line); ADD_TRACE(ctx, ptr, size, file, line);
if (ctx->hi_water != 0U && ctx->inuse > ctx->hi_water) { if (ctx->hi_water != 0U && ctx->inuse > ctx->hi_water) {
ctx->is_overmem = true; atomic_store_relaxed(&ctx->is_overmem, true);
if (!ctx->hi_called) if (!ctx->hi_called)
call_water = true; call_water = true;
} }
@@ -1103,7 +1103,7 @@ isc___mem_put(isc_mem_t *ctx0, void *ptr, size_t size FLARG) {
* isc_mem_setwater() called with 0 for hi_water and lo_water. * isc_mem_setwater() called with 0 for hi_water and lo_water.
*/ */
if ((ctx->inuse < ctx->lo_water) || (ctx->lo_water == 0U)) { if ((ctx->inuse < ctx->lo_water) || (ctx->lo_water == 0U)) {
ctx->is_overmem = false; atomic_store_relaxed(&ctx->is_overmem, false);
if (ctx->hi_called) if (ctx->hi_called)
call_water = true; call_water = true;
} }
@@ -1269,9 +1269,8 @@ isc___mem_allocate(isc_mem_t *ctx0, size_t size FLARG) {
mem_getstats(ctx, si[-1].u.size); mem_getstats(ctx, si[-1].u.size);
ADD_TRACE(ctx, si, si[-1].u.size, file, line); ADD_TRACE(ctx, si, si[-1].u.size, file, line);
if (ctx->hi_water != 0U && ctx->inuse > ctx->hi_water && if (ctx->hi_water != 0U && ctx->inuse > ctx->hi_water) {
!ctx->is_overmem) { atomic_store_relaxed(&ctx->is_overmem, true);
ctx->is_overmem = true;
} }
if (ctx->hi_water != 0U && !ctx->hi_called && if (ctx->hi_water != 0U && !ctx->hi_called &&
@@ -1371,9 +1370,8 @@ isc___mem_free(isc_mem_t *ctx0, void *ptr FLARG) {
* when the context was pushed over hi_water but then had * when the context was pushed over hi_water but then had
* isc_mem_setwater() called with 0 for hi_water and lo_water. * isc_mem_setwater() called with 0 for hi_water and lo_water.
*/ */
if (ctx->is_overmem && if (ctx->inuse < ctx->lo_water || ctx->lo_water == 0U) {
(ctx->inuse < ctx->lo_water || ctx->lo_water == 0U)) { atomic_store_relaxed(&ctx->is_overmem, false);
ctx->is_overmem = false;
} }
if (ctx->hi_called && if (ctx->hi_called &&
@@ -1518,7 +1516,7 @@ isc_mem_isovermem(isc_mem_t *ctx0) {
* necessary (and even if we locked the context the returned value * necessary (and even if we locked the context the returned value
* could be different from the actual state when it's used anyway) * could be different from the actual state when it's used anyway)
*/ */
return (ctx->is_overmem); return (atomic_load_relaxed(&ctx->is_overmem));
} }
void void
+48 -32
View File
@@ -18,6 +18,10 @@
#include <stddef.h> #include <stddef.h>
#include <inttypes.h> #include <inttypes.h>
#if defined(sun) && (defined(__sparc) || defined(__sparc__))
#include <synch.h> /* for smt_pause(3c) */
#endif
#include <isc/atomic.h> #include <isc/atomic.h>
#include <isc/magic.h> #include <isc/magic.h>
#include <isc/platform.h> #include <isc/platform.h>
@@ -52,6 +56,8 @@
# define isc_rwlock_pause() __asm__ __volatile__ ("hint @pause") # define isc_rwlock_pause() __asm__ __volatile__ ("hint @pause")
#elif defined(__arm__) #elif defined(__arm__)
# define isc_rwlock_pause() __asm__ __volatile__ ("yield") # define isc_rwlock_pause() __asm__ __volatile__ ("yield")
#elif defined(sun) && (defined(__sparc) || defined(__sparc__))
# define isc_rwlock_pause() smt_pause()
#elif defined(__sparc) || defined(__sparc__) #elif defined(__sparc) || defined(__sparc__)
# define isc_rwlock_pause() __asm__ __volatile__ ("pause") # define isc_rwlock_pause() __asm__ __volatile__ ("pause")
#elif defined(__ppc__) || defined(_ARCH_PPC) || \ #elif defined(__ppc__) || defined(_ARCH_PPC) || \
@@ -77,9 +83,9 @@ print_lock(const char *operation, isc_rwlock_t *rwl, isc_rwlocktype_t type) {
"write_granted=%u, write_quota=%u\n", "write_granted=%u, write_quota=%u\n",
rwl, isc_thread_self(), operation, rwl, isc_thread_self(), operation,
(type == isc_rwlocktype_read ? "read" : "write"), (type == isc_rwlocktype_read ? "read" : "write"),
atomic_load_explicit(&rwl->write_requests, memory_order_relaxed), atomic_load_relaxed(&rwl->write_requests),
atomic_load_explicit(&rwl->write_completions, memory_order_relaxed), atomic_load_relaxed(&rwl->write_completions),
atomic_load_explicit(&rwl->cnt_and_flag, memory_order_relaxed), atomic_load_relaxed(&rwl->cnt_and_flag),
rwl->readers_waiting, rwl->readers_waiting,
rwl->write_granted, rwl->write_quota); rwl->write_granted, rwl->write_quota);
} }
@@ -97,7 +103,7 @@ isc_rwlock_init(isc_rwlock_t *rwl, unsigned int read_quota,
*/ */
rwl->magic = 0; rwl->magic = 0;
rwl->spins = 0; atomic_init(&rwl->spins, 0);
atomic_init(&rwl->write_requests, 0); atomic_init(&rwl->write_requests, 0);
atomic_init(&rwl->write_completions, 0); atomic_init(&rwl->write_completions, 0);
atomic_init(&rwl->cnt_and_flag, 0); atomic_init(&rwl->cnt_and_flag, 0);
@@ -125,9 +131,9 @@ void
isc_rwlock_destroy(isc_rwlock_t *rwl) { isc_rwlock_destroy(isc_rwlock_t *rwl) {
REQUIRE(VALID_RWLOCK(rwl)); REQUIRE(VALID_RWLOCK(rwl));
REQUIRE(atomic_load_explicit(&rwl->write_requests, memory_order_relaxed) == REQUIRE(atomic_load_relaxed(&rwl->write_requests) ==
atomic_load_explicit(&rwl->write_completions, memory_order_relaxed) && atomic_load_relaxed(&rwl->write_completions) &&
atomic_load_explicit(&rwl->cnt_and_flag, memory_order_relaxed) == 0 && rwl->readers_waiting == 0); atomic_load_relaxed(&rwl->cnt_and_flag) == 0 && rwl->readers_waiting == 0);
rwl->magic = 0; rwl->magic = 0;
(void)isc_condition_destroy(&rwl->readable); (void)isc_condition_destroy(&rwl->readable);
@@ -211,13 +217,13 @@ isc__rwlock_lock(isc_rwlock_t *rwl, isc_rwlocktype_t type) {
#endif #endif
if (type == isc_rwlocktype_read) { if (type == isc_rwlocktype_read) {
if (atomic_load_explicit(&rwl->write_requests, memory_order_relaxed) != if (atomic_load_relaxed(&rwl->write_requests) !=
atomic_load_explicit(&rwl->write_completions, memory_order_relaxed)) atomic_load_relaxed(&rwl->write_completions))
{ {
/* there is a waiting or active writer */ /* there is a waiting or active writer */
LOCK(&rwl->lock); LOCK(&rwl->lock);
if (atomic_load_explicit(&rwl->write_requests, memory_order_relaxed) != if (atomic_load_relaxed(&rwl->write_requests) !=
atomic_load_explicit(&rwl->write_completions, memory_order_relaxed)) { atomic_load_relaxed(&rwl->write_completions)) {
rwl->readers_waiting++; rwl->readers_waiting++;
WAIT(&rwl->readable, &rwl->lock); WAIT(&rwl->readable, &rwl->lock);
rwl->readers_waiting--; rwl->readers_waiting--;
@@ -230,13 +236,16 @@ isc__rwlock_lock(isc_rwlock_t *rwl, isc_rwlocktype_t type) {
memory_order_relaxed); memory_order_relaxed);
POST(cntflag); POST(cntflag);
while (1) { while (1) {
if ((atomic_load_explicit(&rwl->cnt_and_flag, memory_order_relaxed) & WRITER_ACTIVE) == 0) if ((atomic_load_relaxed(&rwl->cnt_and_flag) &
WRITER_ACTIVE) == 0) {
break; break;
}
/* A writer is still working */ /* A writer is still working */
LOCK(&rwl->lock); LOCK(&rwl->lock);
rwl->readers_waiting++; rwl->readers_waiting++;
if ((atomic_load_explicit(&rwl->cnt_and_flag, memory_order_relaxed) & WRITER_ACTIVE) != 0) { if ((atomic_load_relaxed(&rwl->cnt_and_flag)
& WRITER_ACTIVE) != 0) {
WAIT(&rwl->readable, &rwl->lock); WAIT(&rwl->readable, &rwl->lock);
} }
rwl->readers_waiting--; rwl->readers_waiting--;
@@ -273,16 +282,18 @@ isc__rwlock_lock(isc_rwlock_t *rwl, isc_rwlocktype_t type) {
* quota, reset the condition (race among readers doesn't * quota, reset the condition (race among readers doesn't
* matter). * matter).
*/ */
rwl->write_granted = 0; atomic_store_relaxed(&rwl->write_granted, 0);
} else { } else {
int32_t prev_writer; int32_t prev_writer;
/* enter the waiting queue, and wait for our turn */ /* enter the waiting queue, and wait for our turn */
prev_writer = atomic_fetch_add_explicit(&rwl->write_requests, 1, prev_writer = atomic_fetch_add_explicit(&rwl->write_requests, 1,
memory_order_relaxed); memory_order_relaxed);
while (atomic_load_explicit(&rwl->write_completions, memory_order_relaxed) != prev_writer) { while (atomic_load_relaxed(&rwl->write_completions) !=
prev_writer) {
LOCK(&rwl->lock); LOCK(&rwl->lock);
if (atomic_load_explicit(&rwl->write_completions, memory_order_relaxed) != prev_writer) { if (atomic_load_relaxed(&rwl->write_completions) !=
prev_writer) {
WAIT(&rwl->writeable, &rwl->lock); WAIT(&rwl->writeable, &rwl->lock);
UNLOCK(&rwl->lock); UNLOCK(&rwl->lock);
continue; continue;
@@ -302,13 +313,14 @@ isc__rwlock_lock(isc_rwlock_t *rwl, isc_rwlocktype_t type) {
/* Another active reader or writer is working. */ /* Another active reader or writer is working. */
LOCK(&rwl->lock); LOCK(&rwl->lock);
if (atomic_load_explicit(&rwl->cnt_and_flag, memory_order_relaxed) != 0) { if (atomic_load_relaxed(&rwl->cnt_and_flag) != 0) {
WAIT(&rwl->writeable, &rwl->lock); WAIT(&rwl->writeable, &rwl->lock);
} }
UNLOCK(&rwl->lock); UNLOCK(&rwl->lock);
} }
INSIST((atomic_load_explicit(&rwl->cnt_and_flag, memory_order_relaxed) & WRITER_ACTIVE)); INSIST((atomic_load_relaxed(&rwl->cnt_and_flag) &
WRITER_ACTIVE));
rwl->write_granted++; rwl->write_granted++;
} }
@@ -322,7 +334,8 @@ isc__rwlock_lock(isc_rwlock_t *rwl, isc_rwlocktype_t type) {
isc_result_t isc_result_t
isc_rwlock_lock(isc_rwlock_t *rwl, isc_rwlocktype_t type) { isc_rwlock_lock(isc_rwlock_t *rwl, isc_rwlocktype_t type) {
int32_t cnt = 0; int32_t cnt = 0;
int32_t max_cnt = rwl->spins * 2 + 10; int32_t max_cnt = atomic_load_relaxed(&rwl->spins) * 2 + 10;
int32_t spins;
isc_result_t result = ISC_R_SUCCESS; isc_result_t result = ISC_R_SUCCESS;
if (max_cnt > RWLOCK_MAX_ADAPTIVE_COUNT) if (max_cnt > RWLOCK_MAX_ADAPTIVE_COUNT)
@@ -336,7 +349,9 @@ isc_rwlock_lock(isc_rwlock_t *rwl, isc_rwlocktype_t type) {
isc_rwlock_pause(); isc_rwlock_pause();
} while (isc_rwlock_trylock(rwl, type) != ISC_R_SUCCESS); } while (isc_rwlock_trylock(rwl, type) != ISC_R_SUCCESS);
rwl->spins += (cnt - rwl->spins) / 8; spins = atomic_load_relaxed(&rwl->spins);
spins += (cnt - spins) / 8;
atomic_store_relaxed(&rwl->spins, spins);
return (result); return (result);
} }
@@ -353,8 +368,8 @@ isc_rwlock_trylock(isc_rwlock_t *rwl, isc_rwlocktype_t type) {
if (type == isc_rwlocktype_read) { if (type == isc_rwlocktype_read) {
/* If a writer is waiting or working, we fail. */ /* If a writer is waiting or working, we fail. */
if (atomic_load_explicit(&rwl->write_requests, memory_order_relaxed) != if (atomic_load_relaxed(&rwl->write_requests) !=
atomic_load_explicit(&rwl->write_completions, memory_order_relaxed)) atomic_load_relaxed(&rwl->write_completions))
return (ISC_R_LOCKBUSY); return (ISC_R_LOCKBUSY);
/* Otherwise, be ready for reading. */ /* Otherwise, be ready for reading. */
@@ -374,8 +389,8 @@ isc_rwlock_trylock(isc_rwlock_t *rwl, isc_rwlocktype_t type) {
* new writers in this short period, wake them up. * new writers in this short period, wake them up.
*/ */
if (cntflag == READER_INCR && if (cntflag == READER_INCR &&
atomic_load_explicit(&rwl->write_completions, memory_order_relaxed) != atomic_load_relaxed(&rwl->write_completions) !=
atomic_load_explicit(&rwl->write_requests, memory_order_relaxed)) { atomic_load_relaxed(&rwl->write_requests)) {
LOCK(&rwl->lock); LOCK(&rwl->lock);
BROADCAST(&rwl->writeable); BROADCAST(&rwl->writeable);
UNLOCK(&rwl->lock); UNLOCK(&rwl->lock);
@@ -400,7 +415,8 @@ isc_rwlock_trylock(isc_rwlock_t *rwl, isc_rwlocktype_t type) {
atomic_fetch_sub_explicit(&rwl->write_completions, 1, atomic_fetch_sub_explicit(&rwl->write_completions, 1,
memory_order_relaxed); memory_order_relaxed);
rwl->write_granted++; atomic_fetch_add_explicit(&rwl->write_granted, 1,
memory_order_relaxed);
} }
#ifdef ISC_RWLOCK_TRACE #ifdef ISC_RWLOCK_TRACE
@@ -491,8 +507,8 @@ isc_rwlock_unlock(isc_rwlock_t *rwl, isc_rwlocktype_t type) {
* FIFO order. * FIFO order.
*/ */
if (prev_cnt == READER_INCR && if (prev_cnt == READER_INCR &&
atomic_load_explicit(&rwl->write_completions, memory_order_relaxed) != atomic_load_relaxed(&rwl->write_completions) !=
atomic_load_explicit(&rwl->write_requests, memory_order_relaxed)) { atomic_load_relaxed(&rwl->write_requests)) {
LOCK(&rwl->lock); LOCK(&rwl->lock);
BROADCAST(&rwl->writeable); BROADCAST(&rwl->writeable);
UNLOCK(&rwl->lock); UNLOCK(&rwl->lock);
@@ -510,9 +526,9 @@ isc_rwlock_unlock(isc_rwlock_t *rwl, isc_rwlocktype_t type) {
memory_order_relaxed); memory_order_relaxed);
if (rwl->write_granted >= rwl->write_quota || if (rwl->write_granted >= rwl->write_quota ||
(atomic_load_explicit(&rwl->write_requests, memory_order_relaxed) == (atomic_load_relaxed(&rwl->write_requests) ==
atomic_load_explicit(&rwl->write_completions, memory_order_relaxed)) || atomic_load_relaxed(&rwl->write_completions)) ||
(atomic_load_explicit(&rwl->cnt_and_flag, memory_order_relaxed) & ~WRITER_ACTIVE)) { (atomic_load_relaxed(&rwl->cnt_and_flag) & ~WRITER_ACTIVE)) {
/* /*
* We have passed the write quota, no writer is * We have passed the write quota, no writer is
* waiting, or some readers are almost ready, pending * waiting, or some readers are almost ready, pending
@@ -529,8 +545,8 @@ isc_rwlock_unlock(isc_rwlock_t *rwl, isc_rwlocktype_t type) {
UNLOCK(&rwl->lock); UNLOCK(&rwl->lock);
} }
if ((atomic_load_explicit(&rwl->write_requests, memory_order_relaxed) != if ((atomic_load_relaxed(&rwl->write_requests) !=
atomic_load_explicit(&rwl->write_completions, memory_order_relaxed)) && atomic_load_relaxed(&rwl->write_completions)) &&
wakeup_writers) { wakeup_writers) {
LOCK(&rwl->lock); LOCK(&rwl->lock);
BROADCAST(&rwl->writeable); BROADCAST(&rwl->writeable);
+72 -58
View File
@@ -147,15 +147,16 @@ struct isc__taskmgr {
atomic_uint_fast32_t tasks_running; atomic_uint_fast32_t tasks_running;
atomic_uint_fast32_t tasks_ready; atomic_uint_fast32_t tasks_ready;
atomic_uint_fast32_t curq; atomic_uint_fast32_t curq;
atomic_uint_fast32_t tasks_count;
isc__taskqueue_t *queues; isc__taskqueue_t *queues;
/* Locked by task manager lock. */ /* Locked by task manager lock. */
unsigned int default_quantum; unsigned int default_quantum;
LIST(isc__task_t) tasks; LIST(isc__task_t) tasks;
isc_taskmgrmode_t mode; atomic_uint_fast32_t mode;
bool pause_requested; atomic_bool pause_req;
bool exclusive_requested; atomic_bool exclusive_req;
bool exiting; atomic_bool exiting;
/* Locked by halt_lock */ /* Locked by halt_lock */
unsigned int halted; unsigned int halted;
@@ -176,7 +177,8 @@ isc__taskmgr_resume(isc_taskmgr_t *manager0);
#define DEFAULT_DEFAULT_QUANTUM 25 #define DEFAULT_DEFAULT_QUANTUM 25
#define FINISHED(m) ((m)->exiting && EMPTY((m)->tasks)) #define FINISHED(m) (atomic_load_relaxed(&((m)->exiting)) == true && \
atomic_load(&(m)->tasks_count) == 0)
/*% /*%
* The following are intended for internal use (indicated by "isc__" * The following are intended for internal use (indicated by "isc__"
@@ -228,6 +230,7 @@ task_finished(isc__task_t *task) {
LOCK(&manager->lock); LOCK(&manager->lock);
UNLINK(manager->tasks, task, link); UNLINK(manager->tasks, task, link);
atomic_fetch_sub(&manager->tasks_count, 1);
UNLOCK(&manager->lock); UNLOCK(&manager->lock);
if (FINISHED(manager)) { if (FINISHED(manager)) {
/* /*
@@ -303,8 +306,9 @@ isc_task_create_bound(isc_taskmgr_t *manager0, unsigned int quantum,
exiting = false; exiting = false;
LOCK(&manager->lock); LOCK(&manager->lock);
if (!manager->exiting) { if (!atomic_load_relaxed(&manager->exiting)) {
APPEND(manager->tasks, task, link); APPEND(manager->tasks, task, link);
atomic_fetch_add(&manager->tasks_count, 1);
} else { } else {
exiting = true; exiting = true;
} }
@@ -397,7 +401,8 @@ task_ready(isc__task_t *task) {
XTRACE("task_ready"); XTRACE("task_ready");
LOCK(&manager->queues[task->threadid].lock); LOCK(&manager->queues[task->threadid].lock);
push_readyq(manager, task, task->threadid); push_readyq(manager, task, task->threadid);
if (manager->mode == isc_taskmgrmode_normal || has_privilege) { if (atomic_load(&manager->mode) == isc_taskmgrmode_normal ||
has_privilege) {
SIGNAL(&manager->queues[task->threadid].work_available); SIGNAL(&manager->queues[task->threadid].work_available);
} }
UNLOCK(&manager->queues[task->threadid].lock); UNLOCK(&manager->queues[task->threadid].lock);
@@ -512,6 +517,13 @@ isc_task_sendto(isc_task_t *task0, isc_event_t **eventp, int c) {
REQUIRE(VALID_TASK(task)); REQUIRE(VALID_TASK(task));
XTRACE("isc_task_send"); XTRACE("isc_task_send");
/*
* We're trying hard to hold locks for as short a time as possible.
* We're also trying to hold as few locks as possible. This is why
* some processing is deferred until after the lock is released.
*/
LOCK(&task->lock);
/* If task is bound ignore provided cpu. */ /* If task is bound ignore provided cpu. */
if (task->bound) { if (task->bound) {
c = task->threadid; c = task->threadid;
@@ -520,13 +532,6 @@ isc_task_sendto(isc_task_t *task0, isc_event_t **eventp, int c) {
memory_order_relaxed); memory_order_relaxed);
} }
c %= task->manager->workers; c %= task->manager->workers;
/*
* We're trying hard to hold locks for as short a time as possible.
* We're also trying to hold as few locks as possible. This is why
* some processing is deferred until after the lock is released.
*/
LOCK(&task->lock);
was_idle = task_send(task, eventp, c); was_idle = task_send(task, eventp, c);
UNLOCK(&task->lock); UNLOCK(&task->lock);
@@ -565,6 +570,7 @@ isc_task_sendtoanddetach(isc_task_t **taskp, isc_event_t **eventp, int c) {
REQUIRE(VALID_TASK(task)); REQUIRE(VALID_TASK(task));
XTRACE("isc_task_sendanddetach"); XTRACE("isc_task_sendanddetach");
LOCK(&task->lock);
if (task->bound) { if (task->bound) {
c = task->threadid; c = task->threadid;
} else if (c < 0) { } else if (c < 0) {
@@ -572,8 +578,6 @@ isc_task_sendtoanddetach(isc_task_t **taskp, isc_event_t **eventp, int c) {
memory_order_relaxed); memory_order_relaxed);
} }
c %= task->manager->workers; c %= task->manager->workers;
LOCK(&task->lock);
idle1 = task_send(task, eventp, c); idle1 = task_send(task, eventp, c);
idle2 = task_detach(task); idle2 = task_detach(task);
UNLOCK(&task->lock); UNLOCK(&task->lock);
@@ -902,11 +906,11 @@ static inline bool
empty_readyq(isc__taskmgr_t *manager, int c) { empty_readyq(isc__taskmgr_t *manager, int c) {
isc__tasklist_t queue; isc__tasklist_t queue;
if (manager->mode == isc_taskmgrmode_normal) if (atomic_load_relaxed(&manager->mode) == isc_taskmgrmode_normal) {
queue = manager->queues[c].ready_tasks; queue = manager->queues[c].ready_tasks;
else } else {
queue = manager->queues[c].ready_priority_tasks; queue = manager->queues[c].ready_priority_tasks;
}
return (EMPTY(queue)); return (EMPTY(queue));
} }
@@ -922,7 +926,7 @@ static inline isc__task_t *
pop_readyq(isc__taskmgr_t *manager, int c) { pop_readyq(isc__taskmgr_t *manager, int c) {
isc__task_t *task; isc__task_t *task;
if (manager->mode == isc_taskmgrmode_normal) { if (atomic_load_relaxed(&manager->mode) == isc_taskmgrmode_normal) {
task = HEAD(manager->queues[c].ready_tasks); task = HEAD(manager->queues[c].ready_tasks);
} else { } else {
task = HEAD(manager->queues[c].ready_priority_tasks); task = HEAD(manager->queues[c].ready_priority_tasks);
@@ -1029,15 +1033,15 @@ dispatch(isc__taskmgr_t *manager, unsigned int threadid) {
* until it's been released. * until it's been released.
*/ */
while ((empty_readyq(manager, threadid) && while ((empty_readyq(manager, threadid) &&
!manager->pause_requested && !atomic_load_relaxed(&manager->pause_req) &&
!manager->exclusive_requested) && !atomic_load_relaxed(&manager->exclusive_req)) &&
!FINISHED(manager)) !FINISHED(manager))
{ {
XTHREADTRACE("wait"); XTHREADTRACE("wait");
XTHREADTRACE(manager->pause_requested XTHREADTRACE(atomic_load_relaxed(&manager->pause_req)
? "paused" ? "paused"
: "notpaused"); : "notpaused");
XTHREADTRACE(manager->exclusive_requested XTHREADTRACE(atomic_load_relaxed(&manager->exclusive_req)
? "excreq" ? "excreq"
: "notexcreq"); : "notexcreq");
WAIT(&manager->queues[threadid].work_available, WAIT(&manager->queues[threadid].work_available,
@@ -1046,15 +1050,16 @@ dispatch(isc__taskmgr_t *manager, unsigned int threadid) {
} }
XTHREADTRACE("working"); XTHREADTRACE("working");
if (manager->pause_requested || manager->exclusive_requested) { if (atomic_load_relaxed(&manager->pause_req) ||
atomic_load_relaxed(&manager->exclusive_req)) {
UNLOCK(&manager->queues[threadid].lock); UNLOCK(&manager->queues[threadid].lock);
XTHREADTRACE("halting"); XTHREADTRACE("halting");
/* /*
* Switching to exclusive mode is done as a * Switching to exclusive mode is done as a
* 2-phase-lock, checking if we have to switch is * 2-phase-lock, checking if we have to switch is
* done without any locks on pause_requested and * done without any locks on pause_req and
* exclusive_requested to save time - the worst * exclusive_req to save time - the worst
* thing that can happen is that we'll launch one * thing that can happen is that we'll launch one
* task more and exclusive task will be postponed a * task more and exclusive task will be postponed a
* bit. * bit.
@@ -1066,8 +1071,8 @@ dispatch(isc__taskmgr_t *manager, unsigned int threadid) {
LOCK(&manager->halt_lock); LOCK(&manager->halt_lock);
manager->halted++; manager->halted++;
BROADCAST(&manager->halt_cond); BROADCAST(&manager->halt_cond);
while (manager->pause_requested || while (atomic_load_relaxed(&manager->pause_req) ||
manager->exclusive_requested) atomic_load_relaxed(&manager->exclusive_req))
{ {
WAIT(&manager->halt_cond, &manager->halt_lock); WAIT(&manager->halt_cond, &manager->halt_lock);
} }
@@ -1260,7 +1265,8 @@ dispatch(isc__taskmgr_t *manager, unsigned int threadid) {
UNLOCK(&manager->queues[i].lock); UNLOCK(&manager->queues[i].lock);
} }
if (empty) { if (empty) {
manager->mode = isc_taskmgrmode_normal; atomic_store(&manager->mode,
isc_taskmgrmode_normal);
wake_all_queues(manager); wake_all_queues(manager);
} }
} }
@@ -1331,7 +1337,7 @@ isc_taskmgr_create(isc_mem_t *mctx, unsigned int workers,
RUNTIME_CHECK(manager != NULL); RUNTIME_CHECK(manager != NULL);
manager->common.impmagic = TASK_MANAGER_MAGIC; manager->common.impmagic = TASK_MANAGER_MAGIC;
manager->common.magic = ISCAPI_TASKMGR_MAGIC; manager->common.magic = ISCAPI_TASKMGR_MAGIC;
manager->mode = isc_taskmgrmode_normal; atomic_store(&manager->mode, isc_taskmgrmode_normal);
manager->mctx = NULL; manager->mctx = NULL;
isc_mutex_init(&manager->lock); isc_mutex_init(&manager->lock);
isc_mutex_init(&manager->excl_lock); isc_mutex_init(&manager->excl_lock);
@@ -1346,6 +1352,7 @@ isc_taskmgr_create(isc_mem_t *mctx, unsigned int workers,
} }
manager->default_quantum = default_quantum; manager->default_quantum = default_quantum;
INIT_LIST(manager->tasks); INIT_LIST(manager->tasks);
atomic_store(&manager->tasks_count, 0);
manager->queues = isc_mem_get(mctx, workers * sizeof(isc__taskqueue_t)); manager->queues = isc_mem_get(mctx, workers * sizeof(isc__taskqueue_t));
RUNTIME_CHECK(manager->queues != NULL); RUNTIME_CHECK(manager->queues != NULL);
@@ -1355,8 +1362,8 @@ isc_taskmgr_create(isc_mem_t *mctx, unsigned int workers,
manager->exiting = false; manager->exiting = false;
manager->excl = NULL; manager->excl = NULL;
manager->halted = 0; manager->halted = 0;
manager->exclusive_requested = false; atomic_store_relaxed(&manager->exclusive_req, false);
manager->pause_requested = false; atomic_store_relaxed(&manager->pause_req, false);
isc_mem_attach(mctx, &manager->mctx); isc_mem_attach(mctx, &manager->mctx);
@@ -1433,13 +1440,13 @@ isc_taskmgr_destroy(isc_taskmgr_t **managerp) {
/* /*
* Make sure we only get called once. * Make sure we only get called once.
*/ */
INSIST(!manager->exiting); INSIST(!atomic_load(&manager->exiting));
manager->exiting = true; atomic_store(&manager->exiting, true);
/* /*
* If privileged mode was on, turn it off. * If privileged mode was on, turn it off.
*/ */
manager->mode = isc_taskmgrmode_normal; atomic_store(&manager->mode, isc_taskmgrmode_normal);
/* /*
* Post shutdown event(s) to every task (if they haven't already been * Post shutdown event(s) to every task (if they haven't already been
@@ -1481,19 +1488,13 @@ void
isc_taskmgr_setprivilegedmode(isc_taskmgr_t *manager0) { isc_taskmgr_setprivilegedmode(isc_taskmgr_t *manager0) {
isc__taskmgr_t *manager = (isc__taskmgr_t *)manager0; isc__taskmgr_t *manager = (isc__taskmgr_t *)manager0;
LOCK(&manager->lock); atomic_store(&manager->mode, isc_taskmgrmode_privileged);
manager->mode = isc_taskmgrmode_privileged;
UNLOCK(&manager->lock);
} }
isc_taskmgrmode_t isc_taskmgrmode_t
isc_taskmgr_mode(isc_taskmgr_t *manager0) { isc_taskmgr_mode(isc_taskmgr_t *manager0) {
isc__taskmgr_t *manager = (isc__taskmgr_t *)manager0; isc__taskmgr_t *manager = (isc__taskmgr_t *)manager0;
isc_taskmgrmode_t mode; return (atomic_load(&manager->mode));
LOCK(&manager->lock);
mode = manager->mode;
UNLOCK(&manager->lock);
return (mode);
} }
void void
@@ -1501,14 +1502,15 @@ isc__taskmgr_pause(isc_taskmgr_t *manager0) {
isc__taskmgr_t *manager = (isc__taskmgr_t *)manager0; isc__taskmgr_t *manager = (isc__taskmgr_t *)manager0;
LOCK(&manager->halt_lock); LOCK(&manager->halt_lock);
while (manager->exclusive_requested || manager->pause_requested) { while (atomic_load_relaxed(&manager->exclusive_req) ||
atomic_load_relaxed(&manager->pause_req)) {
UNLOCK(&manager->halt_lock); UNLOCK(&manager->halt_lock);
/* This is ugly but pause is used EXCLUSIVELY in tests */ /* This is ugly but pause is used EXCLUSIVELY in tests */
isc_thread_yield(); isc_thread_yield();
LOCK(&manager->halt_lock); LOCK(&manager->halt_lock);
} }
manager->pause_requested = true; atomic_store_relaxed(&manager->pause_req, true);
while (manager->halted < manager->workers) { while (manager->halted < manager->workers) {
wake_all_queues(manager); wake_all_queues(manager);
WAIT(&manager->halt_cond, &manager->halt_lock); WAIT(&manager->halt_cond, &manager->halt_lock);
@@ -1520,8 +1522,8 @@ void
isc__taskmgr_resume(isc_taskmgr_t *manager0) { isc__taskmgr_resume(isc_taskmgr_t *manager0) {
isc__taskmgr_t *manager = (isc__taskmgr_t *)manager0; isc__taskmgr_t *manager = (isc__taskmgr_t *)manager0;
LOCK(&manager->halt_lock); LOCK(&manager->halt_lock);
if (manager->pause_requested) { if (manager->pause_req) {
manager->pause_requested = false; manager->pause_req = false;
while (manager->halted > 0) { while (manager->halted > 0) {
BROADCAST(&manager->halt_cond); BROADCAST(&manager->halt_cond);
WAIT(&manager->halt_cond, &manager->halt_lock); WAIT(&manager->halt_cond, &manager->halt_lock);
@@ -1573,16 +1575,19 @@ isc_task_beginexclusive(isc_task_t *task0) {
LOCK(&manager->excl_lock); LOCK(&manager->excl_lock);
REQUIRE(task == task->manager->excl || REQUIRE(task == task->manager->excl ||
(task->manager->exiting && task->manager->excl == NULL)); (atomic_load_relaxed(&task->manager->exiting) &&
task->manager->excl == NULL));
UNLOCK(&manager->excl_lock); UNLOCK(&manager->excl_lock);
if (manager->exclusive_requested || manager->pause_requested) { if (atomic_load_relaxed(&manager->exclusive_req) ||
atomic_load_relaxed(&manager->pause_req)) {
return (ISC_R_LOCKBUSY); return (ISC_R_LOCKBUSY);
} }
LOCK(&manager->halt_lock); LOCK(&manager->halt_lock);
INSIST(!manager->exclusive_requested && !manager->pause_requested); INSIST(!atomic_load_relaxed(&manager->exclusive_req) &&
manager->exclusive_requested = true; !atomic_load_relaxed(&manager->pause_req));
atomic_store_relaxed(&manager->exclusive_req, true);
while (manager->halted + 1 < manager->workers) { while (manager->halted + 1 < manager->workers) {
wake_all_queues(manager); wake_all_queues(manager);
WAIT(&manager->halt_cond, &manager->halt_lock); WAIT(&manager->halt_cond, &manager->halt_lock);
@@ -1599,8 +1604,8 @@ isc_task_endexclusive(isc_task_t *task0) {
REQUIRE(VALID_TASK(task)); REQUIRE(VALID_TASK(task));
REQUIRE(task->state == task_state_running); REQUIRE(task->state == task_state_running);
LOCK(&manager->halt_lock); LOCK(&manager->halt_lock);
REQUIRE(manager->exclusive_requested); REQUIRE(atomic_load_relaxed(&manager->exclusive_req) == true);
manager->exclusive_requested = false; atomic_store_relaxed(&manager->exclusive_req, false);
while (manager->halted > 0) { while (manager->halted > 0) {
BROADCAST(&manager->halt_cond); BROADCAST(&manager->halt_cond);
WAIT(&manager->halt_cond, &manager->halt_lock); WAIT(&manager->halt_cond, &manager->halt_lock);
@@ -1685,14 +1690,19 @@ isc_taskmgr_renderxml(isc_taskmgr_t *mgr0, xmlTextWriterPtr writer) {
mgr->default_quantum)); mgr->default_quantum));
TRY0(xmlTextWriterEndElement(writer)); /* default-quantum */ TRY0(xmlTextWriterEndElement(writer)); /* default-quantum */
TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "tasks-count"));
TRY0(xmlTextWriterWriteFormatString(writer, "%d",
(int) atomic_load_relaxed(&mgr->tasks_count)));
TRY0(xmlTextWriterEndElement(writer)); /* tasks-count */
TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "tasks-running")); TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "tasks-running"));
TRY0(xmlTextWriterWriteFormatString(writer, "%d", TRY0(xmlTextWriterWriteFormatString(writer, "%d",
(int) mgr->tasks_running)); (int) atomic_load_relaxed(&mgr->tasks_running)));
TRY0(xmlTextWriterEndElement(writer)); /* tasks-running */ TRY0(xmlTextWriterEndElement(writer)); /* tasks-running */
TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "tasks-ready")); TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "tasks-ready"));
TRY0(xmlTextWriterWriteFormatString(writer, "%d", TRY0(xmlTextWriterWriteFormatString(writer, "%d",
(int) mgr->tasks_ready)); (int) atomic_load_relaxed(&mgr->tasks_ready)));
TRY0(xmlTextWriterEndElement(writer)); /* tasks-ready */ TRY0(xmlTextWriterEndElement(writer)); /* tasks-ready */
TRY0(xmlTextWriterEndElement(writer)); /* thread-model */ TRY0(xmlTextWriterEndElement(writer)); /* thread-model */
@@ -1785,11 +1795,15 @@ isc_taskmgr_renderjson(isc_taskmgr_t *mgr0, json_object *tasks) {
CHECKMEM(obj); CHECKMEM(obj);
json_object_object_add(tasks, "default-quantum", obj); json_object_object_add(tasks, "default-quantum", obj);
obj = json_object_new_int(mgr->tasks_running); obj = json_object_new_int(atomic_load_relaxed(&mgr->tasks_count));
CHECKMEM(obj);
json_object_object_add(tasks, "tasks-count", obj);
obj = json_object_new_int(atomic_load_relaxed(&mgr->tasks_running));
CHECKMEM(obj); CHECKMEM(obj);
json_object_object_add(tasks, "tasks-running", obj); json_object_object_add(tasks, "tasks-running", obj);
obj = json_object_new_int(mgr->tasks_ready); obj = json_object_new_int(atomic_load_relaxed(&mgr->tasks_ready));
CHECKMEM(obj); CHECKMEM(obj);
json_object_object_add(tasks, "tasks-ready", obj); json_object_object_add(tasks, "tasks-ready", obj);
+36 -31
View File
@@ -36,6 +36,7 @@
#include <isc/event.h> #include <isc/event.h>
#include <isc/platform.h> #include <isc/platform.h>
#include <isc/strerr.h> #include <isc/strerr.h>
#include <isc/atomic.h>
#include <isc/string.h> #include <isc/string.h>
#include <isc/task.h> #include <isc/task.h>
#include <isc/time.h> #include <isc/time.h>
@@ -50,7 +51,7 @@
* as an event loop dispatching various events. * as an event loop dispatching various events.
*/ */
static pthread_t blockedthread; static pthread_t blockedthread;
static bool is_running; static atomic_bool is_running;
/* /*
* The application context of this module. This implementation actually * The application context of this module. This implementation actually
@@ -70,13 +71,13 @@ typedef struct isc__appctx {
/*! /*!
* We assume that 'want_shutdown' can be read and written atomically. * We assume that 'want_shutdown' can be read and written atomically.
*/ */
bool want_shutdown; atomic_bool want_shutdown;
/* /*
* We assume that 'want_reload' can be read and written atomically. * We assume that 'want_reload' can be read and written atomically.
*/ */
bool want_reload; atomic_bool want_reload;
bool blocked; atomic_bool blocked;
isc_taskmgr_t *taskmgr; isc_taskmgr_t *taskmgr;
isc_socketmgr_t *socketmgr; isc_socketmgr_t *socketmgr;
@@ -91,13 +92,13 @@ static isc__appctx_t isc_g_appctx;
static void static void
exit_action(int arg) { exit_action(int arg) {
UNUSED(arg); UNUSED(arg);
isc_g_appctx.want_shutdown = true; atomic_store(&isc_g_appctx.want_shutdown, true);
} }
static void static void
reload_action(int arg) { reload_action(int arg) {
UNUSED(arg); UNUSED(arg);
isc_g_appctx.want_reload = true; atomic_store(&isc_g_appctx.want_reload, true);
} }
#endif #endif
@@ -145,9 +146,9 @@ isc_app_ctxstart(isc_appctx_t *ctx0) {
ctx->shutdown_requested = false; ctx->shutdown_requested = false;
ctx->running = false; ctx->running = false;
ctx->want_shutdown = false; atomic_store(&ctx->want_shutdown, false);
ctx->want_reload = false; atomic_store(&ctx->want_reload, false);
ctx->blocked = false; atomic_store(&ctx->blocked, false);
#ifndef HAVE_SIGWAIT #ifndef HAVE_SIGWAIT
/* /*
@@ -337,7 +338,7 @@ isc_app_ctxrun(isc_appctx_t *ctx0) {
* simply be made pending and we will get it when we call * simply be made pending and we will get it when we call
* sigwait(). * sigwait().
*/ */
while (!ctx->want_shutdown) { while (!atomic_load(&ctx->want_shutdown)) {
#ifdef HAVE_SIGWAIT #ifdef HAVE_SIGWAIT
if (isc_bind9) { if (isc_bind9) {
/* /*
@@ -357,10 +358,11 @@ isc_app_ctxrun(isc_appctx_t *ctx0) {
result = sigwait(&sset, &sig); result = sigwait(&sset, &sig);
if (result == 0) { if (result == 0) {
if (sig == SIGINT || sig == SIGTERM) if (sig == SIGINT || sig == SIGTERM) {
ctx->want_shutdown = true; atomic_store(&ctx->want_shutdown, true);
else if (sig == SIGHUP) } else if (sig == SIGHUP) {
ctx->want_reload = true; atomic_store(&ctx->want_reload, true);
}
} }
} else { } else {
@@ -369,12 +371,12 @@ isc_app_ctxrun(isc_appctx_t *ctx0) {
* wait until woken up. * wait until woken up.
*/ */
LOCK(&ctx->readylock); LOCK(&ctx->readylock);
if (ctx->want_shutdown) { if (atomic_load(&ctx->want_shutdown)) {
/* shutdown() won the race. */ /* shutdown() won the race. */
UNLOCK(&ctx->readylock); UNLOCK(&ctx->readylock);
break; break;
} }
if (!ctx->want_reload) if (!atomic_load(&ctx->want_reload))
WAIT(&ctx->ready, &ctx->readylock); WAIT(&ctx->ready, &ctx->readylock);
UNLOCK(&ctx->readylock); UNLOCK(&ctx->readylock);
} }
@@ -412,25 +414,28 @@ isc_app_ctxrun(isc_appctx_t *ctx0) {
* wait until woken up. * wait until woken up.
*/ */
LOCK(&ctx->readylock); LOCK(&ctx->readylock);
if (ctx->want_shutdown) { if (atomic_load(&ctx->want_shutdown)) {
/* shutdown() won the race. */ /* shutdown() won the race. */
UNLOCK(&ctx->readylock); UNLOCK(&ctx->readylock);
break; break;
} }
if (!ctx->want_reload) if (!atomic_load(&ctx->want_reload)) {
WAIT(&ctx->ready, &ctx->readylock); WAIT(&ctx->ready, &ctx->readylock);
}
UNLOCK(&ctx->readylock); UNLOCK(&ctx->readylock);
} }
#endif /* HAVE_SIGWAIT */ #endif /* HAVE_SIGWAIT */
if (ctx->want_reload) { if (atomic_load(&ctx->want_reload)) {
ctx->want_reload = false; atomic_store(&ctx->want_reload, false);
return (ISC_R_RELOAD); return (ISC_R_RELOAD);
} }
if (ctx->want_shutdown && ctx->blocked) if (atomic_load(&ctx->want_shutdown) &&
atomic_load(&ctx->blocked)) {
exit(1); exit(1);
} }
}
return (ISC_R_SUCCESS); return (ISC_R_SUCCESS);
} }
@@ -439,16 +444,16 @@ isc_result_t
isc_app_run(void) { isc_app_run(void) {
isc_result_t result; isc_result_t result;
is_running = true; atomic_store(&is_running, true);
result = isc_app_ctxrun((isc_appctx_t *)&isc_g_appctx); result = isc_app_ctxrun((isc_appctx_t *)&isc_g_appctx);
is_running = false; atomic_store(&is_running, false);
return (result); return (result);
} }
bool bool
isc_app_isrunning() { isc_app_isrunning() {
return (is_running); return (atomic_load(&is_running));
} }
isc_result_t isc_result_t
@@ -473,7 +478,7 @@ isc_app_ctxshutdown(isc_appctx_t *ctx0) {
if (want_kill) { if (want_kill) {
if (isc_bind9 && ctx != &isc_g_appctx) if (isc_bind9 && ctx != &isc_g_appctx)
/* BIND9 internal, but using multiple contexts */ /* BIND9 internal, but using multiple contexts */
ctx->want_shutdown = true; atomic_store(&ctx->want_shutdown, true);
else { else {
if (isc_bind9) { if (isc_bind9) {
/* BIND9 internal, single context */ /* BIND9 internal, single context */
@@ -489,7 +494,7 @@ isc_app_ctxshutdown(isc_appctx_t *ctx0) {
else { else {
/* External, multiple contexts */ /* External, multiple contexts */
LOCK(&ctx->readylock); LOCK(&ctx->readylock);
ctx->want_shutdown = true; atomic_store(&ctx->want_shutdown, true);
UNLOCK(&ctx->readylock); UNLOCK(&ctx->readylock);
SIGNAL(&ctx->ready); SIGNAL(&ctx->ready);
} }
@@ -527,9 +532,9 @@ isc_app_ctxsuspend(isc_appctx_t *ctx0) {
if (want_kill) { if (want_kill) {
if (isc_bind9 && ctx != &isc_g_appctx) if (isc_bind9 && ctx != &isc_g_appctx)
/* BIND9 internal, but using multiple contexts */ /* BIND9 internal, but using multiple contexts */
ctx->want_reload = true; atomic_store(&ctx->want_reload, true);
else { else {
ctx->want_reload = true; atomic_store(&ctx->want_reload, true);
if (isc_bind9) { if (isc_bind9) {
/* BIND9 internal, single context */ /* BIND9 internal, single context */
if (kill(getpid(), SIGHUP) < 0) { if (kill(getpid(), SIGHUP) < 0) {
@@ -544,7 +549,7 @@ isc_app_ctxsuspend(isc_appctx_t *ctx0) {
else { else {
/* External, multiple contexts */ /* External, multiple contexts */
LOCK(&ctx->readylock); LOCK(&ctx->readylock);
ctx->want_reload = true; atomic_store(&ctx->want_reload, true);
UNLOCK(&ctx->readylock); UNLOCK(&ctx->readylock);
SIGNAL(&ctx->ready); SIGNAL(&ctx->ready);
} }
@@ -577,9 +582,9 @@ void
isc_app_block(void) { isc_app_block(void) {
sigset_t sset; sigset_t sset;
REQUIRE(isc_g_appctx.running); REQUIRE(isc_g_appctx.running);
REQUIRE(!isc_g_appctx.blocked); REQUIRE(!atomic_load(&isc_g_appctx.blocked));
isc_g_appctx.blocked = true; atomic_store(&isc_g_appctx.blocked, true);
blockedthread = pthread_self(); blockedthread = pthread_self();
RUNTIME_CHECK(sigemptyset(&sset) == 0 && RUNTIME_CHECK(sigemptyset(&sset) == 0 &&
sigaddset(&sset, SIGINT) == 0 && sigaddset(&sset, SIGINT) == 0 &&
+62 -8
View File
@@ -678,9 +678,11 @@ dec_stats(isc_stats_t *stats, isc_statscounter_t counterid) {
static inline isc_result_t static inline isc_result_t
watch_fd(isc__socketthread_t *thread, int fd, int msg) { watch_fd(isc__socketthread_t *thread, int fd, int msg) {
isc_result_t result = ISC_R_SUCCESS; isc_result_t result = ISC_R_SUCCESS;
int lockid = FDLOCK_ID(fd);
#ifdef USE_KQUEUE #ifdef USE_KQUEUE
struct kevent evchange; struct kevent evchange;
(void) lockid;
memset(&evchange, 0, sizeof(evchange)); memset(&evchange, 0, sizeof(evchange));
if (msg == SELECT_POKE_READ) { if (msg == SELECT_POKE_READ) {
@@ -701,19 +703,37 @@ watch_fd(isc__socketthread_t *thread, int fd, int msg) {
int ret; int ret;
int op; int op;
LOCK(&thread->fdlock[lockid]);
oldevents = thread->epoll_events[fd]; oldevents = thread->epoll_events[fd];
if (msg == SELECT_POKE_READ) { if (msg == SELECT_POKE_READ) {
thread->epoll_events[fd] |= EPOLLIN; thread->epoll_events[fd] |= EPOLLIN;
} else { } else {
thread->epoll_events[fd] |= EPOLLOUT; thread->epoll_events[fd] |= EPOLLOUT;
} }
#if __SANITIZE_THREAD__
isc__socket_t *sock = thread->fds[fd];
#endif
event.events = thread->epoll_events[fd]; event.events = thread->epoll_events[fd];
memset(&event.data, 0, sizeof(event.data)); memset(&event.data, 0, sizeof(event.data));
event.data.fd = fd; event.data.fd = fd;
UNLOCK(&thread->fdlock[lockid]);
op = (oldevents == 0U) ? EPOLL_CTL_ADD : EPOLL_CTL_MOD; op = (oldevents == 0U) ? EPOLL_CTL_ADD : EPOLL_CTL_MOD;
#if __SANITIZE_THREAD__
/*
* This is to suppress TSAN warnings about epoll_ctl operating on
* on an unlocked socket - lock it if it's lockable and not locked.
*/
bool unlock = (sock != NULL &&
isc_mutex_trylock(&sock->lock) == ISC_R_SUCCESS);
#endif
ret = epoll_ctl(thread->epoll_fd, op, fd, &event); ret = epoll_ctl(thread->epoll_fd, op, fd, &event);
#if __SANITIZE_THREAD__
if (unlock) {
UNLOCK(&sock->lock);
}
#endif
if (ret == -1) { if (ret == -1) {
if (errno == EEXIST) { if (errno == EEXIST) {
UNEXPECTED_ERROR(__FILE__, __LINE__, UNEXPECTED_ERROR(__FILE__, __LINE__,
@@ -726,8 +746,8 @@ watch_fd(isc__socketthread_t *thread, int fd, int msg) {
return (result); return (result);
#elif defined(USE_DEVPOLL) #elif defined(USE_DEVPOLL)
struct pollfd pfd; struct pollfd pfd;
int lockid = FDLOCK_ID(fd);
LOCK(&thread->fdlock[lockid]);
memset(&pfd, 0, sizeof(pfd)); memset(&pfd, 0, sizeof(pfd));
if (msg == SELECT_POKE_READ) { if (msg == SELECT_POKE_READ) {
pfd.events = POLLIN; pfd.events = POLLIN;
@@ -745,6 +765,7 @@ watch_fd(isc__socketthread_t *thread, int fd, int msg) {
thread->fdpollinfo[fd].want_write = 1; thread->fdpollinfo[fd].want_write = 1;
} }
} }
UNLOCK(&thread->fdlock[lockid]);
return (result); return (result);
#elif defined(USE_SELECT) #elif defined(USE_SELECT)
@@ -764,9 +785,11 @@ watch_fd(isc__socketthread_t *thread, int fd, int msg) {
static inline isc_result_t static inline isc_result_t
unwatch_fd(isc__socketthread_t *thread, int fd, int msg) { unwatch_fd(isc__socketthread_t *thread, int fd, int msg) {
isc_result_t result = ISC_R_SUCCESS; isc_result_t result = ISC_R_SUCCESS;
int lockid = FDLOCK_ID(fd);
#ifdef USE_KQUEUE #ifdef USE_KQUEUE
struct kevent evchange; struct kevent evchange;
(void) lockid;
memset(&evchange, 0, sizeof(evchange)); memset(&evchange, 0, sizeof(evchange));
if (msg == SELECT_POKE_READ) { if (msg == SELECT_POKE_READ) {
@@ -786,6 +809,7 @@ unwatch_fd(isc__socketthread_t *thread, int fd, int msg) {
int ret; int ret;
int op; int op;
LOCK(&thread->fdlock[lockid]);
if (msg == SELECT_POKE_READ) { if (msg == SELECT_POKE_READ) {
thread->epoll_events[fd] &= ~(EPOLLIN); thread->epoll_events[fd] &= ~(EPOLLIN);
} else { } else {
@@ -795,9 +819,29 @@ unwatch_fd(isc__socketthread_t *thread, int fd, int msg) {
event.events = thread->epoll_events[fd]; event.events = thread->epoll_events[fd];
memset(&event.data, 0, sizeof(event.data)); memset(&event.data, 0, sizeof(event.data));
event.data.fd = fd; event.data.fd = fd;
#if __SANITIZE_THREAD__
isc__socket_t *sock = thread->fds[fd];
#endif
UNLOCK(&thread->fdlock[lockid]);
#if __SANITIZE_THREAD__
/*
* This is to suppress TSAN warnings about epoll_ctl operating on
* on an unlocked socket - lock it if it's lockable and not locked.
*/
bool unlock = (sock != NULL &&
isc_mutex_trylock(&sock->lock) == ISC_R_SUCCESS);
#endif
op = (event.events == 0U) ? EPOLL_CTL_DEL : EPOLL_CTL_MOD; op = (event.events == 0U) ? EPOLL_CTL_DEL : EPOLL_CTL_MOD;
ret = epoll_ctl(thread->epoll_fd, op, fd, &event); ret = epoll_ctl(thread->epoll_fd, op, fd, &event);
#if __SANITIZE_THREAD__
if (unlock) {
UNLOCK(&sock->lock);
}
#endif
if (ret == -1 && errno != ENOENT) { if (ret == -1 && errno != ENOENT) {
char strbuf[ISC_STRERRORSIZE]; char strbuf[ISC_STRERRORSIZE];
strerror_r(errno, strbuf, sizeof(strbuf)); strerror_r(errno, strbuf, sizeof(strbuf));
@@ -809,7 +853,6 @@ unwatch_fd(isc__socketthread_t *thread, int fd, int msg) {
#elif defined(USE_DEVPOLL) #elif defined(USE_DEVPOLL)
struct pollfd pfds[2]; struct pollfd pfds[2];
size_t writelen = sizeof(pfds[0]); size_t writelen = sizeof(pfds[0]);
int lockid = FDLOCK_ID(fd);
memset(pfds, 0, sizeof(pfds)); memset(pfds, 0, sizeof(pfds));
pfds[0].events = POLLREMOVE; pfds[0].events = POLLREMOVE;
@@ -820,6 +863,8 @@ unwatch_fd(isc__socketthread_t *thread, int fd, int msg) {
* only provides a way of canceling per FD, we may need to re-poll the * only provides a way of canceling per FD, we may need to re-poll the
* socket for the other operation. * socket for the other operation.
*/ */
LOCK(&thread->fdlock[lockid]);
if (msg == SELECT_POKE_READ && if (msg == SELECT_POKE_READ &&
thread->fdpollinfo[fd].want_write == 1) thread->fdpollinfo[fd].want_write == 1)
{ {
@@ -844,6 +889,7 @@ unwatch_fd(isc__socketthread_t *thread, int fd, int msg) {
thread->fdpollinfo[fd].want_write = 0; thread->fdpollinfo[fd].want_write = 0;
} }
} }
UNLOCK(&thread->fdlock[lockid]);
return (result); return (result);
#elif defined(USE_SELECT) #elif defined(USE_SELECT)
@@ -876,17 +922,17 @@ wakeup_socket(isc__socketthread_t *thread, int fd, int msg) {
INSIST(fd >= 0 && fd < (int)thread->manager->maxsocks); INSIST(fd >= 0 && fd < (int)thread->manager->maxsocks);
LOCK(&thread->fdlock[lockid]);
if (msg == SELECT_POKE_CLOSE) { if (msg == SELECT_POKE_CLOSE) {
/* No one should be updating fdstate, so no need to lock it */
INSIST(thread->fdstate[fd] == CLOSE_PENDING); INSIST(thread->fdstate[fd] == CLOSE_PENDING);
thread->fdstate[fd] = CLOSED; thread->fdstate[fd] = CLOSED;
UNLOCK(&thread->fdlock[lockid]);
(void)unwatch_fd(thread, fd, SELECT_POKE_READ); (void)unwatch_fd(thread, fd, SELECT_POKE_READ);
(void)unwatch_fd(thread, fd, SELECT_POKE_WRITE); (void)unwatch_fd(thread, fd, SELECT_POKE_WRITE);
(void)close(fd); (void)close(fd);
return; return;
} }
LOCK(&thread->fdlock[lockid]);
if (thread->fdstate[fd] == CLOSE_PENDING) { if (thread->fdstate[fd] == CLOSE_PENDING) {
UNLOCK(&thread->fdlock[lockid]); UNLOCK(&thread->fdlock[lockid]);
@@ -1833,6 +1879,7 @@ destroy(isc__socket_t **sockp) {
socket_log(sock, NULL, CREATION, "destroying"); socket_log(sock, NULL, CREATION, "destroying");
LOCK(&sock->lock);
INSIST(ISC_LIST_EMPTY(sock->connect_list)); INSIST(ISC_LIST_EMPTY(sock->connect_list));
INSIST(ISC_LIST_EMPTY(sock->accept_list)); INSIST(ISC_LIST_EMPTY(sock->accept_list));
INSIST(ISC_LIST_EMPTY(sock->recv_list)); INSIST(ISC_LIST_EMPTY(sock->recv_list));
@@ -1846,6 +1893,7 @@ destroy(isc__socket_t **sockp) {
sock->threadid = -1; sock->threadid = -1;
socketclose(thread, sock, fd); socketclose(thread, sock, fd);
} }
UNLOCK(&sock->lock);
LOCK(&manager->lock); LOCK(&manager->lock);
@@ -3153,6 +3201,7 @@ process_fd(isc__socketthread_t *thread, int fd, bool readable,
bool writeable) bool writeable)
{ {
isc__socket_t *sock; isc__socket_t *sock;
bool listener, connecting;
int lockid = FDLOCK_ID(fd); int lockid = FDLOCK_ID(fd);
/* /*
@@ -3181,9 +3230,15 @@ process_fd(isc__socketthread_t *thread, int fd, bool readable,
UNLOCK(&thread->fdlock[lockid]); UNLOCK(&thread->fdlock[lockid]);
return; return;
} }
UNLOCK(&thread->fdlock[lockid]);
LOCK(&sock->lock);
listener = sock->listener;
connecting = sock->connecting;
UNLOCK(&sock->lock);
if (readable) { if (readable) {
if (sock->listener) { if (listener) {
internal_accept(sock); internal_accept(sock);
} else { } else {
internal_recv(sock); internal_recv(sock);
@@ -3191,14 +3246,13 @@ process_fd(isc__socketthread_t *thread, int fd, bool readable,
} }
if (writeable) { if (writeable) {
if (sock->connecting) { if (connecting) {
internal_connect(sock); internal_connect(sock);
} else { } else {
internal_send(sock); internal_send(sock);
} }
} }
UNLOCK(&thread->fdlock[lockid]);
if (isc_refcount_decrement(&sock->references) == 1) { if (isc_refcount_decrement(&sock->references) == 1) {
destroy(&sock); destroy(&sock);
} }
+2 -2
View File
@@ -229,7 +229,7 @@ struct ns_clientmgr {
#define NS_CLIENT_DROPPORT 1 #define NS_CLIENT_DROPPORT 1
#endif #endif
LIBNS_EXTERNAL_DATA unsigned int ns_client_requests; LIBNS_EXTERNAL_DATA atomic_uint_fast32_t ns_client_requests;
static void read_settimeout(ns_client_t *client, bool newconn); static void read_settimeout(ns_client_t *client, bool newconn);
static void client_read(ns_client_t *client, bool newconn); static void client_read(ns_client_t *client, bool newconn);
@@ -2246,7 +2246,7 @@ ns__client_request(isc_task_t *task, isc_event_t *event) {
NS_CLIENTSTATE_READING : NS_CLIENTSTATE_READING :
NS_CLIENTSTATE_READY)); NS_CLIENTSTATE_READY));
ns_client_requests++; atomic_fetch_add(&ns_client_requests, 1);
if (event->ev_type == ISC_SOCKEVENT_RECVDONE) { if (event->ev_type == ISC_SOCKEVENT_RECVDONE) {
INSIST(!TCP_CLIENT(client)); INSIST(!TCP_CLIENT(client));
+1 -1
View File
@@ -204,7 +204,7 @@ typedef ISC_LIST(ns_client_t) client_list_t;
*/ */
#define NS_FAILCACHE_CD 0x01 #define NS_FAILCACHE_CD 0x01
LIBNS_EXTERNAL_DATA extern unsigned int ns_client_requests; LIBNS_EXTERNAL_DATA extern atomic_uint_fast32_t ns_client_requests;
/*** /***
*** Functions *** Functions