2 * Copyright (C) 2014, Dan Aloni, Kernelim Ltd.
3 * Copyright (C) 2014, Benjamin LaHaise <bcrl@kvack.org>.
4 * Copyright (C) 2014, Red Hat, Inc.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
17 * This regression test ensures that submitting more events than can
18 * fit in the completion ring will not result in a hung task.
29 #include <sys/param.h>
31 #include <sys/types.h>
34 #include <sys/types.h>
40 const int max_events = 32;
41 const int io_size = 0x1000;
45 struct io_event *events;
52 #define SYS_IO_GETEVENTS 0
53 #define USER_GETEVENTS 1
55 static volatile sig_atomic_t done = 0;
58 unsigned id; /* kernel internal index number */
59 unsigned nr; /* number of io_events */
60 volatile unsigned head;
61 volatile unsigned tail;
64 unsigned compat_features;
65 unsigned incompat_features;
66 unsigned header_length; /* size of aio_ring */
68 struct io_event io_events[0];
71 int get_ring_size(int nr_events)
75 struct aio_ring *ring;
77 memset(&ctx, 0, sizeof(ctx));
78 ret = io_setup(nr_events, &ctx);
84 ret = io_destroy(ctx);
90 int user_getevents(io_context_t ctx, int nr_events, struct io_event *event)
92 struct aio_ring *ring = (void *)ctx;
94 while ((completed < nr_events) && (ring->head != ring->tail)) {
95 unsigned new_head = ring->head;
96 *event = ring->io_events[new_head];
99 ring->head = new_head;
105 void prune(io_context_t io_ctx, int max_ios, int getevents_type)
109 if (getevents_type == USER_GETEVENTS)
110 ret = user_getevents(io_ctx, max_ios, events);
112 ret = io_getevents(io_ctx, pending, max_ios, events, NULL);
114 printf("Completed: %d\n", ret);
120 void run_test(int max_ios, int getevents_type)
124 struct iocb **iocb_sub;
126 const char *filename = "testfile";
128 printf("MAX_IOS: %d, %s\n", max_ios, getevents_type == USER_GETEVENTS ?
129 "USER_GETEVENTS" : "IO_GETEVENTS");
130 memset(&io_ctx, 0, sizeof(io_ctx));
131 ret = io_setup(max_events, &io_ctx);
134 io = calloc(max_ios, sizeof(*io));
135 iops = calloc(max_ios, sizeof(*iops));
136 iovecs = calloc(max_ios, sizeof(*iovecs));
137 events = calloc(max_ios, sizeof(*events));
140 fd = open(filename, O_CREAT | O_RDWR, 0644);
144 * Use O_DIRECT if it's available. If it's not, the test code
145 * will still operate correctly, just potentially slower.
147 flags = fcntl(fd, F_GETFL, 0);
148 fcntl(fd, F_SETFL, flags | O_DIRECT);
150 ret = ftruncate(fd, max_ios * io_size);
153 data = mmap(NULL, io_size * max_ios, PROT_READ | PROT_WRITE,
154 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
155 assert(data != MAP_FAILED);
157 for (i = 0; i < max_ios; i++) {
160 iovecs[i].iov_base = &data[io_size * i];
161 iovecs[i].iov_len = io_size;
162 io_prep_preadv(&io[i], fd, &iovecs[i], 1, 0);
165 submitted = completed = pending = 0;
170 while (submitted < max_ios) {
171 printf("Submitting: %ld\n", to_submit);
173 ret = io_submit(io_ctx, to_submit, iocb_sub);
175 printf("Submitted: %d\n", ret);
181 if (ret == -EAGAIN) {
182 printf("Submitted too much, that's okay\n");
183 prune(io_ctx, max_ios, getevents_type);
188 prune(io_ctx, max_ios, getevents_type);
191 ret = munmap(data, io_size * max_ios);
194 printf("Verifying...\n");
196 assert(completed == submitted);
205 ring_size = get_ring_size(max_events);
207 printf("aio ring size: %d\n", ring_size);
209 run_test(ring_size-1, SYS_IO_GETEVENTS);
210 run_test(ring_size, SYS_IO_GETEVENTS);
211 run_test(ring_size+1, SYS_IO_GETEVENTS);
212 run_test(ring_size*2, SYS_IO_GETEVENTS);
213 run_test(ring_size*4, SYS_IO_GETEVENTS);
215 run_test(ring_size-1, USER_GETEVENTS);
216 run_test(ring_size, USER_GETEVENTS);
217 run_test(ring_size+1, USER_GETEVENTS);
218 run_test(ring_size*2, USER_GETEVENTS);
219 run_test(ring_size*4, USER_GETEVENTS);
224 void sighandler(int signo)
226 assert(signo == SIGCHLD);
233 sighandler_t oldhandler;
236 switch (child = fork()) {
244 oldhandler = signal(SIGCHLD, sighandler);
245 assert(oldhandler != SIG_ERR);
262 return WEXITSTATUS(status);
265 return 1; /* failed */