Home | History | Annotate | Download | only in src
      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