[PATCH rdma-core 7/9] verbs: Add RDMA_STATIC_PROVIDERS

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Jason Gunthorpe <jgg@xxxxxxxxxxxx>

This macro is to be set by the user to a comma separated list of providers
that should be included in the static link. The special word 'all' will
include every supported provider.

To make this work we list all of the provider libraries in the pkg-config
file, if the macro isn't used then none of them will contribute to the
link, as before.

Signed-off-by: Jason Gunthorpe <jgg@xxxxxxxxxxxx>
---
 CMakeLists.txt                          |  1 +
 buildlib/check-build                    | 34 ++++++++++++++++
 buildlib/rdma_functions.cmake           | 13 ++++--
 buildlib/sanitize_static_lib.py         | 11 ++++-
 libibverbs/CMakeLists.txt               | 35 ++++++++++++----
 libibverbs/all_providers.c              | 53 +++++++++++++++++++++++++
 libibverbs/driver.h                     |  1 +
 libibverbs/man/ibv_get_device_list.3.md | 20 ++++++++++
 libibverbs/static_driver.c              | 52 ++++++++++++++++++++++++
 libibverbs/verbs.h                      | 31 +++++++++++++++
 10 files changed, 239 insertions(+), 12 deletions(-)
 create mode 100644 libibverbs/all_providers.c
 create mode 100644 libibverbs/static_driver.c

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 94f3736b5b3ad6..90ee3fcb4eb59a 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -562,6 +562,7 @@ if (UDEV_FOUND)
 endif()
 add_subdirectory(srp_daemon)
 
+ibverbs_finalize()
 rdma_finalize_libs()
 
 #-------------------------
diff --git a/buildlib/check-build b/buildlib/check-build
index 74e7350a9840c6..4c76814d4f050c 100755
--- a/buildlib/check-build
+++ b/buildlib/check-build
@@ -395,6 +395,13 @@ default {name}""".format(
         opts=" ".join(pipes.quote(I) for I in opts))
 
 
+def get_providers(args):
+    """Return a list of provider names"""
+    return set(
+        I for I in os.listdir(os.path.join(args.SRC, "providers"))
+        if not I.startswith("."))
+
+
 def check_static_lib(args, tmpd, Fninja, static_lib, shared_lib, name):
     syms = get_symbol_names(shared_lib)
     if not syms:
@@ -416,6 +423,32 @@ def check_static_lib(args, tmpd, Fninja, static_lib, shared_lib, name):
                   get_cc_args_from_pkgconfig(args, name, static=False))
 
 
+def check_static_providers(args, tmpd, Fninja):
+    """Test that expected values for RDMA_STATIC_PROVIDERS are accepted and the
+    link works"""
+    cfn = os.path.join(tmpd, "provider-test.c")
+    with open(cfn, "wt") as F:
+        F.write("#include <infiniband/verbs.h>\n")
+        F.write("int main(int argc,const char *argv[]) {\n")
+        F.write('ibv_get_device_list(NULL);\n')
+        F.write("return 0; }\n")
+
+    opts = get_cc_args_from_pkgconfig(
+        args, "ibverbs", static=True)
+
+    providers = get_providers(args)
+    for I in sorted(providers | {
+            "none",
+            "all",
+    }):
+        compile_ninja(args, Fninja, "providers-%s-static-out" % (I), cfn,
+                      ["-DRDMA_STATIC_PROVIDERS=%s" % (I)] + opts)
+
+    compile_ninja(
+        args, Fninja, "providers-static-out", cfn,
+        ["-DRDMA_STATIC_PROVIDERS=%s" % (",".join(providers))] + opts)
+
+
 def test_static_libs(args):
     """Compile then link statically and dynamically a dummy program that touches
     every symbol in the libraries using pkgconfig output to guide the link
@@ -445,6 +478,7 @@ def test_static_libs(args):
         with open(os.path.join(tmpd, "build.ninja"), "wt") as Fninja:
             for I in libs:
                 check_static_lib(args, tmpd, Fninja, I[0], I[1], I[2])
+            check_static_providers(args, tmpd, Fninja)
         subprocess.check_call(["ninja"], cwd=tmpd)
 
 
diff --git a/buildlib/rdma_functions.cmake b/buildlib/rdma_functions.cmake
index 8934a8bb999601..fa3fed3368ee0f 100644
--- a/buildlib/rdma_functions.cmake
+++ b/buildlib/rdma_functions.cmake
@@ -7,6 +7,9 @@
 # Global list of tuples of (SHARED STATIC MAP) library target names
 set(RDMA_STATIC_LIBS "" CACHE INTERNAL "Doc" FORCE)
 
