1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 
  27 #include "nfsgen.h"
  28 
  29 char    *testname;
  30 
  31 #define BUFF_32k 32*1024
  32 
  33 #define MIN(a, b) ((a) < (b) ? (a) : (b))
  34 
  35 void usage(int);
  36 void fill_buffer(char *, int);
  37 void mk_file(char *, int, char *, int);
  38 void ck_file(int, int, char *);
  39 void ck_locking(int, int);
  40 
  41 /*
  42  * Prints out the usage message and exits with the
  43  * passed in exit code "ec"
  44  */
  45 void
  46 usage(int ec)
  47 {
  48         printf("\t Test UNINITIATED: ");
  49         printf("usage: %s -u <u.g>  -d <dbg> -b <base_dir> -s <fsize> \n"
  50             "          -n <ocnt> -l -v -W <tc_nap>\n", testname);
  51         puts("\t -u <u.g>       Uid(u) and Gid(g) to become (numeric value)\n");
  52         puts("\t -d <dbg>       Information level: 0 - none \n"
  53             "\t                                  1 - errors \n"
  54             "\t                                  2 - errors and debug\n");
  55         puts("\t -b <base_dir>  The directory under which to create files\n");
  56         puts("\t -s <fsize>     The size to make the files created\n");
  57         puts("\t -n <ocnt>      Number of files to create and open\n");
  58         puts("\t -l             Skip the locking test\n");
  59         puts("\t -v             Skip the file content validation test\n");
  60         puts("\t -W <tc_nap>    Pause period (in seconds)  \n"
  61             "\t -S <num>       Scenario number \n");
  62         exit(ec);
  63 }
  64 
  65 /*
  66  * For a buffer "ptr" fill it with a numerically
  67  * increasing byte value for the entire "size"
  68  * of the buffer.
  69  */
  70 void
  71 fill_buffer(char *ptr, int size)
  72 {
  73         int i;
  74 
  75         for (i = 0; i < size; i++) {
  76                 ptr[i] = (i & 0xff);
  77         }
  78 }
  79 
  80 /*
  81  * Create a file using "path" and "file_flags" then write
  82  * the data described by "buf" and size then close the file.
  83  */
  84 void
  85 mk_file(char *path, int file_flags, char *buf, int size)
  86 {
  87         int fd, rc;
  88 
  89         /*
  90          * create and open a file
  91          */
  92         if ((fd = open_file(path, file_flags, 0777)) < 0) {
  93                 fprintf(stderr, "\t Test  UNINITIATED: ");
  94                 exit(NOOK);
  95         }
  96 
  97         if ((rc = write(fd, buf, size)) != size) {
  98                 fprintf(stderr, "\t Test UNINITIATED: ");
  99                 fprintf(stderr, "error on write (%d)\n", errno);
 100                 close_file(fd, path);
 101                 exit(NOOK);
 102         }
 103         close(fd);
 104 }
 105 
 106 /*
 107  * Close all the files.
 108  */
 109 void
 110 cls_file(int fds[], int file_opens)
 111 {
 112         int c;
 113         char  fileGumbo[25];
 114 
 115         for (c = 0; c < file_opens; c++) {
 116                 sprintf(fileGumbo, "F%06d", c);
 117                 close_file(fds[c], fileGumbo);
 118         }
 119 }
 120 
 121 /*
 122  * The intent is to verify that the file "fd" still matches
 123  * "buffy" which is a 32k buffer setup by fill_buffer for
 124  * the size of the file "file_size".
 125  */
 126 void
 127 ck_file(int fd, int file_size, char *buffy)
 128 {
 129         int  blk = 0, rc, wc, fs = file_size;
 130         char yffub[BUFF_32k];
 131 
 132 
 133         do {
 134                 /*
 135                  * compare in 32k blocks.
 136                  */
 137                 wc = MIN(fs, BUFF_32k);
 138 
 139                 if ((rc = read(fd, yffub, wc)) != wc) {
 140                         fprintf(stderr, "\t Test FAIL: ");
 141                         Perror("read():");
 142                         exit(NOOK);
 143                 }
 144 
 145                 if ((rc = memcmp(buffy, yffub, wc)) != 0) {
 146                         fprintf(stderr, "\t Test FAIL: ");
 147                         eprint("(rc=%d) written != read "
 148                             " in 32k blk @offset %d\n",
 149                             rc, blk);
 150                         exit(NOOK);
 151                 }
 152                 blk += wc;
 153                 fs -= wc;
 154         } while (fs);
 155 }
 156 
 157 /*
 158  * For each "file_opens" file descriptors in array "fds"
 159  * open the file, acquire a write lock then fork a child
 160  * that hammers to get a write lock, in the meantime the
 161  * parent sleeps for "parent_sleep" time, wakes up and
 162  * releases the initial write lock and waits for the
 163  * child to exit.
 164  */
 165 int
 166 s1(int *fds, int file_opens, int parent_sleep, char *buffy)
 167 {
 168         char fileGumbo[35];
 169         int  stat;
 170         pid_t kid;
 171         int   c, s;
 172 
 173         for (c = 0; c < file_opens; c++) {
 174                 sprintf(fileGumbo, "F%06d", c);
 175                 fds[c] = open_file(fileGumbo, O_RDWR, 0);
 176                 if (fds[c] < 0) {
 177                         fprintf(stderr, "\t Test FAIL: ");
 178                         eprint("EEK!.. open failed");
 179                         return (-1);
 180                 } else {
 181                         /* parent will lock file first.. */
 182                         if (lock_reg(fds[c], 0,  F_WRLCK, 0, 0, 0) != OK) {
 183                                 /* error */
 184                                 fprintf(stderr, "\t Test FAIL: ");
 185                                 eprint("lock: not acquired\n");
 186                                 return (-1);
 187                         }
 188 
 189                         if ((kid = fork()) == 0) {
 190                                 /*
 191                                  * kid spins till parent sleep time
 192                                  * exhaused..
 193                                  * but try not to print the conflict lock error.
 194                                  */
 195                                 s = showerror;
 196                                 if (debug == 0)
 197                                         showerror = 0;
 198                                 while (lock_reg(fds[c], 0, F_WRLCK,
 199                                     0, 0, 0) != OK) {
 200                                         if (errno != EAGAIN) {
 201                                                 fprintf(stderr,
 202                                                     "\t Test FAIL: ");
 203                                                 Perror("Child: WRLCK");
 204                                                 exit(1);
 205                                         }
 206                                 }
 207                                 showerror = s;
 208 
 209                                 if (lock_reg(fds[c], 0, F_UNLCK, 0, 0,
 210                                     0) != OK) {
 211                                         fprintf(stderr, "\t Test FAIL: ");
 212                                         eprint("Child: unlock failed\n");
 213                                         exit(2);
 214                                 }
 215                                 /* kid delete it */
 216                                 unlink(fileGumbo);
 217                                 exit(0);
 218                         } else {
 219                                 /* parent.. */
 220 
 221                                 sleep(parent_sleep);
 222                                 if (lock_reg(fds[c], 0, F_UNLCK, 0, 0,
 223                                     0) != OK) {
 224                                         fprintf(stderr, "\t Test FAIL: ");
 225                                         eprint("unlock failed\n");
 226                                 }
 227                                 /* hang about for the kid .. */
 228                                 wait(&stat);
 229                         }
 230                 }
 231                 /* and now.. parent deletes it */
 232                 unlink(fileGumbo);
 233         }
 234         printf("\t Test PASS: successfully completed execution runs.\n");
 235 
 236         return (0);
 237 }
 238 
 239 /*
 240  * For "file_opens" file descriptors in "fds" open the file
 241  * read donly, close it and open it write only, close it and
 242  * then open it read only finally close and unlink it.
 243  */
 244 void
 245 s2(int *fds, int file_opens)
 246 {
 247         int c;
 248         char fileGumbo[35];
 249 
 250         dprint("Opening files O_RDONLY: ");
 251         for (c = 0; c < file_opens; c++) {
 252                 sprintf(fileGumbo, "F%06d", c);
 253                 fds[c] = open_file(fileGumbo, O_RDONLY, 0);
 254                 if (fds[c] < 0) {
 255                         fprintf(stderr, "\t Test FAIL: ");
 256                         eprint("0001 EEK!.. open failed (%s)\n",
 257                             fileGumbo);
 258                 }
 259         }
 260         dprint("OK\n");
 261 
 262         cls_file(fds, file_opens);
 263 
 264         dprint("Reopening files O_WRONLY: ");
 265         for (c = 0; c < file_opens; c++) {
 266                 sprintf(fileGumbo, "F%06d", c);
 267                 fds[c] = open_file(fileGumbo, O_WRONLY, 0);
 268                 if (fds[c] < 0) {
 269                         fprintf(stderr, "\t Test FAIL: ");
 270                         eprint("0002 EEK!.. open(O_WRONLY) failed (%s)\n",
 271                             fileGumbo);
 272                 }
 273         }
 274         dprint("OK\n");
 275 
 276         cls_file(fds, file_opens);
 277 
 278         dprint("Reopening files O_RDONLY: ");
 279         for (c = 0; c < file_opens; c++) {
 280                 sprintf(fileGumbo, "F%06d", c);
 281                 fds[c] = open_file(fileGumbo, O_RDONLY, 0);
 282                 if (fds[c] < 0) {
 283                         fprintf(stderr, "\t Test FAIL: ");
 284                         eprint("0003 EEK!.. open(O_RDONLY) failed (%s)\n",
 285                             fileGumbo);
 286                 }
 287         }
 288         dprint("OK\n");
 289 
 290         dprint("Close and unlink files: ");
 291         for (c = 0; c < file_opens; c++) {
 292                 close(fds[c]);
 293                 sprintf(fileGumbo, "F%06d", c);
 294                 unlink(fileGumbo);
 295         }
 296         dprint("OK\n");
 297 
 298         printf("\t Test PASS: successfully completed execution runs.\n");
 299 }
 300 
 301 /*
 302  * For "file_opens" file descriptors in "fds" open the file
 303  * read/write read_lock the entire file, write_lock the
 304  * first anad last 1024 bytes, release the 1st read_lock,
 305  * get a write_lock on thte rest of thte file (middle bit)
 306  * unlock everythihng and delete file.
 307  *
 308  */
 309 void
 310 s3(int *fds, int file_opens)
 311 {
 312         int c;
 313         char fileGumbo[35];
 314 
 315         for (c = 0; c < file_opens; c++) {
 316                 sprintf(fileGumbo, "F%06d", c);
 317                 fds[c] = open_file(fileGumbo, O_RDWR, 0);
 318                 if (fds[c] < 0) {
 319                         fprintf(stderr, "\t Test FAIL: ");
 320                         eprint("0001 EEK!.. open failed (%s)\n",
 321                             fileGumbo);
 322                 }
 323         }
 324 
 325         for (c = 0; c < file_opens; c++) {
 326                 /* Get a read lock for the entire file. */
 327                 if (lock_reg(fds[c], 0, F_RDLCK, 0, 0, 0) != OK) {
 328                         /* error */
 329                         fprintf(stderr, "\t Test FAIL: ");
 330                         eprint("read lock not acquired (F%06d)\n", c);
 331                         return;
 332                 }
 333                 /* now write lock for last 1024 bytes of the file */
 334                 if (lock_reg(fds[c], 0,  F_WRLCK, 0, SEEK_END, -1024) != OK) {
 335                         /* error */
 336                         fprintf(stderr, "\t Test FAIL: ");
 337                         eprint("wrirte lock last 1k not acquired (F%06d)\n", c);
 338                         return;
 339                 }
 340 
 341                 /* now a write lock for first 1024 bytes. */
 342                 if (lock_reg(fds[c], 0,  F_WRLCK, 0, SEEK_SET, 1024) != OK) {
 343                         /* error */
 344                         fprintf(stderr, "\t Test FAIL: ");
 345                         eprint("write lock first 1k not acquired (F%06d)\n", c);
 346                         return;
 347                 }
 348 
 349                 /* release thte read lock */
 350                 if (lock_reg(fds[c], 0,  F_UNLCK, 0, 0, 0) != OK) {
 351                         /* error */
 352                         fprintf(stderr, "\t Test FAIL: ");
 353                         eprint("unlock failed (F%06d) for read lock\n", c);
 354                         return;
 355                 }
 356 
 357                 /* get a write lock for the middle of the file.. */
 358                 if (lock_reg(fds[c], 0,  F_WRLCK, 1024+1, SEEK_SET,
 359                     (BUFF_32k-(2048+1))) != OK) {
 360                         /* error */
 361                         fprintf(stderr, "\t Test FAIL: ");
 362                         eprint("write lock middle chunk not "
 363                             "acquired (F%06d)\n", c);
 364                         return;
 365                 }
 366                 if (lock_reg(fds[c], 0,  F_UNLCK, 0, SEEK_END, -1024) != OK) {
 367                         /* error */
 368                         fprintf(stderr, "\t Test FAIL: ");
 369                         eprint("wrirte lock last 1k not acquired (F%06d)\n", c);
 370                         return;
 371                 }
 372 
 373                 /* now a write lock for first 1024 bytes. */
 374                 if (lock_reg(fds[c], 0,  F_UNLCK, 0, SEEK_SET, 1024) != OK) {
 375                         /* error */
 376                         fprintf(stderr, "\t Test FAIL: ");
 377                         eprint("write lock first 1k not acquired (F%06d)\n", c);
 378                         return;
 379                 }
 380                 /* get a write lock for the middle of the file.. */
 381                 if (lock_reg(fds[c], 0, F_UNLCK, 1024+1, SEEK_SET,
 382                     (BUFF_32k-(2048+1))) != OK) {
 383                         /* error */
 384                         fprintf(stderr, "\t Test FAIL: ");
 385                         eprint("write lock middle chunk not "
 386                             "acquired (F%06d)\n", c);
 387                         return;
 388                 }
 389                 close(fds[c]);
 390         }
 391         /* now run 'n delete 'em.. */
 392         for (c = 0; c < file_opens; c++) {
 393                 sprintf(fileGumbo, "F%06d", c);
 394                 unlink(fileGumbo);
 395         }
 396 
 397         printf("\t Test PASS: successfully completed execution runs.\n");
 398 }
 399 /*
 400  * For each "file_opens" file descriptors in array "fds"
 401  * open the file, acquire a write lock then unlink the
 402  * file _without_ a close.
 403  */
 404 void
 405 s4(int *fds, int file_opens)
 406 {
 407         char fileGumbo[35];
 408         int c;
 409 
 410         for (c = 0; c < file_opens; c++) {
 411                 sprintf(fileGumbo, "F%06d", c);
 412                 fds[c] = open_file(fileGumbo, O_RDWR, 0);
 413                 if (fds[c] < 0) {
 414                         fprintf(stderr, "\t Test FAIL: ");
 415                         printf("EEK!.. open failed");
 416                 } else {
 417                         /*  lock file  */
 418                         if (lock_reg(fds[c], 0, F_WRLCK, 0, 0, 0) != OK) {
 419                                 /* error */
 420                                 fprintf(stderr, "\t Test FAIL: ");
 421                                 eprint("lock: not acquired\n");
 422                         }
 423                         /* yank out thte file without a close() */
 424                         unlink(fileGumbo);
 425                 }
 426         }
 427         printf("\t Test PASS: successfully completed execution runs.\n");
 428 }
 429 
 430 /*
 431  * Main test loop.
 432  */
 433 int
 434 main(int  argc, char *argv[])
 435 {
 436         extern int  optind;
 437         extern char *optarg;
 438 
 439         char  buffy[BUFF_32k];
 440         char  fileGumbo[25];
 441 
 442         char  *buf, *base_dir = NULL;
 443 
 444         int   *fds, c;
 445 
 446         int   do_lock_checking = 1, do_content_validation = 1, nap_time = 30;
 447 
 448         int   file_opens = 250;
 449         int   file_size  = BUFF_32k;
 450         int   file_flags = (O_CREAT|O_TRUNC|O_RDWR);
 451         int   mand = 0;
 452         int   stressTest = 0;
 453 
 454         struct rlimit rlp;
 455 
 456         testname = argv[0];
 457 
 458         while ((c = getopt(argc, argv, "S:d:b:s:n:hW:lv")) != -1) {
 459 
 460                 switch (c) {
 461                 /* sez which stress test to do.. */
 462                 case 'S':
 463                         stressTest = atoi(optarg);
 464                         break;
 465                 /* Skip the lock checks */
 466                 case 'l':
 467                         do_lock_checking = 0;
 468                         break;
 469                 /* Skip the content validation */
 470                 case 'v':
 471                         do_content_validation = 0;
 472                         break;
 473                 /* number of files to open */
 474                 case 'n':
 475                         file_opens = atoi(optarg);
 476                         break;
 477                 /* the size of a file */
 478                 case 's':
 479                         file_size = atoi(optarg);
 480                         break;
 481                 /* base directory into which chdir and create files */
 482                 case 'b':
 483                         base_dir = optarg;
 484                         break;
 485                 /*
 486                  * debug flags treated as bit field for
 487                  * debug and showerror
 488                  */
 489                 case 'd':
 490                         switch (atoi(optarg)) {
 491                         case 0:
 492                                 debug = 0;
 493                                 showerror = 0;
 494                                 break;
 495                         case 1:
 496                                 debug = 0;
 497                                 showerror = 1;
 498                                 break;
 499                         case 2:
 500                                 debug = 1;
 501                                 showerror = 1;
 502                                 break;
 503                         default:
 504                                 usage(-1);
 505                         }
 506                         break;
 507 
 508                 /* the user wants me to nap... */
 509                 case 'W':
 510                         nap_time = atoi(optarg);
 511                         break;
 512                 case 'h':
 513                         usage(0);
 514                         break;
 515                 default:
 516                         usage(-1);
 517                 }
 518         }
 519 
 520         if (base_dir == NULL) {
 521                 fprintf(stderr, "\t Test  UNINITIATED: ");
 522                 printf(" specify base directory via -b\n");
 523                 usage(-1);
 524         }
 525 
 526         if (getrlimit(RLIMIT_NOFILE, &rlp) < 0) {
 527                 fprintf(stderr, "\t Test  UNINITIATED: ");
 528                 eprint("getrlimit() for RLIMIT_NOFILE failed\n");
 529                 Perror(":-(");
 530                 return (-1);
 531         }
 532 
 533         dprint("RLMIT_NOFILE is cur=%d / max=%d\n",
 534             rlp.rlim_cur, rlp.rlim_max);
 535 
 536         /*
 537          * The user has specified a number of files to open.
 538          * We may have to increase the process limit for MAX
 539          * open files.  We also need to account for the fact
 540          * that the process already has 3 open file descriptors
 541          * for std{in,our,err}.
 542          */
 543         if (file_opens+3 > rlp.rlim_cur) {
 544                 rlp.rlim_cur = MIN(rlp.rlim_max, file_opens+3);
 545                 if (rlp.rlim_cur <= file_opens)
 546                         file_opens =  rlp.rlim_cur-3;
 547 
 548                 if (setrlimit(RLIMIT_NOFILE, &rlp) < 0) {
 549                         fprintf(stderr, "\t Test  UNINITIATED: ");
 550                         eprint("setrlimit() for RLIMIT_NOFILE failed\n");
 551                         Perror(":-/");
 552                         return (-1);
 553                 }
 554         }
 555 
 556         fill_buffer(buffy, BUFF_32k);
 557 
 558         if (chdir(base_dir) != 0) {
 559                 fprintf(stderr, "\t Test  UNINITIATED: ");
 560                 eprint("chdir() to %s failed\n");
 561                 Perror("chdir()");
 562                 return (-1);
 563         }
 564 
 565         /*
 566          * generate file names and files.
 567          */
 568         dprint("Generating files: ");
 569         for (c = 0; c < file_opens; c++) {
 570                 sprintf(fileGumbo, "F%06d", c);
 571                 mk_file(fileGumbo, file_flags, buffy, BUFF_32k);
 572         }
 573         dprint("OK.\n");
 574 
 575         if ((fds = malloc(sizeof (int)*file_opens)) == NULL) {
 576                 printf("\t Test UNRESOLVED: ");
 577                 eprint("malloc for RLIMIT_NOFILE fds failed\n");
 578                 Perror(":-(");
 579                 return (-1);
 580         }
 581 
 582         switch (stressTest) {
 583         case 1:
 584                 starttime(
 585                     "\n st_0003{a}: stress conflict lock until "
 586                     "child gets the lock\n\t ");
 587                 s1(fds, file_opens, nap_time, buffy);
 588                 printf("\t ==> Going to create and open %d files with "
 589                     "%d processes.\n", file_opens, file_opens);
 590                 endtime("         ");
 591                 break;
 592         case 2:
 593                 starttime(
 594                     "\n st_0003{b}: stress open/close files with "
 595                     "RDONLY and WRONLY\n\t ");
 596                 printf("\t ==> Going to create and open %d files.\n",
 597                     file_opens);
 598                 s2(fds, file_opens);
 599                 endtime("         ");
 600                 break;
 601         case 3:
 602                 starttime(
 603                     "\n st_0003{d}: stress read/write lock with "
 604                     "different boundary\n\t ");
 605                 printf("\t ==> Going to create and open %d files.\n",
 606                     file_opens);
 607                 s3(fds, file_opens);
 608                 endtime("         ");
 609                 break;
 610         case 4:
 611                 starttime(
 612                     "\n st_0003{c}: stress unlink WRLCK files "
 613                     "without a close\n\t ");
 614                 printf("\t ==> Going to create and open %d files.\n",
 615                     file_opens);
 616                 s4(fds, file_opens);
 617                 endtime("         ");
 618                 break;
 619         }
 620 
 621         return (0);
 622 }