2 * Copyright 2015, Red Hat, Inc.
4 * This test remaps the aio ring buffer and ensures that I/O completions
5 * can still be reaped from userspace.
7 * Author: Jeff Moyer <jmoyer@redhat.com>
20 #define TEMPLATE "19.XXXXXX"
22 volatile sig_atomic_t timed_out = 0;
25 unsigned id; /* kernel internal index number */
26 unsigned nr; /* number of io_events */
27 volatile unsigned head;
28 volatile unsigned tail;
31 unsigned compat_features;
32 unsigned incompat_features;
33 unsigned header_length; /* size of aio_ring */
35 struct io_event io_events[0];
42 char template[sizeof(TEMPLATE)];
44 strncpy(template, TEMPLATE, sizeof(TEMPLATE));
45 fd = mkostemp(template, O_DIRECT);
55 * mmap will do the address space search for us. when remapping the ring,
56 * the use of MREMAP_FIXED will cause this mapping to be unmapped.
58 * len - length in bytes
60 * Returns the available virtual address, or MAP_FAILED on error.
63 find_unused_va(size_t len)
65 return mmap(0, len, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
69 alarm_handler(int __attribute__((unused))signo)
75 user_getevents(io_context_t ctx, int nr_events, struct io_event *event)
77 struct aio_ring *ring = (void *)ctx;
81 signal(SIGALRM, alarm_handler);
84 while ((completed < nr_events) && !timed_out) {
87 if (ring->head == ring->tail) {
92 new_head = ring->head;
93 *event = ring->io_events[new_head];
96 ring->head = new_head;
101 signal(SIGALRM, SIG_DFL);
107 remap_ring(struct aio_ring *ring)
109 struct aio_ring *new_ring;
113 * No need to round up to page size as ring->nr was adjusted
114 * already to fill the last page in the ring.
116 ring_size = sizeof(struct aio_ring) + ring->nr * sizeof(struct io_event);
121 new_ring = find_unused_va(ring_size);
122 if (new_ring == MAP_FAILED) {
123 fprintf(stderr, "Unable to find suitable va for ring\n");
127 new_ring = mremap(ring, ring_size, ring_size,
128 MREMAP_FIXED|MREMAP_MAYMOVE, new_ring);
129 if (new_ring == MAP_FAILED || new_ring == ring) {
138 remap_io_context(io_context_t ctx)
140 struct aio_ring *ring, *new_ring;
143 new_ring = remap_ring(ring);
147 ctx = (io_context_t)new_ring;
152 do_io(io_context_t ctx, struct iocb *iocbp, int fd)
157 io_prep_pwrite(iocbp, fd, buf, BUFLEN, 0);
158 ret = io_submit(ctx, 1, &iocbp);
160 fprintf(stderr, "io_submit failed with %d\n", ret);
167 check_completion(io_context_t ctx, struct iocb *iocbp)
170 struct io_event event;
172 ret = user_getevents(ctx, 1, &event);
174 fprintf(stderr, "user_getevents timed out.\n");
178 if (event.obj != iocbp) {
180 "Error: event->opj (%p) does not match iocbp (%p)\n",
196 memset(&ctx, 0, sizeof(ctx));
197 fd = open_temp_file();
199 ret = io_setup(1, &ctx);
201 fprintf(stderr, "io_setup failed with %d\n", ret);
206 * First, try remapping the ring buffer in-between io_setup and
209 ctx = remap_io_context(ctx);
213 ret = do_io(ctx, &iocb, fd);
217 ret = check_completion(ctx, &iocb);
222 * Now remap the ring in between io_submit and getevents.
224 ret = do_io(ctx, &iocb, fd);
228 ctx = remap_io_context(ctx);
232 ret = check_completion(ctx, &iocb);
239 ret = io_destroy(ctx);
241 fprintf(stderr, "io_destroy failed with %d\n", ret);