+# Global list of tuples of (PROVIDER_NAME LIB_NAME)
+set(RDMA_PROVIDER_LIST "" CACHE INTERNAL "Doc" FORCE)
+
 set(COMMON_LIBS_PIC ccan_pic rdma_util_pic)
 set(COMMON_LIBS ccan rdma_util)
 
@@ -130,6 +133,9 @@ function(rdma_shared_provider DEST VERSION_SCRIPT SOVERSION VERSION)
   file(MAKE_DIRECTORY "${BUILD_ETC}/libibverbs.d/")
   file(WRITE "${BUILD_ETC}/libibverbs.d/${DEST}.driver" "driver ${BUILD_LIB}/lib${DEST}\n")
 
+  list(APPEND RDMA_PROVIDER_LIST ${DEST} ${DEST})
+  set(RDMA_PROVIDER_LIST "${RDMA_PROVIDER_LIST}" CACHE INTERNAL "")
+
   # Create a static provider library
   if (ENABLE_STATIC)
     add_library(${DEST}-static STATIC ${ARGN})
@@ -173,14 +179,13 @@ function(rdma_provider DEST)
   file(MAKE_DIRECTORY "${BUILD_ETC}/libibverbs.d/")
   file(WRITE "${BUILD_ETC}/libibverbs.d/${DEST}.driver" "driver ${BUILD_LIB}/lib${DEST}\n")
 
+  list(APPEND RDMA_PROVIDER_LIST ${DEST} "${DEST}-rdmav${IBVERBS_PABI_VERSION}")
+  set(RDMA_PROVIDER_LIST "${RDMA_PROVIDER_LIST}" CACHE INTERNAL "")
+
   # Create a static provider library
-  # FIXME: This is probably pointless, the provider library has no symbols so
-  # what good is it? Presumably it should be used with -Wl,--whole-archive,
-  # but we don't have any directions on how to make static linking work..
   if (ENABLE_STATIC)
     add_library(${DEST} STATIC ${ARGN})
     rdma_public_static_lib("${DEST}-rdmav${IBVERBS_PABI_VERSION}" ${DEST} ${BUILDLIB}/provider.map)
-    set_target_properties(${DEST} PROPERTIES OUTPUT_NAME ${DEST})
   endif()
 
   # Create the plugin shared library
diff --git a/buildlib/sanitize_static_lib.py b/buildlib/sanitize_static_lib.py
index 86027ccc817457..55b69261992595 100644
--- a/buildlib/sanitize_static_lib.py
+++ b/buildlib/sanitize_static_lib.py
@@ -163,7 +163,8 @@ class Lib(object):
             for ln in syms.decode().splitlines():
                 ln = ln.split()
                 if ln[0].isupper():
-                    self.needed_syms.add(ln[1])
+                    if not ln[1].startswith("verbs_provider_"):
+                        self.needed_syms.add(ln[1])
 
     def rename_syms(self, rename_fn):
         """Invoke objcopy on all the objects to rename their symbols"""
@@ -254,6 +255,14 @@ with TemporaryDirectory() as tmpdir:
         all_syms.update(I.syms)
     compute_graph(all_libs)
 
+    # To support the ibv_static_providers() machinery these are made global
+    # too, even though they are not in map files. We only want to expose them
+    # for the static linking case.
+    global_syms.add("ibv_static_providers")
+    for I in all_syms:
+        if I.startswith("verbs_provider_"):
+            global_syms.add(I)
+
     # Generate a redefine file for objcopy that will sanitize the internal names
     prefix = re.sub(r"\W", "_", args.version)
     redefine_fn = os.path.join(tmpdir, "redefine")
