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