1 #define __USE_GNU 2 #include <stdio.h> 3 #include <stdlib.h> 4 #include <unistd.h> 5 #include <sys/types.h> 6 #include <sys/stat.h> 7 #include <libaio.h> 8 #include <malloc.h> 9 #include <fcntl.h> 10 #include <pthread.h> 11 #include <errno.h> 12 13 #ifndef O_DIRECT 14 #define O_DIRECT 040000 /* direct disk access hint */ 15 #endif 16 17 18 /* 19 * This was originally submitted to 20 * http://bugzilla.kernel.org/show_bug.cgi?id=6831 by 21 * Rafal Wijata <wijata (at) nec-labs.com>. It caught a race in dio aio completion 22 * that would call aio_complete() before the dio callers would update i_size. 23 * A stat after io_getevents() would not see the new file size. 24 * 25 * The bug was fixed in the fs/direct-io.c completion reworking that appeared 26 * in 2.6.20. This test should fail on 2.6.19. 27 */ 28 29 #define BUFSIZE 1024 30 31 static unsigned char buf[BUFSIZE] __attribute((aligned (512))); 32 33 /* 34 * this was arbitrarily chosen to take about two seconds on a dual athlon in a 35 * debugging kernel.. it trips up long before that. 36 */ 37 #define MAX_AIO_EVENTS 4000 38 39 #define fail(fmt , args...) do {\ 40 printf(fmt , ##args); \ 41 exit(1); \ 42 } while (0) 43 44 void fun_write1(void* ptr); 45 void fun_writeN(void* ptr); 46 void fun_read(void* ptr); 47 48 int handle = 0; 49 io_context_t ctxp; 50 struct iocb *iocbs[MAX_AIO_EVENTS]; 51 struct io_event ioevents[MAX_AIO_EVENTS]; 52 53 volatile int submittedSize = 0; //synchronization 54 55 int main(int argc, char **argv) 56 { 57 pthread_t thread_read; 58 pthread_t thread_write; 59 int i; 60 int ret; 61 62 if (argc != 2) 63 fail("only arg should be file name\n"); 64 65 for (i = 0; i < BUFSIZE; ++i) 66 buf[i] = 'A' + (char)(i % ('Z'-'A'+1)); 67 68 buf[BUFSIZE-1] = '\n'; 69 70 handle = open(argv[1], O_CREAT | O_TRUNC | O_DIRECT | O_RDWR, 0600); 71 if (handle == -1) 72 fail("failed to open test file %s, errno: %d\n", 73 argv[1], errno); 74 75 memset(&ctxp, 0, sizeof(ctxp)); 76 ret = io_setup(MAX_AIO_EVENTS, &ctxp); 77 if (ret) 78 fail("io_setup returned %d\n", ret); 79 80 for (i = 0; i < MAX_AIO_EVENTS; ++i) { 81 82 iocbs[i] = calloc(1, sizeof(struct iocb)); 83 if (iocbs[i] == NULL) 84 fail("failed to allocate an iocb\n"); 85 86 /* iocbs[i]->data = i; */ 87 iocbs[i]->aio_fildes = handle; 88 iocbs[i]->aio_lio_opcode = IO_CMD_PWRITE; 89 iocbs[i]->aio_reqprio = 0; 90 iocbs[i]->u.c.buf = buf; 91 iocbs[i]->u.c.nbytes = BUFSIZE; 92 iocbs[i]->u.c.offset = BUFSIZE*i; 93 } 94 95 pthread_create(&thread_read, NULL, (void*)&fun_read, NULL); 96 pthread_create(&thread_write, NULL, (void*)&fun_writeN, NULL); 97 98 pthread_join(thread_read, NULL); 99 pthread_join(thread_write, NULL); 100 101 io_destroy(ctxp); 102 close(handle); 103 104 printf("%u iterations of racing extensions and collection passed\n", 105 MAX_AIO_EVENTS); 106 107 return 0; 108 } 109 110 void fun_read(void *ptr) 111 { 112 long n = MAX_AIO_EVENTS; 113 struct stat filestat; 114 long long exSize; 115 long i; 116 long r; 117 118 while (n > 0) { 119 r = io_getevents(ctxp, 1, MAX_AIO_EVENTS, ioevents, NULL); 120 if (r < 0) 121 fail("io_getevents returned %ld\n", r); 122 123 n -= r; 124 for (i = 0; i < r; ++i) { 125 if (ioevents[i].obj->u.c.nbytes != BUFSIZE) 126 fail("error in block: expacted %d bytes, " 127 "receiced %ld\n", BUFSIZE, 128 ioevents[i].obj->u.c.nbytes); 129 130 exSize = ioevents[i].obj->u.c.offset + 131 ioevents[i].obj->u.c.nbytes; 132 fstat(handle, &filestat); 133 if (filestat.st_size < exSize) 134 fail("write of %lu bytes @%llu finished, " 135 "expected filesize at least %llu, but " 136 "got %ld\n", ioevents[i].obj->u.c.nbytes, 137 ioevents[i].obj->u.c.offset, exSize, 138 filestat.st_size); 139 } 140 } 141 } 142 143 void fun_writeN(void *ptr) 144 { 145 int i; 146 int ret; 147 148 for(i = 0; i < MAX_AIO_EVENTS; ++i) { 149 ret = io_submit(ctxp, 1, &(iocbs[i])); 150 if (ret != 1) 151 fail("io_subit returned %d instead of 1\n", ret); 152 } 153 } 154 155 void fun_write1(void *ptr) 156 { 157 int ret; 158 159 ret = io_submit(ctxp, MAX_AIO_EVENTS, iocbs); 160 if (ret != MAX_AIO_EVENTS) 161 fail("io_subit returned %d instead of %u\n", ret, 162 MAX_AIO_EVENTS); 163 } 164