]> git.ipfire.org Git - thirdparty/knot-dns.git/commitdiff
knotd: start ctl early in server bootstrap
authorDavid Vašek <david.vasek@nic.cz>
Thu, 5 Jun 2025 16:22:01 +0000 (18:22 +0200)
committerDavid Vašek <david.vasek@nic.cz>
Thu, 17 Jul 2025 16:37:53 +0000 (18:37 +0200)
src/knot/events/handlers/load.c
src/knot/server/server.c
src/knot/zone/zone.h
src/knot/zone/zonedb-load.c
src/utils/knotd/main.c

index 54b29ba1639df32d0dc291fba601eec50cade9ae..754267249c849eb2089e2dc2b8117959d976b561 100644 (file)
@@ -419,6 +419,7 @@ load_end:
                zone_schedule_notify(conf, zone, 0);
        }
        zone_skip_free(&skip);
+       zone->started = true;
 
        return KNOT_EOK;
 
@@ -430,6 +431,7 @@ cleanup:
        zone_contents_deep_free(zf_conts);
        zone_contents_deep_free(journal_conts);
        zone_skip_free(&skip);
+       zone->started = true;
 
        return (dontcare_load_error(conf, zone) ? KNOT_EOK : ret);
 }
index 9bf95c5a24e6c8da644f6bdc2c19e24d272834e2..b390cbdc2a79f9195ede523439e4617d3d6d57e4 100644 (file)
@@ -1395,6 +1395,10 @@ int server_reload(server_t *server, reload_t mode)
 
 void server_stop(server_t *server)
 {
+       if (server == NULL || !(server->state & ServerRunning)) {
+               return;
+       }
+
        log_info("stopping server");
        systemd_stopping_notify();
 
index b5792cfdb61cc0880748ade1e46025c7ac79adef..5f7a156b32dd24bbeeee2a964a5e05b53af4b245 100644 (file)
@@ -77,6 +77,7 @@ typedef struct zone
        zone_contents_t *contents;
        zone_flag_t flags;
        bool is_catalog_flag; //!< Lock-less indication of ZONE_IS_CATALOG flag.
+       bool started;         //!< Lock-less indication of a started zone.
 
        /*! \brief Dynamic configuration zone change type. */
        conf_io_type_t change_type;
index c023ad4fd1a7814573bcb51e7dedd65802364ebc..d376b526ae7bdad7c2dc3c1ac4fd40121f92b3ab 100644 (file)
@@ -176,6 +176,7 @@ static zone_t *create_zone_new(conf_t *conf, const knot_dname_t *name,
                log_zone_info(zone->name, "zone will be bootstrapped");
                assert(zone_is_slave(conf, zone));
                replan_load_bootstrap(conf, zone);
+               zone->started = true;
        } else {
                log_zone_info(zone->name, "zone will be loaded");
                // if load fails, fallback to bootstrap
index 398d536d56826eaea2ddbd06dd257a4e7d01b72e..794a7d0bd1fe23c0f5ac010ca0c2cfe0473b98be 100644 (file)
@@ -116,42 +116,77 @@ static void drop_capabilities(void)
 #endif /* ENABLE_CAP_NG */
 }
 
-static void check_loaded(server_t *server)
+static int check_loaded(server_t *server, bool async)
 {
-       static bool finished = false;
-       if (finished) {
-               return;
+       /*
+        * Started: all zones loaded or at least tried to load at least once,
+        *          the server is already running and accepting queries.
+        * Loaded:  all zones successfully loaded, it implies 'started',
+        *          KNOT_BUS_EVENT_STARTED already emitted over DBus.
+        */
+       static bool started = false;
+       static bool loaded = false;
+       assert(server->state & ServerRunning);
+       if (loaded) {
+               assert(server->state & ServerAnswering);
+               return KNOT_EOK;
        }
 
        /* Avoid traversing the zonedb too frequently. */
        static struct timespec last = { 0 };
        struct timespec now = time_now();
        if (last.tv_sec == now.tv_sec) {
-               return;
+               return KNOT_EOK;
        }
        last = now;
 
-       if (!(conf()->cache.srv_dbus_event & DBUS_EVENT_RUNNING)) {
-               finished = true;
-               return;
-       }
-
+       started = started || async;
+       bool start = true;
+       bool load = true;
        rcu_read_lock();
        knot_zonedb_iter_t *it = knot_zonedb_iter_begin(server->zone_db);
        while (!knot_zonedb_iter_finished(it)) {
                zone_t *zone = (zone_t *)knot_zonedb_iter_val(it);
-               if (zone->contents == NULL) {
-                       knot_zonedb_iter_free(it);
-                       rcu_read_unlock();
-                       return;
+               if (zone->contents != NULL) {
+                       knot_zonedb_iter_next(it);
+                       continue;
                }
+               load = false;
+               if (started) {
+                       break;
+               } else if (!zone->started) {
+                       start = false;
+                       break;
+               }
+
                knot_zonedb_iter_next(it);
        }
        knot_zonedb_iter_free(it);
        rcu_read_unlock();
 
-       finished = true;
-       dbus_emit_running(true);
+       if (!start) {
+               return KNOT_EOK;
+       }
+       if (!started) {
+               int ret = server_start_answering(server);
+               if (ret != KNOT_EOK) {
+                       return ret;
+               }
+               started = true;
+       }
+
+       assert(server->state & ServerAnswering);
+       if (!(conf()->cache.srv_dbus_event & DBUS_EVENT_RUNNING)) {
+               loaded = true;
+               return KNOT_EOK;
+       }
+
+       if (load) {   /* Not 'loaded' yet. */
+               dbus_emit_running(true);
+               loaded = true;
+       }
+
+       return KNOT_EOK;
 }
 
 static void deinit_ctls(knot_ctl_t **ctls, unsigned count)
@@ -218,12 +253,12 @@ static knot_ctl_t **init_ctls(const char *socket)
 }
 
 /*! \brief Event loop listening for signals and remote commands. */
-static void event_loop(server_t *server, const char *socket, bool daemonize,
-                       unsigned long pid)
+static int event_loop(server_t *server, const char *socket, bool daemonize,
+                      unsigned long pid, bool async)
 {
        knot_ctl_t **ctls = init_ctls(socket);
        if (ctls == NULL) {
-               return;
+               return KNOT_ERROR;
        }
 
        conf_val_t listen_val = conf_get(conf(), C_CTL, C_LISTEN);
@@ -238,7 +273,7 @@ static void event_loop(server_t *server, const char *socket, bool daemonize,
        if (ret != KNOT_EOK) {
                log_fatal("control, failed to launch socket threads (%s)",
                          knot_strerror(ret));
-               return;
+               return ret;
        }
 
        signals_enable();
@@ -276,7 +311,10 @@ static void event_loop(server_t *server, const char *socket, bool daemonize,
                        continue;
                }
 
-               check_loaded(server);
+               ret = check_loaded(server, async);
+               if (ret != KNOT_EOK) {
+                       goto done;
+               }
 
                sleep(5); // wait for signals to arrive
        }
@@ -285,8 +323,10 @@ static void event_loop(server_t *server, const char *socket, bool daemonize,
                dbus_emit_running(false);
        }
 
+done:
        ctl_socket_thr_end(&sctx);
        deinit_ctls(ctls, sock_count);
+       return ret;
 }
 
 static void print_help(void)
@@ -573,26 +613,25 @@ int main(int argc, char **argv)
        stats_reconfigure(conf(), &server);
 
        /* Start it up. */
-       log_info("starting server");
+       /* In async-start mode, start answering early, otherwise in the event loop. */
        conf_val_t async_val = conf_get(conf(), C_SRV, C_ASYNC_START);
-       ret = server_start(&server, conf_bool(&async_val));
-       if (ret != KNOT_EOK) {
+       bool async = conf_bool(&async_val);
+       if ((ret = server_start(&server, async)) != KNOT_EOK ||
+           (ret = event_loop(&server, socket, daemonize, pid, async)) != KNOT_EOK) {
                log_fatal("failed to start server (%s)", knot_strerror(ret));
+               server_stop(&server);
                server_wait(&server);
                stats_deinit();
-               server_deinit(&server);
-               rcu_unregister_thread();
                pid_cleanup();
+               server_deinit(&server);
                conf_free(conf());
+               rcu_unregister_thread();
                dbus_close();
                log_close();
                dnssec_crypto_cleanup();
                return EXIT_FAILURE;
        }
 
-       /* Start the event loop. */
-       event_loop(&server, socket, daemonize, pid);
-
        /* Teardown server. */
        server_stop(&server);
        server_wait(&server);