2
0
mirror of https://gitlab.isc.org/isc-projects/dhcp synced 2025-08-22 18:07:25 +00:00

[master] Add option to suppress the use of fsync when writing lease files

The option is dont-use-async <flag> and it defaults to disabled.
This commit is contained in:
Shawn Routhier 2013-11-08 12:00:02 -08:00
parent 1534fff7c5
commit cde11a4cdb
6 changed files with 136 additions and 127 deletions

View File

@ -89,6 +89,13 @@ work on other platforms. Please report any problems and suggested fixes to
key for security reasons. key for security reasons.
[ISC-Bugs 30461] [ISC-Bugs 30461]
- Add a configuration option to the server to suppress using fsync().
Enabling this option will mean that fsync() is never called. This
may provide better performance but there is also a risk that a lease
will not be properly written to the disk after it has been issued
to a client and before the server stops. Using this option is
not recommended.
Changes since 4.2.5 Changes since 4.2.5
- Address static analysis warnings. - Address static analysis warnings.

View File

@ -732,6 +732,7 @@ struct lease_state {
#endif #endif
#endif #endif
#define SV_CACHE_THRESHOLD 78 #define SV_CACHE_THRESHOLD 78
#define SV_DONT_USE_FSYNC 79
#if !defined (DEFAULT_PING_TIMEOUT) #if !defined (DEFAULT_PING_TIMEOUT)
# define DEFAULT_PING_TIMEOUT 1 # define DEFAULT_PING_TIMEOUT 1
@ -1916,6 +1917,7 @@ extern struct timeval cur_tv;
#define cur_time cur_tv.tv_sec #define cur_time cur_tv.tv_sec
extern int ddns_update_style; extern int ddns_update_style;
extern int dont_use_fsync;
extern const char *path_dhcpd_conf; extern const char *path_dhcpd_conf;
extern const char *path_dhcpd_db; extern const char *path_dhcpd_db;

View File

@ -1014,12 +1014,13 @@ int commit_leases ()
We need to do this even if we're rewriting the file below, We need to do this even if we're rewriting the file below,
just in case the rewrite fails. */ just in case the rewrite fails. */
if (fflush (db_file) == EOF) { if (fflush (db_file) == EOF) {
log_info ("commit_leases: unable to commit, fflush(): %m"); log_info("commit_leases: unable to commit, fflush(): %m");
return 0; return (0);
} }
if (fsync (fileno (db_file)) < 0) { if ((dont_use_fsync == 0) &&
(fsync(fileno (db_file)) < 0)) {
log_info ("commit_leases: unable to commit, fsync(): %m"); log_info ("commit_leases: unable to commit, fsync(): %m");
return 0; return (0);
} }
/* send out all deferred ACKs now */ /* send out all deferred ACKs now */
@ -1031,9 +1032,9 @@ int commit_leases ()
if (count && cur_time - write_time > LEASE_REWRITE_PERIOD) { if (count && cur_time - write_time > LEASE_REWRITE_PERIOD) {
count = 0; count = 0;
write_time = cur_time; write_time = cur_time;
new_lease_file (); new_lease_file();
} }
return 1; return (1);
} }
/* /*

View File

@ -78,6 +78,7 @@ option server.ddns-rev-domainname = \"in-addr.arpa.\";";
#endif /* NSUPDATE */ #endif /* NSUPDATE */
int ddns_update_style; int ddns_update_style;
int dont_use_fsync = 0; /* 0 = default, use fsync, 1 = don't use fsync */
const char *path_dhcpd_conf = _PATH_DHCPD_CONF; const char *path_dhcpd_conf = _PATH_DHCPD_CONF;
const char *path_dhcpd_db = _PATH_DHCPD_DB; const char *path_dhcpd_db = _PATH_DHCPD_DB;
@ -800,7 +801,7 @@ main(int argc, char **argv) {
void postconf_initialization (int quiet) void postconf_initialization (int quiet)
{ {
struct option_state *options = (struct option_state *)0; struct option_state *options = NULL;
struct data_string db; struct data_string db;
struct option_cache *oc; struct option_cache *oc;
char *s; char *s;
@ -808,39 +809,35 @@ void postconf_initialization (int quiet)
int tmp; int tmp;
/* Now try to get the lease file name. */ /* Now try to get the lease file name. */
option_state_allocate (&options, MDL); option_state_allocate(&options, MDL);
execute_statements_in_scope(NULL, NULL, NULL, NULL, NULL, execute_statements_in_scope(NULL, NULL, NULL, NULL, NULL,
options, &global_scope, root_group, options, &global_scope, root_group,
NULL, NULL); NULL, NULL);
memset (&db, 0, sizeof db); memset(&db, 0, sizeof db);
oc = lookup_option (&server_universe, options, SV_LEASE_FILE_NAME); oc = lookup_option(&server_universe, options, SV_LEASE_FILE_NAME);
if (oc && if (oc &&
evaluate_option_cache (&db, (struct packet *)0, evaluate_option_cache(&db, NULL, NULL, NULL, options, NULL,
(struct lease *)0, (struct client_state *)0, &global_scope, oc, MDL)) {
options, (struct option_state *)0, s = dmalloc(db.len + 1, MDL);
&global_scope, oc, MDL)) {
s = dmalloc (db.len + 1, MDL);
if (!s) if (!s)
log_fatal ("no memory for lease db filename."); log_fatal("no memory for lease db filename.");
memcpy (s, db.data, db.len); memcpy(s, db.data, db.len);
s [db.len] = 0; s[db.len] = 0;
data_string_forget (&db, MDL); data_string_forget(&db, MDL);
path_dhcpd_db = s; path_dhcpd_db = s;
} }
oc = lookup_option (&server_universe, options, SV_PID_FILE_NAME); oc = lookup_option(&server_universe, options, SV_PID_FILE_NAME);
if (oc && if (oc &&
evaluate_option_cache (&db, (struct packet *)0, evaluate_option_cache(&db, NULL, NULL, NULL, options, NULL,
(struct lease *)0, (struct client_state *)0, &global_scope, oc, MDL)) {
options, (struct option_state *)0, s = dmalloc(db.len + 1, MDL);
&global_scope, oc, MDL)) {
s = dmalloc (db.len + 1, MDL);
if (!s) if (!s)
log_fatal ("no memory for pid filename."); log_fatal("no memory for pid filename.");
memcpy (s, db.data, db.len); memcpy(s, db.data, db.len);
s [db.len] = 0; s[db.len] = 0;
data_string_forget (&db, MDL); data_string_forget(&db, MDL);
path_dhcpd_pid = s; path_dhcpd_pid = s;
} }
@ -853,137 +850,116 @@ void postconf_initialization (int quiet)
oc = lookup_option(&server_universe, options, oc = lookup_option(&server_universe, options,
SV_DHCPV6_LEASE_FILE_NAME); SV_DHCPV6_LEASE_FILE_NAME);
if (oc && if (oc &&
evaluate_option_cache(&db, NULL, NULL, NULL, evaluate_option_cache(&db, NULL, NULL, NULL, options, NULL,
options, NULL, &global_scope, &global_scope, oc, MDL)) {
oc, MDL)) { s = dmalloc(db.len + 1, MDL);
s = dmalloc (db.len + 1, MDL);
if (!s) if (!s)
log_fatal ("no memory for lease db filename."); log_fatal("no memory for lease db filename.");
memcpy (s, db.data, db.len); memcpy(s, db.data, db.len);
s [db.len] = 0; s[db.len] = 0;
data_string_forget (&db, MDL); data_string_forget(&db, MDL);
path_dhcpd_db = s; path_dhcpd_db = s;
} }
oc = lookup_option(&server_universe, options, oc = lookup_option(&server_universe, options,
SV_DHCPV6_PID_FILE_NAME); SV_DHCPV6_PID_FILE_NAME);
if (oc && if (oc &&
evaluate_option_cache(&db, NULL, NULL, NULL, evaluate_option_cache(&db, NULL, NULL, NULL, options, NULL,
options, NULL, &global_scope, &global_scope, oc, MDL)) {
oc, MDL)) { s = dmalloc(db.len + 1, MDL);
s = dmalloc (db.len + 1, MDL);
if (!s) if (!s)
log_fatal ("no memory for pid filename."); log_fatal("no memory for pid filename.");
memcpy (s, db.data, db.len); memcpy(s, db.data, db.len);
s [db.len] = 0; s[db.len] = 0;
data_string_forget (&db, MDL); data_string_forget(&db, MDL);
path_dhcpd_pid = s; path_dhcpd_pid = s;
} }
} }
#endif /* DHCPv6 */ #endif /* DHCPv6 */
omapi_port = -1; omapi_port = -1;
oc = lookup_option (&server_universe, options, SV_OMAPI_PORT); oc = lookup_option(&server_universe, options, SV_OMAPI_PORT);
if (oc && if (oc &&
evaluate_option_cache (&db, (struct packet *)0, evaluate_option_cache(&db, NULL, NULL, NULL, options, NULL,
(struct lease *)0, (struct client_state *)0, &global_scope, oc, MDL)) {
options, (struct option_state *)0,
&global_scope, oc, MDL)) {
if (db.len == 2) { if (db.len == 2) {
omapi_port = getUShort (db.data); omapi_port = getUShort(db.data);
} else } else
log_fatal ("invalid omapi port data length"); log_fatal("invalid omapi port data length");
data_string_forget (&db, MDL); data_string_forget(&db, MDL);
} }
oc = lookup_option (&server_universe, options, SV_OMAPI_KEY); oc = lookup_option(&server_universe, options, SV_OMAPI_KEY);
if (oc && if (oc &&
evaluate_option_cache (&db, (struct packet *)0, evaluate_option_cache(&db, NULL, NULL, NULL, options, NULL,
(struct lease *)0, (struct client_state *)0, &global_scope, oc, MDL)) {
options, s = dmalloc(db.len + 1, MDL);
(struct option_state *)0,
&global_scope, oc, MDL)) {
s = dmalloc (db.len + 1, MDL);
if (!s) if (!s)
log_fatal ("no memory for OMAPI key filename."); log_fatal("no memory for OMAPI key filename.");
memcpy (s, db.data, db.len); memcpy(s, db.data, db.len);
s [db.len] = 0; s[db.len] = 0;
data_string_forget (&db, MDL); data_string_forget(&db, MDL);
result = omapi_auth_key_lookup_name (&omapi_key, s); result = omapi_auth_key_lookup_name(&omapi_key, s);
dfree (s, MDL); dfree(s, MDL);
if (result != ISC_R_SUCCESS) if (result != ISC_R_SUCCESS)
log_fatal ("OMAPI key %s: %s", log_fatal("OMAPI key %s: %s",
s, isc_result_totext (result)); s, isc_result_totext (result));
} }
oc = lookup_option (&server_universe, options, SV_LOCAL_PORT); oc = lookup_option(&server_universe, options, SV_LOCAL_PORT);
if (oc && if (oc &&
evaluate_option_cache (&db, (struct packet *)0, evaluate_option_cache(&db, NULL, NULL, NULL, options, NULL,
(struct lease *)0, (struct client_state *)0, &global_scope, oc, MDL)) {
options,
(struct option_state *)0,
&global_scope, oc, MDL)) {
if (db.len == 2) { if (db.len == 2) {
local_port = htons (getUShort (db.data)); local_port = htons(getUShort (db.data));
} else } else
log_fatal ("invalid local port data length"); log_fatal("invalid local port data length");
data_string_forget (&db, MDL); data_string_forget(&db, MDL);
} }
oc = lookup_option (&server_universe, options, SV_REMOTE_PORT); oc = lookup_option(&server_universe, options, SV_REMOTE_PORT);
if (oc && if (oc &&
evaluate_option_cache (&db, (struct packet *)0, evaluate_option_cache(&db, NULL, NULL, NULL, options, NULL,
(struct lease *)0, (struct client_state *)0, &global_scope, oc, MDL)) {
options, (struct option_state *)0,
&global_scope, oc, MDL)) {
if (db.len == 2) { if (db.len == 2) {
remote_port = htons (getUShort (db.data)); remote_port = htons(getUShort (db.data));
} else } else
log_fatal ("invalid remote port data length"); log_fatal("invalid remote port data length");
data_string_forget (&db, MDL); data_string_forget(&db, MDL);
} }
oc = lookup_option (&server_universe, options, oc = lookup_option(&server_universe, options,
SV_LIMITED_BROADCAST_ADDRESS); SV_LIMITED_BROADCAST_ADDRESS);
if (oc && if (oc &&
evaluate_option_cache (&db, (struct packet *)0, evaluate_option_cache(&db, NULL, NULL, NULL, options, NULL,
(struct lease *)0, (struct client_state *)0, &global_scope, oc, MDL)) {
options, (struct option_state *)0,
&global_scope, oc, MDL)) {
if (db.len == 4) { if (db.len == 4) {
memcpy (&limited_broadcast, db.data, 4); memcpy(&limited_broadcast, db.data, 4);
} else } else
log_fatal ("invalid broadcast address data length"); log_fatal("invalid broadcast address data length");
data_string_forget (&db, MDL); data_string_forget(&db, MDL);
} }
oc = lookup_option (&server_universe, options, oc = lookup_option(&server_universe, options, SV_LOCAL_ADDRESS);
SV_LOCAL_ADDRESS);
if (oc && if (oc &&
evaluate_option_cache (&db, (struct packet *)0, evaluate_option_cache(&db, NULL, NULL, NULL, options, NULL,
(struct lease *)0, (struct client_state *)0, &global_scope, oc, MDL)) {
options, (struct option_state *)0,
&global_scope, oc, MDL)) {
if (db.len == 4) { if (db.len == 4) {
memcpy (&local_address, db.data, 4); memcpy(&local_address, db.data, 4);
} else } else
log_fatal ("invalid local address data length"); log_fatal("invalid local address data length");
data_string_forget (&db, MDL); data_string_forget(&db, MDL);
} }
oc = lookup_option (&server_universe, options, SV_DDNS_UPDATE_STYLE); oc = lookup_option(&server_universe, options, SV_DDNS_UPDATE_STYLE);
if (oc) { if (oc) {
if (evaluate_option_cache (&db, (struct packet *)0, if (evaluate_option_cache(&db, NULL, NULL, NULL, options, NULL,
(struct lease *)0, &global_scope, oc, MDL)) {
(struct client_state *)0,
options,
(struct option_state *)0,
&global_scope, oc, MDL)) {
if (db.len == 1) { if (db.len == 1) {
ddns_update_style = db.data [0]; ddns_update_style = db.data[0];
} else } else
log_fatal ("invalid dns update type"); log_fatal("invalid dns update type");
data_string_forget (&db, MDL); data_string_forget(&db, MDL);
} }
} else { } else {
ddns_update_style = DDNS_UPDATE_STYLE_NONE; ddns_update_style = DDNS_UPDATE_STYLE_NONE;
@ -1000,17 +976,13 @@ void postconf_initialization (int quiet)
} }
#endif #endif
oc = lookup_option (&server_universe, options, SV_LOG_FACILITY); oc = lookup_option(&server_universe, options, SV_LOG_FACILITY);
if (oc) { if (oc) {
if (evaluate_option_cache (&db, (struct packet *)0, if (evaluate_option_cache(&db, NULL, NULL, NULL, options, NULL,
(struct lease *)0, &global_scope, oc, MDL)) {
(struct client_state *)0,
options,
(struct option_state *)0,
&global_scope, oc, MDL)) {
if (db.len == 1) { if (db.len == 1) {
closelog (); closelog ();
openlog ("dhcpd", LOG_NDELAY, db.data[0]); openlog("dhcpd", LOG_NDELAY, db.data[0]);
/* Log the startup banner into the new /* Log the startup banner into the new
log file. */ log file. */
if (!quiet) { if (!quiet) {
@ -1019,14 +991,14 @@ void postconf_initialization (int quiet)
log_perror = 0; log_perror = 0;
log_info("%s %s", log_info("%s %s",
message, PACKAGE_VERSION); message, PACKAGE_VERSION);
log_info (copyright); log_info(copyright);
log_info (arr); log_info(arr);
log_info (url); log_info(url);
log_perror = tmp; log_perror = tmp;
} }
} else } else
log_fatal ("invalid log facility"); log_fatal("invalid log facility");
data_string_forget (&db, MDL); data_string_forget(&db, MDL);
} }
} }
@ -1058,8 +1030,16 @@ void postconf_initialization (int quiet)
data_string_forget(&db, MDL); data_string_forget(&db, MDL);
} }
oc = lookup_option(&server_universe, options, SV_DONT_USE_FSYNC);
if ((oc != NULL) &&
evaluate_boolean_option_cache(NULL, NULL, NULL, NULL, options, NULL,
&global_scope, oc, MDL)) {
dont_use_fsync = 1;
log_error("Not using fsync() to flush lease writes");
}
/* Don't need the options anymore. */ /* Don't need the options anymore. */
option_state_dereference (&options, MDL); option_state_dereference(&options, MDL);
} }
void postdb_startup (void) void postdb_startup (void)

