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 * $FreeBSD$ 27 */ 28 29 #define _WANT_ALL_LIO_OPCODES 30 31 #include <sys/param.h> 32 #include <sys/event.h> 33 #include <sys/uio.h> 34 35 #include <aio.h> 36 #include <fcntl.h> 37 #include <semaphore.h> 38 #include <stdlib.h> 39 40 #include <atf-c.h> 41 42 #include "local.h" 43 #include "freebsd_test_suite/macros.h" 44 45 static sem_t completions; 46 47 48 static void 49 handler(int sig __unused) 50 { 51 ATF_REQUIRE_EQ(0, sem_post(&completions)); 52 } 53 54 static void 55 thr_handler(union sigval sv __unused) 56 { 57 ATF_REQUIRE_EQ(0, sem_post(&completions)); 58 } 59 60 /* 61 * If lio_listio is unable to enqueue any requests at all, it should return 62 * EAGAIN. 63 */ 64 ATF_TC_WITHOUT_HEAD(lio_listio_eagain_kevent); 65 ATF_TC_BODY(lio_listio_eagain_kevent, tc) 66 { 67 int fd, i, j, kq, max_queue_per_proc, ios_per_call; 68 size_t max_queue_per_proc_size; 69 struct aiocb *aiocbs[2]; 70 struct aiocb **list[2]; 71 struct sigevent sev[2]; 72 char *buffer; 73 const char *path="tempfile"; 74 void *udata[2]; 75 76 ATF_REQUIRE_KERNEL_MODULE("aio"); 77 ATF_REQUIRE_UNSAFE_AIO(); 78 79 max_queue_per_proc_size = sizeof(max_queue_per_proc); 80 ATF_REQUIRE_EQ(sysctlbyname("vfs.aio.max_aio_queue_per_proc", 81 &max_queue_per_proc, &max_queue_per_proc_size, NULL, 0), 0); 82 ios_per_call = max_queue_per_proc; 83 84 fd = open(path, O_RDWR|O_CREAT, 0666); 85 ATF_REQUIRE(fd >= 0); 86 87 kq = kqueue(); 88 ATF_REQUIRE(kq > 0); 89 90 buffer = calloc(1, 4096); 91 ATF_REQUIRE(buffer != NULL); 92 93 /* 94 * Call lio_listio twice, each with the maximum number of operations. 95 * The first call should succeed and the second should fail. 96 */ 97 for (i = 0; i < 2; i++) { 98 aiocbs[i] = calloc(ios_per_call, sizeof(struct aiocb)); 99 ATF_REQUIRE(aiocbs[i] != NULL); 100 list[i] = calloc(ios_per_call, sizeof(struct aiocb*)); 101 ATF_REQUIRE(list[i] != NULL); 102 udata[i] = (void*)((caddr_t)0xdead0000 + i); 103 sev[i].sigev_notify = SIGEV_KEVENT; 104 sev[i].sigev_notify_kqueue = kq; 105 sev[i].sigev_value.sival_ptr = udata[i]; 106 for (j = 0; j < ios_per_call; j++) { 107 aiocbs[i][j].aio_fildes = fd; 108 aiocbs[i][j].aio_offset = (i * ios_per_call + j) * 4096; 109 aiocbs[i][j].aio_buf = buffer; 110 aiocbs[i][j].aio_nbytes = 4096; 111 aiocbs[i][j].aio_lio_opcode = LIO_WRITE; 112 list[i][j] = &aiocbs[i][j]; 113 } 114 } 115 116 ATF_REQUIRE_EQ(0, lio_listio(LIO_NOWAIT, list[0], ios_per_call, &sev[0])); 117 ATF_REQUIRE_EQ(-1, lio_listio(LIO_NOWAIT, list[1], ios_per_call, &sev[1])); 118 /* 119 * The second lio_listio call should fail with EAGAIN. Bad timing may 120 * mean that some requests did get enqueued, but the result should 121 * still be EAGAIN. 122 */ 123 ATF_REQUIRE_EQ(errno, EAGAIN); 124 } 125 126 127 /* With LIO_WAIT, an empty lio_listio should return immediately */ 128 ATF_TC_WITHOUT_HEAD(lio_listio_empty_wait); 129 ATF_TC_BODY(lio_listio_empty_wait, tc) 130 { 131 struct aiocb *list = NULL; 132 133 ATF_REQUIRE_EQ(0, lio_listio(LIO_WAIT, &list, 0, NULL)); 134 } 135 136 /* 137 * With LIO_NOWAIT, an empty lio_listio should send completion notification 138 * immediately 139 */ 140 ATF_TC_WITHOUT_HEAD(lio_listio_empty_nowait_kevent); 141 ATF_TC_BODY(lio_listio_empty_nowait_kevent, tc) 142 { 143 struct aiocb *list = NULL; 144 struct sigevent sev; 145 struct kevent kq_returned; 146 int kq, result; 147 void *udata = (void*)0xdeadbeefdeadbeef; 148 149 atf_tc_expect_timeout("Bug 251515 - lio_listio(2) never sends" 150 " kevent if nent==0"); 151 kq = kqueue(); 152 ATF_REQUIRE(kq > 0); 153 sev.sigev_notify = SIGEV_KEVENT; 154 sev.sigev_notify_kqueue = kq; 155 sev.sigev_value.sival_ptr = udata; 156 ATF_REQUIRE_EQ(0, lio_listio(LIO_NOWAIT, &list, 0, &sev)); 157 result = kevent(kq, NULL, 0, &kq_returned, 1, NULL); 158 ATF_REQUIRE_MSG(result == 1, "Never got completion notification"); 159 ATF_REQUIRE_EQ((uintptr_t)list, kq_returned.ident); 160 ATF_REQUIRE_EQ(EVFILT_LIO, kq_returned.filter); 161 ATF_REQUIRE_EQ(udata, kq_returned.udata); 162 } 163 164 /* 165 * With LIO_NOWAIT, an empty lio_listio should send completion notification 166 * immediately 167 */ 168 ATF_TC_WITHOUT_HEAD(lio_listio_empty_nowait_signal); 169 ATF_TC_BODY(lio_listio_empty_nowait_signal, tc) 170 { 171 struct aiocb *list = NULL; 172 struct sigevent sev; 173 174 ATF_REQUIRE_EQ(0, sem_init(&completions, false, 0)); 175 sev.sigev_notify = SIGEV_SIGNAL; 176 sev.sigev_signo = SIGUSR1; 177 ATF_REQUIRE(SIG_ERR != signal(SIGUSR1, handler)); 178 ATF_REQUIRE_EQ(0, lio_listio(LIO_NOWAIT, &list, 0, &sev)); 179 ATF_REQUIRE_EQ(0, sem_wait(&completions)); 180 ATF_REQUIRE_EQ(0, sem_destroy(&completions)); 181 } 182 183 /* 184 * With LIO_NOWAIT, an empty lio_listio should send completion notification 185 * immediately 186 */ 187 ATF_TC_WITHOUT_HEAD(lio_listio_empty_nowait_thread); 188 ATF_TC_BODY(lio_listio_empty_nowait_thread, tc) 189 { 190 struct aiocb *list = NULL; 191 struct sigevent sev; 192 193 ATF_REQUIRE_EQ(0, sem_init(&completions, false, 0)); 194 bzero(&sev, sizeof(sev)); 195 sev.sigev_notify = SIGEV_THREAD; 196 sev.sigev_notify_function = thr_handler; 197 sev.sigev_notify_attributes = NULL; 198 ATF_REQUIRE_MSG(0 == lio_listio(LIO_NOWAIT, &list, 0, &sev), 199 "lio_listio: %s", strerror(errno)); 200 ATF_REQUIRE_EQ(0, sem_wait(&completions)); 201 ATF_REQUIRE_EQ(0, sem_destroy(&completions)); 202 } 203 204 /* 205 * Only select opcodes are allowed with lio_listio 206 */ 207 ATF_TC_WITHOUT_HEAD(lio_listio_invalid_opcode); 208 ATF_TC_BODY(lio_listio_invalid_opcode, tc) 209 { 210 struct aiocb sync_cb, mlock_cb, writev_cb, readv_cb; 211 struct aiocb *list[] = {&sync_cb, &mlock_cb, &writev_cb, &readv_cb}; 212 struct iovec iov; 213 int fd; 214 215 fd = open("testfile", O_CREAT | O_RDWR); 216 ATF_REQUIRE_MSG(fd >= 0, "open: %s", strerror(errno)); 217 218 bzero(&sync_cb, sizeof(sync_cb)); 219 sync_cb.aio_fildes = fd; 220 sync_cb.aio_lio_opcode = LIO_SYNC; 221 222 bzero(&mlock_cb, sizeof(mlock_cb)); 223 mlock_cb.aio_lio_opcode = LIO_MLOCK; 224 225 iov.iov_base = NULL; 226 iov.iov_len = 0; 227 228 bzero(&readv_cb, sizeof(readv_cb)); 229 readv_cb.aio_fildes = fd; 230 readv_cb.aio_lio_opcode = LIO_READV; 231 readv_cb.aio_iov = &iov; 232 readv_cb.aio_iovcnt = 1; 233 234 bzero(&writev_cb, sizeof(writev_cb)); 235 writev_cb.aio_fildes = fd; 236 writev_cb.aio_lio_opcode = LIO_WRITEV; 237 writev_cb.aio_iov = &iov; 238 writev_cb.aio_iovcnt = 1; 239 240 ATF_CHECK_ERRNO(EIO, lio_listio(LIO_WAIT, list, nitems(list), NULL)); 241 ATF_CHECK_EQ(EINVAL, aio_error(&sync_cb)); 242 ATF_CHECK_ERRNO(EINVAL, aio_return(&sync_cb) < 0); 243 ATF_CHECK_EQ(EINVAL, aio_error(&mlock_cb)); 244 ATF_CHECK_ERRNO(EINVAL, aio_return(&mlock_cb) < 0); 245 ATF_CHECK_EQ(EINVAL, aio_error(&readv_cb)); 246 ATF_CHECK_ERRNO(EINVAL, aio_return(&readv_cb) < 0); 247 ATF_CHECK_EQ(EINVAL, aio_error(&writev_cb)); 248 ATF_CHECK_ERRNO(EINVAL, aio_return(&writev_cb) < 0); 249 } 250 251 252 ATF_TP_ADD_TCS(tp) 253 { 254 255 ATF_TP_ADD_TC(tp, lio_listio_eagain_kevent); 256 ATF_TP_ADD_TC(tp, lio_listio_empty_nowait_kevent); 257 ATF_TP_ADD_TC(tp, lio_listio_empty_nowait_signal); 258 ATF_TP_ADD_TC(tp, lio_listio_empty_nowait_thread); 259 ATF_TP_ADD_TC(tp, lio_listio_empty_wait); 260 ATF_TP_ADD_TC(tp, lio_listio_invalid_opcode); 261 262 return (atf_no_error()); 263 } 264