xv6, line by line
user/usertests.c

user/usertests.c

C · 3538 lines · annotated 100% · user program / library · upstream

About this file

usertests is xv6’s test suite: one user program, about seventy small tests, each a C function that pokes at the kernel through system calls and checks the answers. Many are regression tests for bugs that were once real.

Tests come in two tables. quicktests holds most of them; slowtests holds a few that fill the disk or make huge directories. drivetests runs the tables in order, and run runs each test in its own forked child: the test fails if that child exits with a non-zero status. Each test gets its own name as s, and most use it as the prefix of their error messages. Before and after a run, countfree counts free memory pages, so a kernel that leaks pages fails even when every test passed.

At the xv6 shell prompt you type usertests (all tests), usertests -q (quick tests only), or usertests copyin (one test by name). -c repeats until something fails; -C repeats forever and ignores failures. Only one argument is accepted, so options cannot be combined. A run prints

usertests starting
test copyin: OK
test copyout: OK
...
ALL TESTS PASSED

A failing test prints FAILED and the run stops with SOME TESTS FAILED (with -C it carries on). Leaked pages print FAILED -- lost some free pages. Kernel usertrap(): unexpected scause lines between tests are expected when the test still says OK. From the host, ./test-xv6.py usertests runs it under QEMU.

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//
20#define BUFSZ ((MAXOPBLOCKS + 2) * BSIZE)
22char buf[BUFSZ];
24//
25// Section with tests that run fairly quickly. Use -q if you want to
26// run just those. Without -q usertests also runs the ones that take a
27// fair amount of time.
28//
30// what if you pass ridiculous pointers to system calls
31// that read user memory with copyin?
32void
33copyin(char *s)
35 uint64 addrs[] = {0x80000000LL, 0x3fffffe000, 0x3ffffff000, 0x4000000000,
36 0xffffffffffffffff};
38 for (int ai = 0; ai < sizeof(addrs) / sizeof(addrs[0]); ai++) {
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 }
52 unlink("copyin1");
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 }
60 int fds[2];
61 if (pipe(fds) < 0) {
62 printf("pipe() failed\n");
63 exit(1);
64 }
65 n = write(fds[1], (char *)addr, 8192);
66 if (n > 0) {
67 printf("write(pipe, %p, 8192) returned %d, not -1 or 0\n", (void *)addr,
68 n);
69 exit(1);
70 }
71 close(fds[0]);
72 close(fds[1]);
73 }
76// what if you pass ridiculous pointers to system calls
77// that write user memory with copyout?
78void
79copyout(char *s)
81 uint64 addrs[] = {0LL, 0x80000000LL, 0x3fffffe000,
82 0x3ffffff000, 0x4000000000, 0xffffffffffffffff};
84 for (int ai = 0; ai < sizeof(addrs) / sizeof(addrs[0]); ai++) {
87 int fd = open("README", 0);
88 if (fd < 0) {
89 printf("open(README) failed\n");
90 exit(1);
91 }
92 int n = read(fd, (void *)addr, 8192);
93 if (n > 0) {
94 printf("read(fd, %p, 8192) returned %d, not -1 or 0\n", (void *)addr, n);
95 exit(1);
96 }
99 int fds[2];
100 if (pipe(fds) < 0) {
101 printf("pipe() failed\n");
102 exit(1);
103 }
104 n = write(fds[1], "x", 1);
105 if (n != 1) {
106 printf("pipe write failed\n");
107 exit(1);
108 }
109 n = read(fds[0], (void *)addr, 8192);
110 if (n > 0) {
111 printf("read(pipe, %p, 8192) returned %d, not -1 or 0\n", (void *)addr,
112 n);
113 exit(1);
114 }
117 }
120// what if you pass ridiculous string pointers to system calls?
121void
124 uint64 addrs[] = {0x80000000LL, 0x3fffffe000, 0x3ffffff000, 0x4000000000,
125 0xffffffffffffffff};
127 for (int ai = 0; ai < sizeof(addrs) / sizeof(addrs[0]); ai++) {
130 int fd = open((char *)addr, O_CREATE | O_WRONLY);
131 if (fd >= 0) {
132 printf("open(%p) returned %d, not -1\n", (void *)addr, fd);
133 exit(1);
134 }
135 }
138// what if a string system call argument is exactly the size
139// of the kernel buffer it is copied into, so that the null
140// would fall just beyond the end of the kernel buffer?
141void
144 char b[MAXPATH + 1];
146 for (int i = 0; i < MAXPATH; i++)
147 b[i] = 'x';
148 b[MAXPATH] = '\0';
150 int ret = unlink(b);
151 if (ret != -1) {
152 printf("unlink(%s) returned %d, not -1\n", b, ret);
153 exit(1);
154 }
157 if (fd != -1) {
158 printf("open(%s) returned %d, not -1\n", b, fd);
159 exit(1);
160 }
162 ret = link(b, b);
163 if (ret != -1) {
164 printf("link(%s, %s) returned %d, not -1\n", b, b, ret);
165 exit(1);
166 }
168 char *args[] = {"xx", 0};
170 if (ret != -1) {
171 printf("exec(%s) returned %d, not -1\n", b, fd);
172 exit(1);
173 }
175 int pid = fork();
176 if (pid < 0) {
177 printf("fork failed\n");
178 exit(1);
179 }
180 if (pid == 0) {
181 static char big[PGSIZE + 1];
182 for (int i = 0; i < PGSIZE; i++)
183 big[i] = 'x';
184 big[PGSIZE] = '\0';
185 char *args2[] = {big, big, big, 0};
186 ret = exec("echo", args2);
187 if (ret != -1) {
188 printf("exec(echo, BIG) returned %d, not -1\n", fd);
189 exit(1);
190 }
191 exit(747); // OK
192 }
194 int st = 0;
196 if (st != 747) {
197 printf("exec(echo, BIG) succeeded, should have failed\n");
198 exit(1);
199 }
202// what if a string argument crosses over the end of last user page?
203void
206 sbrk(8192);
208 if ((top % PGSIZE) != 0) {
210 }
212 if (top % PGSIZE) {
213 printf("oops\n");
214 exit(1);
215 }
217 char *b = (char *)(top - 1);
218 *b = 'x';
220 int ret = unlink(b);
221 if (ret != -1) {
222 printf("unlink(%s) returned %d, not -1\n", b, ret);
223 exit(1);
224 }
227 if (fd != -1) {
228 printf("open(%s) returned %d, not -1\n", b, fd);
229 exit(1);
230 }
232 ret = link(b, b);
233 if (ret != -1) {
234 printf("link(%s, %s) returned %d, not -1\n", b, b, ret);
235 exit(1);
236 }
238 char *args[] = {"xx", 0};
240 if (ret != -1) {
241 printf("exec(%s) returned %d, not -1\n", b, fd);
242 exit(1);
243 }
246// See if the kernel refuses to read/write user memory that the
247// application doesn't have anymore, because it returned it.
248void
249rwsbrk(char *s)
251 int fd, n;
253 uint64 a = (uint64)sbrk(8192);
255 if (a == (uint64)SBRK_ERROR) {
256 printf("sbrk(rwsbrk) failed\n");
257 exit(1);
258 }
260 if (sbrk(-8192) == SBRK_ERROR) {
261 printf("sbrk(rwsbrk) shrink failed\n");
262 exit(1);
263 }
265 fd = open("rwsbrk", O_CREATE | O_WRONLY);
266 if (fd < 0) {
267 printf("open(rwsbrk) failed\n");
268 exit(1);
269 }
270 n = write(fd, (void *)(a + PGSIZE), 1024);
271 if (n >= 0) {
272 printf("write(fd, %p, 1024) returned %d, not -1\n", (void *)a + PGSIZE, n);
273 exit(1);
274 }
276 unlink("rwsbrk");
278 fd = open("README", O_RDONLY);
279 if (fd < 0) {
280 printf("open(README) failed\n");
281 exit(1);
282 }
283 n = read(fd, (void *)(a + PGSIZE), 10);
284 if (n >= 0) {
285 printf("read(fd, %p, 10) returned %d, not -1\n", (void *)a + PGSIZE, n);
286 exit(1);
287 }
290 exit(0);
293// test O_TRUNC.
294void
297 char buf[32];
299 unlink("truncfile");
300 int fd1 = open("truncfile", O_CREATE | O_WRONLY | O_TRUNC);
301 write(fd1, "abcd", 4);
304 int fd2 = open("truncfile", O_RDONLY);
305 int n = read(fd2, buf, sizeof(buf));
306 if (n != 4) {
307 printf("%s: read %d bytes, wanted 4\n", s, n);
308 exit(1);
309 }
311 fd1 = open("truncfile", O_WRONLY | O_TRUNC);
313 int fd3 = open("truncfile", O_RDONLY);
314 n = read(fd3, buf, sizeof(buf));
315 if (n != 0) {
316 printf("aaa fd3=%d\n", fd3);
317 printf("%s: read %d bytes, wanted 0\n", s, n);
318 exit(1);
319 }
321 n = read(fd2, buf, sizeof(buf));
322 if (n != 0) {
323 printf("bbb fd2=%d\n", fd2);
324 printf("%s: read %d bytes, wanted 0\n", s, n);
325 exit(1);
326 }
328 write(fd1, "abcdef", 6);
330 n = read(fd3, buf, sizeof(buf));
331 if (n != 6) {
332 printf("%s: read %d bytes, wanted 6\n", s, n);
333 exit(1);
334 }
336 n = read(fd2, buf, sizeof(buf));
337 if (n != 2) {
338 printf("%s: read %d bytes, wanted 2\n", s, n);
339 exit(1);
340 }
342 unlink("truncfile");
349// write to an open FD whose file has just been truncated.
350// this causes a write at an offset beyond the end of the file.
351// such writes fail on xv6 (unlike POSIX) but at least
352// they don't crash.
353void
356 unlink("truncfile");
358 int fd1 = open("truncfile", O_CREATE | O_TRUNC | O_WRONLY);
359 write(fd1, "abcd", 4);
361 int fd2 = open("truncfile", O_TRUNC | O_WRONLY);
363 int n = write(fd1, "x", 1);
364 if (n != -1) {
365 printf("%s: write returned %d, expected -1\n", s, n);
366 exit(1);
367 }
369 unlink("truncfile");
374void
379 close(open("truncfile", O_CREATE | O_TRUNC | O_WRONLY));
381 pid = fork();
382 if (pid < 0) {
383 printf("%s: fork failed\n", s);
384 exit(1);
385 }
387 if (pid == 0) {
388 for (int i = 0; i < 100; i++) {
389 char buf[32];
390 int fd = open("truncfile", O_WRONLY);
391 if (fd < 0) {
392 printf("%s: open failed\n", s);
393 exit(1);
394 }
395 int n = write(fd, "1234567890", 10);
396 if (n != 10) {
397 printf("%s: write got %d, expected 10\n", s, n);
398 exit(1);
399 }
401 fd = open("truncfile", O_RDONLY);
402 read(fd, buf, sizeof(buf));
404 }
405 exit(0);
406 }
408 for (int i = 0; i < 150; i++) {
409 int fd = open("truncfile", O_CREATE | O_WRONLY | O_TRUNC);
410 if (fd < 0) {
411 printf("%s: open failed\n", s);
412 exit(1);
413 }
414 int n = write(fd, "xxx", 3);
415 if (n != 3) {
416 printf("%s: write got %d, expected 3\n", s, n);
417 exit(1);
418 }
420 }
423 unlink("truncfile");
427// does chdir() call iput(p->cwd) in a transaction?
428void
429iputtest(char *s)
431 if (mkdir("iputdir") < 0) {
432 printf("%s: mkdir failed\n", s);
433 exit(1);
434 }
435 if (chdir("iputdir") < 0) {
436 printf("%s: chdir iputdir failed\n", s);
437 exit(1);
438 }
439 if (unlink("../iputdir") < 0) {
440 printf("%s: unlink ../iputdir failed\n", s);
441 exit(1);
442 }
443 if (chdir("/") < 0) {
444 printf("%s: chdir / failed\n", s);
445 exit(1);
446 }
449// does exit() call iput(p->cwd) in a transaction?
450void
455 pid = fork();
456 if (pid < 0) {
457 printf("%s: fork failed\n", s);
458 exit(1);
459 }
460 if (pid == 0) {
461 if (mkdir("iputdir") < 0) {
462 printf("%s: mkdir failed\n", s);
463 exit(1);
464 }
465 if (chdir("iputdir") < 0) {
466 printf("%s: child chdir failed\n", s);
467 exit(1);
468 }
469 if (unlink("../iputdir") < 0) {
470 printf("%s: unlink ../iputdir failed\n", s);
471 exit(1);
472 }
473 exit(0);
474 }
479// does the error path in open() for attempt to write a
480// directory call iput() in a transaction?
481// needs a hacked kernel that pauses just after the namei()
482// call in sys_open():
483// if((ip = namei(path)) == 0)
484// return -1;
485// {
486// int i;
487// for(i = 0; i < 10000; i++)
488// yield();
489// }
490void
495 if (mkdir("oidir") < 0) {
496 printf("%s: mkdir oidir failed\n", s);
497 exit(1);
498 }
499 pid = fork();
500 if (pid < 0) {
501 printf("%s: fork failed\n", s);
502 exit(1);
503 }
504 if (pid == 0) {
505 int fd = open("oidir", O_RDWR);
506 if (fd >= 0) {
507 printf("%s: open directory for write succeeded\n", s);
508 exit(1);
509 }
510 exit(0);
511 }
513 if (unlink("oidir") != 0) {
514 printf("%s: unlink failed\n", s);
515 exit(1);
516 }
521// simple file system tests
523void
524opentest(char *s)
526 int fd;
528 fd = open("echo", 0);
529 if (fd < 0) {
530 printf("%s: open echo failed!\n", s);
531 exit(1);
532 }
534 fd = open("doesnotexist", 0);
535 if (fd >= 0) {
536 printf("%s: open doesnotexist succeeded!\n", s);
537 exit(1);
538 }
541void
544 int fd;
545 int i;
546 enum { N = 100, SZ = 10 };
548 fd = open("small", O_CREATE | O_RDWR);
549 if (fd < 0) {
550 printf("%s: error: creat small failed!\n", s);
551 exit(1);
552 }
553 for (i = 0; i < N; i++) {
554 if (write(fd, "aaaaaaaaaa", SZ) != SZ) {
555 printf("%s: error: write aa %d new file failed\n", s, i);
556 exit(1);
557 }
558 if (write(fd, "bbbbbbbbbb", SZ) != SZ) {
559 printf("%s: error: write bb %d new file failed\n", s, i);
560 exit(1);
561 }
562 }
564 fd = open("small", O_RDONLY);
565 if (fd < 0) {
566 printf("%s: error: open small failed!\n", s);
567 exit(1);
568 }
569 i = read(fd, buf, N * SZ * 2);
570 if (i != N * SZ * 2) {
571 printf("%s: read failed\n", s);
572 exit(1);
573 }
576 if (unlink("small") < 0) {
577 printf("%s: unlink small failed\n", s);
578 exit(1);
579 }
582void
583writebig(char *s)
585 int i, fd, n;
587 fd = open("big", O_CREATE | O_RDWR);
588 if (fd < 0) {
589 printf("%s: error: creat big failed!\n", s);
590 exit(1);
591 }
593 for (i = 0; i < MAXFILE; i++) {
594 ((int *)buf)[0] = i;
595 if (write(fd, buf, BSIZE) != BSIZE) {
596 printf("%s: error: write big file failed i=%d\n", s, i);
597 exit(1);
598 }
599 }
603 fd = open("big", O_RDONLY);
604 if (fd < 0) {
605 printf("%s: error: open big failed!\n", s);
606 exit(1);
607 }
609 n = 0;
610 for (;;) {
612 if (i == 0) {
613 if (n != MAXFILE) {
614 printf("%s: read only %d blocks from big", s, n);
615 exit(1);
616 }
617 break;
618 } else if (i != BSIZE) {
619 printf("%s: read failed %d\n", s, i);
620 exit(1);
621 }
622 if (((int *)buf)[0] != n) {
623 printf("%s: read content of block %d is %d\n", s, n, ((int *)buf)[0]);
624 exit(1);
625 }
626 n++;
627 }
629 if (unlink("big") < 0) {
630 printf("%s: unlink big failed\n", s);
631 exit(1);
632 }
635// many creates, followed by unlink test
636void
639 int i, fd;
640 enum { N = 52 };
642 char name[3];
643 name[0] = 'a';
644 name[2] = '\0';
645 for (i = 0; i < N; i++) {
646 name[1] = '0' + i;
649 }
650 name[0] = 'a';
651 name[2] = '\0';
652 for (i = 0; i < N; i++) {
653 name[1] = '0' + i;
655 }
658void
659dirtest(char *s)
661 if (mkdir("dir0") < 0) {
662 printf("%s: mkdir failed\n", s);
663 exit(1);
664 }
666 if (chdir("dir0") < 0) {
667 printf("%s: chdir dir0 failed\n", s);
668 exit(1);
669 }
671 if (chdir("..") < 0) {
672 printf("%s: chdir .. failed\n", s);
673 exit(1);
674 }
676 if (unlink("dir0") < 0) {
677 printf("%s: unlink dir0 failed\n", s);
678 exit(1);
679 }
682void
683exectest(char *s)
685 int fd, xstatus, pid;
686 char *echoargv[] = {"echo", "OK", 0};
687 char buf[3];
689 unlink("echo-ok");
690 pid = fork();
691 if (pid < 0) {
692 printf("%s: fork failed\n", s);
693 exit(1);
694 }
695 if (pid == 0) {
696 int errfd = dup(1);
697 if (errfd < 0) {
698 printf("%s: dup failed\n", s);
699 exit(1);
700 }
702 fd = open("echo-ok", O_CREATE | O_WRONLY);
703 if (fd < 0) {
704 fprintf(errfd, "%s: create failed\n", s);
705 exit(1);
706 }
707 if (fd != 1) {
708 fprintf(errfd, "%s: wrong fd\n", s);
709 exit(1);
710 }
711 if (exec("echo", echoargv) < 0) {
712 fprintf(errfd, "%s: exec echo failed\n", s);
713 exit(1);
714 }
715 // won't get to here
716 }
717 if (wait(&xstatus) != pid) {
718 printf("%s: wait failed!\n", s);
719 }
720 if (xstatus != 0) {
721 printf("%s: nonzero wait status %d\n", s, xstatus);
722 exit(1);
723 }
725 fd = open("echo-ok", O_RDONLY);
726 if (fd < 0) {
727 printf("%s: open failed\n", s);
728 exit(1);
729 }
730 if (read(fd, buf, 2) != 2) {
731 printf("%s: read failed\n", s);
732 exit(1);
733 }
734 unlink("echo-ok");
735 if (buf[0] == 'O' && buf[1] == 'K')
736 exit(0);
737 else {
738 printf("%s: wrong output\n", s);
739 exit(1);
740 }
743// simple fork and pipe read/write
745void
746pipe1(char *s)
748 int fds[2], pid, xstatus;
749 int seq, i, n, cc, total;
750 enum { N = 5, SZ = 1033 };
752 if (pipe(fds) != 0) {
753 printf("%s: pipe() failed\n", s);
754 exit(1);
755 }
756 pid = fork();
757 seq = 0;
758 if (pid == 0) {
760 for (n = 0; n < N; n++) {
761 for (i = 0; i < SZ; i++)
762 buf[i] = seq++;
763 if (write(fds[1], buf, SZ) != SZ) {
764 printf("%s: pipe1 oops 1\n", s);
765 exit(1);
766 }
767 }
768 exit(0);
769 } else if (pid > 0) {
771 total = 0;
772 cc = 1;
773 while ((n = read(fds[0], buf, cc)) > 0) {
774 for (i = 0; i < n; i++) {
775 if ((buf[i] & 0xff) != (seq++ & 0xff)) {
776 printf("%s: pipe1 oops 2\n", s);
777 return;
778 }
779 }
780 total += n;
781 cc = cc * 2;
782 if (cc > sizeof(buf))
783 cc = sizeof(buf);
784 }
785 if (total != N * SZ) {
786 printf("%s: pipe1 oops 3 total %d\n", s, total);
787 exit(1);
788 }
792 } else {
793 printf("%s: fork() failed\n", s);
794 exit(1);
795 }
798// test if child is killed (status = -1)
799void
802 int xst;
804 for (int i = 0; i < 100; i++) {
805 int pid1 = fork();
806 if (pid1 < 0) {
807 printf("%s: fork failed\n", s);
808 exit(1);
809 }
810 if (pid1 == 0) {
811 while (1) {
813 }
814 exit(0);
815 }
819 if (xst != -1) {
820 printf("%s: status should be -1\n", s);
821 exit(1);
822 }
823 }
824 exit(0);
827// test that kill on unused process 0 doesn't set the killed flag
828void
829killzero(char *s)
831 int pid, xst;
833 kill(0);
835 pid = fork();
836 if (pid < 0) {
837 printf("%s: fork failed\n", s);
838 exit(1);
839 }
840 if (pid == 0) {
841 exit(7);
842 }
843 if (wait(&xst) != pid) {
844 printf("%s: wait wrong pid\n", s);
845 exit(1);
846 }
847 if (xst != 7) {
848 printf("%s: child exited with status %d, expected 7\n", s, xst);
849 exit(1);
850 }
851 exit(0);
854// meant to be run w/ at most two CPUs
855void
856preempt(char *s)
858 int pid1, pid2, pid3;
859 int pfds[2];
862 if (pid1 < 0) {
863 printf("%s: fork failed", s);
864 exit(1);
865 }
866 if (pid1 == 0)
867 for (;;)
868 ;
871 if (pid2 < 0) {
872 printf("%s: fork failed\n", s);
873 exit(1);
874 }
875 if (pid2 == 0)
876 for (;;)
877 ;
881 if (pid3 < 0) {
882 printf("%s: fork failed\n", s);
883 exit(1);
884 }
885 if (pid3 == 0) {
887 if (write(pfds[1], "x", 1) != 1)
888 printf("%s: preempt write error", s);
890 for (;;)
891 ;
892 }
895 if (read(pfds[0], buf, sizeof(buf)) != 1) {
896 printf("%s: preempt read error", s);
897 return;
898 }
900 printf("kill... ");
904 printf("wait... ");
905 wait(0);
906 wait(0);
907 wait(0);
910// try to find any races between exit and wait
911void
912exitwait(char *s)
914 int i, pid;
916 for (i = 0; i < 100; i++) {
917 pid = fork();
918 if (pid < 0) {
919 printf("%s: fork failed\n", s);
920 exit(1);
921 }
922 if (pid) {
923 int xstate;
924 if (wait(&xstate) != pid) {
925 printf("%s: wait wrong pid\n", s);
926 exit(1);
927 }
928 if (i != xstate) {
929 printf("%s: wait wrong exit status\n", s);
930 exit(1);
931 }
932 } else {
934 }
935 }
938// try to find races in the reparenting
939// code that handles a parent exiting
940// when it still has live children.
941void
942reparent(char *s)
945 for (int i = 0; i < 200; i++) {
946 int pid = fork();
947 if (pid < 0) {
948 printf("%s: fork failed\n", s);
949 exit(1);
950 }
951 if (pid) {
952 if (wait(0) != pid) {
953 printf("%s: wait wrong pid\n", s);
954 exit(1);
955 }
956 } else {
957 int pid2 = fork();
958 if (pid2 < 0) {
960 exit(1);
961 }
962 exit(0);
963 }
964 }
965 exit(0);
968// what if two children exit() at the same time?
969void
972 for (int i = 0; i < 1000; i++) {
973 int pid1 = fork();
974 if (pid1 < 0) {
975 printf("%s: fork failed\n", s);
976 exit(1);
977 }
978 if (pid1 == 0) {
979 exit(0);
980 } else {
981 int pid2 = fork();
982 if (pid2 < 0) {
983 printf("%s: fork failed\n", s);
984 exit(1);
985 }
986 if (pid2 == 0) {
987 exit(0);
988 } else {
989 wait(0);
990 wait(0);
991 }
992 }
993 }
996// concurrent forks to try to expose locking bugs.
997void
998forkfork(char *s)
1000 enum { N = 2 };
1002 for (int i = 0; i < N; i++) {
1003 int pid = fork();
1004 if (pid < 0) {
1005 printf("%s: fork failed", s);
1008 if (pid == 0) {
1009 for (int j = 0; j < 200; j++) {
1010 int pid1 = fork();
1011 if (pid1 < 0) {
1014 if (pid1 == 0) {
1024 for (int i = 0; i < N; i++) {
1026 if (xstatus != 0) {
1027 printf("%s: fork in child failed", s);
1033void
1036 unlink("stopforking");
1038 int pid = fork();
1039 if (pid < 0) {
1040 printf("%s: fork failed", s);
1043 if (pid == 0) {
1044 while (1) {
1045 int fd = open("stopforking", 0);
1046 if (fd >= 0) {
1049 if (fork() < 0) {
1050 close(open("stopforking", O_CREATE | O_RDWR));
1057 pause(20); // two seconds
1058 close(open("stopforking", O_CREATE | O_RDWR));
1060 pause(10); // one second
1063// regression test. does reparent() violate the parent-then-child
1064// locking order when giving away a child to init, so that exit()
1065// deadlocks against init's wait()? also used to trigger a "panic:
1066// release" due to exit() releasing a different p->parent->lock than
1067// it acquired.
1068void
1071 for (int i = 0; i < 800; i++) {
1072 int pid1 = fork();
1073 if (pid1 < 0) {
1074 printf("fork failed\n");
1077 if (pid1 == 0) {
1088// allocate all mem, free it, and allocate again
1089void
1090mem(char *s)
1092 void *m1, *m2;
1093 int pid;
1095 if ((pid = fork()) == 0) {
1096 m1 = 0;
1097 while ((m2 = malloc(10001)) != 0) {
1098 *(char **)m2 = m1;
1101 while (m1) {
1102 m2 = *(char **)m1;
1106 m1 = malloc(1024 * 20);
1107 if (m1 == 0) {
1108 printf("%s: couldn't allocate mem?!!\n", s);
1113 } else {
1116 if (xstatus == -1) {
1117 // probably page fault, so might be lazy lab,
1118 // so OK.
1125// More file system tests
1127// two processes write to the same file descriptor
1128// is the offset shared? does inode locking work?
1129void
1132 int fd, pid, i, n, nc, np;
1133 enum { N = 1000, SZ = 10 };
1134 char buf[SZ];
1136 unlink("sharedfd");
1137 fd = open("sharedfd", O_CREATE | O_RDWR);
1138 if (fd < 0) {
1139 printf("%s: cannot open sharedfd for writing", s);
1143 memset(buf, pid == 0 ? 'c' : 'p', sizeof(buf));
1144 for (i = 0; i < N; i++) {
1145 if (write(fd, buf, sizeof(buf)) != sizeof(buf)) {
1146 printf("%s: write sharedfd failed\n", s);
1150 if (pid == 0) {
1152 } else {
1155 if (xstatus != 0)
1160 fd = open("sharedfd", 0);
1161 if (fd < 0) {
1162 printf("%s: cannot open sharedfd for reading\n", s);
1165 nc = np = 0;
1166 while ((n = read(fd, buf, sizeof(buf))) > 0) {
1167 for (i = 0; i < sizeof(buf); i++) {
1168 if (buf[i] == 'c')
1169 nc++;
1170 if (buf[i] == 'p')
1171 np++;
1175 unlink("sharedfd");
1176 if (nc == N * SZ && np == N * SZ) {
1178 } else {
1179 printf("%s: nc/np test fails\n", s);
1184// four processes write different files at the same
1185// time, to test block allocation.
1186void
1189 int fd, pid, i, j, n, total, pi;
1190 char *names[] = {"f0", "f1", "f2", "f3"};
1191 char *fname;
1192 enum { N = 12, NCHILD = 4, SZ = 500 };
1194 for (pi = 0; pi < NCHILD; pi++) {
1199 if (pid < 0) {
1200 printf("%s: fork failed\n", s);
1204 if (pid == 0) {
1206 if (fd < 0) {
1207 printf("%s: create failed\n", s);
1211 memset(buf, '0' + pi, SZ);
1212 for (i = 0; i < N; i++) {
1213 if ((n = write(fd, buf, SZ)) != SZ) {
1214 printf("write failed %d\n", n);
1223 for (pi = 0; pi < NCHILD; pi++) {
1225 if (xstatus != 0)
1229 for (i = 0; i < NCHILD; i++) {
1231 fd = open(fname, 0);
1232 total = 0;
1233 while ((n = read(fd, buf, sizeof(buf))) > 0) {
1234 for (j = 0; j < n; j++) {
1235 if (buf[j] != '0' + i) {
1236 printf("%s: wrong char\n", s);
1243 if (total != N * SZ) {
1244 printf("wrong length %d\n", total);
1251// four processes create and delete different files in same directory
1252void
1255 enum { N = 20, NCHILD = 4 };
1256 int pid, i, fd, pi;
1257 char name[32];
1259 for (pi = 0; pi < NCHILD; pi++) {
1261 if (pid < 0) {
1262 printf("%s: fork failed\n", s);
1266 if (pid == 0) {
1267 name[0] = 'p' + pi;
1268 name[2] = '\0';
1269 for (i = 0; i < N; i++) {
1270 name[1] = '0' + i;
1272 if (fd < 0) {
1273 printf("%s: create failed\n", s);
1277 if (i > 0 && (i % 2) == 0) {
1278 name[1] = '0' + (i / 2);
1279 if (unlink(name) < 0) {
1280 printf("%s: unlink failed\n", s);
1290 for (pi = 0; pi < NCHILD; pi++) {
1292 if (xstatus != 0)
1296 name[0] = name[1] = name[2] = 0;
1297 for (i = 0; i < N; i++) {
1298 for (pi = 0; pi < NCHILD; pi++) {
1299 name[0] = 'p' + pi;
1300 name[1] = '0' + i;
1301 fd = open(name, 0);
1302 if ((i == 0 || i >= N / 2) && fd < 0) {
1303 printf("%s: oops createdelete %s didn't exist\n", s, name);
1305 } else if ((i >= 1 && i < N / 2) && fd >= 0) {
1306 printf("%s: oops createdelete %s did exist\n", s, name);
1309 if (fd >= 0)
1314 for (i = 0; i < N; i++) {
1315 for (pi = 0; pi < NCHILD; pi++) {
1316 name[0] = 'p' + pi;
1317 name[1] = '0' + i;
1323// can I unlink a file and still read it?
1324void
1327 enum { SZ = 5 };
1328 int fd, fd1;
1330 fd = open("unlinkread", O_CREATE | O_RDWR);
1331 if (fd < 0) {
1332 printf("%s: create unlinkread failed\n", s);
1335 write(fd, "hello", SZ);
1338 fd = open("unlinkread", O_RDWR);
1339 if (fd < 0) {
1340 printf("%s: open unlinkread failed\n", s);
1343 if (unlink("unlinkread") != 0) {
1344 printf("%s: unlink unlinkread failed\n", s);
1348 fd1 = open("unlinkread", O_CREATE | O_RDWR);
1349 write(fd1, "yyy", 3);
1352 if (read(fd, buf, sizeof(buf)) != SZ) {
1353 printf("%s: unlinkread read failed", s);
1356 if (buf[0] != 'h') {
1357 printf("%s: unlinkread wrong data\n", s);
1360 if (write(fd, buf, 10) != 10) {
1361 printf("%s: unlinkread write failed\n", s);
1365 unlink("unlinkread");
1368void
1371 enum { SZ = 5 };
1372 int fd;
1374 unlink("lf1");
1375 unlink("lf2");
1377 fd = open("lf1", O_CREATE | O_RDWR);
1378 if (fd < 0) {
1379 printf("%s: create lf1 failed\n", s);
1382 if (write(fd, "hello", SZ) != SZ) {
1383 printf("%s: write lf1 failed\n", s);
1388 if (link("lf1", "lf2") < 0) {
1389 printf("%s: link lf1 lf2 failed\n", s);
1392 unlink("lf1");
1394 if (open("lf1", 0) >= 0) {
1395 printf("%s: unlinked lf1 but it is still there!\n", s);
1399 fd = open("lf2", 0);
1400 if (fd < 0) {
1401 printf("%s: open lf2 failed\n", s);
1404 if (read(fd, buf, sizeof(buf)) != SZ) {
1405 printf("%s: read lf2 failed\n", s);
1410 if (link("lf2", "lf2") >= 0) {
1411 printf("%s: link lf2 lf2 succeeded! oops\n", s);
1415 unlink("lf2");
1416 if (link("lf2", "lf1") >= 0) {
1417 printf("%s: link non-existent succeeded! oops\n", s);
1421 if (link(".", "lf1") >= 0) {
1422 printf("%s: link . lf1 succeeded! oops\n", s);
1427// test concurrent create/link/unlink of the same file
1428void
1431 enum { N = 40 };
1432 char file[3];
1433 int i, pid, n, fd;
1434 char fa[N];
1435 struct {
1438 } de;
1440 file[0] = 'C';
1441 file[2] = '\0';
1442 for (i = 0; i < N; i++) {
1443 file[1] = '0' + i;
1446 if (pid && (i % 3) == 1) {
1447 link("C0", file);
1448 } else if (pid == 0 && (i % 5) == 1) {
1449 link("C0", file);
1450 } else {
1452 if (fd < 0) {
1453 printf("concreate create %s failed\n", file);
1458 if (pid == 0) {
1460 } else {
1463 if (xstatus != 0)
1468 memset(fa, 0, sizeof(fa));
1469 fd = open(".", 0);
1470 n = 0;
1471 while (read(fd, &de, sizeof(de)) > 0) {
1472 if (de.inum == 0)
1473 continue;
1474 if (de.name[0] == 'C' && de.name[2] == '\0') {
1475 i = de.name[1] - '0';
1476 if (i < 0 || i >= sizeof(fa)) {
1477 printf("%s: concreate weird file %s\n", s, de.name);
1480 if (fa[i]) {
1481 printf("%s: concreate duplicate file %s\n", s, de.name);
1484 fa[i] = 1;
1485 n++;
1490 if (n != N) {
1491 printf("%s: concreate not enough files in directory listing\n", s);
1495 for (i = 0; i < N; i++) {
1496 file[1] = '0' + i;
1498 if (pid < 0) {
1499 printf("%s: fork failed\n", s);
1502 if (((i % 3) == 0 && pid == 0) || ((i % 3) == 1 && pid != 0)) {
1509 } else {
1517 if (pid == 0)
1519 else
1524// another concurrent link/unlink/create test,
1525// to look for deadlocks.
1526void
1529 int pid, i;
1531 unlink("x");
1533 if (pid < 0) {
1534 printf("%s: fork failed\n", s);
1538 unsigned int x = (pid ? 1 : 97);
1539 for (i = 0; i < 100; i++) {
1540 x = x * 1103515245 + 12345;
1541 if ((x % 3) == 0) {
1543 } else if ((x % 3) == 1) {
1544 link("cat", "x");
1545 } else {
1546 unlink("x");
1550 if (pid)
1552 else
1556void
1557subdir(char *s)
1559 int fd, cc;
1561 unlink("ff");
1562 if (mkdir("dd") != 0) {
1563 printf("%s: mkdir dd failed\n", s);
1567 fd = open("dd/ff", O_CREATE | O_RDWR);
1568 if (fd < 0) {
1569 printf("%s: create dd/ff failed\n", s);
1572 write(fd, "ff", 2);
1575 if (unlink("dd") >= 0) {
1576 printf("%s: unlink dd (non-empty dir) succeeded!\n", s);
1580 if (mkdir("/dd/dd") != 0) {
1581 printf("%s: subdir mkdir dd/dd failed\n", s);
1585 fd = open("dd/dd/ff", O_CREATE | O_RDWR);
1586 if (fd < 0) {
1587 printf("%s: create dd/dd/ff failed\n", s);
1590 write(fd, "FF", 2);
1593 fd = open("dd/dd/../ff", 0);
1594 if (fd < 0) {
1595 printf("%s: open dd/dd/../ff failed\n", s);
1598 cc = read(fd, buf, sizeof(buf));
1599 if (cc != 2 || buf[0] != 'f') {
1600 printf("%s: dd/dd/../ff wrong content\n", s);
1605 if (link("dd/dd/ff", "dd/dd/ffff") != 0) {
1606 printf("%s: link dd/dd/ff dd/dd/ffff failed\n", s);
1610 if (unlink("dd/dd/ff") != 0) {
1611 printf("%s: unlink dd/dd/ff failed\n", s);
1614 if (open("dd/dd/ff", O_RDONLY) >= 0) {
1615 printf("%s: open (unlinked) dd/dd/ff succeeded\n", s);
1619 if (chdir("dd") != 0) {
1620 printf("%s: chdir dd failed\n", s);
1623 if (chdir("dd/../../dd") != 0) {
1624 printf("%s: chdir dd/../../dd failed\n", s);
1627 if (chdir("dd/../../../dd") != 0) {
1628 printf("%s: chdir dd/../../../dd failed\n", s);
1631 if (chdir("./..") != 0) {
1632 printf("%s: chdir ./.. failed\n", s);
1636 fd = open("dd/dd/ffff", 0);
1637 if (fd < 0) {
1638 printf("%s: open dd/dd/ffff failed\n", s);
1641 if (read(fd, buf, sizeof(buf)) != 2) {
1642 printf("%s: read dd/dd/ffff wrong len\n", s);
1647 if (open("dd/dd/ff", O_RDONLY) >= 0) {
1648 printf("%s: open (unlinked) dd/dd/ff succeeded!\n", s);
1652 if (open("dd/ff/ff", O_CREATE | O_RDWR) >= 0) {
1653 printf("%s: create dd/ff/ff succeeded!\n", s);
1656 if (open("dd/xx/ff", O_CREATE | O_RDWR) >= 0) {
1657 printf("%s: create dd/xx/ff succeeded!\n", s);
1660 if (open("dd", O_CREATE) >= 0) {
1661 printf("%s: create dd succeeded!\n", s);
1664 if (open("dd", O_RDWR) >= 0) {
1665 printf("%s: open dd rdwr succeeded!\n", s);
1668 if (open("dd", O_WRONLY) >= 0) {
1669 printf("%s: open dd wronly succeeded!\n", s);
1672 if (link("dd/ff/ff", "dd/dd/xx") == 0) {
1673 printf("%s: link dd/ff/ff dd/dd/xx succeeded!\n", s);
1676 if (link("dd/xx/ff", "dd/dd/xx") == 0) {
1677 printf("%s: link dd/xx/ff dd/dd/xx succeeded!\n", s);
1680 if (link("dd/ff", "dd/dd/ffff") == 0) {
1681 printf("%s: link dd/ff dd/dd/ffff succeeded!\n", s);
1684 if (mkdir("dd/ff/ff") == 0) {
1685 printf("%s: mkdir dd/ff/ff succeeded!\n", s);
1688 if (mkdir("dd/xx/ff") == 0) {
1689 printf("%s: mkdir dd/xx/ff succeeded!\n", s);
1692 if (mkdir("dd/dd/ffff") == 0) {
1693 printf("%s: mkdir dd/dd/ffff succeeded!\n", s);
1696 if (unlink("dd/xx/ff") == 0) {
1697 printf("%s: unlink dd/xx/ff succeeded!\n", s);
1700 if (unlink("dd/ff/ff") == 0) {
1701 printf("%s: unlink dd/ff/ff succeeded!\n", s);
1704 if (chdir("dd/ff") == 0) {
1705 printf("%s: chdir dd/ff succeeded!\n", s);
1708 if (chdir("dd/xx") == 0) {
1709 printf("%s: chdir dd/xx succeeded!\n", s);
1713 if (unlink("dd/dd/ffff") != 0) {
1714 printf("%s: unlink dd/dd/ff failed\n", s);
1717 if (unlink("dd/ff") != 0) {
1718 printf("%s: unlink dd/ff failed\n", s);
1721 if (unlink("dd") == 0) {
1722 printf("%s: unlink non-empty dd succeeded!\n", s);
1725 if (unlink("dd/dd") < 0) {
1726 printf("%s: unlink dd/dd failed\n", s);
1729 if (unlink("dd") < 0) {
1730 printf("%s: unlink dd failed\n", s);
1735// test writes that are larger than the log.
1736void
1739 int fd, sz;
1741 unlink("bigwrite");
1742 for (sz = 499; sz < (MAXOPBLOCKS + 2) * BSIZE; sz += 471) {
1743 fd = open("bigwrite", O_CREATE | O_RDWR);
1744 if (fd < 0) {
1745 printf("%s: cannot create bigwrite\n", s);
1748 int i;
1749 for (i = 0; i < 2; i++) {
1750 int cc = write(fd, buf, sz);
1751 if (cc != sz) {
1752 printf("%s: write(%d) ret %d\n", s, sz, cc);
1757 unlink("bigwrite");
1761void
1762bigfile(char *s)
1764 enum { N = 20, SZ = 600 };
1765 int fd, i, total, cc;
1767 unlink("bigfile.dat");
1768 fd = open("bigfile.dat", O_CREATE | O_RDWR);
1769 if (fd < 0) {
1770 printf("%s: cannot create bigfile", s);
1773 for (i = 0; i < N; i++) {
1775 if (write(fd, buf, SZ) != SZ) {
1776 printf("%s: write bigfile failed\n", s);
1782 fd = open("bigfile.dat", 0);
1783 if (fd < 0) {
1784 printf("%s: cannot open bigfile\n", s);
1787 total = 0;
1788 for (i = 0;; i++) {
1789 cc = read(fd, buf, SZ / 2);
1790 if (cc < 0) {
1791 printf("%s: read bigfile failed\n", s);
1794 if (cc == 0)
1795 break;
1796 if (cc != SZ / 2) {
1797 printf("%s: short read bigfile\n", s);
1800 if (buf[0] != i / 2 || buf[SZ / 2 - 1] != i / 2) {
1801 printf("%s: read bigfile wrong data\n", s);
1807 if (total != N * SZ) {
1808 printf("%s: read bigfile wrong total\n", s);
1811 unlink("bigfile.dat");
1814void
1817 int fd;
1819 // DIRSIZ is 14.
1821 if (mkdir("12345678901234") != 0) {
1822 printf("%s: mkdir 12345678901234 failed\n", s);
1825 if (mkdir("12345678901234/123456789012345") != 0) {
1826 printf("%s: mkdir 12345678901234/123456789012345 failed\n", s);
1829 fd = open("123456789012345/123456789012345/123456789012345", O_CREATE);
1830 if (fd < 0) {
1832 "%s: create 123456789012345/123456789012345/123456789012345 failed\n", s);
1836 fd = open("12345678901234/12345678901234/12345678901234", 0);
1837 if (fd < 0) {
1838 printf("%s: open 12345678901234/12345678901234/12345678901234 failed\n", s);
1843 if (mkdir("12345678901234/12345678901234") == 0) {
1844 printf("%s: mkdir 12345678901234/12345678901234 succeeded!\n", s);
1847 if (mkdir("123456789012345/12345678901234") == 0) {
1848 printf("%s: mkdir 12345678901234/123456789012345 succeeded!\n", s);
1852 // clean up
1853 unlink("123456789012345/12345678901234");
1854 unlink("12345678901234/12345678901234");
1855 unlink("12345678901234/12345678901234/12345678901234");
1856 unlink("123456789012345/123456789012345/123456789012345");
1857 unlink("12345678901234/123456789012345");
1858 unlink("12345678901234");
1861void
1862rmdot(char *s)
1864 if (mkdir("dots") != 0) {
1865 printf("%s: mkdir dots failed\n", s);
1868 if (chdir("dots") != 0) {
1869 printf("%s: chdir dots failed\n", s);
1872 if (unlink(".") == 0) {
1873 printf("%s: rm . worked!\n", s);
1876 if (unlink("..") == 0) {
1877 printf("%s: rm .. worked!\n", s);
1880 if (chdir("/") != 0) {
1881 printf("%s: chdir / failed\n", s);
1884 if (unlink("dots/.") == 0) {
1885 printf("%s: unlink dots/. worked!\n", s);
1888 if (unlink("dots/..") == 0) {
1889 printf("%s: unlink dots/.. worked!\n", s);
1892 if (unlink("dots") != 0) {
1893 printf("%s: unlink dots failed!\n", s);
1898void
1899dirfile(char *s)
1901 int fd;
1903 fd = open("dirfile", O_CREATE);
1904 if (fd < 0) {
1905 printf("%s: create dirfile failed\n", s);
1909 if (chdir("dirfile") == 0) {
1910 printf("%s: chdir dirfile succeeded!\n", s);
1913 fd = open("dirfile/xx", 0);
1914 if (fd >= 0) {
1915 printf("%s: create dirfile/xx succeeded!\n", s);
1918 fd = open("dirfile/xx", O_CREATE);
1919 if (fd >= 0) {
1920 printf("%s: create dirfile/xx succeeded!\n", s);
1923 if (mkdir("dirfile/xx") == 0) {
1924 printf("%s: mkdir dirfile/xx succeeded!\n", s);
1927 if (unlink("dirfile/xx") == 0) {
1928 printf("%s: unlink dirfile/xx succeeded!\n", s);
1931 if (link("README", "dirfile/xx") == 0) {
1932 printf("%s: link to dirfile/xx succeeded!\n", s);
1935 if (unlink("dirfile") != 0) {
1936 printf("%s: unlink dirfile failed!\n", s);
1940 fd = open(".", O_RDWR);
1941 if (fd >= 0) {
1942 printf("%s: open . for writing succeeded!\n", s);
1945 fd = open(".", 0);
1946 if (write(fd, "x", 1) > 0) {
1947 printf("%s: write . succeeded!\n", s);
1953// test that iput() is called at the end of _namei().
1954// also tests empty file names.
1955void
1956iref(char *s)
1958 int i, fd;
1960 for (i = 0; i < NINODE + 1; i++) {
1961 if (mkdir("irefd") != 0) {
1962 printf("%s: mkdir irefd failed\n", s);
1965 if (chdir("irefd") != 0) {
1966 printf("%s: chdir irefd failed\n", s);
1970 mkdir("");
1971 link("README", "");
1973 if (fd >= 0)
1975 fd = open("xx", O_CREATE);
1976 if (fd >= 0)
1978 unlink("xx");
1981 // clean up
1982 for (i = 0; i < NINODE + 1; i++) {
1983 chdir("..");
1984 unlink("irefd");
1987 chdir("/");
1990// test that fork fails gracefully
1991// the forktest binary also does this, but it runs out of proc entries first.
1992// inside the bigger usertests binary, we run out of memory first.
1993void
1996 enum { N = 1000 };
1997 int n, pid;
1999 for (n = 0; n < N; n++) {
2001 if (pid < 0)
2002 break;
2003 if (pid == 0)
2007 if (n == 0) {
2008 printf("%s: no fork at all!\n", s);
2012 if (n == N) {
2013 printf("%s: fork claimed to work 1000 times!\n", s);
2017 for (; n > 0; n--) {
2018 if (wait(0) < 0) {
2019 printf("%s: wait stopped early\n", s);
2024 if (wait(0) != -1) {
2025 printf("%s: wait got too many\n", s);
2030void
2033 enum { TOOMUCH = 1024 * 1024 * 1024 };
2034 int i, pid, xstatus;
2035 char *c, *a, *b;
2037 // does sbrk() return the expected failure value?
2039 if (pid < 0) {
2040 printf("fork failed in sbrkbasic\n");
2043 if (pid == 0) {
2045 if (a == (char *)SBRK_ERROR) {
2046 // it's OK if this fails.
2050 for (b = a; b < a + TOOMUCH; b += PGSIZE) {
2051 *b = 99;
2054 // we should not get here! either sbrk(TOOMUCH)
2055 // should have failed, or (with lazy allocation)
2056 // a pagefault should have killed this process.
2061 if (xstatus == 1) {
2062 printf("%s: too much memory allocated!\n", s);
2066 // can one sbrk() less than a page?
2067 a = sbrk(0);
2068 for (i = 0; i < 5000; i++) {
2069 b = sbrk(1);
2070 if (b != a) {
2071 printf("%s: sbrk test failed %d %p %p\n", s, i, a, b);
2074 *b = 1;
2075 a = b + 1;
2078 if (pid < 0) {
2079 printf("%s: sbrk test fork failed\n", s);
2082 c = sbrk(1);
2083 c = sbrk(1);
2084 if (c != a + 1) {
2085 printf("%s: sbrk test failed post-fork\n", s);
2088 if (pid == 0)
2094void
2097 enum { BIG = 100 * 1024 * 1024 };
2098 char *c, *oldbrk, *a, *lastaddr, *p;
2103 // can one grow address space to something big?
2104 a = sbrk(0);
2107 if (p != a) {
2108 printf("%s: sbrk test failed to grow big address space; enough phys mem?\n",
2113 lastaddr = (char *)(BIG - 1);
2114 *lastaddr = 99;
2116 // can one de-allocate?
2117 a = sbrk(0);
2119 if (c == (char *)SBRK_ERROR) {
2120 printf("%s: sbrk could not deallocate\n", s);
2123 c = sbrk(0);
2124 if (c != a - PGSIZE) {
2125 printf("%s: sbrk deallocation produced wrong address, a %p c %p\n", s, a,
2130 // can one re-allocate that page?
2131 a = sbrk(0);
2133 if (c != a || sbrk(0) != a + PGSIZE) {
2134 printf("%s: sbrk re-allocation failed, a %p c %p\n", s, a, c);
2137 if (*lastaddr == 99) {
2138 // should be zero
2139 printf("%s: sbrk de-allocation didn't really deallocate\n", s);
2143 a = sbrk(0);
2144 c = sbrk(-(sbrk(0) - oldbrk));
2145 if (c != a) {
2146 printf("%s: sbrk downsize failed, a %p c %p\n", s, a, c);
2151// can we read the kernel's memory?
2152void
2153kernmem(char *s)
2155 char *a;
2156 int pid;
2158 for (a = (char *)(KERNBASE); a < (char *)(KERNBASE + 2000000); a += 50000) {
2160 if (pid < 0) {
2161 printf("%s: fork failed\n", s);
2164 if (pid == 0) {
2165 printf("%s: oops could read %p = %x\n", s, a, *a);
2170 if (xstatus != -1) // did kernel kill child?
2175// user code should not be able to write to addresses above MAXVA.
2176void
2179 volatile uint64 a = MAXVA;
2180 for (; a != 0; a <<= 1) {
2181 int pid;
2183 if (pid < 0) {
2184 printf("%s: fork failed\n", s);
2187 if (pid == 0) {
2188 *(char *)a = 99;
2189 printf("%s: oops wrote %p\n", s, (void *)a);
2194 if (xstatus != -1) // did kernel kill child?
2199// if we run the system out of memory, does it clean up the last
2200// failed allocation?
2201void
2204 enum { BIG = 100 * 1024 * 1024 };
2205 int i, xstatus;
2206 int fds[2];
2208 char *c, *a;
2209 int pids[10];
2210 int pid;
2214 if (pipe(fds) != 0) {
2215 printf("%s: pipe() failed\n", s);
2218 for (i = 0; i < sizeof(pids) / sizeof(pids[0]); i++) {
2219 if ((pids[i] = fork()) == 0) {
2220 // allocate a lot of memory
2221 if (sbrk(BIG - (uint64)sbrk(0)) == (char *)SBRK_ERROR)
2222 write(fds[1], "0", 1);
2223 else
2224 write(fds[1], "1", 1);
2225 // sit around until killed
2226 for (;;)
2227 pause(1000);
2229 if (pids[i] != -1) {
2230 read(fds[0], &scratch, 1);
2231 if (scratch == '0')
2235 if (!failed) {
2236 printf("%s: no allocation failed; allocate more?\n", s);
2239 // if those failed allocations freed up the pages they did allocate,
2240 // we'll be able to allocate here
2242 for (i = 0; i < sizeof(pids) / sizeof(pids[0]); i++) {
2243 if (pids[i] == -1)
2244 continue;
2248 if (c == (char *)SBRK_ERROR) {
2249 printf("%s: failed sbrk leaked memory\n", s);
2253 // test running fork with the above allocated page
2255 if (pid < 0) {
2256 printf("%s: fork failed\n", s);
2259 if (pid == 0) {
2260 // allocate a lot of memory. this should produce an error
2261 a = sbrk(10 * BIG);
2262 if (a == (char *)SBRK_ERROR) {
2265 printf("%s: allocate a lot of memory succeeded %d\n", s, 10 * BIG);
2269 if (xstatus != 0)
2273// test reads/writes from/to allocated memory
2274void
2275sbrkarg(char *s)
2277 char *a;
2278 int fd, n;
2281 fd = open("sbrk", O_CREATE | O_WRONLY);
2282 unlink("sbrk");
2283 if (fd < 0) {
2284 printf("%s: open sbrk failed\n", s);
2287 if ((n = write(fd, a, PGSIZE)) < 0) {
2288 printf("%s: write sbrk failed\n", s);
2293 // test writes to allocated memory
2295 if (pipe((int *)a) != 0) {
2296 printf("%s: pipe() failed\n", s);
2301void
2304 int hi;
2307 hi = 1100 * 1024;
2308 for (p = 0; p <= (uint)hi; p += PGSIZE) {
2309 // try to crash the kernel by passing in a bad string pointer
2310 if (link("nosuchfile", (char *)p) != -1) {
2311 printf("%s: link should not succeed\n", s);
2317// does uninitialized data start out zero?
2318char uninit[10000];
2319void
2320bsstest(char *s)
2322 int i;
2324 for (i = 0; i < sizeof(uninit); i++) {
2325 if (uninit[i] != '\0') {
2326 printf("%s: bss test failed\n", s);
2332// does exec return an error if the arguments
2333// are larger than a page? or does it write
2334// below the stack and wreck the instructions/data?
2335void
2340 unlink("bigarg-ok");
2342 if (pid == 0) {
2343 static char *args[MAXARG];
2344 int i;
2345 char big[400];
2346 memset(big, ' ', sizeof(big));
2347 big[sizeof(big) - 1] = '\0';
2348 for (i = 0; i < MAXARG - 1; i++)
2350 args[MAXARG - 1] = 0;
2351 // this exec() should fail (and return) because the
2352 // arguments are too large.
2353 exec("echo", args);
2354 fd = open("bigarg-ok", O_CREATE);
2357 } else if (pid < 0) {
2358 printf("%s: bigargtest: fork failed\n", s);
2363 if (xstatus != 0)
2365 fd = open("bigarg-ok", 0);
2366 if (fd < 0) {
2367 printf("%s: bigarg test failed!\n", s);
2373// what happens when the file system runs out of blocks?
2374// answer: balloc panics, so this test is not useful.
2375void
2379 int fsblocks = 0;
2381 printf("fsfull test\n");
2383 for (nfiles = 0;; nfiles++) {
2384 char name[64];
2385 name[0] = 'f';
2386 name[1] = '0' + nfiles / 1000;
2387 name[2] = '0' + (nfiles % 1000) / 100;
2388 name[3] = '0' + (nfiles % 100) / 10;
2389 name[4] = '0' + (nfiles % 10);
2390 name[5] = '\0';
2391 printf("writing %s\n", name);
2393 if (fd < 0) {
2394 printf("open %s failed\n", name);
2395 break;
2397 int total = 0;
2398 while (1) {
2399 int cc = write(fd, buf, BSIZE);
2400 if (cc < BSIZE)
2401 break;
2405 printf("wrote %d bytes\n", total);
2407 if (total == 0)
2408 break;
2411 while (nfiles >= 0) {
2412 char name[64];
2413 name[0] = 'f';
2414 name[1] = '0' + nfiles / 1000;
2415 name[2] = '0' + (nfiles % 1000) / 100;
2416 name[3] = '0' + (nfiles % 100) / 10;
2417 name[4] = '0' + (nfiles % 10);
2418 name[5] = '\0';
2423 printf("fsfull test finished, %d blocks\n", fsblocks);
2426void
2429 int fd;
2430 fd = open("init", O_RDONLY);
2431 if (fd < 0) {
2432 printf("%s: open failed\n", s);
2435 read(fd, sbrk(0) - 1, -1);
2439// check that there's an invalid page beneath
2440// the user stack, to catch stack overflow.
2441void
2444 int pid;
2448 if (pid == 0) {
2449 char *sp = (char *)r_sp();
2451 // the *sp should cause a trap.
2452 printf("%s: stacktest: read below stack %d\n", s, *sp);
2454 } else if (pid < 0) {
2455 printf("%s: fork failed\n", s);
2459 if (xstatus == -1) // kernel killed child?
2461 else
2465// check that writes to a few forbidden addresses
2466// cause a fault, e.g. process's text and TRAMPOLINE.
2467void
2468nowrite(char *s)
2470 int pid;
2472 uint64 addrs[] = {0,
2473 0x80000000LL,
2474 0x3fffffe000,
2475 0x3ffffff000,
2476 0x4000000000,
2477 0xffffffffffffffff};
2479 for (int ai = 0; ai < sizeof(addrs) / sizeof(addrs[0]); ai++) {
2481 if (pid == 0) {
2482 volatile int *addr = (int *)addrs[ai];
2483 *addr = 10;
2484 printf("%s: write to %p did not fail!\n", s, addr);
2486 } else if (pid < 0) {
2487 printf("%s: fork failed\n", s);
2491 if (xstatus == 0) {
2492 // kernel did not kill child!
2499// regression test. copyin(), copyout(), and copyinstr() used to cast
2500// the virtual page address to uint, which (with certain wild system
2501// call arguments) resulted in a kernel page faults.
2502void *big = (void *)0xeaeb0b5b00002f5e;
2503void
2504pgbug(char *s)
2506 char *argv[1];
2507 argv[0] = 0;
2514// regression test. does the kernel panic if a process sbrk()s its
2515// size to be less than a page, or zero, or reduces the break by an
2516// amount too small to cause a page to be freed?
2517void
2520 int pid = fork();
2521 if (pid < 0) {
2522 printf("fork failed\n");
2525 if (pid == 0) {
2526 int sz = (uint64)sbrk(0);
2527 // free all user memory; there used to be a bug that
2528 // would not adjust p->sz correctly in this case,
2529 // causing exit() to panic.
2531 // user page fault here.
2537 if (pid < 0) {
2538 printf("fork failed\n");
2541 if (pid == 0) {
2542 int sz = (uint64)sbrk(0);
2543 // set the break to somewhere in the very first
2544 // page; there used to be a bug that would incorrectly
2545 // free the first page.
2546 sbrk(-(sz - 3500));
2552 if (pid < 0) {
2553 printf("fork failed\n");
2556 if (pid == 0) {
2557 // set the break in the middle of a page.
2558 sbrk((10 * PGSIZE + 2048) - (uint64)sbrk(0));
2560 // reduce the break a bit, but not enough to
2561 // cause a page to be freed. this used to cause
2562 // a panic.
2563 sbrk(-10);
2572// if process size was somewhat more than a page boundary, and then
2573// shrunk to be somewhat less than that page boundary, can the kernel
2574// still copyin() from addresses in the last page?
2575void
2579 if ((top % PGSIZE) != 0)
2582 sbrk(10);
2583 sbrk(-20);
2585 char *p = (char *)(top - 64);
2586 p[0] = 'x';
2587 p[1] = '\0';
2589 write(fd, p, 1);
2592 p[0] = '\0';
2593 read(fd, p, 1);
2594 if (p[0] != 'x')
2598// does sbrk handle signed int32 wrap-around with
2599// negative arguments?
2600void
2603 sbrk(0x80000004);
2604 volatile char *top = sbrk(0);
2605 *(top - 1) = *(top - 1) + 1;
2608// regression test. test whether exec() leaks memory if one of the
2609// arguments is invalid. the test passes if the kernel doesn't panic.
2610void
2611badarg(char *s)
2613 for (int i = 0; i < 50000; i++) {
2614 char *argv[2];
2615 argv[0] = (char *)0xffffffff;
2616 argv[1] = 0;
2617 exec("echo", argv);
2623#define REGION_SZ (1024 * 1024 * 1024)
2625// Touch a page every 64 pages, which with lazy allocation
2626// causes one page to be allocated.
2627void
2630 char *i, *prev_end, *new_end;
2633 if (prev_end == (char *)SBRK_ERROR) {
2634 printf("sbrklazy() failed\n");
2639 for (i = prev_end + PGSIZE; i < new_end; i += 64 * PGSIZE)
2640 *(char **)i = i;
2642 for (i = prev_end + PGSIZE; i < new_end; i += 64 * PGSIZE) {
2643 if (*(char **)i != i) {
2644 printf("failed to read value from memory\n");
2652// Touch a page every 64 pages in region, which with lazy allocation
2653// causes one page to be allocated. Check that freeing the region
2654// frees the allocated pages.
2655void
2658 int pid;
2659 char *i, *prev_end, *new_end;
2662 if (prev_end == (char *)SBRK_ERROR) {
2663 printf("sbrklazy() failed\n");
2668 for (i = prev_end + PGSIZE; i < new_end; i += PGSIZE * PGSIZE)
2669 *(char **)i = i;
2671 for (i = prev_end + PGSIZE; i < new_end; i += PGSIZE * PGSIZE) {
2673 if (pid < 0) {
2674 printf("error forking\n");
2676 } else if (pid == 0) {
2678 *(char **)i = i;
2680 } else {
2683 if (status == 0) {
2684 printf("memory not unmapped\n");
2693void
2696 // copyinstr on lazy page
2698 char *p = sbrk(0);
2700 open(p + 8192, 0);
2704 void *xx = sbrk(0);
2705 void *ret = sbrk(-(((uint64)xx) + 1));
2706 if (ret != xx) {
2707 printf("sbrk(sbrk(0)+1) returned %p, not old sz\n", ret);
2712 // read() and write() to these addresses should fail.
2713 unsigned long bad[] = {
2714 0x3fffffc000, 0x3fffffd000, 0x3fffffe000,
2715 0x3ffffff000, 0x4000000000, 0x8000000000,
2716 };
2717 for (int i = 0; i < sizeof(bad) / sizeof(bad[0]); i++) {
2718 int fd = open("README", 0);
2719 if (fd < 0) {
2720 printf("cannot open README\n");
2723 if (read(fd, (char *)bad[i], 512) >= 0) {
2724 printf("read succeeded\n");
2728 fd = open("junk", O_CREATE | O_RDWR | O_TRUNC);
2729 if (fd < 0) {
2730 printf("cannot open junk\n");
2733 if (write(fd, (char *)bad[i], 512) >= 0) {
2734 printf("write succeeded\n");
2743void
2746 char *p = sbrk(0);
2749 p = sbrk(0);
2750 if ((uint64)p % PGSIZE != 0) {
2751 printf("%s: sbrk did not align\n", s);
2756 p[4095] = '/';
2757 int fd = open(&p[4095], O_RDONLY);
2758 if (fd < 0) {
2759 printf("could not open /");
2763 struct stat st;
2764 int r = fstat(fd, &st);
2765 if (r < 0) {
2766 printf("could not stat /");
2770 if (st.type != T_DIR) {
2771 printf("/ is not T_DIR");
2778void
2781 // sbrk() takes just int, so take 2^30-sized steps towards MAXVA
2782 char *p = sbrk(0);
2783 while ((uint64)p < MAXVA - (1 << 30)) {
2784 p = sbrklazy(1 << 30);
2785 if (p < 0) {
2786 printf("sbrklazy(%d) returned %p\n", 1 << 30, p);
2795 char *p1 = sbrklazy(n);
2796 if (p1 < 0 || p1 != p) {
2797 printf("sbrklazy(%d) returned %p, not expected %p\n", n, p1, p);
2802 if (p < 0 || (uint64)p != TRAPFRAME - PGSIZE) {
2803 printf("sbrk(%d) returned %p, not expected TRAPFRAME-PGSIZE\n", PGSIZE, p);
2807 p[0] = 1;
2808 if (p[1] != 0) {
2809 printf("sbrk() returned non-zero-filled memory\n");
2813 p = sbrk(1);
2814 if ((uint64)p != -1) {
2815 printf("sbrk(1) returned %p, expected error\n", p);
2820 if ((uint64)p != -1) {
2821 printf("sbrklazy(1) returned %p, expected error\n", p);
2828void
2831 // Create testfile containing "A".
2832 // write() 2 bytes that span page boundary: first is "X", second is unmapped.
2833 // Potential problem: write errors, forgets to log the updated first byte.
2834 // read() from file returns "X".
2835 // Flush buffer cache with some large writes.
2836 // read() from file should still return "X" (but might return "A" due to bug).
2838 unlink("testfile");
2839 int fd = open("testfile", O_CREATE | O_RDWR);
2840 if (fd < 0) {
2841 printf("%s: cannot create testfile\n", s);
2845 int cc = write(fd, "A", 1);
2846 if (cc != 1) {
2847 printf("%s: could not write A\n", s);
2852 fd = open("testfile", O_RDWR);
2853 if (fd < 0) {
2854 printf("%s: cannot re-open testfile\n", s);
2858 char *p = sbrk(0);
2861 p = sbrk(0);
2862 if ((uint64)p % PGSIZE != 0) {
2863 printf("%s: sbrk did not align\n", s);
2867 p[-1] = 'X';
2869 cc = write(fd, p - 1, 2);
2870 if (cc != -1) {
2871 printf("%s: write succeeded, should have failed\n", s);
2877 fd = open("testfile", O_RDONLY);
2878 if (fd < 0) {
2879 printf("%s: cannot re-open testfile\n", s);
2883 char b;
2884 cc = read(fd, &b, 1);
2885 if (cc != 1) {
2886 printf("%s: cannot read testfile\n", s);
2892 if (b != 'X') {
2893 printf("%s: read returned %c, expected X\n", s, b);
2897 fd = open("bigfile", O_CREATE | O_RDWR);
2898 for (int i = 0; i < 64; i++) {
2899 char buf[1024];
2900 memset(buf, 0, sizeof(buf));
2901 cc = write(fd, buf, sizeof(buf));
2902 if (cc != sizeof(buf)) {
2903 printf("%s: could not write to bigfile\n", s);
2904 exit(-1);
2909 unlink("bigfile");
2911 fd = open("testfile", O_RDONLY);
2912 if (fd < 0) {
2913 printf("%s: cannot re-open testfile\n", s);
2917 cc = read(fd, &b, 1);
2918 if (cc != 1) {
2919 printf("%s: cannot read testfile\n", s);
2925 if (b != 'X') {
2926 printf("%s: read returned %c, expected X\n", s, b);
2930 unlink("testfile");
2933void
2936 if (mkdir("/a") < 0) {
2937 printf("%s: mkdir /a failed\n", s);
2940 if (mkdir("/a/b") < 0) {
2941 printf("%s: mkdir /a/b failed\n", s);
2944 if (chdir("/a/b") < 0) {
2945 printf("%s: chdir failed\n", s);
2948 if (unlink("/a/b") < 0) {
2949 printf("%s: unlink /a/b failed\n", s);
2952 if (unlink("/a") < 0) {
2953 printf("%s: unlink /a failed\n", s);
2956 if (open("../", O_RDONLY) > 0) {
2957 printf("%s: open ../ non-existing directory\n", s);
2959 if (open("../c", O_CREATE) > 0) {
2960 printf("%s: create ../c non-existing file\n", s);
2964struct test {
2965 void (*f)(char *);
2966 char *s;
2968 {copyin, "copyin"},
2969 {copyout, "copyout"},
2970 {copyinstr1, "copyinstr1"},
2971 {copyinstr2, "copyinstr2"},
2972 {copyinstr3, "copyinstr3"},
2973 {rwsbrk, "rwsbrk"},
2974 {truncate1, "truncate1"},
2975 {truncate2, "truncate2"},
2976 {truncate3, "truncate3"},
2977 {openiputtest, "openiput"},
2978 {exitiputtest, "exitiput"},
2979 {iputtest, "iput"},
2980 {opentest, "opentest"},
2981 {writetest, "writetest"},
2982 {writebig, "writebig"},
2983 {createtest, "createtest"},
2984 {dirtest, "dirtest"},
2985 {exectest, "exectest"},
2986 {pipe1, "pipe1"},
2987 {killstatus, "killstatus"},
2988 {killzero, "killzero"},
2989 {preempt, "preempt"},
2990 {exitwait, "exitwait"},
2991 {reparent, "reparent"},
2992 {twochildren, "twochildren"},
2993 {forkfork, "forkfork"},
2994 {forkforkfork, "forkforkfork"},
2995 {reparent2, "reparent2"},
2996 {mem, "mem"},
2997 {sharedfd, "sharedfd"},
2998 {fourfiles, "fourfiles"},
2999 {createdelete, "createdelete"},
3000 {unlinkread, "unlinkread"},
3001 {linktest, "linktest"},
3002 {concreate, "concreate"},
3003 {linkunlink, "linkunlink"},
3004 {subdir, "subdir"},
3005 {bigwrite, "bigwrite"},
3006 {bigfile, "bigfile"},
3007 {fourteen, "fourteen"},
3008 {rmdot, "rmdot"},
3009 {dirfile, "dirfile"},
3010 {iref, "iref"},
3011 {forktest, "forktest"},
3012 {sbrkbasic, "sbrkbasic"},
3013 {sbrkmuch, "sbrkmuch"},
3014 {kernmem, "kernmem"},
3015 {MAXVAplus, "MAXVAplus"},
3016 {sbrkfail, "sbrkfail"},
3017 {sbrkarg, "sbrkarg"},
3018 {validatetest, "validatetest"},
3019 {bsstest, "bsstest"},
3020 {bigargtest, "bigargtest"},
3021 {argptest, "argptest"},
3022 {stacktest, "stacktest"},
3023 {nowrite, "nowrite"},
3024 {pgbug, "pgbug"},
3025 {sbrkbugs, "sbrkbugs"},
3026 {sbrklast, "sbrklast"},
3027 {sbrk8000, "sbrk8000"},
3028 {badarg, "badarg"},
3029 {lazy_alloc, "lazy_alloc"},
3030 {lazy_unmap, "lazy_unmap"},
3031 {lazy_copy, "lazy_copy"},
3032 {lazy_copyinstr, "lazy_copyinstr"},
3033 {lazy_sbrk, "lazy_sbrk"},
3034 {partial_write, "partial_write"},
3035 {unlinkcwd, "unlinkcwd"},
3036 {0, 0},
3040// Section with tests that take a fair bit of time
3043// directory that uses indirect blocks
3044void
3045bigdir(char *s)
3047 enum { N = 500 };
3048 int i, fd;
3049 char name[10];
3051 unlink("bd");
3053 fd = open("bd", O_CREATE);
3054 if (fd < 0) {
3055 printf("%s: bigdir create failed\n", s);
3060 for (i = 0; i < N; i++) {
3061 name[0] = 'x';
3062 name[1] = '0' + (i / 64);
3063 name[2] = '0' + (i % 64);
3064 name[3] = '\0';
3065 if (link("bd", name) != 0) {
3066 printf("%s: bigdir i=%d link(bd, %s) failed\n", s, i, name);
3071 unlink("bd");
3072 for (i = 0; i < N; i++) {
3073 name[0] = 'x';
3074 name[1] = '0' + (i / 64);
3075 name[2] = '0' + (i % 64);
3076 name[3] = '\0';
3077 if (unlink(name) != 0) {
3078 printf("%s: bigdir unlink failed", s);
3084// concurrent writes to try to provoke deadlock in the virtio disk
3085// driver.
3086void
3089 int nchildren = 4;
3090 int howmany = 30; // increase to look for deadlock
3092 for (int ci = 0; ci < nchildren; ci++) {
3093 int pid = fork();
3094 if (pid < 0) {
3095 printf("fork failed\n");
3099 if (pid == 0) {
3100 char name[3];
3101 name[0] = 'b';
3102 name[1] = 'a' + ci;
3103 name[2] = '\0';
3106 for (int iters = 0; iters < howmany; iters++) {
3107 for (int i = 0; i < ci + 1; i++) {
3109 if (fd < 0) {
3110 printf("%s: cannot create %s\n", s, name);
3113 int sz = sizeof(buf);
3114 int cc = write(fd, buf, sz);
3115 if (cc != sz) {
3116 printf("%s: write(%d) ret %d\n", s, sz, cc);
3129 for (int ci = 0; ci < nchildren; ci++) {
3130 int st = 0;
3132 if (st != 0)
3138// regression test. does write() with an invalid buffer pointer cause
3139// a block to be allocated for a file that is then not freed when the
3140// file is deleted? if the kernel has this bug, it will panic: balloc:
3141// out of blocks. assumed_free may need to be raised to be more than
3142// the number of free blocks. this test takes a long time.
3143void
3146 int assumed_free = 600;
3148 unlink("junk");
3149 for (int i = 0; i < assumed_free; i++) {
3150 int fd = open("junk", O_CREATE | O_WRONLY);
3151 if (fd < 0) {
3152 printf("open junk failed\n");
3155 write(fd, (char *)0xffffffffffL, 1);
3157 unlink("junk");
3160 int fd = open("junk", O_CREATE | O_WRONLY);
3161 if (fd < 0) {
3162 printf("open junk failed\n");
3165 if (write(fd, "x", 1) != 1) {
3166 printf("write failed\n");
3170 unlink("junk");
3175// test the exec() code that cleans up if it runs out
3176// of memory. it's really a test that such a condition
3177// doesn't cause a panic.
3178void
3179execout(char *s)
3181 for (int avail = 0; avail < 15; avail++) {
3182 int pid = fork();
3183 if (pid < 0) {
3184 printf("fork failed\n");
3186 } else if (pid == 0) {
3187 // allocate all of memory.
3188 while (1) {
3189 char *a = sbrk(PGSIZE);
3190 if (a == SBRK_ERROR)
3191 break;
3192 *(a + PGSIZE - 1) = 1;
3195 // free a few pages, in order to let exec() make some
3196 // progress.
3197 for (int i = 0; i < avail; i++)
3201 char *args[] = {"echo", "x", 0};
3202 exec("echo", args);
3204 } else {
3205 wait((int *)0);
3212// can the kernel tolerate running out of disk space?
3213void
3216 int fi;
3217 int done = 0;
3219 unlink("diskfulldir");
3221 for (fi = 0; done == 0 && '0' + fi < 0177; fi++) {
3222 char name[32];
3223 name[0] = 'b';
3224 name[1] = 'i';
3225 name[2] = 'g';
3226 name[3] = '0' + fi;
3227 name[4] = '\0';
3230 if (fd < 0) {
3231 // oops, ran out of inodes before running out of blocks.
3232 printf("%s: could not create file %s\n", s, name);
3233 done = 1;
3234 break;
3236 for (int i = 0; i < MAXFILE; i++) {
3237 char buf[BSIZE];
3238 if (write(fd, buf, BSIZE) != BSIZE) {
3239 done = 1;
3241 break;
3247 // now that there are no free blocks, test that dirlink()
3248 // merely fails (doesn't panic) if it can't extend
3249 // directory content. one of these file creations
3250 // is expected to fail.
3251 int nzz = 128;
3252 for (int i = 0; i < nzz; i++) {
3253 char name[32];
3254 name[0] = 'z';
3255 name[1] = 'z';
3256 name[2] = '0' + (i / 32);
3257 name[3] = '0' + (i % 32);
3258 name[4] = '\0';
3261 if (fd < 0)
3262 break;
3266 // this mkdir() is expected to fail.
3267 if (mkdir("diskfulldir") == 0)
3268 printf("%s: mkdir(diskfulldir) unexpectedly succeeded!\n", s);
3270 unlink("diskfulldir");
3272 for (int i = 0; i < nzz; i++) {
3273 char name[32];
3274 name[0] = 'z';
3275 name[1] = 'z';
3276 name[2] = '0' + (i / 32);
3277 name[3] = '0' + (i % 32);
3278 name[4] = '\0';
3282 for (int i = 0; '0' + i < 0177; i++) {
3283 char name[32];
3284 name[0] = 'b';
3285 name[1] = 'i';
3286 name[2] = 'g';
3287 name[3] = '0' + i;
3288 name[4] = '\0';
3293void
3296 int nzz = 32 * 32;
3297 for (int i = 0; i < nzz; i++) {
3298 char name[32];
3299 name[0] = 'z';
3300 name[1] = 'z';
3301 name[2] = '0' + (i / 32);
3302 name[3] = '0' + (i % 32);
3303 name[4] = '\0';
3306 if (fd < 0) {
3307 // failure is eventually expected.
3308 break;
3313 for (int i = 0; i < nzz; i++) {
3314 char name[32];
3315 name[0] = 'z';
3316 name[1] = 'z';
3317 name[2] = '0' + (i / 32);
3318 name[3] = '0' + (i % 32);
3319 name[4] = '\0';
3324void
3327 enum { TARGET = 32768 };
3328 enum { DIRS = 64 };
3329 struct stat st;
3330 int i;
3332 unlink("/lof");
3333 int fd = open("/lof", O_CREATE | O_RDWR);
3334 if (fd < 0) {
3335 printf("%s: cannot create /lof\n", s);
3340 for (i = 0; i < TARGET; i++) {
3341 int d = i % DIRS;
3342 int f = i / DIRS;
3344 char pn[16];
3345 pn[0] = '/';
3346 pn[1] = 'd';
3347 pn[2] = '_';
3348 pn[3] = 'a' + (d / 16);
3349 pn[4] = 'a' + (d % 16);
3350 pn[5] = '\0';
3351 if (f == 0 && mkdir(pn) < 0) {
3352 printf("%s: mkdir(%s) failed\n", s, pn);
3356 pn[5] = '/';
3357 pn[6] = 'l';
3358 pn[7] = 'a' + (f / 256);
3359 pn[8] = 'a' + ((f / 16) % 16);
3360 pn[9] = 'a' + (f % 16);
3361 pn[10] = '\0';
3363 if (link("/lof", pn) < 0) {
3364 if (stat("/lof", &st) < 0) {
3365 printf("%s: stat(/lof) failed\n", s);
3368 if (st.nlink >= 32767) {
3369 // overflow check succeeded.
3370 break;
3372 printf("%s: link failed after %d links (nlink=%d)\n", s, i, st.nlink);
3376 if (i % 100 == 0) {
3377 printf("%s: i=%d, pn=%s\n", s, i, pn);
3381 if (stat("/lof", &st) < 0) {
3382 printf("%s: stat(/lof) failed\n", s);
3386 unlink("/lof");
3388 if (st.nlink < 0) {
3389 printf("%s: negative link count: %d\n", s, st.nlink);
3394struct test slowtests[] = {
3395 {bigdir, "bigdir"},
3396 {manywrites, "manywrites"},
3397 {badwrite, "badwrite"},
3398 {execout, "execout"},
3399 {diskfull, "diskfull"},
3400 {outofinodes, "outofinodes"},
3401 // {linkoverflow, "linkoverflow"},
3403 {0, 0},
3407// drive tests
3410// run each test in its own process. run returns 1 if child's exit()
3411// indicates success.
3412int
3413run(void f(char *), char *s)
3415 int pid;
3418 printf("test %s: ", s);
3419 if ((pid = fork()) < 0) {
3420 printf("runtest: fork error\n");
3423 if (pid == 0) {
3424 f(s);
3426 } else {
3428 if (xstatus != 0)
3429 printf("FAILED\n");
3430 else
3431 printf("OK\n");
3432 return xstatus == 0;
3436int
3439 int ntests = 0;
3440 for (struct test *t = tests; t->s != 0; t++) {
3441 if ((justone == 0) || strcmp(t->s, justone) == 0) {
3443 if (!run(t->f, t->s)) {
3444 if (continuous != 2) {
3445 printf("SOME TESTS FAILED\n");
3446 return -1;
3451 return ntests;
3454// use sbrk() to count how many free physical memory pages there are.
3455int
3458 int n = 0;
3460 while (1) {
3461 char *a = sbrk(PGSIZE);
3462 if (a == SBRK_ERROR) {
3463 break;
3465 n += 1;
3467 sbrk(-((uint64)sbrk(0) - sz0));
3468 return n;
3471int
3474 do {
3475 printf("usertests starting\n");
3477 int free1 = 0;
3478 int ntests = 0;
3479 int n;
3481 if (n < 0) {
3482 if (continuous != 2) {
3483 return 1;
3485 } else {
3488 if (!quick) {
3489 if (justone == 0)
3490 printf("usertests slow tests starting\n");
3492 if (n < 0) {
3493 if (continuous != 2) {
3494 return 1;
3496 } else {
3500 if ((free1 = countfree()) < free0) {
3501 printf("FAILED -- lost some free pages %d (out of %d)\n", free1, free0);
3502 if (continuous != 2) {
3503 return 1;
3506 if (justone != 0 && ntests == 0) {
3507 printf("NO TESTS EXECUTED\n");
3508 return 1;
3510 } while (continuous);
3511 return 0;
3514int
3515main(int argc, char *argv[])
3517 int continuous = 0;
3518 int quick = 0;
3519 char *justone = 0;
3521 if (argc == 2 && strcmp(argv[1], "-q") == 0) {
3522 quick = 1;
3523 } else if (argc == 2 && strcmp(argv[1], "-c") == 0) {
3525 } else if (argc == 2 && strcmp(argv[1], "-C") == 0) {
3527 } else if (argc == 2 && argv[1][0] != '-') {
3529 } else if (argc > 1) {
3530 printf("Usage: usertests [-c] [-C] [-q] [testname]\n");
3536 printf("ALL TESTS PASSED\n");