View File

@ -2110,6 +2110,24 @@ will still honor the setting of the \fBclient-updates\fR flag.
.RE .RE
.PP .PP
The The
.I dont-use-async
statement
.RS 0.25i
.PP
.B dont-use-async \fIflag\fB;\fR
.PP
The \fIdont-use-async\fR statement instructs the DHCP server if
it should call fsync() when writing leases to the lease file. By
default and if the flag is set to false the server \fBwill\fR call
fsync(). Suppressing the call to fsync() may increase the performance
of the server but it also adds a risk that a lease will not be
properly written to the disk after it has been issued to a client
and before the server stops. This can lead to duplicate leases
being issued to different clients. Using this option is \fBnot
recommended\FR.
.RE
.PP
The
.I dynamic-bootp-lease-cutoff .I dynamic-bootp-lease-cutoff
statement statement
.RS 0.25i .RS 0.25i

View File

@ -267,6 +267,7 @@ static struct option server_options[] = {
#endif /* LDAP_USE_SSL */ #endif /* LDAP_USE_SSL */
#endif /* LDAP_CONFIGURATION */ #endif /* LDAP_CONFIGURATION */
{ "dhcp-cache-threshold", "B", &server_universe, 78, 1 }, { "dhcp-cache-threshold", "B", &server_universe, 78, 1 },
{ "dont-use-fsync", "f", &server_universe, 79, 1 },
{ NULL, NULL, NULL, 0, 0 } { NULL, NULL, NULL, 0, 0 }
}; };