File 0101-initrd-avoid-dynamic-linking-of-libnvme-use-dlopen-i.patch of Package NetworkManager

From 4a1e9564639a1351617ec454b216379ec90d08e0 Mon Sep 17 00:00:00 2001
From: Tomas Bzatek <tbzatek@redhat.com>
Date: Mon, 2 Dec 2024 14:52:54 +0100
Subject: [PATCH 101/106] initrd: avoid dynamic linking of libnvme, use
 dlopen() instead

As suggested during the review process, NBFT is niche and most users
won't need it. So keep the initrd generator light and only open
libnvme when any NBFT table is found.

In a typical dracut host-only scenario the nbft dracut module will
be pulled in only when NBFT is present in the system, packing in
nvme-cli and libnvme in the initramfs image.

Signed-off-by: Tomas Bzatek <tbzatek@redhat.com>
---
 config.h.meson                            |  3 ++
 meson.build                               |  3 ++
 src/nm-initrd-generator/meson.build       | 18 +++-----
 src/nm-initrd-generator/nmi-nbft-reader.c | 53 +++++++++++++++++++----
 4 files changed, 57 insertions(+), 20 deletions(-)

diff --git a/config.h.meson b/config.h.meson
index 6aaf798..cce0130 100644
--- a/config.h.meson
+++ b/config.h.meson
@@ -279,3 +279,6 @@
 
 /* Define if NBFT support is enabled */
 #mesondefine WITH_NBFT
