root/user/usertests.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. copyin
  2. copyout
  3. copyinstr1
  4. copyinstr2
  5. copyinstr3
  6. rwsbrk
  7. truncate1
  8. truncate2
  9. truncate3
  10. iputtest
  11. exitiputtest
  12. openiputtest
  13. opentest
  14. writetest
  15. writebig
  16. createtest
  17. dirtest
  18. exectest
  19. pipe1
  20. killstatus
  21. killzero
  22. preempt
  23. exitwait
  24. reparent
  25. twochildren
  26. forkfork
  27. forkforkfork
  28. reparent2
  29. mem
  30. sharedfd
  31. fourfiles
  32. createdelete
  33. unlinkread
  34. linktest
  35. concreate
  36. linkunlink
  37. subdir
  38. bigwrite
  39. bigfile
  40. fourteen
  41. rmdot
  42. dirfile
  43. iref
  44. forktest
  45. sbrkbasic
  46. sbrkmuch
  47. kernmem
  48. MAXVAplus
  49. sbrkfail
  50. sbrkarg
  51. validatetest
  52. bsstest
  53. bigargtest
  54. fsfull
  55. argptest
  56. stacktest
  57. nowrite
  58. pgbug
  59. sbrkbugs
  60. sbrklast
  61. sbrk8000
  62. badarg
  63. lazy_alloc
  64. lazy_unmap
  65. lazy_copy
  66. lazy_copyinstr
  67. lazy_sbrk
  68. partial_write
  69. unlinkcwd
  70. bigdir
  71. manywrites
  72. badwrite
  73. execout
  74. diskfull
  75. outofinodes
  76. linkoverflow
  77. run
  78. runtests
  79. countfree
  80. drivetests
  81. main

   1 #include "kernel/param.h"
   2 #include "kernel/types.h"
   3 #include "kernel/stat.h"
   4 #include "user/user.h"
   5 #include "kernel/fs.h"
   6 #include "kernel/fcntl.h"
   7 #include "kernel/syscall.h"
   8 #include "kernel/memlayout.h"
   9 #include "kernel/riscv.h"
  10 
  11 //
  12 // Tests xv6 system calls.  usertests without arguments runs them all
  13 // and usertests <name> runs <name> test. The test runner creates for
  14 // each test a process and based on the exit status of the process,
  15 // the test runner reports "OK" or "FAILED".  Some tests result in
  16 // kernel printing usertrap messages, which can be ignored if test
  17 // prints "OK".
  18 //
  19 
  20 #define BUFSZ ((MAXOPBLOCKS + 2) * BSIZE)
  21 
  22 char buf[BUFSZ];
  23 
  24 //
  25 // Section with tests that run fairly quickly.  Use -q if you want to
  26 // run just those.  Without -q usertests also runs the ones that take a
  27 // fair amount of time.
  28 //
  29 
  30 // what if you pass ridiculous pointers to system calls
  31 // that read user memory with copyin?
  32 void
  33 copyin(char *s)
  34 {
  35   uint64 addrs[] = {0x80000000LL, 0x3fffffe000, 0x3ffffff000, 0x4000000000,
  36                     0xffffffffffffffff};
  37 
  38   for (int ai = 0; ai < sizeof(addrs) / sizeof(addrs[0]); ai++) {
  39     uint64 addr = addrs[ai];
  40 
  41     int fd = open("copyin1", O_CREATE | O_WRONLY);
  42     if (fd < 0) {
  43       printf("open(copyin1) failed\n");
  44       exit(1);
  45     }
  46     int n = write(fd, (void *)addr, 8192);
  47     if (n >= 0) {
  48       printf("write(fd, %p, 8192) returned %d, not -1\n", (void *)addr, n);
  49       exit(1);
  50     }
  51     close(fd);
  52     unlink("copyin1");
  53 
  54     n = write(1, (char *)addr, 8192);
  55     if (n > 0) {
  56       printf("write(1, %p, 8192) returned %d, not -1 or 0\n", (void *)addr, n);
  57       exit(1);
  58     }
  59 
  60     int fds[2];
  61     if (pipe(fds) < 0) {
  62       printf("pipe() failed\n");
  63       exit(1);
  64     }
  65     n = write(fds[1], (char *)addr, 8192);
  66     if (n > 0) {
  67       printf("write(pipe, %p, 8192) returned %d, not -1 or 0\n", (void *)addr,
  68              n);
  69       exit(1);
  70     }
  71     close(fds[0]);
  72     close(fds[1]);
  73   }
  74 }
  75 
  76 // what if you pass ridiculous pointers to system calls
  77 // that write user memory with copyout?
  78 void
  79 copyout(char *s)
  80 {
  81   uint64 addrs[] = {0LL,          0x80000000LL, 0x3fffffe000,
  82                     0x3ffffff000, 0x4000000000, 0xffffffffffffffff};
  83 
  84   for (int ai = 0; ai < sizeof(addrs) / sizeof(addrs[0]); ai++) {
  85     uint64 addr = addrs[ai];
  86 
  87     int fd = open("README", 0);
  88     if (fd < 0) {
  89       printf("open(README) failed\n");
  90       exit(1);
  91     }
  92     int n = read(fd, (void *)addr, 8192);
  93     if (n > 0) {
  94       printf("read(fd, %p, 8192) returned %d, not -1 or 0\n", (void *)addr, n);
  95       exit(1);
  96     }
  97     close(fd);
  98 
  99     int fds[2];
 100     if (pipe(fds) < 0) {
 101       printf("pipe() failed\n");
 102       exit(1);
 103     }
 104     n = write(fds[1], "x", 1);
 105     if (n != 1) {
 106       printf("pipe write failed\n");
 107       exit(1);
 108     }
 109     n = read(fds[0], (void *)addr, 8192);
 110     if (n > 0) {
 111       printf("read(pipe, %p, 8192) returned %d, not -1 or 0\n", (void *)addr,
 112              n);
 113       exit(1);
 114     }
 115     close(fds[0]);
 116     close(fds[1]);
 117   }
 118 }
 119 
 120 // what if you pass ridiculous string pointers to system calls?
 121 void
 122 copyinstr1(char *s)
 123 {
 124   uint64 addrs[] = {0x80000000LL, 0x3fffffe000, 0x3ffffff000, 0x4000000000,
 125                     0xffffffffffffffff};
 126 
 127   for (int ai = 0; ai < sizeof(addrs) / sizeof(addrs[0]); ai++) {
 128     uint64 addr = addrs[ai];
 129 
 130     int fd = open((char *)addr, O_CREATE | O_WRONLY);
 131     if (fd >= 0) {
 132       printf("open(%p) returned %d, not -1\n", (void *)addr, fd);
 133       exit(1);
 134     }
 135   }
 136 }
 137 
 138 // what if a string system call argument is exactly the size
 139 // of the kernel buffer it is copied into, so that the null
 140 // would fall just beyond the end of the kernel buffer?
 141 void
 142 copyinstr2(char *s)
 143 {
 144   char b[MAXPATH + 1];
 145 
 146   for (int i = 0; i < MAXPATH; i++)
 147     b[i] = 'x';
 148   b[MAXPATH] = '\0';
 149 
 150   int ret = unlink(b);
 151   if (ret != -1) {
 152     printf("unlink(%s) returned %d, not -1\n", b, ret);
 153     exit(1);
 154   }
 155 
 156   int fd = open(b, O_CREATE | O_WRONLY);
 157   if (fd != -1) {
 158     printf("open(%s) returned %d, not -1\n", b, fd);
 159     exit(1);
 160   }
 161 
 162   ret = link(b, b);
 163   if (ret != -1) {
 164     printf("link(%s, %s) returned %d, not -1\n", b, b, ret);
 165     exit(1);
 166   }
 167 
 168   char *args[] = {"xx", 0};
 169   ret = exec(b, args);
 170   if (ret != -1) {
 171     printf("exec(%s) returned %d, not -1\n", b, fd);
 172     exit(1);
 173   }
 174 
 175   int pid = fork();
 176   if (pid < 0) {
 177     printf("fork failed\n");
 178     exit(1);
 179   }
 180   if (pid == 0) {
 181     static char big[PGSIZE + 1];
 182     for (int i = 0; i < PGSIZE; i++)
 183       big[i] = 'x';
 184     big[PGSIZE] = '\0';
 185     char *args2[] = {big, big, big, 0};
 186     ret = exec("echo", args2);
 187     if (ret != -1) {
 188       printf("exec(echo, BIG) returned %d, not -1\n", fd);
 189       exit(1);
 190     }
 191     exit(747); // OK
 192   }
 193 
 194   int st = 0;
 195   wait(&st);
 196   if (st != 747) {
 197     printf("exec(echo, BIG) succeeded, should have failed\n");
 198     exit(1);
 199   }
 200 }
 201 
 202 // what if a string argument crosses over the end of last user page?
 203 void
 204 copyinstr3(char *s)
 205 {
 206   sbrk(8192);
 207   uint64 top = (uint64)sbrk(0);
 208   if ((top % PGSIZE) != 0) {
 209     sbrk(PGSIZE - (top % PGSIZE));
 210   }
 211   top = (uint64)sbrk(0);
 212   if (top % PGSIZE) {
 213     printf("oops\n");
 214     exit(1);
 215   }
 216 
 217   char *b = (char *)(top - 1);
 218   *b = 'x';
 219 
 220   int ret = unlink(b);
 221   if (ret != -1) {
 222     printf("unlink(%s) returned %d, not -1\n", b, ret);
 223     exit(1);
 224   }
 225 
 226   int fd = open(b, O_CREATE | O_WRONLY);
 227   if (fd != -1) {
 228     printf("open(%s) returned %d, not -1\n", b, fd);
 229     exit(1);
 230   }
 231 
 232   ret = link(b, b);
 233   if (ret != -1) {
 234     printf("link(%s, %s) returned %d, not -1\n", b, b, ret);
 235     exit(1);
 236   }
 237 
 238   char *args[] = {"xx", 0};
 239   ret = exec(b, args);
 240   if (ret != -1) {
 241     printf("exec(%s) returned %d, not -1\n", b, fd);
 242     exit(1);
 243   }
 244 }
 245 
 246 // See if the kernel refuses to read/write user memory that the
 247 // application doesn't have anymore, because it returned it.
 248 void
 249 rwsbrk(char *s)
 250 {
 251   int fd, n;
 252 
 253   uint64 a = (uint64)sbrk(8192);
 254 
 255   if (a == (uint64)SBRK_ERROR) {
 256     printf("sbrk(rwsbrk) failed\n");
 257     exit(1);
 258   }
 259 
 260   if (sbrk(-8192) == SBRK_ERROR) {
 261     printf("sbrk(rwsbrk) shrink failed\n");
 262     exit(1);
 263   }
 264 
 265   fd = open("rwsbrk", O_CREATE | O_WRONLY);
 266   if (fd < 0) {
 267     printf("open(rwsbrk) failed\n");
 268     exit(1);
 269   }
 270   n = write(fd, (void *)(a + PGSIZE), 1024);
 271   if (n >= 0) {
 272     printf("write(fd, %p, 1024) returned %d, not -1\n", (void *)a + PGSIZE, n);
 273     exit(1);
 274   }
 275   close(fd);
 276   unlink("rwsbrk");
 277 
 278   fd = open("README", O_RDONLY);
 279   if (fd < 0) {
 280     printf("open(README) failed\n");
 281     exit(1);
 282   }
 283   n = read(fd, (void *)(a + PGSIZE), 10);
 284   if (n >= 0) {
 285     printf("read(fd, %p, 10) returned %d, not -1\n", (void *)a + PGSIZE, n);
 286     exit(1);
 287   }
 288   close(fd);
 289 
 290   exit(0);
 291 }
 292 
 293 // test O_TRUNC.
 294 void
 295 truncate1(char *s)
 296 {
 297   char buf[32];
 298 
 299   unlink("truncfile");
 300   int fd1 = open("truncfile", O_CREATE | O_WRONLY | O_TRUNC);
 301   write(fd1, "abcd", 4);
 302   close(fd1);
 303 
 304   int fd2 = open("truncfile", O_RDONLY);
 305   int n = read(fd2, buf, sizeof(buf));
 306   if (n != 4) {
 307     printf("%s: read %d bytes, wanted 4\n", s, n);
 308     exit(1);
 309   }
 310 
 311   fd1 = open("truncfile", O_WRONLY | O_TRUNC);
 312 
 313   int fd3 = open("truncfile", O_RDONLY);
 314   n = read(fd3, buf, sizeof(buf));
 315   if (n != 0) {
 316     printf("aaa fd3=%d\n", fd3);
 317     printf("%s: read %d bytes, wanted 0\n", s, n);
 318     exit(1);
 319   }
 320 
 321   n = read(fd2, buf, sizeof(buf));
 322   if (n != 0) {
 323     printf("bbb fd2=%d\n", fd2);
 324     printf("%s: read %d bytes, wanted 0\n", s, n);
 325     exit(1);
 326   }
 327 
 328   write(fd1, "abcdef", 6);
 329 
 330   n = read(fd3, buf, sizeof(buf));
 331   if (n != 6) {
 332     printf("%s: read %d bytes, wanted 6\n", s, n);
 333     exit(1);
 334   }
 335 
 336   n = read(fd2, buf, sizeof(buf));
 337   if (n != 2) {
 338     printf("%s: read %d bytes, wanted 2\n", s, n);
 339     exit(1);
 340   }
 341 
 342   unlink("truncfile");
 343 
 344   close(fd1);
 345   close(fd2);
 346   close(fd3);
 347 }
 348 
 349 // write to an open FD whose file has just been truncated.
 350 // this causes a write at an offset beyond the end of the file.
 351 // such writes fail on xv6 (unlike POSIX) but at least
 352 // they don't crash.
 353 void
 354 truncate2(char *s)
 355 {
 356   unlink("truncfile");
 357 
 358   int fd1 = open("truncfile", O_CREATE | O_TRUNC | O_WRONLY);
 359   write(fd1, "abcd", 4);
 360 
 361   int fd2 = open("truncfile", O_TRUNC | O_WRONLY);
 362 
 363   int n = write(fd1, "x", 1);
 364   if (n != -1) {
 365     printf("%s: write returned %d, expected -1\n", s, n);
 366     exit(1);
 367   }
 368 
 369   unlink("truncfile");
 370   close(fd1);
 371   close(fd2);
 372 }
 373 
 374 void
 375 truncate3(char *s)
 376 {
 377   int pid, xstatus;
 378 
 379   close(open("truncfile", O_CREATE | O_TRUNC | O_WRONLY));
 380 
 381   pid = fork();
 382   if (pid < 0) {
 383     printf("%s: fork failed\n", s);
 384     exit(1);
 385   }
 386 
 387   if (pid == 0) {
 388     for (int i = 0; i < 100; i++) {
 389       char buf[32];
 390       int fd = open("truncfile", O_WRONLY);
 391       if (fd < 0) {
 392         printf("%s: open failed\n", s);
 393         exit(1);
 394       }
 395       int n = write(fd, "1234567890", 10);
 396       if (n != 10) {
 397         printf("%s: write got %d, expected 10\n", s, n);
 398         exit(1);
 399       }
 400       close(fd);
 401       fd = open("truncfile", O_RDONLY);
 402       read(fd, buf, sizeof(buf));
 403       close(fd);
 404     }
 405     exit(0);
 406   }
 407 
 408   for (int i = 0; i < 150; i++) {
 409     int fd = open("truncfile", O_CREATE | O_WRONLY | O_TRUNC);
 410     if (fd < 0) {
 411       printf("%s: open failed\n", s);
 412       exit(1);
 413     }
 414     int n = write(fd, "xxx", 3);
 415     if (n != 3) {
 416       printf("%s: write got %d, expected 3\n", s, n);
 417       exit(1);
 418     }
 419     close(fd);
 420   }
 421 
 422   wait(&xstatus);
 423   unlink("truncfile");
 424   exit(xstatus);
 425 }
 426 
 427 // does chdir() call iput(p->cwd) in a transaction?
 428 void
 429 iputtest(char *s)
 430 {
 431   if (mkdir("iputdir") < 0) {
 432     printf("%s: mkdir failed\n", s);
 433     exit(1);
 434   }
 435   if (chdir("iputdir") < 0) {
 436     printf("%s: chdir iputdir failed\n", s);
 437     exit(1);
 438   }
 439   if (unlink("../iputdir") < 0) {
 440     printf("%s: unlink ../iputdir failed\n", s);
 441     exit(1);
 442   }
 443   if (chdir("/") < 0) {
 444     printf("%s: chdir / failed\n", s);
 445     exit(1);
 446   }
 447 }
 448 
 449 // does exit() call iput(p->cwd) in a transaction?
 450 void
 451 exitiputtest(char *s)
 452 {
 453   int pid, xstatus;
 454 
 455   pid = fork();
 456   if (pid < 0) {
 457     printf("%s: fork failed\n", s);
 458     exit(1);
 459   }
 460   if (pid == 0) {
 461     if (mkdir("iputdir") < 0) {
 462       printf("%s: mkdir failed\n", s);
 463       exit(1);
 464     }
 465     if (chdir("iputdir") < 0) {
 466       printf("%s: child chdir failed\n", s);
 467       exit(1);
 468     }
 469     if (unlink("../iputdir") < 0) {
 470       printf("%s: unlink ../iputdir failed\n", s);
 471       exit(1);
 472     }
 473     exit(0);
 474   }
 475   wait(&xstatus);
 476   exit(xstatus);
 477 }
 478 
 479 // does the error path in open() for attempt to write a
 480 // directory call iput() in a transaction?
 481 // needs a hacked kernel that pauses just after the namei()
 482 // call in sys_open():
 483 //    if((ip = namei(path)) == 0)
 484 //      return -1;
 485 //    {
 486 //      int i;
 487 //      for(i = 0; i < 10000; i++)
 488 //        yield();
 489 //    }
 490 void
 491 openiputtest(char *s)
 492 {
 493   int pid, xstatus;
 494 
 495   if (mkdir("oidir") < 0) {
 496     printf("%s: mkdir oidir failed\n", s);
 497     exit(1);
 498   }
 499   pid = fork();
 500   if (pid < 0) {
 501     printf("%s: fork failed\n", s);
 502     exit(1);
 503   }
 504   if (pid == 0) {
 505     int fd = open("oidir", O_RDWR);
 506     if (fd >= 0) {
 507       printf("%s: open directory for write succeeded\n", s);
 508       exit(1);
 509     }
 510     exit(0);
 511   }
 512   pause(1);
 513   if (unlink("oidir") != 0) {
 514     printf("%s: unlink failed\n", s);
 515     exit(1);
 516   }
 517   wait(&xstatus);
 518   exit(xstatus);
 519 }
 520 
 521 // simple file system tests
 522 
 523 void
 524 opentest(char *s)
 525 {
 526   int fd;
 527 
 528   fd = open("echo", 0);
 529   if (fd < 0) {
 530     printf("%s: open echo failed!\n", s);
 531     exit(1);
 532   }
 533   close(fd);
 534   fd = open("doesnotexist", 0);
 535   if (fd >= 0) {
 536     printf("%s: open doesnotexist succeeded!\n", s);
 537     exit(1);
 538   }
 539 }
 540 
 541 void
 542 writetest(char *s)
 543 {
 544   int fd;
 545   int i;
 546   enum { N = 100, SZ = 10 };
 547 
 548   fd = open("small", O_CREATE | O_RDWR);
 549   if (fd < 0) {
 550     printf("%s: error: creat small failed!\n", s);
 551     exit(1);
 552   }
 553   for (i = 0; i < N; i++) {
 554     if (write(fd, "aaaaaaaaaa", SZ) != SZ) {
 555       printf("%s: error: write aa %d new file failed\n", s, i);
 556       exit(1);
 557     }
 558     if (write(fd, "bbbbbbbbbb", SZ) != SZ) {
 559       printf("%s: error: write bb %d new file failed\n", s, i);
 560       exit(1);
 561     }
 562   }
 563   close(fd);
 564   fd = open("small", O_RDONLY);
 565   if (fd < 0) {
 566     printf("%s: error: open small failed!\n", s);
 567     exit(1);
 568   }
 569   i = read(fd, buf, N * SZ * 2);
 570   if (i != N * SZ * 2) {
 571     printf("%s: read failed\n", s);
 572     exit(1);
 573   }
 574   close(fd);
 575 
 576   if (unlink("small") < 0) {
 577     printf("%s: unlink small failed\n", s);
 578     exit(1);
 579   }
 580 }
 581 
 582 void
 583 writebig(char *s)
 584 {
 585   int i, fd, n;
 586 
 587   fd = open("big", O_CREATE | O_RDWR);
 588   if (fd < 0) {
 589     printf("%s: error: creat big failed!\n", s);
 590     exit(1);
 591   }
 592 
 593   for (i = 0; i < MAXFILE; i++) {
 594     ((int *)buf)[0] = i;
 595     if (write(fd, buf, BSIZE) != BSIZE) {
 596       printf("%s: error: write big file failed i=%d\n", s, i);
 597       exit(1);
 598     }
 599   }
 600 
 601   close(fd);
 602 
 603   fd = open("big", O_RDONLY);
 604   if (fd < 0) {
 605     printf("%s: error: open big failed!\n", s);
 606     exit(1);
 607   }
 608 
 609   n = 0;
 610   for (;;) {
 611     i = read(fd, buf, BSIZE);
 612     if (i == 0) {
 613       if (n != MAXFILE) {
 614         printf("%s: read only %d blocks from big", s, n);
 615         exit(1);
 616       }
 617       break;
 618     } else if (i != BSIZE) {
 619       printf("%s: read failed %d\n", s, i);
 620       exit(1);
 621     }
 622     if (((int *)buf)[0] != n) {
 623       printf("%s: read content of block %d is %d\n", s, n, ((int *)buf)[0]);
 624       exit(1);
 625     }
 626     n++;
 627   }
 628   close(fd);
 629   if (unlink("big") < 0) {
 630     printf("%s: unlink big failed\n", s);
 631     exit(1);
 632   }
 633 }
 634 
 635 // many creates, followed by unlink test
 636 void
 637 createtest(char *s)
 638 {
 639   int i, fd;
 640   enum { N = 52 };
 641 
 642   char name[3];
 643   name[0] = 'a';
 644   name[2] = '\0';
 645   for (i = 0; i < N; i++) {
 646     name[1] = '0' + i;
 647     fd = open(name, O_CREATE | O_RDWR);
 648     close(fd);
 649   }
 650   name[0] = 'a';
 651   name[2] = '\0';
 652   for (i = 0; i < N; i++) {
 653     name[1] = '0' + i;
 654     unlink(name);
 655   }
 656 }
 657 
 658 void
 659 dirtest(char *s)
 660 {
 661   if (mkdir("dir0") < 0) {
 662     printf("%s: mkdir failed\n", s);
 663     exit(1);
 664   }
 665 
 666   if (chdir("dir0") < 0) {
 667     printf("%s: chdir dir0 failed\n", s);
 668     exit(1);
 669   }
 670 
 671   if (chdir("..") < 0) {
 672     printf("%s: chdir .. failed\n", s);
 673     exit(1);
 674   }
 675 
 676   if (unlink("dir0") < 0) {
 677     printf("%s: unlink dir0 failed\n", s);
 678     exit(1);
 679   }
 680 }
 681 
 682 void
 683 exectest(char *s)
 684 {
 685   int fd, xstatus, pid;
 686   char *echoargv[] = {"echo", "OK", 0};
 687   char buf[3];
 688 
 689   unlink("echo-ok");
 690   pid = fork();
 691   if (pid < 0) {
 692     printf("%s: fork failed\n", s);
 693     exit(1);
 694   }
 695   if (pid == 0) {
 696     int errfd = dup(1);
 697     if (errfd < 0) {
 698       printf("%s: dup failed\n", s);
 699       exit(1);
 700     }
 701     close(1);
 702     fd = open("echo-ok", O_CREATE | O_WRONLY);
 703     if (fd < 0) {
 704       fprintf(errfd, "%s: create failed\n", s);
 705       exit(1);
 706     }
 707     if (fd != 1) {
 708       fprintf(errfd, "%s: wrong fd\n", s);
 709       exit(1);
 710     }
 711     if (exec("echo", echoargv) < 0) {
 712       fprintf(errfd, "%s: exec echo failed\n", s);
 713       exit(1);
 714     }
 715     // won't get to here
 716   }
 717   if (wait(&xstatus) != pid) {
 718     printf("%s: wait failed!\n", s);
 719   }
 720   if (xstatus != 0) {
 721     printf("%s: nonzero wait status %d\n", s, xstatus);
 722     exit(1);
 723   }
 724 
 725   fd = open("echo-ok", O_RDONLY);
 726   if (fd < 0) {
 727     printf("%s: open failed\n", s);
 728     exit(1);
 729   }
 730   if (read(fd, buf, 2) != 2) {
 731     printf("%s: read failed\n", s);
 732     exit(1);
 733   }
 734   unlink("echo-ok");
 735   if (buf[0] == 'O' && buf[1] == 'K')
 736     exit(0);
 737   else {
 738     printf("%s: wrong output\n", s);
 739     exit(1);
 740   }
 741 }
 742 
 743 // simple fork and pipe read/write
 744 
 745 void
 746 pipe1(char *s)
 747 {
 748   int fds[2], pid, xstatus;
 749   int seq, i, n, cc, total;
 750   enum { N = 5, SZ = 1033 };
 751 
 752   if (pipe(fds) != 0) {
 753     printf("%s: pipe() failed\n", s);
 754     exit(1);
 755   }
 756   pid = fork();
 757   seq = 0;
 758   if (pid == 0) {
 759     close(fds[0]);
 760     for (n = 0; n < N; n++) {
 761       for (i = 0; i < SZ; i++)
 762         buf[i] = seq++;
 763       if (write(fds[1], buf, SZ) != SZ) {
 764         printf("%s: pipe1 oops 1\n", s);
 765         exit(1);
 766       }
 767     }
 768     exit(0);
 769   } else if (pid > 0) {
 770     close(fds[1]);
 771     total = 0;
 772     cc = 1;
 773     while ((n = read(fds[0], buf, cc)) > 0) {
 774       for (i = 0; i < n; i++) {
 775         if ((buf[i] & 0xff) != (seq++ & 0xff)) {
 776           printf("%s: pipe1 oops 2\n", s);
 777           return;
 778         }
 779       }
 780       total += n;
 781       cc = cc * 2;
 782       if (cc > sizeof(buf))
 783         cc = sizeof(buf);
 784     }
 785     if (total != N * SZ) {
 786       printf("%s: pipe1 oops 3 total %d\n", s, total);
 787       exit(1);
 788     }
 789     close(fds[0]);
 790     wait(&xstatus);
 791     exit(xstatus);
 792   } else {
 793     printf("%s: fork() failed\n", s);
 794     exit(1);
 795   }
 796 }
 797 
 798 // test if child is killed (status = -1)
 799 void
 800 killstatus(char *s)
 801 {
 802   int xst;
 803 
 804   for (int i = 0; i < 100; i++) {
 805     int pid1 = fork();
 806     if (pid1 < 0) {
 807       printf("%s: fork failed\n", s);
 808       exit(1);
 809     }
 810     if (pid1 == 0) {
 811       while (1) {
 812         getpid();
 813       }
 814       exit(0);
 815     }
 816     pause(1);
 817     kill(pid1);
 818     wait(&xst);
 819     if (xst != -1) {
 820       printf("%s: status should be -1\n", s);
 821       exit(1);
 822     }
 823   }
 824   exit(0);
 825 }
 826 
 827 // test that kill on unused process 0 doesn't set the killed flag
 828 void
 829 killzero(char *s)
 830 {
 831   int pid, xst;
 832 
 833   kill(0);
 834 
 835   pid = fork();
 836   if (pid < 0) {
 837     printf("%s: fork failed\n", s);
 838     exit(1);
 839   }
 840   if (pid == 0) {
 841     exit(7);
 842   }
 843   if (wait(&xst) != pid) {
 844     printf("%s: wait wrong pid\n", s);
 845     exit(1);
 846   }
 847   if (xst != 7) {
 848     printf("%s: child exited with status %d, expected 7\n", s, xst);
 849     exit(1);
 850   }
 851   exit(0);
 852 }
 853 
 854 // meant to be run w/ at most two CPUs
 855 void
 856 preempt(char *s)
 857 {
 858   int pid1, pid2, pid3;
 859   int pfds[2];
 860 
 861   pid1 = fork();
 862   if (pid1 < 0) {
 863     printf("%s: fork failed", s);
 864     exit(1);
 865   }
 866   if (pid1 == 0)
 867     for (;;)
 868       ;
 869 
 870   pid2 = fork();
 871   if (pid2 < 0) {
 872     printf("%s: fork failed\n", s);
 873     exit(1);
 874   }
 875   if (pid2 == 0)
 876     for (;;)
 877       ;
 878 
 879   pipe(pfds);
 880   pid3 = fork();
 881   if (pid3 < 0) {
 882     printf("%s: fork failed\n", s);
 883     exit(1);
 884   }
 885   if (pid3 == 0) {
 886     close(pfds[0]);
 887     if (write(pfds[1], "x", 1) != 1)
 888       printf("%s: preempt write error", s);
 889     close(pfds[1]);
 890     for (;;)
 891       ;
 892   }
 893 
 894   close(pfds[1]);
 895   if (read(pfds[0], buf, sizeof(buf)) != 1) {
 896     printf("%s: preempt read error", s);
 897     return;
 898   }
 899   close(pfds[0]);
 900   printf("kill... ");
 901   kill(pid1);
 902   kill(pid2);
 903   kill(pid3);
 904   printf("wait... ");
 905   wait(0);
 906   wait(0);
 907   wait(0);
 908 }
 909 
 910 // try to find any races between exit and wait
 911 void
 912 exitwait(char *s)
 913 {
 914   int i, pid;
 915 
 916   for (i = 0; i < 100; i++) {
 917     pid = fork();
 918     if (pid < 0) {
 919       printf("%s: fork failed\n", s);
 920       exit(1);
 921     }
 922     if (pid) {
 923       int xstate;
 924       if (wait(&xstate) != pid) {
 925         printf("%s: wait wrong pid\n", s);
 926         exit(1);
 927       }
 928       if (i != xstate) {
 929         printf("%s: wait wrong exit status\n", s);
 930         exit(1);
 931       }
 932     } else {
 933       exit(i);
 934     }
 935   }
 936 }
 937 
 938 // try to find races in the reparenting
 939 // code that handles a parent exiting
 940 // when it still has live children.
 941 void
 942 reparent(char *s)
 943 {
 944   int master_pid = getpid();
 945   for (int i = 0; i < 200; i++) {
 946     int pid = fork();
 947     if (pid < 0) {
 948       printf("%s: fork failed\n", s);
 949       exit(1);
 950     }
 951     if (pid) {
 952       if (wait(0) != pid) {
 953         printf("%s: wait wrong pid\n", s);
 954         exit(1);
 955       }
 956     } else {
 957       int pid2 = fork();
 958       if (pid2 < 0) {
 959         kill(master_pid);
 960         exit(1);
 961       }
 962       exit(0);
 963     }
 964   }
 965   exit(0);
 966 }
 967 
 968 // what if two children exit() at the same time?
 969 void
 970 twochildren(char *s)
 971 {
 972   for (int i = 0; i < 1000; i++) {
 973     int pid1 = fork();
 974     if (pid1 < 0) {
 975       printf("%s: fork failed\n", s);
 976       exit(1);
 977     }
 978     if (pid1 == 0) {
 979       exit(0);
 980     } else {
 981       int pid2 = fork();
 982       if (pid2 < 0) {
 983         printf("%s: fork failed\n", s);
 984         exit(1);
 985       }
 986       if (pid2 == 0) {
 987         exit(0);
 988       } else {
 989         wait(0);
 990         wait(0);
 991       }
 992     }
 993   }
 994 }
 995 
 996 // concurrent forks to try to expose locking bugs.
 997 void
 998 forkfork(char *s)
 999 {
1000   enum { N = 2 };
1001 
1002   for (int i = 0; i < N; i++) {
1003     int pid = fork();
1004     if (pid < 0) {
1005       printf("%s: fork failed", s);
1006       exit(1);
1007     }
1008     if (pid == 0) {
1009       for (int j = 0; j < 200; j++) {
1010         int pid1 = fork();
1011         if (pid1 < 0) {
1012           exit(1);
1013         }
1014         if (pid1 == 0) {
1015           exit(0);
1016         }
1017         wait(0);
1018       }
1019       exit(0);
1020     }
1021   }
1022 
1023   int xstatus;
1024   for (int i = 0; i < N; i++) {
1025     wait(&xstatus);
1026     if (xstatus != 0) {
1027       printf("%s: fork in child failed", s);
1028       exit(1);
1029     }
1030   }
1031 }
1032 
1033 void
1034 forkforkfork(char *s)
1035 {
1036   unlink("stopforking");
1037 
1038   int pid = fork();
1039   if (pid < 0) {
1040     printf("%s: fork failed", s);
1041     exit(1);
1042   }
1043   if (pid == 0) {
1044     while (1) {
1045       int fd = open("stopforking", 0);
1046       if (fd >= 0) {
1047         exit(0);
1048       }
1049       if (fork() < 0) {
1050         close(open("stopforking", O_CREATE | O_RDWR));
1051       }
1052     }
1053 
1054     exit(0);
1055   }
1056 
1057   pause(20); // two seconds
1058   close(open("stopforking", O_CREATE | O_RDWR));
1059   wait(0);
1060   pause(10); // one second
1061 }
1062 
1063 // regression test. does reparent() violate the parent-then-child
1064 // locking order when giving away a child to init, so that exit()
1065 // deadlocks against init's wait()? also used to trigger a "panic:
1066 // release" due to exit() releasing a different p->parent->lock than
1067 // it acquired.
1068 void
1069 reparent2(char *s)
1070 {
1071   for (int i = 0; i < 800; i++) {
1072     int pid1 = fork();
1073     if (pid1 < 0) {
1074       printf("fork failed\n");
1075       exit(1);
1076     }
1077     if (pid1 == 0) {
1078       fork();
1079       fork();
1080       exit(0);
1081     }
1082     wait(0);
1083   }
1084 
1085   exit(0);
1086 }
1087 
1088 // allocate all mem, free it, and allocate again
1089 void
1090 mem(char *s)
1091 {
1092   void *m1, *m2;
1093   int pid;
1094 
1095   if ((pid = fork()) == 0) {
1096     m1 = 0;
1097     while ((m2 = malloc(10001)) != 0) {
1098       *(char **)m2 = m1;
1099       m1 = m2;
1100     }
1101     while (m1) {
1102       m2 = *(char **)m1;
1103       free(m1);
1104       m1 = m2;
1105     }
1106     m1 = malloc(1024 * 20);
1107     if (m1 == 0) {
1108       printf("%s: couldn't allocate mem?!!\n", s);
1109       exit(1);
1110     }
1111     free(m1);
1112     exit(0);
1113   } else {
1114     int xstatus;
1115     wait(&xstatus);
1116     if (xstatus == -1) {
1117       // probably page fault, so might be lazy lab,
1118       // so OK.
1119       exit(0);
1120     }
1121     exit(xstatus);
1122   }
1123 }
1124 
1125 // More file system tests
1126 
1127 // two processes write to the same file descriptor
1128 // is the offset shared? does inode locking work?
1129 void
1130 sharedfd(char *s)
1131 {
1132   int fd, pid, i, n, nc, np;
1133   enum { N = 1000, SZ = 10 };
1134   char buf[SZ];
1135 
1136   unlink("sharedfd");
1137   fd = open("sharedfd", O_CREATE | O_RDWR);
1138   if (fd < 0) {
1139     printf("%s: cannot open sharedfd for writing", s);
1140     exit(1);
1141   }
1142   pid = fork();
1143   memset(buf, pid == 0 ? 'c' : 'p', sizeof(buf));
1144   for (i = 0; i < N; i++) {
1145     if (write(fd, buf, sizeof(buf)) != sizeof(buf)) {
1146       printf("%s: write sharedfd failed\n", s);
1147       exit(1);
1148     }
1149   }
1150   if (pid == 0) {
1151     exit(0);
1152   } else {
1153     int xstatus;
1154     wait(&xstatus);
1155     if (xstatus != 0)
1156       exit(xstatus);
1157   }
1158 
1159   close(fd);
1160   fd = open("sharedfd", 0);
1161   if (fd < 0) {
1162     printf("%s: cannot open sharedfd for reading\n", s);
1163     exit(1);
1164   }
1165   nc = np = 0;
1166   while ((n = read(fd, buf, sizeof(buf))) > 0) {
1167     for (i = 0; i < sizeof(buf); i++) {
1168       if (buf[i] == 'c')
1169         nc++;
1170       if (buf[i] == 'p')
1171         np++;
1172     }
1173   }
1174   close(fd);
1175   unlink("sharedfd");
1176   if (nc == N * SZ && np == N * SZ) {
1177     exit(0);
1178   } else {
1179     printf("%s: nc/np test fails\n", s);
1180     exit(1);
1181   }
1182 }
1183 
1184 // four processes write different files at the same
1185 // time, to test block allocation.
1186 void
1187 fourfiles(char *s)
1188 {
1189   int fd, pid, i, j, n, total, pi;
1190   char *names[] = {"f0", "f1", "f2", "f3"};
1191   char *fname;
1192   enum { N = 12, NCHILD = 4, SZ = 500 };
1193 
1194   for (pi = 0; pi < NCHILD; pi++) {
1195     fname = names[pi];
1196     unlink(fname);
1197 
1198     pid = fork();
1199     if (pid < 0) {
1200       printf("%s: fork failed\n", s);
1201       exit(1);
1202     }
1203 
1204     if (pid == 0) {
1205       fd = open(fname, O_CREATE | O_RDWR);
1206       if (fd < 0) {
1207         printf("%s: create failed\n", s);
1208         exit(1);
1209       }
1210 
1211       memset(buf, '0' + pi, SZ);
1212       for (i = 0; i < N; i++) {
1213         if ((n = write(fd, buf, SZ)) != SZ) {
1214           printf("write failed %d\n", n);
1215           exit(1);
1216         }
1217       }
1218       exit(0);
1219     }
1220   }
1221 
1222   int xstatus;
1223   for (pi = 0; pi < NCHILD; pi++) {
1224     wait(&xstatus);
1225     if (xstatus != 0)
1226       exit(xstatus);
1227   }
1228 
1229   for (i = 0; i < NCHILD; i++) {
1230     fname = names[i];
1231     fd = open(fname, 0);
1232     total = 0;
1233     while ((n = read(fd, buf, sizeof(buf))) > 0) {
1234       for (j = 0; j < n; j++) {
1235         if (buf[j] != '0' + i) {
1236           printf("%s: wrong char\n", s);
1237           exit(1);
1238         }
1239       }
1240       total += n;
1241     }
1242     close(fd);
1243     if (total != N * SZ) {
1244       printf("wrong length %d\n", total);
1245       exit(1);
1246     }
1247     unlink(fname);
1248   }
1249 }
1250 
1251 // four processes create and delete different files in same directory
1252 void
1253 createdelete(char *s)
1254 {
1255   enum { N = 20, NCHILD = 4 };
1256   int pid, i, fd, pi;
1257   char name[32];
1258 
1259   for (pi = 0; pi < NCHILD; pi++) {
1260     pid = fork();
1261     if (pid < 0) {
1262       printf("%s: fork failed\n", s);
1263       exit(1);
1264     }
1265 
1266     if (pid == 0) {
1267       name[0] = 'p' + pi;
1268       name[2] = '\0';
1269       for (i = 0; i < N; i++) {
1270         name[1] = '0' + i;
1271         fd = open(name, O_CREATE | O_RDWR);
1272         if (fd < 0) {
1273           printf("%s: create failed\n", s);
1274           exit(1);
1275         }
1276         close(fd);
1277         if (i > 0 && (i % 2) == 0) {
1278           name[1] = '0' + (i / 2);
1279           if (unlink(name) < 0) {
1280             printf("%s: unlink failed\n", s);
1281             exit(1);
1282           }
1283         }
1284       }
1285       exit(0);
1286     }
1287   }
1288 
1289   int xstatus;
1290   for (pi = 0; pi < NCHILD; pi++) {
1291     wait(&xstatus);
1292     if (xstatus != 0)
1293       exit(1);
1294   }
1295 
1296   name[0] = name[1] = name[2] = 0;
1297   for (i = 0; i < N; i++) {
1298     for (pi = 0; pi < NCHILD; pi++) {
1299       name[0] = 'p' + pi;
1300       name[1] = '0' + i;
1301       fd = open(name, 0);
1302       if ((i == 0 || i >= N / 2) && fd < 0) {
1303         printf("%s: oops createdelete %s didn't exist\n", s, name);
1304         exit(1);
1305       } else if ((i >= 1 && i < N / 2) && fd >= 0) {
1306         printf("%s: oops createdelete %s did exist\n", s, name);
1307         exit(1);
1308       }
1309       if (fd >= 0)
1310         close(fd);
1311     }
1312   }
1313 
1314   for (i = 0; i < N; i++) {
1315     for (pi = 0; pi < NCHILD; pi++) {
1316       name[0] = 'p' + pi;
1317       name[1] = '0' + i;
1318       unlink(name);
1319     }
1320   }
1321 }
1322 
1323 // can I unlink a file and still read it?
1324 void
1325 unlinkread(char *s)
1326 {
1327   enum { SZ = 5 };
1328   int fd, fd1;
1329 
1330   fd = open("unlinkread", O_CREATE | O_RDWR);
1331   if (fd < 0) {
1332     printf("%s: create unlinkread failed\n", s);
1333     exit(1);
1334   }
1335   write(fd, "hello", SZ);
1336   close(fd);
1337 
1338   fd = open("unlinkread", O_RDWR);
1339   if (fd < 0) {
1340     printf("%s: open unlinkread failed\n", s);
1341     exit(1);
1342   }
1343   if (unlink("unlinkread") != 0) {
1344     printf("%s: unlink unlinkread failed\n", s);
1345     exit(1);
1346   }
1347 
1348   fd1 = open("unlinkread", O_CREATE | O_RDWR);
1349   write(fd1, "yyy", 3);
1350   close(fd1);
1351 
1352   if (read(fd, buf, sizeof(buf)) != SZ) {
1353     printf("%s: unlinkread read failed", s);
1354     exit(1);
1355   }
1356   if (buf[0] != 'h') {
1357     printf("%s: unlinkread wrong data\n", s);
1358     exit(1);
1359   }
1360   if (write(fd, buf, 10) != 10) {
1361     printf("%s: unlinkread write failed\n", s);
1362     exit(1);
1363   }
1364   close(fd);
1365   unlink("unlinkread");
1366 }
1367 
1368 void
1369 linktest(char *s)
1370 {
1371   enum { SZ = 5 };
1372   int fd;
1373 
1374   unlink("lf1");
1375   unlink("lf2");
1376 
1377   fd = open("lf1", O_CREATE | O_RDWR);
1378   if (fd < 0) {
1379     printf("%s: create lf1 failed\n", s);
1380     exit(1);
1381   }
1382   if (write(fd, "hello", SZ) != SZ) {
1383     printf("%s: write lf1 failed\n", s);
1384     exit(1);
1385   }
1386   close(fd);
1387 
1388   if (link("lf1", "lf2") < 0) {
1389     printf("%s: link lf1 lf2 failed\n", s);
1390     exit(1);
1391   }
1392   unlink("lf1");
1393 
1394   if (open("lf1", 0) >= 0) {
1395     printf("%s: unlinked lf1 but it is still there!\n", s);
1396     exit(1);
1397   }
1398 
1399   fd = open("lf2", 0);
1400   if (fd < 0) {
1401     printf("%s: open lf2 failed\n", s);
1402     exit(1);
1403   }
1404   if (read(fd, buf, sizeof(buf)) != SZ) {
1405     printf("%s: read lf2 failed\n", s);
1406     exit(1);
1407   }
1408   close(fd);
1409 
1410   if (link("lf2", "lf2") >= 0) {
1411     printf("%s: link lf2 lf2 succeeded! oops\n", s);
1412     exit(1);
1413   }
1414 
1415   unlink("lf2");
1416   if (link("lf2", "lf1") >= 0) {
1417     printf("%s: link non-existent succeeded! oops\n", s);
1418     exit(1);
1419   }
1420 
1421   if (link(".", "lf1") >= 0) {
1422     printf("%s: link . lf1 succeeded! oops\n", s);
1423     exit(1);
1424   }
1425 }
1426 
1427 // test concurrent create/link/unlink of the same file
1428 void
1429 concreate(char *s)
1430 {
1431   enum { N = 40 };
1432   char file[3];
1433   int i, pid, n, fd;
1434   char fa[N];
1435   struct {
1436     ushort inum;
1437     char name[DIRSIZ];
1438   } de;
1439 
1440   file[0] = 'C';
1441   file[2] = '\0';
1442   for (i = 0; i < N; i++) {
1443     file[1] = '0' + i;
1444     unlink(file);
1445     pid = fork();
1446     if (pid && (i % 3) == 1) {
1447       link("C0", file);
1448     } else if (pid == 0 && (i % 5) == 1) {
1449       link("C0", file);
1450     } else {
1451       fd = open(file, O_CREATE | O_RDWR);
1452       if (fd < 0) {
1453         printf("concreate create %s failed\n", file);
1454         exit(1);
1455       }
1456       close(fd);
1457     }
1458     if (pid == 0) {
1459       exit(0);
1460     } else {
1461       int xstatus;
1462       wait(&xstatus);
1463       if (xstatus != 0)
1464         exit(1);
1465     }
1466   }
1467 
1468   memset(fa, 0, sizeof(fa));
1469   fd = open(".", 0);
1470   n = 0;
1471   while (read(fd, &de, sizeof(de)) > 0) {
1472     if (de.inum == 0)
1473       continue;
1474     if (de.name[0] == 'C' && de.name[2] == '\0') {
1475       i = de.name[1] - '0';
1476       if (i < 0 || i >= sizeof(fa)) {
1477         printf("%s: concreate weird file %s\n", s, de.name);
1478         exit(1);
1479       }
1480       if (fa[i]) {
1481         printf("%s: concreate duplicate file %s\n", s, de.name);
1482         exit(1);
1483       }
1484       fa[i] = 1;
1485       n++;
1486     }
1487   }
1488   close(fd);
1489 
1490   if (n != N) {
1491     printf("%s: concreate not enough files in directory listing\n", s);
1492     exit(1);
1493   }
1494 
1495   for (i = 0; i < N; i++) {
1496     file[1] = '0' + i;
1497     pid = fork();
1498     if (pid < 0) {
1499       printf("%s: fork failed\n", s);
1500       exit(1);
1501     }
1502     if (((i % 3) == 0 && pid == 0) || ((i % 3) == 1 && pid != 0)) {
1503       close(open(file, 0));
1504       close(open(file, 0));
1505       close(open(file, 0));
1506       close(open(file, 0));
1507       close(open(file, 0));
1508       close(open(file, 0));
1509     } else {
1510       unlink(file);
1511       unlink(file);
1512       unlink(file);
1513       unlink(file);
1514       unlink(file);
1515       unlink(file);
1516     }
1517     if (pid == 0)
1518       exit(0);
1519     else
1520       wait(0);
1521   }
1522 }
1523 
1524 // another concurrent link/unlink/create test,
1525 // to look for deadlocks.
1526 void
1527 linkunlink(char *s)
1528 {
1529   int pid, i;
1530 
1531   unlink("x");
1532   pid = fork();
1533   if (pid < 0) {
1534     printf("%s: fork failed\n", s);
1535     exit(1);
1536   }
1537 
1538   unsigned int x = (pid ? 1 : 97);
1539   for (i = 0; i < 100; i++) {
1540     x = x * 1103515245 + 12345;
1541     if ((x % 3) == 0) {
1542       close(open("x", O_RDWR | O_CREATE));
1543     } else if ((x % 3) == 1) {
1544       link("cat", "x");
1545     } else {
1546       unlink("x");
1547     }
1548   }
1549 
1550   if (pid)
1551     wait(0);
1552   else
1553     exit(0);
1554 }
1555 
1556 void
1557 subdir(char *s)
1558 {
1559   int fd, cc;
1560 
1561   unlink("ff");
1562   if (mkdir("dd") != 0) {
1563     printf("%s: mkdir dd failed\n", s);
1564     exit(1);
1565   }
1566 
1567   fd = open("dd/ff", O_CREATE | O_RDWR);
1568   if (fd < 0) {
1569     printf("%s: create dd/ff failed\n", s);
1570     exit(1);
1571   }
1572   write(fd, "ff", 2);
1573   close(fd);
1574 
1575   if (unlink("dd") >= 0) {
1576     printf("%s: unlink dd (non-empty dir) succeeded!\n", s);
1577     exit(1);
1578   }
1579 
1580   if (mkdir("/dd/dd") != 0) {
1581     printf("%s: subdir mkdir dd/dd failed\n", s);
1582     exit(1);
1583   }
1584 
1585   fd = open("dd/dd/ff", O_CREATE | O_RDWR);
1586   if (fd < 0) {
1587     printf("%s: create dd/dd/ff failed\n", s);
1588     exit(1);
1589   }
1590   write(fd, "FF", 2);
1591   close(fd);
1592 
1593   fd = open("dd/dd/../ff", 0);
1594   if (fd < 0) {
1595     printf("%s: open dd/dd/../ff failed\n", s);
1596     exit(1);
1597   }
1598   cc = read(fd, buf, sizeof(buf));
1599   if (cc != 2 || buf[0] != 'f') {
1600     printf("%s: dd/dd/../ff wrong content\n", s);
1601     exit(1);
1602   }
1603   close(fd);
1604 
1605   if (link("dd/dd/ff", "dd/dd/ffff") != 0) {
1606     printf("%s: link dd/dd/ff dd/dd/ffff failed\n", s);
1607     exit(1);
1608   }
1609 
1610   if (unlink("dd/dd/ff") != 0) {
1611     printf("%s: unlink dd/dd/ff failed\n", s);
1612     exit(1);
1613   }
1614   if (open("dd/dd/ff", O_RDONLY) >= 0) {
1615     printf("%s: open (unlinked) dd/dd/ff succeeded\n", s);
1616     exit(1);
1617   }
1618 
1619   if (chdir("dd") != 0) {
1620     printf("%s: chdir dd failed\n", s);
1621     exit(1);
1622   }
1623   if (chdir("dd/../../dd") != 0) {
1624     printf("%s: chdir dd/../../dd failed\n", s);
1625     exit(1);
1626   }
1627   if (chdir("dd/../../../dd") != 0) {
1628     printf("%s: chdir dd/../../../dd failed\n", s);
1629     exit(1);
1630   }
1631   if (chdir("./..") != 0) {
1632     printf("%s: chdir ./.. failed\n", s);
1633     exit(1);
1634   }
1635 
1636   fd = open("dd/dd/ffff", 0);
1637   if (fd < 0) {
1638     printf("%s: open dd/dd/ffff failed\n", s);
1639     exit(1);
1640   }
1641   if (read(fd, buf, sizeof(buf)) != 2) {
1642     printf("%s: read dd/dd/ffff wrong len\n", s);
1643     exit(1);
1644   }
1645   close(fd);
1646 
1647   if (open("dd/dd/ff", O_RDONLY) >= 0) {
1648     printf("%s: open (unlinked) dd/dd/ff succeeded!\n", s);
1649     exit(1);
1650   }
1651 
1652   if (open("dd/ff/ff", O_CREATE | O_RDWR) >= 0) {
1653     printf("%s: create dd/ff/ff succeeded!\n", s);
1654     exit(1);
1655   }
1656   if (open("dd/xx/ff", O_CREATE | O_RDWR) >= 0) {
1657     printf("%s: create dd/xx/ff succeeded!\n", s);
1658     exit(1);
1659   }
1660   if (open("dd", O_CREATE) >= 0) {
1661     printf("%s: create dd succeeded!\n", s);
1662     exit(1);
1663   }
1664   if (open("dd", O_RDWR) >= 0) {
1665     printf("%s: open dd rdwr succeeded!\n", s);
1666     exit(1);
1667   }
1668   if (open("dd", O_WRONLY) >= 0) {
1669     printf("%s: open dd wronly succeeded!\n", s);
1670     exit(1);
1671   }
1672   if (link("dd/ff/ff", "dd/dd/xx") == 0) {
1673     printf("%s: link dd/ff/ff dd/dd/xx succeeded!\n", s);
1674     exit(1);
1675   }
1676   if (link("dd/xx/ff", "dd/dd/xx") == 0) {
1677     printf("%s: link dd/xx/ff dd/dd/xx succeeded!\n", s);
1678     exit(1);
1679   }
1680   if (link("dd/ff", "dd/dd/ffff") == 0) {
1681     printf("%s: link dd/ff dd/dd/ffff succeeded!\n", s);
1682     exit(1);
1683   }
1684   if (mkdir("dd/ff/ff") == 0) {
1685     printf("%s: mkdir dd/ff/ff succeeded!\n", s);
1686     exit(1);
1687   }
1688   if (mkdir("dd/xx/ff") == 0) {
1689     printf("%s: mkdir dd/xx/ff succeeded!\n", s);
1690     exit(1);
1691   }
1692   if (mkdir("dd/dd/ffff") == 0) {
1693     printf("%s: mkdir dd/dd/ffff succeeded!\n", s);
1694     exit(1);
1695   }
1696   if (unlink("dd/xx/ff") == 0) {
1697     printf("%s: unlink dd/xx/ff succeeded!\n", s);
1698     exit(1);
1699   }
1700   if (unlink("dd/ff/ff") == 0) {
1701     printf("%s: unlink dd/ff/ff succeeded!\n", s);
1702     exit(1);
1703   }
1704   if (chdir("dd/ff") == 0) {
1705     printf("%s: chdir dd/ff succeeded!\n", s);
1706     exit(1);
1707   }
1708   if (chdir("dd/xx") == 0) {
1709     printf("%s: chdir dd/xx succeeded!\n", s);
1710     exit(1);
1711   }
1712 
1713   if (unlink("dd/dd/ffff") != 0) {
1714     printf("%s: unlink dd/dd/ff failed\n", s);
1715     exit(1);
1716   }
1717   if (unlink("dd/ff") != 0) {
1718     printf("%s: unlink dd/ff failed\n", s);
1719     exit(1);
1720   }
1721   if (unlink("dd") == 0) {
1722     printf("%s: unlink non-empty dd succeeded!\n", s);
1723     exit(1);
1724   }
1725   if (unlink("dd/dd") < 0) {
1726     printf("%s: unlink dd/dd failed\n", s);
1727     exit(1);
1728   }
1729   if (unlink("dd") < 0) {
1730     printf("%s: unlink dd failed\n", s);
1731     exit(1);
1732   }
1733 }
1734 
1735 // test writes that are larger than the log.
1736 void
1737 bigwrite(char *s)
1738 {
1739   int fd, sz;
1740 
1741   unlink("bigwrite");
1742   for (sz = 499; sz < (MAXOPBLOCKS + 2) * BSIZE; sz += 471) {
1743     fd = open("bigwrite", O_CREATE | O_RDWR);
1744     if (fd < 0) {
1745       printf("%s: cannot create bigwrite\n", s);
1746       exit(1);
1747     }
1748     int i;
1749     for (i = 0; i < 2; i++) {
1750       int cc = write(fd, buf, sz);
1751       if (cc != sz) {
1752         printf("%s: write(%d) ret %d\n", s, sz, cc);
1753         exit(1);
1754       }
1755     }
1756     close(fd);
1757     unlink("bigwrite");
1758   }
1759 }
1760 
1761 void
1762 bigfile(char *s)
1763 {
1764   enum { N = 20, SZ = 600 };
1765   int fd, i, total, cc;
1766 
1767   unlink("bigfile.dat");
1768   fd = open("bigfile.dat", O_CREATE | O_RDWR);
1769   if (fd < 0) {
1770     printf("%s: cannot create bigfile", s);
1771     exit(1);
1772   }
1773   for (i = 0; i < N; i++) {
1774     memset(buf, i, SZ);
1775     if (write(fd, buf, SZ) != SZ) {
1776       printf("%s: write bigfile failed\n", s);
1777       exit(1);
1778     }
1779   }
1780   close(fd);
1781 
1782   fd = open("bigfile.dat", 0);
1783   if (fd < 0) {
1784     printf("%s: cannot open bigfile\n", s);
1785     exit(1);
1786   }
1787   total = 0;
1788   for (i = 0;; i++) {
1789     cc = read(fd, buf, SZ / 2);
1790     if (cc < 0) {
1791       printf("%s: read bigfile failed\n", s);
1792       exit(1);
1793     }
1794     if (cc == 0)
1795       break;
1796     if (cc != SZ / 2) {
1797       printf("%s: short read bigfile\n", s);
1798       exit(1);
1799     }
1800     if (buf[0] != i / 2 || buf[SZ / 2 - 1] != i / 2) {
1801       printf("%s: read bigfile wrong data\n", s);
1802       exit(1);
1803     }
1804     total += cc;
1805   }
1806   close(fd);
1807   if (total != N * SZ) {
1808     printf("%s: read bigfile wrong total\n", s);
1809     exit(1);
1810   }
1811   unlink("bigfile.dat");
1812 }
1813 
1814 void
1815 fourteen(char *s)
1816 {
1817   int fd;
1818 
1819   // DIRSIZ is 14.
1820 
1821   if (mkdir("12345678901234") != 0) {
1822     printf("%s: mkdir 12345678901234 failed\n", s);
1823     exit(1);
1824   }
1825   if (mkdir("12345678901234/123456789012345") != 0) {
1826     printf("%s: mkdir 12345678901234/123456789012345 failed\n", s);
1827     exit(1);
1828   }
1829   fd = open("123456789012345/123456789012345/123456789012345", O_CREATE);
1830   if (fd < 0) {
1831     printf(
1832       "%s: create 123456789012345/123456789012345/123456789012345 failed\n", s);
1833     exit(1);
1834   }
1835   close(fd);
1836   fd = open("12345678901234/12345678901234/12345678901234", 0);
1837   if (fd < 0) {
1838     printf("%s: open 12345678901234/12345678901234/12345678901234 failed\n", s);
1839     exit(1);
1840   }
1841   close(fd);
1842 
1843   if (mkdir("12345678901234/12345678901234") == 0) {
1844     printf("%s: mkdir 12345678901234/12345678901234 succeeded!\n", s);
1845     exit(1);
1846   }
1847   if (mkdir("123456789012345/12345678901234") == 0) {
1848     printf("%s: mkdir 12345678901234/123456789012345 succeeded!\n", s);
1849     exit(1);
1850   }
1851 
1852   // clean up
1853   unlink("123456789012345/12345678901234");
1854   unlink("12345678901234/12345678901234");
1855   unlink("12345678901234/12345678901234/12345678901234");
1856   unlink("123456789012345/123456789012345/123456789012345");
1857   unlink("12345678901234/123456789012345");
1858   unlink("12345678901234");
1859 }
1860 
1861 void
1862 rmdot(char *s)
1863 {
1864   if (mkdir("dots") != 0) {
1865     printf("%s: mkdir dots failed\n", s);
1866     exit(1);
1867   }
1868   if (chdir("dots") != 0) {
1869     printf("%s: chdir dots failed\n", s);
1870     exit(1);
1871   }
1872   if (unlink(".") == 0) {
1873     printf("%s: rm . worked!\n", s);
1874     exit(1);
1875   }
1876   if (unlink("..") == 0) {
1877     printf("%s: rm .. worked!\n", s);
1878     exit(1);
1879   }
1880   if (chdir("/") != 0) {
1881     printf("%s: chdir / failed\n", s);
1882     exit(1);
1883   }
1884   if (unlink("dots/.") == 0) {
1885     printf("%s: unlink dots/. worked!\n", s);
1886     exit(1);
1887   }
1888   if (unlink("dots/..") == 0) {
1889     printf("%s: unlink dots/.. worked!\n", s);
1890     exit(1);
1891   }
1892   if (unlink("dots") != 0) {
1893     printf("%s: unlink dots failed!\n", s);
1894     exit(1);
1895   }
1896 }
1897 
1898 void
1899 dirfile(char *s)
1900 {
1901   int fd;
1902 
1903   fd = open("dirfile", O_CREATE);
1904   if (fd < 0) {
1905     printf("%s: create dirfile failed\n", s);
1906     exit(1);
1907   }
1908   close(fd);
1909   if (chdir("dirfile") == 0) {
1910     printf("%s: chdir dirfile succeeded!\n", s);
1911     exit(1);
1912   }
1913   fd = open("dirfile/xx", 0);
1914   if (fd >= 0) {
1915     printf("%s: create dirfile/xx succeeded!\n", s);
1916     exit(1);
1917   }
1918   fd = open("dirfile/xx", O_CREATE);
1919   if (fd >= 0) {
1920     printf("%s: create dirfile/xx succeeded!\n", s);
1921     exit(1);
1922   }
1923   if (mkdir("dirfile/xx") == 0) {
1924     printf("%s: mkdir dirfile/xx succeeded!\n", s);
1925     exit(1);
1926   }
1927   if (unlink("dirfile/xx") == 0) {
1928     printf("%s: unlink dirfile/xx succeeded!\n", s);
1929     exit(1);
1930   }
1931   if (link("README", "dirfile/xx") == 0) {
1932     printf("%s: link to dirfile/xx succeeded!\n", s);
1933     exit(1);
1934   }
1935   if (unlink("dirfile") != 0) {
1936     printf("%s: unlink dirfile failed!\n", s);
1937     exit(1);
1938   }
1939 
1940   fd = open(".", O_RDWR);
1941   if (fd >= 0) {
1942     printf("%s: open . for writing succeeded!\n", s);
1943     exit(1);
1944   }
1945   fd = open(".", 0);
1946   if (write(fd, "x", 1) > 0) {
1947     printf("%s: write . succeeded!\n", s);
1948     exit(1);
1949   }
1950   close(fd);
1951 }
1952 
1953 // test that iput() is called at the end of _namei().
1954 // also tests empty file names.
1955 void
1956 iref(char *s)
1957 {
1958   int i, fd;
1959 
1960   for (i = 0; i < NINODE + 1; i++) {
1961     if (mkdir("irefd") != 0) {
1962       printf("%s: mkdir irefd failed\n", s);
1963       exit(1);
1964     }
1965     if (chdir("irefd") != 0) {
1966       printf("%s: chdir irefd failed\n", s);
1967       exit(1);
1968     }
1969 
1970     mkdir("");
1971     link("README", "");
1972     fd = open("", O_CREATE);
1973     if (fd >= 0)
1974       close(fd);
1975     fd = open("xx", O_CREATE);
1976     if (fd >= 0)
1977       close(fd);
1978     unlink("xx");
1979   }
1980 
1981   // clean up
1982   for (i = 0; i < NINODE + 1; i++) {
1983     chdir("..");
1984     unlink("irefd");
1985   }
1986 
1987   chdir("/");
1988 }
1989 
1990 // test that fork fails gracefully
1991 // the forktest binary also does this, but it runs out of proc entries first.
1992 // inside the bigger usertests binary, we run out of memory first.
1993 void
1994 forktest(char *s)
1995 {
1996   enum { N = 1000 };
1997   int n, pid;
1998 
1999   for (n = 0; n < N; n++) {
2000     pid = fork();
2001     if (pid < 0)
2002       break;
2003     if (pid == 0)
2004       exit(0);
2005   }
2006 
2007   if (n == 0) {
2008     printf("%s: no fork at all!\n", s);
2009     exit(1);
2010   }
2011 
2012   if (n == N) {
2013     printf("%s: fork claimed to work 1000 times!\n", s);
2014     exit(1);
2015   }
2016 
2017   for (; n > 0; n--) {
2018     if (wait(0) < 0) {
2019       printf("%s: wait stopped early\n", s);
2020       exit(1);
2021     }
2022   }
2023 
2024   if (wait(0) != -1) {
2025     printf("%s: wait got too many\n", s);
2026     exit(1);
2027   }
2028 }
2029 
2030 void
2031 sbrkbasic(char *s)
2032 {
2033   enum { TOOMUCH = 1024 * 1024 * 1024 };
2034   int i, pid, xstatus;
2035   char *c, *a, *b;
2036 
2037   // does sbrk() return the expected failure value?
2038   pid = fork();
2039   if (pid < 0) {
2040     printf("fork failed in sbrkbasic\n");
2041     exit(1);
2042   }
2043   if (pid == 0) {
2044     a = sbrk(TOOMUCH);
2045     if (a == (char *)SBRK_ERROR) {
2046       // it's OK if this fails.
2047       exit(0);
2048     }
2049 
2050     for (b = a; b < a + TOOMUCH; b += PGSIZE) {
2051       *b = 99;
2052     }
2053 
2054     // we should not get here! either sbrk(TOOMUCH)
2055     // should have failed, or (with lazy allocation)
2056     // a pagefault should have killed this process.
2057     exit(1);
2058   }
2059 
2060   wait(&xstatus);
2061   if (xstatus == 1) {
2062     printf("%s: too much memory allocated!\n", s);
2063     exit(1);
2064   }
2065 
2066   // can one sbrk() less than a page?
2067   a = sbrk(0);
2068   for (i = 0; i < 5000; i++) {
2069     b = sbrk(1);
2070     if (b != a) {
2071       printf("%s: sbrk test failed %d %p %p\n", s, i, a, b);
2072       exit(1);
2073     }
2074     *b = 1;
2075     a = b + 1;
2076   }
2077   pid = fork();
2078   if (pid < 0) {
2079     printf("%s: sbrk test fork failed\n", s);
2080     exit(1);
2081   }
2082   c = sbrk(1);
2083   c = sbrk(1);
2084   if (c != a + 1) {
2085     printf("%s: sbrk test failed post-fork\n", s);
2086     exit(1);
2087   }
2088   if (pid == 0)
2089     exit(0);
2090   wait(&xstatus);
2091   exit(xstatus);
2092 }
2093 
2094 void
2095 sbrkmuch(char *s)
2096 {
2097   enum { BIG = 100 * 1024 * 1024 };
2098   char *c, *oldbrk, *a, *lastaddr, *p;
2099   uint64 amt;
2100 
2101   oldbrk = sbrk(0);
2102 
2103   // can one grow address space to something big?
2104   a = sbrk(0);
2105   amt = BIG - (uint64)a;
2106   p = sbrk(amt);
2107   if (p != a) {
2108     printf("%s: sbrk test failed to grow big address space; enough phys mem?\n",
2109            s);
2110     exit(1);
2111   }
2112 
2113   lastaddr = (char *)(BIG - 1);
2114   *lastaddr = 99;
2115 
2116   // can one de-allocate?
2117   a = sbrk(0);
2118   c = sbrk(-PGSIZE);
2119   if (c == (char *)SBRK_ERROR) {
2120     printf("%s: sbrk could not deallocate\n", s);
2121     exit(1);
2122   }
2123   c = sbrk(0);
2124   if (c != a - PGSIZE) {
2125     printf("%s: sbrk deallocation produced wrong address, a %p c %p\n", s, a,
2126            c);
2127     exit(1);
2128   }
2129 
2130   // can one re-allocate that page?
2131   a = sbrk(0);
2132   c = sbrk(PGSIZE);
2133   if (c != a || sbrk(0) != a + PGSIZE) {
2134     printf("%s: sbrk re-allocation failed, a %p c %p\n", s, a, c);
2135     exit(1);
2136   }
2137   if (*lastaddr == 99) {
2138     // should be zero
2139     printf("%s: sbrk de-allocation didn't really deallocate\n", s);
2140     exit(1);
2141   }
2142 
2143   a = sbrk(0);
2144   c = sbrk(-(sbrk(0) - oldbrk));
2145   if (c != a) {
2146     printf("%s: sbrk downsize failed, a %p c %p\n", s, a, c);
2147     exit(1);
2148   }
2149 }
2150 
2151 // can we read the kernel's memory?
2152 void
2153 kernmem(char *s)
2154 {
2155   char *a;
2156   int pid;
2157 
2158   for (a = (char *)(KERNBASE); a < (char *)(KERNBASE + 2000000); a += 50000) {
2159     pid = fork();
2160     if (pid < 0) {
2161       printf("%s: fork failed\n", s);
2162       exit(1);
2163     }
2164     if (pid == 0) {
2165       printf("%s: oops could read %p = %x\n", s, a, *a);
2166       exit(1);
2167     }
2168     int xstatus;
2169     wait(&xstatus);
2170     if (xstatus != -1) // did kernel kill child?
2171       exit(1);
2172   }
2173 }
2174 
2175 // user code should not be able to write to addresses above MAXVA.
2176 void
2177 MAXVAplus(char *s)
2178 {
2179   volatile uint64 a = MAXVA;
2180   for (; a != 0; a <<= 1) {
2181     int pid;
2182     pid = fork();
2183     if (pid < 0) {
2184       printf("%s: fork failed\n", s);
2185       exit(1);
2186     }
2187     if (pid == 0) {
2188       *(char *)a = 99;
2189       printf("%s: oops wrote %p\n", s, (void *)a);
2190       exit(1);
2191     }
2192     int xstatus;
2193     wait(&xstatus);
2194     if (xstatus != -1) // did kernel kill child?
2195       exit(1);
2196   }
2197 }
2198 
2199 // if we run the system out of memory, does it clean up the last
2200 // failed allocation?
2201 void
2202 sbrkfail(char *s)
2203 {
2204   enum { BIG = 100 * 1024 * 1024 };
2205   int i, xstatus;
2206   int fds[2];
2207   char scratch;
2208   char *c, *a;
2209   int pids[10];
2210   int pid;
2211   int failed;
2212 
2213   failed = 0;
2214   if (pipe(fds) != 0) {
2215     printf("%s: pipe() failed\n", s);
2216     exit(1);
2217   }
2218   for (i = 0; i < sizeof(pids) / sizeof(pids[0]); i++) {
2219     if ((pids[i] = fork()) == 0) {
2220       // allocate a lot of memory
2221       if (sbrk(BIG - (uint64)sbrk(0)) == (char *)SBRK_ERROR)
2222         write(fds[1], "0", 1);
2223       else
2224         write(fds[1], "1", 1);
2225       // sit around until killed
2226       for (;;)
2227         pause(1000);
2228     }
2229     if (pids[i] != -1) {
2230       read(fds[0], &scratch, 1);
2231       if (scratch == '0')
2232         failed = 1;
2233     }
2234   }
2235   if (!failed) {
2236     printf("%s: no allocation failed; allocate more?\n", s);
2237   }
2238 
2239   // if those failed allocations freed up the pages they did allocate,
2240   // we'll be able to allocate here
2241   c = sbrk(PGSIZE);
2242   for (i = 0; i < sizeof(pids) / sizeof(pids[0]); i++) {
2243     if (pids[i] == -1)
2244       continue;
2245     kill(pids[i]);
2246     wait(0);
2247   }
2248   if (c == (char *)SBRK_ERROR) {
2249     printf("%s: failed sbrk leaked memory\n", s);
2250     exit(1);
2251   }
2252 
2253   // test running fork with the above allocated page
2254   pid = fork();
2255   if (pid < 0) {
2256     printf("%s: fork failed\n", s);
2257     exit(1);
2258   }
2259   if (pid == 0) {
2260     // allocate a lot of memory. this should produce an error
2261     a = sbrk(10 * BIG);
2262     if (a == (char *)SBRK_ERROR) {
2263       exit(0);
2264     }
2265     printf("%s: allocate a lot of memory succeeded %d\n", s, 10 * BIG);
2266     exit(1);
2267   }
2268   wait(&xstatus);
2269   if (xstatus != 0)
2270     exit(1);
2271 }
2272 
2273 // test reads/writes from/to allocated memory
2274 void
2275 sbrkarg(char *s)
2276 {
2277   char *a;
2278   int fd, n;
2279 
2280   a = sbrk(PGSIZE);
2281   fd = open("sbrk", O_CREATE | O_WRONLY);
2282   unlink("sbrk");
2283   if (fd < 0) {
2284     printf("%s: open sbrk failed\n", s);
2285     exit(1);
2286   }
2287   if ((n = write(fd, a, PGSIZE)) < 0) {
2288     printf("%s: write sbrk failed\n", s);
2289     exit(1);
2290   }
2291   close(fd);
2292 
2293   // test writes to allocated memory
2294   a = sbrk(PGSIZE);
2295   if (pipe((int *)a) != 0) {
2296     printf("%s: pipe() failed\n", s);
2297     exit(1);
2298   }
2299 }
2300 
2301 void
2302 validatetest(char *s)
2303 {
2304   int hi;
2305   uint64 p;
2306 
2307   hi = 1100 * 1024;
2308   for (p = 0; p <= (uint)hi; p += PGSIZE) {
2309     // try to crash the kernel by passing in a bad string pointer
2310     if (link("nosuchfile", (char *)p) != -1) {
2311       printf("%s: link should not succeed\n", s);
2312       exit(1);
2313     }
2314   }
2315 }
2316 
2317 // does uninitialized data start out zero?
2318 char uninit[10000];
2319 void
2320 bsstest(char *s)
2321 {
2322   int i;
2323 
2324   for (i = 0; i < sizeof(uninit); i++) {
2325     if (uninit[i] != '\0') {
2326       printf("%s: bss test failed\n", s);
2327       exit(1);
2328     }
2329   }
2330 }
2331 
2332 // does exec return an error if the arguments
2333 // are larger than a page? or does it write
2334 // below the stack and wreck the instructions/data?
2335 void
2336 bigargtest(char *s)
2337 {
2338   int pid, fd, xstatus;
2339 
2340   unlink("bigarg-ok");
2341   pid = fork();
2342   if (pid == 0) {
2343     static char *args[MAXARG];
2344     int i;
2345     char big[400];
2346     memset(big, ' ', sizeof(big));
2347     big[sizeof(big) - 1] = '\0';
2348     for (i = 0; i < MAXARG - 1; i++)
2349       args[i] = big;
2350     args[MAXARG - 1] = 0;
2351     // this exec() should fail (and return) because the
2352     // arguments are too large.
2353     exec("echo", args);
2354     fd = open("bigarg-ok", O_CREATE);
2355     close(fd);
2356     exit(0);
2357   } else if (pid < 0) {
2358     printf("%s: bigargtest: fork failed\n", s);
2359     exit(1);
2360   }
2361 
2362   wait(&xstatus);
2363   if (xstatus != 0)
2364     exit(xstatus);
2365   fd = open("bigarg-ok", 0);
2366   if (fd < 0) {
2367     printf("%s: bigarg test failed!\n", s);
2368     exit(1);
2369   }
2370   close(fd);
2371 }
2372 
2373 // what happens when the file system runs out of blocks?
2374 // answer: balloc panics, so this test is not useful.
2375 void
2376 fsfull()
2377 {
2378   int nfiles;
2379   int fsblocks = 0;
2380 
2381   printf("fsfull test\n");
2382 
2383   for (nfiles = 0;; nfiles++) {
2384     char name[64];
2385     name[0] = 'f';
2386     name[1] = '0' + nfiles / 1000;
2387     name[2] = '0' + (nfiles % 1000) / 100;
2388     name[3] = '0' + (nfiles % 100) / 10;
2389     name[4] = '0' + (nfiles % 10);
2390     name[5] = '\0';
2391     printf("writing %s\n", name);
2392     int fd = open(name, O_CREATE | O_RDWR);
2393     if (fd < 0) {
2394       printf("open %s failed\n", name);
2395       break;
2396     }
2397     int total = 0;
2398     while (1) {
2399       int cc = write(fd, buf, BSIZE);
2400       if (cc < BSIZE)
2401         break;
2402       total += cc;
2403       fsblocks++;
2404     }
2405     printf("wrote %d bytes\n", total);
2406     close(fd);
2407     if (total == 0)
2408       break;
2409   }
2410 
2411   while (nfiles >= 0) {
2412     char name[64];
2413     name[0] = 'f';
2414     name[1] = '0' + nfiles / 1000;
2415     name[2] = '0' + (nfiles % 1000) / 100;
2416     name[3] = '0' + (nfiles % 100) / 10;
2417     name[4] = '0' + (nfiles % 10);
2418     name[5] = '\0';
2419     unlink(name);
2420     nfiles--;
2421   }
2422 
2423   printf("fsfull test finished, %d blocks\n", fsblocks);
2424 }
2425 
2426 void
2427 argptest(char *s)
2428 {
2429   int fd;
2430   fd = open("init", O_RDONLY);
2431   if (fd < 0) {
2432     printf("%s: open failed\n", s);
2433     exit(1);
2434   }
2435   read(fd, sbrk(0) - 1, -1);
2436   close(fd);
2437 }
2438 
2439 // check that there's an invalid page beneath
2440 // the user stack, to catch stack overflow.
2441 void
2442 stacktest(char *s)
2443 {
2444   int pid;
2445   int xstatus;
2446 
2447   pid = fork();
2448   if (pid == 0) {
2449     char *sp = (char *)r_sp();
2450     sp -= USERSTACK * PGSIZE;
2451     // the *sp should cause a trap.
2452     printf("%s: stacktest: read below stack %d\n", s, *sp);
2453     exit(1);
2454   } else if (pid < 0) {
2455     printf("%s: fork failed\n", s);
2456     exit(1);
2457   }
2458   wait(&xstatus);
2459   if (xstatus == -1) // kernel killed child?
2460     exit(0);
2461   else
2462     exit(xstatus);
2463 }
2464 
2465 // check that writes to a few forbidden addresses
2466 // cause a fault, e.g. process's text and TRAMPOLINE.
2467 void
2468 nowrite(char *s)
2469 {
2470   int pid;
2471   int xstatus;
2472   uint64 addrs[] = {0,
2473                     0x80000000LL,
2474                     0x3fffffe000,
2475                     0x3ffffff000,
2476                     0x4000000000,
2477                     0xffffffffffffffff};
2478 
2479   for (int ai = 0; ai < sizeof(addrs) / sizeof(addrs[0]); ai++) {
2480     pid = fork();
2481     if (pid == 0) {
2482       volatile int *addr = (int *)addrs[ai];
2483       *addr = 10;
2484       printf("%s: write to %p did not fail!\n", s, addr);
2485       exit(0);
2486     } else if (pid < 0) {
2487       printf("%s: fork failed\n", s);
2488       exit(1);
2489     }
2490     wait(&xstatus);
2491     if (xstatus == 0) {
2492       // kernel did not kill child!
2493       exit(1);
2494     }
2495   }
2496   exit(0);
2497 }
2498 
2499 // regression test. copyin(), copyout(), and copyinstr() used to cast
2500 // the virtual page address to uint, which (with certain wild system
2501 // call arguments) resulted in a kernel page faults.
2502 void *big = (void *)0xeaeb0b5b00002f5e;
2503 void
2504 pgbug(char *s)
2505 {
2506   char *argv[1];
2507   argv[0] = 0;
2508   exec(big, argv);
2509   pipe(big);
2510 
2511   exit(0);
2512 }
2513 
2514 // regression test. does the kernel panic if a process sbrk()s its
2515 // size to be less than a page, or zero, or reduces the break by an
2516 // amount too small to cause a page to be freed?
2517 void
2518 sbrkbugs(char *s)
2519 {
2520   int pid = fork();
2521   if (pid < 0) {
2522     printf("fork failed\n");
2523     exit(1);
2524   }
2525   if (pid == 0) {
2526     int sz = (uint64)sbrk(0);
2527     // free all user memory; there used to be a bug that
2528     // would not adjust p->sz correctly in this case,
2529     // causing exit() to panic.
2530     sbrk(-sz);
2531     // user page fault here.
2532     exit(0);
2533   }
2534   wait(0);
2535 
2536   pid = fork();
2537   if (pid < 0) {
2538     printf("fork failed\n");
2539     exit(1);
2540   }
2541   if (pid == 0) {
2542     int sz = (uint64)sbrk(0);
2543     // set the break to somewhere in the very first
2544     // page; there used to be a bug that would incorrectly
2545     // free the first page.
2546     sbrk(-(sz - 3500));
2547     exit(0);
2548   }
2549   wait(0);
2550 
2551   pid = fork();
2552   if (pid < 0) {
2553     printf("fork failed\n");
2554     exit(1);
2555   }
2556   if (pid == 0) {
2557     // set the break in the middle of a page.
2558     sbrk((10 * PGSIZE + 2048) - (uint64)sbrk(0));
2559 
2560     // reduce the break a bit, but not enough to
2561     // cause a page to be freed. this used to cause
2562     // a panic.
2563     sbrk(-10);
2564 
2565     exit(0);
2566   }
2567   wait(0);
2568 
2569   exit(0);
2570 }
2571 
2572 // if process size was somewhat more than a page boundary, and then
2573 // shrunk to be somewhat less than that page boundary, can the kernel
2574 // still copyin() from addresses in the last page?
2575 void
2576 sbrklast(char *s)
2577 {
2578   uint64 top = (uint64)sbrk(0);
2579   if ((top % PGSIZE) != 0)
2580     sbrk(PGSIZE - (top % PGSIZE));
2581   sbrk(PGSIZE);
2582   sbrk(10);
2583   sbrk(-20);
2584   top = (uint64)sbrk(0);
2585   char *p = (char *)(top - 64);
2586   p[0] = 'x';
2587   p[1] = '\0';
2588   int fd = open(p, O_RDWR | O_CREATE);
2589   write(fd, p, 1);
2590   close(fd);
2591   fd = open(p, O_RDWR);
2592   p[0] = '\0';
2593   read(fd, p, 1);
2594   if (p[0] != 'x')
2595     exit(1);
2596 }
2597 
2598 // does sbrk handle signed int32 wrap-around with
2599 // negative arguments?
2600 void
2601 sbrk8000(char *s)
2602 {
2603   sbrk(0x80000004);
2604   volatile char *top = sbrk(0);
2605   *(top - 1) = *(top - 1) + 1;
2606 }
2607 
2608 // regression test. test whether exec() leaks memory if one of the
2609 // arguments is invalid. the test passes if the kernel doesn't panic.
2610 void
2611 badarg(char *s)
2612 {
2613   for (int i = 0; i < 50000; i++) {
2614     char *argv[2];
2615     argv[0] = (char *)0xffffffff;
2616     argv[1] = 0;
2617     exec("echo", argv);
2618   }
2619 
2620   exit(0);
2621 }
2622 
2623 #define REGION_SZ (1024 * 1024 * 1024)
2624 
2625 // Touch a page every 64 pages, which with lazy allocation
2626 // causes one page to be allocated.
2627 void
2628 lazy_alloc(char *s)
2629 {
2630   char *i, *prev_end, *new_end;
2631 
2632   prev_end = sbrklazy(REGION_SZ);
2633   if (prev_end == (char *)SBRK_ERROR) {
2634     printf("sbrklazy() failed\n");
2635     exit(1);
2636   }
2637   new_end = prev_end + REGION_SZ;
2638 
2639   for (i = prev_end + PGSIZE; i < new_end; i += 64 * PGSIZE)
2640     *(char **)i = i;
2641 
2642   for (i = prev_end + PGSIZE; i < new_end; i += 64 * PGSIZE) {
2643     if (*(char **)i != i) {
2644       printf("failed to read value from memory\n");
2645       exit(1);
2646     }
2647   }
2648 
2649   exit(0);
2650 }
2651 
2652 // Touch a page every 64 pages in region, which with lazy allocation
2653 // causes one page to be allocated. Check that freeing the region
2654 // frees the allocated pages.
2655 void
2656 lazy_unmap(char *s)
2657 {
2658   int pid;
2659   char *i, *prev_end, *new_end;
2660 
2661   prev_end = sbrklazy(REGION_SZ);
2662   if (prev_end == (char *)SBRK_ERROR) {
2663     printf("sbrklazy() failed\n");
2664     exit(1);
2665   }
2666   new_end = prev_end + REGION_SZ;
2667 
2668   for (i = prev_end + PGSIZE; i < new_end; i += PGSIZE * PGSIZE)
2669     *(char **)i = i;
2670 
2671   for (i = prev_end + PGSIZE; i < new_end; i += PGSIZE * PGSIZE) {
2672     pid = fork();
2673     if (pid < 0) {
2674       printf("error forking\n");
2675       exit(1);
2676     } else if (pid == 0) {
2677       sbrklazy(-1L * REGION_SZ);
2678       *(char **)i = i;
2679       exit(0);
2680     } else {
2681       int status;
2682       wait(&status);
2683       if (status == 0) {
2684         printf("memory not unmapped\n");
2685         exit(1);
2686       }
2687     }
2688   }
2689 
2690   exit(0);
2691 }
2692 
2693 void
2694 lazy_copy(char *s)
2695 {
2696   // copyinstr on lazy page
2697   {
2698     char *p = sbrk(0);
2699     sbrklazy(4 * PGSIZE);
2700     open(p + 8192, 0);
2701   }
2702 
2703   {
2704     void *xx = sbrk(0);
2705     void *ret = sbrk(-(((uint64)xx) + 1));
2706     if (ret != xx) {
2707       printf("sbrk(sbrk(0)+1) returned %p, not old sz\n", ret);
2708       exit(1);
2709     }
2710   }
2711 
2712   // read() and write() to these addresses should fail.
2713   unsigned long bad[] = {
2714     0x3fffffc000, 0x3fffffd000, 0x3fffffe000,
2715     0x3ffffff000, 0x4000000000, 0x8000000000,
2716   };
2717   for (int i = 0; i < sizeof(bad) / sizeof(bad[0]); i++) {
2718     int fd = open("README", 0);
2719     if (fd < 0) {
2720       printf("cannot open README\n");
2721       exit(1);
2722     }
2723     if (read(fd, (char *)bad[i], 512) >= 0) {
2724       printf("read succeeded\n");
2725       exit(1);
2726     }
2727     close(fd);
2728     fd = open("junk", O_CREATE | O_RDWR | O_TRUNC);
2729     if (fd < 0) {
2730       printf("cannot open junk\n");
2731       exit(1);
2732     }
2733     if (write(fd, (char *)bad[i], 512) >= 0) {
2734       printf("write succeeded\n");
2735       exit(1);
2736     }
2737     close(fd);
2738   }
2739 
2740   exit(0);
2741 }
2742 
2743 void
2744 lazy_copyinstr(char *s)
2745 {
2746   char *p = sbrk(0);
2747   sbrk(PGSIZE - ((uint64)p % PGSIZE));
2748 
2749   p = sbrk(0);
2750   if ((uint64)p % PGSIZE != 0) {
2751     printf("%s: sbrk did not align\n", s);
2752     exit(1);
2753   }
2754 
2755   sbrklazy(2 * PGSIZE);
2756   p[4095] = '/';
2757   int fd = open(&p[4095], O_RDONLY);
2758   if (fd < 0) {
2759     printf("could not open /");
2760     exit(1);
2761   }
2762 
2763   struct stat st;
2764   int r = fstat(fd, &st);
2765   if (r < 0) {
2766     printf("could not stat /");
2767     exit(1);
2768   }
2769 
2770   if (st.type != T_DIR) {
2771     printf("/ is not T_DIR");
2772     exit(1);
2773   }
2774 
2775   close(fd);
2776 }
2777 
2778 void
2779 lazy_sbrk(char *s)
2780 {
2781   // sbrk() takes just int, so take 2^30-sized steps towards MAXVA
2782   char *p = sbrk(0);
2783   while ((uint64)p < MAXVA - (1 << 30)) {
2784     p = sbrklazy(1 << 30);
2785     if (p < 0) {
2786       printf("sbrklazy(%d) returned %p\n", 1 << 30, p);
2787       exit(1);
2788     }
2789 
2790     p = sbrklazy(0);
2791   }
2792 
2793   int n = TRAPFRAME - PGSIZE - (uint64)p;
2794 
2795   char *p1 = sbrklazy(n);
2796   if (p1 < 0 || p1 != p) {
2797     printf("sbrklazy(%d) returned %p, not expected %p\n", n, p1, p);
2798     exit(1);
2799   }
2800 
2801   p = sbrk(PGSIZE);
2802   if (p < 0 || (uint64)p != TRAPFRAME - PGSIZE) {
2803     printf("sbrk(%d) returned %p, not expected TRAPFRAME-PGSIZE\n", PGSIZE, p);
2804     exit(1);
2805   }
2806 
2807   p[0] = 1;
2808   if (p[1] != 0) {
2809     printf("sbrk() returned non-zero-filled memory\n");
2810     exit(1);
2811   }
2812 
2813   p = sbrk(1);
2814   if ((uint64)p != -1) {
2815     printf("sbrk(1) returned %p, expected error\n", p);
2816     exit(1);
2817   }
2818 
2819   p = sbrklazy(1);
2820   if ((uint64)p != -1) {
2821     printf("sbrklazy(1) returned %p, expected error\n", p);
2822     exit(1);
2823   }
2824 
2825   exit(0);
2826 }
2827 
2828 void
2829 partial_write(char *s)
2830 {
2831   // Create testfile containing "A".
2832   // write() 2 bytes that span page boundary: first is "X", second is unmapped.
2833   // Potential problem: write errors, forgets to log the updated first byte.
2834   // read() from file returns "X".
2835   // Flush buffer cache with some large writes.
2836   // read() from file should still return "X" (but might return "A" due to bug).
2837 
2838   unlink("testfile");
2839   int fd = open("testfile", O_CREATE | O_RDWR);
2840   if (fd < 0) {
2841     printf("%s: cannot create testfile\n", s);
2842     exit(1);
2843   }
2844 
2845   int cc = write(fd, "A", 1);
2846   if (cc != 1) {
2847     printf("%s: could not write A\n", s);
2848     exit(1);
2849   }
2850 
2851   close(fd);
2852   fd = open("testfile", O_RDWR);
2853   if (fd < 0) {
2854     printf("%s: cannot re-open testfile\n", s);
2855     exit(1);
2856   }
2857 
2858   char *p = sbrk(0);
2859   sbrk(PGSIZE - ((uint64)p % PGSIZE));
2860 
2861   p = sbrk(0);
2862   if ((uint64)p % PGSIZE != 0) {
2863     printf("%s: sbrk did not align\n", s);
2864     exit(1);
2865   }
2866 
2867   p[-1] = 'X';
2868 
2869   cc = write(fd, p - 1, 2);
2870   if (cc != -1) {
2871     printf("%s: write succeeded, should have failed\n", s);
2872     exit(1);
2873   }
2874 
2875   close(fd);
2876 
2877   fd = open("testfile", O_RDONLY);
2878   if (fd < 0) {
2879     printf("%s: cannot re-open testfile\n", s);
2880     exit(1);
2881   }
2882 
2883   char b;
2884   cc = read(fd, &b, 1);
2885   if (cc != 1) {
2886     printf("%s: cannot read testfile\n", s);
2887     exit(1);
2888   }
2889 
2890   close(fd);
2891 
2892   if (b != 'X') {
2893     printf("%s: read returned %c, expected X\n", s, b);
2894     exit(1);
2895   }
2896 
2897   fd = open("bigfile", O_CREATE | O_RDWR);
2898   for (int i = 0; i < 64; i++) {
2899     char buf[1024];
2900     memset(buf, 0, sizeof(buf));
2901     cc = write(fd, buf, sizeof(buf));
2902     if (cc != sizeof(buf)) {
2903       printf("%s: could not write to bigfile\n", s);
2904       exit(-1);
2905     }
2906   }
2907   close(fd);
2908 
2909   unlink("bigfile");
2910 
2911   fd = open("testfile", O_RDONLY);
2912   if (fd < 0) {
2913     printf("%s: cannot re-open testfile\n", s);
2914     exit(1);
2915   }
2916 
2917   cc = read(fd, &b, 1);
2918   if (cc != 1) {
2919     printf("%s: cannot read testfile\n", s);
2920     exit(1);
2921   }
2922 
2923   close(fd);
2924 
2925   if (b != 'X') {
2926     printf("%s: read returned %c, expected X\n", s, b);
2927     exit(1);
2928   }
2929 
2930   unlink("testfile");
2931 }
2932 
2933 void
2934 unlinkcwd(char *s)
2935 {
2936   if (mkdir("/a") < 0) {
2937     printf("%s: mkdir /a failed\n", s);
2938     exit(1);
2939   }
2940   if (mkdir("/a/b") < 0) {
2941     printf("%s: mkdir /a/b failed\n", s);
2942     exit(1);
2943   }
2944   if (chdir("/a/b") < 0) {
2945     printf("%s: chdir failed\n", s);
2946     exit(1);
2947   }
2948   if (unlink("/a/b") < 0) {
2949     printf("%s: unlink /a/b failed\n", s);
2950     exit(1);
2951   }
2952   if (unlink("/a") < 0) {
2953     printf("%s: unlink /a failed\n", s);
2954     exit(1);
2955   }
2956   if (open("../", O_RDONLY) > 0) {
2957     printf("%s: open ../ non-existing directory\n", s);
2958   }
2959   if (open("../c", O_CREATE) > 0) {
2960     printf("%s: create ../c non-existing file\n", s);
2961   }
2962 }
2963 
2964 struct test {
2965   void (*f)(char *);
2966   char *s;
2967 } quicktests[] = {
2968   {copyin, "copyin"},
2969   {copyout, "copyout"},
2970   {copyinstr1, "copyinstr1"},
2971   {copyinstr2, "copyinstr2"},
2972   {copyinstr3, "copyinstr3"},
2973   {rwsbrk, "rwsbrk"},
2974   {truncate1, "truncate1"},
2975   {truncate2, "truncate2"},
2976   {truncate3, "truncate3"},
2977   {openiputtest, "openiput"},
2978   {exitiputtest, "exitiput"},
2979   {iputtest, "iput"},
2980   {opentest, "opentest"},
2981   {writetest, "writetest"},
2982   {writebig, "writebig"},
2983   {createtest, "createtest"},
2984   {dirtest, "dirtest"},
2985   {exectest, "exectest"},
2986   {pipe1, "pipe1"},
2987   {killstatus, "killstatus"},
2988   {killzero, "killzero"},
2989   {preempt, "preempt"},
2990   {exitwait, "exitwait"},
2991   {reparent, "reparent"},
2992   {twochildren, "twochildren"},
2993   {forkfork, "forkfork"},
2994   {forkforkfork, "forkforkfork"},
2995   {reparent2, "reparent2"},
2996   {mem, "mem"},
2997   {sharedfd, "sharedfd"},
2998   {fourfiles, "fourfiles"},
2999   {createdelete, "createdelete"},
3000   {unlinkread, "unlinkread"},
3001   {linktest, "linktest"},
3002   {concreate, "concreate"},
3003   {linkunlink, "linkunlink"},
3004   {subdir, "subdir"},
3005   {bigwrite, "bigwrite"},
3006   {bigfile, "bigfile"},
3007   {fourteen, "fourteen"},
3008   {rmdot, "rmdot"},
3009   {dirfile, "dirfile"},
3010   {iref, "iref"},
3011   {forktest, "forktest"},
3012   {sbrkbasic, "sbrkbasic"},
3013   {sbrkmuch, "sbrkmuch"},
3014   {kernmem, "kernmem"},
3015   {MAXVAplus, "MAXVAplus"},
3016   {sbrkfail, "sbrkfail"},
3017   {sbrkarg, "sbrkarg"},
3018   {validatetest, "validatetest"},
3019   {bsstest, "bsstest"},
3020   {bigargtest, "bigargtest"},
3021   {argptest, "argptest"},
3022   {stacktest, "stacktest"},
3023   {nowrite, "nowrite"},
3024   {pgbug, "pgbug"},
3025   {sbrkbugs, "sbrkbugs"},
3026   {sbrklast, "sbrklast"},
3027   {sbrk8000, "sbrk8000"},
3028   {badarg, "badarg"},
3029   {lazy_alloc, "lazy_alloc"},
3030   {lazy_unmap, "lazy_unmap"},
3031   {lazy_copy, "lazy_copy"},
3032   {lazy_copyinstr, "lazy_copyinstr"},
3033   {lazy_sbrk, "lazy_sbrk"},
3034   {partial_write, "partial_write"},
3035   {unlinkcwd, "unlinkcwd"},
3036   {0, 0},
3037 };
3038 
3039 //
3040 // Section with tests that take a fair bit of time
3041 //
3042 
3043 // directory that uses indirect blocks
3044 void
3045 bigdir(char *s)
3046 {
3047   enum { N = 500 };
3048   int i, fd;
3049   char name[10];
3050 
3051   unlink("bd");
3052 
3053   fd = open("bd", O_CREATE);
3054   if (fd < 0) {
3055     printf("%s: bigdir create failed\n", s);
3056     exit(1);
3057   }
3058   close(fd);
3059 
3060   for (i = 0; i < N; i++) {
3061     name[0] = 'x';
3062     name[1] = '0' + (i / 64);
3063     name[2] = '0' + (i % 64);
3064     name[3] = '\0';
3065     if (link("bd", name) != 0) {
3066       printf("%s: bigdir i=%d link(bd, %s) failed\n", s, i, name);
3067       exit(1);
3068     }
3069   }
3070 
3071   unlink("bd");
3072   for (i = 0; i < N; i++) {
3073     name[0] = 'x';
3074     name[1] = '0' + (i / 64);
3075     name[2] = '0' + (i % 64);
3076     name[3] = '\0';
3077     if (unlink(name) != 0) {
3078       printf("%s: bigdir unlink failed", s);
3079       exit(1);
3080     }
3081   }
3082 }
3083 
3084 // concurrent writes to try to provoke deadlock in the virtio disk
3085 // driver.
3086 void
3087 manywrites(char *s)
3088 {
3089   int nchildren = 4;
3090   int howmany = 30; // increase to look for deadlock
3091 
3092   for (int ci = 0; ci < nchildren; ci++) {
3093     int pid = fork();
3094     if (pid < 0) {
3095       printf("fork failed\n");
3096       exit(1);
3097     }
3098 
3099     if (pid == 0) {
3100       char name[3];
3101       name[0] = 'b';
3102       name[1] = 'a' + ci;
3103       name[2] = '\0';
3104       unlink(name);
3105 
3106       for (int iters = 0; iters < howmany; iters++) {
3107         for (int i = 0; i < ci + 1; i++) {
3108           int fd = open(name, O_CREATE | O_RDWR);
3109           if (fd < 0) {
3110             printf("%s: cannot create %s\n", s, name);
3111             exit(1);
3112           }
3113           int sz = sizeof(buf);
3114           int cc = write(fd, buf, sz);
3115           if (cc != sz) {
3116             printf("%s: write(%d) ret %d\n", s, sz, cc);
3117             exit(1);
3118           }
3119           close(fd);
3120         }
3121         unlink(name);
3122       }
3123 
3124       unlink(name);
3125       exit(0);
3126     }
3127   }
3128 
3129   for (int ci = 0; ci < nchildren; ci++) {
3130     int st = 0;
3131     wait(&st);
3132     if (st != 0)
3133       exit(st);
3134   }
3135   exit(0);
3136 }
3137 
3138 // regression test. does write() with an invalid buffer pointer cause
3139 // a block to be allocated for a file that is then not freed when the
3140 // file is deleted? if the kernel has this bug, it will panic: balloc:
3141 // out of blocks. assumed_free may need to be raised to be more than
3142 // the number of free blocks. this test takes a long time.
3143 void
3144 badwrite(char *s)
3145 {
3146   int assumed_free = 600;
3147 
3148   unlink("junk");
3149   for (int i = 0; i < assumed_free; i++) {
3150     int fd = open("junk", O_CREATE | O_WRONLY);
3151     if (fd < 0) {
3152       printf("open junk failed\n");
3153       exit(1);
3154     }
3155     write(fd, (char *)0xffffffffffL, 1);
3156     close(fd);
3157     unlink("junk");
3158   }
3159 
3160   int fd = open("junk", O_CREATE | O_WRONLY);
3161   if (fd < 0) {
3162     printf("open junk failed\n");
3163     exit(1);
3164   }
3165   if (write(fd, "x", 1) != 1) {
3166     printf("write failed\n");
3167     exit(1);
3168   }
3169   close(fd);
3170   unlink("junk");
3171 
3172   exit(0);
3173 }
3174 
3175 // test the exec() code that cleans up if it runs out
3176 // of memory. it's really a test that such a condition
3177 // doesn't cause a panic.
3178 void
3179 execout(char *s)
3180 {
3181   for (int avail = 0; avail < 15; avail++) {
3182     int pid = fork();
3183     if (pid < 0) {
3184       printf("fork failed\n");
3185       exit(1);
3186     } else if (pid == 0) {
3187       // allocate all of memory.
3188       while (1) {
3189         char *a = sbrk(PGSIZE);
3190         if (a == SBRK_ERROR)
3191           break;
3192         *(a + PGSIZE - 1) = 1;
3193       }
3194 
3195       // free a few pages, in order to let exec() make some
3196       // progress.
3197       for (int i = 0; i < avail; i++)
3198         sbrk(-PGSIZE);
3199 
3200       close(1);
3201       char *args[] = {"echo", "x", 0};
3202       exec("echo", args);
3203       exit(0);
3204     } else {
3205       wait((int *)0);
3206     }
3207   }
3208 
3209   exit(0);
3210 }
3211 
3212 // can the kernel tolerate running out of disk space?
3213 void
3214 diskfull(char *s)
3215 {
3216   int fi;
3217   int done = 0;
3218 
3219   unlink("diskfulldir");
3220 
3221   for (fi = 0; done == 0 && '0' + fi < 0177; fi++) {
3222     char name[32];
3223     name[0] = 'b';
3224     name[1] = 'i';
3225     name[2] = 'g';
3226     name[3] = '0' + fi;
3227     name[4] = '\0';
3228     unlink(name);
3229     int fd = open(name, O_CREATE | O_RDWR | O_TRUNC);
3230     if (fd < 0) {
3231       // oops, ran out of inodes before running out of blocks.
3232       printf("%s: could not create file %s\n", s, name);
3233       done = 1;
3234       break;
3235     }
3236     for (int i = 0; i < MAXFILE; i++) {
3237       char buf[BSIZE];
3238       if (write(fd, buf, BSIZE) != BSIZE) {
3239         done = 1;
3240         close(fd);
3241         break;
3242       }
3243     }
3244     close(fd);
3245   }
3246 
3247   // now that there are no free blocks, test that dirlink()
3248   // merely fails (doesn't panic) if it can't extend
3249   // directory content. one of these file creations
3250   // is expected to fail.
3251   int nzz = 128;
3252   for (int i = 0; i < nzz; i++) {
3253     char name[32];
3254     name[0] = 'z';
3255     name[1] = 'z';
3256     name[2] = '0' + (i / 32);
3257     name[3] = '0' + (i % 32);
3258     name[4] = '\0';
3259     unlink(name);
3260     int fd = open(name, O_CREATE | O_RDWR | O_TRUNC);
3261     if (fd < 0)
3262       break;
3263     close(fd);
3264   }
3265 
3266   // this mkdir() is expected to fail.
3267   if (mkdir("diskfulldir") == 0)
3268     printf("%s: mkdir(diskfulldir) unexpectedly succeeded!\n", s);
3269 
3270   unlink("diskfulldir");
3271 
3272   for (int i = 0; i < nzz; i++) {
3273     char name[32];
3274     name[0] = 'z';
3275     name[1] = 'z';
3276     name[2] = '0' + (i / 32);
3277     name[3] = '0' + (i % 32);
3278     name[4] = '\0';
3279     unlink(name);
3280   }
3281 
3282   for (int i = 0; '0' + i < 0177; i++) {
3283     char name[32];
3284     name[0] = 'b';
3285     name[1] = 'i';
3286     name[2] = 'g';
3287     name[3] = '0' + i;
3288     name[4] = '\0';
3289     unlink(name);
3290   }
3291 }
3292 
3293 void
3294 outofinodes(char *s)
3295 {
3296   int nzz = 32 * 32;
3297   for (int i = 0; i < nzz; i++) {
3298     char name[32];
3299     name[0] = 'z';
3300     name[1] = 'z';
3301     name[2] = '0' + (i / 32);
3302     name[3] = '0' + (i % 32);
3303     name[4] = '\0';
3304     unlink(name);
3305     int fd = open(name, O_CREATE | O_RDWR | O_TRUNC);
3306     if (fd < 0) {
3307       // failure is eventually expected.
3308       break;
3309     }
3310     close(fd);
3311   }
3312 
3313   for (int i = 0; i < nzz; i++) {
3314     char name[32];
3315     name[0] = 'z';
3316     name[1] = 'z';
3317     name[2] = '0' + (i / 32);
3318     name[3] = '0' + (i % 32);
3319     name[4] = '\0';
3320     unlink(name);
3321   }
3322 }
3323 
3324 void
3325 linkoverflow(char *s)
3326 {
3327   enum { TARGET = 32768 };
3328   enum { DIRS = 64 };
3329   struct stat st;
3330   int i;
3331 
3332   unlink("/lof");
3333   int fd = open("/lof", O_CREATE | O_RDWR);
3334   if (fd < 0) {
3335     printf("%s: cannot create /lof\n", s);
3336     exit(1);
3337   }
3338   close(fd);
3339 
3340   for (i = 0; i < TARGET; i++) {
3341     int d = i % DIRS;
3342     int f = i / DIRS;
3343 
3344     char pn[16];
3345     pn[0] = '/';
3346     pn[1] = 'd';
3347     pn[2] = '_';
3348     pn[3] = 'a' + (d / 16);
3349     pn[4] = 'a' + (d % 16);
3350     pn[5] = '\0';
3351     if (f == 0 && mkdir(pn) < 0) {
3352       printf("%s: mkdir(%s) failed\n", s, pn);
3353       exit(1);
3354     }
3355 
3356     pn[5] = '/';
3357     pn[6] = 'l';
3358     pn[7] = 'a' + (f / 256);
3359     pn[8] = 'a' + ((f / 16) % 16);
3360     pn[9] = 'a' + (f % 16);
3361     pn[10] = '\0';
3362 
3363     if (link("/lof", pn) < 0) {
3364       if (stat("/lof", &st) < 0) {
3365         printf("%s: stat(/lof) failed\n", s);
3366         exit(1);
3367       }
3368       if (st.nlink >= 32767) {
3369         // overflow check succeeded.
3370         break;
3371       }
3372       printf("%s: link failed after %d links (nlink=%d)\n", s, i, st.nlink);
3373       exit(1);
3374     }
3375 
3376     if (i % 100 == 0) {
3377       printf("%s: i=%d, pn=%s\n", s, i, pn);
3378     }
3379   }
3380 
3381   if (stat("/lof", &st) < 0) {
3382     printf("%s: stat(/lof) failed\n", s);
3383     exit(1);
3384   }
3385 
3386   unlink("/lof");
3387 
3388   if (st.nlink < 0) {
3389     printf("%s: negative link count: %d\n", s, st.nlink);
3390     exit(1);
3391   }
3392 }
3393 
3394 struct test slowtests[] = {
3395   {bigdir, "bigdir"},
3396   {manywrites, "manywrites"},
3397   {badwrite, "badwrite"},
3398   {execout, "execout"},
3399   {diskfull, "diskfull"},
3400   {outofinodes, "outofinodes"},
3401   // {linkoverflow, "linkoverflow"},
3402 
3403   {0, 0},
3404 };
3405 
3406 //
3407 // drive tests
3408 //
3409 
3410 // run each test in its own process. run returns 1 if child's exit()
3411 // indicates success.
3412 int
3413 run(void f(char *), char *s)
3414 {
3415   int pid;
3416   int xstatus;
3417 
3418   printf("test %s: ", s);
3419   if ((pid = fork()) < 0) {
3420     printf("runtest: fork error\n");
3421     exit(1);
3422   }
3423   if (pid == 0) {
3424     f(s);
3425     exit(0);
3426   } else {
3427     wait(&xstatus);
3428     if (xstatus != 0)
3429       printf("FAILED\n");
3430     else
3431       printf("OK\n");
3432     return xstatus == 0;
3433   }
3434 }
3435 
3436 int
3437 runtests(struct test *tests, char *justone, int continuous)
3438 {
3439   int ntests = 0;
3440   for (struct test *t = tests; t->s != 0; t++) {
3441     if ((justone == 0) || strcmp(t->s, justone) == 0) {
3442       ntests++;
3443       if (!run(t->f, t->s)) {
3444         if (continuous != 2) {
3445           printf("SOME TESTS FAILED\n");
3446           return -1;
3447         }
3448       }
3449     }
3450   }
3451   return ntests;
3452 }
3453 
3454 // use sbrk() to count how many free physical memory pages there are.
3455 int
3456 countfree()
3457 {
3458   int n = 0;
3459   uint64 sz0 = (uint64)sbrk(0);
3460   while (1) {
3461     char *a = sbrk(PGSIZE);
3462     if (a == SBRK_ERROR) {
3463       break;
3464     }
3465     n += 1;
3466   }
3467   sbrk(-((uint64)sbrk(0) - sz0));
3468   return n;
3469 }
3470 
3471 int
3472 drivetests(int quick, int continuous, char *justone)
3473 {
3474   do {
3475     printf("usertests starting\n");
3476     int free0 = countfree();
3477     int free1 = 0;
3478     int ntests = 0;
3479     int n;
3480     n = runtests(quicktests, justone, continuous);
3481     if (n < 0) {
3482       if (continuous != 2) {
3483         return 1;
3484       }
3485     } else {
3486       ntests += n;
3487     }
3488     if (!quick) {
3489       if (justone == 0)
3490         printf("usertests slow tests starting\n");
3491       n = runtests(slowtests, justone, continuous);
3492       if (n < 0) {
3493         if (continuous != 2) {
3494           return 1;
3495         }
3496       } else {
3497         ntests += n;
3498       }
3499     }
3500     if ((free1 = countfree()) < free0) {
3501       printf("FAILED -- lost some free pages %d (out of %d)\n", free1, free0);
3502       if (continuous != 2) {
3503         return 1;
3504       }
3505     }
3506     if (justone != 0 && ntests == 0) {
3507       printf("NO TESTS EXECUTED\n");
3508       return 1;
3509     }
3510   } while (continuous);
3511   return 0;
3512 }
3513 
3514 int
3515 main(int argc, char *argv[])
3516 {
3517   int continuous = 0;
3518   int quick = 0;
3519   char *justone = 0;
3520 
3521   if (argc == 2 && strcmp(argv[1], "-q") == 0) {
3522     quick = 1;
3523   } else if (argc == 2 && strcmp(argv[1], "-c") == 0) {
3524     continuous = 1;
3525   } else if (argc == 2 && strcmp(argv[1], "-C") == 0) {
3526     continuous = 2;
3527   } else if (argc == 2 && argv[1][0] != '-') {
3528     justone = argv[1];
3529   } else if (argc > 1) {
3530     printf("Usage: usertests [-c] [-C] [-q] [testname]\n");
3531     exit(1);
3532   }
3533   if (drivetests(quick, continuous, justone)) {
3534     exit(1);
3535   }
3536   printf("ALL TESTS PASSED\n");
3537   exit(0);
3538 }

/* [<][>][^][v][top][bottom][index][help] */