diff --git a/libnvme/src/nvme/private.h b/libnvme/src/nvme/private.h index ccacba7472..7a984f28fc 100644 --- a/libnvme/src/nvme/private.h +++ b/libnvme/src/nvme/private.h @@ -13,6 +13,8 @@ #include #include #include +#include +#include #include #include @@ -273,6 +275,7 @@ struct nvme_global_ctx { bool create_only; bool dry_run; struct nvme_fabric_options *options; + struct ifaddrs *ifaddrs_cache; /* init with nvme_getifaddrs() */ }; struct nvmf_discovery_ctx { @@ -552,4 +555,18 @@ static inline char *xstrdup(const char *s) return strdup(s); } +/** + * nvme_getifaddrs - Cached wrapper around getifaddrs() + * @ctx: pointer to the global context + * + * On the first call, this function invokes the POSIX getifaddrs() + * and caches the result in the global context. Subsequent calls + * return the cached data. The caller must NOT call freeifaddrs() + * on the returned data. The cache will be freed when the global + * context is freed. + * + * Return: Pointer to I/F data, NULL on error (with errno set). + */ +const struct ifaddrs *nvme_getifaddrs(struct nvme_global_ctx *ctx); + #endif /* _LIBNVME_PRIVATE_H */ diff --git a/libnvme/src/nvme/tree.c b/libnvme/src/nvme/tree.c index 796cdd61a8..9b59b19825 100644 --- a/libnvme/src/nvme/tree.c +++ b/libnvme/src/nvme/tree.c @@ -55,7 +55,7 @@ struct candidate_args { const char *subsysnqn; const char *host_traddr; const char *host_iface; - struct ifaddrs *iface_list; + const struct ifaddrs *iface_list; bool (*addreq)(const char *, const char *); bool well_known_nqn; }; @@ -525,6 +525,9 @@ void nvme_free_global_ctx(struct nvme_global_ctx *ctx) if (!ctx) return; + freeifaddrs(ctx->ifaddrs_cache); /* NULL-safe */ + ctx->ifaddrs_cache = NULL; + free(ctx->options); nvme_for_each_host_safe(ctx, h, _h) __nvme_free_host(h); @@ -1756,7 +1759,8 @@ static bool _match_ctrl(struct nvme_ctrl *c, struct candidate_args *candidate) * Return: The matching function to use when comparing an existing * controller to the candidate controller. */ -static ctrl_match_t _candidate_init(struct candidate_args *candidate, +static ctrl_match_t _candidate_init(struct nvme_global_ctx *ctx, + struct candidate_args *candidate, const char *transport, const char *traddr, const char *trsvcid, @@ -1786,12 +1790,7 @@ static ctrl_match_t _candidate_init(struct candidate_args *candidate, } if (streq0(transport, "tcp")) { - /* For TCP we may need to access the interface map. - * Let's retrieve and cache the map. - */ - if (getifaddrs(&candidate->iface_list) == -1) - candidate->iface_list = NULL; - + candidate->iface_list = nvme_getifaddrs(ctx); /* TCP only */ candidate->addreq = nvme_ipaddrs_eq; return _tcp_match_ctrl; } @@ -1806,30 +1805,19 @@ static ctrl_match_t _candidate_init(struct candidate_args *candidate, return _match_ctrl; } -/** - * _candidate_free() - Release resources allocated by _candidate_init() - * - * @candidate: data to free. - */ -static void _candidate_free(struct candidate_args *candidate) -{ - freeifaddrs(candidate->iface_list); /* This is NULL-safe */ -} - -#define _cleanup_candidate_ __cleanup__(_candidate_free) - nvme_ctrl_t __nvme_lookup_ctrl(nvme_subsystem_t s, const char *transport, const char *traddr, const char *host_traddr, const char *host_iface, const char *trsvcid, const char *subsysnqn, nvme_ctrl_t p) { - _cleanup_candidate_ struct candidate_args candidate = {}; + struct candidate_args candidate = {}; struct nvme_ctrl *c, *matching_c = NULL; ctrl_match_t ctrl_match; /* Init candidate and get the matching function to use */ - ctrl_match = _candidate_init(&candidate, transport, traddr, trsvcid, - subsysnqn, host_traddr, host_iface); + ctrl_match = _candidate_init(s->h->ctx, &candidate, transport, traddr, + trsvcid, subsysnqn, host_traddr, + host_iface); c = p ? nvme_subsystem_next_ctrl(s, p) : nvme_subsystem_first_ctrl(s); for (; c != NULL; c = nvme_subsystem_next_ctrl(s, c)) { @@ -1847,12 +1835,13 @@ bool nvme_ctrl_config_match(struct nvme_ctrl *c, const char *transport, const char *subsysnqn, const char *host_traddr, const char *host_iface) { - _cleanup_candidate_ struct candidate_args candidate = {}; + struct candidate_args candidate = {}; ctrl_match_t ctrl_match; /* Init candidate and get the matching function to use */ - ctrl_match = _candidate_init(&candidate, transport, traddr, trsvcid, - subsysnqn, host_traddr, host_iface); + ctrl_match = _candidate_init(c->ctx, &candidate, transport, traddr, + trsvcid, subsysnqn, host_traddr, + host_iface); return ctrl_match(c, &candidate); } diff --git a/libnvme/src/nvme/util.c b/libnvme/src/nvme/util.c index 73215f9cff..13d22af9c1 100644 --- a/libnvme/src/nvme/util.c +++ b/libnvme/src/nvme/util.c @@ -1167,3 +1167,15 @@ void *__nvme_realloc(void *p, size_t len) return result; } + +const struct ifaddrs *nvme_getifaddrs(struct nvme_global_ctx *ctx) +{ + if (!ctx->ifaddrs_cache) { + struct ifaddrs *p; + + if (!getifaddrs(&p)) + ctx->ifaddrs_cache = p; + } + + return ctx->ifaddrs_cache; +}