t_aio_cancel.c revision 1.1 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