Commit 9c3060bedd84144653a2ad7bea32389f65598d40

Authored by Davide Libenzi
Committed by Linus Torvalds
1 parent fdb902b122

signal/timer/event: KAIO eventfd support example

This is an example about how to add eventfd support to the current KAIO code,
in order to enable KAIO to post readiness events to a pollable fd (hence
compatible with POSIX select/poll).  The KAIO code simply signals the eventfd
fd when events are ready, and this triggers a POLLIN in the fd.  This patch
uses a reserved for future use member of the struct iocb to pass an eventfd
file descriptor, that KAIO will use to post events every time a request
completes.  At that point, an aio_getevents() will return the completed result
to a struct io_event.  I made a quick test program to verify the patch, and it
runs fine here:

http://www.xmailserver.org/eventfd-aio-test.c

The test program uses poll(2), but it'd, of course, work with select and epoll
too.

This can allow to schedule both block I/O and other poll-able devices
requests, and wait for results using select/poll/epoll.  In a typical
scenario, an application would submit KAIO request using aio_submit(), and
will also use epoll_ctl() on the whole other class of devices (that with the
addition of signals, timers and user events, now it's pretty much complete),
and then would:

	epoll_wait(...);
	for_each_event {
		if (curr_event_is_kaiofd) {
			aio_getevents();
			dispatch_aio_events();
		} else {
			dispatch_epoll_event();
		}
	}

Signed-off-by: Davide Libenzi <davidel@xmailserver.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

Showing 3 changed files with 49 additions and 3 deletions Side-by-side Diff

... ... @@ -30,6 +30,7 @@
30 30 #include <linux/highmem.h>
31 31 #include <linux/workqueue.h>
32 32 #include <linux/security.h>
  33 +#include <linux/eventfd.h>
33 34  
34 35 #include <asm/kmap_types.h>
35 36 #include <asm/uaccess.h>
... ... @@ -417,6 +418,7 @@
417 418 req->private = NULL;
418 419 req->ki_iovec = NULL;
419 420 INIT_LIST_HEAD(&req->ki_run_list);
  421 + req->ki_eventfd = ERR_PTR(-EINVAL);
420 422  
421 423 /* Check if the completion queue has enough free space to
422 424 * accept an event from this io.
... ... @@ -458,6 +460,8 @@
458 460 {
459 461 assert_spin_locked(&ctx->ctx_lock);
460 462  
  463 + if (!IS_ERR(req->ki_eventfd))
  464 + fput(req->ki_eventfd);
461 465 if (req->ki_dtor)
462 466 req->ki_dtor(req);
463 467 if (req->ki_iovec != &req->ki_inline_vec)
... ... @@ -942,6 +946,14 @@
942 946 return 1;
943 947 }
944 948  
  949 + /*
  950 + * Check if the user asked us to deliver the result through an
  951 + * eventfd. The eventfd_signal() function is safe to be called
  952 + * from IRQ context.
  953 + */
  954 + if (!IS_ERR(iocb->ki_eventfd))
  955 + eventfd_signal(iocb->ki_eventfd, 1);
  956 +
945 957 info = &ctx->ring_info;
946 958  
947 959 /* add a completion event to the ring buffer.
... ... @@ -1526,8 +1538,7 @@
1526 1538 ssize_t ret;
1527 1539  
1528 1540 /* enforce forwards compatibility on users */
1529   - if (unlikely(iocb->aio_reserved1 || iocb->aio_reserved2 ||
1530   - iocb->aio_reserved3)) {
  1541 + if (unlikely(iocb->aio_reserved1 || iocb->aio_reserved2)) {
1531 1542 pr_debug("EINVAL: io_submit: reserve field set\n");
1532 1543 return -EINVAL;
1533 1544 }
... ... @@ -1550,6 +1561,19 @@
1550 1561 if (unlikely(!req)) {
1551 1562 fput(file);
1552 1563 return -EAGAIN;
  1564 + }
  1565 + if (iocb->aio_flags & IOCB_FLAG_RESFD) {
  1566 + /*
  1567 + * If the IOCB_FLAG_RESFD flag of aio_flags is set, get an
  1568 + * instance of the file* now. The file descriptor must be
  1569 + * an eventfd() fd, and will be signaled for each completed
  1570 + * event using the eventfd_signal() function.
  1571 + */
  1572 + req->ki_eventfd = eventfd_fget((int) iocb->aio_resfd);
  1573 + if (unlikely(IS_ERR(req->ki_eventfd))) {
  1574 + ret = PTR_ERR(req->ki_eventfd);
  1575 + goto out_put_req;
  1576 + }
1553 1577 }
1554 1578  
1555 1579 req->ki_filp = file;
... ... @@ -119,6 +119,12 @@
119 119  
120 120 struct list_head ki_list; /* the aio core uses this
121 121 * for cancellation */
  122 +
  123 + /*
  124 + * If the aio_resfd field of the userspace iocb is not zero,
  125 + * this is the underlying file* to deliver event to.
  126 + */
  127 + struct file *ki_eventfd;
122 128 };
123 129  
124 130 #define is_sync_kiocb(iocb) ((iocb)->ki_key == KIOCB_SYNC_KEY)
include/linux/aio_abi.h
... ... @@ -45,6 +45,14 @@
45 45 IOCB_CMD_PWRITEV = 8,
46 46 };
47 47  
  48 +/*
  49 + * Valid flags for the "aio_flags" member of the "struct iocb".
  50 + *
  51 + * IOCB_FLAG_RESFD - Set if the "aio_resfd" member of the "struct iocb"
  52 + * is valid.
  53 + */
  54 +#define IOCB_FLAG_RESFD (1 << 0)
  55 +
48 56 /* read() from /dev/aio returns these structures. */
49 57 struct io_event {
50 58 __u64 data; /* the data field from the iocb */
... ... @@ -84,7 +92,15 @@
84 92  
85 93 /* extra parameters */
86 94 __u64 aio_reserved2; /* TODO: use this for a (struct sigevent *) */
87   - __u64 aio_reserved3;
  95 +
  96 + /* flags for the "struct iocb" */
  97 + __u32 aio_flags;
  98 +
  99 + /*
  100 + * if the IOCB_FLAG_RESFD flag of "aio_flags" is set, this is an
  101 + * eventfd to signal AIO readiness to
  102 + */
  103 + __u32 aio_resfd;
88 104 }; /* 64 bytes */
89 105  
90 106 #undef IFBIG