1 /*- 2 * Copyright (c) 2004 Robert N. M. Watson 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 /* 30 * Regression test to do some very basic AIO exercising on several types of 31 * file descriptors. Currently, the tests consist of initializing a fixed 32 * size buffer with pseudo-random data, writing it to one fd using AIO, then 33 * reading it from a second descriptor using AIO. For some targets, the same 34 * fd is used for write and read (i.e., file, md device), but for others the 35 * operation is performed on a peer (pty, socket, fifo, etc). A timeout is 36 * initiated to detect undo blocking. This test does not attempt to exercise 37 * error cases or more subtle asynchronous behavior, just make sure that the 38 * basic operations work on some basic object types. 39 */ 40 41 #include <sys/param.h> 42 #include <sys/module.h> 43 #include <sys/socket.h> 44 #include <sys/stat.h> 45 #include <sys/mdioctl.h> 46 47 #include <aio.h> 48 #include <err.h> 49 #include <errno.h> 50 #include <fcntl.h> 51 #include <libutil.h> 52 #include <limits.h> 53 #include <stdint.h> 54 #include <stdio.h> 55 #include <stdlib.h> 56 #include <string.h> 57 #include <termios.h> 58 #include <unistd.h> 59 60 #include <atf-c.h> 61 62 #include "freebsd_test_suite/macros.h" 63 64 #define PATH_TEMPLATE "aio.XXXXXXXXXX" 65 66 /* 67 * GLOBAL_MAX sets the largest usable buffer size to be read and written, as 68 * it sizes ac_buffer in the aio_context structure. It is also the default 69 * size for file I/O. For other types, we use smaller blocks or we risk 70 * blocking (and we run in a single process/thread so that would be bad). 71 */ 72 #define GLOBAL_MAX 16384 73 74 #define BUFFER_MAX GLOBAL_MAX 75 struct aio_context { 76 int ac_read_fd, ac_write_fd; 77 long ac_seed; 78 char ac_buffer[GLOBAL_MAX]; 79 int ac_buflen; 80 int ac_seconds; 81 void (*ac_cleanup)(void *arg); 82 void *ac_cleanup_arg; 83 }; 84 85 static int aio_timedout; 86 87 /* 88 * Each test run specifies a timeout in seconds. Use the somewhat obsoleted 89 * signal(3) and alarm(3) APIs to set this up. 90 */ 91 static void 92 aio_timeout_signal(int sig __unused) 93 { 94 95 aio_timedout = 1; 96 } 97 98 static void 99 aio_timeout_start(int seconds) 100 { 101 102 aio_timedout = 0; 103 ATF_REQUIRE_MSG(signal(SIGALRM, aio_timeout_signal) != SIG_ERR, 104 "failed to set SIGALRM handler: %s", strerror(errno)); 105 alarm(seconds); 106 } 107 108 static void 109 aio_timeout_stop(void) 110 { 111 112 ATF_REQUIRE_MSG(signal(SIGALRM, NULL) != SIG_ERR, 113 "failed to reset SIGALRM handler to default: %s", strerror(errno)); 114 alarm(0); 115 } 116 117 /* 118 * Fill a buffer given a seed that can be fed into srandom() to initialize 119 * the PRNG in a repeatable manner. 120 */ 121 static void 122 aio_fill_buffer(char *buffer, int len, long seed) 123 { 124 char ch; 125 int i; 126 127 srandom(seed); 128 for (i = 0; i < len; i++) { 129 ch = random() & 0xff; 130 buffer[i] = ch; 131 } 132 } 133 134 /* 135 * Test that a buffer matches a given seed. See aio_fill_buffer(). Return 136 * (1) on a match, (0) on a mismatch. 137 */ 138 static int 139 aio_test_buffer(char *buffer, int len, long seed) 140 { 141 char ch; 142 int i; 143 144 srandom(seed); 145 for (i = 0; i < len; i++) { 146 ch = random() & 0xff; 147 if (buffer[i] != ch) 148 return (0); 149 } 150 return (1); 151 } 152 153 /* 154 * Initialize a testing context given the file descriptors provided by the 155 * test setup. 156 */ 157 static void 158 aio_context_init(struct aio_context *ac, int read_fd, 159 int write_fd, int buflen, int seconds, void (*cleanup)(void *), 160 void *cleanup_arg) 161 { 162 163 ATF_REQUIRE_MSG(buflen <= BUFFER_MAX, 164 "aio_context_init: buffer too large (%d > %d)", 165 buflen, BUFFER_MAX); 166 bzero(ac, sizeof(*ac)); 167 ac->ac_read_fd = read_fd; 168 ac->ac_write_fd = write_fd; 169 ac->ac_buflen = buflen; 170 srandomdev(); 171 ac->ac_seed = random(); 172 aio_fill_buffer(ac->ac_buffer, buflen, ac->ac_seed); 173 ATF_REQUIRE_MSG(aio_test_buffer(ac->ac_buffer, buflen, 174 ac->ac_seed) != 0, "aio_test_buffer: internal error"); 175 ac->ac_seconds = seconds; 176 ac->ac_cleanup = cleanup; 177 ac->ac_cleanup_arg = cleanup_arg; 178 } 179 180 /* 181 * Each tester can register a callback to clean up in the event the test 182 * fails. Preserve the value of errno so that subsequent calls to errx() 183 * work properly. 184 */ 185 static void 186 aio_cleanup(struct aio_context *ac) 187 { 188 int error; 189 190 if (ac->ac_cleanup == NULL) 191 return; 192 error = errno; 193 (ac->ac_cleanup)(ac->ac_cleanup_arg); 194 errno = error; 195 } 196 197 /* 198 * Perform a simple write test of our initialized data buffer to the provided 199 * file descriptor. 200 */ 201 static void 202 aio_write_test(struct aio_context *ac) 203 { 204 struct aiocb aio, *aiop; 205 ssize_t len; 206 207 ATF_REQUIRE_KERNEL_MODULE("aio"); 208 209 bzero(&aio, sizeof(aio)); 210 aio.aio_buf = ac->ac_buffer; 211 aio.aio_nbytes = ac->ac_buflen; 212 aio.aio_fildes = ac->ac_write_fd; 213 aio.aio_offset = 0; 214 215 aio_timeout_start(ac->ac_seconds); 216 217 if (aio_write(&aio) < 0) { 218 if (errno == EINTR) { 219 if (aio_timedout) { 220 aio_cleanup(ac); 221 atf_tc_fail("aio_write timed out"); 222 } 223 } 224 aio_cleanup(ac); 225 atf_tc_fail("aio_write failed: %s", strerror(errno)); 226 } 227 228 len = aio_waitcomplete(&aiop, NULL); 229 if (len < 0) { 230 if (errno == EINTR) { 231 if (aio_timedout) { 232 aio_cleanup(ac); 233 atf_tc_fail("aio_waitcomplete timed out"); 234 } 235 } 236 aio_cleanup(ac); 237 atf_tc_fail("aio_waitcomplete failed: %s", strerror(errno)); 238 } 239 240 aio_timeout_stop(); 241 242 if (len != ac->ac_buflen) { 243 aio_cleanup(ac); 244 atf_tc_fail("aio_waitcomplete short write (%jd)", 245 (intmax_t)len); 246 } 247 } 248 249 /* 250 * Perform a simple read test of our initialized data buffer from the 251 * provided file descriptor. 252 */ 253 static void 254 aio_read_test(struct aio_context *ac) 255 { 256 struct aiocb aio, *aiop; 257 ssize_t len; 258 259 ATF_REQUIRE_KERNEL_MODULE("aio"); 260 261 bzero(ac->ac_buffer, ac->ac_buflen); 262 bzero(&aio, sizeof(aio)); 263 aio.aio_buf = ac->ac_buffer; 264 aio.aio_nbytes = ac->ac_buflen; 265 aio.aio_fildes = ac->ac_read_fd; 266 aio.aio_offset = 0; 267 268 aio_timeout_start(ac->ac_seconds); 269 270 if (aio_read(&aio) < 0) { 271 if (errno == EINTR) { 272 if (aio_timedout) { 273 aio_cleanup(ac); 274 atf_tc_fail("aio_write timed out"); 275 } 276 } 277 aio_cleanup(ac); 278 atf_tc_fail("aio_read failed: %s", strerror(errno)); 279 } 280 281 len = aio_waitcomplete(&aiop, NULL); 282 if (len < 0) { 283 if (errno == EINTR) { 284 if (aio_timedout) { 285 aio_cleanup(ac); 286 atf_tc_fail("aio_waitcomplete timed out"); 287 } 288 } 289 aio_cleanup(ac); 290 atf_tc_fail("aio_waitcomplete failed: %s", strerror(errno)); 291 } 292 293 aio_timeout_stop(); 294 295 if (len != ac->ac_buflen) { 296 aio_cleanup(ac); 297 atf_tc_fail("aio_waitcomplete short read (%jd)", 298 (intmax_t)len); 299 } 300 301 if (aio_test_buffer(ac->ac_buffer, ac->ac_buflen, ac->ac_seed) == 0) { 302 aio_cleanup(ac); 303 atf_tc_fail("buffer mismatched"); 304 } 305 } 306 307 /* 308 * Series of type-specific tests for AIO. For now, we just make sure we can 309 * issue a write and then a read to each type. We assume that once a write 310 * is issued, a read can follow. 311 */ 312 313 /* 314 * Test with a classic file. Assumes we can create a moderate size temporary 315 * file. 316 */ 317 struct aio_file_arg { 318 int afa_fd; 319 char *afa_pathname; 320 }; 321 322 static void 323 aio_file_cleanup(void *arg) 324 { 325 struct aio_file_arg *afa; 326 327 afa = arg; 328 close(afa->afa_fd); 329 unlink(afa->afa_pathname); 330 } 331 332 #define FILE_LEN GLOBAL_MAX 333 #define FILE_TIMEOUT 30 334 ATF_TC_WITHOUT_HEAD(aio_file_test); 335 ATF_TC_BODY(aio_file_test, tc) 336 { 337 char pathname[PATH_MAX]; 338 struct aio_file_arg arg; 339 struct aio_context ac; 340 int fd; 341 342 ATF_REQUIRE_KERNEL_MODULE("aio"); 343 344 strcpy(pathname, PATH_TEMPLATE); 345 fd = mkstemp(pathname); 346 ATF_REQUIRE_MSG(fd != -1, "mkstemp failed: %s", strerror(errno)); 347 348 arg.afa_fd = fd; 349 arg.afa_pathname = pathname; 350 351 aio_context_init(&ac, fd, fd, FILE_LEN, 352 FILE_TIMEOUT, aio_file_cleanup, &arg); 353 aio_write_test(&ac); 354 aio_read_test(&ac); 355 356 aio_file_cleanup(&arg); 357 } 358 359 struct aio_fifo_arg { 360 int afa_read_fd; 361 int afa_write_fd; 362 char *afa_pathname; 363 }; 364 365 static void 366 aio_fifo_cleanup(void *arg) 367 { 368 struct aio_fifo_arg *afa; 369 370 afa = arg; 371 if (afa->afa_read_fd != -1) 372 close(afa->afa_read_fd); 373 if (afa->afa_write_fd != -1) 374 close(afa->afa_write_fd); 375 unlink(afa->afa_pathname); 376 } 377 378 #define FIFO_LEN 256 379 #define FIFO_TIMEOUT 30 380 ATF_TC_WITHOUT_HEAD(aio_fifo_test); 381 ATF_TC_BODY(aio_fifo_test, tc) 382 { 383 int error, read_fd = -1, write_fd = -1; 384 struct aio_fifo_arg arg; 385 char pathname[PATH_MAX]; 386 struct aio_context ac; 387 388 ATF_REQUIRE_KERNEL_MODULE("aio"); 389 390 /* 391 * In theory, mkstemp() can return a name that is then collided with. 392 * Because this is a regression test, we treat that as a test failure 393 * rather than retrying. 394 */ 395 strcpy(pathname, PATH_TEMPLATE); 396 ATF_REQUIRE_MSG(mkstemp(pathname) != -1, 397 "mkstemp failed: %s", strerror(errno)); 398 ATF_REQUIRE_MSG(unlink(pathname) == 0, 399 "unlink failed: %s", strerror(errno)); 400 ATF_REQUIRE_MSG(mkfifo(pathname, 0600) != -1, 401 "mkfifo failed: %s", strerror(errno)); 402 arg.afa_pathname = pathname; 403 arg.afa_read_fd = -1; 404 arg.afa_write_fd = -1; 405 406 read_fd = open(pathname, O_RDONLY | O_NONBLOCK); 407 if (read_fd == -1) { 408 error = errno; 409 aio_fifo_cleanup(&arg); 410 errno = error; 411 atf_tc_fail("read_fd open failed: %s", 412 strerror(errno)); 413 } 414 arg.afa_read_fd = read_fd; 415 416 write_fd = open(pathname, O_WRONLY); 417 if (write_fd == -1) { 418 error = errno; 419 aio_fifo_cleanup(&arg); 420 errno = error; 421 atf_tc_fail("write_fd open failed: %s", 422 strerror(errno)); 423 } 424 arg.afa_write_fd = write_fd; 425 426 aio_context_init(&ac, read_fd, write_fd, FIFO_LEN, 427 FIFO_TIMEOUT, aio_fifo_cleanup, &arg); 428 aio_write_test(&ac); 429 aio_read_test(&ac); 430 431 aio_fifo_cleanup(&arg); 432 } 433 434 struct aio_unix_socketpair_arg { 435 int asa_sockets[2]; 436 }; 437 438 static void 439 aio_unix_socketpair_cleanup(void *arg) 440 { 441 struct aio_unix_socketpair_arg *asa; 442 443 asa = arg; 444 close(asa->asa_sockets[0]); 445 close(asa->asa_sockets[1]); 446 } 447 448 #define UNIX_SOCKETPAIR_LEN 256 449 #define UNIX_SOCKETPAIR_TIMEOUT 30 450 ATF_TC_WITHOUT_HEAD(aio_unix_socketpair_test); 451 ATF_TC_BODY(aio_unix_socketpair_test, tc) 452 { 453 struct aio_unix_socketpair_arg arg; 454 struct aio_context ac; 455 int sockets[2]; 456 457 ATF_REQUIRE_KERNEL_MODULE("aio"); 458 459 ATF_REQUIRE_MSG(socketpair(PF_UNIX, SOCK_STREAM, 0, sockets) != -1, 460 "socketpair failed: %s", strerror(errno)); 461 462 arg.asa_sockets[0] = sockets[0]; 463 arg.asa_sockets[1] = sockets[1]; 464 aio_context_init(&ac, sockets[0], 465 sockets[1], UNIX_SOCKETPAIR_LEN, UNIX_SOCKETPAIR_TIMEOUT, 466 aio_unix_socketpair_cleanup, &arg); 467 aio_write_test(&ac); 468 aio_read_test(&ac); 469 470 aio_unix_socketpair_cleanup(&arg); 471 } 472 473 struct aio_pty_arg { 474 int apa_read_fd; 475 int apa_write_fd; 476 }; 477 478 static void 479 aio_pty_cleanup(void *arg) 480 { 481 struct aio_pty_arg *apa; 482 483 apa = arg; 484 close(apa->apa_read_fd); 485 close(apa->apa_write_fd); 486 }; 487 488 #define PTY_LEN 256 489 #define PTY_TIMEOUT 30 490 ATF_TC_WITHOUT_HEAD(aio_pty_test); 491 ATF_TC_BODY(aio_pty_test, tc) 492 { 493 struct aio_pty_arg arg; 494 struct aio_context ac; 495 int read_fd, write_fd; 496 struct termios ts; 497 int error; 498 499 ATF_REQUIRE_KERNEL_MODULE("aio"); 500 501 ATF_REQUIRE_MSG(openpty(&read_fd, &write_fd, NULL, NULL, NULL) == 0, 502 "openpty failed: %s", strerror(errno)); 503 504 arg.apa_read_fd = read_fd; 505 arg.apa_write_fd = write_fd; 506 507 if (tcgetattr(write_fd, &ts) < 0) { 508 error = errno; 509 aio_pty_cleanup(&arg); 510 errno = error; 511 atf_tc_fail("tcgetattr failed: %s", strerror(errno)); 512 } 513 cfmakeraw(&ts); 514 if (tcsetattr(write_fd, TCSANOW, &ts) < 0) { 515 error = errno; 516 aio_pty_cleanup(&arg); 517 errno = error; 518 atf_tc_fail("tcsetattr failed: %s", strerror(errno)); 519 } 520 aio_context_init(&ac, read_fd, write_fd, PTY_LEN, 521 PTY_TIMEOUT, aio_pty_cleanup, &arg); 522 523 aio_write_test(&ac); 524 aio_read_test(&ac); 525 526 aio_pty_cleanup(&arg); 527 } 528 529 static void 530 aio_pipe_cleanup(void *arg) 531 { 532 int *pipes = arg; 533 534 close(pipes[0]); 535 close(pipes[1]); 536 } 537 538 #define PIPE_LEN 256 539 #define PIPE_TIMEOUT 30 540 ATF_TC_WITHOUT_HEAD(aio_pipe_test); 541 ATF_TC_BODY(aio_pipe_test, tc) 542 { 543 struct aio_context ac; 544 int pipes[2]; 545 546 ATF_REQUIRE_KERNEL_MODULE("aio"); 547 548 ATF_REQUIRE_MSG(pipe(pipes) != -1, 549 "pipe failed: %s", strerror(errno)); 550 551 aio_context_init(&ac, pipes[0], pipes[1], PIPE_LEN, 552 PIPE_TIMEOUT, aio_pipe_cleanup, pipes); 553 aio_write_test(&ac); 554 aio_read_test(&ac); 555 556 aio_pipe_cleanup(pipes); 557 } 558 559 struct aio_md_arg { 560 int ama_mdctl_fd; 561 int ama_unit; 562 int ama_fd; 563 }; 564 565 static void 566 aio_md_cleanup(void *arg) 567 { 568 struct aio_md_arg *ama; 569 struct md_ioctl mdio; 570 int error; 571 572 ama = arg; 573 574 if (ama->ama_fd != -1) 575 close(ama->ama_fd); 576 577 if (ama->ama_unit != -1) { 578 bzero(&mdio, sizeof(mdio)); 579 mdio.md_version = MDIOVERSION; 580 mdio.md_unit = ama->ama_unit; 581 if (ioctl(ama->ama_mdctl_fd, MDIOCDETACH, &mdio) == -1) { 582 error = errno; 583 close(ama->ama_mdctl_fd); 584 errno = error; 585 atf_tc_fail("ioctl MDIOCDETACH failed: %s", 586 strerror(errno)); 587 } 588 } 589 590 close(ama->ama_mdctl_fd); 591 } 592 593 #define MD_LEN GLOBAL_MAX 594 #define MD_TIMEOUT 30 595 ATF_TC(aio_md_test); 596 ATF_TC_HEAD(aio_md_test, tc) 597 { 598 599 atf_tc_set_md_var(tc, "require.user", "root"); 600 } 601 ATF_TC_BODY(aio_md_test, tc) 602 { 603 int error, fd, mdctl_fd, unit; 604 char pathname[PATH_MAX]; 605 struct aio_md_arg arg; 606 struct aio_context ac; 607 struct md_ioctl mdio; 608 609 ATF_REQUIRE_KERNEL_MODULE("aio"); 610 611 mdctl_fd = open("/dev/" MDCTL_NAME, O_RDWR, 0); 612 ATF_REQUIRE_MSG(mdctl_fd != -1, 613 "opening /dev/%s failed: %s", MDCTL_NAME, strerror(errno)); 614 615 bzero(&mdio, sizeof(mdio)); 616 mdio.md_version = MDIOVERSION; 617 mdio.md_type = MD_MALLOC; 618 mdio.md_options = MD_AUTOUNIT | MD_COMPRESS; 619 mdio.md_mediasize = GLOBAL_MAX; 620 mdio.md_sectorsize = 512; 621 622 arg.ama_mdctl_fd = mdctl_fd; 623 arg.ama_unit = -1; 624 arg.ama_fd = -1; 625 if (ioctl(mdctl_fd, MDIOCATTACH, &mdio) < 0) { 626 error = errno; 627 aio_md_cleanup(&arg); 628 errno = error; 629 atf_tc_fail("ioctl MDIOCATTACH failed: %s", strerror(errno)); 630 } 631 632 arg.ama_unit = unit = mdio.md_unit; 633 snprintf(pathname, PATH_MAX, "/dev/md%d", unit); 634 fd = open(pathname, O_RDWR); 635 ATF_REQUIRE_MSG(fd != -1, 636 "opening %s failed: %s", pathname, strerror(errno)); 637 arg.ama_fd = fd; 638 639 aio_context_init(&ac, fd, fd, MD_LEN, MD_TIMEOUT, 640 aio_md_cleanup, &arg); 641 aio_write_test(&ac); 642 aio_read_test(&ac); 643 644 aio_md_cleanup(&arg); 645 } 646 647 ATF_TP_ADD_TCS(tp) 648 { 649 650 ATF_TP_ADD_TC(tp, aio_file_test); 651 ATF_TP_ADD_TC(tp, aio_fifo_test); 652 ATF_TP_ADD_TC(tp, aio_unix_socketpair_test); 653 ATF_TP_ADD_TC(tp, aio_pty_test); 654 ATF_TP_ADD_TC(tp, aio_pipe_test); 655 ATF_TP_ADD_TC(tp, aio_md_test); 656 657 return (atf_no_error()); 658 } 659