1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright (C) 2024 Samsung Electronics Co., Ltd. 3 * All rights reserved. 4 */ 5 6 #include "spdk/stdinc.h" 7 #include "spdk_internal/cunit.h" 8 #include "util/fd_group.c" 9 10 static int 11 fd_group_cb_fn(void *ctx) 12 { 13 return 0; 14 } 15 16 static void 17 test_fd_group_basic(void) 18 { 19 struct spdk_fd_group *fgrp; 20 struct event_handler *ehdlr = NULL; 21 int fd; 22 int rc; 23 int cb_arg; 24 25 rc = spdk_fd_group_create(&fgrp); 26 SPDK_CU_ASSERT_FATAL(rc == 0); 27 28 fd = epoll_create1(0); 29 SPDK_CU_ASSERT_FATAL(fd >= 0); 30 31 rc = SPDK_FD_GROUP_ADD(fgrp, fd, fd_group_cb_fn, &cb_arg); 32 SPDK_CU_ASSERT_FATAL(rc == 0); 33 SPDK_CU_ASSERT_FATAL(fgrp->num_fds == 1); 34 35 /* Verify that event handler is initialized correctly */ 36 ehdlr = TAILQ_FIRST(&fgrp->event_handlers); 37 SPDK_CU_ASSERT_FATAL(ehdlr != NULL); 38 CU_ASSERT(ehdlr->fd == fd); 39 CU_ASSERT(ehdlr->state == EVENT_HANDLER_STATE_WAITING); 40 CU_ASSERT(ehdlr->events == EPOLLIN); 41 42 /* Modify event type and see if event handler is updated correctly */ 43 rc = spdk_fd_group_event_modify(fgrp, fd, EPOLLIN | EPOLLERR); 44 SPDK_CU_ASSERT_FATAL(rc == 0); 45 46 ehdlr = TAILQ_FIRST(&fgrp->event_handlers); 47 SPDK_CU_ASSERT_FATAL(ehdlr != NULL); 48 CU_ASSERT(ehdlr->events == (EPOLLIN | EPOLLERR)); 49 50 spdk_fd_group_remove(fgrp, fd); 51 SPDK_CU_ASSERT_FATAL(fgrp->num_fds == 0); 52 53 rc = close(fd); 54 CU_ASSERT(rc == 0); 55 56 spdk_fd_group_destroy(fgrp); 57 } 58 59 static void 60 test_fd_group_nest_unnest(void) 61 { 62 struct spdk_fd_group *parent, *child, *not_parent; 63 int fd_parent, fd_child, fd_child_2; 64 int rc; 65 int cb_arg; 66 67 rc = spdk_fd_group_create(&parent); 68 SPDK_CU_ASSERT_FATAL(rc == 0); 69 70 rc = spdk_fd_group_create(&child); 71 SPDK_CU_ASSERT_FATAL(rc == 0); 72 73 rc = spdk_fd_group_create(¬_parent); 74 SPDK_CU_ASSERT_FATAL(rc == 0); 75 76 fd_parent = epoll_create1(0); 77 SPDK_CU_ASSERT_FATAL(fd_parent >= 0); 78 79 fd_child = epoll_create1(0); 80 SPDK_CU_ASSERT_FATAL(fd_child >= 0); 81 82 fd_child_2 = epoll_create1(0); 83 SPDK_CU_ASSERT_FATAL(fd_child_2 >= 0); 84 85 rc = SPDK_FD_GROUP_ADD(parent, fd_parent, fd_group_cb_fn, &cb_arg); 86 SPDK_CU_ASSERT_FATAL(rc == 0); 87 SPDK_CU_ASSERT_FATAL(parent->num_fds == 1); 88 89 rc = SPDK_FD_GROUP_ADD(child, fd_child, fd_group_cb_fn, &cb_arg); 90 SPDK_CU_ASSERT_FATAL(rc == 0); 91 SPDK_CU_ASSERT_FATAL(child->num_fds == 1); 92 93 /* Nest child fd group to a parent fd group and verify their relation */ 94 rc = spdk_fd_group_nest(parent, child); 95 SPDK_CU_ASSERT_FATAL(rc == 0); 96 SPDK_CU_ASSERT_FATAL(child->parent == parent); 97 SPDK_CU_ASSERT_FATAL(parent->num_fds == 2); 98 SPDK_CU_ASSERT_FATAL(child->num_fds == 0); 99 100 /* Register second child fd to the child fd group and verify that the parent fd group 101 * has the correct number of fds. 102 */ 103 rc = SPDK_FD_GROUP_ADD(child, fd_child_2, fd_group_cb_fn, &cb_arg); 104 SPDK_CU_ASSERT_FATAL(rc == 0); 105 SPDK_CU_ASSERT_FATAL(child->num_fds == 0); 106 SPDK_CU_ASSERT_FATAL(parent->num_fds == 3); 107 108 /* Unnest child fd group from wrong parent fd group and verify that it fails. */ 109 rc = spdk_fd_group_unnest(not_parent, child); 110 SPDK_CU_ASSERT_FATAL(rc == -EINVAL); 111 112 /* Unnest child fd group from its parent fd group and verify it. */ 113 rc = spdk_fd_group_unnest(parent, child); 114 SPDK_CU_ASSERT_FATAL(rc == 0); 115 SPDK_CU_ASSERT_FATAL(child->parent == NULL); 116 SPDK_CU_ASSERT_FATAL(parent->num_fds == 1); 117 SPDK_CU_ASSERT_FATAL(child->num_fds == 2); 118 119 spdk_fd_group_remove(child, fd_child); 120 SPDK_CU_ASSERT_FATAL(child->num_fds == 1); 121 122 spdk_fd_group_remove(child, fd_child_2); 123 SPDK_CU_ASSERT_FATAL(child->num_fds == 0); 124 125 spdk_fd_group_remove(parent, fd_parent); 126 SPDK_CU_ASSERT_FATAL(parent->num_fds == 0); 127 128 rc = close(fd_child); 129 CU_ASSERT(rc == 0); 130 131 rc = close(fd_child_2); 132 CU_ASSERT(rc == 0); 133 134 rc = close(fd_parent); 135 CU_ASSERT(rc == 0); 136 137 spdk_fd_group_destroy(child); 138 spdk_fd_group_destroy(parent); 139 spdk_fd_group_destroy(not_parent); 140 } 141 142 struct ut_fgrp { 143 struct spdk_fd_group *fgrp; 144 size_t num_fds; 145 #define UT_MAX_FDS 4 146 int fd[UT_MAX_FDS]; 147 }; 148 149 static void 150 test_fd_group_multi_nest(void) 151 { 152 struct ut_fgrp fgrp[] = { 153 { .num_fds = 1 }, 154 { .num_fds = 2 }, 155 { .num_fds = 2 }, 156 { .num_fds = 3 }, 157 }; 158 size_t i, j; 159 int fd, rc; 160 161 /* Create four fd_groups with the folowing hierarchy: 162 * fgrp[0] 163 * (fd:0) 164 * | 165 * fgrp[1]-----+-----fgrp[2] 166 * (fd:1,2) (fd:3,4) 167 * | 168 * fgrp[3] 169 * (fd:5,6,7) 170 */ 171 for (i = 0; i < SPDK_COUNTOF(fgrp); i++) { 172 rc = spdk_fd_group_create(&fgrp[i].fgrp); 173 SPDK_CU_ASSERT_FATAL(rc == 0); 174 for (j = 0; j < fgrp[i].num_fds; j++) { 175 fgrp[i].fd[j] = fd = eventfd(0, 0); 176 CU_ASSERT(fd >= 0); 177 rc = SPDK_FD_GROUP_ADD(fgrp[i].fgrp, fd, fd_group_cb_fn, NULL); 178 CU_ASSERT_EQUAL(rc, 0); 179 } 180 } 181 182 CU_ASSERT_EQUAL(fgrp[0].fgrp->num_fds, fgrp[0].num_fds); 183 CU_ASSERT_EQUAL(fgrp[1].fgrp->num_fds, fgrp[1].num_fds); 184 CU_ASSERT_EQUAL(fgrp[2].fgrp->num_fds, fgrp[2].num_fds); 185 CU_ASSERT_EQUAL(fgrp[3].fgrp->num_fds, fgrp[3].num_fds); 186 187 rc = spdk_fd_group_nest(fgrp[0].fgrp, fgrp[2].fgrp); 188 CU_ASSERT_EQUAL(rc, 0); 189 rc = spdk_fd_group_nest(fgrp[1].fgrp, fgrp[3].fgrp); 190 CU_ASSERT_EQUAL(rc, 0); 191 rc = spdk_fd_group_nest(fgrp[0].fgrp, fgrp[1].fgrp); 192 CU_ASSERT_EQUAL(rc, 0); 193 194 CU_ASSERT_PTR_EQUAL(fgrp[0].fgrp->parent, NULL); 195 CU_ASSERT_PTR_EQUAL(fgrp[1].fgrp->parent, fgrp[0].fgrp); 196 CU_ASSERT_PTR_EQUAL(fgrp[2].fgrp->parent, fgrp[0].fgrp); 197 CU_ASSERT_PTR_EQUAL(fgrp[3].fgrp->parent, fgrp[1].fgrp); 198 CU_ASSERT_EQUAL(fgrp[0].fgrp->num_fds, 199 fgrp[0].num_fds + fgrp[1].num_fds + 200 fgrp[2].num_fds + fgrp[3].num_fds); 201 CU_ASSERT_EQUAL(fgrp[1].fgrp->num_fds, 0); 202 CU_ASSERT_EQUAL(fgrp[2].fgrp->num_fds, 0); 203 CU_ASSERT_EQUAL(fgrp[3].fgrp->num_fds, 0); 204 205 /* Unnest fgrp[1] and verify that it now owns its own fds along with fgrp[3] fds */ 206 rc = spdk_fd_group_unnest(fgrp[0].fgrp, fgrp[1].fgrp); 207 CU_ASSERT_EQUAL(rc, 0); 208 209 CU_ASSERT_PTR_EQUAL(fgrp[0].fgrp->parent, NULL); 210 CU_ASSERT_PTR_EQUAL(fgrp[1].fgrp->parent, NULL); 211 CU_ASSERT_PTR_EQUAL(fgrp[2].fgrp->parent, fgrp[0].fgrp); 212 CU_ASSERT_PTR_EQUAL(fgrp[3].fgrp->parent, fgrp[1].fgrp); 213 CU_ASSERT_EQUAL(fgrp[0].fgrp->num_fds, fgrp[0].num_fds + fgrp[2].num_fds); 214 CU_ASSERT_EQUAL(fgrp[1].fgrp->num_fds, fgrp[1].num_fds + fgrp[3].num_fds); 215 CU_ASSERT_EQUAL(fgrp[2].fgrp->num_fds, 0); 216 CU_ASSERT_EQUAL(fgrp[3].fgrp->num_fds, 0); 217 218 /* Nest it again, keeping the same configuration */ 219 rc = spdk_fd_group_nest(fgrp[0].fgrp, fgrp[1].fgrp); 220 CU_ASSERT_EQUAL(rc, 0); 221 CU_ASSERT_PTR_EQUAL(fgrp[0].fgrp->parent, NULL); 222 CU_ASSERT_PTR_EQUAL(fgrp[1].fgrp->parent, fgrp[0].fgrp); 223 CU_ASSERT_PTR_EQUAL(fgrp[2].fgrp->parent, fgrp[0].fgrp); 224 CU_ASSERT_PTR_EQUAL(fgrp[3].fgrp->parent, fgrp[1].fgrp); 225 CU_ASSERT_EQUAL(fgrp[0].fgrp->num_fds, 226 fgrp[0].num_fds + fgrp[1].num_fds + 227 fgrp[2].num_fds + fgrp[3].num_fds); 228 CU_ASSERT_EQUAL(fgrp[1].fgrp->num_fds, 0); 229 CU_ASSERT_EQUAL(fgrp[2].fgrp->num_fds, 0); 230 CU_ASSERT_EQUAL(fgrp[3].fgrp->num_fds, 0); 231 232 /* Add a new fd to the fgrp at the bottom, fgrp[3] */ 233 fgrp[3].fd[fgrp[3].num_fds++] = fd = eventfd(0, 0); 234 rc = SPDK_FD_GROUP_ADD(fgrp[3].fgrp, fd, fd_group_cb_fn, NULL); 235 CU_ASSERT_EQUAL(rc, 0); 236 CU_ASSERT_EQUAL(fgrp[0].fgrp->num_fds, 237 fgrp[0].num_fds + fgrp[1].num_fds + 238 fgrp[2].num_fds + fgrp[3].num_fds); 239 CU_ASSERT_EQUAL(fgrp[1].fgrp->num_fds, 0); 240 CU_ASSERT_EQUAL(fgrp[2].fgrp->num_fds, 0); 241 CU_ASSERT_EQUAL(fgrp[3].fgrp->num_fds, 0); 242 243 /* Remove one of the fds from fgrp[2] */ 244 fd = fgrp[2].fd[--fgrp[2].num_fds]; 245 spdk_fd_group_remove(fgrp[2].fgrp, fd); 246 close(fd); 247 CU_ASSERT_EQUAL(fgrp[0].fgrp->num_fds, 248 fgrp[0].num_fds + fgrp[1].num_fds + 249 fgrp[2].num_fds + fgrp[3].num_fds); 250 CU_ASSERT_EQUAL(fgrp[1].fgrp->num_fds, 0); 251 CU_ASSERT_EQUAL(fgrp[2].fgrp->num_fds, 0); 252 CU_ASSERT_EQUAL(fgrp[3].fgrp->num_fds, 0); 253 254 /* Unnest the fgrp at the bottom, fgrp[3] */ 255 rc = spdk_fd_group_unnest(fgrp[1].fgrp, fgrp[3].fgrp); 256 CU_ASSERT_EQUAL(rc, 0); 257 CU_ASSERT_PTR_EQUAL(fgrp[0].fgrp->parent, NULL); 258 CU_ASSERT_PTR_EQUAL(fgrp[1].fgrp->parent, fgrp[0].fgrp); 259 CU_ASSERT_PTR_EQUAL(fgrp[2].fgrp->parent, fgrp[0].fgrp); 260 CU_ASSERT_PTR_EQUAL(fgrp[3].fgrp->parent, NULL); 261 CU_ASSERT_EQUAL(fgrp[0].fgrp->num_fds, fgrp[0].num_fds + fgrp[1].num_fds + fgrp[2].num_fds); 262 CU_ASSERT_EQUAL(fgrp[1].fgrp->num_fds, 0); 263 CU_ASSERT_EQUAL(fgrp[2].fgrp->num_fds, 0); 264 CU_ASSERT_EQUAL(fgrp[3].fgrp->num_fds, fgrp[3].num_fds); 265 266 /* Unnest the remaining fgrps, fgrp[1] and fgrp[2] */ 267 rc = spdk_fd_group_unnest(fgrp[0].fgrp, fgrp[1].fgrp); 268 CU_ASSERT_EQUAL(rc, 0); 269 CU_ASSERT_PTR_EQUAL(fgrp[0].fgrp->parent, NULL); 270 CU_ASSERT_PTR_EQUAL(fgrp[1].fgrp->parent, NULL); 271 CU_ASSERT_PTR_EQUAL(fgrp[2].fgrp->parent, fgrp[0].fgrp); 272 CU_ASSERT_EQUAL(fgrp[0].fgrp->num_fds, fgrp[0].num_fds + fgrp[2].num_fds); 273 CU_ASSERT_EQUAL(fgrp[1].fgrp->num_fds, fgrp[1].num_fds); 274 CU_ASSERT_EQUAL(fgrp[2].fgrp->num_fds, 0); 275 276 rc = spdk_fd_group_unnest(fgrp[0].fgrp, fgrp[2].fgrp); 277 CU_ASSERT_EQUAL(rc, 0); 278 CU_ASSERT_PTR_EQUAL(fgrp[0].fgrp->parent, NULL); 279 CU_ASSERT_PTR_EQUAL(fgrp[2].fgrp->parent, NULL);; 280 CU_ASSERT_EQUAL(fgrp[0].fgrp->num_fds, fgrp[0].num_fds); 281 CU_ASSERT_EQUAL(fgrp[2].fgrp->num_fds, fgrp[2].num_fds); 282 283 for (i = 0; i < SPDK_COUNTOF(fgrp); i++) { 284 for (j = 0; j < fgrp[i].num_fds; j++) { 285 spdk_fd_group_remove(fgrp[i].fgrp, fgrp[i].fd[j]); 286 close(fgrp[i].fd[j]); 287 } 288 spdk_fd_group_destroy(fgrp[i].fgrp); 289 } 290 } 291 292 int 293 main(int argc, char **argv) 294 { 295 CU_pSuite suite = NULL; 296 unsigned int num_failures; 297 298 CU_initialize_registry(); 299 300 suite = CU_add_suite("fd_group", NULL, NULL); 301 302 CU_ADD_TEST(suite, test_fd_group_basic); 303 CU_ADD_TEST(suite, test_fd_group_nest_unnest); 304 CU_ADD_TEST(suite, test_fd_group_multi_nest); 305 306 num_failures = spdk_ut_run_tests(argc, argv, NULL); 307 308 CU_cleanup_registry(); 309 310 return num_failures; 311 } 312