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