1 /* $NetBSD: t_aio_cancel.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 <time.h> 43 #include <unistd.h> 44 45 static int mktemp_file(char *, size_t); 46 static void fill_pattern(uint8_t *, size_t, uint8_t); 47 static void wait_all(const struct aiocb * const [], size_t); 48 49 static int 50 mktemp_file(char *path, size_t pathlen) 51 { 52 int fd, n; 53 54 n = snprintf(path, pathlen, "t_aio_cancel.XXXXXX"); 55 ATF_REQUIRE(n > 0 && (size_t)n < pathlen); 56 57 fd = mkstemp(path); 58 ATF_REQUIRE(fd >= 0); 59 60 return fd; 61 } 62 63 static void 64 fill_pattern(uint8_t *buf, size_t len, uint8_t seed) 65 { 66 size_t i; 67 68 for (i = 0; i < len; i++) { 69 buf[i] = (uint8_t)(seed + (i & 0xff)); 70 } 71 } 72 73 static void 74 wait_all(const struct aiocb * const list[], size_t nent) 75 { 76 size_t i; 77 int pending, rv; 78 79 for (;;) { 80 pending = 0; 81 82 for (i = 0; i < nent; i++) { 83 int err; 84 85 if (list[i] == NULL) { 86 continue; 87 } 88 89 err = aio_error(list[i]); 90 if (err == EINPROGRESS) { 91 pending = 1; 92 } 93 } 94 95 if (!pending) { 96 break; 97 } 98 99 rv = aio_suspend(list, (int)nent, NULL); 100 ATF_REQUIRE_EQ_MSG(0, rv, "aio_suspend failed: %s", 101 strerror(errno)); 102 } 103 } 104 105 ATF_TC_WITHOUT_HEAD(cancel_active_write); 106 ATF_TC_BODY(cancel_active_write, tc) 107 { 108 char path[64]; 109 int fd, rv, crv, err; 110 const size_t blksz = 0x1000; 111 uint8_t *wbuf; 112 struct aiocb cb; 113 const struct aiocb *list[1]; 114 115 fd = mktemp_file(path, sizeof(path)); 116 117 wbuf = malloc(blksz); 118 ATF_REQUIRE(wbuf != NULL); 119 fill_pattern(wbuf, blksz, 0x33); 120 121 memset(&cb, 0, sizeof(cb)); 122 cb.aio_fildes = fd; 123 cb.aio_buf = wbuf; 124 cb.aio_nbytes = blksz; 125 cb.aio_offset = 0; 126 127 rv = aio_write(&cb); 128 ATF_REQUIRE_EQ(0, rv); 129 130 crv = aio_cancel(fd, &cb); 131 ATF_REQUIRE(crv == AIO_CANCELED || crv == AIO_NOTCANCELED 132 || crv == AIO_ALLDONE); 133 134 if (crv == AIO_CANCELED) { 135 do { 136 err = aio_error(&cb); 137 } while (err == EINPROGRESS); 138 ATF_REQUIRE_EQ(ECANCELED, err); 139 ATF_REQUIRE_EQ(-1, aio_return(&cb)); 140 } else if (crv == AIO_NOTCANCELED) { 141 list[0] = &cb; 142 wait_all(list, 1); 143 ATF_REQUIRE_EQ(0, aio_error(&cb)); 144 ATF_REQUIRE_EQ((ssize_t)blksz, aio_return(&cb)); 145 } else { 146 do { 147 err = aio_error(&cb); 148 } while (err == EINPROGRESS); 149 ATF_REQUIRE_EQ(0, err); 150 ATF_REQUIRE_EQ((ssize_t)blksz, aio_return(&cb)); 151 } 152 153 rv = close(fd); 154 ATF_REQUIRE_EQ(0, rv); 155 rv = unlink(path); 156 ATF_REQUIRE_EQ(0, rv); 157 158 free(wbuf); 159 } 160 161 ATF_TC_WITHOUT_HEAD(cancel_completed_request); 162 ATF_TC_BODY(cancel_completed_request, tc) 163 { 164 char path[64]; 165 int fd, rv, crv; 166 const size_t blksz = 4096; 167 uint8_t *wbuf; 168 struct aiocb cb; 169 const struct aiocb *list[1]; 170 171 fd = mktemp_file(path, sizeof(path)); 172 173 wbuf = malloc(blksz); 174 ATF_REQUIRE(wbuf != NULL); 175 memset(wbuf, 0x7E, blksz); 176 177 memset(&cb, 0, sizeof(cb)); 178 cb.aio_fildes = fd; 179 cb.aio_buf = wbuf; 180 cb.aio_nbytes = blksz; 181 cb.aio_offset = 0; 182 183 rv = aio_write(&cb); 184 ATF_REQUIRE_EQ(0, rv); 185 186 list[0] = &cb; 187 wait_all(list, 1); 188 ATF_REQUIRE_EQ(0, aio_error(&cb)); 189 ATF_REQUIRE_EQ((ssize_t)blksz, aio_return(&cb)); 190 191 crv = aio_cancel(fd, &cb); 192 ATF_REQUIRE_EQ(AIO_ALLDONE, crv); 193 194 rv = close(fd); 195 ATF_REQUIRE_EQ(0, rv); 196 rv = unlink(path); 197 ATF_REQUIRE_EQ(0, rv); 198 199 free(wbuf); 200 } 201 202 ATF_TC_WITHOUT_HEAD(cancel_invalid_fd); 203 ATF_TC_BODY(cancel_invalid_fd, tc) 204 { 205 struct aiocb cb; 206 int crv; 207 208 memset(&cb, 0, sizeof(cb)); 209 cb.aio_fildes = -1; 210 211 errno = 0; 212 crv = aio_cancel(-1, &cb); 213 ATF_REQUIRE_EQ(-1, crv); 214 ATF_REQUIRE_EQ(EBADF, errno); 215 } 216 217 ATF_TP_ADD_TCS(tp) 218 { 219 ATF_TP_ADD_TC(tp, cancel_active_write); 220 ATF_TP_ADD_TC(tp, cancel_completed_request); 221 ATF_TP_ADD_TC(tp, cancel_invalid_fd); 222 return atf_no_error(); 223 } 224