1 /*-
2 * Copyright (c) 2017 Spectra Logic Corp
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27 #define _WANT_ALL_LIO_OPCODES
28
29 #include <sys/param.h>
30 #include <sys/event.h>
31 #include <sys/uio.h>
32
33 #include <aio.h>
34 #include <fcntl.h>
35 #include <semaphore.h>
36 #include <stdlib.h>
37
38 #include <atf-c.h>
39
40 #include "local.h"
41 #include "freebsd_test_suite/macros.h"
42
43 static sem_t completions;
44
45
46 static void
handler(int sig __unused)47 handler(int sig __unused)
48 {
49 ATF_REQUIRE_EQ(0, sem_post(&completions));
50 }
51
52 static void
thr_handler(union sigval sv __unused)53 thr_handler(union sigval sv __unused)
54 {
55 ATF_REQUIRE_EQ(0, sem_post(&completions));
56 }
57
58 /*
59 * If lio_listio is unable to enqueue any requests at all, it should return
60 * EAGAIN.
61 */
62 ATF_TC_WITHOUT_HEAD(lio_listio_eagain_kevent);
ATF_TC_BODY(lio_listio_eagain_kevent,tc)63 ATF_TC_BODY(lio_listio_eagain_kevent, tc)
64 {
65 int fd, i, j, kq, max_queue_per_proc, ios_per_call;
66 size_t max_queue_per_proc_size;
67 struct aiocb *aiocbs[2];
68 struct aiocb **list[2];
69 struct sigevent sev[2];
70 char *buffer;
71 const char *path="tempfile";
72 void *udata[2];
73
74 ATF_REQUIRE_KERNEL_MODULE("aio");
75 ATF_REQUIRE_UNSAFE_AIO();
76
77 max_queue_per_proc_size = sizeof(max_queue_per_proc);
78 ATF_REQUIRE_EQ(sysctlbyname("vfs.aio.max_aio_queue_per_proc",
79 &max_queue_per_proc, &max_queue_per_proc_size, NULL, 0), 0);
80 ios_per_call = max_queue_per_proc;
81
82 fd = open(path, O_RDWR|O_CREAT, 0666);
83 ATF_REQUIRE(fd >= 0);
84
85 kq = kqueue();
86 ATF_REQUIRE(kq > 0);
87
88 buffer = calloc(1, 4096);
89 ATF_REQUIRE(buffer != NULL);
90
91 /*
92 * Call lio_listio twice, each with the maximum number of operations.
93 * The first call should succeed and the second should fail.
94 */
95 for (i = 0; i < 2; i++) {
96 aiocbs[i] = calloc(ios_per_call, sizeof(struct aiocb));
97 ATF_REQUIRE(aiocbs[i] != NULL);
98 list[i] = calloc(ios_per_call, sizeof(struct aiocb*));
99 ATF_REQUIRE(list[i] != NULL);
100 udata[i] = (void*)((caddr_t)0xdead0000 + i);
101 sev[i].sigev_notify = SIGEV_KEVENT;
102 sev[i].sigev_notify_kqueue = kq;
103 sev[i].sigev_value.sival_ptr = udata[i];
104 for (j = 0; j < ios_per_call; j++) {
105 aiocbs[i][j].aio_fildes = fd;
106 aiocbs[i][j].aio_offset = (i * ios_per_call + j) * 4096;
107 aiocbs[i][j].aio_buf = buffer;
108 aiocbs[i][j].aio_nbytes = 4096;
109 aiocbs[i][j].aio_lio_opcode = LIO_WRITE;
110 list[i][j] = &aiocbs[i][j];
111 }
112 }
113
114 ATF_REQUIRE_EQ(0, lio_listio(LIO_NOWAIT, list[0], ios_per_call, &sev[0]));
115 ATF_REQUIRE_EQ(-1, lio_listio(LIO_NOWAIT, list[1], ios_per_call, &sev[1]));
116 /*
117 * The second lio_listio call should fail with EAGAIN. Bad timing may
118 * mean that some requests did get enqueued, but the result should
119 * still be EAGAIN.
120 */
121 ATF_REQUIRE_EQ(errno, EAGAIN);
122 }
123
124
125 /* With LIO_WAIT, an empty lio_listio should return immediately */
126 ATF_TC_WITHOUT_HEAD(lio_listio_empty_wait);
ATF_TC_BODY(lio_listio_empty_wait,tc)127 ATF_TC_BODY(lio_listio_empty_wait, tc)
128 {
129 struct aiocb *list = NULL;
130
131 ATF_REQUIRE_EQ(0, lio_listio(LIO_WAIT, &list, 0, NULL));
132 }
133
134 /* With LIO_NOWAIT, an empty lio_listio should return immediately */
135 ATF_TC_WITHOUT_HEAD(lio_listio_empty_nowait);
ATF_TC_BODY(lio_listio_empty_nowait,tc)136 ATF_TC_BODY(lio_listio_empty_nowait, tc)
137 {
138 struct aiocb *list = NULL;
139
140 ATF_REQUIRE_EQ(0, lio_listio(LIO_NOWAIT, &list, 0, NULL));
141 }
142
143 /*
144 * With LIO_NOWAIT, an empty lio_listio should send completion notification
145 * immediately
146 */
147 ATF_TC_WITHOUT_HEAD(lio_listio_empty_nowait_kevent);
ATF_TC_BODY(lio_listio_empty_nowait_kevent,tc)148 ATF_TC_BODY(lio_listio_empty_nowait_kevent, tc)
149 {
150 struct aiocb *list = NULL;
151 struct sigevent sev;
152 struct kevent kq_returned;
153 int kq, result;
154 void *udata = (void*)0xdeadbeefdeadbeef;
155
156 atf_tc_expect_timeout("Bug 251515 - lio_listio(2) never sends"
157 " kevent if nent==0");
158 kq = kqueue();
159 ATF_REQUIRE(kq > 0);
160 sev.sigev_notify = SIGEV_KEVENT;
161 sev.sigev_notify_kqueue = kq;
162 sev.sigev_value.sival_ptr = udata;
163 ATF_REQUIRE_EQ(0, lio_listio(LIO_NOWAIT, &list, 0, &sev));
164 result = kevent(kq, NULL, 0, &kq_returned, 1, NULL);
165 ATF_REQUIRE_MSG(result == 1, "Never got completion notification");
166 ATF_REQUIRE_EQ((uintptr_t)list, kq_returned.ident);
167 ATF_REQUIRE_EQ(EVFILT_LIO, kq_returned.filter);
168 ATF_REQUIRE_EQ(udata, kq_returned.udata);
169 }
170
171 /*
172 * With LIO_NOWAIT, an empty lio_listio should send completion notification
173 * immediately
174 */
175 ATF_TC_WITHOUT_HEAD(lio_listio_empty_nowait_signal);
ATF_TC_BODY(lio_listio_empty_nowait_signal,tc)176 ATF_TC_BODY(lio_listio_empty_nowait_signal, tc)
177 {
178 struct aiocb *list = NULL;
179 struct sigevent sev;
180
181 ATF_REQUIRE_EQ(0, sem_init(&completions, false, 0));
182 sev.sigev_notify = SIGEV_SIGNAL;
183 sev.sigev_signo = SIGUSR1;
184 ATF_REQUIRE(SIG_ERR != signal(SIGUSR1, handler));
185 ATF_REQUIRE_EQ(0, lio_listio(LIO_NOWAIT, &list, 0, &sev));
186 ATF_REQUIRE_EQ(0, sem_wait(&completions));
187 ATF_REQUIRE_EQ(0, sem_destroy(&completions));
188 }
189
190 /*
191 * With LIO_NOWAIT, an empty lio_listio should send completion notification
192 * immediately
193 */
194 ATF_TC_WITHOUT_HEAD(lio_listio_empty_nowait_thread);
ATF_TC_BODY(lio_listio_empty_nowait_thread,tc)195 ATF_TC_BODY(lio_listio_empty_nowait_thread, tc)
196 {
197 struct aiocb *list = NULL;
198 struct sigevent sev;
199
200 ATF_REQUIRE_EQ(0, sem_init(&completions, false, 0));
201 bzero(&sev, sizeof(sev));
202 sev.sigev_notify = SIGEV_THREAD;
203 sev.sigev_notify_function = thr_handler;
204 sev.sigev_notify_attributes = NULL;
205 ATF_REQUIRE_MSG(0 == lio_listio(LIO_NOWAIT, &list, 0, &sev),
206 "lio_listio: %s", strerror(errno));
207 ATF_REQUIRE_EQ(0, sem_wait(&completions));
208 ATF_REQUIRE_EQ(0, sem_destroy(&completions));
209 }
210
211 /*
212 * A simple check that the allowed operations work.
213 */
214 ATF_TC_WITHOUT_HEAD(lio_listio_opcodes);
ATF_TC_BODY(lio_listio_opcodes,tc)215 ATF_TC_BODY(lio_listio_opcodes, tc)
216 {
217 struct aiocb write_cb, read_cb, writev_cb, readv_cb;
218 struct aiocb *list[] = {&write_cb, &read_cb, &writev_cb, &readv_cb};
219 struct iovec writev_iov[2];
220 struct iovec readv_iov[2];
221 char buffer[6];
222 int fd;
223
224 fd = open("testfile", O_CREAT | O_RDWR, 0666);
225 ATF_REQUIRE_MSG(fd >= 0, "open: %s", strerror(errno));
226
227 /* We start with numbers in a file and letters in memory... */
228 ATF_CHECK_EQ(6, write(fd, "123456", 6));
229 memcpy(buffer, "abcdef", 6);
230
231 /* a -> 1 */
232 bzero(&write_cb, sizeof(write_cb));
233 write_cb.aio_sigevent.sigev_notify = SIGEV_NONE;
234 write_cb.aio_fildes = fd;
235 write_cb.aio_lio_opcode = LIO_WRITE;
236 write_cb.aio_buf = &buffer[0];
237 write_cb.aio_nbytes = 1;
238 write_cb.aio_offset = 0;
239
240 /* b <- 2 */
241 bzero(&read_cb, sizeof(read_cb));
242 read_cb.aio_sigevent.sigev_notify = SIGEV_NONE;
243 read_cb.aio_fildes = fd;
244 read_cb.aio_lio_opcode = LIO_READ;
245 read_cb.aio_buf = &buffer[1];
246 read_cb.aio_nbytes = 1;
247 read_cb.aio_offset = 1;
248
249 /* d -> 3, c -> 4 */
250 writev_iov[0].iov_base = &buffer[3];
251 writev_iov[0].iov_len = 1;
252 writev_iov[1].iov_base = &buffer[2];
253 writev_iov[1].iov_len = 1;
254 bzero(&writev_cb, sizeof(writev_cb));
255 writev_cb.aio_sigevent.sigev_notify = SIGEV_NONE;
256 writev_cb.aio_fildes = fd;
257 writev_cb.aio_lio_opcode = LIO_WRITEV;
258 writev_cb.aio_iov = &writev_iov;
259 writev_cb.aio_iovcnt = 2;
260 writev_cb.aio_offset = 2;
261
262 /* f <- 5, e <- 6 */
263 readv_iov[0].iov_base = &buffer[5];
264 readv_iov[0].iov_len = 1;
265 readv_iov[1].iov_base = &buffer[4];
266 readv_iov[1].iov_len = 1;
267 bzero(&readv_cb, sizeof(readv_cb));
268 readv_cb.aio_sigevent.sigev_notify = SIGEV_NONE;
269 readv_cb.aio_fildes = fd;
270 readv_cb.aio_lio_opcode = LIO_READV;
271 readv_cb.aio_iov = &readv_iov;
272 readv_cb.aio_iovcnt = 2;
273 readv_cb.aio_offset = 4;
274
275 ATF_CHECK_EQ(0, lio_listio(LIO_WAIT, list, nitems(list), NULL));
276 ATF_CHECK_EQ(0, aio_error(&write_cb));
277 ATF_CHECK_EQ(1, aio_return(&write_cb));
278 ATF_CHECK_EQ(0, aio_error(&read_cb));
279 ATF_CHECK_EQ(1, aio_return(&read_cb));
280 ATF_CHECK_EQ(0, aio_error(&writev_cb));
281 ATF_CHECK_EQ(2, aio_return(&writev_cb));
282 ATF_CHECK_EQ(0, aio_error(&readv_cb));
283 ATF_CHECK_EQ(2, aio_return(&readv_cb));
284
285 ATF_CHECK_EQ(0, memcmp(buffer, "a2cd65", 6));
286 ATF_CHECK_EQ(6, pread(fd, buffer, 6, 0));
287 ATF_CHECK_EQ(0, memcmp(buffer, "a2dc56", 6));
288
289 close(fd);
290 }
291
292
293 /*
294 * Only select opcodes are allowed with lio_listio
295 */
296 ATF_TC_WITHOUT_HEAD(lio_listio_invalid_opcode);
ATF_TC_BODY(lio_listio_invalid_opcode,tc)297 ATF_TC_BODY(lio_listio_invalid_opcode, tc)
298 {
299 struct aiocb sync_cb, mlock_cb;
300 struct aiocb *list[] = {&sync_cb, &mlock_cb};
301 int fd;
302
303 fd = open("testfile", O_CREAT | O_RDWR, 0666);
304 ATF_REQUIRE_MSG(fd >= 0, "open: %s", strerror(errno));
305
306 bzero(&sync_cb, sizeof(sync_cb));
307 sync_cb.aio_fildes = fd;
308 sync_cb.aio_lio_opcode = LIO_SYNC;
309
310 bzero(&mlock_cb, sizeof(mlock_cb));
311 mlock_cb.aio_lio_opcode = LIO_MLOCK;
312
313 ATF_CHECK_ERRNO(EIO, lio_listio(LIO_WAIT, list, nitems(list), NULL));
314 ATF_CHECK_EQ(EINVAL, aio_error(&sync_cb));
315 ATF_CHECK_ERRNO(EINVAL, aio_return(&sync_cb) < 0);
316 ATF_CHECK_EQ(EINVAL, aio_error(&mlock_cb));
317 ATF_CHECK_ERRNO(EINVAL, aio_return(&mlock_cb) < 0);
318
319 close(fd);
320 }
321
322
ATF_TP_ADD_TCS(tp)323 ATF_TP_ADD_TCS(tp)
324 {
325
326 ATF_TP_ADD_TC(tp, lio_listio_eagain_kevent);
327 ATF_TP_ADD_TC(tp, lio_listio_empty_nowait);
328 ATF_TP_ADD_TC(tp, lio_listio_empty_nowait_kevent);
329 ATF_TP_ADD_TC(tp, lio_listio_empty_nowait_signal);
330 ATF_TP_ADD_TC(tp, lio_listio_empty_nowait_thread);
331 ATF_TP_ADD_TC(tp, lio_listio_empty_wait);
332 ATF_TP_ADD_TC(tp, lio_listio_opcodes);
333 ATF_TP_ADD_TC(tp, lio_listio_invalid_opcode);
334
335 return (atf_no_error());
336 }
337