Line data Source code
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 0 : spdk_fd_group_get_fd(struct spdk_fd_group *fgrp)
60 : {
61 0 : return fgrp->epfd;
62 : }
63 :
64 : #ifdef __linux__
65 :
66 : static __thread struct epoll_event *g_event = NULL;
67 :
68 : int
69 0 : spdk_fd_group_get_epoll_event(struct epoll_event *event)
70 : {
71 0 : if (g_event == NULL) {
72 0 : return -EINVAL;
73 : }
74 0 : *event = *g_event;
75 0 : return 0;
76 : }
77 :
78 : static int
79 0 : _fd_group_del_all(int epfd, struct spdk_fd_group *grp)
80 : {
81 0 : struct event_handler *ehdlr = NULL;
82 0 : struct epoll_event epevent = {0};
83 : int rc;
84 0 : int ret = 0;
85 :
86 0 : TAILQ_FOREACH(ehdlr, &grp->event_handlers, next) {
87 0 : rc = epoll_ctl(epfd, EPOLL_CTL_DEL, ehdlr->fd, NULL);
88 0 : if (rc < 0) {
89 0 : 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 0 : continue;
94 : }
95 :
96 0 : ret = -errno;
97 0 : SPDK_ERRLOG("Failed to remove fd %d from group: %s\n", ehdlr->fd, strerror(errno));
98 0 : goto recover;
99 : }
100 : }
101 :
102 0 : return 0;
103 :
104 0 : recover:
105 : /* We failed to remove everything. Let's try to get everything put back into
106 : * the original group. */
107 0 : TAILQ_FOREACH(ehdlr, &grp->event_handlers, next) {
108 0 : epevent.events = ehdlr->events;
109 0 : epevent.data.ptr = ehdlr;
110 0 : rc = epoll_ctl(epfd, EPOLL_CTL_ADD, ehdlr->fd, &epevent);
111 0 : if (rc < 0) {
112 0 : if (errno == EEXIST) {
113 : /* This is fine. Keep going. */
114 0 : continue;
115 : }
116 :
117 : /* Continue on even though we've failed. But indicate
118 : * this is a fatal error. */
119 0 : SPDK_ERRLOG("Failed to recover fd_group_del_all: %s\n", strerror(errno));
120 0 : ret = -ENOTRECOVERABLE;
121 : }
122 : }
123 :
124 0 : return ret;
125 : }
126 :
127 : static int
128 0 : _fd_group_add_all(int epfd, struct spdk_fd_group *grp)
129 : {
130 0 : struct event_handler *ehdlr = NULL;
131 0 : struct epoll_event epevent = {0};
132 : int rc;
133 0 : int ret = 0;
134 :
135 : /* Hoist the fds from the child up into the parent */
136 0 : TAILQ_FOREACH(ehdlr, &grp->event_handlers, next) {
137 0 : epevent.events = ehdlr->events;
138 0 : epevent.data.ptr = ehdlr;
139 0 : rc = epoll_ctl(epfd, EPOLL_CTL_ADD, ehdlr->fd, &epevent);
140 0 : if (rc < 0) {
141 0 : if (errno == EEXIST) {
142 : /* This is treated as success */
143 0 : continue;
144 : }
145 :
146 0 : ret = -errno;
147 0 : SPDK_ERRLOG("Failed to add fd to fd group: %s\n", strerror(errno));
148 0 : goto recover;
149 : }
150 : }
151 :
152 0 : return 0;
153 :
154 0 : recover:
155 : /* We failed to add everything, so try to remove what we did add. */
156 0 : TAILQ_FOREACH(ehdlr, &grp->event_handlers, next) {
157 0 : rc = epoll_ctl(epfd, EPOLL_CTL_DEL, ehdlr->fd, NULL);
158 0 : if (rc < 0) {
159 0 : if (errno == ENOENT) {
160 : /* This is treated as success. */
161 0 : continue;
162 : }
163 :
164 :
165 : /* Continue on even though we've failed. But indicate
166 : * this is a fatal error. */
167 0 : SPDK_ERRLOG("Failed to recover fd_group_del_all: %s\n", strerror(errno));
168 0 : ret = -ENOTRECOVERABLE;
169 : }
170 : }
171 :
172 0 : return ret;
173 : }
174 :
175 : int
176 0 : spdk_fd_group_unnest(struct spdk_fd_group *parent, struct spdk_fd_group *child)
177 : {
178 : int rc;
179 :
180 0 : if (parent == NULL || child == NULL) {
181 0 : return -EINVAL;
182 : }
183 :
184 0 : if (child->parent != parent) {
185 0 : return -EINVAL;
186 : }
187 :
188 0 : rc = _fd_group_del_all(parent->epfd, child);
189 0 : if (rc < 0) {
190 0 : return rc;
191 : }
192 :
193 0 : child->parent = NULL;
194 :
195 0 : return _fd_group_add_all(child->epfd, child);
196 : }
197 :
198 : int
199 0 : spdk_fd_group_nest(struct spdk_fd_group *parent, struct spdk_fd_group *child)
200 : {
201 : int rc;
202 :
203 0 : if (parent == NULL || child == NULL) {
204 0 : return -EINVAL;
205 : }
206 :
207 0 : if (child->parent) {
208 0 : return -EINVAL;
209 : }
210 :
211 0 : if (parent->parent) {
212 : /* More than one layer of nesting is not currently supported */
213 0 : assert(false);
214 : return -ENOTSUP;
215 : }
216 :
217 0 : rc = _fd_group_del_all(child->epfd, child);
218 0 : if (rc < 0) {
219 0 : return rc;
220 : }
221 :
222 0 : child->parent = parent;
223 :
224 0 : return _fd_group_add_all(parent->epfd, child);
225 : }
226 :
227 : int
228 59 : spdk_fd_group_add(struct spdk_fd_group *fgrp, int efd, spdk_fd_fn fn,
229 : void *arg, const char *name)
230 : {
231 59 : struct event_handler *ehdlr = NULL;
232 59 : struct epoll_event epevent = {0};
233 : int rc;
234 : int epfd;
235 :
236 : /* parameter checking */
237 59 : if (fgrp == NULL || efd < 0 || fn == NULL) {
238 0 : return -EINVAL;
239 : }
240 :
241 : /* check if there is already one function registered for this fd */
242 96 : TAILQ_FOREACH(ehdlr, &fgrp->event_handlers, next) {
243 37 : if (ehdlr->fd == efd) {
244 0 : return -EEXIST;
245 : }
246 : }
247 :
248 : /* create a new event src */
249 59 : ehdlr = calloc(1, sizeof(*ehdlr));
250 59 : if (ehdlr == NULL) {
251 0 : return -errno;
252 : }
253 :
254 59 : ehdlr->fd = efd;
255 59 : ehdlr->fn = fn;
256 59 : ehdlr->fn_arg = arg;
257 59 : ehdlr->state = EVENT_HANDLER_STATE_WAITING;
258 59 : ehdlr->events = EPOLLIN;
259 59 : snprintf(ehdlr->name, sizeof(ehdlr->name), "%s", name);
260 :
261 59 : if (fgrp->parent) {
262 0 : epfd = fgrp->parent->epfd;
263 : } else {
264 59 : epfd = fgrp->epfd;
265 : }
266 :
267 59 : epevent.events = ehdlr->events;
268 59 : epevent.data.ptr = ehdlr;
269 59 : rc = epoll_ctl(epfd, EPOLL_CTL_ADD, efd, &epevent);
270 59 : if (rc < 0) {
271 0 : free(ehdlr);
272 0 : return -errno;
273 : }
274 :
275 59 : TAILQ_INSERT_TAIL(&fgrp->event_handlers, ehdlr, next);
276 59 : fgrp->num_fds++;
277 :
278 59 : return 0;
279 : }
280 :
281 : void
282 59 : 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 59 : if (fgrp == NULL || efd < 0) {
289 0 : SPDK_ERRLOG("Invalid to remvoe efd(%d) from fd_group(%p).\n", efd, fgrp);
290 0 : assert(0);
291 : return;
292 : }
293 :
294 :
295 93 : TAILQ_FOREACH(ehdlr, &fgrp->event_handlers, next) {
296 93 : if (ehdlr->fd == efd) {
297 59 : break;
298 : }
299 : }
300 :
301 59 : if (ehdlr == NULL) {
302 0 : SPDK_ERRLOG("efd(%d) is not existed in fgrp(%p)\n", efd, fgrp);
303 0 : return;
304 : }
305 :
306 59 : assert(ehdlr->state != EVENT_HANDLER_STATE_REMOVED);
307 :
308 59 : if (fgrp->parent) {
309 0 : epfd = fgrp->parent->epfd;
310 : } else {
311 59 : epfd = fgrp->epfd;
312 : }
313 :
314 59 : rc = epoll_ctl(epfd, EPOLL_CTL_DEL, ehdlr->fd, NULL);
315 59 : if (rc < 0) {
316 0 : SPDK_ERRLOG("Failed to delete the fd(%d) from the epoll group(%p)\n", efd, fgrp);
317 0 : return;
318 : }
319 :
320 59 : assert(fgrp->num_fds > 0);
321 59 : fgrp->num_fds--;
322 59 : 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 59 : if (ehdlr->state == EVENT_HANDLER_STATE_RUNNING) {
326 0 : ehdlr->state = EVENT_HANDLER_STATE_REMOVED;
327 : } else {
328 59 : free(ehdlr);
329 : }
330 : }
331 :
332 : int
333 0 : spdk_fd_group_event_modify(struct spdk_fd_group *fgrp,
334 : int efd, int event_types)
335 : {
336 0 : struct epoll_event epevent;
337 : struct event_handler *ehdlr;
338 : int epfd;
339 :
340 0 : if (fgrp == NULL || efd < 0) {
341 0 : return -EINVAL;
342 : }
343 :
344 0 : TAILQ_FOREACH(ehdlr, &fgrp->event_handlers, next) {
345 0 : if (ehdlr->fd == efd) {
346 0 : break;
347 : }
348 : }
349 :
350 0 : if (ehdlr == NULL) {
351 0 : return -EINVAL;
352 : }
353 :
354 0 : assert(ehdlr->state != EVENT_HANDLER_STATE_REMOVED);
355 :
356 0 : ehdlr->events = event_types;
357 :
358 0 : if (fgrp->parent) {
359 0 : epfd = fgrp->parent->epfd;
360 : } else {
361 0 : epfd = fgrp->epfd;
362 : }
363 :
364 0 : epevent.events = ehdlr->events;
365 0 : epevent.data.ptr = ehdlr;
366 :
367 0 : return epoll_ctl(epfd, EPOLL_CTL_MOD, ehdlr->fd, &epevent);
368 : }
369 :
370 : int
371 28 : spdk_fd_group_create(struct spdk_fd_group **_egrp)
372 : {
373 : struct spdk_fd_group *fgrp;
374 :
375 28 : if (_egrp == NULL) {
376 0 : return -EINVAL;
377 : }
378 :
379 28 : fgrp = calloc(1, sizeof(*fgrp));
380 28 : if (fgrp == NULL) {
381 0 : return -ENOMEM;
382 : }
383 :
384 : /* init the event source head */
385 28 : TAILQ_INIT(&fgrp->event_handlers);
386 :
387 28 : fgrp->num_fds = 0;
388 28 : fgrp->epfd = epoll_create1(EPOLL_CLOEXEC);
389 28 : if (fgrp->epfd < 0) {
390 0 : free(fgrp);
391 0 : return -errno;
392 : }
393 :
394 28 : *_egrp = fgrp;
395 :
396 28 : return 0;
397 : }
398 :
399 : void
400 28 : spdk_fd_group_destroy(struct spdk_fd_group *fgrp)
401 : {
402 28 : if (fgrp == NULL || fgrp->num_fds > 0) {
403 0 : SPDK_ERRLOG("Invalid fd_group(%p) to destroy.\n", fgrp);
404 0 : assert(0);
405 : return;
406 : }
407 :
408 28 : close(fgrp->epfd);
409 28 : free(fgrp);
410 :
411 28 : return;
412 : }
413 :
414 : int
415 6 : spdk_fd_group_wait(struct spdk_fd_group *fgrp, int timeout)
416 6 : {
417 6 : int totalfds = fgrp->num_fds;
418 6 : struct epoll_event events[totalfds];
419 : struct event_handler *ehdlr;
420 : int n;
421 : int nfds;
422 :
423 6 : if (fgrp->parent != NULL) {
424 0 : if (timeout < 0) {
425 0 : SPDK_ERRLOG("Calling spdk_fd_group_wait on a group nested in another group without a timeout will block indefinitely.\n");
426 0 : assert(false);
427 : return -EINVAL;
428 : } else {
429 0 : SPDK_WARNLOG("Calling spdk_fd_group_wait on a group nested in another group will never find any events\n");
430 0 : return 0;
431 : }
432 : }
433 :
434 6 : nfds = epoll_wait(fgrp->epfd, events, totalfds, timeout);
435 6 : if (nfds < 0) {
436 0 : if (errno != EINTR) {
437 0 : SPDK_ERRLOG("fgrp epoll_wait returns with fail. errno is %d\n", errno);
438 : }
439 :
440 0 : return -errno;
441 6 : } else if (nfds == 0) {
442 2 : return 0;
443 : }
444 :
445 8 : for (n = 0; n < nfds; n++) {
446 : /* find the event_handler */
447 4 : ehdlr = events[n].data.ptr;
448 :
449 4 : if (ehdlr == NULL) {
450 0 : 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 4 : assert(ehdlr->state == EVENT_HANDLER_STATE_WAITING);
457 4 : ehdlr->state = EVENT_HANDLER_STATE_RUNNING;
458 : }
459 :
460 8 : for (n = 0; n < nfds; n++) {
461 : /* find the event_handler */
462 4 : ehdlr = events[n].data.ptr;
463 :
464 4 : if (ehdlr == NULL || ehdlr->fn == NULL) {
465 0 : continue;
466 : }
467 :
468 : /* It is possible that the ehdlr was removed
469 : * during this wait loop but before it get executed.
470 : */
471 4 : if (ehdlr->state == EVENT_HANDLER_STATE_REMOVED) {
472 0 : free(ehdlr);
473 0 : continue;
474 : }
475 :
476 4 : g_event = &events[n];
477 : /* call the interrupt response function */
478 4 : ehdlr->fn(ehdlr->fn_arg);
479 4 : g_event = NULL;
480 :
481 : /* It is possible that the ehdlr was removed
482 : * during this wait loop when it get executed.
483 : */
484 4 : if (ehdlr->state == EVENT_HANDLER_STATE_REMOVED) {
485 0 : free(ehdlr);
486 : } else {
487 4 : ehdlr->state = EVENT_HANDLER_STATE_WAITING;
488 : }
489 : }
490 :
491 4 : 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
|