441eaa8db4a993f9e64222ddb57eb6555ad0ee25
[platform/upstream/libaio.git] / harness / cases / 21.t
1 /*
2  * Copyright 2017, Red Hat, Inc.
3  *
4  * Test RWF_NOWAIT.
5  *
6  * RWF_NOWAIT will cause -EAGAIN to be returned in the io_event for
7  * any I/O that cannot be serviced without blocking the submission
8  * thread.  Instances covered by the kernel at the time this test was
9  * written include:
10  * - O_DIRECT I/O to a file offset that has populated page cache pages
11  * - the submission context cannot obtain the inode lock
12  * - space allocation is necessary
13  * - we need to wait for other I/O (e.g. in the misaligned I/O case)
14  * - ...
15  *
16
17  * The easiest of these to test is that a direct I/O is writing to a
18  * file offset with populated page cache.  We also test to ensure that
19  * we can perform I/O in the absence of the above conditions.
20  *
21  * Author: Jeff Moyer <jmoyer@redhat.com>
22  */
23 #define _GNU_SOURCE
24 #include <stdio.h>
25 #include <unistd.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <sys/mman.h>
29 #include <signal.h>
30 #include <sched.h>
31 #include <libaio.h>
32
33 #define TEMPLATE "21.XXXXXX"
34 #define BUFLEN 4096
35
36 #ifndef RWF_NOWAIT
37 #define RWF_NOWAIT      0x00000008
38 #endif
39
40 int
41 open_temp_file()
42 {
43         int fd;
44         char temp_file[sizeof(TEMPLATE)];
45
46         strncpy(temp_file, TEMPLATE, sizeof(TEMPLATE));
47         fd = mkstemp(temp_file);
48         if (fd < 0) {
49                 perror("mkstemp");
50                 return -1;
51         }
52         unlink(temp_file);
53         return fd;
54 }
55
56 int
57 test_main()
58 {
59         int fd, flags;
60         int ret;
61         io_context_t ctx;
62         struct iocb iocb, *iocbp = &iocb;
63         struct io_event event;
64         char buf[BUFLEN] __attribute__((aligned (4096)));
65         struct iovec iov;
66
67         fd = open_temp_file();
68         if (fd < 0)
69                 return 1;
70
71         memset(&ctx, 0, sizeof(ctx));
72         ret = io_setup(1, &ctx);
73         if (ret != 0) {
74                 fprintf(stderr, "io_setup failed with %d\n", ret);
75                 return 1;
76         }
77
78         /*
79          * Perform a buffered write to a file.  This instantiates the
80          * block and adds the page to the page cache.
81          */
82         memset(buf, 0xa, BUFLEN);
83         ret = write(fd, buf, BUFLEN);
84         if (ret != BUFLEN) {
85                 perror("write");
86                 return 1;
87         }
88
89         /*
90          * Now attempt an aio/dio pwritev2 with the RWF_NONBLOCK flag
91          * set.
92          */
93         flags = fcntl(fd, F_GETFL);
94         ret = fcntl(fd, F_SETFL, flags | O_DIRECT);
95         if (ret != 0) {
96                 perror("fcntl");
97                 return 1;
98         }
99
100         memset(buf, 0, BUFLEN);
101         iov.iov_base = buf;
102         iov.iov_len = BUFLEN;
103         io_prep_preadv2(&iocb, fd, &iov, 1, 0, RWF_NOWAIT);
104
105         ret = io_submit(ctx, 1, &iocbp);
106
107         /*
108          * io_submit will return -EINVAL if RWF_NOWAIT is not supported.
109          */
110         if (ret != 1) {
111                 if (ret == -EINVAL) {
112                         fprintf(stderr, "RWF_NOWAIT not supported by kernel.\n");
113                         /* just return success */
114                         return 0;
115                 }
116                 errno = -ret;
117                 perror("io_submit");
118                 return 1;
119         }
120
121         ret = io_getevents(ctx, 1, 1, &event, NULL);
122         if (ret != 1) {
123                 errno = -ret;
124                 perror("io_getevents");
125                 return 1;
126         }
127
128         /*
129          * We expect -EAGAIN due to the existence of a page cache page
130          * for the file system block we are writing.
131          */
132         if (event.res != -EAGAIN) {
133                 fprintf(stderr, "Expected -EAGAIN, got %lu\n", event.res);
134                 return 1;
135         }
136
137         /*
138          * An O_DIRECT write to the page will force the page out of the
139          * page cache, allowing the subsequent RWF_NOWAIT I/O to complete.
140          */
141         ret = pwrite(fd, buf, BUFLEN, 0);
142         if (ret != BUFLEN) {
143                 perror("write");
144                 return 1;
145         }
146
147         /*
148          * Now retry the RWF_NOWAIT I/O.  This should succeed.
149          */
150         ret = io_submit(ctx, 1, &iocbp);
151         if (ret != 1) {
152                 errno = -ret;
153                 perror("io_submit");
154                 return 1;
155         }
156
157         ret = io_getevents(ctx, 1, 1, &event, NULL);
158         if (ret != 1) {
159                 errno = -ret;
160                 perror("io_getevents");
161                 return 1;
162         }
163
164         if (event.res != BUFLEN) {
165                 fprintf(stderr, "Expected %d, got %lu\n", BUFLEN, event.res);
166                 return 1;
167         }
168
169         return 0;
170 }
171 /*
172  * Local variables:
173  *  mode: c
174  *  c-basic-offset: 8
175  * End:
176  */