Imported Upstream version 0.3.113
[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(temp_file));
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                 /* SKIP this test if O_DIRECT is not available on this fs */
97                 if (errno == EINVAL)
98                         return 3;
99                 perror("fcntl");
100                 return 1;
101         }
102
103         memset(buf, 0, BUFLEN);
104         iov.iov_base = buf;
105         iov.iov_len = BUFLEN;
106         io_prep_preadv2(&iocb, fd, &iov, 1, 0, RWF_NOWAIT);
107
108         ret = io_submit(ctx, 1, &iocbp);
109
110         /*
111          * io_submit will return -EINVAL if RWF_NOWAIT is not supported by
112          * the kernel, and EOPNOTSUPP if it's not supported by the fs.
113          */
114         if (ret != 1) {
115                 if (ret == -EINVAL || ret == -ENOTSUP) {
116                         fprintf(stderr, "RWF_NOWAIT not supported by %s.\n",
117                                 ret == -EINVAL ? "kernel" : "file system");
118                         /* skip this test */
119                         return 3;
120                 }
121                 errno = -ret;
122                 perror("io_submit");
123                 return 1;
124         }
125
126         ret = io_getevents(ctx, 1, 1, &event, NULL);
127         if (ret != 1) {
128                 errno = -ret;
129                 perror("io_getevents");
130                 return 1;
131         }
132
133         /*
134          * We expect -EAGAIN due to the existence of a page cache page
135          * for the file system block we are writing.
136          */
137         if (event.res != -EAGAIN) {
138                 fprintf(stderr, "Expected -EAGAIN, got %lu\n", event.res);
139                 return 1;
140         }
141
142         /*
143          * An O_DIRECT write to the page will force the page out of the
144          * page cache, allowing the subsequent RWF_NOWAIT I/O to complete.
145          */
146         ret = pwrite(fd, buf, BUFLEN, 0);
147         if (ret != BUFLEN) {
148                 perror("write");
149                 return 1;
150         }
151
152         /*
153          * Now retry the RWF_NOWAIT I/O.  This should succeed.
154          */
155         ret = io_submit(ctx, 1, &iocbp);
156         if (ret != 1) {
157                 errno = -ret;
158                 perror("io_submit");
159                 return 1;
160         }
161
162         ret = io_getevents(ctx, 1, 1, &event, NULL);
163         if (ret != 1) {
164                 errno = -ret;
165                 perror("io_getevents");
166                 return 1;
167         }
168
169         if (event.res != BUFLEN) {
170                 fprintf(stderr, "Expected %d, got %lu\n", BUFLEN, event.res);
171                 return 1;
172         }
173
174         return 0;
175 }
176 /*
177  * Local variables:
178  *  mode: c
179  *  c-basic-offset: 8
180  * End:
181  */