]> www.infradead.org Git - users/sagi/libnvme.git/commitdiff
mi: free endpoints on root destruction
authorJeremy Kerr <jk@codeconstruct.com.au>
Tue, 21 Jun 2022 08:47:18 +0000 (16:47 +0800)
committerJeremy Kerr <jk@codeconstruct.com.au>
Fri, 24 Jun 2022 07:42:50 +0000 (15:42 +0800)
The root_t object needs to persist through the lifetime of an endpoint,
so close the endpoints on nvme_mi_free_root, and track allocated
endpoints in the root->endpoints list.

To do the destruction safely, we need a _safe variant of the endpoint
iterator macro.

Signed-off-by: Jeremy Kerr <jk@codeconstruct.com.au>
src/nvme/mi.c
src/nvme/mi.h
test/mi.c

index b59cacada4704fbc7de2a0800c0fae88f1e7d51c..1d3162b32d1d66020fbe9382f31b22a9eb2ca158 100644 (file)
@@ -39,6 +39,11 @@ nvme_root_t nvme_mi_create_root(FILE *fp, int log_level)
 
 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);
 }
 
@@ -50,6 +55,8 @@ struct nvme_mi_ep *nvme_mi_init_ep(nvme_root_t root)
        list_node_init(&ep->root_entry);
        ep->root = root;
 
+       list_add(&root->endpoints, &ep->root_entry);
+
        return ep;
 }
 
index 57087157bab257b34535d8f8008cd06d7302fe61..58f3267e1d1f8411b7fec807ec797804c69e78ad 100644 (file)
@@ -317,6 +317,18 @@ nvme_mi_ep_t nvme_mi_next_endpoint(nvme_root_t m, nvme_mi_ep_t e);
        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;
 
 /**
index c45c9d01e01ba4908af2e8ecfab9cf74534e328e..5cea68b77010e0f97835f2afc6ad648f288205f7 100644 (file)
--- a/test/mi.c
+++ b/test/mi.c
@@ -121,6 +121,37 @@ nvme_mi_ep_t nvme_mi_open_test(nvme_root_t root)
        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,
@@ -357,6 +388,7 @@ struct test {
        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),