+
+/* Define to 1 if dlvsym() is available */
+#mesondefine HAVE_DLVSYM
diff --git a/meson.build b/meson.build
index 23257c1..5dc025c 100644
--- a/meson.build
+++ b/meson.build
@@ -137,6 +137,9 @@ config_h.set10('HAVE_DECL_REALLOCARRAY', cc.has_function('reallocarray', prefix:
 config_h.set10('HAVE_DECL_EXPLICIT_BZERO', cc.has_function('explicit_bzero', prefix: '#include <string.h>'))
 config_h.set10('HAVE_DECL_MEMFD_CREATE', cc.has_function('memfd_create', prefix: '#include <sys/mman.h>'))
 
+config_h.set10('HAVE_DLVSYM', cc.has_function('dlvsym', prefix: '''#define _GNU_SOURCE
+                                                                   #include <dlfcn.h>'''))
+
 # types
 config_h.set('SIZEOF_PID_T', cc.sizeof('pid_t', prefix : '#include <sys/types.h>'))
 config_h.set('SIZEOF_UID_T', cc.sizeof('uid_t', prefix : '#include <sys/types.h>'))
diff --git a/src/nm-initrd-generator/meson.build b/src/nm-initrd-generator/meson.build
index 0e9689f..6b02e06 100644
--- a/src/nm-initrd-generator/meson.build
+++ b/src/nm-initrd-generator/meson.build
@@ -1,15 +1,5 @@
 # SPDX-License-Identifier: LGPL-2.1-or-later
 
-libnmi_deps = [
-    libnm_core_public_dep,
-]
-
-if enable_nbft
-    libnmi_deps += [
-        libnvme_dep
-    ]
-endif
-
 libnmi_core = static_library(
   'nmi-core',
   sources: files(
@@ -22,7 +12,9 @@ libnmi_core = static_library(
     src_inc,
     top_inc,
   ],
-  dependencies: libnmi_deps,
+  dependencies: [
+    libnm_core_public_dep,
+  ],
 )
 
 executable(
@@ -32,7 +24,9 @@ executable(
     src_inc,
     top_inc,
   ],
-  dependencies: libnmi_deps,
+  dependencies: [
+    libnm_core_public_dep,
+  ],
   link_with: [
     libnmi_core,
     libnm_core_aux_intern,
diff --git a/src/nm-initrd-generator/nmi-nbft-reader.c b/src/nm-initrd-generator/nmi-nbft-reader.c
index 782c6ac..09e5eb1 100644
--- a/src/nm-initrd-generator/nmi-nbft-reader.c
+++ b/src/nm-initrd-generator/nmi-nbft-reader.c
@@ -10,6 +10,7 @@
 #if WITH_NBFT
 
 #include <libnvme.h>
+#include <dlfcn.h>
 
 #include "libnm-log-core/nm-logging.h"
 #include "libnm-core-intern/nm-core-internal.h"
@@ -32,6 +33,34 @@ is_valid_addr(int family, const char *addr)
             && nm_utils_ipaddr_valid(family, addr));
 }
 
+static int (*_nvme_nbft_read)(struct nbft_info **nbft, const char *filename);
+static void (*_nvme_nbft_free)(struct nbft_info *nbft);
+
+static void *
+load_libnvme(void)
+{
+    void *handle;
+
+    handle = dlopen("libnvme.so.1", RTLD_LAZY);
+    if (!handle)
+        return NULL;
+
+#if HAVE_DLVSYM
+    _nvme_nbft_read = dlvsym(handle, "nvme_nbft_read", "LIBNVME_1_5");
+    _nvme_nbft_free = dlvsym(handle, "nvme_nbft_free", "LIBNVME_1_5");
+#else
+    /* no dlvsym() in musl */
+    _nvme_nbft_read = dlsym(handle, "nvme_nbft_read");
+    _nvme_nbft_free = dlsym(handle, "nvme_nbft_free");
+#endif
+
+    if (!_nvme_nbft_read || !_nvme_nbft_free) {
+        dlclose(handle);
+        return NULL;
+    }
+    return handle;
+}
+
 static NMConnection *
 parse_hfi(struct nbft_info_hfi *hfi, int iface_idx, char **hostname)
 {
@@ -225,12 +254,13 @@ parse_hfi(struct nbft_info_hfi *hfi, int iface_idx, char **hostname)
 NMConnection **
 nmi_nbft_reader_parse(const char *sysfs_dir, char **hostname)
 {
-    GPtrArray            *a;
-    gs_free char         *path  = NULL;
-    gs_free_error GError *error = NULL;
-    GDir                 *dir;
-    const char           *entry_name;
-    int                   idx = 1;
+    nm_auto_unref_ptrarray GPtrArray *a     = NULL;
+    gs_free char                     *path  = NULL;
+    gs_free_error GError             *error = NULL;
+    GDir                             *dir;
+    void                             *libnvme_handle = NULL;
+    const char                       *entry_name;
+    int                               idx = 1;
 
     g_return_val_if_fail(sysfs_dir != NULL, NULL);
     path = g_build_filename(sysfs_dir, "firmware", "acpi", "tables", NULL);
@@ -250,8 +280,14 @@ nmi_nbft_reader_parse(const char *sysfs_dir, char **hostname)
         if (!g_str_has_prefix(entry_name, "NBFT"))
             continue;
 
+        /* attempt to load libnvme only on the first table match, saving some I/O */
+        if (!libnvme_handle && !(libnvme_handle = load_libnvme())) {
+            g_dir_close(dir);
+            return NULL;
+        }
+
         entry_path = g_build_filename(path, entry_name, NULL);
-        ret        = nvme_nbft_read(&nbft, entry_path);
+        ret        = _nvme_nbft_read(&nbft, entry_path);
         if (ret) {
             _LOGW(LOGD_CORE, "Error parsing NBFT table %s: %m", entry_path);
             continue;
@@ -274,10 +310,11 @@ nmi_nbft_reader_parse(const char *sysfs_dir, char **hostname)
                 g_ptr_array_add(a, connection);
         }
 
-        nvme_nbft_free(nbft);
+        _nvme_nbft_free(nbft);
     }
 
     g_dir_close(dir);
+    dlclose(libnvme_handle);
     g_ptr_array_add(a, NULL); /* trailing NULL-delimiter */
     return (NMConnection **) g_ptr_array_free(a, FALSE);
 }
-- 
2.49.0

openSUSE Build Service is sponsored by