1/* 2 * Copyright (c) 2008 Vijay Kumar B. <vijaykumar@bravegnu.org> 3 * 4 * Based on testcases/kernel/syscalls/waitpid/waitpid01.c 5 * Original copyright message: 6 * 7 * Copyright (c) International Business Machines Corp., 2001 8 * 9 * This program is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License as published by 11 * the Free Software Foundation; either version 2 of the License, or 12 * (at your option) any later version. 13 * 14 * This program is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See 17 * the GNU General Public License for more details. 18 * 19 * You should have received a copy of the GNU General Public License 20 * along with this program; if not, write to the Free Software 21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 22 */ 23 24/* 25 * NAME 26 * eventfd01.c 27 * 28 * DESCRIPTION 29 * Test cases for eventfd syscall. 30 * 31 * USAGE: <for command-line> 32 * eventfd01 [-c n] [-i n] [-I x] [-P x] [-t] 33 * where, -c n : Run n copies concurrently. 34 * -i n : Execute test n times. 35 * -I x : Execute test for x seconds. 36 * -P x : Pause for x seconds between iterations. 37 * 38 * History 39 * 07/2008 Vijay Kumar 40 * Initial Version. 41 * 42 * Restrictions 43 * None 44 */ 45 46#include "config.h" 47 48#include <sys/types.h> 49#include <sys/select.h> 50#include <sys/wait.h> 51#include <errno.h> 52#include <fcntl.h> 53#include <inttypes.h> 54#include <poll.h> 55#include <signal.h> 56#include <stdint.h> 57#include <string.h> 58#include <unistd.h> 59 60#include "test.h" 61#define CLEANUP cleanup 62#include "linux_syscall_numbers.h" 63 64#ifdef HAVE_LIBAIO_H 65#include <libaio.h> 66#endif 67 68static void setup(void); 69 70TCID_DEFINE(eventfd01); 71int TST_TOTAL = 15; 72 73static int myeventfd(unsigned int initval, int flags) 74{ 75 /* eventfd2 uses FLAGS but eventfd doesn't take FLAGS. */ 76 return ltp_syscall(__NR_eventfd, initval); 77} 78 79/* 80 * clear_counter() - clears the counter by performing a dummy read 81 * @fd: the eventfd 82 * 83 * RETURNS: 84 * 0 on success, and -1 on failure 85 */ 86static int clear_counter(int fd) 87{ 88 uint64_t dummy; 89 int ret; 90 91 ret = read(fd, &dummy, sizeof(dummy)); 92 if (ret == -1) { 93 if (errno != EAGAIN) { 94 tst_resm(TINFO | TERRNO, "error clearing counter"); 95 return -1; 96 } 97 } 98 99 return 0; 100} 101 102/* 103 * set_counter() - sets the count to specified value 104 * @fd: the eventfd 105 * @val: the value to be set 106 * 107 * Clears the counter and sets the counter to @val. 108 * 109 * RETURNS: 110 * 0 on success, -1 on failure 111 */ 112static int set_counter(int fd, uint64_t val) 113{ 114 int ret; 115 116 ret = clear_counter(fd); 117 if (ret == -1) 118 return -1; 119 120 ret = write(fd, &val, sizeof(val)); 121 if (ret == -1) { 122 tst_resm(TINFO | TERRNO, "error setting counter value"); 123 return -1; 124 } 125 126 return 0; 127} 128 129/* 130 * Test whether the current value of the counter matches @required. 131 */ 132static void read_test(int fd, uint64_t required) 133{ 134 int ret; 135 uint64_t val; 136 137 ret = read(fd, &val, sizeof(val)); 138 if (ret == -1) { 139 tst_resm(TBROK | TERRNO, "error reading eventfd"); 140 return; 141 } 142 143 if (val == required) 144 tst_resm(TPASS, "counter value matches required"); 145 else 146 tst_resm(TFAIL, "counter value mismatch: " 147 "required: %" PRIu64 ", got: %" PRIu64, required, val); 148} 149 150/* 151 * Test whether read returns with error EAGAIN when counter is at 0. 152 */ 153static void read_eagain_test(int fd) 154{ 155 int ret; 156 uint64_t val; 157 158 ret = clear_counter(fd); 159 if (ret == -1) { 160 tst_resm(TBROK, "error clearing counter"); 161 return; 162 } 163 164 ret = read(fd, &val, sizeof(val)); 165 if (ret == -1) { 166 if (errno == EAGAIN) 167 tst_resm(TPASS, "read failed with EAGAIN as expected"); 168 else 169 tst_resm(TFAIL | TERRNO, "read failed (wanted EAGAIN)"); 170 } else 171 tst_resm(TFAIL, "read returned with %d", ret); 172} 173 174/* 175 * Test whether writing to counter works. 176 */ 177static void write_test(int fd) 178{ 179 int ret; 180 uint64_t val; 181 182 val = 12; 183 184 ret = set_counter(fd, val); 185 if (ret == -1) { 186 tst_resm(TBROK, "error setting counter value to %" PRIu64, val); 187 return; 188 } 189 190 read_test(fd, val); 191} 192 193/* 194 * Test whether write returns with error EAGAIN when counter is at 195 * (UINT64_MAX - 1). 196 */ 197static void write_eagain_test(int fd) 198{ 199 int ret; 200 uint64_t val; 201 202 ret = set_counter(fd, UINT64_MAX - 1); 203 if (ret == -1) { 204 tst_resm(TBROK, "error setting counter value to UINT64_MAX-1"); 205 return; 206 } 207 208 val = 1; 209 ret = write(fd, &val, sizeof(val)); 210 if (ret == -1) { 211 if (errno == EAGAIN) 212 tst_resm(TPASS, "write failed with EAGAIN as expected"); 213 else 214 tst_resm(TFAIL, "write failed (wanted EAGAIN)"); 215 } else 216 tst_resm(TFAIL, "write returned with %d", ret); 217} 218 219/* 220 * Test whether read returns with error EINVAL, if buffer size is less 221 * than 8 bytes. 222 */ 223static void read_einval_test(int fd) 224{ 225 uint32_t invalid; 226 int ret; 227 228 ret = read(fd, &invalid, sizeof(invalid)); 229 if (ret == -1) { 230 if (errno == EINVAL) 231 tst_resm(TPASS, "read failed with EINVAL as expected"); 232 else 233 tst_resm(TFAIL | TERRNO, "read failed (wanted EINVAL)"); 234 } else 235 tst_resm(TFAIL, "read returned with %d", ret); 236} 237 238/* 239 * Test whether write returns with error EINVAL, if buffer size is 240 * less than 8 bytes. 241 */ 242static void write_einval_test(int fd) 243{ 244 uint32_t invalid; 245 int ret; 246 247 ret = write(fd, &invalid, sizeof(invalid)); 248 if (ret == -1) { 249 if (errno == EINVAL) 250 tst_resm(TPASS, "write failed with EINVAL as expected"); 251 else 252 tst_resm(TFAIL | TERRNO, 253 "write failed (wanted EINVAL)"); 254 } else 255 tst_resm(TFAIL, "write returned with %d", ret); 256} 257 258/* 259 * Test wheter write returns with error EINVAL, when the written value 260 * is 0xFFFFFFFFFFFFFFFF. 261 */ 262static void write_einval2_test(int fd) 263{ 264 int ret; 265 uint64_t val; 266 267 ret = clear_counter(fd); 268 if (ret == -1) { 269 tst_resm(TBROK, "error clearing counter"); 270 return; 271 } 272 273 val = 0xffffffffffffffffLL; 274 ret = write(fd, &val, sizeof(val)); 275 if (ret == -1) { 276 if (errno == EINVAL) 277 tst_resm(TPASS, "write failed with EINVAL as expected"); 278 else 279 tst_resm(TFAIL | TERRNO, 280 "write failed (wanted EINVAL)"); 281 } else { 282 tst_resm(TFAIL, "write returned with %d", ret); 283 } 284} 285 286/* 287 * Test whether readfd is set by select when counter value is 288 * non-zero. 289 */ 290static void readfd_set_test(int fd) 291{ 292 int ret; 293 fd_set readfds; 294 struct timeval timeout = { 0, 0 }; 295 uint64_t non_zero = 10; 296 297 FD_ZERO(&readfds); 298 FD_SET(fd, &readfds); 299 300 ret = set_counter(fd, non_zero); 301 if (ret == -1) { 302 tst_resm(TBROK, "error setting counter value to %" PRIu64, 303 non_zero); 304 return; 305 } 306 307 ret = select(fd + 1, &readfds, NULL, NULL, &timeout); 308 if (ret == -1) { 309 /* EINTR cannot occur, since we don't block. */ 310 tst_resm(TBROK | TERRNO, "select() failed"); 311 return; 312 } 313 314 if (FD_ISSET(fd, &readfds)) 315 tst_resm(TPASS, "fd is set in readfds"); 316 else 317 tst_resm(TFAIL, "fd is not set in readfds"); 318} 319 320/* 321 * Test whether readfd is not set by select when counter value is 322 * zero. 323 */ 324static void readfd_not_set_test(int fd) 325{ 326 int ret; 327 fd_set readfds; 328 struct timeval timeout = { 0, 0 }; 329 330 FD_ZERO(&readfds); 331 FD_SET(fd, &readfds); 332 333 ret = clear_counter(fd); 334 if (ret == -1) { 335 tst_resm(TBROK, "error clearing counter"); 336 return; 337 } 338 339 ret = select(fd + 1, &readfds, NULL, NULL, &timeout); 340 if (ret == -1) { 341 /* EINTR cannot occur, since we don't block. */ 342 tst_resm(TBROK | TERRNO, "select() failed"); 343 return; 344 } 345 346 if (!FD_ISSET(fd, &readfds)) 347 tst_resm(TPASS, "fd is not set in readfds"); 348 else 349 tst_resm(TFAIL, "fd is set in readfds"); 350} 351 352/* 353 * Test whether writefd is set by select when counter value is not the 354 * maximum counter value. 355 */ 356static void writefd_set_test(int fd) 357{ 358 int ret; 359 fd_set writefds; 360 struct timeval timeout = { 0, 0 }; 361 uint64_t non_max = 10; 362 363 FD_ZERO(&writefds); 364 FD_SET(fd, &writefds); 365 366 ret = set_counter(fd, non_max); 367 if (ret == -1) { 368 tst_resm(TBROK, "error setting counter value to %" PRIu64, 369 non_max); 370 return; 371 } 372 373 ret = select(fd + 1, NULL, &writefds, NULL, &timeout); 374 if (ret == -1) { 375 /* EINTR cannot occur, since we don't block. */ 376 tst_resm(TBROK | TERRNO, "select: error getting fd status"); 377 return; 378 } 379 380 if (FD_ISSET(fd, &writefds)) 381 tst_resm(TPASS, "fd is set in writefds"); 382 else 383 tst_resm(TFAIL, "fd is not set in writefds"); 384} 385 386/* 387 * Test whether writefd is not set by select when counter value is at 388 * (UINT64_MAX - 1). 389 */ 390static void writefd_not_set_test(int fd) 391{ 392 int ret; 393 fd_set writefds; 394 struct timeval timeout = { 0, 0 }; 395 396 FD_ZERO(&writefds); 397 FD_SET(fd, &writefds); 398 399 ret = set_counter(fd, UINT64_MAX - 1); 400 if (ret == -1) { 401 tst_resm(TBROK, "error setting counter value to UINT64_MAX-1"); 402 return; 403 } 404 405 ret = select(fd + 1, NULL, &writefds, NULL, &timeout); 406 if (ret == -1) { 407 /* EINTR cannot occur, since we don't block. */ 408 tst_resm(TBROK | TERRNO, "select: error getting fd status"); 409 return; 410 } 411 412 if (!FD_ISSET(fd, &writefds)) 413 tst_resm(TPASS, "fd is not set in writefds"); 414 else 415 tst_resm(TFAIL, "fd is set in writefds"); 416} 417 418/* 419 * Test whether counter update in child is reflected in the parent. 420 */ 421static void child_inherit_test(int fd) 422{ 423 uint64_t val; 424 pid_t cpid; 425 int ret; 426 int status; 427 uint64_t to_parent = 0xdeadbeef; 428 uint64_t dummy; 429 430 cpid = fork(); 431 if (cpid == -1) 432 tst_resm(TBROK | TERRNO, "fork failed"); 433 else if (cpid != 0) { 434 ret = wait(&status); 435 if (ret == -1) { 436 tst_resm(TBROK, "error getting child exit status"); 437 return; 438 } 439 440 if (WEXITSTATUS(status) == 1) { 441 tst_resm(TBROK, "counter value write not " 442 "successful in child"); 443 return; 444 } 445 446 ret = read(fd, &val, sizeof(val)); 447 if (ret == -1) { 448 tst_resm(TBROK | TERRNO, "error reading eventfd"); 449 return; 450 } 451 452 if (val == to_parent) 453 tst_resm(TPASS, "counter value write from " 454 "child successful"); 455 else 456 tst_resm(TFAIL, "counter value write in child " 457 "failed"); 458 } else { 459 /* Child */ 460 ret = read(fd, &dummy, sizeof(dummy)); 461 if (ret == -1 && errno != EAGAIN) { 462 tst_resm(TWARN | TERRNO, "error clearing counter"); 463 exit(1); 464 } 465 466 ret = write(fd, &to_parent, sizeof(to_parent)); 467 if (ret == -1) { 468 tst_resm(TWARN | TERRNO, "error writing eventfd"); 469 exit(1); 470 } 471 472 exit(0); 473 } 474} 475 476#ifdef HAVE_IO_SET_EVENTFD 477/* 478 * Test whether counter overflow is detected and handled correctly. 479 * 480 * It is not possible to directly overflow the counter using the 481 * write() syscall. Overflows occur when the counter is incremented 482 * from kernel space, in an irq context, when it is not possible to 483 * block the calling thread of execution. 484 * 485 * The AIO subsystem internally uses eventfd mechanism for 486 * notification of completion of read or write requests. In this test 487 * we trigger a counter overflow, by setting the counter value to the 488 * max possible value initially. When the AIO subsystem notifies 489 * through the eventfd counter, the counter overflows. 490 * 491 * NOTE: If the the counter starts from an initial value of 0, it will 492 * take decades for an overflow to occur. But since we set the initial 493 * value to the max possible counter value, we are able to cause it to 494 * overflow with a single increment. 495 * 496 * When the counter overflows, the following are tested 497 * 1. Check whether POLLERR event occurs in poll() for the eventfd. 498 * 2. Check whether readfd_set/writefd_set is set in select() for the 499 eventfd. 500 * 3. The counter value is UINT64_MAX. 501 */ 502static int trigger_eventfd_overflow(int evfd, int *fd, io_context_t * ctx) 503{ 504 int ret; 505 struct iocb iocb; 506 struct iocb *iocbap[1]; 507 static char buf[4 * 1024]; 508 509 *ctx = 0; 510 ret = io_setup(16, ctx); 511 if (ret < 0) { 512 errno = -ret; 513 tst_resm(TINFO | TERRNO, "io_setup error"); 514 return -1; 515 } 516 517 *fd = open("testfile", O_RDWR | O_CREAT, 0644); 518 if (*fd == -1) { 519 tst_resm(TINFO | TERRNO, "open(testfile) failed"); 520 goto err_io_destroy; 521 } 522 523 ret = set_counter(evfd, UINT64_MAX - 1); 524 if (ret == -1) { 525 tst_resm(TINFO, "error setting counter to UINT64_MAX-1"); 526 goto err_close_file; 527 } 528 529 io_prep_pwrite(&iocb, *fd, buf, sizeof(buf), 0); 530 io_set_eventfd(&iocb, evfd); 531 532 iocbap[0] = &iocb; 533 ret = io_submit(*ctx, 1, iocbap); 534 if (ret < 0) { 535 errno = -ret; 536 tst_resm(TINFO | TERRNO, "error submitting iocb"); 537 goto err_close_file; 538 } 539 540 return 0; 541 542err_close_file: 543 close(*fd); 544 545err_io_destroy: 546 io_destroy(*ctx); 547 548 return -1; 549} 550 551static void cleanup_overflow(int fd, io_context_t ctx) 552{ 553 close(fd); 554 io_destroy(ctx); 555} 556 557static void overflow_select_test(int evfd) 558{ 559 struct timeval timeout = { 10, 0 }; 560 fd_set readfds; 561 int fd; 562 io_context_t ctx; 563 int ret; 564 565 ret = trigger_eventfd_overflow(evfd, &fd, &ctx); 566 if (ret == -1) { 567 tst_resm(TBROK, "error triggering eventfd overflow"); 568 return; 569 } 570 571 FD_ZERO(&readfds); 572 FD_SET(evfd, &readfds); 573 ret = select(evfd + 1, &readfds, NULL, NULL, &timeout); 574 if (ret == -1) 575 tst_resm(TBROK | TERRNO, 576 "error getting evfd status with select"); 577 else { 578 if (FD_ISSET(evfd, &readfds)) 579 tst_resm(TPASS, "read fd set as expected"); 580 else 581 tst_resm(TFAIL, "read fd not set"); 582 } 583 cleanup_overflow(fd, ctx); 584} 585 586static void overflow_poll_test(int evfd) 587{ 588 struct pollfd pollfd; 589 int fd; 590 io_context_t ctx; 591 int ret; 592 593 ret = trigger_eventfd_overflow(evfd, &fd, &ctx); 594 if (ret == -1) { 595 tst_resm(TBROK, "error triggering eventfd overflow"); 596 return; 597 } 598 599 pollfd.fd = evfd; 600 pollfd.events = POLLIN; 601 pollfd.revents = 0; 602 ret = poll(&pollfd, 1, 10000); 603 if (ret == -1) 604 tst_resm(TBROK | TERRNO, "error getting evfd status with poll"); 605 else { 606 if (pollfd.revents & POLLERR) 607 tst_resm(TPASS, "POLLERR occurred as expected"); 608 else 609 tst_resm(TFAIL, "POLLERR did not occur"); 610 } 611 cleanup_overflow(fd, ctx); 612} 613 614static void overflow_read_test(int evfd) 615{ 616 uint64_t count; 617 io_context_t ctx; 618 int fd; 619 int ret; 620 621 ret = trigger_eventfd_overflow(evfd, &fd, &ctx); 622 if (ret == -1) { 623 tst_resm(TBROK, "error triggering eventfd overflow"); 624 return; 625 } 626 627 ret = read(evfd, &count, sizeof(count)); 628 if (ret == -1) 629 tst_resm(TBROK | TERRNO, "error reading eventfd"); 630 else { 631 632 if (count == UINT64_MAX) 633 tst_resm(TPASS, "overflow occurred as expected"); 634 else 635 tst_resm(TFAIL, "overflow did not occur"); 636 } 637 cleanup_overflow(fd, ctx); 638} 639#else 640static void overflow_select_test(int evfd) 641{ 642 tst_resm(TCONF, "eventfd support is not available in AIO subsystem"); 643} 644 645static void overflow_poll_test(int evfd) 646{ 647 tst_resm(TCONF, "eventfd support is not available in AIO subsystem"); 648} 649 650static void overflow_read_test(int evfd) 651{ 652 tst_resm(TCONF, "eventfd support is not available in AIO subsystem"); 653} 654#endif 655 656int main(int argc, char **argv) 657{ 658 int lc; 659 int fd; 660 661 tst_parse_opts(argc, argv, NULL, NULL); 662 663 setup(); 664 665 for (lc = 0; TEST_LOOPING(lc); lc++) { 666 int ret; 667 uint64_t einit = 10; 668 669 tst_count = 0; 670 671 fd = myeventfd(einit, 0); 672 if (fd == -1) 673 tst_brkm(TBROK | TERRNO, CLEANUP, 674 "error creating eventfd"); 675 676 ret = fcntl(fd, F_SETFL, O_NONBLOCK); 677 if (ret == -1) 678 tst_brkm(TBROK | TERRNO, CLEANUP, 679 "error setting non-block mode"); 680 681 read_test(fd, einit); 682 read_eagain_test(fd); 683 write_test(fd); 684 write_eagain_test(fd); 685 read_einval_test(fd); 686 write_einval_test(fd); 687 write_einval2_test(fd); 688 readfd_set_test(fd); 689 readfd_not_set_test(fd); 690 writefd_set_test(fd); 691 writefd_not_set_test(fd); 692 child_inherit_test(fd); 693 overflow_select_test(fd); 694 overflow_poll_test(fd); 695 overflow_read_test(fd); 696 697 close(fd); 698 } 699 700 cleanup(); 701 702 tst_exit(); 703} 704 705static void setup(void) 706{ 707 708 tst_sig(FORK, DEF_HANDLER, cleanup); 709 710 if (tst_kvercmp(2, 6, 22) < 0) 711 tst_brkm(TCONF, NULL, "2.6.22 or greater kernel required"); 712 713 tst_tmpdir(); 714 715 TEST_PAUSE; 716} 717 718static void cleanup(void) 719{ 720 tst_rmdir(); 721} 722