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>
This commit is contained in:
Tomas Bzatek
2024-12-02 14:52:54 +01:00
committed by Beniamino Galvani
parent 1cb0635d08
commit 8b7c6f8b90
4 changed files with 57 additions and 20 deletions

View File

@@ -282,3 +282,6 @@
/* Define if NBFT support is enabled */ /* Define if NBFT support is enabled */
#mesondefine WITH_NBFT #mesondefine WITH_NBFT
/* Define to 1 if dlvsym() is available */
#mesondefine HAVE_DLVSYM

View File

@@ -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_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_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 # types
config_h.set('SIZEOF_PID_T', cc.sizeof('pid_t', prefix : '#include <sys/types.h>')) 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>')) config_h.set('SIZEOF_UID_T', cc.sizeof('uid_t', prefix : '#include <sys/types.h>'))

View File

@@ -1,15 +1,5 @@
# SPDX-License-Identifier: LGPL-2.1-or-later # 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( libnmi_core = static_library(
'nmi-core', 'nmi-core',
sources: files( sources: files(
@@ -22,7 +12,9 @@ libnmi_core = static_library(
src_inc, src_inc,
top_inc, top_inc,
], ],
dependencies: libnmi_deps, dependencies: [
libnm_core_public_dep,
],
) )
executable( executable(
@@ -32,7 +24,9 @@ executable(
src_inc, src_inc,
top_inc, top_inc,
], ],
dependencies: libnmi_deps, dependencies: [
libnm_core_public_dep,
],
link_with: [ link_with: [
libnmi_core, libnmi_core,
libnm_core_aux_intern, libnm_core_aux_intern,

View File

@@ -10,6 +10,7 @@
#if WITH_NBFT #if WITH_NBFT
#include <libnvme.h> #include <libnvme.h>
#include <dlfcn.h>
#include "libnm-log-core/nm-logging.h" #include "libnm-log-core/nm-logging.h"
#include "libnm-core-intern/nm-core-internal.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)); && 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 * static NMConnection *
parse_hfi(struct nbft_info_hfi *hfi, int iface_idx, char **hostname) 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 ** NMConnection **
nmi_nbft_reader_parse(const char *sysfs_dir, char **hostname) nmi_nbft_reader_parse(const char *sysfs_dir, char **hostname)
{ {
GPtrArray *a; nm_auto_unref_ptrarray GPtrArray *a = NULL;
gs_free char *path = NULL; gs_free char *path = NULL;
gs_free_error GError *error = NULL; gs_free_error GError *error = NULL;
GDir *dir; GDir *dir;
const char *entry_name; void *libnvme_handle = NULL;
int idx = 1; const char *entry_name;
int idx = 1;
g_return_val_if_fail(sysfs_dir != NULL, NULL); g_return_val_if_fail(sysfs_dir != NULL, NULL);
path = g_build_filename(sysfs_dir, "firmware", "acpi", "tables", 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")) if (!g_str_has_prefix(entry_name, "NBFT"))
continue; 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); 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) { if (ret) {
_LOGW(LOGD_CORE, "Error parsing NBFT table %s: %m", entry_path); _LOGW(LOGD_CORE, "Error parsing NBFT table %s: %m", entry_path);
continue; continue;
@@ -274,10 +310,11 @@ nmi_nbft_reader_parse(const char *sysfs_dir, char **hostname)
g_ptr_array_add(a, connection); g_ptr_array_add(a, connection);
} }
nvme_nbft_free(nbft); _nvme_nbft_free(nbft);
} }
g_dir_close(dir); g_dir_close(dir);
dlclose(libnvme_handle);
g_ptr_array_add(a, NULL); /* trailing NULL-delimiter */ g_ptr_array_add(a, NULL); /* trailing NULL-delimiter */
return (NMConnection **) g_ptr_array_free(a, FALSE); return (NMConnection **) g_ptr_array_free(a, FALSE);
} }