diff --git a/libibverbs/CMakeLists.txt b/libibverbs/CMakeLists.txt
index 3e60c808636847..ddf5995e7fae31 100644
--- a/libibverbs/CMakeLists.txt
+++ b/libibverbs/CMakeLists.txt
@@ -28,6 +28,7 @@ configure_file("libibverbs.map.in"
 rdma_library(ibverbs "${CMAKE_CURRENT_BINARY_DIR}/libibverbs.map"
   # See Documentation/versioning.md
   1 1.5.${PACKAGE_VERSION}
+  all_providers.c
   cmd.c
   cmd_counters.c
   cmd_cq.c
@@ -44,6 +45,7 @@ rdma_library(ibverbs "${CMAKE_CURRENT_BINARY_DIR}/libibverbs.map"
   marshall.c
   memory.c
   ${NEIGH}
+  static_driver.c
   sysfs.c
   verbs.c
   )
@@ -54,11 +56,30 @@ target_link_libraries(ibverbs LINK_PRIVATE
   kern-abi
   )
 
-if (ENABLE_STATIC)
-  if (NOT NL_KIND EQUAL 0)
-    set(REQUIRES "libnl-3.0, libnl-route-3.0")
+function(ibverbs_finalize)
+  if (ENABLE_STATIC)
+    # In static mode the .pc file lists all of the providers for static
+    # linking. The user should set RDMA_STATIC_PROVIDERS to select which ones
+    # to include.
+    list(LENGTH RDMA_PROVIDER_LIST LEN)
+    math(EXPR LEN ${LEN}-1)
+    foreach(I RANGE 0 ${LEN} 2)
+      list(GET RDMA_PROVIDER_LIST ${I} PROVIDER_NAME)
+      math(EXPR I ${I}+1)
+      list(GET RDMA_PROVIDER_LIST ${I} LIB_NAME)
+      math(EXPR I ${I}+1)
+
+      set(PROVIDER_LIBS "${PROVIDER_LIBS} -l${LIB_NAME}")
+      set(FOR_EACH_PROVIDER "${FOR_EACH_PROVIDER} FOR_PROVIDER(${PROVIDER_NAME})")
+    endforeach()
+
+    if (NOT NL_KIND EQUAL 0)
+      set(REQUIRES "libnl-3.0, libnl-route-3.0")
+    endif()
+    rdma_pkg_config("ibverbs" "${REQUIRES}" "${PROVIDER_LIBS} -libverbs ${CMAKE_THREAD_LIBS_INIT}")
+
+    file(WRITE ${BUILD_INCLUDE}/infiniband/all_providers.h "#define FOR_EACH_PROVIDER() ${FOR_EACH_PROVIDER}")
+  else()
+    rdma_pkg_config("ibverbs" "" "${CMAKE_THREAD_LIBS_INIT}")
   endif()
-  rdma_pkg_config("ibverbs" "${REQUIRES}" "${CMAKE_THREAD_LIBS_INIT}")
-else()
-  rdma_pkg_config("ibverbs" "" "${CMAKE_THREAD_LIBS_INIT}")
-endif()
+endfunction()
diff --git a/libibverbs/all_providers.c b/libibverbs/all_providers.c
new file mode 100644
index 00000000000000..78adac9c31eaf6
--- /dev/null
+++ b/libibverbs/all_providers.c
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2018 Mellanox Technologies, Ltd.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#ifdef _STATIC_LIBRARY_BUILD_
+#define RDMA_STATIC_PROVIDERS none
+#include <infiniband/verbs.h>
+#include <infiniband/driver.h>
+#include <infiniband/all_providers.h>
+
+/* When static linking this object will be included in the final link only if
+ * something refers to the 'verbs_provider_all' symbol. It in turn brings all
+ * the providers into the link as well. Otherwise the static linker will not
+ * include this. It is important this is the only thing in this file.
+ */
+#define FOR_PROVIDER(x) &verbs_provider_ ## x,
+static const struct verbs_device_ops *all_providers[] = {
+	FOR_EACH_PROVIDER()
+	NULL
+};
+
+const struct verbs_device_ops verbs_provider_all = {
+	.static_providers = all_providers,
+};
+
+#endif
diff --git a/libibverbs/driver.h b/libibverbs/driver.h
index 3e8c2ba07c95db..adf46c39e87112 100644
--- a/libibverbs/driver.h
+++ b/libibverbs/driver.h
@@ -183,6 +183,7 @@ struct verbs_device_ops {
 	int match_min_abi_version;
 	int match_max_abi_version;
 	const struct verbs_match_ent *match_table;
+	const struct verbs_device_ops **static_providers;
 
 	bool (*match_device)(struct verbs_sysfs_dev *sysfs_dev);
 
diff --git a/libibverbs/man/ibv_get_device_list.3.md b/libibverbs/man/ibv_get_device_list.3.md
index 3f2ba8b8f5577e..3d222f668c678a 100644
--- a/libibverbs/man/ibv_get_device_list.3.md
+++ b/libibverbs/man/ibv_get_device_list.3.md
@@ -63,6 +63,26 @@ Setting the environment variable **IBV_SHOW_WARNINGS** will cause warnings to
 be emitted to stderr if a kernel verbs device is discovered, but no
 corresponding userspace driver can be found for it.
 
+# STATIC LINKING
+
+If **libibverbs** is statically linked to the application then all provider
+drivers must also be statically linked. The library will not load dynamic
+providers when static linking is used.
+
+To link the providers set the **RDMA_STATIC_PROVIDERS** define to the comma
+separated list of desired providers when compiling the application. The
+special keyword 'all' will statically link all supported **libibverbs**
+providers.
+
+This is intended to be used along with **pkg-config(1)** to setup the proper
+flags for **libibverbs** linking.
+
+If this is not done then **ibv_get_device_list** will always return an empty
+list.
+
+Using only dynamic linking for **libibverbs** applications is strongly
+recommended.
+
 # SEE ALSO
 
 **ibv_fork_init**(3),
diff --git a/libibverbs/static_driver.c b/libibverbs/static_driver.c
new file mode 100644
index 00000000000000..b6ee32d9280191
--- /dev/null
+++ b/libibverbs/static_driver.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2018 Mellanox Technologies, Ltd.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#ifdef _STATIC_LIBRARY_BUILD_
+#define RDMA_STATIC_PROVIDERS none
+#include <infiniband/verbs.h>
+#include <infiniband/driver.h>
+
+const struct verbs_device_ops verbs_provider_none;
+
+void ibv_static_providers(void *unused, ...)
+{
+	/*
+	 * We do not need to do anything with the VA_ARGs since we continue to
+	 * rely on the constructor attribute and simply referencing the
+	 * verbs_provider_X symbol will be enough to trigger the constructor.
+	 *
+	 * This would need to actually check and do the registration for
+	 * specialty cases like LTO or section-gc which may not work with the
+	 * constructor scheme.
+	 */
+}
+
+#endif
diff --git a/libibverbs/verbs.h b/libibverbs/verbs.h
index e5327eee48564d..93e0430f4b7678 100644
--- a/libibverbs/verbs.h
+++ b/libibverbs/verbs.h
@@ -1880,7 +1880,27 @@ static inline struct verbs_context *verbs_get_ctx(struct ibv_context *ctx)
  */
 struct ibv_device **ibv_get_device_list(int *num_devices);
 
+/*
+ * When statically linking the user can set RDMA_STATIC_PROVIDERS to a comma
+ * separated list of provider names to include in the static link, and this
+ * machinery will cause those providers to be included statically.
+ *
+ * Linking will fail if this is set for dynamic linking.
+ */
 #ifdef RDMA_STATIC_PROVIDERS
+#define _RDMA_STATIC_PREFIX_(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11,     \
+			     _12, _13, _14, _15, ...)                          \
+	&verbs_provider_##_1, &verbs_provider_##_2, &verbs_provider_##_3,      \
+		&verbs_provider_##_4, &verbs_provider_##_5,                    \
+		&verbs_provider_##_6, &verbs_provider_##_7,                    \
+		&verbs_provider_##_8, &verbs_provider_##_9,                    \
+		&verbs_provider_##_10, &verbs_provider_##_11,                  \
+		&verbs_provider_##_12, &verbs_provider_##_13,                  \
+		&verbs_provider_##_14, &verbs_provider_##_15
+#define _RDMA_STATIC_PREFIX(arg)                                               \
+	_RDMA_STATIC_PREFIX_(arg, none, none, none, none, none, none, none,    \
+			     none, none, none, none, none, none, none)
+
 struct verbs_devices_ops;
 extern const struct verbs_device_ops verbs_provider_bnxt_re;
 extern const struct verbs_device_ops verbs_provider_cxgb3;
@@ -1897,6 +1917,17 @@ extern const struct verbs_device_ops verbs_provider_ocrdma;
 extern const struct verbs_device_ops verbs_provider_qedr;
 extern const struct verbs_device_ops verbs_provider_rxe;
 extern const struct verbs_device_ops verbs_provider_vmw_pvrdma;
+extern const struct verbs_device_ops verbs_provider_all;
+extern const struct verbs_device_ops verbs_provider_none;
+void ibv_static_providers(void *unused, ...);
+
+static inline struct ibv_device **__ibv_get_device_list(int *num_devices)
+{
+	ibv_static_providers(NULL, _RDMA_STATIC_PREFIX(RDMA_STATIC_PROVIDERS),
+			     NULL);
+	return ibv_get_device_list(num_devices);
+}
+#define ibv_get_device_list(num_devices) __ibv_get_device_list(num_devices)
 #endif
 
 /**
-- 
2.19.1




[Index of Archives]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Photo]     [Yosemite News]     [Yosemite Photos]     [Linux Kernel]     [Linux SCSI]     [XFree86]

  Powered by Linux