git: f1c5de5fab9d - main - ctld: Add a dedicated conf method for shutting down

From: John Baldwin <jhb_at_FreeBSD.org>
Date: Mon, 18 May 2026 19:51:14 UTC
The branch main has been updated by jhb:

URL: https://cgit.FreeBSD.org/src/commit/?id=f1c5de5fab9d5cada11935418db11e19ebff7e34

commit f1c5de5fab9d5cada11935418db11e19ebff7e34
Author:     John Baldwin <jhb@FreeBSD.org>
AuthorDate: 2026-05-18 19:48:09 +0000
Commit:     John Baldwin <jhb@FreeBSD.org>
CommitDate: 2026-05-18 19:49:35 +0000

    ctld: Add a dedicated conf method for shutting down
    
    Currently the main loop creates an empty config and applies it to
    force a shutdown of all of the existing configuration.  While this is
    functional and does avoid duplicating some code, it is also a bit
    clunky and requires a special hack in the pidfile path handling
    in the conf::apply method.
    
    Instead, use a dedicated conf::shutdown method which tears down the
    CTL ports and LUNs and closes the sockets.
    
    Sponsored by:   Chelsio Communications
    Differential Revision:  https://reviews.freebsd.org/D56532
---
 usr.sbin/ctld/ctld.cc | 56 ++++++++++++++++++++++++++++++++++++---------------
 usr.sbin/ctld/ctld.hh |  1 +
 2 files changed, 41 insertions(+), 16 deletions(-)

diff --git a/usr.sbin/ctld/ctld.cc b/usr.sbin/ctld/ctld.cc
index 627ecf8bba93..24b02a936670 100644
--- a/usr.sbin/ctld/ctld.cc
+++ b/usr.sbin/ctld/ctld.cc
@@ -1976,11 +1976,9 @@ conf::apply(struct conf *oldconf)
 	/*
 	 * Rename the pidfile if the pathname changes.  On startup,
 	 * oldconf created via conf_new_from_kernel will not contain a
-	 * valid pidfile_path.  On shutdown, the temporary newconf
-	 * will not contain a valid pidfile_path.
+	 * valid pidfile_path.
 	 */
-	if (!oldconf->conf_pidfile_path.empty() &&
-	    !conf_pidfile_path.empty()) {
+	if (!oldconf->conf_pidfile_path.empty()) {
 		if (oldconf->conf_pidfile_path != conf_pidfile_path) {
 			/* pidfile has changed.  rename it */
 			log_debugx("moving pidfile to %s",
@@ -2210,6 +2208,41 @@ conf::apply(struct conf *oldconf)
 	return (cumulated_error);
 }
 
+void
+conf::shutdown()
+{
+	/* Deregister from iSNS servers. */
+	for (auto &kv : conf_isns)
+		isns_deregister_targets(&kv.second);
+
+	/* Remove all ports. */
+	for (const auto &kv : conf_ports) {
+		const std::string &name = kv.first;
+		port *port = kv.second.get();
+
+		if (port->is_dummy())
+			continue;
+		log_debugx("removing port \"%s\"", name.c_str());
+		if (!port->kernel_remove())
+			log_warnx("failed to remove port %s", name.c_str());
+	}
+
+	/* Remove all LUNs. */
+	for (const auto &kv : conf_luns) {
+		struct lun *lun = kv.second.get();
+
+		if (!lun->kernel_remove())
+			log_warnx("failed to remove lun \"%s\", CTL lun %d",
+			    lun->name(), lun->ctl_lun());
+	}
+
+	/* Close sockets on all portal groups. */
+	for (auto &kv : conf_portal_groups)
+		kv.second->close_sockets();
+	for (auto &kv : conf_transport_groups)
+		kv.second->close_sockets();
+}
+
 bool
 timed_out(void)
 {
@@ -2767,21 +2800,12 @@ main(int argc, char **argv)
 				oldconf.reset();
 			}
 		} else if (sigterm_received) {
-			log_debugx("exiting on signal; "
-			    "reloading empty configuration");
+			log_debugx("exiting on signal");
 
-			log_debugx("removing CTL iSCSI ports "
+			log_debugx("removing CTL iSCSI and NVMeoF ports "
 			    "and terminating all connections");
 
-			oldconf = std::move(newconf);
-			newconf = std::make_unique<conf>();
-			if (debug > 0)
-				newconf->set_debug(debug);
-			error = newconf->apply(oldconf.get());
-			if (error != 0)
-				log_warnx("failed to apply configuration");
-			oldconf.reset();
-
+			newconf->shutdown();
 			log_warnx("exiting on signal");
 			return (0);
 		} else {
diff --git a/usr.sbin/ctld/ctld.hh b/usr.sbin/ctld/ctld.hh
index d3b08dc12603..7ae033804157 100644
--- a/usr.sbin/ctld/ctld.hh
+++ b/usr.sbin/ctld/ctld.hh
@@ -513,6 +513,7 @@ struct conf {
 	int apply(struct conf *oldconf);
 	void delete_target_luns(struct lun *lun);
 	bool reuse_portal_group_socket(struct portal &newp);
+	void shutdown();
 	bool verify();
 
 private: