1/* 2 * 3 * Copyright (c) International Business Machines Corp., 2001 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See 13 * the GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, write to the Free Software 17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 */ 19 20/* 21 * NAME 22 * fcntl16.c 23 * 24 * DESCRIPTION 25 * Additional file locking test cases for checking proper notifictaion 26 * of processes on lock change 27 * 28 * ALGORITHM 29 * Various test cases are used to lock a file opened without mandatory 30 * locking, with madatory locking and mandatory locking with NOBLOCK. 31 * Checking that processes waiting on lock boundaries are notified 32 * properly when boundaries change 33 * 34 * USAGE 35 * fcntl16 36 * 37 * HISTORY 38 * 07/2001 Ported by Wayne Boyer 39 * 04/2002 wjhuie sigset cleanups 40 * 41 * RESTRICTIONS 42 * None 43 */ 44 45#include <fcntl.h> 46#include <signal.h> 47#include <errno.h> 48#include "test.h" 49#include <sys/stat.h> 50#include <sys/types.h> 51#include <sys/wait.h> 52 53 54#define SKIPVAL 0x0f00 55//#define SKIP SKIPVAL, 0, 0L, 0L, IGNORED 56#define SKIP 0,0,0L,0L,0 57#if (SKIPVAL == F_RDLCK) || (SKIPVAL == F_WRLCK) 58#error invalid SKIP, must not be F_RDLCK or F_WRLCK 59#endif 60 61#define IGNORED 0 62#define NOBLOCK 2 /* immediate success */ 63#define WILLBLOCK 3 /* blocks, succeeds, parent unlocks records */ 64#define TIME_OUT 10 65int NO_NFS = 1; /* Test on NFS or not */ 66 67typedef struct { 68 struct flock parent_a; 69 struct flock parent_b; 70 struct flock child_a; 71 struct flock child_b; 72 struct flock parent_c; 73 struct flock parent_d; 74} testcase; 75 76static testcase testcases[] = { 77 /* #1 Parent_a making a write lock on entire file */ 78 {{F_WRLCK, 0, 0L, 0L, IGNORED}, 79 /* Parent_b skipped */ 80 {SKIP}, 81 /* Child_a read lock on byte 1 to byte 5 */ 82 {F_RDLCK, 0, 0L, 5L, NOBLOCK}, 83 /* Child_b read lock on byte 6 to byte 10 */ 84 {F_RDLCK, 0, 6L, 5L, NOBLOCK}, 85 /* 86 * Parent_c read lock on entire file 87 */ 88 {F_RDLCK, 0, 0L, 0L, IGNORED}, 89 /* Parent_d skipped */ 90 {SKIP},}, 91 92 /* #2 Parent_a making a write lock on entire file */ 93 {{F_WRLCK, 0, 0L, 0L, IGNORED}, 94 /* Parent_b skipped */ 95 {SKIP}, 96 /* Child_a read lock on byte 1 to byte 5 */ 97 {F_RDLCK, 0, 0L, 5L, WILLBLOCK}, 98 /* Child_b read lock on byte 6 to byte 10 */ 99 {F_RDLCK, 0, 6L, 5L, WILLBLOCK}, 100 /* 101 * Parent_c write lock on entire 102 * file 103 */ 104 {F_WRLCK, 0, 0L, 0L, IGNORED}, 105 /* Parent_d skipped */ 106 {SKIP},}, 107 108 /* #3 Parent_a making a write lock on entire file */ 109 {{F_WRLCK, 0, 0L, 0L, IGNORED}, 110 /* Parent_b skipped */ 111 {SKIP}, 112 /* Child_a read lock on byte 2 to byte 4 */ 113 {F_RDLCK, 0, 2L, 3L, WILLBLOCK}, 114 /* Child_b read lock on byte 6 to byte 8 */ 115 {F_RDLCK, 0, 6L, 3L, WILLBLOCK}, 116 /* 117 * Parent_c read lock on byte 3 to 118 * byte 7 119 */ 120 {F_RDLCK, 0, 3L, 5L, IGNORED}, 121 /* Parent_d skipped */ 122 {SKIP},}, 123 124 /* #4 Parent_a making a write lock on entire file */ 125 {{F_WRLCK, 0, 0L, 0L, IGNORED}, 126 /* Parent_b skipped */ 127 {SKIP}, 128 /* Child_a read lock on byte 2 to byte 4 */ 129 {F_RDLCK, 0, 2L, 3L, WILLBLOCK}, 130 /* Child_b read lock on byte 6 to byte 8 */ 131 {F_RDLCK, 0, 6L, 3L, NOBLOCK}, 132 /* 133 * Parent_c read lock on byte 5 to 134 * byte 9 135 */ 136 {F_RDLCK, 0, 5L, 5L, IGNORED}, 137 /* Parent_d skipped */ 138 {SKIP},}, 139 140 /* #5 Parent_a making a write lock on entire file */ 141 {{F_WRLCK, 0, 0L, 0L, IGNORED}, 142 /* Parent_b skipped */ 143 {SKIP}, 144 /* Child_a read lock on byte 3 to byte 7 */ 145 {F_RDLCK, 0, 3L, 5L, NOBLOCK}, 146 /* Child_b read lock on byte 5 to byte 10 */ 147 {F_RDLCK, 0, 5L, 6L, WILLBLOCK}, 148 /* 149 * Parent_c read lock on byte 2 to 150 * byte 8 151 */ 152 {F_RDLCK, 0, 2L, 7L, IGNORED}, 153 /* Parent_d skipped */ 154 {SKIP},}, 155 156 /* #6 Parent_a making a write lock on entire file */ 157 {{F_WRLCK, 0, 0L, 0L, IGNORED}, 158 /* Parent_b skipped */ 159 {SKIP}, 160 /* Child_a read lock on byte 2 to byte 4 */ 161 {F_RDLCK, 0, 2L, 3L, WILLBLOCK}, 162 /* Child_b write lock on byte 6 to byte 8 */ 163 {F_RDLCK, 0, 6L, 3L, NOBLOCK}, 164 /* Parent_c no lock on byte 3 to 9 */ 165 {F_UNLCK, 0, 3L, 7L, IGNORED}, 166 /* Parent_d skipped */ 167 {SKIP},}, 168 169 /* #7 Parent_a making a write lock on entire file */ 170 {{F_WRLCK, 0, 0L, 0L, IGNORED}, 171 /* Parent_b read lock on byte 3 to byte 7 */ 172 {F_RDLCK, 0, 3L, 5L, IGNORED}, 173 /* Child_a read lock on byte 2 to byte 4 */ 174 {F_RDLCK, 0, 2L, 3L, NOBLOCK}, 175 /* Child_b read lock on byte 6 to byte 8 */ 176 {F_RDLCK, 0, 6L, 3L, NOBLOCK}, 177 /* 178 * Parent_c read lock on byte 1 to 179 * byte 9 180 */ 181 {F_RDLCK, 0, 1L, 9L, IGNORED}, 182 /* Parent_d skipped */ 183 {SKIP},}, 184 185 /* #8 Parent_a making a write lock on byte 2 to byte 4 */ 186 {{F_WRLCK, 0, 2L, 3L, IGNORED}, 187 /* Parent_b write lock on byte 6 to byte 8 */ 188 {F_WRLCK, 0, 6L, 3L, IGNORED}, 189 /* Child_a read lock on byte 3 to byte 7 */ 190 {F_RDLCK, 0, 3L, 5L, NOBLOCK}, 191 /* Child_b skipped */ 192 {SKIP}, 193 /* 194 * Parent_c read lock on byte 1 to 195 * byte 5 196 */ 197 {F_RDLCK, 0, 1L, 5L, IGNORED}, 198 /* 199 * Parent_d read lock on 200 * byte 5 to byte 9 201 */ 202 {F_RDLCK, 0, 5L, 5L, 203 IGNORED},}, 204 205 /* #9 Parent_a making a write lock on entire file */ 206 {{F_WRLCK, 0, 0L, 0L, IGNORED}, 207 /* Parent_b read lock on byte 3 to byte 7 */ 208 {F_RDLCK, 0, 3L, 5L, IGNORED}, 209 /* Child_a read lock on byte 2 to byte 4 */ 210 {F_RDLCK, 0, 2L, 3L, NOBLOCK}, 211 /* Child_b read lock on byte 6 to byte 8 */ 212 {F_RDLCK, 0, 6L, 3L, NOBLOCK}, 213 /* 214 * Parent_c read lock on byte 1 to 215 * byte 3 216 */ 217 {F_RDLCK, 0, 1L, 3L, IGNORED}, 218 /* 219 * Parent_d read lock on 220 * byte 7 to byte 9 221 */ 222 {F_RDLCK, 0, 7L, 3L, 223 IGNORED},}, 224 225 /* #10 Parent_a making a write lock on entire file */ 226 {{F_WRLCK, 0, 0L, 0L, IGNORED}, 227 /* Parent_b skipped */ 228 {SKIP}, 229 /* Child_a read lock on byte 2 to byte 4 */ 230 {F_RDLCK, 0, 2L, 3L, NOBLOCK}, 231 /* Child_b read lock on byte 6 to byte 8 */ 232 {F_RDLCK, 0, 6L, 3L, NOBLOCK}, 233 /* 234 * Parent_c read lock on byte 1 to 235 * byte 7 236 */ 237 {F_RDLCK, 0, 1L, 7L, IGNORED}, 238 /* 239 * Parent_d read lock on 240 * byte 3 to byte 9 241 */ 242 {F_RDLCK, 0, 3L, 7L, 243 IGNORED},}, 244 245 /* #11 Parent_a making a write lock on entire file */ 246 {{F_WRLCK, 0, 0L, 0L, IGNORED}, 247 /* Parent_b skipped */ 248 {SKIP}, 249 /* Child_a read lock on byte 3 to byte 7 */ 250 {F_RDLCK, 0, 3L, 5L, NOBLOCK}, 251 /* Child_b read lock on byte 3 to byte 7 */ 252 {F_RDLCK, 0, 3L, 5L, NOBLOCK}, 253 /* 254 * Parent_c read lock on byte 3 to 255 * byte 7 256 */ 257 {F_RDLCK, 0, 3L, 5L, IGNORED}, 258 /* Parent_d skipped */ 259 {SKIP},}, 260}; 261 262static testcase *thiscase; 263static struct flock *thislock; 264static int parent; 265static int child_flag1 = 0; 266static int child_flag2 = 0; 267static int parent_flag = 0; 268static int alarm_flag = 0; 269static int child_pid[2], flag[2]; 270static int fd; 271static int test; 272static char tmpname[40]; 273 274#define FILEDATA "tenbytes!" 275 276extern void catch_int(int sig); /* signal catching subroutine */ 277 278char *TCID = "fcntl16"; 279int TST_TOTAL = 1; 280 281#ifdef UCLINUX 282static char *argv0; 283#endif 284 285/* 286 * cleanup - performs all the ONE TIME cleanup for this test at completion or 287 * premature exit 288 */ 289void cleanup(void) 290{ 291 tst_rmdir(); 292 293} 294 295void dochild(int kid) 296{ 297 /* child process */ 298 struct sigaction sact; 299 sact.sa_flags = 0; 300 sact.sa_handler = catch_int; 301 sigemptyset(&sact.sa_mask); 302 (void)sigaction(SIGUSR1, &sact, NULL); 303 304 /* Lock should succeed after blocking and parent releases lock */ 305 if (kid) { 306 if ((kill(parent, SIGUSR2)) < 0) { 307 tst_resm(TFAIL, "Attempt to send signal to parent " 308 "failed"); 309 tst_resm(TFAIL, "Test case %d, child %d, errno = %d", 310 test + 1, kid, errno); 311 exit(1); 312 } 313 } else { 314 if ((kill(parent, SIGUSR1)) < 0) { 315 tst_resm(TFAIL, "Attempt to send signal to parent " 316 "failed"); 317 tst_resm(TFAIL, "Test case %d, child %d, errno = %d", 318 test + 1, kid, errno); 319 exit(1); 320 } 321 } 322 323 if ((fcntl(fd, F_SETLKW, thislock)) < 0) { 324 if (errno == EINTR && parent_flag) { 325 /* 326 * signal received is waiting for lock to clear, 327 * this is expected if flag = WILLBLOCK 328 */ 329 exit(1); 330 } else { 331 tst_resm(TFAIL, "Attempt to set child BLOCKING lock " 332 "failed"); 333 tst_resm(TFAIL, "Test case %d, errno = %d", test + 1, 334 errno); 335 exit(2); 336 } 337 } 338 exit(0); 339} /* end of child process */ 340 341#ifdef UCLINUX 342static int kid_uc; 343 344void dochild_uc(void) 345{ 346 dochild(kid_uc); 347} 348#endif 349 350void catch_alarm(int sig) 351{ 352 alarm_flag = 1; 353} 354 355void catch_usr1(int sig) 356{ /* invoked on catching SIGUSR1 */ 357 /* 358 * Set flag to let parent know that child #1 is ready to have the 359 * lock removed 360 */ 361 child_flag1 = 1; 362} 363 364void catch_usr2(int sig) 365{ /* invoked on catching SIGUSR2 */ 366 /* 367 * Set flag to let parent know that child #2 is ready to have the 368 * lock removed 369 */ 370 child_flag2 = 1; 371} 372 373void catch_int(int sig) 374{ /* invoked on child catching SIGUSR1 */ 375 /* 376 * Set flag to interrupt fcntl call in child and force a controlled 377 * exit 378 */ 379 parent_flag = 1; 380} 381 382void child_sig(int sig, int nkids) 383{ 384 int i; 385 386 for (i = 0; i < nkids; i++) { 387 if (kill(child_pid[i], 0) == 0) { 388 if ((kill(child_pid[i], sig)) < 0) { 389 tst_resm(TFAIL, "Attempt to signal child %d, " 390 "failed", i + 1); 391 } 392 } 393 } 394} 395 396/* 397 * setup - performs all ONE TIME steup for this test 398 */ 399void setup(void) 400{ 401 struct sigaction sact; 402 403 tst_sig(FORK, DEF_HANDLER, cleanup); 404 405 umask(0); 406 407 /* Pause if option was specified */ 408 TEST_PAUSE; 409 410 parent = getpid(); 411 412 tst_tmpdir(); 413 414 /* On NFS or not */ 415 if (tst_fs_type(cleanup, ".") == TST_NFS_MAGIC) 416 NO_NFS = 0; 417 418 /* set up temp filename */ 419 sprintf(tmpname, "fcntl4.%d", parent); 420 421 /* 422 * Set up signal handling functions 423 */ 424 memset(&sact, 0, sizeof(sact)); 425 sact.sa_handler = catch_usr1; 426 sigemptyset(&sact.sa_mask); 427 sigaddset(&sact.sa_mask, SIGUSR1); 428 sigaction(SIGUSR1, &sact, NULL); 429 430 memset(&sact, 0, sizeof(sact)); 431 sact.sa_handler = catch_usr2; 432 sigemptyset(&sact.sa_mask); 433 sigaddset(&sact.sa_mask, SIGUSR2); 434 sigaction(SIGUSR2, &sact, NULL); 435 436 memset(&sact, 0, sizeof(sact)); 437 sact.sa_handler = catch_alarm; 438 sigemptyset(&sact.sa_mask); 439 sigaddset(&sact.sa_mask, SIGALRM); 440 sigaction(SIGALRM, &sact, NULL); 441} 442 443int run_test(int file_flag, int file_mode, int start, int end) 444{ 445 int child_count; 446 int child; 447 int nexited; 448 int status, expect_stat; 449 int i, fail = 0; 450 451 /* loop through all test cases */ 452 for (test = start; test < end; test++) { 453 /* open a temp file to lock */ 454 fd = open(tmpname, file_flag, file_mode); 455 if (fd < 0) { 456 tst_brkm(TBROK, cleanup, "open failed"); 457 } 458 459 /* write some dummy data to the file */ 460 (void)write(fd, FILEDATA, 10); 461 462 /* Initialize first parent lock structure */ 463 thiscase = &testcases[test]; 464 thislock = &thiscase->parent_a; 465 466 /* set the initial parent lock on the file */ 467 if ((fcntl(fd, F_SETLK, thislock)) < 0) { 468 tst_resm(TFAIL, "First parent lock failed"); 469 tst_resm(TFAIL, "Test case %d, errno = %d", test + 1, 470 errno); 471 close(fd); 472 unlink(tmpname); 473 return 1; 474 } 475 476 /* Initialize second parent lock structure */ 477 thislock = &thiscase->parent_b; 478 479 if ((thislock->l_type) != IGNORED) { /*SKIPVAL */ 480 /* set the second parent lock */ 481 if ((fcntl(fd, F_SETLK, thislock)) < 0) { 482 tst_resm(TFAIL, "Second parent lock failed"); 483 tst_resm(TFAIL, "Test case %d, errno = %d", 484 test + 1, errno); 485 close(fd); 486 unlink(tmpname); 487 return 1; 488 } 489 } 490 491 /* Initialize first child lock structure */ 492 thislock = &thiscase->child_a; 493 494 /* Initialize child counter and flags */ 495 alarm_flag = parent_flag = 0; 496 child_flag1 = child_flag2 = 0; 497 child_count = 0; 498 499 /* spawn child processes */ 500 for (i = 0; i < 2; i++) { 501 if (thislock->l_type != IGNORED) { 502 if ((child = FORK_OR_VFORK()) == 0) { 503#ifdef UCLINUX 504 if (self_exec(argv0, "ddddd", i, parent, 505 test, thislock, fd) < 0) { 506 perror("self_exec failed"); 507 return 1; 508 } 509#else 510 dochild(i); 511#endif 512 } 513 if (child < 0) { 514 perror("Fork failed"); 515 return 1; 516 } 517 child_count++; 518 child_pid[i] = child; 519 flag[i] = thislock->l_pid; 520 } 521 /* Initialize second child lock structure */ 522 thislock = &thiscase->child_b; 523 } 524 /* parent process */ 525 526 /* 527 * Wait for children to signal they are ready. Set a timeout 528 * just in case they don't signal at all. 529 */ 530 alarm(TIME_OUT); 531 532 while (!alarm_flag 533 && (child_flag1 + child_flag2 != child_count)) { 534 pause(); 535 } 536 537 /* 538 * Turn off alarm and unmask signals 539 */ 540 alarm((unsigned)0); 541 542 if (child_flag1 + child_flag2 != child_count) { 543 tst_resm(TFAIL, "Test case %d: kids didn't signal", 544 test + 1); 545 fail = 1; 546 } 547 child_flag1 = child_flag2 = alarm_flag = 0; 548 549 thislock = &thiscase->parent_c; 550 551 /* set the third parent lock on the file */ 552 if ((fcntl(fd, F_SETLK, thislock)) < 0) { 553 tst_resm(TFAIL, "Third parent lock failed"); 554 tst_resm(TFAIL, "Test case %d, errno = %d", 555 test + 1, errno); 556 close(fd); 557 unlink(tmpname); 558 return 1; 559 } 560 561 /* Initialize fourth parent lock structure */ 562 thislock = &thiscase->parent_d; 563 564 if ((thislock->l_type) != IGNORED) { /*SKIPVAL */ 565 /* set the fourth parent lock */ 566 if ((fcntl(fd, F_SETLK, thislock)) < 0) { 567 tst_resm(TINFO, "Fourth parent lock failed"); 568 tst_resm(TINFO, "Test case %d, errno = %d", 569 test + 1, errno); 570 close(fd); 571 unlink(tmpname); 572 return 1; 573 } 574 } 575 576 /* 577 * Wait for children to exit, or for timeout to occur. 578 * Timeouts are expected for testcases where kids are 579 * 'WILLBLOCK', In that case, send kids a wakeup interrupt 580 * and wait again for them. If a second timeout occurs, then 581 * something is wrong. 582 */ 583 alarm_flag = nexited = 0; 584 while (nexited < child_count) { 585 alarm(TIME_OUT); 586 child = wait(&status); 587 alarm(0); 588 589 if (child == -1) { 590 if (errno != EINTR || alarm_flag != 1) { 591 /* 592 * Some error other than a timeout, 593 * or else this is the second 594 * timeout. Both cases are errors. 595 */ 596 break; 597 } 598 599 /* 600 * Expected timeout case. Signal kids then 601 * go back and wait again 602 */ 603 child_sig(SIGUSR1, child_count); 604 continue; 605 } 606 607 for (i = 0; i < child_count; i++) 608 if (child == child_pid[i]) 609 break; 610 if (i == child_count) { 611 /* 612 * Ignore unexpected kid, it could be a 613 * leftover from a previous iteration that 614 * timed out. 615 */ 616 continue; 617 } 618 619 /* Found the right kid, check his status */ 620 nexited++; 621 622 expect_stat = (flag[i] == NOBLOCK) ? 0 : 1; 623 624 if (!WIFEXITED(status) 625 || WEXITSTATUS(status) != expect_stat) { 626 /* got unexpected exit status from kid */ 627 tst_resm(TFAIL, "Test case %d: child %d %s " 628 "or got bad status (x%x)", test + 1, 629 i, (flag[i] == NOBLOCK) ? 630 "BLOCKED unexpectedly" : 631 "failed to BLOCK", status); 632 fail = 1; 633 } 634 } 635 636 if (nexited != child_count) { 637 tst_resm(TFAIL, "Test case %d, caught %d expected %d " 638 "children", test + 1, nexited, child_count); 639 child_sig(SIGKILL, nexited); 640 fail = 1; 641 } 642 close(fd); 643 } 644 unlink(tmpname); 645 if (fail) { 646 return 1; 647 } else { 648 return 0; 649 } 650 return 0; 651} 652 653int main(int ac, char **av) 654{ 655 656 int lc; 657 658 tst_parse_opts(ac, av, NULL, NULL); 659#ifdef UCLINUX 660 maybe_run_child(dochild_uc, "ddddd", &kid_uc, &parent, &test, 661 &thislock, &fd); 662 argv0 = av[0]; 663#endif 664 665 setup(); /* global setup */ 666 667 for (lc = 0; TEST_LOOPING(lc); lc++) { 668 /* reset tst_count in case we are looping */ 669 tst_count = 0; 670 671/* //block1: */ 672 /* 673 * Check file locks on an ordinary file without 674 * mandatory locking 675 */ 676 tst_resm(TINFO, "Entering block 1"); 677 if (run_test(O_CREAT | O_RDWR | O_TRUNC, 0777, 0, 11)) { 678 tst_resm(TINFO, "Test case 1: without mandatory " 679 "locking FAILED"); 680 } else { 681 tst_resm(TINFO, "Test case 1: without manadatory " 682 "locking PASSED"); 683 } 684 tst_resm(TINFO, "Exiting block 1"); 685 686/* //block2: */ 687 /* 688 * Check the file locks on a file with mandatory record 689 * locking 690 */ 691 tst_resm(TINFO, "Entering block 2"); 692 if (NO_NFS && run_test(O_CREAT | O_RDWR | O_TRUNC, S_ISGID | 693 S_IRUSR | S_IWUSR, 0, 11)) { 694 tst_resm(TINFO, "Test case 2: with mandatory record " 695 "locking FAILED"); 696 } else { 697 if (NO_NFS) 698 tst_resm(TINFO, "Test case 2: with mandatory" 699 " record locking PASSED"); 700 else 701 tst_resm(TCONF, "Test case 2: NFS does not" 702 " support mandatory locking"); 703 } 704 tst_resm(TINFO, "Exiting block 2"); 705 706/* //block3: */ 707 /* 708 * Check file locks on a file with mandatory record locking 709 * and no delay 710 */ 711 tst_resm(TINFO, "Entering block 3"); 712 if (NO_NFS && run_test(O_CREAT | O_RDWR | O_TRUNC | O_NDELAY, 713 S_ISGID | S_IRUSR | S_IWUSR, 0, 11)) { 714 tst_resm(TINFO, "Test case 3: mandatory locking with " 715 "NODELAY FAILED"); 716 } else { 717 if (NO_NFS) 718 tst_resm(TINFO, "Test case 3: mandatory" 719 " locking with NODELAY PASSED"); 720 else 721 tst_resm(TCONF, "Test case 3: NFS does not" 722 " support mandatory locking"); 723 } 724 tst_resm(TINFO, "Exiting block 3"); 725 } 726 cleanup(); 727 tst_exit(); 728} 729