git: 888ec3a71912 - main - ctld: Convert struct conf to a C++ class

From: John Baldwin <jhb_at_FreeBSD.org>
Date: Mon, 04 Aug 2025 19:47:03 UTC
The branch main has been updated by jhb:

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

commit 888ec3a71912994e4585a6444962de691b56d5d6
Author:     John Baldwin <jhb@FreeBSD.org>
AuthorDate: 2025-08-04 19:38:07 +0000
Commit:     John Baldwin <jhb@FreeBSD.org>
CommitDate: 2025-08-04 19:38:07 +0000

    ctld: Convert struct conf to a C++ class
    
    - Various functions to add or lookup configuration objects are now
      methods of the conf class.
    
    - Use std::string and freebsd::pidfile for various members.
    
    - Rename the global set_timeout() to start_timer() to avoid shadowing
      conf::set_timeout() and also split out a separate stop_timer().
    
    Sponsored by:   Chelsio Communications
    Pull Request:   https://github.com/freebsd/freebsd-src/pull/1794
---
 usr.sbin/ctld/conf.cc   |  63 ++----
 usr.sbin/ctld/ctld.cc   | 564 +++++++++++++++++++++++++++---------------------
 usr.sbin/ctld/ctld.hh   | 109 ++++++----
 usr.sbin/ctld/kernel.cc |  28 +--
 4 files changed, 416 insertions(+), 348 deletions(-)

diff --git a/usr.sbin/ctld/conf.cc b/usr.sbin/ctld/conf.cc
index 81451009067c..2eae12c31d0c 100644
--- a/usr.sbin/ctld/conf.cc
+++ b/usr.sbin/ctld/conf.cc
@@ -70,48 +70,43 @@ conf_finish(void)
 bool
 isns_add_server(const char *addr)
 {
-	return (isns_new(conf, addr));
+	return (conf->add_isns(addr));
 }
 
 void
 conf_set_debug(int debug)
 {
-	conf->conf_debug = debug;
+	conf->set_debug(debug);
 }
 
 void
 conf_set_isns_period(int period)
 {
-	conf->conf_isns_period = period;
+	conf->set_isns_period(period);
 }
 
 void
 conf_set_isns_timeout(int timeout)
 {
-	conf->conf_isns_timeout = timeout;
+	conf->set_isns_timeout(timeout);
 }
 
 void
 conf_set_maxproc(int maxproc)
 {
-	conf->conf_maxproc = maxproc;
+	conf->set_maxproc(maxproc);
 }
 
 bool
 conf_set_pidfile_path(const char *path)
 {
-	if (conf->conf_pidfile_path != NULL) {
-		log_warnx("pidfile specified more than once");
-		return (false);
-	}
-	conf->conf_pidfile_path = checked_strdup(path);
-	return (true);
+	return (conf->set_pidfile_path(path));
 }
 
 void
 conf_set_timeout(int timeout)
 {
-	conf->conf_timeout = timeout;
+	conf->set_timeout(timeout);
 }
 
 bool
@@ -148,22 +143,10 @@ auth_group_set_type(const char *type)
 bool
 auth_group_start(const char *name)
 {
-	/*
-	 * Make it possible to redefine the default auth-group. but
-	 * only once.
-	 */
-	if (strcmp(name, "default") == 0) {
-		if (conf->conf_default_ag_defined) {
-			log_warnx("duplicated auth-group \"default\"");
-			return (false);
-		}
-
-		conf->conf_default_ag_defined = true;
-		auth_group = auth_group_find(conf, "default").get();
-		return (true);
-	}
-
-	auth_group = auth_group_new(conf, name);
+	if (strcmp(name, "default") == 0)
+		auth_group = conf->define_default_auth_group();
+	else
+		auth_group = conf->add_auth_group(name);
 	return (auth_group != nullptr);
 }
 
@@ -176,22 +159,10 @@ auth_group_finish(void)
 bool
 portal_group_start(const char *name)
 {
-	/*
-	 * Make it possible to redefine the default portal-group. but
-	 * only once.
-	 */
-	if (strcmp(name, "default") == 0) {
-		if (conf->conf_default_pg_defined) {
-			log_warnx("duplicated portal-group \"default\"");
-			return (false);
-		}
-
-		conf->conf_default_pg_defined = true;
-		portal_group = portal_group_find(conf, "default");
-		return (true);
-	}
-
-	portal_group = portal_group_new(conf, name);
+	if (strcmp(name, "default") == 0)
+		portal_group = conf->define_default_portal_group();
+	else
+		portal_group = conf->add_portal_group(name);
 	return (portal_group != NULL);
 }
 
@@ -264,7 +235,7 @@ portal_group_set_tag(uint16_t tag)
 bool
 lun_start(const char *name)
 {
-	lun = lun_new(conf, name);
+	lun = conf->add_lun(name);
 	return (lun != NULL);
 }
 
@@ -331,7 +302,7 @@ lun_set_ctl_lun(uint32_t value)
 bool
 target_start(const char *name)
 {
-	target = target_new(conf, name);
+	target = conf->add_target(name);
 	return (target != NULL);
 }
 
diff --git a/usr.sbin/ctld/ctld.cc b/usr.sbin/ctld/ctld.cc
index 2aaba32ed101..d3106a00d417 100644
--- a/usr.sbin/ctld/ctld.cc
+++ b/usr.sbin/ctld/ctld.cc
@@ -96,29 +96,75 @@ usage(void)
 	exit(1);
 }
 
-struct conf *
-conf_new(void)
+void
+conf::set_debug(int debug)
 {
-	struct conf *conf;
+	conf_debug = debug;
+}
 
-	conf = new struct conf();
+void
+conf::set_isns_period(int period)
+{
+	conf_isns_period = period;
+}
 
-	conf->conf_isns_period = 900;
-	conf->conf_isns_timeout = 5;
-	conf->conf_debug = 0;
-	conf->conf_timeout = 60;
-	conf->conf_maxproc = 30;
+void
+conf::set_isns_timeout(int timeout)
+{
+	conf_isns_timeout = timeout;
+}
 
-	return (conf);
+void
+conf::set_maxproc(int maxproc)
+{
+	conf_maxproc = maxproc;
+}
+
+void
+conf::set_timeout(int timeout)
+{
+	conf_timeout = timeout;
+}
+
+bool
+conf::set_pidfile_path(std::string_view path)
+{
+	if (!conf_pidfile_path.empty()) {
+		log_warnx("pidfile specified more than once");
+		return (false);
+	}
+	conf_pidfile_path = path;
+	return (true);
+}
+
+void
+conf::open_pidfile()
+{
+	const char *path;
+	pid_t otherpid;
+
+	assert(!conf_pidfile_path.empty());
+	path = conf_pidfile_path.c_str();
+	log_debugx("opening pidfile %s", path);
+	conf_pidfile = pidfile_open(path, 0600, &otherpid);
+	if (!conf_pidfile) {
+		if (errno == EEXIST)
+			log_errx(1, "daemon already running, pid: %jd.",
+			    (intmax_t)otherpid);
+		log_err(1, "cannot open or create pidfile \"%s\"", path);
+	}
 }
 
 void
-conf_delete(struct conf *conf)
+conf::write_pidfile()
 {
-	assert(conf->conf_pidfh == NULL);
+	conf_pidfile.write();
+}
 
-	free(conf->conf_pidfile_path);
-	delete conf;
+void
+conf::close_pidfile()
+{
+	conf_pidfile.close();
 }
 
 #ifdef ICL_KERNEL_PROXY
@@ -393,9 +439,9 @@ auth_group::initiator_permitted(const struct sockaddr *sa) const
 }
 
 struct auth_group *
-auth_group_new(struct conf *conf, const char *name)
+conf::add_auth_group(const char *name)
 {
-	const auto &pair = conf->conf_auth_groups.try_emplace(name,
+	const auto &pair = conf_auth_groups.try_emplace(name,
 	    std::make_shared<auth_group>(freebsd::stringf("auth-group \"%s\"",
 	    name)));
 	if (!pair.second) {
@@ -406,11 +452,26 @@ auth_group_new(struct conf *conf, const char *name)
 	return (pair.first->second.get());
 }
 
+/*
+ * Make it possible to redefine the default auth-group, but only once.
+ */
+struct auth_group *
+conf::define_default_auth_group()
+{
+	if (conf_default_ag_defined) {
+		log_warnx("duplicated auth-group \"default\"");
+		return (nullptr);
+	}
+
+	conf_default_ag_defined = true;
+	return (find_auth_group("default").get());
+}
+
 auth_group_sp
-auth_group_find(const struct conf *conf, const char *name)
+conf::find_auth_group(std::string_view name)
 {
-	auto it = conf->conf_auth_groups.find(name);
-	if (it == conf->conf_auth_groups.end())
+	auto it = conf_auth_groups.find(std::string(name));
+	if (it == conf_auth_groups.end())
 		return {};
 
 	return (it->second);
@@ -422,10 +483,10 @@ portal_group::portal_group(struct conf *conf, std::string_view name)
 }
 
 struct portal_group *
-portal_group_new(struct conf *conf, const char *name)
+conf::add_portal_group(const char *name)
 {
-	auto pair = conf->conf_portal_groups.try_emplace(name,
-	    std::make_unique<portal_group>(conf, name));
+	auto pair = conf_portal_groups.try_emplace(name,
+	    std::make_unique<portal_group>(this, name));
 	if (!pair.second) {
 		log_warnx("duplicated portal-group \"%s\"", name);
 		return (nullptr);
@@ -434,11 +495,27 @@ portal_group_new(struct conf *conf, const char *name)
 	return (pair.first->second.get());
 }
 
+/*
+ * Make it possible to redefine the default portal-group, but only
+ * once.
+ */
+struct portal_group *
+conf::define_default_portal_group()
+{
+	if (conf_default_pg_defined) {
+		log_warnx("duplicated portal-group \"default\"");
+		return (nullptr);
+	}
+
+	conf_default_pg_defined = true;
+	return (find_portal_group("default"));
+}
+
 struct portal_group *
-portal_group_find(struct conf *conf, const char *name)
+conf::find_portal_group(std::string_view name)
 {
-	auto it = conf->conf_portal_groups.find(name);
-	if (it == conf->conf_portal_groups.end())
+	auto it = conf_portal_groups.find(std::string(name));
+	if (it == conf_portal_groups.end())
 		return (nullptr);
 
 	return (it->second.get());
@@ -554,7 +631,7 @@ portal_group::set_discovery_auth_group(const char *ag_name)
 		    "\"%s\" specified more than once", name());
 		return (false);
 	}
-	pg_discovery_auth_group = auth_group_find(pg_conf, ag_name);
+	pg_discovery_auth_group = pg_conf->find_auth_group(ag_name);
 	if (pg_discovery_auth_group == nullptr) {
 		log_warnx("unknown discovery-auth-group \"%s\" "
 		    "for portal-group \"%s\"", ag_name, name());
@@ -666,7 +743,7 @@ void
 portal_group::verify(struct conf *conf)
 {
 	if (pg_discovery_auth_group == nullptr) {
-		pg_discovery_auth_group =  auth_group_find(conf, "default");
+		pg_discovery_auth_group = conf->find_auth_group("default");
 		assert(pg_discovery_auth_group != nullptr);
 	}
 
@@ -748,9 +825,9 @@ portal_group::close_sockets()
 }
 
 bool
-isns_new(struct conf *conf, const char *addr)
+conf::add_isns(const char *addr)
 {
-	if (conf->conf_isns.count(addr) > 0) {
+	if (conf_isns.count(addr) > 0) {
 		log_warnx("duplicate iSNS address %s", addr);
 		return (false);
 	}
@@ -766,10 +843,11 @@ isns_new(struct conf *conf, const char *addr)
 	 *	those into multiple servers.
 	 */
 
-	conf->conf_isns.emplace(addr, isns(addr, std::move(ai)));
+	conf_isns.emplace(addr, isns(addr, std::move(ai)));
 	return (true);
 }
 
+
 freebsd::fd_up
 isns::connect()
 {
@@ -807,18 +885,18 @@ isns::send_request(int s, struct isns_req req)
 	return (true);
 }
 
-static struct isns_req
-isns_register_request(struct conf *conf, const char *hostname)
+struct isns_req
+conf::isns_register_request(const char *hostname)
 {
 	const struct portal_group *pg;
 
 	isns_req req(ISNS_FUNC_DEVATTRREG, ISNS_FLAG_CLIENT, "register");
-	req.add_str(32, conf->conf_first_target->name());
+	req.add_str(32, conf_first_target->name());
 	req.add_delim();
 	req.add_str(1, hostname);
 	req.add_32(2, 2); /* 2 -- iSCSI */
-	req.add_32(6, conf->conf_isns_period);
-	for (const auto &kv : conf->conf_portal_groups) {
+	req.add_32(6, conf_isns_period);
+	for (const auto &kv : conf_portal_groups) {
 		pg = kv.second.get();
 
 		if (!pg->assigned())
@@ -828,7 +906,7 @@ isns_register_request(struct conf *conf, const char *hostname)
 			req.add_port(17, portal->ai());
 		}
 	}
-	for (const auto &kv : conf->conf_targets) {
+	for (const auto &kv : conf_targets) {
 		const struct target *target = kv.second.get();
 
 		req.add_str(32, target->name());
@@ -849,40 +927,39 @@ isns_register_request(struct conf *conf, const char *hostname)
 	return (req);
 }
 
-static struct isns_req
-isns_check_request(struct conf *conf, const char *hostname)
+struct isns_req
+conf::isns_check_request(const char *hostname)
 {
 	isns_req req(ISNS_FUNC_DEVATTRQRY, ISNS_FLAG_CLIENT, "check");
-	req.add_str(32, conf->conf_first_target->name());
+	req.add_str(32, conf_first_target->name());
 	req.add_str(1, hostname);
 	req.add_delim();
 	req.add(2, 0, NULL);
 	return (req);
 }
 
-static struct isns_req
-isns_deregister_request(struct conf *conf, const char *hostname)
+struct isns_req
+conf::isns_deregister_request(const char *hostname)
 {
 	isns_req req(ISNS_FUNC_DEVDEREG, ISNS_FLAG_CLIENT, "deregister");
-	req.add_str(32, conf->conf_first_target->name());
+	req.add_str(32, conf_first_target->name());
 	req.add_delim();
 	req.add_str(1, hostname);
 	return (req);
 }
 
 void
-isns_register_targets(struct conf *conf, struct isns *isns,
-    struct conf *oldconf)
+conf::isns_register_targets(struct isns *isns, struct conf *oldconf)
 {
 	int error;
 	char hostname[256];
 
-	if (conf->conf_targets.empty() || conf->conf_portal_groups.empty())
+	if (conf_targets.empty() || conf_portal_groups.empty())
 		return;
-	set_timeout(conf->conf_isns_timeout, false);
+	start_timer(conf_isns_timeout);
 	freebsd::fd_up s = isns->connect();
 	if (!s) {
-		set_timeout(0, false);
+		stop_timer();
 		return;
 	}
 	error = gethostname(hostname, sizeof(hostname));
@@ -890,48 +967,48 @@ isns_register_targets(struct conf *conf, struct isns *isns,
 		log_err(1, "gethostname");
 
 	if (oldconf == nullptr || oldconf->conf_first_target == nullptr)
-		oldconf = conf;
-	isns->send_request(s, isns_deregister_request(oldconf, hostname));
-	isns->send_request(s, isns_register_request(conf, hostname));
+		oldconf = this;
+	isns->send_request(s, oldconf->isns_deregister_request(hostname));
+	isns->send_request(s, isns_register_request(hostname));
 	s.reset();
-	set_timeout(0, false);
+	stop_timer();
 }
 
 void
-isns_check(struct conf *conf, struct isns *isns)
+conf::isns_check(struct isns *isns)
 {
 	int error;
 	char hostname[256];
 
-	if (conf->conf_targets.empty() || conf->conf_portal_groups.empty())
+	if (conf_targets.empty() || conf_portal_groups.empty())
 		return;
-	set_timeout(conf->conf_isns_timeout, false);
+	start_timer(conf_isns_timeout);
 	freebsd::fd_up s = isns->connect();
 	if (!s) {
-		set_timeout(0, false);
+		stop_timer();
 		return;
 	}
 	error = gethostname(hostname, sizeof(hostname));
 	if (error != 0)
 		log_err(1, "gethostname");
 
-	if (!isns->send_request(s, isns_check_request(conf, hostname))) {
-		isns->send_request(s, isns_deregister_request(conf, hostname));
-		isns->send_request(s, isns_register_request(conf, hostname));
+	if (!isns->send_request(s, isns_check_request(hostname))) {
+		isns->send_request(s, isns_deregister_request(hostname));
+		isns->send_request(s, isns_register_request(hostname));
 	}
 	s.reset();
-	set_timeout(0, false);
+	stop_timer();
 }
 
 void
-isns_deregister_targets(struct conf *conf, struct isns *isns)
+conf::isns_deregister_targets(struct isns *isns)
 {
 	int error;
 	char hostname[256];
 
-	if (conf->conf_targets.empty() || conf->conf_portal_groups.empty())
+	if (conf_targets.empty() || conf_portal_groups.empty())
 		return;
-	set_timeout(conf->conf_isns_timeout, false);
+	start_timer(conf_isns_timeout);
 	freebsd::fd_up s = isns->connect();
 	if (!s)
 		return;
@@ -939,9 +1016,26 @@ isns_deregister_targets(struct conf *conf, struct isns *isns)
 	if (error != 0)
 		log_err(1, "gethostname");
 
-	isns->send_request(s, isns_deregister_request(conf, hostname));
+	isns->send_request(s, isns_deregister_request(hostname));
 	s.reset();
-	set_timeout(0, false);
+	stop_timer();
+}
+
+void
+conf::isns_schedule_update()
+{
+	if (!conf_isns.empty())
+		start_timer((conf_isns_period + 2) / 3);
+}
+
+void
+conf::isns_update()
+{
+	stop_timer();
+	for (auto &kv : conf_isns)
+		isns_check(&kv.second);
+
+	isns_schedule_update();
 }
 
 bool
@@ -1012,12 +1106,11 @@ portal_group_port::clear_references()
 }
 
 bool
-port_new(struct conf *conf, struct target *target, struct portal_group *pg,
-    auth_group_sp ag)
+conf::add_port(struct target *target, struct portal_group *pg, auth_group_sp ag)
 {
 	std::string name = freebsd::stringf("%s-%s", pg->name(),
 	    target->name());
-	const auto &pair = conf->conf_ports.try_emplace(name,
+	const auto &pair = conf_ports.try_emplace(name,
 	    std::make_unique<portal_group_port>(target, pg, ag));
 	if (!pair.second) {
 		log_warnx("duplicate port \"%s\"", name.c_str());
@@ -1028,12 +1121,12 @@ port_new(struct conf *conf, struct target *target, struct portal_group *pg,
 }
 
 bool
-port_new(struct conf *conf, struct target *target, struct portal_group *pg,
+conf::add_port(struct target *target, struct portal_group *pg,
     uint32_t ctl_port)
 {
 	std::string name = freebsd::stringf("%s-%s", pg->name(),
 	    target->name());
-	const auto &pair = conf->conf_ports.try_emplace(name,
+	const auto &pair = conf_ports.try_emplace(name,
 	    std::make_unique<portal_group_port>(target, pg, ctl_port));
 	if (!pair.second) {
 		log_warnx("duplicate port \"%s\"", name.c_str());
@@ -1043,12 +1136,12 @@ port_new(struct conf *conf, struct target *target, struct portal_group *pg,
 	return (true);
 }
 
-static bool
-port_new_pp(struct conf *conf, struct target *target, struct pport *pp)
+bool
+conf::add_port(struct target *target, struct pport *pp)
 {
 	std::string name = freebsd::stringf("%s-%s", pp->name(),
 	    target->name());
-	const auto &pair = conf->conf_ports.try_emplace(name,
+	const auto &pair = conf_ports.try_emplace(name,
 	    std::make_unique<kernel_port>(target, pp));
 	if (!pair.second) {
 		log_warnx("duplicate port \"%s\"", name.c_str());
@@ -1059,9 +1152,8 @@ port_new_pp(struct conf *conf, struct target *target, struct pport *pp)
 	return (true);
 }
 
-static bool
-port_new_ioctl(struct conf *conf, struct kports &kports, struct target *target,
-    int pp, int vp)
+bool
+conf::add_port(struct kports &kports, struct target *target, int pp, int vp)
 {
 	struct pport *pport;
 
@@ -1069,10 +1161,10 @@ port_new_ioctl(struct conf *conf, struct kports &kports, struct target *target,
 
 	pport = kports.find_port(pname);
 	if (pport != NULL)
-		return (port_new_pp(conf, target, pport));
+		return (add_port(target, pport));
 
 	std::string name = pname + "-" + target->name();
-	const auto &pair = conf->conf_ports.try_emplace(name,
+	const auto &pair = conf_ports.try_emplace(name,
 	    std::make_unique<ioctl_port>(target, pp, vp));
 	if (!pair.second) {
 		log_warnx("duplicate port \"%s\"", name.c_str());
@@ -1092,7 +1184,7 @@ portal_group::find_port(std::string_view target) const
 }
 
 struct target *
-target_new(struct conf *conf, const char *name)
+conf::add_target(const char *name)
 {
 	if (!valid_iscsi_name(name, log_warnx))
 		return (nullptr);
@@ -1104,23 +1196,23 @@ target_new(struct conf *conf, const char *name)
 	for (char &c : t_name)
 		c = tolower(c);
 
-	auto const &pair = conf->conf_targets.try_emplace(t_name,
-	    std::make_unique<target>(conf, t_name));
+	auto const &pair = conf_targets.try_emplace(t_name,
+	    std::make_unique<target>(this, t_name));
 	if (!pair.second) {
 		log_warnx("duplicated target \"%s\"", name);
 		return (NULL);
 	}
 
-	if (conf->conf_first_target == nullptr)
-		conf->conf_first_target = pair.first->second.get();
+	if (conf_first_target == nullptr)
+		conf_first_target = pair.first->second.get();
 	return (pair.first->second.get());
 }
 
 struct target *
-target_find(struct conf *conf, const char *name)
+conf::find_target(std::string_view name)
 {
-	auto it = conf->conf_targets.find(name);
-	if (it == conf->conf_targets.end())
+	auto it = conf_targets.find(std::string(name));
+	if (it == conf_targets.end())
 		return (nullptr);
 	return (it->second.get());
 }
@@ -1191,7 +1283,7 @@ target::add_lun(u_int id, const char *lun_name)
 		return (false);
 	}
 
-	t_lun = lun_find(t_conf, lun_name);
+	t_lun = t_conf->find_lun(lun_name);
 	if (t_lun == NULL) {
 		log_warnx("unknown LUN named %s used for target \"%s\"",
 		    lun_name, name());
@@ -1208,7 +1300,7 @@ target::add_portal_group(const char *pg_name, const char *ag_name)
 	struct portal_group *pg;
 	auth_group_sp ag;
 
-	pg = portal_group_find(t_conf, pg_name);
+	pg = t_conf->find_portal_group(pg_name);
 	if (pg == NULL) {
 		log_warnx("unknown portal-group \"%s\" for target \"%s\"",
 		    pg_name, name());
@@ -1216,7 +1308,7 @@ target::add_portal_group(const char *pg_name, const char *ag_name)
 	}
 
 	if (ag_name != NULL) {
-		ag = auth_group_find(t_conf, ag_name);
+		ag = t_conf->find_auth_group(ag_name);
 		if (ag == NULL) {
 			log_warnx("unknown auth-group \"%s\" for target \"%s\"",
 			    ag_name, name());
@@ -1224,7 +1316,7 @@ target::add_portal_group(const char *pg_name, const char *ag_name)
 		}
 	}
 
-	if (!port_new(t_conf, this, pg, std::move(ag))) {
+	if (!t_conf->add_port(this, pg, std::move(ag))) {
 		log_warnx("can't link portal-group \"%s\" to target \"%s\"",
 		    pg_name, name());
 		return (false);
@@ -1256,7 +1348,7 @@ target::set_auth_group(const char *ag_name)
 			    "specified more than once", name());
 		return (false);
 	}
-	t_auth_group = auth_group_find(t_conf, ag_name);
+	t_auth_group = t_conf->find_auth_group(ag_name);
 	if (t_auth_group == nullptr) {
 		log_warnx("unknown auth-group \"%s\" for target \"%s\"",
 		    ag_name, name());
@@ -1317,7 +1409,7 @@ target::start_lun(u_int id)
 	}
 
 	std::string lun_name = freebsd::stringf("%s,lun,%u", name(), id);
-	new_lun = lun_new(t_conf, lun_name.c_str());
+	new_lun = t_conf->add_lun(lun_name.c_str());
 	if (new_lun == nullptr)
 		return (nullptr);
 
@@ -1352,13 +1444,13 @@ void
 target::verify()
 {
 	if (t_auth_group == nullptr) {
-		t_auth_group = auth_group_find(t_conf, "default");
+		t_auth_group = t_conf->find_auth_group("default");
 		assert(t_auth_group != nullptr);
 	}
 	if (t_ports.empty()) {
-		struct portal_group *pg = portal_group_find(t_conf, "default");
+		struct portal_group *pg = t_conf->find_portal_group("default");
 		assert(pg != NULL);
-		port_new(t_conf, this, pg, nullptr);
+		t_conf->add_port(this, pg, nullptr);
 	}
 
 	bool found = std::any_of(t_luns.begin(), t_luns.end(),
@@ -1376,10 +1468,10 @@ lun::lun(struct conf *conf, std::string_view name)
 }
 
 struct lun *
-lun_new(struct conf *conf, const char *name)
+conf::add_lun(const char *name)
 {
-	const auto &pair = conf->conf_luns.try_emplace(name,
-	    std::make_unique<lun>(conf, name));
+	const auto &pair = conf_luns.try_emplace(name,
+	    std::make_unique<lun>(this, name));
 	if (!pair.second) {
 		log_warnx("duplicated lun \"%s\"", name);
 		return (NULL);
@@ -1387,18 +1479,18 @@ lun_new(struct conf *conf, const char *name)
 	return (pair.first->second.get());
 }
 
-static void
-conf_delete_target_luns(struct conf *conf, struct lun *lun)
+void
+conf::delete_target_luns(struct lun *lun)
 {
-	for (const auto &kv : conf->conf_targets)
+	for (const auto &kv : conf_targets)
 		kv.second->remove_lun(lun);
 }
 
 struct lun *
-lun_find(const struct conf *conf, const char *name)
+conf::find_lun(std::string_view name)
 {
-	auto it = conf->conf_luns.find(name);
-	if (it == conf->conf_luns.end())
+	auto it = conf_luns.find(std::string(name));
+	if (it == conf_luns.end())
 		return (nullptr);
 	return (it->second.get());
 }
@@ -1721,13 +1813,13 @@ lun::verify()
 }
 
 bool
-conf_verify(struct conf *conf)
+conf::verify()
 {
-	if (conf->conf_pidfile_path == NULL)
-		conf->conf_pidfile_path = checked_strdup(DEFAULT_PIDFILE);
+	if (conf_pidfile_path.empty())
+		conf_pidfile_path = DEFAULT_PIDFILE;
 
 	std::unordered_map<std::string, struct lun *> path_map;
-	for (const auto &kv : conf->conf_luns) {
+	for (const auto &kv : conf_luns) {
 		struct lun *lun = kv.second.get();
 		if (!lun->verify())
 			return (false);
@@ -1746,13 +1838,13 @@ conf_verify(struct conf *conf)
 		}
 	}
 
-	for (auto &kv : conf->conf_targets) {
+	for (auto &kv : conf_targets) {
 		kv.second->verify();
 	}
-	for (auto &kv : conf->conf_portal_groups) {
-		kv.second->verify(conf);
+	for (auto &kv : conf_portal_groups) {
+		kv.second->verify(this);
 	}
-	for (const auto &kv : conf->conf_auth_groups) {
+	for (const auto &kv : conf_auth_groups) {
 		const std::string &ag_name = kv.first;
 		if (ag_name == "default" ||
 		    ag_name == "no-authentication" ||
@@ -1903,41 +1995,44 @@ conf::reuse_portal_group_socket(struct portal &newp)
 	return (false);
 }
 
-static int
-conf_apply(struct conf *oldconf, struct conf *newconf)
+int
+conf::apply(struct conf *oldconf)
 {
 	int cumulated_error = 0;
 
-	if (oldconf->conf_debug != newconf->conf_debug) {
-		log_debugx("changing debug level to %d", newconf->conf_debug);
-		log_init(newconf->conf_debug);
+	if (oldconf->conf_debug != conf_debug) {
+		log_debugx("changing debug level to %d", conf_debug);
+		log_init(conf_debug);
 	}
 
-	if (oldconf->conf_pidfile_path != NULL &&
-	    newconf->conf_pidfile_path != NULL)
-	{
-		if (strcmp(oldconf->conf_pidfile_path,
-		           newconf->conf_pidfile_path) != 0)
-		{
+	/*
+	 * On startup, oldconf created via conf_new_from_kernel will
+	 * not contain a valid pidfile_path, and the current
+	 * conf_pidfile will already own the pidfile.  On shutdown,
+	 * the temporary newconf will not contain a valid
+	 * pidfile_path, and the pidfile will be cleaned up when the
+	 * oldconf is deleted.
+	 */
+	if (!oldconf->conf_pidfile_path.empty() &&
+	    !conf_pidfile_path.empty()) {
+		if (oldconf->conf_pidfile_path != conf_pidfile_path) {
 			/* pidfile has changed.  rename it */
 			log_debugx("moving pidfile to %s",
-				newconf->conf_pidfile_path);
-			if (rename(oldconf->conf_pidfile_path,
-				   newconf->conf_pidfile_path))
-			{
+			    conf_pidfile_path.c_str());
+			if (rename(oldconf->conf_pidfile_path.c_str(),
+				conf_pidfile_path.c_str()) != 0) {
 				log_err(1, "renaming pidfile %s -> %s",
-					oldconf->conf_pidfile_path,
-					newconf->conf_pidfile_path);
+				    oldconf->conf_pidfile_path.c_str(),
+				    conf_pidfile_path.c_str());
 			}
 		}
-		newconf->conf_pidfh = oldconf->conf_pidfh;
-		oldconf->conf_pidfh = NULL;
+		conf_pidfile = std::move(oldconf->conf_pidfile);
 	}
 
 	/*
 	 * Go through the new portal groups, assigning tags or preserving old.
 	 */
-	for (auto &kv : newconf->conf_portal_groups) {
+	for (auto &kv : conf_portal_groups) {
 		struct portal_group &newpg = *kv.second;
 
 		if (newpg.tag() != 0)
@@ -1951,14 +2046,14 @@ conf_apply(struct conf *oldconf, struct conf *newconf)
 
 	/* Deregister on removed iSNS servers. */
 	for (auto &kv : oldconf->conf_isns) {
-		if (newconf->conf_isns.count(kv.first) == 0)
-			isns_deregister_targets(oldconf, &kv.second);
+		if (conf_isns.count(kv.first) == 0)
+			oldconf->isns_deregister_targets(&kv.second);
 	}
 
 	/*
 	 * XXX: If target or lun removal fails, we should somehow "move"
-	 *      the old lun or target into newconf, so that subsequent
-	 *      conf_apply() would try to remove them again.  That would
+	 *      the old lun or target into this, so that subsequent
+	 *      conf::apply() would try to remove them again.  That would
 	 *      be somewhat hairy, though, and lun deletion failures don't
 	 *      really happen, so leave it as it is for now.
 	 */
@@ -1972,9 +2067,8 @@ conf_apply(struct conf *oldconf, struct conf *newconf)
 
 		if (oldport->is_dummy())
 			continue;
-		const auto it = newconf->conf_ports.find(name);
-		if (it != newconf->conf_ports.end() &&
-		    !it->second->is_dummy())
+		const auto it = conf_ports.find(name);
+		if (it != conf_ports.end() && !it->second->is_dummy())
 			continue;
 		log_debugx("removing port \"%s\"", name.c_str());
 		if (!oldport->kernel_remove()) {
@@ -1995,8 +2089,8 @@ conf_apply(struct conf *oldconf, struct conf *newconf)
 	     it != oldconf->conf_luns.end(); ) {
 		struct lun *oldlun = it->second.get();
 
-		auto newit = newconf->conf_luns.find(it->first);
-		if (newit == newconf->conf_luns.end()) {
+		auto newit = conf_luns.find(it->first);
+		if (newit == conf_luns.end()) {
 			log_debugx("lun \"%s\", CTL lun %d "
 			    "not found in new configuration; "
 			    "removing", oldlun->name(), oldlun->ctl_lun());
@@ -2034,8 +2128,7 @@ conf_apply(struct conf *oldconf, struct conf *newconf)
 		it++;
 	}
 
-	for (auto it = newconf->conf_luns.begin();
-	     it != newconf->conf_luns.end(); ) {
+	for (auto it = conf_luns.begin(); it != conf_luns.end(); ) {
 		struct lun *newlun = it->second.get();
 
 		auto oldit = oldconf->conf_luns.find(it->first);
@@ -2055,8 +2148,8 @@ conf_apply(struct conf *oldconf, struct conf *newconf)
 		log_debugx("adding lun \"%s\"", newlun->name());
 		if (!newlun->kernel_add()) {
 			log_warnx("failed to add lun \"%s\"", newlun->name());
-			conf_delete_target_luns(newconf, newlun);
-			it = newconf->conf_luns.erase(it);
+			delete_target_luns(newlun);
+			it = conf_luns.erase(it);
 			cumulated_error++;
 		} else
 			it++;
@@ -2065,8 +2158,7 @@ conf_apply(struct conf *oldconf, struct conf *newconf)
 	/*
 	 * Now add new ports or modify existing ones.
 	 */
-	for (auto it = newconf->conf_ports.begin();
-	     it != newconf->conf_ports.end(); ) {
+	for (auto it = conf_ports.begin(); it != conf_ports.end(); ) {
 		const std::string &name = it->first;
 		port *newport = it->second.get();
 
@@ -2096,7 +2188,7 @@ conf_apply(struct conf *oldconf, struct conf *newconf)
 				 * deleting the port.
 				 */
 				newport->clear_references();
-				it = newconf->conf_ports.erase(it);
+				it = conf_ports.erase(it);
 			} else
 				it++;
 		} else {
@@ -2111,7 +2203,7 @@ conf_apply(struct conf *oldconf, struct conf *newconf)
 	/*
 	 * Go through the new portals, opening the sockets as necessary.
 	 */
-	for (auto &kv : newconf->conf_portal_groups) {
+	for (auto &kv : conf_portal_groups) {
 		cumulated_error += kv.second->open_sockets(*oldconf);
 	}
 
@@ -2123,17 +2215,15 @@ conf_apply(struct conf *oldconf, struct conf *newconf)
 	}
 
 	/* (Re-)Register on remaining/new iSNS servers. */
-	for (auto &kv : newconf->conf_isns) {
+	for (auto &kv : conf_isns) {
 		auto it = oldconf->conf_isns.find(kv.first);
 		if (it == oldconf->conf_isns.end())
-			isns_register_targets(newconf, &kv.second, nullptr);
+			isns_register_targets(&kv.second, nullptr);
 		else
*** 617 LINES SKIPPED ***