[Nbd] [PATCH 1/1] 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@...1261...>
---
man/nbd-server.1.in.sgml | 7 +++
nbd-server.c | 124 ++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 131 insertions(+)
diff --git a/man/nbd-server.1.in.sgml b/man/nbd-server.1.in.sgml
index 7a5832e..a6adce4 100644
--- a/man/nbd-server.1.in.sgml
+++ b/man/nbd-server.1.in.sgml
@@ -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>
diff --git a/nbd-server.c b/nbd-server.c
index d49874d..27c4600 100644
--- a/nbd-server.c
+++ b/nbd-server.c
@@ -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
@@ -1117,6 +1122,19 @@ void sigterm_handler(int s) {
}
/**
+ * 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 __attribute__ ((unused))) {
+ is_sighup_caught = 1;
+}
+
+/**
* Detect the size of a file.
*
* @param fhandle An open filedescriptor
@@ -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);
@@ -2267,6 +2286,72 @@ handle_connection_out:
}
/**
+ * 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.
**/
void serveloop(GArray* servers) {
@@ -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");
}
/**
--
1.7.10.4
Reply to: