Compare commits
35
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2f9da7f225 | ||
|
|
b7a76fad2b | ||
|
|
5e5e8da953 | ||
|
|
7b8757db45 | ||
|
|
dc2ca4fa8d | ||
|
|
6f89098e32 | ||
|
|
2f93fa320f | ||
|
|
3d11d69ebf | ||
|
|
cb847810aa | ||
|
|
2680c6d189 | ||
|
|
2445c44f21 | ||
|
|
a1101c07fc | ||
|
|
ea2720cc00 | ||
|
|
a6c53a015a | ||
|
|
e2102aabbe | ||
|
|
e4e9930397 | ||
|
|
58e1baba7a | ||
|
|
3ed794bb45 | ||
|
|
3e8838654d | ||
|
|
fcb8aec700 | ||
|
|
1565ee6c3d | ||
|
|
527e540841 | ||
|
|
43ca8bc50a | ||
|
|
733a3db7a5 | ||
|
|
7b9f4cfc08 | ||
|
|
258f1dc94c | ||
|
|
b1c35f812a | ||
|
|
f65933d11a | ||
|
|
e1f80772b2 | ||
|
|
f880388607 | ||
|
|
3fa5684e19 | ||
|
|
28025720a8 | ||
|
|
e83e6be806 | ||
|
|
505b88e1a3 | ||
|
|
b7a199184c |
@@ -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
@@ -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
@@ -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; };
|
||||
};
|
||||
@@ -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 {
|
||||
|
||||
@@ -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";
|
||||
};
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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" {
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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";
|
||||
};
|
||||
};
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
@@ -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>
|
||||
|
||||
@@ -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
@@ -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
@@ -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);
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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.
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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));
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user