diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2023-12-24 07:51:44 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2023-12-24 07:51:44 +0000 |
commit | 4da5b4b2fba02bd3e78f16828359cef79a757911 (patch) | |
tree | 326db4edaddfc20f78fb048509fd646f497e2a65 /src/nvme/util.c | |
parent | Adding upstream version 1.5. (diff) | |
download | libnvme-4da5b4b2fba02bd3e78f16828359cef79a757911.tar.xz libnvme-4da5b4b2fba02bd3e78f16828359cef79a757911.zip |
Adding upstream version 1.7.1.upstream/1.7.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/nvme/util.c')
-rw-r--r-- | src/nvme/util.c | 230 |
1 files changed, 187 insertions, 43 deletions
diff --git a/src/nvme/util.c b/src/nvme/util.c index 143cc31..45512ff 100644 --- a/src/nvme/util.c +++ b/src/nvme/util.c @@ -7,6 +7,7 @@ * Chaitanya Kulkarni <chaitanya.kulkarni@wdc.com> */ +#include <stdlib.h> #include <stdio.h> #include <stdbool.h> #include <string.h> @@ -22,6 +23,7 @@ #include <ccan/endian/endian.h> +#include "cleanup.h" #include "private.h" #include "util.h" #include "log.h" @@ -290,6 +292,10 @@ static const char * const nvm_status[] = { [NVME_SC_INVALID_PI] = "Invalid Protection Information: The command's Protection Information Field settings are invalid for the namespace's Protection Information format", [NVME_SC_READ_ONLY] = "Attempted Write to Read Only Range: The LBA range specified contains read-only blocks", [NVME_SC_CMD_SIZE_LIMIT_EXCEEDED] = "Command Size Limit Exceeded", + [NVME_SC_INCOMPATIBLE_NS] = "Incompatible Namespace or Format", + [NVME_SC_FAST_COPY_NOT_POSSIBLE] = "Fast Copy Not Possible", + [NVME_SC_OVERLAPPING_IO_RANGE] = "Overlapping I/O Range", + [NVME_SC_INSUFFICIENT_RESOURCES] = "Insufficient Resources", [NVME_SC_ZNS_INVALID_OP_REQUEST] = "Invalid Zone Operation Request: The operation requested is invalid", [NVME_SC_ZNS_ZRWA_RESOURCES_UNAVAILABLE] = "ZRWA Resources Unavailable: No ZRWAs are available", [NVME_SC_ZNS_BOUNDARY_ERROR] = "Zoned Boundary Error: Invalid Zone Boundary crossing", @@ -385,6 +391,16 @@ const char *nvme_status_to_string(int status, bool fabrics) return s; } +static inline void nvme_init_copy_range_elbt(__u8 *elbt, __u64 eilbrt) +{ + int i; + + for (i = 0; i < 8; i++) + elbt[9 - i] = (eilbrt >> (8 * i)) & 0xff; + elbt[1] = 0; + elbt[0] = 0; +} + void nvme_init_copy_range(struct nvme_copy_range *copy, __u16 *nlbs, __u64 *slbas, __u32 *eilbrts, __u32 *elbatms, __u32 *elbats, __u16 nr) @@ -404,18 +420,51 @@ void nvme_init_copy_range_f1(struct nvme_copy_range_f1 *copy, __u16 *nlbs, __u64 *slbas, __u64 *eilbrts, __u32 *elbatms, __u32 *elbats, __u16 nr) { - int i, j; + int i; + + for (i = 0; i < nr; i++) { + copy[i].nlb = cpu_to_le16(nlbs[i]); + copy[i].slba = cpu_to_le64(slbas[i]); + copy[i].elbatm = cpu_to_le16(elbatms[i]); + copy[i].elbat = cpu_to_le16(elbats[i]); + nvme_init_copy_range_elbt(copy[i].elbt, eilbrts[i]); + } +} + +void nvme_init_copy_range_f2(struct nvme_copy_range_f2 *copy, __u32 *snsids, + __u16 *nlbs, __u64 *slbas, __u16 *sopts, + __u32 *eilbrts, __u32 *elbatms, __u32 *elbats, + __u16 nr) +{ + int i; for (i = 0; i < nr; i++) { + copy[i].snsid = cpu_to_le32(snsids[i]); copy[i].nlb = cpu_to_le16(nlbs[i]); copy[i].slba = cpu_to_le64(slbas[i]); + copy[i].sopt = cpu_to_le16(sopts[i]); + copy[i].eilbrt = cpu_to_le32(eilbrts[i]); copy[i].elbatm = cpu_to_le16(elbatms[i]); copy[i].elbat = cpu_to_le16(elbats[i]); - for (j = 0; j < 8; j++) - copy[i].elbt[9 - j] = (eilbrts[i] >> (8 * j)) & 0xff; - copy[i].elbt[1] = 0; - copy[i].elbt[0] = 0; - } + } +} + +void nvme_init_copy_range_f3(struct nvme_copy_range_f3 *copy, __u32 *snsids, + __u16 *nlbs, __u64 *slbas, __u16 *sopts, + __u64 *eilbrts, __u32 *elbatms, __u32 *elbats, + __u16 nr) +{ + int i; + + for (i = 0; i < nr; i++) { + copy[i].snsid = cpu_to_le32(snsids[i]); + copy[i].nlb = cpu_to_le16(nlbs[i]); + copy[i].slba = cpu_to_le64(slbas[i]); + copy[i].sopt = cpu_to_le16(sopts[i]); + copy[i].elbatm = cpu_to_le16(elbatms[i]); + copy[i].elbat = cpu_to_le16(elbats[i]); + nvme_init_copy_range_elbt(copy[i].elbt, eilbrts[i]); + } } void nvme_init_dsm_range(struct nvme_dsm_range *dsm, __u32 *ctx_attrs, @@ -708,7 +757,7 @@ char *kv_keymatch(const char *kv, const char *key) static size_t read_file(const char * fname, char *buffer, size_t *bufsz) { char *p; - FILE *file; + _cleanup_file_ FILE *file; size_t len; file = fopen(fname, "re"); @@ -716,7 +765,6 @@ static size_t read_file(const char * fname, char *buffer, size_t *bufsz) return 0; p = fgets(buffer, *bufsz, file); - fclose(file); if (!p) return 0; @@ -758,7 +806,7 @@ size_t get_entity_name(char *buffer, size_t bufsz) size_t get_entity_version(char *buffer, size_t bufsz) { - FILE *file; + _cleanup_file_ FILE *file; size_t num_bytes = 0; /* /proc/sys/kernel/ostype typically contains the string "Linux" */ @@ -808,7 +856,6 @@ size_t get_entity_version(char *buffer, size_t bufsz) if (s) ver_id_len = copy_value(ver_id, sizeof(ver_id), s); } - fclose(file); if (name_len) { /* Append a space */ @@ -881,14 +928,13 @@ int nvme_uuid_from_string(const char *str, unsigned char uuid[NVME_UUID_LEN]) int nvme_uuid_random(unsigned char uuid[NVME_UUID_LEN]) { - int f; + _cleanup_fd_ int f; ssize_t n; f = open("/dev/urandom", O_RDONLY); if (f < 0) return -errno; n = read(f, uuid, NVME_UUID_LEN); - close(f); if (n < 0) return -errno; else if (n != NVME_UUID_LEN) @@ -906,6 +952,46 @@ int nvme_uuid_random(unsigned char uuid[NVME_UUID_LEN]) } #ifdef HAVE_NETDB +static bool _nvme_ipaddrs_eq(struct sockaddr *addr1, struct sockaddr *addr2) +{ + struct sockaddr_in *sockaddr_v4; + struct sockaddr_in6 *sockaddr_v6; + + if (addr1->sa_family == AF_INET && addr2->sa_family == AF_INET) { + struct sockaddr_in *sockaddr1 = (struct sockaddr_in *)addr1; + struct sockaddr_in *sockaddr2 = (struct sockaddr_in *)addr2; + return sockaddr1->sin_addr.s_addr == sockaddr2->sin_addr.s_addr; + } + + if (addr1->sa_family == AF_INET6 && addr2->sa_family == AF_INET6) { + struct sockaddr_in6 *sockaddr1 = (struct sockaddr_in6 *)addr1; + struct sockaddr_in6 *sockaddr2 = (struct sockaddr_in6 *)addr2; + return !memcmp(&sockaddr1->sin6_addr, &sockaddr2->sin6_addr, sizeof(struct in6_addr)); + } + + switch (addr1->sa_family) { + case AF_INET: + sockaddr_v6 = (struct sockaddr_in6 *)addr2; + if (IN6_IS_ADDR_V4MAPPED(&sockaddr_v6->sin6_addr)) { + sockaddr_v4 = (struct sockaddr_in *)addr1; + return sockaddr_v4->sin_addr.s_addr == sockaddr_v6->sin6_addr.s6_addr32[3]; + } + break; + + case AF_INET6: + sockaddr_v6 = (struct sockaddr_in6 *)addr1; + if (IN6_IS_ADDR_V4MAPPED(&sockaddr_v6->sin6_addr)) { + sockaddr_v4 = (struct sockaddr_in *)addr2; + return sockaddr_v4->sin_addr.s_addr == sockaddr_v6->sin6_addr.s6_addr32[3]; + } + break; + + default: ; + } + + return false; +} + bool nvme_ipaddrs_eq(const char *addr1, const char *addr2) { bool result = false; @@ -924,37 +1010,7 @@ bool nvme_ipaddrs_eq(const char *addr1, const char *addr2) if (getaddrinfo(addr2, 0, &hint2, &info2) || !info2) goto ipaddrs_eq_fail; - if (info1->ai_family == AF_INET && info2->ai_family == AF_INET) { - struct sockaddr_in *sockaddr1 = (struct sockaddr_in *)(info1->ai_addr); - struct sockaddr_in *sockaddr2 = (struct sockaddr_in *)(info2->ai_addr); - result = sockaddr1->sin_addr.s_addr == sockaddr2->sin_addr.s_addr; - } else if (info1->ai_family == AF_INET6 && info2->ai_family == AF_INET6) { - struct sockaddr_in6 *sockaddr1 = (struct sockaddr_in6 *)(info1->ai_addr); - struct sockaddr_in6 *sockaddr2 = (struct sockaddr_in6 *)(info2->ai_addr); - result = !memcmp(&sockaddr1->sin6_addr, &sockaddr2->sin6_addr, sizeof(struct in6_addr)); - } else { - struct sockaddr_in *sockaddr_v4; - struct sockaddr_in6 *sockaddr_v6; - switch (info1->ai_family) { - case AF_INET: - sockaddr_v6 = (struct sockaddr_in6 *)(info2->ai_addr); - if (IN6_IS_ADDR_V4MAPPED(&sockaddr_v6->sin6_addr)) { - sockaddr_v4 = (struct sockaddr_in *)(info1->ai_addr); - result = sockaddr_v4->sin_addr.s_addr == sockaddr_v6->sin6_addr.s6_addr32[3]; - } - break; - - case AF_INET6: - sockaddr_v6 = (struct sockaddr_in6 *)(info1->ai_addr); - if (IN6_IS_ADDR_V4MAPPED(&sockaddr_v6->sin6_addr)) { - sockaddr_v4 = (struct sockaddr_in *)(info2->ai_addr); - result = sockaddr_v4->sin_addr.s_addr == sockaddr_v6->sin6_addr.s6_addr32[3]; - } - break; - - default: ; - } - } + result = _nvme_ipaddrs_eq(info1->ai_addr, info2->ai_addr); ipaddrs_eq_fail: if (info1) @@ -972,3 +1028,91 @@ bool nvme_ipaddrs_eq(const char *addr1, const char *addr2) return false; } #endif /* HAVE_NETDB */ + +#ifdef HAVE_NETDB +const char *nvme_iface_matching_addr(const struct ifaddrs *iface_list, const char *addr) +{ + const struct ifaddrs *iface_it; + struct addrinfo *info = NULL, hint = { .ai_flags = AI_NUMERICHOST, .ai_family = AF_UNSPEC }; + const char *iface_name = NULL; + + if (!iface_list || !addr || getaddrinfo(addr, 0, &hint, &info) || !info) + return NULL; + + /* Walk through the linked list */ + for (iface_it = iface_list; iface_it != NULL; iface_it = iface_it->ifa_next) { + struct sockaddr *ifaddr = iface_it->ifa_addr; + + if (ifaddr && (ifaddr->sa_family == AF_INET || ifaddr->sa_family == AF_INET6) && + _nvme_ipaddrs_eq(info->ai_addr, ifaddr)) { + iface_name = iface_it->ifa_name; + break; + } + } + + freeaddrinfo(info); + + return iface_name; +} + +bool nvme_iface_primary_addr_matches(const struct ifaddrs *iface_list, const char *iface, const char *addr) +{ + const struct ifaddrs *iface_it; + struct addrinfo *info = NULL, hint = { .ai_flags = AI_NUMERICHOST, .ai_family = AF_UNSPEC }; + bool match_found = false; + + if (!iface_list || !addr || getaddrinfo(addr, 0, &hint, &info) || !info) + return false; + + /* Walk through the linked list */ + for (iface_it = iface_list; iface_it != NULL; iface_it = iface_it->ifa_next) { + if (strcmp(iface, iface_it->ifa_name)) + continue; /* Not the interface we're looking for*/ + + /* The interface list is ordered in a way that the primary + * address is listed first. As soon as the parsed address + * matches the family of the address we're looking for, we + * have found the primary address for that family. + */ + if (iface_it->ifa_addr && (iface_it->ifa_addr->sa_family == info->ai_addr->sa_family)) { + match_found = _nvme_ipaddrs_eq(info->ai_addr, iface_it->ifa_addr); + break; + } + } + + freeaddrinfo(info); + + return match_found; +} + +#else /* HAVE_NETDB */ + +const char *nvme_iface_matching_addr(const struct ifaddrs *iface_list, const char *addr) +{ + nvme_msg(NULL, LOG_ERR, "no support for interface lookup; " + "recompile with libnss support.\n"); + + return NULL; +} + +bool nvme_iface_primary_addr_matches(const struct ifaddrs *iface_list, const char *iface, const char *addr) +{ + nvme_msg(NULL, LOG_ERR, "no support for interface lookup; " + "recompile with libnss support.\n"); + + return false; +} + +#endif /* HAVE_NETDB */ + +void *__nvme_alloc(size_t len) +{ + size_t _len = round_up(len, 0x1000); + void *p; + + if (posix_memalign((void *)&p, getpagesize(), _len)) + return NULL; + + memset(p, 0, _len); + return p; +} |