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 : #include "spdk/util.h"
12 :
13 : #include "spdk/fd_group.h"
14 :
15 : #define SPDK_MAX_EVENT_NAME_LEN 256
16 :
17 : enum event_handler_state {
18 : /* The event_handler is added into an fd_group waiting for event,
19 : * but not currently in the execution of a wait loop.
20 : */
21 : EVENT_HANDLER_STATE_WAITING,
22 :
23 : /* The event_handler is currently in the execution of a wait loop. */
24 : EVENT_HANDLER_STATE_RUNNING,
25 :
26 : /* The event_handler was removed during the execution of a wait loop. */
27 : EVENT_HANDLER_STATE_REMOVED,
28 : };
29 :
30 : /* Taking "ehdlr" as short name for file descriptor handler of the interrupt event. */
31 : struct event_handler {
32 : TAILQ_ENTRY(event_handler) next;
33 : enum event_handler_state state;
34 :
35 : spdk_fd_fn fn;
36 : void *fn_arg;
37 : /* file descriptor of the interrupt event */
38 : int fd;
39 : uint32_t events;
40 : uint32_t fd_type;
41 : char name[SPDK_MAX_EVENT_NAME_LEN + 1];
42 : };
43 :
44 : struct spdk_fd_group {
45 : int epfd;
46 :
47 : /* Number of fds registered in this group. The epoll file descriptor of this fd group
48 : * i.e. epfd waits for interrupt event on all the fds from its interrupt sources list, as
49 : * well as from all its children fd group interrupt sources list.
50 : */
51 : uint32_t num_fds;
52 :
53 : struct spdk_fd_group *parent;
54 :
55 : /* interrupt sources list */
56 : TAILQ_HEAD(, event_handler) event_handlers;
57 : };
58 :
59 : int
60 0 : spdk_fd_group_get_fd(struct spdk_fd_group *fgrp)
61 : {
62 0 : return fgrp->epfd;
63 : }
64 :
65 : #ifdef __linux__
66 :
67 : static __thread struct epoll_event *g_event = NULL;
68 :
69 : int
70 0 : spdk_fd_group_get_epoll_event(struct epoll_event *event)
71 : {
72 0 : if (g_event == NULL) {
73 0 : return -EINVAL;
74 : }
75 0 : *event = *g_event;
76 0 : return 0;
77 : }
78 :
79 : static int
80 2 : _fd_group_del_all(int epfd, struct spdk_fd_group *grp)
81 : {
82 2 : struct event_handler *ehdlr = NULL;
83 2 : struct epoll_event epevent = {0};
84 : int rc;
85 2 : int ret = 0;
86 :
87 5 : TAILQ_FOREACH(ehdlr, &grp->event_handlers, next) {
88 3 : rc = epoll_ctl(epfd, EPOLL_CTL_DEL, ehdlr->fd, NULL);
89 3 : if (rc < 0) {
90 0 : if (errno == ENOENT) {
91 : /* This is treated as success. It happens if there are multiple
92 : * attempts to remove fds from the group.
93 : */
94 0 : continue;
95 : }
96 :
97 0 : ret = -errno;
98 0 : SPDK_ERRLOG("Failed to remove fd: %d from group: %s\n",
99 : ehdlr->fd, strerror(errno));
100 0 : goto recover;
101 : }
102 3 : ret++;
103 : }
104 :
105 2 : return ret;
106 :
107 0 : recover:
108 : /* We failed to remove everything. Let's try to put everything back into
109 : * the original group. */
110 0 : TAILQ_FOREACH(ehdlr, &grp->event_handlers, next) {
111 0 : epevent.events = ehdlr->events;
112 0 : epevent.data.ptr = ehdlr;
113 0 : rc = epoll_ctl(epfd, EPOLL_CTL_ADD, ehdlr->fd, &epevent);
114 0 : if (rc < 0) {
115 0 : if (errno == EEXIST) {
116 : /* This is fine. Keep going. */
117 0 : continue;
118 : }
119 :
120 : /* Continue on even though we've failed. But indicate
121 : * this is a fatal error. */
122 0 : SPDK_ERRLOG("Failed to recover fd_group_del_all: %s\n", strerror(errno));
123 0 : ret = -ENOTRECOVERABLE;
124 : }
125 : }
126 :
127 0 : return ret;
128 : }
129 :
130 : static int
131 2 : _fd_group_add_all(int epfd, struct spdk_fd_group *grp)
132 : {
133 2 : struct event_handler *ehdlr = NULL;
134 2 : struct epoll_event epevent = {0};
135 : int rc;
136 2 : int ret = 0;
137 :
138 : /* Hoist the fds from the child up into the parent */
139 5 : TAILQ_FOREACH(ehdlr, &grp->event_handlers, next) {
140 3 : epevent.events = ehdlr->events;
141 3 : epevent.data.ptr = ehdlr;
142 3 : rc = epoll_ctl(epfd, EPOLL_CTL_ADD, ehdlr->fd, &epevent);
143 3 : if (rc < 0) {
144 0 : if (errno == EEXIST) {
145 : /* This is treated as success */
146 0 : continue;
147 : }
148 :
149 0 : ret = -errno;
150 0 : SPDK_ERRLOG("Failed to add fd: %d to fd group: %s\n",
151 : ehdlr->fd, strerror(errno));
152 0 : goto recover;
153 : }
154 3 : ret++;
155 : }
156 :
157 2 : return ret;
158 :
159 0 : recover:
160 : /* We failed to add everything, so try to remove what we did add. */
161 0 : TAILQ_FOREACH(ehdlr, &grp->event_handlers, next) {
162 0 : rc = epoll_ctl(epfd, EPOLL_CTL_DEL, ehdlr->fd, NULL);
163 0 : if (rc < 0) {
164 0 : if (errno == ENOENT) {
165 : /* This is treated as success. */
166 0 : continue;
167 : }
168 :
169 :
170 : /* Continue on even though we've failed. But indicate
171 : * this is a fatal error. */
172 0 : SPDK_ERRLOG("Failed to recover fd_group_del_all: %s\n", strerror(errno));
173 0 : ret = -ENOTRECOVERABLE;
174 : }
175 : }
176 :
177 0 : return ret;
178 : }
179 :
180 : int
181 2 : spdk_fd_group_unnest(struct spdk_fd_group *parent, struct spdk_fd_group *child)
182 : {
183 : int rc;
184 :
185 2 : if (parent == NULL || child == NULL) {
186 0 : return -EINVAL;
187 : }
188 :
189 2 : if (child->parent != parent) {
190 1 : return -EINVAL;
191 : }
192 :
193 1 : rc = _fd_group_del_all(parent->epfd, child);
194 1 : if (rc < 0) {
195 0 : return rc;
196 : } else {
197 1 : assert(parent->num_fds >= (uint32_t)rc);
198 1 : parent->num_fds -= rc;
199 : }
200 :
201 1 : child->parent = NULL;
202 :
203 1 : rc = _fd_group_add_all(child->epfd, child);
204 1 : if (rc < 0) {
205 0 : return rc;
206 : } else {
207 1 : child->num_fds += rc;
208 : }
209 :
210 1 : return 0;
211 : }
212 :
213 : int
214 1 : spdk_fd_group_nest(struct spdk_fd_group *parent, struct spdk_fd_group *child)
215 : {
216 : int rc;
217 :
218 1 : if (parent == NULL || child == NULL) {
219 0 : return -EINVAL;
220 : }
221 :
222 1 : if (child->parent) {
223 0 : return -EINVAL;
224 : }
225 :
226 1 : if (parent->parent) {
227 : /* More than one layer of nesting is currently not supported */
228 0 : assert(false);
229 : return -ENOTSUP;
230 : }
231 :
232 1 : rc = _fd_group_del_all(child->epfd, child);
233 1 : if (rc < 0) {
234 0 : return rc;
235 : } else {
236 1 : assert(child->num_fds >= (uint32_t)rc);
237 1 : child->num_fds -= rc;
238 : }
239 :
240 1 : child->parent = parent;
241 :
242 1 : rc = _fd_group_add_all(parent->epfd, child);
243 1 : if (rc < 0) {
244 0 : return rc;
245 : } else {
246 1 : parent->num_fds += rc;
247 : }
248 :
249 1 : return 0;
250 : }
251 :
252 : void
253 142 : spdk_fd_group_get_default_event_handler_opts(struct spdk_event_handler_opts *opts,
254 : size_t opts_size)
255 : {
256 142 : if (!opts) {
257 0 : SPDK_ERRLOG("opts should not be NULL\n");
258 0 : return;
259 : }
260 :
261 142 : if (!opts_size) {
262 0 : SPDK_ERRLOG("opts_size should not be zero value\n");
263 0 : return;
264 : }
265 :
266 142 : memset(opts, 0, opts_size);
267 142 : opts->opts_size = opts_size;
268 :
269 : #define FIELD_OK(field) \
270 : offsetof(struct spdk_event_handler_opts, field) + sizeof(opts->field) <= opts_size
271 :
272 : #define SET_FIELD(field, value) \
273 : if (FIELD_OK(field)) { \
274 : opts->field = value; \
275 : } \
276 :
277 142 : SET_FIELD(events, EPOLLIN);
278 142 : SET_FIELD(fd_type, SPDK_FD_TYPE_DEFAULT);
279 :
280 : #undef FIELD_OK
281 : #undef SET_FIELD
282 : }
283 :
284 : static void
285 71 : event_handler_opts_copy(const struct spdk_event_handler_opts *src,
286 : struct spdk_event_handler_opts *dst)
287 : {
288 71 : if (!src->opts_size) {
289 0 : SPDK_ERRLOG("opts_size should not be zero value\n");
290 0 : assert(false);
291 : }
292 :
293 : #define FIELD_OK(field) \
294 : offsetof(struct spdk_event_handler_opts, field) + sizeof(src->field) <= src->opts_size
295 :
296 : #define SET_FIELD(field) \
297 : if (FIELD_OK(field)) { \
298 : dst->field = src->field; \
299 : } \
300 :
301 71 : SET_FIELD(events);
302 71 : SET_FIELD(fd_type);
303 :
304 71 : dst->opts_size = src->opts_size;
305 :
306 : /* You should not remove this statement, but need to update the assert statement
307 : * if you add a new field, and also add a corresponding SET_FIELD statement */
308 : SPDK_STATIC_ASSERT(sizeof(struct spdk_event_handler_opts) == 16, "Incorrect size");
309 :
310 : #undef FIELD_OK
311 : #undef SET_FIELD
312 71 : }
313 :
314 : int
315 71 : spdk_fd_group_add(struct spdk_fd_group *fgrp, int efd, spdk_fd_fn fn,
316 : void *arg, const char *name)
317 : {
318 71 : return spdk_fd_group_add_for_events(fgrp, efd, EPOLLIN, fn, arg, name);
319 : }
320 :
321 : int
322 71 : spdk_fd_group_add_for_events(struct spdk_fd_group *fgrp, int efd, uint32_t events,
323 : spdk_fd_fn fn, void *arg, const char *name)
324 : {
325 71 : struct spdk_event_handler_opts opts = {};
326 :
327 71 : spdk_fd_group_get_default_event_handler_opts(&opts, sizeof(opts));
328 71 : opts.events = events;
329 71 : opts.fd_type = SPDK_FD_TYPE_DEFAULT;
330 :
331 71 : return spdk_fd_group_add_ext(fgrp, efd, fn, arg, name, &opts);
332 : }
333 :
334 : int
335 71 : spdk_fd_group_add_ext(struct spdk_fd_group *fgrp, int efd, spdk_fd_fn fn, void *arg,
336 : const char *name, struct spdk_event_handler_opts *opts)
337 : {
338 71 : struct event_handler *ehdlr = NULL;
339 71 : struct epoll_event epevent = {0};
340 71 : struct spdk_event_handler_opts eh_opts = {};
341 : int rc;
342 : int epfd;
343 :
344 : /* parameter checking */
345 71 : if (fgrp == NULL || efd < 0 || fn == NULL) {
346 0 : return -EINVAL;
347 : }
348 :
349 71 : spdk_fd_group_get_default_event_handler_opts(&eh_opts, sizeof(eh_opts));
350 71 : if (opts) {
351 71 : event_handler_opts_copy(opts, &eh_opts);
352 : }
353 :
354 : /* check if there is already one function registered for this fd */
355 113 : TAILQ_FOREACH(ehdlr, &fgrp->event_handlers, next) {
356 42 : if (ehdlr->fd == efd) {
357 0 : return -EEXIST;
358 : }
359 : }
360 :
361 : /* create a new event src */
362 71 : ehdlr = calloc(1, sizeof(*ehdlr));
363 71 : if (ehdlr == NULL) {
364 0 : return -errno;
365 : }
366 :
367 71 : ehdlr->fd = efd;
368 71 : ehdlr->fn = fn;
369 71 : ehdlr->fn_arg = arg;
370 71 : ehdlr->state = EVENT_HANDLER_STATE_WAITING;
371 71 : ehdlr->events = eh_opts.events;
372 71 : ehdlr->fd_type = eh_opts.fd_type;
373 71 : snprintf(ehdlr->name, sizeof(ehdlr->name), "%s", name);
374 :
375 71 : if (fgrp->parent) {
376 1 : epfd = fgrp->parent->epfd;
377 : } else {
378 70 : epfd = fgrp->epfd;
379 : }
380 :
381 71 : epevent.events = ehdlr->events;
382 71 : epevent.data.ptr = ehdlr;
383 71 : rc = epoll_ctl(epfd, EPOLL_CTL_ADD, efd, &epevent);
384 71 : if (rc < 0) {
385 0 : SPDK_ERRLOG("Failed to add fd: %d to fd group(%p): %s\n",
386 : efd, fgrp, strerror(errno));
387 0 : free(ehdlr);
388 0 : return -errno;
389 : }
390 :
391 71 : TAILQ_INSERT_TAIL(&fgrp->event_handlers, ehdlr, next);
392 71 : if (fgrp->parent) {
393 1 : fgrp->parent->num_fds++;
394 : } else {
395 70 : fgrp->num_fds++;
396 : }
397 :
398 71 : return 0;
399 : }
400 :
401 : void
402 71 : spdk_fd_group_remove(struct spdk_fd_group *fgrp, int efd)
403 : {
404 : struct event_handler *ehdlr;
405 : int rc;
406 : int epfd;
407 :
408 71 : if (fgrp == NULL || efd < 0) {
409 0 : SPDK_ERRLOG("Cannot remove fd: %d from fd group(%p)\n", efd, fgrp);
410 0 : assert(0);
411 : return;
412 : }
413 :
414 :
415 109 : TAILQ_FOREACH(ehdlr, &fgrp->event_handlers, next) {
416 109 : if (ehdlr->fd == efd) {
417 71 : break;
418 : }
419 : }
420 :
421 71 : if (ehdlr == NULL) {
422 0 : SPDK_ERRLOG("fd: %d doesn't exist in fd group(%p)\n", efd, fgrp);
423 0 : return;
424 : }
425 :
426 71 : assert(ehdlr->state != EVENT_HANDLER_STATE_REMOVED);
427 :
428 71 : if (fgrp->parent) {
429 0 : epfd = fgrp->parent->epfd;
430 : } else {
431 71 : epfd = fgrp->epfd;
432 : }
433 :
434 71 : rc = epoll_ctl(epfd, EPOLL_CTL_DEL, ehdlr->fd, NULL);
435 71 : if (rc < 0) {
436 0 : SPDK_ERRLOG("Failed to remove fd: %d from fd group(%p): %s\n",
437 : ehdlr->fd, fgrp, strerror(errno));
438 0 : return;
439 : }
440 :
441 71 : if (fgrp->parent) {
442 0 : assert(fgrp->parent->num_fds > 0);
443 0 : fgrp->parent->num_fds--;
444 : } else {
445 71 : assert(fgrp->num_fds > 0);
446 71 : fgrp->num_fds--;
447 : }
448 71 : TAILQ_REMOVE(&fgrp->event_handlers, ehdlr, next);
449 :
450 : /* Delay ehdlr's free in case it is waiting for execution in fgrp wait loop */
451 71 : if (ehdlr->state == EVENT_HANDLER_STATE_RUNNING) {
452 0 : ehdlr->state = EVENT_HANDLER_STATE_REMOVED;
453 : } else {
454 71 : free(ehdlr);
455 : }
456 : }
457 :
458 : int
459 1 : spdk_fd_group_event_modify(struct spdk_fd_group *fgrp,
460 : int efd, int event_types)
461 : {
462 1 : struct epoll_event epevent;
463 : struct event_handler *ehdlr;
464 : int epfd;
465 :
466 1 : if (fgrp == NULL || efd < 0) {
467 0 : return -EINVAL;
468 : }
469 :
470 1 : TAILQ_FOREACH(ehdlr, &fgrp->event_handlers, next) {
471 1 : if (ehdlr->fd == efd) {
472 1 : break;
473 : }
474 : }
475 :
476 1 : if (ehdlr == NULL) {
477 0 : return -EINVAL;
478 : }
479 :
480 1 : assert(ehdlr->state != EVENT_HANDLER_STATE_REMOVED);
481 :
482 1 : ehdlr->events = event_types;
483 :
484 1 : if (fgrp->parent) {
485 0 : epfd = fgrp->parent->epfd;
486 : } else {
487 1 : epfd = fgrp->epfd;
488 : }
489 :
490 1 : epevent.events = ehdlr->events;
491 1 : epevent.data.ptr = ehdlr;
492 :
493 1 : return epoll_ctl(epfd, EPOLL_CTL_MOD, ehdlr->fd, &epevent);
494 : }
495 :
496 : int
497 44 : spdk_fd_group_create(struct spdk_fd_group **_egrp)
498 : {
499 : struct spdk_fd_group *fgrp;
500 :
501 44 : if (_egrp == NULL) {
502 0 : return -EINVAL;
503 : }
504 :
505 44 : fgrp = calloc(1, sizeof(*fgrp));
506 44 : if (fgrp == NULL) {
507 0 : return -ENOMEM;
508 : }
509 :
510 : /* init the event source head */
511 44 : TAILQ_INIT(&fgrp->event_handlers);
512 :
513 44 : fgrp->num_fds = 0;
514 44 : fgrp->epfd = epoll_create1(EPOLL_CLOEXEC);
515 44 : if (fgrp->epfd < 0) {
516 0 : free(fgrp);
517 0 : return -errno;
518 : }
519 :
520 44 : *_egrp = fgrp;
521 :
522 44 : return 0;
523 : }
524 :
525 : void
526 44 : spdk_fd_group_destroy(struct spdk_fd_group *fgrp)
527 : {
528 44 : if (fgrp == NULL || fgrp->num_fds > 0) {
529 0 : if (!fgrp) {
530 0 : SPDK_ERRLOG("fd_group doesn't exist.\n");
531 : } else {
532 0 : SPDK_ERRLOG("Cannot delete fd group(%p) as (%u) fds are still registered to it.\n",
533 : fgrp, fgrp->num_fds);
534 : }
535 0 : assert(0);
536 : return;
537 : }
538 :
539 : /* Check if someone tried to delete the fd group before unnesting it */
540 44 : if (!TAILQ_EMPTY(&fgrp->event_handlers)) {
541 0 : SPDK_ERRLOG("Interrupt sources list not empty.\n");
542 0 : assert(0);
543 : return;
544 : }
545 :
546 44 : close(fgrp->epfd);
547 44 : free(fgrp);
548 :
549 44 : return;
550 : }
551 :
552 : int
553 4 : spdk_fd_group_wait(struct spdk_fd_group *fgrp, int timeout)
554 4 : {
555 4 : uint32_t totalfds = fgrp->num_fds;
556 4 : struct epoll_event events[totalfds];
557 : struct event_handler *ehdlr;
558 4 : uint64_t count;
559 : int n;
560 : int nfds;
561 : int bytes_read;
562 : int read_errno;
563 :
564 4 : if (fgrp->parent != NULL) {
565 0 : if (timeout < 0) {
566 0 : SPDK_ERRLOG("Calling spdk_fd_group_wait on a group nested in another group without a timeout will block indefinitely.\n");
567 0 : assert(false);
568 : return -EINVAL;
569 : } else {
570 0 : SPDK_WARNLOG("Calling spdk_fd_group_wait on a group nested in another group will never find any events.\n");
571 0 : return 0;
572 : }
573 : }
574 :
575 4 : nfds = epoll_wait(fgrp->epfd, events, totalfds, timeout);
576 4 : if (nfds < 0) {
577 0 : if (errno != EINTR) {
578 0 : SPDK_ERRLOG("fd group(%p) epoll_wait failed: %s\n",
579 : fgrp, strerror(errno));
580 : }
581 :
582 0 : return -errno;
583 4 : } else if (nfds == 0) {
584 2 : return 0;
585 : }
586 :
587 4 : for (n = 0; n < nfds; n++) {
588 : /* find the event_handler */
589 2 : ehdlr = events[n].data.ptr;
590 :
591 2 : if (ehdlr == NULL) {
592 0 : continue;
593 : }
594 :
595 : /* Tag ehdlr as running state in case that it is removed
596 : * during this wait loop but before or when it get executed.
597 : */
598 2 : assert(ehdlr->state == EVENT_HANDLER_STATE_WAITING);
599 2 : ehdlr->state = EVENT_HANDLER_STATE_RUNNING;
600 : }
601 :
602 4 : for (n = 0; n < nfds; n++) {
603 : /* find the event_handler */
604 2 : ehdlr = events[n].data.ptr;
605 :
606 2 : if (ehdlr == NULL || ehdlr->fn == NULL) {
607 0 : continue;
608 : }
609 :
610 : /* It is possible that the ehdlr was removed
611 : * during this wait loop but before it get executed.
612 : */
613 2 : if (ehdlr->state == EVENT_HANDLER_STATE_REMOVED) {
614 0 : free(ehdlr);
615 0 : continue;
616 : }
617 :
618 2 : g_event = &events[n];
619 :
620 : /* read fd to reset the internal eventfd object counter value to 0 */
621 2 : if (ehdlr->fd_type == SPDK_FD_TYPE_EVENTFD) {
622 0 : bytes_read = read(ehdlr->fd, &count, sizeof(count));
623 0 : if (bytes_read < 0) {
624 0 : g_event = NULL;
625 0 : if (errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN) {
626 0 : continue;
627 : }
628 0 : read_errno = errno;
629 : /* TODO: Device is buggy. Handle this properly */
630 0 : SPDK_ERRLOG("Failed to read fd (%d) %s\n",
631 : ehdlr->fd, strerror(errno));
632 0 : return -read_errno;
633 0 : } else if (bytes_read == 0) {
634 0 : SPDK_ERRLOG("Read nothing from fd (%d)\n", ehdlr->fd);
635 0 : g_event = NULL;
636 0 : return -EINVAL;
637 : }
638 : }
639 :
640 : /* call the interrupt response function */
641 2 : ehdlr->fn(ehdlr->fn_arg);
642 2 : g_event = NULL;
643 :
644 : /* It is possible that the ehdlr was removed
645 : * during this wait loop when it get executed.
646 : */
647 2 : if (ehdlr->state == EVENT_HANDLER_STATE_REMOVED) {
648 0 : free(ehdlr);
649 : } else {
650 2 : ehdlr->state = EVENT_HANDLER_STATE_WAITING;
651 : }
652 : }
653 :
654 2 : return nfds;
655 : }
656 :
657 : #else /* !__linux__ */
658 :
659 : int
660 : spdk_fd_group_get_epoll_event(struct epoll_event *event)
661 : {
662 : return -ENOTSUP;
663 : }
664 :
665 : int
666 : spdk_fd_group_add(struct spdk_fd_group *fgrp, int efd, spdk_fd_fn fn,
667 : void *arg, const char *name)
668 : {
669 : return -ENOTSUP;
670 : }
671 :
672 : int
673 : spdk_fd_group_add_for_events(struct spdk_fd_group *fgrp, int efd, uint32_t events, spdk_fd_fn fn,
674 : void *arg, const char *name)
675 : {
676 : return -ENOTSUP;
677 : }
678 :
679 : int
680 : spdk_fd_group_add_ext(struct spdk_fd_group *fgrp, int efd, spdk_fd_fn fn, void *arg,
681 : const char *name, struct spdk_event_handler_opts *opts)
682 : {
683 : return -ENOTSUP;
684 : }
685 :
686 : void
687 : spdk_fd_group_get_default_event_handler_opts(struct spdk_event_handler_opts *opts,
688 : size_t opts_size)
689 : {
690 : assert(false);
691 : }
692 :
693 : void
694 : spdk_fd_group_remove(struct spdk_fd_group *fgrp, int efd)
695 : {
696 : }
697 :
698 : int
699 : spdk_fd_group_event_modify(struct spdk_fd_group *fgrp,
700 : int efd, int event_types)
701 : {
702 : return -ENOTSUP;
703 : }
704 :
705 : int
706 : spdk_fd_group_create(struct spdk_fd_group **fgrp)
707 : {
708 : return -ENOTSUP;
709 : }
710 :
711 : void
712 : spdk_fd_group_destroy(struct spdk_fd_group *fgrp)
713 : {
714 : }
715 :
716 : int
717 : spdk_fd_group_wait(struct spdk_fd_group *fgrp, int timeout)
718 : {
719 : return -ENOTSUP;
720 : }
721 :
722 : int
723 : spdk_fd_group_unnest(struct spdk_fd_group *parent, struct spdk_fd_group *child)
724 : {
725 : return -ENOTSUP;
726 : }
727 :
728 : int
729 : spdk_fd_group_nest(struct spdk_fd_group *parent, struct spdk_fd_group *child)
730 : {
731 : return -ENOTSUP;
732 : }
733 :
734 : #endif /* __linux__ */
|