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().
[GL !1323]
+22 -29
View File
@@ -4995,16 +4995,10 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist,
&view->sortlist));
/*
* Configure default allow-notify, allow-update
* and allow-update-forwarding ACLs, so they can be
* inherited by zones. (Note these cannot be set at
* Configure default allow-update and allow-update-forwarding ACLs,
* so they can be inherited by zones. (Note these cannot be set at
* 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) {
CHECK(configure_view_acl(NULL, NULL, named_g_config,
"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
* by zones. (Note this *can* be set at options or view level.)
* Configure default allow-transfer and allow-notify ACLs so they
* can be inherited by zones.
*/
if (view->transferacl == NULL) {
CHECK(configure_view_acl(vconfig, config, named_g_config,
"allow-transfer", NULL, actx,
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;
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
pps_timer_tick(isc_task_t *task, isc_event_t *event) {
static unsigned int oldrequests = 0;
unsigned int requests = ns_client_requests;
unsigned int requests = atomic_load(&ns_client_requests);
UNUSED(task);
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. */
classtxt = next_token(lex, text);
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;
r.base = classtxt;
r.length = strlen(classtxt);
result = dns_rdataclass_fromtext(&rdclass, &r);
if (result != ISC_R_SUCCESS) {
if (viewtxt == NULL) {
rdclass = dns_rdataclass_in;
viewtxt = classtxt;
result = ISC_R_SUCCESS;
} else {
snprintf(msg, sizeof(msg),
"unknown class '%s'", classtxt);
(void) putstr(text, msg);
goto cleanup;
}
snprintf(msg, sizeof(msg),
"unknown class '%s'", classtxt);
(void) putstr(text, msg);
goto cleanup;
}
viewtxt = next_token(lex, text);
}
for (view = ISC_LIST_HEAD(server->viewlist);
@@ -15100,6 +15087,9 @@ named_server_mkeys(named_server_t *server, isc_lex_t *lex,
switch (opt) {
case REFRESH:
if (!first) {
CHECK(putstr(text, "\n"));
}
CHECK(mkey_refresh(view, text));
break;
case STATUS:
@@ -15107,12 +15097,14 @@ named_server_mkeys(named_server_t *server, isc_lex_t *lex,
CHECK(putstr(text, "\n\n"));
}
CHECK(mkey_status(view, text));
first = false;
break;
case SYNC:
CHECK(dns_zone_flush(view->managed_keys));
break;
case DESTROY:
if (!first) {
CHECK(putstr(text, "\n"));
}
CHECK(mkey_destroy(server, view, text));
break;
default:
@@ -15123,6 +15115,7 @@ named_server_mkeys(named_server_t *server, isc_lex_t *lex,
if (viewtxt != NULL) {
break;
}
first = false;
}
if (!found) {
+9 -7
View File
@@ -75,7 +75,7 @@ static isccc_region_t secret;
static bool failed = false;
static bool c_flag = false;
static isc_mem_t *rndc_mctx;
static int sends, recvs, connects;
static atomic_uint_fast32_t sends, recvs, connects;
static char *command;
static char *args;
static char program[256];
@@ -273,11 +273,11 @@ rndc_senddone(isc_task_t *task, isc_event_t *event) {
UNUSED(task);
sends--;
atomic_fetch_sub(&sends, 1);
if (sevent->result != ISC_R_SUCCESS)
fatal("send failed: %s", isc_result_totext(sevent->result));
isc_event_free(&event);
if (sends == 0 && recvs == 0) {
if (atomic_load(&sends) == 0 && atomic_load(&recvs) == 0) {
isc_socket_detach(&sock);
isc_task_shutdown(task);
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);
isccc_sexpr_free(&response);
if (sends == 0 && recvs == 0) {
if (atomic_load(&sends) == 0 && atomic_load(&recvs) == 0) {
isc_socket_detach(&sock);
isc_task_shutdown(task);
RUNTIME_CHECK(isc_app_shutdown() == ISC_R_SUCCESS);
@@ -430,7 +430,7 @@ rndc_recvnonce(isc_task_t *task, isc_event_t *event) {
recvs++;
DO("send message", isc_socket_send(sock, &r, task, rndc_senddone,
NULL));
sends++;
atomic_fetch_add(&sends, 1);
isc_event_free(&event);
isccc_sexpr_free(&response);
@@ -498,7 +498,7 @@ rndc_connected(isc_task_t *task, isc_event_t *event) {
recvs++;
DO("send message", isc_socket_send(sock, &r, task, rndc_senddone,
NULL));
sends++;
atomic_fetch_add(&sends, 1);
isc_event_free(&event);
isccc_sexpr_free(&request);
}
@@ -999,8 +999,10 @@ main(int argc, char **argv) {
if (result != ISC_R_SUCCESS)
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_task_detach(&task);
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" {
type master;
file "file";
allow-update {
"any";
};
auto-dnssec maintain;
};
zone "p" {
@@ -145,9 +148,6 @@ view "third" {
1.2.3.4;
};
};
allow-update {
"any";
};
};
view "chaos" chaos {
zone "hostname.bind" chaos {
+6 -10
View File
@@ -57,18 +57,14 @@ showprivate () {
}
# check that signing records are marked as complete
checkprivate () { (
checkprivate () {
for i in 1 2 3 4 5 6 7 8 9 10; do
ret=0
showprivate "$@" | grep incomplete >/dev/null 2>&1 && { ret=1; sleep 1; continue; }
break
showprivate "$@" | grep -q incomplete || return 0
sleep 1
done
[ $ret -eq 1 ] && {
echo_d "$1 signing incomplete"
return 1
}
return 0
) }
echo_d "$1 signing incomplete"
return 1
}
# check that a zone file is raw format, version 0
israw0 () {
@@ -19,6 +19,7 @@ options {
listen-on-v6 { none; };
recursion yes;
dnssec-validation yes;
minimal-responses yes;
};
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 ns4/named.conf.in ns4/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
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"
[ $status -eq 0 ] || exit 1
@@ -59,6 +59,7 @@ zone "verify-ixfr" {
type master;
file "verify-ixfr.db.signed";
ixfr-from-differences yes;
allow-transfer { 10.53.0.3; };
};
zone "verify-reconfig" {
+61 -11
View File
@@ -62,7 +62,8 @@ ret=0
wait_for_transfer verify-unsigned
$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
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
status=`expr $status + $ret`
@@ -73,7 +74,8 @@ nextpartreset ns3/named.run
wait_for_transfer verify-untrusted
$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
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
status=`expr $status + $ret`
@@ -84,7 +86,8 @@ nextpartreset ns3/named.run
wait_for_transfer verify-axfr
$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
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
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
$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
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
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
ret=0
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.
cp ns2/verify-ixfr.db.signed ns3/verify-journal.db.mirror
# 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
# 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
reload_zone verify-ixfr ${UPDATED_SERIAL_BAD}
# 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.
$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
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
status=`expr $status + $ret`
@@ -148,6 +166,10 @@ wait_for_transfer verify-ixfr
# 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
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
status=`expr $status + $ret`
@@ -158,7 +180,8 @@ nextpartreset 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
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
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
$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
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
status=`expr $status + $ret`
@@ -181,12 +205,31 @@ ret=0
$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.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
$PERL $SYSTEMTESTTOP/start.pl --noclean --restart --port ${PORT} mirror ns3
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
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
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
$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
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
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.
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.
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
rndc_reconfig ns2 10.53.0.2
# 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
# Reconfigure ns2 so that the zone from the previous test can no longer be
# 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
rndc_reconfig ns2 10.53.0.2
# 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
# Ensure named attempts to retransfer the zone due to its expiry.
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.
$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.
+8 -7
View File
@@ -10,14 +10,15 @@
# information regarding copyright ownership.
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-keys.bind* */named.secroots
rm -f */named.conf
rm -f */named.memstats */named.run */named.run.prev
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 */named.conf
rm -rf ns4/nope
rm -f ns5/named.args
rm -f dsset-. ns1/dsset-.
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 ns4/named.conf.in ns4/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
+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
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"
[ $status -eq 0 ] || exit 1
+56 -43
View File
@@ -7053,18 +7053,24 @@ options {
<term><command>allow-notify</command></term>
<listitem>
<para>
Specifies which hosts are allowed to
notify this server, a slave, of zone changes in addition
to the zone masters.
<command>allow-notify</command> may also be
specified in the
<command>zone</command> statement, in which case
it overrides the
<command>options allow-notify</command>
statement. It is only meaningful
for a slave zone. If not specified, the default is to
process notify messages
only from a zone's master.
This ACL specifies which hosts may send NOTIFY messages
to inform this server of changes to zones for which it
is acting as a secondary server. This is only
applicable for secondary zones (i.e., type
<literal>secondary</literal> or <literal>slave</literal>).
</para>
<para>
If this option is set in <command>view</command> or
<command>options</command>, it is globally applied to
all secondary zones. If set in the <command>zone</command>
statement, the global value is overridden.
</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>
</listitem>
</varlistentry>
@@ -7199,11 +7205,16 @@ options {
<term><command>allow-update</command></term>
<listitem>
<para>
Specifies which hosts are allowed to
submit Dynamic DNS updates for master zones. The default is
to deny
updates from all hosts. Note that allowing updates based
on the requestor's IP address is insecure; see
When set in the <command>zone</command> statement for
a master zone, specifies which hosts are allowed to
submit Dynamic DNS updates to that zone. The default
is to deny updates from all hosts. This can only
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.
</para>
</listitem>
@@ -7213,29 +7224,30 @@ options {
<term><command>allow-update-forwarding</command></term>
<listitem>
<para>
Specifies which hosts are allowed to
submit Dynamic DNS updates to slave zones to be forwarded to
the
master. The default is <userinput>{ none; }</userinput>,
which
means that no update forwarding will be performed. To
enable
update forwarding, specify
When set in the <command>zone</command> statement for
a slave zone, specifies which hosts are allowed to
submit Dynamic DNS updates and have them be forwarded
to the master. The default is
<userinput>{ none; }</userinput>, which means that no
update forwarding will be performed. This can only be
set at the <command>zone</command> level, not in
<command>options</command> or <command>view</command>.
</para>
<para>
To enable update forwarding, specify
<userinput>allow-update-forwarding { any; };</userinput>.
Specifying values other than <userinput>{ none; }</userinput> or
<userinput>{ any; }</userinput> is usually
counterproductive, since
the responsibility for update access control should rest
with the
master server, not the slaves.
in the <command>zone</command> statement.
Specifying values other than <userinput>{ none; }</userinput>
or <userinput>{ any; }</userinput> is usually
counterproductive; the responsibility for update
access control should rest with the master server, not
the slave.
</para>
<para>
Note that enabling the update forwarding feature on a slave
server
may expose master servers relying on insecure IP address
based
access control to attacks; see <xref linkend="dynamic_update_security"/>
for more details.
server may expose master servers to attacks if they rely
on insecure IP-address-based access control; see
<xref linkend="dynamic_update_security"/> for more details.
</para>
</listitem>
</varlistentry>
@@ -7259,13 +7271,14 @@ options {
<term xml:id="allow_transfer_term"><command>allow-transfer</command></term>
<listitem>
<para>
Specifies which hosts are allowed to
receive zone transfers from the server. <command>allow-transfer</command> may
also be specified in the <command>zone</command>
statement, in which
case it overrides the <command>options allow-transfer</command> statement.
If not specified, the default is to allow transfers to all
hosts.
Specifies which hosts are allowed to receive zone
transfers from the server. <command>allow-transfer</command>
may also be specified in the <command>zone</command>
statement, in which case it overrides the
<command>allow-transfer</command> statement set in
<command>options</command> or <command>view</command>.
If not specified, the default is to allow transfers to
all hosts.
</para>
</listitem>
</varlistentry>
+42
View File
@@ -484,6 +484,43 @@ check_viewacls(cfg_aclconfctx_t *actx, const cfg_obj_t *voptions,
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 isc_result_t
@@ -3692,6 +3729,11 @@ check_viewconf(const cfg_obj_t *config, const cfg_obj_t *voptions,
if (tresult != ISC_R_SUCCESS)
result = tresult;
tresult = check_non_viewacls(voptions, config, logctx);
if (tresult != ISC_R_SUCCESS) {
result = tresult;
}
tresult = check_recursionacls(actx, voptions, viewname,
config, logctx, mctx);
if (tresult != ISC_R_SUCCESS)
+34 -8
View File
@@ -2791,9 +2791,8 @@ dns_adb_detach(dns_adb_t **adbx) {
adb = *adbx;
*adbx = NULL;
INSIST(adb->erefcnt > 0);
LOCK(&adb->reflock);
INSIST(adb->erefcnt > 0);
adb->erefcnt--;
need_exit_check = (adb->erefcnt == 0 && adb->irefcnt == 0);
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,
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++)
LOCK(&adb->namelocks[i]);
for (i = 0; i < adb->nentries; i++)
LOCK(&adb->entrylocks[i]);
#endif
/*
* Dump the names
*/
for (i = 0; i < adb->nnames; i++) {
#ifdef __SANITIZE_THREAD__
LOCK(&adb->namelocks[i]);
#endif
name = ISC_LIST_HEAD(adb->names[i]);
if (name == NULL)
if (name == NULL) {
#ifdef __SANITIZE_THREAD__
UNLOCK(&adb->namelocks[i]);
#endif
continue;
if (debug)
}
if (debug) {
fprintf(f, "; bucket %u\n", i);
}
for (;
name != NULL;
name = ISC_LIST_NEXT(name, plink))
{
if (debug)
if (debug) {
fprintf(f, "; name %p (flags %08x)\n",
name, name->flags);
}
fprintf(f, "; ");
print_dns_name(f, &name->name);
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);
}
}
#ifdef __SANITIZE_THREAD__
UNLOCK(&adb->namelocks[i]);
#endif
}
fprintf(f, ";\n; Unassociated entries\n;\n");
for (i = 0; i < adb->nentries; i++) {
#ifdef __SANITIZE_THREAD__
LOCK(&adb->entrylocks[i]);
#endif
entry = ISC_LIST_HEAD(adb->entries[i]);
while (entry != NULL) {
if (entry->nh == 0)
dump_entry(f, adb, entry, debug, now);
entry = ISC_LIST_NEXT(entry, plink);
}
#ifdef __SANITIZE_THREAD__
UNLOCK(&adb->entrylocks[i]);
#endif
}
#ifndef __SANITIZE_THREAD__
/*
* Unlock everything
*/
for (i = 0; i < adb->nentries; i++)
for (i = adb->nentries-1; i >= 0; i--)
UNLOCK(&adb->entrylocks[i]);
for (i = 0; i < adb->nnames; i++)
for (i = adb->nnames-1; i >= 0; i--)
UNLOCK(&adb->namelocks[i]);
#endif
}
static void
+29 -22
View File
@@ -76,9 +76,10 @@ struct dns_dispatchmgr {
/* locked by buffer_lock */
dns_qid_t *qid;
isc_mutex_t buffer_lock;
unsigned int buffers; /*%< allocated buffers */
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. */
isc_mutex_t depool_lock;
@@ -900,9 +901,8 @@ free_buffer(dns_dispatch_t *disp, void *buf, unsigned int len) {
break;
case isc_sockettype_udp:
LOCK(&disp->mgr->buffer_lock);
INSIST(disp->mgr->buffers > 0);
INSIST(len == disp->mgr->buffersize);
disp->mgr->buffers--;
INSIST(atomic_fetch_sub(&disp->mgr->buffers, 1) > 0);
bpool = disp->mgr->bpool;
UNLOCK(&disp->mgr->buffer_lock);
isc_mempool_put(bpool, buf);
@@ -918,17 +918,15 @@ allocate_udp_buffer(dns_dispatch_t *disp) {
isc_mempool_t *bpool;
void *temp;
atomic_fetch_add(&disp->mgr->buffers, 1);
LOCK(&disp->mgr->buffer_lock);
bpool = disp->mgr->bpool;
disp->mgr->buffers++;
UNLOCK(&disp->mgr->buffer_lock);
temp = isc_mempool_get(bpool);
if (temp == NULL) {
LOCK(&disp->mgr->buffer_lock);
disp->mgr->buffers--;
UNLOCK(&disp->mgr->buffer_lock);
atomic_fetch_sub(&disp->mgr->buffers, 1);
}
return (temp);
@@ -1050,8 +1048,9 @@ udp_recv(isc_event_t *ev_in, dns_dispatch_t *disp, dispsocket_t *dispsock) {
qid = mgr->qid;
dispatch_log(disp, LVL(90),
"got packet: requests %d, buffers %d, recvs %d",
disp->requests, disp->mgr->buffers, disp->recv_pending);
"got packet: requests %d, buffers %lu, recvs %d",
disp->requests, atomic_load(&disp->mgr->buffers),
disp->recv_pending);
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;
LOCK(&disp->lock);
dispatch_log(disp, LVL(90),
"got TCP packet: requests %d, buffers %d, recvs %d",
disp->requests, disp->tcpbuffers, disp->recv_pending);
LOCK(&disp->lock);
INSIST(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_socket_t *sock;
if (disp->shutting_down == 1)
if (disp->shutting_down == 1) {
return (ISC_R_SUCCESS);
}
if ((disp->attributes & DNS_DISPATCHATTR_NOLISTEN) != 0)
if ((disp->attributes & DNS_DISPATCHATTR_NOLISTEN) != 0) {
return (ISC_R_SUCCESS);
}
if (disp->recv_pending != 0 && dispsock == NULL)
if (disp->recv_pending != 0 && dispsock == NULL) {
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);
}
if ((disp->attributes & DNS_DISPATCHATTR_EXCLUSIVE) != 0 &&
dispsock == NULL)
dispsock == NULL) {
return (ISC_R_SUCCESS);
}
if (dispsock != NULL)
if (dispsock != NULL) {
sock = dispsock->socket;
else
} else {
sock = disp->socket;
}
INSIST(sock != NULL);
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_setfillcount(mgr->dpool, 32);
mgr->buffers = 0;
atomic_store(&mgr->buffers, 0);
mgr->buffersize = 0;
mgr->maxbuffers = 0;
atomic_store(&mgr->maxbuffers, 0);
mgr->bpool = NULL;
mgr->spool = NULL;
mgr->qid = NULL;
@@ -2043,7 +2050,7 @@ dns_dispatchmgr_setudp(dns_dispatchmgr_t *mgr,
goto cleanup;
mgr->buffersize = buffersize;
mgr->maxbuffers = maxbuffers;
atomic_store(&mgr->maxbuffers, maxbuffers);
UNLOCK(&mgr->buffer_lock);
return (ISC_R_SUCCESS);
+2
View File
@@ -118,6 +118,8 @@ typedef enum {
when doing qname
minimization on
ip6.arpa. */
#define DNS_FETCHOPT_NOFORWARD 0x00080000 /*%< Do not use forwarders
if possible. */
/* Reserved in use by adb.c 0x00400000 */
#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;
pubattr = pk11_attribute_bytype(pubec, CKA_EC_PARAMS);
INSIST(pubattr != NULL);
attr->pValue = isc_mem_get(key->mctx, pubattr->ulValueLen);
if (attr->pValue == NULL)
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;
pubattr = pk11_attribute_bytype(pubec, CKA_EC_POINT);
INSIST(pubattr != NULL);
attr->pValue = isc_mem_get(key->mctx, pubattr->ulValueLen);
if (attr->pValue == NULL)
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;
pubattr = pk11_attribute_bytype(pubrsa, CKA_MODULUS);
INSIST(pubattr != NULL);
attr->pValue = isc_mem_get(key->mctx, pubattr->ulValueLen);
if (attr->pValue == NULL)
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;
pubattr = pk11_attribute_bytype(pubrsa, CKA_PUBLIC_EXPONENT);
INSIST(pubattr != NULL);
attr->pValue = isc_mem_get(key->mctx, pubattr->ulValueLen);
if (attr->pValue == NULL)
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;
/*
* 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 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->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
* selective forwarders specified in the view; otherwise use the
@@ -3586,7 +3607,7 @@ fctx_getaddresses(fetchctx_t *fctx, bool badcache) {
/*
* Normal nameservers.
*/
normal_nses:
stdoptions = DNS_ADBFIND_WANTEVENT | DNS_ADBFIND_EMPTYEVENT;
if (fctx->restarts == 1) {
/*
@@ -4031,9 +4052,11 @@ fctx_try(fetchctx_t *fctx, bool retrying, bool badcache) {
options &= ~DNS_FETCHOPT_QMINIMIZE;
fctx_increference(fctx);
task = res->buckets[bucketnum].task;
fctx_stoptimer(fctx);
result = dns_resolver_createfetch(fctx->res, &fctx->qminname,
fctx->qmintype, &fctx->domain,
&fctx->nameservers, NULL, NULL, 0,
&fctx->nameservers,
NULL, NULL, 0,
options, 0, fctx->qc, task,
resume_qmin, fctx,
&fctx->qminrrset, NULL,
@@ -4362,13 +4385,12 @@ fctx_timeout(isc_task_t *task, isc_event_t *event) {
* timer.
*/
result = fctx_starttimer(fctx);
if (result != ISC_R_SUCCESS)
if (result != ISC_R_SUCCESS) {
fctx_done(fctx, result, __LINE__);
else
/*
* Keep trying.
*/
} else {
/* Keep trying */
fctx_try(fctx, true, false);
}
}
isc_event_free(&event);
@@ -10115,16 +10137,16 @@ prime_done(isc_task_t *task, isc_event_t *event) {
UNUSED(task);
LOCK(&res->primelock);
LOCK(&res->lock);
INSIST(res->priming);
res->priming = false;
LOCK(&res->primelock);
fetch = res->primefetch;
res->primefetch = NULL;
UNLOCK(&res->primelock);
UNLOCK(&res->lock);
UNLOCK(&res->primelock);
if (fevent->result == ISC_R_SUCCESS &&
res->view->cache != NULL && res->view->hints != NULL) {
@@ -10192,12 +10214,11 @@ dns_resolver_prime(dns_resolver_t *res) {
LOCK(&res->primelock);
result = dns_resolver_createfetch(res, dns_rootname,
dns_rdatatype_ns,
NULL, NULL, NULL, NULL, 0, 0,
0, NULL,
res->buckets[0].task,
prime_done,
res, rdataset, NULL,
&res->primefetch);
NULL, NULL, NULL, NULL, 0,
DNS_FETCHOPT_NOFORWARD, 0,
NULL, res->buckets[0].task,
prime_done, res, rdataset,
NULL, &res->primefetch);
UNLOCK(&res->primelock);
if (result != ISC_R_SUCCESS) {
isc_mem_put(res->mctx, rdataset, sizeof(*rdataset));
+15 -11
View File
@@ -2432,20 +2432,24 @@ dns_view_loadnta(dns_view_t *view) {
void
dns_view_setviewcommit(dns_view_t *view) {
REQUIRE(DNS_VIEW_VALID(view));
dns_zone_t *redirect, *managed_keys;
dns_zt_t *zonetable;
LOCK(&view->lock);
if (view->redirect != NULL) {
dns_zone_setviewcommit(view->redirect);
}
if (view->managed_keys != NULL) {
dns_zone_setviewcommit(view->managed_keys);
}
if (view->zonetable != NULL) {
dns_zt_setviewcommit(view->zonetable);
}
redirect = view->redirect;
managed_keys = view->managed_keys;
zonetable = view->zonetable;
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
+22 -1
View File
@@ -133,6 +133,13 @@ struct dns_xfrin_ctx {
dns_tcpmsg_t tcpmsg;
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_dbversion_t *ver;
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,
sourceaddr, dscp, tsigkey, &xfr));
if (db != NULL) {
xfr->zone_had_db = true;
}
CHECK(xfrin_start(xfr));
xfr->done = done;
@@ -821,6 +832,7 @@ xfrin_create(isc_mem_t *mctx,
/* tcpmsg */
xfr->tcpmsg_valid = false;
xfr->zone_had_db = false;
xfr->db = NULL;
if (db != NULL)
dns_db_attach(db, &xfr->db);
@@ -1513,8 +1525,17 @@ maybe_free(dns_xfrin_ctx_t *xfr) {
if (xfr->db != NULL)
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);
}
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 hasinclude = DNS_ZONE_FLAG(zone, DNS_ZONEFLG_HASINCLUDE);
bool nomaster = false;
bool had_db = false;
unsigned int options;
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);
if (zone->db != NULL) {
had_db = true;
result = zone_replacedb(zone, db, false);
ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_write);
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)" : "");
}
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;
goto done;
@@ -10838,6 +10845,12 @@ zone_unload(dns_zone_t *zone) {
ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_write);
DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_LOADED);
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
+27 -29
View File
@@ -48,10 +48,11 @@ struct dns_zt {
void * loaddone_arg;
struct zt_load_params *loadparams;
/* Locked by lock. */
bool flush;
uint32_t references;
unsigned int loads_pending;
bool flush;
dns_rbt_t *table;
/* Atomic */
isc_refcount_t refs;
isc_refcount_t loads_pending;
};
#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;
isc_mem_attach(mctx, &zt->mctx);
zt->references = 1;
isc_refcount_init(&zt->refs, 1);
zt->flush = false;
zt->rdclass = rdclass;
zt->magic = ZTMAGIC;
zt->loaddone = NULL;
zt->loaddone_arg = NULL;
zt->loadparams = NULL;
zt->loads_pending = 0;
isc_refcount_init(&zt->loads_pending, 0);
*ztp = zt;
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);
INSIST(zt->references > 0);
zt->references++;
INSIST(zt->references != 0);
INSIST(isc_refcount_increment(&zt->refs) > 0);
RWUNLOCK(&zt->rwlock, isc_rwlocktype_write);
@@ -231,6 +230,7 @@ zt_destroy(dns_zt_t *zt) {
static void
zt_flushanddetach(dns_zt_t **ztp, bool need_flush) {
bool destroy = false;
int refs;
dns_zt_t *zt;
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);
INSIST(zt->references > 0);
zt->references--;
if (zt->references == 0)
destroy = true;
if (need_flush)
zt->flush = true;
refs = isc_refcount_decrement(&zt->refs);
INSIST(refs != 0);
destroy = (refs == 1);
zt->flush = need_flush;
RWUNLOCK(&zt->rwlock, isc_rwlocktype_write);
if (destroy)
if (destroy) {
zt_destroy(zt);
}
*ztp = NULL;
}
@@ -332,15 +331,14 @@ asyncload(dns_zone_t *zone, void *zt_) {
isc_result_t result;
struct dns_zt *zt = (dns_zt_t*) zt_;
REQUIRE(zone != NULL);
INSIST(zt->references > 0);
zt->references++;
zt->loads_pending++;
INSIST(isc_refcount_increment(&zt->refs) > 0);
isc_refcount_increment(&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) {
zt->references--;
zt->loads_pending--;
INSIST(zt->references > 0);
INSIST(isc_refcount_decrement(&zt->refs) > 1);
isc_refcount_decrement(&zt->loads_pending);
}
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
doneloading(dns_zt_t *zt, dns_zone_t *zone, isc_task_t *task) {
bool destroy = false;
int refs;
dns_zt_allloaded_t alldone = 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));
RWLOCK(&zt->rwlock, isc_rwlocktype_write);
INSIST(zt->loads_pending != 0);
INSIST(zt->references != 0);
zt->references--;
if (zt->references == 0)
destroy = true;
zt->loads_pending--;
if (zt->loads_pending == 0) {
INSIST(atomic_load(&zt->loads_pending) != 0);
refs = isc_refcount_decrement(&zt->refs);
INSIST(refs > 0);
destroy = (refs == 1);
if (isc_refcount_decrement(&zt->loads_pending) == 1) {
alldone = zt->loaddone;
arg = zt->loaddone_arg;
zt->loaddone = NULL;
+33 -7
View File
@@ -126,6 +126,12 @@
#include <string.h>
#include <errno.h>
#ifdef _WIN32
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#endif
#include <isc/app.h>
#include <isc/buffer.h>
#include <isc/lib.h>
@@ -339,25 +345,45 @@ getaddrinfo(const char *hostname, const char *servname,
port = strtol(servname, &e, 10);
if (*e == '\0') {
if (socktype == 0)
if (socktype == 0) {
return (EAI_SOCKTYPE);
if (port < 0 || port > 65535)
}
if (port < 0 || port > 65535) {
return (EAI_SERVICE);
}
port = htons((unsigned short) port);
} 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);
if (sp == NULL)
if (sp != NULL)
port = sp->s_port;
#ifdef _WIN32
WSACleanup();
#endif
if (sp == NULL) {
return (EAI_SERVICE);
port = sp->s_port;
}
if (socktype == 0) {
if (strcmp(sp->s_proto, "tcp") == 0)
if (strcmp(sp->s_proto, "tcp") == 0) {
socktype = SOCK_STREAM;
else if (strcmp(sp->s_proto, "udp") == 0)
} else if (strcmp(sp->s_proto, "udp") == 0) {
socktype = SOCK_DGRAM;
}
}
}
} else
} else {
port = 0;
}
/*
* Next, deal with just a service name, and no hostname.
+9
View File
@@ -16,3 +16,12 @@
#else
#include <isc/stdatomic.h>
#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. */
unsigned int magic;
isc_mutex_t lock;
int32_t spins;
/*
* When some atomic instructions with hardware assistance are
@@ -51,6 +50,7 @@ struct isc_rwlock {
*/
/* Read or modified atomically. */
atomic_int_fast32_t spins;
atomic_int_fast32_t write_requests;
atomic_int_fast32_t write_completions;
atomic_int_fast32_t cnt_and_flag;
@@ -60,8 +60,8 @@ struct isc_rwlock {
isc_condition_t writeable;
unsigned int readers_waiting;
/* Locked by rwlock itself. */
unsigned int write_granted;
/* Locked by rwlock itself, but sometimes accessed without lock */
atomic_int_fast32_t write_granted;
/* Unlocked. */
unsigned int write_quota;
+4
View File
@@ -186,6 +186,10 @@
#define __SANITIZE_ADDRESS__ 1
#endif
#if __has_feature(thread_sanitizer)
#define __SANITIZE_THREAD__ 1
#endif
#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR >= 6)
#define STATIC_ASSERT(cond, msg) _Static_assert(cond, msg)
#elif __has_feature(c_static_assert)
+9 -11
View File
@@ -142,7 +142,7 @@ struct isc__mem {
size_t hi_water;
size_t lo_water;
bool hi_called;
bool is_overmem;
atomic_bool is_overmem;
isc_mem_water_t water;
void * water_arg;
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->lo_water = 0;
ctx->hi_called = false;
ctx->is_overmem = false;
atomic_store_relaxed(&ctx->is_overmem, false);
ctx->water = NULL;
ctx->water_arg = NULL;
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);
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)
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.
*/
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)
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);
ADD_TRACE(ctx, si, si[-1].u.size, file, line);
if (ctx->hi_water != 0U && ctx->inuse > ctx->hi_water &&
!ctx->is_overmem) {
ctx->is_overmem = true;
if (ctx->hi_water != 0U && ctx->inuse > ctx->hi_water) {
atomic_store_relaxed(&ctx->is_overmem, true);
}
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
* isc_mem_setwater() called with 0 for hi_water and lo_water.
*/
if (ctx->is_overmem &&
(ctx->inuse < ctx->lo_water || ctx->lo_water == 0U)) {
ctx->is_overmem = false;
if (ctx->inuse < ctx->lo_water || ctx->lo_water == 0U) {
atomic_store_relaxed(&ctx->is_overmem, false);
}
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
* could be different from the actual state when it's used anyway)
*/
return (ctx->is_overmem);
return (atomic_load_relaxed(&ctx->is_overmem));
}
void
+48 -32
View File
@@ -18,6 +18,10 @@
#include <stddef.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/magic.h>
#include <isc/platform.h>
@@ -52,6 +56,8 @@
# define isc_rwlock_pause() __asm__ __volatile__ ("hint @pause")
#elif defined(__arm__)
# 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__)
# define isc_rwlock_pause() __asm__ __volatile__ ("pause")
#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",
rwl, isc_thread_self(), operation,
(type == isc_rwlocktype_read ? "read" : "write"),
atomic_load_explicit(&rwl->write_requests, memory_order_relaxed),
atomic_load_explicit(&rwl->write_completions, memory_order_relaxed),
atomic_load_explicit(&rwl->cnt_and_flag, memory_order_relaxed),
atomic_load_relaxed(&rwl->write_requests),
atomic_load_relaxed(&rwl->write_completions),
atomic_load_relaxed(&rwl->cnt_and_flag),
rwl->readers_waiting,
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->spins = 0;
atomic_init(&rwl->spins, 0);
atomic_init(&rwl->write_requests, 0);
atomic_init(&rwl->write_completions, 0);
atomic_init(&rwl->cnt_and_flag, 0);
@@ -125,9 +131,9 @@ void
isc_rwlock_destroy(isc_rwlock_t *rwl) {
REQUIRE(VALID_RWLOCK(rwl));
REQUIRE(atomic_load_explicit(&rwl->write_requests, memory_order_relaxed) ==
atomic_load_explicit(&rwl->write_completions, memory_order_relaxed) &&
atomic_load_explicit(&rwl->cnt_and_flag, memory_order_relaxed) == 0 && rwl->readers_waiting == 0);
REQUIRE(atomic_load_relaxed(&rwl->write_requests) ==
atomic_load_relaxed(&rwl->write_completions) &&
atomic_load_relaxed(&rwl->cnt_and_flag) == 0 && rwl->readers_waiting == 0);
rwl->magic = 0;
(void)isc_condition_destroy(&rwl->readable);
@@ -211,13 +217,13 @@ isc__rwlock_lock(isc_rwlock_t *rwl, isc_rwlocktype_t type) {
#endif
if (type == isc_rwlocktype_read) {
if (atomic_load_explicit(&rwl->write_requests, memory_order_relaxed) !=
atomic_load_explicit(&rwl->write_completions, memory_order_relaxed))
if (atomic_load_relaxed(&rwl->write_requests) !=
atomic_load_relaxed(&rwl->write_completions))
{
/* there is a waiting or active writer */
LOCK(&rwl->lock);
if (atomic_load_explicit(&rwl->write_requests, memory_order_relaxed) !=
atomic_load_explicit(&rwl->write_completions, memory_order_relaxed)) {
if (atomic_load_relaxed(&rwl->write_requests) !=
atomic_load_relaxed(&rwl->write_completions)) {
rwl->readers_waiting++;
WAIT(&rwl->readable, &rwl->lock);
rwl->readers_waiting--;
@@ -230,13 +236,16 @@ isc__rwlock_lock(isc_rwlock_t *rwl, isc_rwlocktype_t type) {
memory_order_relaxed);
POST(cntflag);
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;
}
/* A writer is still working */
LOCK(&rwl->lock);
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);
}
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
* matter).
*/
rwl->write_granted = 0;
atomic_store_relaxed(&rwl->write_granted, 0);
} else {
int32_t prev_writer;
/* enter the waiting queue, and wait for our turn */
prev_writer = atomic_fetch_add_explicit(&rwl->write_requests, 1,
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);
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);
UNLOCK(&rwl->lock);
continue;
@@ -302,13 +313,14 @@ isc__rwlock_lock(isc_rwlock_t *rwl, isc_rwlocktype_t type) {
/* Another active reader or writer is working. */
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);
}
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++;
}
@@ -322,7 +334,8 @@ isc__rwlock_lock(isc_rwlock_t *rwl, isc_rwlocktype_t type) {
isc_result_t
isc_rwlock_lock(isc_rwlock_t *rwl, isc_rwlocktype_t type) {
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;
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();
} 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);
}
@@ -353,8 +368,8 @@ isc_rwlock_trylock(isc_rwlock_t *rwl, isc_rwlocktype_t type) {
if (type == isc_rwlocktype_read) {
/* If a writer is waiting or working, we fail. */
if (atomic_load_explicit(&rwl->write_requests, memory_order_relaxed) !=
atomic_load_explicit(&rwl->write_completions, memory_order_relaxed))
if (atomic_load_relaxed(&rwl->write_requests) !=
atomic_load_relaxed(&rwl->write_completions))
return (ISC_R_LOCKBUSY);
/* 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.
*/
if (cntflag == READER_INCR &&
atomic_load_explicit(&rwl->write_completions, memory_order_relaxed) !=
atomic_load_explicit(&rwl->write_requests, memory_order_relaxed)) {
atomic_load_relaxed(&rwl->write_completions) !=
atomic_load_relaxed(&rwl->write_requests)) {
LOCK(&rwl->lock);
BROADCAST(&rwl->writeable);
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,
memory_order_relaxed);
rwl->write_granted++;
atomic_fetch_add_explicit(&rwl->write_granted, 1,
memory_order_relaxed);
}
#ifdef ISC_RWLOCK_TRACE
@@ -491,8 +507,8 @@ isc_rwlock_unlock(isc_rwlock_t *rwl, isc_rwlocktype_t type) {
* FIFO order.
*/
if (prev_cnt == READER_INCR &&
atomic_load_explicit(&rwl->write_completions, memory_order_relaxed) !=
atomic_load_explicit(&rwl->write_requests, memory_order_relaxed)) {
atomic_load_relaxed(&rwl->write_completions) !=
atomic_load_relaxed(&rwl->write_requests)) {
LOCK(&rwl->lock);
BROADCAST(&rwl->writeable);
UNLOCK(&rwl->lock);
@@ -510,9 +526,9 @@ isc_rwlock_unlock(isc_rwlock_t *rwl, isc_rwlocktype_t type) {
memory_order_relaxed);
if (rwl->write_granted >= rwl->write_quota ||
(atomic_load_explicit(&rwl->write_requests, memory_order_relaxed) ==
atomic_load_explicit(&rwl->write_completions, memory_order_relaxed)) ||
(atomic_load_explicit(&rwl->cnt_and_flag, memory_order_relaxed) & ~WRITER_ACTIVE)) {
(atomic_load_relaxed(&rwl->write_requests) ==
atomic_load_relaxed(&rwl->write_completions)) ||
(atomic_load_relaxed(&rwl->cnt_and_flag) & ~WRITER_ACTIVE)) {
/*
* We have passed the write quota, no writer is
* 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);
}
if ((atomic_load_explicit(&rwl->write_requests, memory_order_relaxed) !=
atomic_load_explicit(&rwl->write_completions, memory_order_relaxed)) &&
if ((atomic_load_relaxed(&rwl->write_requests) !=
atomic_load_relaxed(&rwl->write_completions)) &&
wakeup_writers) {
LOCK(&rwl->lock);
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_ready;
atomic_uint_fast32_t curq;
atomic_uint_fast32_t tasks_count;
isc__taskqueue_t *queues;
/* Locked by task manager lock. */
unsigned int default_quantum;
LIST(isc__task_t) tasks;
isc_taskmgrmode_t mode;
bool pause_requested;
bool exclusive_requested;
bool exiting;
atomic_uint_fast32_t mode;
atomic_bool pause_req;
atomic_bool exclusive_req;
atomic_bool exiting;
/* Locked by halt_lock */
unsigned int halted;
@@ -176,7 +177,8 @@ isc__taskmgr_resume(isc_taskmgr_t *manager0);
#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__"
@@ -228,6 +230,7 @@ task_finished(isc__task_t *task) {
LOCK(&manager->lock);
UNLINK(manager->tasks, task, link);
atomic_fetch_sub(&manager->tasks_count, 1);
UNLOCK(&manager->lock);
if (FINISHED(manager)) {
/*
@@ -303,8 +306,9 @@ isc_task_create_bound(isc_taskmgr_t *manager0, unsigned int quantum,
exiting = false;
LOCK(&manager->lock);
if (!manager->exiting) {
if (!atomic_load_relaxed(&manager->exiting)) {
APPEND(manager->tasks, task, link);
atomic_fetch_add(&manager->tasks_count, 1);
} else {
exiting = true;
}
@@ -397,7 +401,8 @@ task_ready(isc__task_t *task) {
XTRACE("task_ready");
LOCK(&manager->queues[task->threadid].lock);
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);
}
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));
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->bound) {
c = task->threadid;
@@ -520,13 +532,6 @@ isc_task_sendto(isc_task_t *task0, isc_event_t **eventp, int c) {
memory_order_relaxed);
}
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);
UNLOCK(&task->lock);
@@ -565,6 +570,7 @@ isc_task_sendtoanddetach(isc_task_t **taskp, isc_event_t **eventp, int c) {
REQUIRE(VALID_TASK(task));
XTRACE("isc_task_sendanddetach");
LOCK(&task->lock);
if (task->bound) {
c = task->threadid;
} else if (c < 0) {
@@ -572,8 +578,6 @@ isc_task_sendtoanddetach(isc_task_t **taskp, isc_event_t **eventp, int c) {
memory_order_relaxed);
}
c %= task->manager->workers;
LOCK(&task->lock);
idle1 = task_send(task, eventp, c);
idle2 = task_detach(task);
UNLOCK(&task->lock);
@@ -902,11 +906,11 @@ static inline bool
empty_readyq(isc__taskmgr_t *manager, int c) {
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;
else
} else {
queue = manager->queues[c].ready_priority_tasks;
}
return (EMPTY(queue));
}
@@ -922,7 +926,7 @@ static inline isc__task_t *
pop_readyq(isc__taskmgr_t *manager, int c) {
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);
} else {
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.
*/
while ((empty_readyq(manager, threadid) &&
!manager->pause_requested &&
!manager->exclusive_requested) &&
!atomic_load_relaxed(&manager->pause_req) &&
!atomic_load_relaxed(&manager->exclusive_req)) &&
!FINISHED(manager))
{
XTHREADTRACE("wait");
XTHREADTRACE(manager->pause_requested
XTHREADTRACE(atomic_load_relaxed(&manager->pause_req)
? "paused"
: "notpaused");
XTHREADTRACE(manager->exclusive_requested
XTHREADTRACE(atomic_load_relaxed(&manager->exclusive_req)
? "excreq"
: "notexcreq");
WAIT(&manager->queues[threadid].work_available,
@@ -1046,15 +1050,16 @@ dispatch(isc__taskmgr_t *manager, unsigned int threadid) {
}
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);
XTHREADTRACE("halting");
/*
* Switching to exclusive mode is done as a
* 2-phase-lock, checking if we have to switch is
* done without any locks on pause_requested and
* exclusive_requested to save time - the worst
* done without any locks on pause_req and
* exclusive_req to save time - the worst
* thing that can happen is that we'll launch one
* task more and exclusive task will be postponed a
* bit.
@@ -1066,8 +1071,8 @@ dispatch(isc__taskmgr_t *manager, unsigned int threadid) {
LOCK(&manager->halt_lock);
manager->halted++;
BROADCAST(&manager->halt_cond);
while (manager->pause_requested ||
manager->exclusive_requested)
while (atomic_load_relaxed(&manager->pause_req) ||
atomic_load_relaxed(&manager->exclusive_req))
{
WAIT(&manager->halt_cond, &manager->halt_lock);
}
@@ -1260,7 +1265,8 @@ dispatch(isc__taskmgr_t *manager, unsigned int threadid) {
UNLOCK(&manager->queues[i].lock);
}
if (empty) {
manager->mode = isc_taskmgrmode_normal;
atomic_store(&manager->mode,
isc_taskmgrmode_normal);
wake_all_queues(manager);
}
}
@@ -1331,7 +1337,7 @@ isc_taskmgr_create(isc_mem_t *mctx, unsigned int workers,
RUNTIME_CHECK(manager != NULL);
manager->common.impmagic = TASK_MANAGER_MAGIC;
manager->common.magic = ISCAPI_TASKMGR_MAGIC;
manager->mode = isc_taskmgrmode_normal;
atomic_store(&manager->mode, isc_taskmgrmode_normal);
manager->mctx = NULL;
isc_mutex_init(&manager->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;
INIT_LIST(manager->tasks);
atomic_store(&manager->tasks_count, 0);
manager->queues = isc_mem_get(mctx, workers * sizeof(isc__taskqueue_t));
RUNTIME_CHECK(manager->queues != NULL);
@@ -1355,8 +1362,8 @@ isc_taskmgr_create(isc_mem_t *mctx, unsigned int workers,
manager->exiting = false;
manager->excl = NULL;
manager->halted = 0;
manager->exclusive_requested = false;
manager->pause_requested = false;
atomic_store_relaxed(&manager->exclusive_req, false);
atomic_store_relaxed(&manager->pause_req, false);
isc_mem_attach(mctx, &manager->mctx);
@@ -1433,13 +1440,13 @@ isc_taskmgr_destroy(isc_taskmgr_t **managerp) {
/*
* Make sure we only get called once.
*/
INSIST(!manager->exiting);
manager->exiting = true;
INSIST(!atomic_load(&manager->exiting));
atomic_store(&manager->exiting, true);
/*
* 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
@@ -1481,19 +1488,13 @@ void
isc_taskmgr_setprivilegedmode(isc_taskmgr_t *manager0) {
isc__taskmgr_t *manager = (isc__taskmgr_t *)manager0;
LOCK(&manager->lock);
manager->mode = isc_taskmgrmode_privileged;
UNLOCK(&manager->lock);
atomic_store(&manager->mode, isc_taskmgrmode_privileged);
}
isc_taskmgrmode_t
isc_taskmgr_mode(isc_taskmgr_t *manager0) {
isc__taskmgr_t *manager = (isc__taskmgr_t *)manager0;
isc_taskmgrmode_t mode;
LOCK(&manager->lock);
mode = manager->mode;
UNLOCK(&manager->lock);
return (mode);
return (atomic_load(&manager->mode));
}
void
@@ -1501,14 +1502,15 @@ isc__taskmgr_pause(isc_taskmgr_t *manager0) {
isc__taskmgr_t *manager = (isc__taskmgr_t *)manager0;
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);
/* This is ugly but pause is used EXCLUSIVELY in tests */
isc_thread_yield();
LOCK(&manager->halt_lock);
}
manager->pause_requested = true;
atomic_store_relaxed(&manager->pause_req, true);
while (manager->halted < manager->workers) {
wake_all_queues(manager);
WAIT(&manager->halt_cond, &manager->halt_lock);
@@ -1520,8 +1522,8 @@ void
isc__taskmgr_resume(isc_taskmgr_t *manager0) {
isc__taskmgr_t *manager = (isc__taskmgr_t *)manager0;
LOCK(&manager->halt_lock);
if (manager->pause_requested) {
manager->pause_requested = false;
if (manager->pause_req) {
manager->pause_req = false;
while (manager->halted > 0) {
BROADCAST(&manager->halt_cond);
WAIT(&manager->halt_cond, &manager->halt_lock);
@@ -1573,16 +1575,19 @@ isc_task_beginexclusive(isc_task_t *task0) {
LOCK(&manager->excl_lock);
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);
if (manager->exclusive_requested || manager->pause_requested) {
if (atomic_load_relaxed(&manager->exclusive_req) ||
atomic_load_relaxed(&manager->pause_req)) {
return (ISC_R_LOCKBUSY);
}
LOCK(&manager->halt_lock);
INSIST(!manager->exclusive_requested && !manager->pause_requested);
manager->exclusive_requested = true;
INSIST(!atomic_load_relaxed(&manager->exclusive_req) &&
!atomic_load_relaxed(&manager->pause_req));
atomic_store_relaxed(&manager->exclusive_req, true);
while (manager->halted + 1 < manager->workers) {
wake_all_queues(manager);
WAIT(&manager->halt_cond, &manager->halt_lock);
@@ -1599,8 +1604,8 @@ isc_task_endexclusive(isc_task_t *task0) {
REQUIRE(VALID_TASK(task));
REQUIRE(task->state == task_state_running);
LOCK(&manager->halt_lock);
REQUIRE(manager->exclusive_requested);
manager->exclusive_requested = false;
REQUIRE(atomic_load_relaxed(&manager->exclusive_req) == true);
atomic_store_relaxed(&manager->exclusive_req, false);
while (manager->halted > 0) {
BROADCAST(&manager->halt_cond);
WAIT(&manager->halt_cond, &manager->halt_lock);
@@ -1685,14 +1690,19 @@ isc_taskmgr_renderxml(isc_taskmgr_t *mgr0, xmlTextWriterPtr writer) {
mgr->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(xmlTextWriterWriteFormatString(writer, "%d",
(int) mgr->tasks_running));
(int) atomic_load_relaxed(&mgr->tasks_running)));
TRY0(xmlTextWriterEndElement(writer)); /* tasks-running */
TRY0(xmlTextWriterStartElement(writer, ISC_XMLCHAR "tasks-ready"));
TRY0(xmlTextWriterWriteFormatString(writer, "%d",
(int) mgr->tasks_ready));
(int) atomic_load_relaxed(&mgr->tasks_ready)));
TRY0(xmlTextWriterEndElement(writer)); /* tasks-ready */
TRY0(xmlTextWriterEndElement(writer)); /* thread-model */
@@ -1785,11 +1795,15 @@ isc_taskmgr_renderjson(isc_taskmgr_t *mgr0, json_object *tasks) {
CHECKMEM(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);
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);
json_object_object_add(tasks, "tasks-ready", obj);
+36 -31
View File
@@ -36,6 +36,7 @@
#include <isc/event.h>
#include <isc/platform.h>
#include <isc/strerr.h>
#include <isc/atomic.h>
#include <isc/string.h>
#include <isc/task.h>
#include <isc/time.h>
@@ -50,7 +51,7 @@
* as an event loop dispatching various events.
*/
static pthread_t blockedthread;
static bool is_running;
static atomic_bool is_running;
/*
* 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.
*/
bool want_shutdown;
atomic_bool want_shutdown;
/*
* 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_socketmgr_t *socketmgr;
@@ -91,13 +92,13 @@ static isc__appctx_t isc_g_appctx;
static void
exit_action(int arg) {
UNUSED(arg);
isc_g_appctx.want_shutdown = true;
atomic_store(&isc_g_appctx.want_shutdown, true);
}
static void
reload_action(int arg) {
UNUSED(arg);
isc_g_appctx.want_reload = true;
atomic_store(&isc_g_appctx.want_reload, true);
}
#endif
@@ -145,9 +146,9 @@ isc_app_ctxstart(isc_appctx_t *ctx0) {
ctx->shutdown_requested = false;
ctx->running = false;
ctx->want_shutdown = false;
ctx->want_reload = false;
ctx->blocked = false;
atomic_store(&ctx->want_shutdown, false);
atomic_store(&ctx->want_reload, false);
atomic_store(&ctx->blocked, false);
#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
* sigwait().
*/
while (!ctx->want_shutdown) {
while (!atomic_load(&ctx->want_shutdown)) {
#ifdef HAVE_SIGWAIT
if (isc_bind9) {
/*
@@ -357,10 +358,11 @@ isc_app_ctxrun(isc_appctx_t *ctx0) {
result = sigwait(&sset, &sig);
if (result == 0) {
if (sig == SIGINT || sig == SIGTERM)
ctx->want_shutdown = true;
else if (sig == SIGHUP)
ctx->want_reload = true;
if (sig == SIGINT || sig == SIGTERM) {
atomic_store(&ctx->want_shutdown, true);
} else if (sig == SIGHUP) {
atomic_store(&ctx->want_reload, true);
}
}
} else {
@@ -369,12 +371,12 @@ isc_app_ctxrun(isc_appctx_t *ctx0) {
* wait until woken up.
*/
LOCK(&ctx->readylock);
if (ctx->want_shutdown) {
if (atomic_load(&ctx->want_shutdown)) {
/* shutdown() won the race. */
UNLOCK(&ctx->readylock);
break;
}
if (!ctx->want_reload)
if (!atomic_load(&ctx->want_reload))
WAIT(&ctx->ready, &ctx->readylock);
UNLOCK(&ctx->readylock);
}
@@ -412,24 +414,27 @@ isc_app_ctxrun(isc_appctx_t *ctx0) {
* wait until woken up.
*/
LOCK(&ctx->readylock);
if (ctx->want_shutdown) {
if (atomic_load(&ctx->want_shutdown)) {
/* shutdown() won the race. */
UNLOCK(&ctx->readylock);
break;
}
if (!ctx->want_reload)
if (!atomic_load(&ctx->want_reload)) {
WAIT(&ctx->ready, &ctx->readylock);
}
UNLOCK(&ctx->readylock);
}
#endif /* HAVE_SIGWAIT */
if (ctx->want_reload) {
ctx->want_reload = false;
if (atomic_load(&ctx->want_reload)) {
atomic_store(&ctx->want_reload, false);
return (ISC_R_RELOAD);
}
if (ctx->want_shutdown && ctx->blocked)
if (atomic_load(&ctx->want_shutdown) &&
atomic_load(&ctx->blocked)) {
exit(1);
}
}
return (ISC_R_SUCCESS);
@@ -439,16 +444,16 @@ isc_result_t
isc_app_run(void) {
isc_result_t result;
is_running = true;
atomic_store(&is_running, true);
result = isc_app_ctxrun((isc_appctx_t *)&isc_g_appctx);
is_running = false;
atomic_store(&is_running, false);
return (result);
}
bool
isc_app_isrunning() {
return (is_running);
return (atomic_load(&is_running));
}
isc_result_t
@@ -473,7 +478,7 @@ isc_app_ctxshutdown(isc_appctx_t *ctx0) {
if (want_kill) {
if (isc_bind9 && ctx != &isc_g_appctx)
/* BIND9 internal, but using multiple contexts */
ctx->want_shutdown = true;
atomic_store(&ctx->want_shutdown, true);
else {
if (isc_bind9) {
/* BIND9 internal, single context */
@@ -489,7 +494,7 @@ isc_app_ctxshutdown(isc_appctx_t *ctx0) {
else {
/* External, multiple contexts */
LOCK(&ctx->readylock);
ctx->want_shutdown = true;
atomic_store(&ctx->want_shutdown, true);
UNLOCK(&ctx->readylock);
SIGNAL(&ctx->ready);
}
@@ -527,9 +532,9 @@ isc_app_ctxsuspend(isc_appctx_t *ctx0) {
if (want_kill) {
if (isc_bind9 && ctx != &isc_g_appctx)
/* BIND9 internal, but using multiple contexts */
ctx->want_reload = true;
atomic_store(&ctx->want_reload, true);
else {
ctx->want_reload = true;
atomic_store(&ctx->want_reload, true);
if (isc_bind9) {
/* BIND9 internal, single context */
if (kill(getpid(), SIGHUP) < 0) {
@@ -544,7 +549,7 @@ isc_app_ctxsuspend(isc_appctx_t *ctx0) {
else {
/* External, multiple contexts */
LOCK(&ctx->readylock);
ctx->want_reload = true;
atomic_store(&ctx->want_reload, true);
UNLOCK(&ctx->readylock);
SIGNAL(&ctx->ready);
}
@@ -577,9 +582,9 @@ void
isc_app_block(void) {
sigset_t sset;
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();
RUNTIME_CHECK(sigemptyset(&sset) == 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
watch_fd(isc__socketthread_t *thread, int fd, int msg) {
isc_result_t result = ISC_R_SUCCESS;
int lockid = FDLOCK_ID(fd);
#ifdef USE_KQUEUE
struct kevent evchange;
(void) lockid;
memset(&evchange, 0, sizeof(evchange));
if (msg == SELECT_POKE_READ) {
@@ -701,19 +703,37 @@ watch_fd(isc__socketthread_t *thread, int fd, int msg) {
int ret;
int op;
LOCK(&thread->fdlock[lockid]);
oldevents = thread->epoll_events[fd];
if (msg == SELECT_POKE_READ) {
thread->epoll_events[fd] |= EPOLLIN;
} else {
thread->epoll_events[fd] |= EPOLLOUT;
}
#if __SANITIZE_THREAD__
isc__socket_t *sock = thread->fds[fd];
#endif
event.events = thread->epoll_events[fd];
memset(&event.data, 0, sizeof(event.data));
event.data.fd = fd;
UNLOCK(&thread->fdlock[lockid]);
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);
#if __SANITIZE_THREAD__
if (unlock) {
UNLOCK(&sock->lock);
}
#endif
if (ret == -1) {
if (errno == EEXIST) {
UNEXPECTED_ERROR(__FILE__, __LINE__,
@@ -726,8 +746,8 @@ watch_fd(isc__socketthread_t *thread, int fd, int msg) {
return (result);
#elif defined(USE_DEVPOLL)
struct pollfd pfd;
int lockid = FDLOCK_ID(fd);
LOCK(&thread->fdlock[lockid]);
memset(&pfd, 0, sizeof(pfd));
if (msg == SELECT_POKE_READ) {
pfd.events = POLLIN;
@@ -745,6 +765,7 @@ watch_fd(isc__socketthread_t *thread, int fd, int msg) {
thread->fdpollinfo[fd].want_write = 1;
}
}
UNLOCK(&thread->fdlock[lockid]);
return (result);
#elif defined(USE_SELECT)
@@ -764,9 +785,11 @@ watch_fd(isc__socketthread_t *thread, int fd, int msg) {
static inline isc_result_t
unwatch_fd(isc__socketthread_t *thread, int fd, int msg) {
isc_result_t result = ISC_R_SUCCESS;
int lockid = FDLOCK_ID(fd);
#ifdef USE_KQUEUE
struct kevent evchange;
(void) lockid;
memset(&evchange, 0, sizeof(evchange));
if (msg == SELECT_POKE_READ) {
@@ -786,6 +809,7 @@ unwatch_fd(isc__socketthread_t *thread, int fd, int msg) {
int ret;
int op;
LOCK(&thread->fdlock[lockid]);
if (msg == SELECT_POKE_READ) {
thread->epoll_events[fd] &= ~(EPOLLIN);
} else {
@@ -795,9 +819,29 @@ unwatch_fd(isc__socketthread_t *thread, int fd, int msg) {
event.events = thread->epoll_events[fd];
memset(&event.data, 0, sizeof(event.data));
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;
ret = epoll_ctl(thread->epoll_fd, op, fd, &event);
#if __SANITIZE_THREAD__
if (unlock) {
UNLOCK(&sock->lock);
}
#endif
if (ret == -1 && errno != ENOENT) {
char strbuf[ISC_STRERRORSIZE];
strerror_r(errno, strbuf, sizeof(strbuf));
@@ -809,7 +853,6 @@ unwatch_fd(isc__socketthread_t *thread, int fd, int msg) {
#elif defined(USE_DEVPOLL)
struct pollfd pfds[2];
size_t writelen = sizeof(pfds[0]);
int lockid = FDLOCK_ID(fd);
memset(pfds, 0, sizeof(pfds));
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
* socket for the other operation.
*/
LOCK(&thread->fdlock[lockid]);
if (msg == SELECT_POKE_READ &&
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;
}
}
UNLOCK(&thread->fdlock[lockid]);
return (result);
#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);
LOCK(&thread->fdlock[lockid]);
if (msg == SELECT_POKE_CLOSE) {
/* No one should be updating fdstate, so no need to lock it */
INSIST(thread->fdstate[fd] == CLOSE_PENDING);
thread->fdstate[fd] = CLOSED;
UNLOCK(&thread->fdlock[lockid]);
(void)unwatch_fd(thread, fd, SELECT_POKE_READ);
(void)unwatch_fd(thread, fd, SELECT_POKE_WRITE);
(void)close(fd);
return;
}
LOCK(&thread->fdlock[lockid]);
if (thread->fdstate[fd] == CLOSE_PENDING) {
UNLOCK(&thread->fdlock[lockid]);
@@ -1833,6 +1879,7 @@ destroy(isc__socket_t **sockp) {
socket_log(sock, NULL, CREATION, "destroying");
LOCK(&sock->lock);
INSIST(ISC_LIST_EMPTY(sock->connect_list));
INSIST(ISC_LIST_EMPTY(sock->accept_list));
INSIST(ISC_LIST_EMPTY(sock->recv_list));
@@ -1846,6 +1893,7 @@ destroy(isc__socket_t **sockp) {
sock->threadid = -1;
socketclose(thread, sock, fd);
}
UNLOCK(&sock->lock);
LOCK(&manager->lock);
@@ -3153,6 +3201,7 @@ process_fd(isc__socketthread_t *thread, int fd, bool readable,
bool writeable)
{
isc__socket_t *sock;
bool listener, connecting;
int lockid = FDLOCK_ID(fd);
/*
@@ -3181,9 +3230,15 @@ process_fd(isc__socketthread_t *thread, int fd, bool readable,
UNLOCK(&thread->fdlock[lockid]);
return;
}
UNLOCK(&thread->fdlock[lockid]);
LOCK(&sock->lock);
listener = sock->listener;
connecting = sock->connecting;
UNLOCK(&sock->lock);
if (readable) {
if (sock->listener) {
if (listener) {
internal_accept(sock);
} else {
internal_recv(sock);
@@ -3191,14 +3246,13 @@ process_fd(isc__socketthread_t *thread, int fd, bool readable,
}
if (writeable) {
if (sock->connecting) {
if (connecting) {
internal_connect(sock);
} else {
internal_send(sock);
}
}
UNLOCK(&thread->fdlock[lockid]);
if (isc_refcount_decrement(&sock->references) == 1) {
destroy(&sock);
}
+2 -2
View File
@@ -229,7 +229,7 @@ struct ns_clientmgr {
#define NS_CLIENT_DROPPORT 1
#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 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_READY));
ns_client_requests++;
atomic_fetch_add(&ns_client_requests, 1);
if (event->ev_type == ISC_SOCKEVENT_RECVDONE) {
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
LIBNS_EXTERNAL_DATA extern unsigned int ns_client_requests;
LIBNS_EXTERNAL_DATA extern atomic_uint_fast32_t ns_client_requests;
/***
*** Functions