summaryrefslogtreecommitdiffstats
path: root/src/nvme/util.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvme/util.c')
-rw-r--r--src/nvme/util.c230
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;
+}