2 * aio-dio-extend-stat - test race in dio aio completion
3 * Copyright (C) 2006 Rafal Wijata
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
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
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
24 #include <sys/types.h>
33 #define O_DIRECT 040000 /* direct disk access hint */
37 * This was originally submitted to
38 * http://bugzilla.kernel.org/show_bug.cgi?id=6831 by
39 * Rafal Wijata <wijata@nec-labs.com>. It caught a race in dio aio completion
40 * that would call aio_complete() before the dio callers would update i_size.
41 * A stat after io_getevents() would not see the new file size.
43 * The bug was fixed in the fs/direct-io.c completion reworking that appeared
44 * in 2.6.20. This test should fail on 2.6.19.
49 static unsigned char buf[BUFSIZE] __attribute((aligned (4096)));
52 * this was arbitrarily chosen to take about two seconds on a dual athlon in a
53 * debugging kernel.. it trips up long before that.
55 #define MAX_AIO_EVENTS 4000
57 #define fail(fmt , args...) do {\
58 printf(fmt , ##args); \
62 void fun_write1(void* ptr);
63 void fun_writeN(void* ptr);
64 void fun_read(void* ptr);
68 struct iocb *iocbs[MAX_AIO_EVENTS];
69 struct io_event ioevents[MAX_AIO_EVENTS];
71 int main(int argc, char **argv)
73 pthread_t thread_read;
74 pthread_t thread_write;
79 fail("only arg should be file name\n");
81 for (i = 0; i < BUFSIZE; ++i)
82 buf[i] = 'A' + (char)(i % ('Z'-'A'+1));
84 buf[BUFSIZE-1] = '\n';
86 handle = open(argv[1], O_CREAT | O_TRUNC | O_DIRECT | O_RDWR, 0600);
88 fail("failed to open test file %s, errno: %d\n",
91 memset(&ctxp, 0, sizeof(ctxp));
92 ret = io_setup(MAX_AIO_EVENTS, &ctxp);
94 fail("io_setup returned %d\n", ret);
96 for (i = 0; i < MAX_AIO_EVENTS; ++i) {
98 iocbs[i] = calloc(1, sizeof(struct iocb));
100 fail("failed to allocate an iocb\n");
102 /* iocbs[i]->data = i; */
103 iocbs[i]->aio_fildes = handle;
104 iocbs[i]->aio_lio_opcode = IO_CMD_PWRITE;
105 iocbs[i]->aio_reqprio = 0;
106 iocbs[i]->u.c.buf = buf;
107 iocbs[i]->u.c.nbytes = BUFSIZE;
108 iocbs[i]->u.c.offset = BUFSIZE*i;
111 pthread_create(&thread_read, NULL, (void*)&fun_read, NULL);
112 pthread_create(&thread_write, NULL, (void*)&fun_writeN, NULL);
114 pthread_join(thread_read, NULL);
115 pthread_join(thread_write, NULL);
120 printf("%u iterations of racing extensions and collection passed\n",
126 void fun_read(void *ptr)
128 long n = MAX_AIO_EVENTS;
129 struct stat filestat;
135 r = io_getevents(ctxp, 1, MAX_AIO_EVENTS, ioevents, NULL);
137 fail("io_getevents returned %ld\n", r);
140 for (i = 0; i < r; ++i) {
141 struct io_event *event = &ioevents[i];
142 if (event->res != BUFSIZE)
143 fail("error in block: expected %d bytes, "
144 "received %ld\n", BUFSIZE,
145 event->obj->u.c.nbytes);
147 exSize = event->obj->u.c.offset + event->obj->u.c.nbytes;
148 fstat(handle, &filestat);
149 if (filestat.st_size < exSize)
150 fail("write of %lu bytes @%llu finished, "
151 "expected filesize at least %llu, but "
152 "got %lld\n", event->obj->u.c.nbytes,
153 event->obj->u.c.offset, exSize,
154 (long long)filestat.st_size);
159 void fun_writeN(void *ptr)
164 for(i = 0; i < MAX_AIO_EVENTS; ++i) {
165 ret = io_submit(ctxp, 1, &(iocbs[i]));
167 fail("io_subit returned %d instead of 1\n", ret);
171 void fun_write1(void *ptr)
175 ret = io_submit(ctxp, MAX_AIO_EVENTS, iocbs);
176 if (ret != MAX_AIO_EVENTS)
177 fail("io_subit returned %d instead of %u\n", ret,