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

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