From: David VaĊĦek Date: Thu, 5 Jun 2025 16:22:01 +0000 (+0200) Subject: knotd: start ctl early in server bootstrap X-Git-Tag: v3.5.0~47^2~4 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=60d01eb363b2838b0756f5152f20d5c6ed14b16c;p=thirdparty%2Fknot-dns.git knotd: start ctl early in server bootstrap --- diff --git a/src/knot/events/handlers/load.c b/src/knot/events/handlers/load.c index 54b29ba163..754267249c 100644 --- a/src/knot/events/handlers/load.c +++ b/src/knot/events/handlers/load.c @@ -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); } diff --git a/src/knot/server/server.c b/src/knot/server/server.c index 9bf95c5a24..b390cbdc2a 100644 --- a/src/knot/server/server.c +++ b/src/knot/server/server.c @@ -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(); diff --git a/src/knot/zone/zone.h b/src/knot/zone/zone.h index b5792cfdb6..5f7a156b32 100644 --- a/src/knot/zone/zone.h +++ b/src/knot/zone/zone.h @@ -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; diff --git a/src/knot/zone/zonedb-load.c b/src/knot/zone/zonedb-load.c index c023ad4fd1..d376b526ae 100644 --- a/src/knot/zone/zonedb-load.c +++ b/src/knot/zone/zonedb-load.c @@ -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 diff --git a/src/utils/knotd/main.c b/src/utils/knotd/main.c index 398d536d56..794a7d0bd1 100644 --- a/src/utils/knotd/main.c +++ b/src/utils/knotd/main.c @@ -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);