Home | History | Annotate | Line # | Download | only in sys
      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