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 * fcntl17.c 23 * 24 * DESCRIPTION 25 * Check deadlock detection for file locking 26 * 27 * ALGORITHM 28 * The parent forks off 3 children. The parent controls the children 29 * with messages via pipes to create a delayed deadlock between the 30 * second and third child. 31 * 32 * USAGE 33 * fcntl17 34 * 35 * HISTORY 36 * 07/2001 Ported by Wayne Boyer 37 * 04/2002 Minor fixes by William Jay Huie (testcase name 38 fcntl05 => fcntl17, check signal return for SIG_ERR) 39 * 40 * RESTRICTIONS 41 * None 42 */ 43 44 #ifndef _GNU_SOURCE 45 #define _GNU_SOURCE 46 #endif 47 48 #include <fcntl.h> 49 #include <errno.h> 50 #include <signal.h> 51 #include <sys/stat.h> 52 #include <sys/types.h> 53 #include <sys/wait.h> 54 #include <inttypes.h> 55 56 #include "test.h" 57 58 char *TCID = "fcntl17"; 59 int TST_TOTAL = 1; 60 61 #define STRINGSIZE 27 62 #define STRING "abcdefghijklmnopqrstuvwxyz\n" 63 #define STOP 0xFFF0 64 #define TIME_OUT 10 65 66 /* global variables */ 67 int parent_pipe[2]; 68 int child_pipe1[2]; 69 int child_pipe2[2]; 70 int child_pipe3[2]; 71 int file_fd; 72 pid_t parent_pid, child_pid1, child_pid2, child_pid3; 73 int child_stat; 74 struct flock lock1 = { (short)F_WRLCK, (short)0, 2, 5, (short)0 }; 75 struct flock lock2 = { (short)F_WRLCK, (short)0, 9, 5, (short)0 }; 76 struct flock lock3 = { (short)F_WRLCK, (short)0, 17, 5, (short)0 }; 77 struct flock lock4 = { (short)F_WRLCK, (short)0, 17, 5, (short)0 }; 78 struct flock lock5 = { (short)F_WRLCK, (short)0, 2, 14, (short)0 }; 79 struct flock unlock = { (short)F_UNLCK, (short)0, 0, 0, (short)0 }; 80 81 /* prototype declarations */ 82 int setup(); 83 void cleanup(); 84 int parent_wait(); 85 void parent_free(); 86 void child_wait(); 87 void child_free(); 88 void do_child1(); 89 void do_child2(); 90 void do_child3(); 91 int do_test(struct flock *, pid_t); 92 void stop_children(); 93 void catch_child(); 94 void catch_alarm(); 95 char *str_type(); 96 97 int setup(void) 98 { 99 char *buf = STRING; 100 char template[PATH_MAX]; 101 struct sigaction act; 102 103 tst_sig(FORK, DEF_HANDLER, NULL); 104 umask(0); 105 TEST_PAUSE; 106 tst_tmpdir(); /* make temp dir and cd to it */ 107 108 if (pipe(parent_pipe) < 0) { 109 tst_resm(TFAIL, "Couldn't create parent_pipe! errno = %d", 110 errno); 111 return 1; 112 } 113 if (pipe(child_pipe1) < 0) { 114 tst_resm(TFAIL, "Couldn't create child_pipe1! errno = %d", 115 errno); 116 return 1; 117 } 118 if (pipe(child_pipe2) < 0) { 119 tst_resm(TFAIL, "Couldn't create child_pipe2! errno = %d", 120 errno); 121 return 1; 122 } 123 if (pipe(child_pipe3) < 0) { 124 tst_resm(TFAIL, "Couldn't create child_pipe3! errno = %d", 125 errno); 126 return 1; 127 } 128 parent_pid = getpid(); 129 snprintf(template, PATH_MAX, "fcntl17XXXXXX"); 130 131 if ((file_fd = mkstemp(template)) < 0) { 132 tst_resm(TFAIL, "Couldn't open temp file! errno = %d", errno); 133 } 134 135 if (write(file_fd, buf, STRINGSIZE) < 0) { 136 tst_resm(TFAIL, "Couldn't write to temp file! errno = %d", 137 errno); 138 } 139 140 memset(&act, 0, sizeof(act)); 141 act.sa_handler = catch_alarm; 142 sigemptyset(&act.sa_mask); 143 sigaddset(&act.sa_mask, SIGALRM); 144 if (sigaction(SIGALRM, &act, NULL) < 0) { 145 tst_resm(TFAIL, "SIGALRM signal setup failed, errno: %d", 146 errno); 147 return 1; 148 } 149 150 memset(&act, 0, sizeof(act)); 151 act.sa_handler = catch_child; 152 sigemptyset(&act.sa_mask); 153 sigaddset(&act.sa_mask, SIGCHLD); 154 if (sigaction(SIGCHLD, &act, NULL) < 0) { 155 tst_resm(TFAIL, "SIGCHLD signal setup failed, errno: %d", errno); 156 return 1; 157 } 158 return 0; 159 } 160 161 void cleanup(void) 162 { 163 if (child_pid1 > 0) 164 kill(child_pid1, 9); 165 166 if (child_pid2 > 0) 167 kill(child_pid2, 9); 168 169 if (child_pid3 > 0) 170 kill(child_pid3, 9); 171 172 close(file_fd); 173 tst_rmdir(); 174 175 } 176 177 void do_child1(void) 178 { 179 int err; 180 181 close(parent_pipe[0]); 182 close(child_pipe1[1]); 183 close(child_pipe2[0]); 184 close(child_pipe2[1]); 185 close(child_pipe3[0]); 186 close(child_pipe3[1]); 187 188 child_wait(child_pipe1[0]); 189 tst_resm(TINFO, "child 1 starting"); 190 if (fcntl(file_fd, F_SETLK, &lock1) < 0) { 191 err = errno; 192 tst_resm(TINFO, "child 1 lock err %d", err); 193 parent_free(err); 194 } else { 195 tst_resm(TINFO, "child 1 pid %d locked", getpid()); 196 parent_free(0); 197 } 198 199 child_wait(child_pipe1[0]); 200 tst_resm(TINFO, "child 1 resuming"); 201 fcntl(file_fd, F_SETLK, &unlock); 202 tst_resm(TINFO, "child 1 unlocked"); 203 204 child_wait(child_pipe1[0]); 205 tst_resm(TINFO, "child 1 exiting"); 206 exit(1); 207 } 208 209 void do_child2(void) 210 { 211 int err; 212 213 close(parent_pipe[0]); 214 close(child_pipe1[0]); 215 close(child_pipe1[1]); 216 close(child_pipe2[1]); 217 close(child_pipe3[0]); 218 close(child_pipe3[1]); 219 220 child_wait(child_pipe2[0]); 221 tst_resm(TINFO, "child 2 starting"); 222 if (fcntl(file_fd, F_SETLK, &lock2) < 0) { 223 err = errno; 224 tst_resm(TINFO, "child 2 lock err %d", err); 225 parent_free(err); 226 } else { 227 tst_resm(TINFO, "child 2 pid %d locked", getpid()); 228 parent_free(0); 229 } 230 231 child_wait(child_pipe2[0]); 232 tst_resm(TINFO, "child 2 resuming"); 233 if (fcntl(file_fd, F_SETLKW, &lock4) < 0) { 234 err = errno; 235 tst_resm(TINFO, "child 2 lockw err %d", err); 236 parent_free(err); 237 } else { 238 tst_resm(TINFO, "child 2 lockw locked"); 239 parent_free(0); 240 } 241 242 child_wait(child_pipe2[0]); 243 tst_resm(TINFO, "child 2 exiting"); 244 exit(1); 245 } 246 247 void do_child3(void) 248 { 249 int err; 250 251 close(parent_pipe[0]); 252 close(child_pipe1[0]); 253 close(child_pipe1[1]); 254 close(child_pipe2[0]); 255 close(child_pipe2[1]); 256 close(child_pipe3[1]); 257 258 child_wait(child_pipe3[0]); 259 tst_resm(TINFO, "child 3 starting"); 260 if (fcntl(file_fd, F_SETLK, &lock3) < 0) { 261 err = errno; 262 tst_resm(TINFO, "child 3 lock err %d", err); 263 parent_free(err); 264 } else { 265 tst_resm(TINFO, "child 3 pid %d locked", getpid()); 266 parent_free(0); 267 } 268 269 child_wait(child_pipe3[0]); 270 tst_resm(TINFO, "child 3 resuming"); 271 if (fcntl(file_fd, F_SETLKW, &lock5) < 0) { 272 err = errno; 273 tst_resm(TINFO, "child 3 lockw err %d", err); 274 parent_free(err); 275 } else { 276 tst_resm(TINFO, "child 3 lockw locked"); 277 parent_free(0); 278 } 279 280 child_wait(child_pipe3[0]); 281 tst_resm(TINFO, "child 3 exiting"); 282 exit(1); 283 } 284 285 int do_test(struct flock *lock, pid_t pid) 286 { 287 struct flock fl; 288 289 fl.l_type = /* lock->l_type */ F_RDLCK; 290 fl.l_whence = lock->l_whence; 291 fl.l_start = lock->l_start; 292 fl.l_len = lock->l_len; 293 fl.l_pid = (short)0; 294 if (fcntl(file_fd, F_GETLK, &fl) < 0) { 295 tst_resm(TFAIL, "fcntl on file failed, errno =%d", errno); 296 return 1; 297 } 298 299 if (fl.l_type != lock->l_type) { 300 tst_resm(TFAIL, "lock type is wrong should be %s is %s", 301 str_type(lock->l_type), str_type(fl.l_type)); 302 return 1; 303 } 304 305 if (fl.l_whence != lock->l_whence) { 306 tst_resm(TFAIL, "lock whence is wrong should be %d is %d", 307 lock->l_whence, fl.l_whence); 308 return 1; 309 } 310 311 if (fl.l_start != lock->l_start) { 312 tst_resm(TFAIL, "region starts in wrong place, " 313 "should be %" PRId64 " is %" PRId64, 314 (int64_t) lock->l_start, (int64_t) fl.l_start); 315 return 1; 316 } 317 318 if (fl.l_len != lock->l_len) { 319 tst_resm(TFAIL, 320 "region length is wrong, should be %" PRId64 " is %" 321 PRId64, (int64_t) lock->l_len, (int64_t) fl.l_len); 322 return 1; 323 } 324 325 if (fl.l_pid != pid) { 326 tst_resm(TFAIL, "locking pid is wrong, should be %d is %d", 327 pid, fl.l_pid); 328 return 1; 329 } 330 return 0; 331 } 332 333 char *str_type(int type) 334 { 335 static char buf[20]; 336 337 switch (type) { 338 case F_RDLCK: 339 return ("F_RDLCK"); 340 case F_WRLCK: 341 return ("F_WRLCK"); 342 case F_UNLCK: 343 return ("F_UNLCK"); 344 default: 345 sprintf(buf, "BAD VALUE: %d", type); 346 return (buf); 347 } 348 } 349 350 void parent_free(int arg) 351 { 352 if (write(parent_pipe[1], &arg, sizeof(arg)) != sizeof(arg)) { 353 tst_resm(TFAIL, "couldn't send message to parent"); 354 exit(1); 355 } 356 } 357 358 int parent_wait(void) 359 { 360 int arg; 361 362 if (read(parent_pipe[0], &arg, sizeof(arg)) != sizeof(arg)) { 363 tst_resm(TFAIL, "parent_wait() failed"); 364 return (errno); 365 } 366 return (arg); 367 } 368 369 void child_free(int fd, int arg) 370 { 371 if (write(fd, &arg, sizeof(arg)) != sizeof(arg)) { 372 tst_resm(TFAIL, "couldn't send message to child"); 373 exit(1); 374 } 375 } 376 377 void child_wait(int fd) 378 { 379 int arg; 380 381 if (read(fd, &arg, sizeof(arg)) != sizeof(arg)) { 382 tst_resm(TFAIL, "couldn't get message from parent"); 383 exit(1); 384 } else if (arg == (short)STOP) { 385 exit(0); 386 } 387 } 388 389 void stop_children(void) 390 { 391 int arg; 392 393 signal(SIGCHLD, SIG_DFL); 394 arg = STOP; 395 child_free(child_pipe1[1], arg); 396 child_free(child_pipe2[1], arg); 397 child_free(child_pipe3[1], arg); 398 waitpid(child_pid1, &child_stat, 0); 399 child_pid1 = 0; 400 waitpid(child_pid2, &child_stat, 0); 401 child_pid2 = 0; 402 waitpid(child_pid3, &child_stat, 0); 403 child_pid3 = 0; 404 } 405 406 void catch_child(void) 407 { 408 tst_resm(TFAIL, "Unexpected death of child process"); 409 cleanup(); 410 } 411 412 void catch_alarm(void) 413 { 414 sighold(SIGCHLD); 415 /* 416 * Timer has runout and the children have not detected the deadlock. 417 * Need to kill the kids and exit 418 */ 419 if (child_pid1 != 0 && (kill(child_pid1, SIGKILL)) < 0) { 420 tst_resm(TFAIL, "Attempt to signal child 1 failed."); 421 } 422 423 if (child_pid2 != 0 && (kill(child_pid2, SIGKILL)) < 0) { 424 tst_resm(TFAIL, "Attempt to signal child 2 failed."); 425 } 426 if (child_pid3 != 0 && (kill(child_pid3, SIGKILL)) < 0) { 427 tst_resm(TFAIL, "Attempt to signal child 2 failed."); 428 } 429 tst_resm(TFAIL, "Alarm expired, deadlock not detected"); 430 tst_resm(TWARN, "You may need to kill child processes by hand"); 431 cleanup(); 432 } 433 434 int main(int ac, char **av) 435 { 436 int ans; 437 int lc; 438 int fail = 0; 439 440 tst_parse_opts(ac, av, NULL, NULL); 441 #ifdef UCLINUX 442 maybe_run_child(&do_child1, "nddddddddd", 1, &file_fd, 443 &parent_pipe[0], &parent_pipe[1], 444 &child_pipe1[0], &child_pipe1[1], 445 &child_pipe2[0], &child_pipe2[1], 446 &child_pipe3[0], &child_pipe3[1]); 447 maybe_run_child(&do_child2, "nddddddddd", 2, &file_fd, 448 &parent_pipe[0], &parent_pipe[1], 449 &child_pipe1[0], &child_pipe1[1], 450 &child_pipe2[0], &child_pipe2[1], 451 &child_pipe3[0], &child_pipe3[1]); 452 maybe_run_child(&do_child3, "nddddddddd", 3, &file_fd, 453 &parent_pipe[0], &parent_pipe[1], 454 &child_pipe1[0], &child_pipe1[1], 455 &child_pipe2[0], &child_pipe2[1], 456 &child_pipe3[0], &child_pipe3[1]); 457 #endif 458 459 if (setup()) { /* global testup */ 460 tst_resm(TINFO, "setup failed"); 461 cleanup(); 462 } 463 464 /* check for looping state if -i option is given */ 465 for (lc = 0; TEST_LOOPING(lc); lc++) { 466 /* reset tst_count in case we are looping */ 467 tst_count = 0; 468 469 tst_resm(TINFO, "Enter preparation phase"); 470 if ((child_pid1 = FORK_OR_VFORK()) == 0) { /* first child */ 471 #ifdef UCLINUX 472 if (self_exec(av[0], "nddddddddd", 1, file_fd, 473 parent_pipe[0], parent_pipe[1], 474 child_pipe1[0], child_pipe1[1], 475 child_pipe2[0], child_pipe2[1], 476 child_pipe3[0], child_pipe3[1]) < 0) { 477 perror("self_exec failed, child 1"); 478 cleanup(); 479 } 480 #else 481 do_child1(); 482 #endif 483 } else if (child_pid1 < 0) 484 tst_brkm(TBROK|TERRNO, cleanup, "Fork failed: child 1"); 485 486 /* parent */ 487 488 if ((child_pid2 = fork()) == 0) { /* second child */ 489 #ifdef UCLINUX 490 if (self_exec(av[0], "nddddddddd", 2, file_fd, 491 parent_pipe[0], parent_pipe[1], 492 child_pipe1[0], child_pipe1[1], 493 child_pipe2[0], child_pipe2[1], 494 child_pipe3[0], child_pipe3[1]) < 0) { 495 perror("self_exec failed, child 2"); 496 cleanup(); 497 } 498 #else 499 do_child2(); 500 #endif 501 } else if (child_pid2 < 0) { 502 tst_brkm(TBROK|TERRNO, cleanup, "Fork failed: child 2"); 503 } 504 505 /* parent */ 506 507 if ((child_pid3 = fork()) == 0) { /* third child */ 508 #ifdef UCLINUX 509 if (self_exec(av[0], "nddddddddd", 3, file_fd, 510 parent_pipe[0], parent_pipe[1], 511 child_pipe1[0], child_pipe1[1], 512 child_pipe2[0], child_pipe2[1], 513 child_pipe3[0], child_pipe3[1]) < 0) { 514 perror("self_exec failed, child 3"); 515 cleanup(); 516 } 517 #else 518 do_child3(); 519 #endif 520 do_child3(); 521 } else if (child_pid3 < 0) { 522 tst_brkm(TBROK|TERRNO, cleanup, "Fork failed: child 3"); 523 } 524 /* parent */ 525 526 close(parent_pipe[1]); 527 close(child_pipe1[0]); 528 close(child_pipe2[0]); 529 close(child_pipe3[0]); 530 tst_resm(TINFO, "Exit preparation phase"); 531 532 /* //block1: */ 533 tst_resm(TINFO, "Enter block 1"); 534 fail = 0; 535 /* 536 * child 1 puts first lock (bytes 2-7) 537 */ 538 child_free(child_pipe1[1], 0); 539 if (parent_wait()) { 540 tst_resm(TFAIL, "didn't set first child's lock, " 541 "errno: %d", errno); 542 } 543 if (do_test(&lock1, child_pid1)) { 544 tst_resm(TINFO, "do_test failed child 1"); 545 fail = 1; 546 } 547 548 /* 549 * child 2 puts second lock (bytes 9-14) 550 */ 551 child_free(child_pipe2[1], 0); 552 if (parent_wait()) { 553 tst_resm(TINFO, "didn't set second child's lock, " 554 "errno: %d", errno); 555 fail = 1; 556 } 557 if (do_test(&lock2, child_pid2)) { 558 tst_resm(TINFO, "do_test failed child 2"); 559 fail = 1; 560 } 561 562 /* 563 * child 3 puts third lock (bytes 17-22) 564 */ 565 child_free(child_pipe3[1], 0); 566 if (parent_wait()) { 567 tst_resm(TFAIL, "didn't set third child's lock, " 568 "errno: %d", errno); 569 fail = 1; 570 } 571 if (do_test(&lock3, child_pid3)) { 572 tst_resm(TINFO, "do_test failed child 3"); 573 fail = 1; 574 } 575 576 /* 577 * child 2 tries to lock same range as 578 * child 3's first lock. 579 */ 580 child_free(child_pipe2[1], 0); 581 582 /* 583 * child 3 tries to lock same range as 584 * child 1 and child 2's first locks. 585 */ 586 child_free(child_pipe3[1], 0); 587 588 /* 589 * Tell child 1 to release its lock. This should cause a 590 * delayed deadlock between child 2 and child 3. 591 */ 592 child_free(child_pipe1[1], 0); 593 594 /* 595 * Setup an alarm to go off in case the deadlock is not 596 * detected 597 */ 598 alarm(TIME_OUT); 599 600 /* 601 * should get a message from child 3 telling that its 602 * second lock EDEADLOCK 603 */ 604 if ((ans = parent_wait()) != EDEADLK) { 605 tst_resm(TFAIL, "child 2 didn't deadlock, " 606 "returned: %d", ans); 607 fail = 1; 608 } 609 610 /* 611 * Double check that lock 2 and lock 3 are still right 612 */ 613 do_test(&lock2, child_pid2); 614 do_test(&lock3, child_pid3); 615 616 stop_children(); 617 618 if (fail) { 619 tst_resm(TFAIL, "Block 1 FAILED"); 620 } else { 621 tst_resm(TPASS, "Block 1 PASSED"); 622 } 623 tst_resm(TINFO, "Exit block 1"); 624 } 625 cleanup(); 626 tst_exit(); 627 } 628