1 /* $NetBSD: t_aio_lio.c,v 1.1 2025/10/10 15:53:55 christos Exp $ */ 2 3 /* 4 * Copyright (c) 2025 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND 17 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 18 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 19 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY 21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 23 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 25 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 26 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 27 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30 #include <atf-c.h> 31 32 #include <aio.h> 33 #include <errno.h> 34 #include <fcntl.h> 35 #include <signal.h> 36 #include <stdint.h> 37 #include <stdio.h> 38 #include <stdlib.h> 39 #include <string.h> 40 #include <sys/stat.h> 41 #include <sys/types.h> 42 #include <unistd.h> 43 44 static int mktemp_file(char *, size_t); 45 static void fill_pattern(uint8_t *, size_t, uint8_t); 46 static void wait_all(const struct aiocb * const [], size_t); 47 48 static int 49 mktemp_file(char *path, size_t pathlen) 50 { 51 int fd, n; 52 53 n = snprintf(path, pathlen, "t_aio_lio.XXXXXX"); 54 ATF_REQUIRE(n > 0 && (size_t)n < pathlen); 55 56 fd = mkstemp(path); 57 ATF_REQUIRE(fd >= 0); 58 59 return fd; 60 } 61 62 static void 63 fill_pattern(uint8_t *buf, size_t len, uint8_t seed) 64 { 65 size_t i; 66 67 for (i = 0; i < len; i++) { 68 buf[i] = (uint8_t)(seed + (i & 0xff)); 69 } 70 } 71 72 static void 73 wait_all(const struct aiocb * const list[], size_t nent) 74 { 75 size_t i; 76 int pending, rv; 77 78 for (;;) { 79 pending = 0; 80 81 for (i = 0; i < nent; i++) { 82 int err; 83 84 if (list[i] == NULL) { 85 continue; 86 } 87 88 err = aio_error(list[i]); 89 if (err == EINPROGRESS) { 90 pending = 1; 91 } 92 } 93 94 if (!pending) { 95 break; 96 } 97 98 rv = aio_suspend(list, (int)nent, NULL); 99 ATF_REQUIRE_EQ_MSG(0, rv, "aio_suspend failed: %s", 100 strerror(errno)); 101 } 102 } 103 104 ATF_TC_WITHOUT_HEAD(lio_nowait); 105 ATF_TC_BODY(lio_nowait, tc) 106 { 107 char path[64]; 108 int fd, rv; 109 #define NW_REQS 8 110 #define NW_BLKSIZ 8192 111 uint8_t *bufs[NW_REQS]; 112 struct aiocb cbs[NW_REQS]; 113 struct aiocb *list[NW_REQS]; 114 off_t off; 115 size_t i; 116 117 fd = mktemp_file(path, sizeof(path)); 118 119 off = 0; 120 for (i = 0; i < NW_REQS; i++) { 121 bufs[i] = malloc(NW_BLKSIZ); 122 ATF_REQUIRE(bufs[i] != NULL); 123 124 fill_pattern(bufs[i], NW_BLKSIZ, (uint8_t)i); 125 126 memset(&cbs[i], 0, sizeof(cbs[i])); 127 cbs[i].aio_fildes = fd; 128 cbs[i].aio_buf = bufs[i]; 129 cbs[i].aio_nbytes = NW_BLKSIZ; 130 cbs[i].aio_offset = off; 131 cbs[i].aio_lio_opcode = LIO_WRITE; 132 133 list[i] = &cbs[i]; 134 off += (off_t)NW_BLKSIZ; 135 } 136 137 rv = lio_listio(LIO_NOWAIT, list, (int)NW_REQS, NULL); 138 ATF_REQUIRE_EQ_MSG(0, rv, "lio_listio failed: %s", 139 strerror(errno)); 140 141 wait_all((const struct aiocb * const *)list, NW_REQS); 142 143 for (i = 0; i < NW_REQS; i++) { 144 int err; 145 ssize_t done; 146 147 err = aio_error(&cbs[i]); 148 ATF_REQUIRE_EQ(0, err); 149 150 done = aio_return(&cbs[i]); 151 ATF_REQUIRE_EQ(NW_BLKSIZ, done); 152 153 free(bufs[i]); 154 } 155 156 rv = close(fd); 157 ATF_REQUIRE_EQ(0, rv); 158 rv = unlink(path); 159 ATF_REQUIRE_EQ(0, rv); 160 } 161 162 ATF_TC_WITHOUT_HEAD(lio_wait_write_then_read); 163 ATF_TC_BODY(lio_wait_write_then_read, tc) 164 { 165 char path[64]; 166 int fd, rv; 167 #define WWTR_REQS 4 168 #define WWTR_BLKSIZ 4096 169 170 uint8_t *wbufs[WWTR_REQS]; 171 struct aiocb wcbs[WWTR_REQS]; 172 struct aiocb *wlist[WWTR_REQS]; 173 174 uint8_t *rbufs[WWTR_REQS]; 175 struct aiocb rcbs[WWTR_REQS]; 176 struct aiocb *rlist[WWTR_REQS]; 177 178 size_t i; 179 off_t off; 180 181 fd = mktemp_file(path, sizeof(path)); 182 183 off = 0; 184 for (i = 0; i < WWTR_REQS; i++) { 185 wbufs[i] = malloc(WWTR_BLKSIZ); 186 ATF_REQUIRE(wbufs[i] != NULL); 187 188 fill_pattern(wbufs[i], WWTR_BLKSIZ, (uint8_t)(0xA0 + i)); 189 190 memset(&wcbs[i], 0, sizeof(wcbs[i])); 191 wcbs[i].aio_fildes = fd; 192 wcbs[i].aio_buf = wbufs[i]; 193 wcbs[i].aio_nbytes = WWTR_BLKSIZ; 194 wcbs[i].aio_offset = off; 195 wcbs[i].aio_lio_opcode = LIO_WRITE; 196 197 wlist[i] = &wcbs[i]; 198 off += WWTR_BLKSIZ; 199 } 200 201 rv = lio_listio(LIO_WAIT, wlist, (int)WWTR_REQS, NULL); 202 ATF_REQUIRE_EQ_MSG(0, rv, "lio_listio write failed: %s", 203 strerror(errno)); 204 205 for (i = 0; i < WWTR_REQS; i++) { 206 int err; 207 ssize_t done; 208 209 err = aio_error(&wcbs[i]); 210 ATF_REQUIRE_EQ(0, err); 211 212 done = aio_return(&wcbs[i]); 213 ATF_REQUIRE_EQ(WWTR_BLKSIZ, done); 214 } 215 216 for (i = 0; i < WWTR_REQS; i++) { 217 rbufs[i] = calloc(1, WWTR_BLKSIZ); 218 ATF_REQUIRE(rbufs[i] != NULL); 219 220 memset(&rcbs[i], 0, sizeof(rcbs[i])); 221 rcbs[i].aio_fildes = fd; 222 rcbs[i].aio_buf = rbufs[i]; 223 rcbs[i].aio_nbytes = WWTR_BLKSIZ; 224 rcbs[i].aio_offset = (off_t)i * WWTR_BLKSIZ; 225 rcbs[i].aio_lio_opcode = LIO_READ; 226 227 rlist[i] = &rcbs[i]; 228 } 229 230 rv = lio_listio(LIO_NOWAIT, rlist, WWTR_REQS, NULL); 231 ATF_REQUIRE_EQ_MSG(0, rv, "lio_listio read failed: %s", 232 strerror(errno)); 233 234 wait_all((const struct aiocb * const *)rlist, WWTR_REQS); 235 236 for (i = 0; i < WWTR_REQS; i++) { 237 int err; 238 ssize_t done; 239 240 err = aio_error(&rcbs[i]); 241 ATF_REQUIRE_EQ(0, err); 242 243 done = aio_return(&rcbs[i]); 244 ATF_REQUIRE_EQ(WWTR_BLKSIZ, done); 245 246 ATF_REQUIRE_EQ(0, memcmp(wbufs[i], rbufs[i], WWTR_BLKSIZ)); 247 248 free(wbufs[i]); 249 free(rbufs[i]); 250 } 251 252 rv = close(fd); 253 ATF_REQUIRE_EQ(0, rv); 254 rv = unlink(path); 255 ATF_REQUIRE_EQ(0, rv); 256 } 257 258 ATF_TP_ADD_TCS(tp) 259 { 260 ATF_TP_ADD_TC(tp, lio_nowait); 261 ATF_TP_ADD_TC(tp, lio_wait_write_then_read); 262 263 return atf_no_error(); 264 } 265