1 /*
2  *  Code taken from an example posted to linux-aio at kvack.org
3  *  Original Author: Drangon Zhou
4  *  Munged by Jeff Moyer to get it to build and to incorporate it into
5  *  the autotest framework.
6  *
7  *  Description:  This source code implements a test to ensure that an AIO
8  *  read of the last block in a file opened with O_DIRECT returns the proper
9  *  amount of data.  In the past, there was a bug that resulted in a return
10  *  value of the requested block size, when in fact there was only a fraction
11  *  of that data available.  Thus, if the last data block contained 300 bytes
12  *  worth of data, and the user issued a 4k read, we want to ensure that
13  *  the return value is 300, not 4k.
14  */
15 
16 #define _GNU_SOURCE
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <libaio.h>
20 #include <fcntl.h>
21 #include <unistd.h>
22 #include <errno.h>
23 
24 /* Create a file of a size that is not a multiple of block size */
25 #define FILE_SIZE	300
26 
27 #define fail(fmt , args...) 	\
28 do {				\
29 	printf(fmt , ##args);	\
30 	exit(1);		\
31 } while (0)
32 
33 static unsigned char buffer[4096] __attribute((aligned (512)));
34 
35 int
main(int argc,char ** argv)36 main(int argc, char **argv)
37 {
38 	int ret;
39 	int fd;
40 	const char *filename;
41 	struct iocb myiocb;
42 	struct iocb *cb = &myiocb;
43 	io_context_t ioctx;
44 	struct io_event ie;
45 
46 	if (argc != 2)
47 		fail("only arg should be file name");
48 
49 	filename = argv[1];
50 	fd = open(filename, O_CREAT|O_RDWR|O_DIRECT, 0600);
51 	if (fd < 0)
52 		fail("open returned error %d\n", errno);
53 
54 	ret = ftruncate(fd, FILE_SIZE);
55 	if (ret < 0)
56 		fail("truncate returned error %d\n", errno);
57 
58 	/* <1> use normal disk read, this should be ok */
59 	ret = read(fd, buffer, 4096);
60 	if (ret != FILE_SIZE)
61 		fail("buffered read returned %d, should be 300\n", ret);
62 
63 	/* <2> use AIO disk read, it sees error. */
64 	memset(&myiocb, 0, sizeof(myiocb));
65 	cb->data = 0;
66 	cb->key = 0;
67 	cb->aio_lio_opcode = IO_CMD_PREAD;
68 	cb->aio_reqprio = 0;
69 	cb->aio_fildes = fd;
70 	cb->u.c.buf = buffer;
71 	cb->u.c.nbytes = 4096;
72 	cb->u.c.offset = 0;
73 
74 	ret = io_queue_init(1, &ioctx);
75 	if (ret != 0)
76 		fail("io_queue_init returned error %d\n", ret);
77 
78 	ret = io_submit(ioctx, 1, &cb);
79 	if (ret != 1)
80 		fail("io_submit returned error %d\n", ret);
81 
82 	ret = io_getevents(ioctx, 1, 1, &ie, NULL);
83 	if (ret != 1)
84 		fail("io_getevents returned %d\n", ret);
85 
86 	/*
87 	 *  If all goes well, we should see 300 bytes read.  If things
88 	 *  are broken, we may very well see a result of 4k.
89 	 */
90 	if (ie.res != FILE_SIZE)
91 		fail("AIO read of last block in file returned %d bytes, "
92 		     "expected %d\n", ret, FILE_SIZE);
93 
94 	printf("AIO read of last block in file succeeded.\n");
95 	return 0;
96 }
97