void nvme_mi_free_root(nvme_root_t root)
{
+ nvme_mi_ep_t ep, tmp;
+
+ nvme_mi_for_each_endpoint_safe(root, ep, tmp)
+ nvme_mi_close(ep);
+
free(root);
}
list_node_init(&ep->root_entry);
ep->root = root;
+ list_add(&root->endpoints, &ep->root_entry);
+
return ep;
}
for (e = nvme_mi_first_endpoint(m); e != NULL; \
e = nvme_mi_next_endpoint(m, e))
+/**
+ * nvme_mi_for_each_endpoint_safe - Iterator for NVMe-MI endpoints, allowing
+ * deletion during traversal
+ * @m: &nvme_root_t containing endpoints
+ * @e: &nvme_mi_ep_t object, set on each iteration
+ * @_e: &nvme_mi_ep_t object used as temporary storage
+ */
+#define nvme_mi_for_each_endpoint_safe(m, e, _e) \
+ for (e = nvme_mi_first_endpoint(m), _e = nvme_mi_next_endpoint(m, e); \
+ e != NULL; \
+ e = _e, _e = nvme_mi_next_endpoint(m, e))
+
struct nvme_mi_ctrl;
/**
return ep;
}
+unsigned int count_root_eps(nvme_root_t root)
+{
+ unsigned int i = 0;
+ nvme_mi_ep_t ep;
+
+ nvme_mi_for_each_endpoint(root, ep)
+ i++;
+
+ return i;
+}
+
+/* test that the root->endpoints list is updated on endpoint
+ * creation/destruction */
+static void test_endpoint_lifetime(nvme_mi_ep_t ep)
+{
+ nvme_root_t root = ep->root;
+ unsigned int count;
+ nvme_mi_ep_t ep2;
+
+ count = count_root_eps(root);
+ assert(count == 1);
+
+ ep2 = nvme_mi_open_test(root);
+ count = count_root_eps(root);
+ assert(count == 2);
+
+ nvme_mi_close(ep2);
+ count = count_root_eps(root);
+ assert(count == 1);
+}
+
/* test: basic read MI datastructure command */
static int test_read_mi_data_cb(struct nvme_mi_ep *ep,
struct nvme_mi_req *req,
const char *name;
void (*fn)(nvme_mi_ep_t);
} tests[] = {
+ DEFINE_TEST(endpoint_lifetime),
DEFINE_TEST(read_mi_data),
DEFINE_TEST(transport_fail),
DEFINE_TEST(transport_describe),