From 97a16dc89797d88793801ed81e71b69ee138aeec Mon Sep 17 00:00:00 2001 From: Jeremy Kerr Date: Tue, 21 Jun 2022 16:47:18 +0800 Subject: [PATCH] mi: free endpoints on root destruction 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 --- src/nvme/mi.c | 7 +++++++ src/nvme/mi.h | 12 ++++++++++++ test/mi.c | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 51 insertions(+) diff --git a/src/nvme/mi.c b/src/nvme/mi.c index b59cacad..1d3162b3 100644 --- a/src/nvme/mi.c +++ b/src/nvme/mi.c @@ -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; } diff --git a/src/nvme/mi.h b/src/nvme/mi.h index 57087157..58f3267e 100644 --- a/src/nvme/mi.h +++ b/src/nvme/mi.h @@ -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; /** diff --git a/test/mi.c b/test/mi.c index c45c9d01..5cea68b7 100644 --- 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), -- 2.50.1