Permalink
Browse files

nbd-server: read conf on SIGHUP and add new exports

This patch makes the root server process re-read its configuration files
and add new exports dynamically when SIGHUP is sent. The rehash feature
is non-destructive: it does not modify any existing exports, it only
lets the root server process to add new exports. However, it might be a
good idea to implement destructive counterparts (export deletion and
modification) too at some point.

Signed-off-by: Tuomas Räsänen <tuomasjjrasanen@tjjr.fi>
[change usage of __attribute__((unused)) into G_GNUC_UNUSED]
Signed-off-by: Wouter Verhelst <w@uter.be>
  • Loading branch information...
tuomasjjrasanen authored and yoe committed Mar 10, 2013
1 parent f08d0e3 commit 9633af964a38a16e2976437515e08e9d6036f825
Showing with 131 additions and 0 deletions.
  1. +7 −0 man/nbd-server.1.in.sgml
  2. +124 −0 nbd-server.c
View
@@ -95,6 +95,13 @@ manpage.1: manpage.sgml
export, the use of this option is deprecated. It is preferred to
make use of a configuration file instead, the format of which is
defined in nbd-server(5).</para>
<para>While nbd-server is running, new exports can be added by
re-writing configuration files and then sending SIGHUP to
nbd-server. SIGHUP causes nbd-server to re-read its configuration
files and to start serving all new exports which were not served
earlier. Reconfiguration does not modify any existing export, it only
appends new ones.</para>
</refsect1>
<refsect1>
<title>OPTIONS</title>
View
@@ -177,6 +177,11 @@ char default_authname[] = SYSCONFDIR "/nbd-server/allow"; /**< default name of a
#define NEG_OLD (1 << 1)
#define NEG_MODERN (1 << 2)
static volatile sig_atomic_t is_sighup_caught; /**< Flag set by SIGHUP
handler to mark a
reconfiguration
request */
int modernsock=-1; /**< Socket for the modern handler. Not used
if a client was only specified on the
command line; only port used if
@@ -1116,6 +1121,19 @@ void sigterm_handler(int s) {
exit(EXIT_SUCCESS);
}
/**
* Handle SIGHUP by setting atomically a flag which will be evaluated in
* the main loop of the root server process. This allows us to separate
* the signal catching from th actual task triggered by SIGHUP and hence
* processing in the interrupt context is kept as minimial as possible.
*
* @param s the signal we're handling (must be SIGHUP, or something
* is severely wrong).
**/
static void sighup_handler(const int s G_GNUC_UNUSED) {
is_sighup_caught = 1;
}
/**
* Detect the size of a file.
*
@@ -2239,6 +2257,7 @@ handle_connection(GArray *servers, int net, SERVER *serve, CLIENT *client)
/* child */
signal(SIGCHLD, SIG_DFL);
signal(SIGTERM, SIG_DFL);
signal(SIGHUP, SIG_DFL);
sigprocmask(SIG_SETMASK, &oldset, NULL);
g_hash_table_destroy(children);
@@ -2266,6 +2285,72 @@ handle_connection(GArray *servers, int net, SERVER *serve, CLIENT *client)
close(net);
}
/**
* Return the index of the server whose servename matches the given
* name.
*
* @param servename a string to match
* @param servers an array of servers
* @return the first index of the server whose servename matches the
* given name or -1 if one cannot be found
**/
static int get_index_by_servename(const gchar *const servename,
const GArray *const servers) {
int i;
for (i = 0; i < servers->len; ++i) {
const SERVER server = g_array_index(servers, SERVER, i);
if (strcmp(servename, server.servename) == 0)
return i;
}
return -1;
}
int setup_serve(SERVER *const serve, GError **const gerror);
/**
* Parse configuration files and add servers to the array if they don't
* already exist there. The existence is tested by comparing
* servenames. A server is appended to the array only if its servename
* is unique among all other servers.
*
* @param servers an array of servers
* @return the number of new servers appended to the array, or -1 in
* case of an error
**/
static int append_new_servers(GArray *const servers, GError **const gerror) {
int i;
GArray *new_servers;
const int old_len = servers->len;
int retval = -1;
struct generic_conf genconf;
new_servers = parse_cfile(config_file_pos, &genconf, gerror);
if (!new_servers)
goto out;
for (i = 0; i < new_servers->len; ++i) {
SERVER new_server = g_array_index(new_servers, SERVER, i);
if (new_server.servename
&& -1 == get_index_by_servename(new_server.servename,
servers)) {
if (setup_serve(&new_server, gerror) == -1)
goto out;
if (append_serve(&new_server, servers) == -1)
goto out;
}
}
retval = servers->len - old_len;
out:
g_array_free(new_servers, TRUE);
return retval;
}
/**
* Loop through the available servers, and serve them. Never returns.
**/
@@ -2298,6 +2383,39 @@ void serveloop(GArray* servers) {
max=modernsock>max?modernsock:max;
}
for(;;) {
/* SIGHUP causes the root server process to reconfigure
* itself and add new export servers for each newly
* found export configuration group, i.e. spawn new
* server processes for each previously non-existent
* export. This does not alter old runtime configuration
* but just appends new exports. */
if (is_sighup_caught) {
int n;
GError *gerror = NULL;
msg(LOG_INFO, "reconfiguration request received");
is_sighup_caught = 0; /* Reset to allow catching
* it again. */
n = append_new_servers(servers, &gerror);
if (n == -1)
msg(LOG_ERR, "failed to append new servers: %s",
gerror->message);
for (i = servers->len - n; i < servers->len; ++i) {
const SERVER server = g_array_index(servers,
SERVER, i);
if (server.socket >= 0) {
FD_SET(server.socket, &mset);
max = server.socket > max ? server.socket : max;
}
msg(LOG_INFO, "reconfigured new server: %s",
server.servename);
}
}
memcpy(&rset, &mset, sizeof(fd_set));
if(select(max+1, &rset, NULL, NULL, NULL)>0) {
int net;
@@ -2599,6 +2717,12 @@ void setup_servers(GArray *const servers, const gchar *const modernaddr,
sa.sa_flags = SA_RESTART;
if(sigaction(SIGTERM, &sa, NULL) == -1)
err("sigaction: %m");
sa.sa_handler = sighup_handler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART;
if(sigaction(SIGHUP, &sa, NULL) == -1)
err("sigaction: %m");
}
/**

0 comments on commit 9633af9

Please sign in to comment.