xref: /spdk/lib/util/fd_group.c (revision b02581a89058ebaebe03bd0e16e3b58adfe406c1)
1 /*   SPDX-License-Identifier: BSD-3-Clause
2  *   Copyright (C) 2020 Intel Corporation. All rights reserved.
3  *   All rights reserved.
4  */
5 
6 #include "spdk_internal/usdt.h"
7 
8 #include "spdk/env.h"
9 #include "spdk/log.h"
10 #include "spdk/queue.h"
11 
12 #include "spdk/fd_group.h"
13 
14 #ifdef __linux__
15 #include <sys/epoll.h>
16 #endif
17 
18 #define SPDK_MAX_EVENT_NAME_LEN 256
19 
20 enum event_handler_state {
21 	/* The event_handler is added into an fd_group waiting for event,
22 	 * but not currently in the execution of a wait loop.
23 	 */
24 	EVENT_HANDLER_STATE_WAITING,
25 
26 	/* The event_handler is currently in the execution of a wait loop. */
27 	EVENT_HANDLER_STATE_RUNNING,
28 
29 	/* The event_handler was removed during the execution of a wait loop. */
30 	EVENT_HANDLER_STATE_REMOVED,
31 };
32 
33 /* file descriptor of the interrupt event */
34 
35 /* Taking "ehdlr" as short name for file descriptor handler of the interrupt event. */
36 struct event_handler {
37 	TAILQ_ENTRY(event_handler)	next;
38 	enum event_handler_state	state;
39 
40 	spdk_fd_fn			fn;
41 	void				*fn_arg;
42 	/* file descriptor of the interrupt event */
43 	int				fd;
44 	uint32_t			events;
45 	char				name[SPDK_MAX_EVENT_NAME_LEN + 1];
46 };
47 
48 struct spdk_fd_group {
49 	int epfd;
50 	int num_fds; /* Number of fds registered in this group. */
51 
52 	struct spdk_fd_group *parent;
53 
54 	/* interrupt sources list */
55 	TAILQ_HEAD(, event_handler) event_handlers;
56 };
57 
58 int
59 spdk_fd_group_get_fd(struct spdk_fd_group *fgrp)
60 {
61 	return fgrp->epfd;
62 }
63 
64 #ifdef __linux__
65 
66 static __thread struct epoll_event *g_event = NULL;
67 
68 int
69 spdk_fd_group_get_epoll_event(struct epoll_event *event)
70 {
71 	if (g_event == NULL) {
72 		return -EINVAL;
73 	}
74 	*event = *g_event;
75 	return 0;
76 }
77 
78 static int
79 _fd_group_del_all(int epfd, struct spdk_fd_group *grp)
80 {
81 	struct event_handler *ehdlr = NULL;
82 	struct epoll_event epevent = {0};
83 	int rc;
84 	int ret = 0;
85 
86 	TAILQ_FOREACH(ehdlr, &grp->event_handlers, next) {
87 		rc = epoll_ctl(epfd, EPOLL_CTL_DEL, ehdlr->fd, NULL);
88 		if (rc < 0) {
89 			if (errno == ENOENT) {
90 				/* This is treated as success. It happens if there are multiple
91 				 * attempts to remove fds from the group.
92 				 */
93 				continue;
94 			}
95 
96 			ret = -errno;
97 			SPDK_ERRLOG("Failed to remove fd %d from group: %s\n", ehdlr->fd, strerror(errno));
98 			goto recover;
99 		}
100 	}
101 
102 	return 0;
103 
104 recover:
105 	/* We failed to remove everything. Let's try to get everything put back into
106 	 * the original group. */
107 	TAILQ_FOREACH(ehdlr, &grp->event_handlers, next) {
108 		epevent.events = ehdlr->events;
109 		epevent.data.ptr = ehdlr;
110 		rc = epoll_ctl(epfd, EPOLL_CTL_ADD, ehdlr->fd, &epevent);
111 		if (rc < 0) {
112 			if (errno == EEXIST) {
113 				/* This is fine. Keep going. */
114 				continue;
115 			}
116 
117 			/* Continue on even though we've failed. But indicate
118 			 * this is a fatal error. */
119 			SPDK_ERRLOG("Failed to recover fd_group_del_all: %s\n", strerror(errno));
120 			ret = -ENOTRECOVERABLE;
121 		}
122 	}
123 
124 	return ret;
125 }
126 
127 static int
128 _fd_group_add_all(int epfd, struct spdk_fd_group *grp)
129 {
130 	struct event_handler *ehdlr = NULL;
131 	struct epoll_event epevent = {0};
132 	int rc;
133 	int ret = 0;
134 
135 	/* Hoist the fds from the child up into the parent */
136 	TAILQ_FOREACH(ehdlr, &grp->event_handlers, next) {
137 		epevent.events = ehdlr->events;
138 		epevent.data.ptr = ehdlr;
139 		rc = epoll_ctl(epfd, EPOLL_CTL_ADD, ehdlr->fd, &epevent);
140 		if (rc < 0) {
141 			if (errno == EEXIST) {
142 				/* This is treated as success */
143 				continue;
144 			}
145 
146 			ret = -errno;
147 			SPDK_ERRLOG("Failed to add fd to fd group: %s\n", strerror(errno));
148 			goto recover;
149 		}
150 	}
151 
152 	return 0;
153 
154 recover:
155 	/* We failed to add everything, so try to remove what we did add. */
156 	TAILQ_FOREACH(ehdlr, &grp->event_handlers, next) {
157 		rc = epoll_ctl(epfd, EPOLL_CTL_DEL, ehdlr->fd, NULL);
158 		if (rc < 0) {
159 			if (errno == ENOENT) {
160 				/* This is treated as success. */
161 				continue;
162 			}
163 
164 
165 			/* Continue on even though we've failed. But indicate
166 			 * this is a fatal error. */
167 			SPDK_ERRLOG("Failed to recover fd_group_del_all: %s\n", strerror(errno));
168 			ret = -ENOTRECOVERABLE;
169 		}
170 	}
171 
172 	return ret;
173 }
174 
175 int
176 spdk_fd_group_unnest(struct spdk_fd_group *parent, struct spdk_fd_group *child)
177 {
178 	int rc;
179 
180 	if (parent == NULL || child == NULL) {
181 		return -EINVAL;
182 	}
183 
184 	if (child->parent != parent) {
185 		return -EINVAL;
186 	}
187 
188 	rc = _fd_group_del_all(parent->epfd, child);
189 	if (rc < 0) {
190 		return rc;
191 	}
192 
193 	child->parent = NULL;
194 
195 	return _fd_group_add_all(child->epfd, child);
196 }
197 
198 int
199 spdk_fd_group_nest(struct spdk_fd_group *parent, struct spdk_fd_group *child)
200 {
201 	int rc;
202 
203 	if (parent == NULL || child == NULL) {
204 		return -EINVAL;
205 	}
206 
207 	if (child->parent) {
208 		return -EINVAL;
209 	}
210 
211 	if (parent->parent) {
212 		/* More than one layer of nesting is not currently supported */
213 		assert(false);
214 		return -ENOTSUP;
215 	}
216 
217 	rc = _fd_group_del_all(child->epfd, child);
218 	if (rc < 0) {
219 		return rc;
220 	}
221 
222 	child->parent = parent;
223 
224 	return _fd_group_add_all(parent->epfd, child);
225 }
226 
227 int
228 spdk_fd_group_add(struct spdk_fd_group *fgrp, int efd, spdk_fd_fn fn,
229 		  void *arg, const char *name)
230 {
231 	struct event_handler *ehdlr = NULL;
232 	struct epoll_event epevent = {0};
233 	int rc;
234 	int epfd;
235 
236 	/* parameter checking */
237 	if (fgrp == NULL || efd < 0 || fn == NULL) {
238 		return -EINVAL;
239 	}
240 
241 	/* check if there is already one function registered for this fd */
242 	TAILQ_FOREACH(ehdlr, &fgrp->event_handlers, next) {
243 		if (ehdlr->fd == efd) {
244 			return -EEXIST;
245 		}
246 	}
247 
248 	/* create a new event src */
249 	ehdlr = calloc(1, sizeof(*ehdlr));
250 	if (ehdlr == NULL) {
251 		return -errno;
252 	}
253 
254 	ehdlr->fd = efd;
255 	ehdlr->fn = fn;
256 	ehdlr->fn_arg = arg;
257 	ehdlr->state = EVENT_HANDLER_STATE_WAITING;
258 	ehdlr->events = EPOLLIN;
259 	snprintf(ehdlr->name, sizeof(ehdlr->name), "%s", name);
260 
261 	if (fgrp->parent) {
262 		epfd = fgrp->parent->epfd;
263 	} else {
264 		epfd = fgrp->epfd;
265 	}
266 
267 	epevent.events = ehdlr->events;
268 	epevent.data.ptr = ehdlr;
269 	rc = epoll_ctl(epfd, EPOLL_CTL_ADD, efd, &epevent);
270 	if (rc < 0) {
271 		free(ehdlr);
272 		return -errno;
273 	}
274 
275 	TAILQ_INSERT_TAIL(&fgrp->event_handlers, ehdlr, next);
276 	fgrp->num_fds++;
277 
278 	return 0;
279 }
280 
281 void
282 spdk_fd_group_remove(struct spdk_fd_group *fgrp, int efd)
283 {
284 	struct event_handler *ehdlr;
285 	int rc;
286 	int epfd;
287 
288 	if (fgrp == NULL || efd < 0) {
289 		SPDK_ERRLOG("Invalid to remvoe efd(%d) from fd_group(%p).\n", efd, fgrp);
290 		assert(0);
291 		return;
292 	}
293 
294 
295 	TAILQ_FOREACH(ehdlr, &fgrp->event_handlers, next) {
296 		if (ehdlr->fd == efd) {
297 			break;
298 		}
299 	}
300 
301 	if (ehdlr == NULL) {
302 		SPDK_ERRLOG("efd(%d) is not existed in fgrp(%p)\n", efd, fgrp);
303 		return;
304 	}
305 
306 	assert(ehdlr->state != EVENT_HANDLER_STATE_REMOVED);
307 
308 	if (fgrp->parent) {
309 		epfd = fgrp->parent->epfd;
310 	} else {
311 		epfd = fgrp->epfd;
312 	}
313 
314 	rc = epoll_ctl(epfd, EPOLL_CTL_DEL, ehdlr->fd, NULL);
315 	if (rc < 0) {
316 		SPDK_ERRLOG("Failed to delete the fd(%d) from the epoll group(%p)\n", efd, fgrp);
317 		return;
318 	}
319 
320 	assert(fgrp->num_fds > 0);
321 	fgrp->num_fds--;
322 	TAILQ_REMOVE(&fgrp->event_handlers, ehdlr, next);
323 
324 	/* Delay ehdlr's free in case it is waiting for execution in fgrp wait loop */
325 	if (ehdlr->state == EVENT_HANDLER_STATE_RUNNING) {
326 		ehdlr->state = EVENT_HANDLER_STATE_REMOVED;
327 	} else {
328 		free(ehdlr);
329 	}
330 }
331 
332 int
333 spdk_fd_group_event_modify(struct spdk_fd_group *fgrp,
334 			   int efd, int event_types)
335 {
336 	struct epoll_event epevent;
337 	struct event_handler *ehdlr;
338 	int epfd;
339 
340 	if (fgrp == NULL || efd < 0) {
341 		return -EINVAL;
342 	}
343 
344 	TAILQ_FOREACH(ehdlr, &fgrp->event_handlers, next) {
345 		if (ehdlr->fd == efd) {
346 			break;
347 		}
348 	}
349 
350 	if (ehdlr == NULL) {
351 		return -EINVAL;
352 	}
353 
354 	assert(ehdlr->state != EVENT_HANDLER_STATE_REMOVED);
355 
356 	ehdlr->events = event_types;
357 
358 	if (fgrp->parent) {
359 		epfd = fgrp->parent->epfd;
360 	} else {
361 		epfd = fgrp->epfd;
362 	}
363 
364 	epevent.events = ehdlr->events;
365 	epevent.data.ptr = ehdlr;
366 
367 	return epoll_ctl(epfd, EPOLL_CTL_MOD, ehdlr->fd, &epevent);
368 }
369 
370 int
371 spdk_fd_group_create(struct spdk_fd_group **_egrp)
372 {
373 	struct spdk_fd_group *fgrp;
374 
375 	if (_egrp == NULL) {
376 		return -EINVAL;
377 	}
378 
379 	fgrp = calloc(1, sizeof(*fgrp));
380 	if (fgrp == NULL) {
381 		return -ENOMEM;
382 	}
383 
384 	/* init the event source head */
385 	TAILQ_INIT(&fgrp->event_handlers);
386 
387 	fgrp->num_fds = 0;
388 	fgrp->epfd = epoll_create1(EPOLL_CLOEXEC);
389 	if (fgrp->epfd < 0) {
390 		free(fgrp);
391 		return -errno;
392 	}
393 
394 	*_egrp = fgrp;
395 
396 	return 0;
397 }
398 
399 void
400 spdk_fd_group_destroy(struct spdk_fd_group *fgrp)
401 {
402 	if (fgrp == NULL || fgrp->num_fds > 0) {
403 		SPDK_ERRLOG("Invalid fd_group(%p) to destroy.\n", fgrp);
404 		assert(0);
405 		return;
406 	}
407 
408 	close(fgrp->epfd);
409 	free(fgrp);
410 
411 	return;
412 }
413 
414 int
415 spdk_fd_group_wait(struct spdk_fd_group *fgrp, int timeout)
416 {
417 	int totalfds = fgrp->num_fds;
418 	struct epoll_event events[totalfds];
419 	struct event_handler *ehdlr;
420 	int n;
421 	int nfds;
422 
423 	if (fgrp->parent != NULL) {
424 		if (timeout < 0) {
425 			SPDK_ERRLOG("Calling spdk_fd_group_wait on a group nested in another group without a timeout will block indefinitely.\n");
426 			assert(false);
427 			return -EINVAL;
428 		} else {
429 			SPDK_WARNLOG("Calling spdk_fd_group_wait on a group nested in another group will never find any events\n");
430 			return 0;
431 		}
432 	}
433 
434 	nfds = epoll_wait(fgrp->epfd, events, totalfds, timeout);
435 	if (nfds < 0) {
436 		if (errno != EINTR) {
437 			SPDK_ERRLOG("fgrp epoll_wait returns with fail. errno is %d\n", errno);
438 		}
439 
440 		return -errno;
441 	} else if (nfds == 0) {
442 		return 0;
443 	}
444 
445 	for (n = 0; n < nfds; n++) {
446 		/* find the event_handler */
447 		ehdlr = events[n].data.ptr;
448 
449 		if (ehdlr == NULL) {
450 			continue;
451 		}
452 
453 		/* Tag ehdlr as running state in case that it is removed
454 		 * during this wait loop but before or when it get executed.
455 		 */
456 		assert(ehdlr->state == EVENT_HANDLER_STATE_WAITING);
457 		ehdlr->state = EVENT_HANDLER_STATE_RUNNING;
458 	}
459 
460 	for (n = 0; n < nfds; n++) {
461 		/* find the event_handler */
462 		ehdlr = events[n].data.ptr;
463 
464 		if (ehdlr == NULL || ehdlr->fn == NULL) {
465 			continue;
466 		}
467 
468 		/* It is possible that the ehdlr was removed
469 		 * during this wait loop but before it get executed.
470 		 */
471 		if (ehdlr->state == EVENT_HANDLER_STATE_REMOVED) {
472 			free(ehdlr);
473 			continue;
474 		}
475 
476 		g_event = &events[n];
477 		/* call the interrupt response function */
478 		ehdlr->fn(ehdlr->fn_arg);
479 		g_event = NULL;
480 
481 		/* It is possible that the ehdlr was removed
482 		 * during this wait loop when it get executed.
483 		 */
484 		if (ehdlr->state == EVENT_HANDLER_STATE_REMOVED) {
485 			free(ehdlr);
486 		} else {
487 			ehdlr->state = EVENT_HANDLER_STATE_WAITING;
488 		}
489 	}
490 
491 	return nfds;
492 }
493 
494 #else
495 
496 int
497 spdk_fd_group_get_epoll_event(struct epoll_event *event)
498 {
499 	return -ENOTSUP;
500 }
501 
502 int
503 spdk_fd_group_add(struct spdk_fd_group *fgrp, int efd, spdk_fd_fn fn,
504 		  void *arg, const char *name)
505 {
506 	return -ENOTSUP;
507 }
508 
509 void
510 spdk_fd_group_remove(struct spdk_fd_group *fgrp, int efd)
511 {
512 }
513 
514 int
515 spdk_fd_group_event_modify(struct spdk_fd_group *fgrp,
516 			   int efd, int event_types)
517 {
518 	return -ENOTSUP;
519 }
520 
521 int
522 spdk_fd_group_create(struct spdk_fd_group **fgrp)
523 {
524 	return -ENOTSUP;
525 }
526 
527 void
528 spdk_fd_group_destroy(struct spdk_fd_group *fgrp)
529 {
530 }
531 
532 int
533 spdk_fd_group_wait(struct spdk_fd_group *fgrp, int timeout)
534 {
535 	return -ENOTSUP;
536 }
537 
538 int
539 spdk_fd_group_unnest(struct spdk_fd_group *parent, struct spdk_fd_group *child)
540 {
541 	return -ENOTSUP;
542 }
543 
544 int
545 spdk_fd_group_nest(struct spdk_fd_group *parent, struct spdk_fd_group *child)
546 {
547 	return -ENOTSUP;
548 }
549 
550 #endif
551