[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

[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: