Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 6 Dec 2018 22:58:26 +0000 (UTC)
From:      Warner Losh <imp@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r341657 - in head: etc/mtree sbin/nvmecontrol share/man/man7
Message-ID:  <201812062258.wB6MwQKb026274@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: imp
Date: Thu Dec  6 22:58:26 2018
New Revision: 341657
URL: https://svnweb.freebsd.org/changeset/base/341657

Log:
  Dynamically load .so modules to expand functionality
  
  o Dynamically load all the .so files found in /libexec/nvmecontrol and
    /usr/local/libexec/nvmecontrol.
  o Link nvmecontrol -rdynamic so that its symbols are visible to the
    libraries we load.
  o Create concatinated linker sets that we dynamically expand.
  o Add the linked-in top and logpage linker sets to the mirrors for them
    and add those sets to the mirrors when we load a new .so.
  o Add some macros to help hide the names of the linker sets.
  o Update the man page.
  
  Sponsored by: Netflix
  Differential Revision: https://reviews.freebsd.org/D18455
  
  fold

Modified:
  head/etc/mtree/BSD.root.dist
  head/sbin/nvmecontrol/Makefile
  head/sbin/nvmecontrol/logpage.c
  head/sbin/nvmecontrol/ns.c
  head/sbin/nvmecontrol/nvmecontrol.8
  head/sbin/nvmecontrol/nvmecontrol.c
  head/sbin/nvmecontrol/nvmecontrol.h
  head/sbin/nvmecontrol/wdc.c
  head/share/man/man7/hier.7

Modified: head/etc/mtree/BSD.root.dist
==============================================================================
--- head/etc/mtree/BSD.root.dist	Thu Dec  6 22:35:07 2018	(r341656)
+++ head/etc/mtree/BSD.root.dist	Thu Dec  6 22:58:26 2018	(r341657)
@@ -88,6 +88,8 @@
         ..
         geom
         ..
+        nvmecontrol
+        ..
     ..
     libexec
         resolvconf

Modified: head/sbin/nvmecontrol/Makefile
==============================================================================
--- head/sbin/nvmecontrol/Makefile	Thu Dec  6 22:35:07 2018	(r341656)
+++ head/sbin/nvmecontrol/Makefile	Thu Dec  6 22:58:26 2018	(r341657)
@@ -6,6 +6,7 @@ SRCS=	nvmecontrol.c devlist.c firmware.c format.c iden
 	perftest.c reset.c ns.c nvme_util.c power.c nc_util.c
 SRCS+=	wdc.c intel.c
 MAN=	nvmecontrol.8
+LDFLAGS+= -rdynamic
 
 .PATH:	${SRCTOP}/sys/dev/nvme
 

Modified: head/sbin/nvmecontrol/logpage.c
==============================================================================
--- head/sbin/nvmecontrol/logpage.c	Thu Dec  6 22:35:07 2018	(r341656)
+++ head/sbin/nvmecontrol/logpage.c	Thu Dec  6 22:58:26 2018	(r341657)
@@ -48,13 +48,13 @@ __FBSDID("$FreeBSD$");
 
 #include "nvmecontrol.h"
 
-SET_DECLARE(logpage, struct logpage_function);
-
 #define LOGPAGE_USAGE							       \
 	"logpage <-p page_id> [-b] [-v vendor] [-x] <controller id|namespace id>\n"  \
 
 #define MAX_FW_SLOTS	(7)
 
+SET_CONCAT_DEF(logpage, struct logpage_function);
+
 const char *
 kv_lookup(const struct kv_name *kv, size_t kv_count, uint32_t key)
 {
@@ -332,7 +332,7 @@ logpage_help(void)
 	fprintf(stderr, "\n");
 	fprintf(stderr, "%-8s %-10s %s\n", "Page", "Vendor","Page Name");
 	fprintf(stderr, "-------- ---------- ----------\n");
-	for (f = SET_BEGIN(logpage); f < SET_LIMIT(logpage); f++) {
+	for (f = logpage_begin(); f < logpage_limit(); f++) {
 		v = (*f)->vendor == NULL ? "-" : (*f)->vendor;
 		fprintf(stderr, "0x%02x     %-10s %s\n", (*f)->log_page, v, (*f)->name);
 	}
@@ -438,7 +438,7 @@ logpage(struct nvme_function *nf, int argc, char *argv
 		 * the page is vendor specific, don't match the print function
 		 * unless the vendors match.
 		 */
-		for (f = SET_BEGIN(logpage); f < SET_LIMIT(logpage); f++) {
+		for (f = logpage_begin(); f < logpage_limit(); f++) {
 			if ((*f)->vendor != NULL && vendor != NULL &&
 			    strcmp((*f)->vendor, vendor) != 0)
 				continue;

Modified: head/sbin/nvmecontrol/ns.c
==============================================================================
--- head/sbin/nvmecontrol/ns.c	Thu Dec  6 22:35:07 2018	(r341656)
+++ head/sbin/nvmecontrol/ns.c	Thu Dec  6 22:58:26 2018	(r341657)
@@ -41,7 +41,7 @@ __FBSDID("$FreeBSD$");
 
 #include "nvmecontrol.h"
 
-SET_DECLARE(ns, struct nvme_function);
+NVME_CMD_DECLARE(ns, struct nvme_function);
 
 #define NS_USAGE							\
 	"ns (create|delete|attach|detach)\n"

Modified: head/sbin/nvmecontrol/nvmecontrol.8
==============================================================================
--- head/sbin/nvmecontrol/nvmecontrol.8	Thu Dec  6 22:35:07 2018	(r341656)
+++ head/sbin/nvmecontrol/nvmecontrol.8	Thu Dec  6 22:58:26 2018	(r341657)
@@ -34,7 +34,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd March 12, 2018
+.Dd December 7, 2018
 .Dt NVMECONTROL 8
 .Os
 .Sh NAME
@@ -230,6 +230,19 @@ Set the current power mode.
 .Dl nvmecontrol power nvme0
 .Pp
 Get the current power mode.
+.Sh DYNAMIC LOADING
+The directories
+.Pa /libexec/nvmecontrol
+and
+.Pa /usr/local/libexec/nvmecontrol
+are scanned for any .so files.
+These files are loaded.
+The members of the
+.Va top
+linker set are added to the top-level commands.
+The members of the
+.Va logpage
+linker set are added to the logpage parsers.
 .Sh HISTORY
 The
 .Nm

Modified: head/sbin/nvmecontrol/nvmecontrol.c
==============================================================================
--- head/sbin/nvmecontrol/nvmecontrol.c	Thu Dec  6 22:35:07 2018	(r341656)
+++ head/sbin/nvmecontrol/nvmecontrol.c	Thu Dec  6 22:58:26 2018	(r341657)
@@ -34,6 +34,8 @@ __FBSDID("$FreeBSD$");
 #include <sys/stat.h>
 
 #include <ctype.h>
+#include <dlfcn.h>
+#include <dirent.h>
 #include <err.h>
 #include <errno.h>
 #include <fcntl.h>
@@ -47,7 +49,7 @@ __FBSDID("$FreeBSD$");
 
 #include "nvmecontrol.h"
 
-SET_DECLARE(top, struct nvme_function);
+SET_CONCAT_DEF(top, struct nvme_function);
 
 static void
 print_usage(const struct nvme_function *f)
@@ -116,6 +118,32 @@ dispatch_set(int argc, char *argv[], struct nvme_funct
 	gen_usage_set(tbl, tbl_limit);
 }
 
+void
+set_concat_add(struct set_concat *m, void *b, void *e)
+{
+	void **bp, **ep;
+	int add_n, cur_n;
+
+	if (b == NULL)
+		return;
+	/*
+	 * Args are really pointers to arrays of pointers, but C's
+	 * casting rules kinda suck since you can't directly cast
+	 * struct foo ** to a void **.
+	 */
+	bp = (void **)b;
+	ep = (void **)e;
+	add_n = ep - bp;
+	cur_n = 0;
+	if (m->begin != NULL)
+		cur_n = m->limit - m->begin;
+	m->begin = reallocarray(m->begin, cur_n + add_n, sizeof(void *));
+	if (m->begin == NULL)
+		err(1, "expanding concat set");
+	memcpy(m->begin + cur_n, bp, add_n * sizeof(void *));
+	m->limit = m->begin + cur_n + add_n;
+}
+
 static void
 print_bytes(void *data, uint32_t length)
 {
@@ -260,14 +288,64 @@ parse_ns_str(const char *ns_str, char *ctrlr_str, uint
 	snprintf(ctrlr_str, nsloc - ns_str + 1, "%s", ns_str);
 }
 
+/*
+ * Loads all the .so's from the specified directory.
+ */
+static void
+load_dir(const char *dir)
+{
+	DIR *d;
+	struct dirent *dent;
+	char *path = NULL;
+	void *h;
+
+	d = opendir(dir);
+	if (d == NULL)
+		return;
+	for (dent = readdir(d); dent != NULL; dent = readdir(d)) {
+		if (strcmp(".so", dent->d_name + dent->d_namlen - 3) != 0)
+			continue;
+		asprintf(&path, "%s/%s", dir, dent->d_name);
+		if (path == NULL)
+			err(1, "Can't malloc for path, giving up.");
+		if ((h = dlopen(path, RTLD_NOW | RTLD_GLOBAL)) == NULL)
+			warnx("Can't load %s: %s", path, dlerror());
+		else {
+			/*
+			 * Add in the top (for cli commands) and logpage (for
+			 * logpage parsing) linker sets. We have to do this by
+			 * hand because linker sets aren't automatically merged.
+			 */
+			void *begin, *limit;
+			begin = dlsym(h, "__start_set_top");
+			limit = dlsym(h, "__stop_set_top");
+			if (begin)
+				add_to_top(begin, limit);
+			begin = dlsym(h, "__start_set_logpage");
+			limit = dlsym(h, "__stop_set_logpage");
+			if (begin)
+				add_to_logpage(begin, limit);
+		}
+		free(path);
+		path = NULL;
+	}
+	closedir(d);
+}
+
 int
 main(int argc, char *argv[])
 {
 
+	add_to_top(NVME_CMD_BEGIN(top), NVME_CMD_LIMIT(top));
+	add_to_logpage(NVME_LOGPAGE_BEGIN, NVME_LOGPAGE_LIMIT);
+
+	load_dir("/lib/nvmecontrol");
+	load_dir("/usr/local/lib/nvmecontrol");
+
 	if (argc < 2)
-		gen_usage_set(SET_BEGIN(top), SET_LIMIT(top));
+		gen_usage_set(top_begin(), top_limit());
 
-	DISPATCH(argc, argv, top);
+	dispatch_set(argc, argv, top_begin(), top_limit());
 
 	return (0);
 }

Modified: head/sbin/nvmecontrol/nvmecontrol.h
==============================================================================
--- head/sbin/nvmecontrol/nvmecontrol.h	Thu Dec  6 22:35:07 2018	(r341656)
+++ head/sbin/nvmecontrol/nvmecontrol.h	Thu Dec  6 22:58:26 2018	(r341657)
@@ -43,11 +43,15 @@ struct nvme_function {
 	const char	*usage;
 };
 
-#define NVME_CMDSET(set, sym)	DATA_SET(set, sym)
+#define NVME_SETNAME(set)	set
+#define	NVME_CMDSET(set, sym)	DATA_SET(NVME_SETNAME(set), sym)
 #define NVME_COMMAND(set, nam, function, usage_str)			\
 	static struct nvme_function function ## _nvme_cmd =		\
 	{ .name = #nam, .fn = function, .usage = usage_str };		\
 	NVME_CMDSET(set, function ## _nvme_cmd)
+#define NVME_CMD_BEGIN(set)	SET_BEGIN(NVME_SETNAME(set))
+#define NVME_CMD_LIMIT(set)	SET_LIMIT(NVME_SETNAME(set))
+#define NVME_CMD_DECLARE(set, t) SET_DECLARE(NVME_SETNAME(set), t)
 
 typedef void (*print_fn_t)(const struct nvme_controller_data *cdata, void *buf, uint32_t size);
 
@@ -59,7 +63,8 @@ struct logpage_function {
 	size_t		size;
 };
 
-#define NVME_LOGPAGESET(sym)		DATA_SET(logpage, sym)
+
+#define NVME_LOGPAGESET(sym)		DATA_SET(NVME_SETNAME(logpage), sym)
 #define NVME_LOGPAGE(unique, lp, vend, nam, fn, sz)			\
 	static struct logpage_function unique ## _lpf = {		\
 		.log_page = lp,						\
@@ -69,6 +74,9 @@ struct logpage_function {
 		.size = sz,						\
 	} ;								\
 	NVME_LOGPAGESET(unique ## _lpf)
+#define NVME_LOGPAGE_BEGIN	SET_BEGIN(NVME_SETNAME(logpage))
+#define NVME_LOGPAGE_LIMIT	SET_LIMIT(NVME_SETNAME(logpage))
+#define NVME_LOGPAGE_DECLARE(t)		SET_DECLARE(NVME_SETNAME(logpage), t)
 
 #define DEFAULT_SIZE	(4096)
 struct kv_name {
@@ -78,6 +86,27 @@ struct kv_name {
 
 const char *kv_lookup(const struct kv_name *kv, size_t kv_count, uint32_t key);
 
+NVME_CMD_DECLARE(top, struct nvme_function);
+NVME_LOGPAGE_DECLARE(struct logpage_function);
+
+struct set_concat {
+	void **begin;
+	void **limit;
+};
+void set_concat_add(struct set_concat *m, void *begin, void *end);
+#define SET_CONCAT_DEF(set, t) 							\
+static struct set_concat set ## _concat;					\
+static inline t **set ## _begin() { return ((t **)set ## _concat.begin); }	\
+static inline t **set ## _limit() { return ((t **)set ## _concat.limit); }	\
+void add_to_ ## set(t **b, t **e)						\
+{										\
+	set_concat_add(&set ## _concat, b, e);					\
+}
+#define SET_CONCAT_DECL(set, t)							\
+	void add_to_ ## set(t **b, t **e)
+SET_CONCAT_DECL(top, struct nvme_function);
+SET_CONCAT_DECL(logpage, struct logpage_function);
+
 #define NVME_CTRLR_PREFIX	"nvme"
 #define NVME_NS_PREFIX		"ns"
 
@@ -95,7 +124,7 @@ void dispatch_set(int argc, char *argv[], struct nvme_
     struct nvme_function **tbl_limit);
 
 #define DISPATCH(argc, argv, set)	\
-	dispatch_set(argc, argv, SET_BEGIN(set), SET_LIMIT(set))
+	dispatch_set(argc, argv, NVME_CMD_BEGIN(set), NVME_CMD_LIMIT(set))
 
 /* Utility Routines */
 /*

Modified: head/sbin/nvmecontrol/wdc.c
==============================================================================
--- head/sbin/nvmecontrol/wdc.c	Thu Dec  6 22:35:07 2018	(r341656)
+++ head/sbin/nvmecontrol/wdc.c	Thu Dec  6 22:58:26 2018	(r341657)
@@ -45,7 +45,7 @@ __FBSDID("$FreeBSD$");
 #define WDC_USAGE							       \
 	"wdc (cap-diag)\n"
 
-SET_DECLARE(wdc, struct nvme_function);
+NVME_CMD_DECLARE(wdc, struct nvme_function);
 
 #define WDC_NVME_TOC_SIZE	8
 

Modified: head/share/man/man7/hier.7
==============================================================================
--- head/share/man/man7/hier.7	Thu Dec  6 22:35:07 2018	(r341656)
+++ head/share/man/man7/hier.7	Thu Dec  6 22:58:26 2018	(r341657)
@@ -152,6 +152,10 @@ Capsicum support libraries
 class-specific libraries for the
 .Xr geom 8
 utility
+.It Pa nvmecontrol/
+vendor-specific libraries to extend the
+.Xr nvmecontrol 8
+utility
 .El
 .It Pa /libexec/
 critical system utilities needed for binaries in



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201812062258.wB6MwQKb026274>