xref: /spdk/test/unit/lib/util/fd_group.c/fd_group_ut.c (revision c12cb8fe35297bfebf155ee658660da0160fbc12)
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(&not_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