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

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