summaryrefslogtreecommitdiff
path: root/user
diff options
context:
space:
mode:
Diffstat (limited to 'user')
-rw-r--r--user/alarmtest.c88
-rw-r--r--user/cat.c8
-rw-r--r--user/grind.c333
-rw-r--r--user/sh.c2
-rw-r--r--user/ulib.c31
-rw-r--r--user/user.h2
-rw-r--r--user/usertests.c471
7 files changed, 817 insertions, 118 deletions
diff --git a/user/alarmtest.c b/user/alarmtest.c
deleted file mode 100644
index ca3db23..0000000
--- a/user/alarmtest.c
+++ /dev/null
@@ -1,88 +0,0 @@
-//
-// test program for the alarm lab.
-// you can modify this file for testing,
-// but please make sure your kernel
-// modifications pass the original
-// versions of these tests.
-//
-
-#include "kernel/param.h"
-#include "kernel/types.h"
-#include "kernel/stat.h"
-#include "kernel/riscv.h"
-#include "user/user.h"
-
-void test0();
-void test1();
-void periodic();
-
-int
-main(int argc, char *argv[])
-{
- test0();
- test1();
- exit();
-}
-
-volatile static int count;
-
-void
-periodic()
-{
- count = count + 1;
- printf("alarm!\n");
- sigreturn();
-}
-
-// tests whether the kernel calls
-// the alarm handler even a single time.
-void
-test0()
-{
- int i;
- printf("test0 start\n");
- count = 0;
- sigalarm(2, periodic);
- for(i = 0; i < 1000*500000; i++){
- if((i % 250000) == 0)
- write(2, ".", 1);
- if(count > 0)
- break;
- }
- sigalarm(0, 0);
- if(count > 0){
- printf("test0 passed\n");
- } else {
- printf("test0 failed\n");
- }
-}
-
-void __attribute__ ((noinline)) foo(int i, int *j) {
- if((i % 2500000) == 0) {
- write(2, ".", 1);
- }
- *j += 1;
-}
-
-void
-test1()
-{
- int i;
- int j;
-
- printf("test1 start\n");
- count = 0;
- j = 0;
- sigalarm(2, periodic);
- for(i = 0; i < 500000000; i++){
- if(count >= 10)
- break;
- foo(i, &j);
- }
- if(i != j || count < 10){
- // i should equal j
- printf("test1 failed\n");
- } else {
- printf("test1 passed\n");
- }
-}
diff --git a/user/cat.c b/user/cat.c
index 36939d8..598f005 100644
--- a/user/cat.c
+++ b/user/cat.c
@@ -11,12 +11,12 @@ cat(int fd)
while((n = read(fd, buf, sizeof(buf))) > 0) {
if (write(1, buf, n) != n) {
- printf("cat: write error\n");
+ fprintf(2, "cat: write error\n");
exit(1);
}
}
if(n < 0){
- printf("cat: read error\n");
+ fprintf(2, "cat: read error\n");
exit(1);
}
}
@@ -28,12 +28,12 @@ main(int argc, char *argv[])
if(argc <= 1){
cat(0);
- exit(1);
+ exit(0);
}
for(i = 1; i < argc; i++){
if((fd = open(argv[i], 0)) < 0){
- printf("cat: cannot open %s\n", argv[i]);
+ fprintf(2, "cat: cannot open %s\n", argv[i]);
exit(1);
}
cat(fd);
diff --git a/user/grind.c b/user/grind.c
new file mode 100644
index 0000000..14e2aae
--- /dev/null
+++ b/user/grind.c
@@ -0,0 +1,333 @@
+//
+// run random system calls in parallel forever.
+//
+
+#include "kernel/param.h"
+#include "kernel/types.h"
+#include "kernel/stat.h"
+#include "user/user.h"
+#include "kernel/fs.h"
+#include "kernel/fcntl.h"
+#include "kernel/syscall.h"
+#include "kernel/memlayout.h"
+#include "kernel/riscv.h"
+
+// from FreeBSD.
+int
+do_rand(unsigned long *ctx)
+{
+/*
+ * Compute x = (7^5 * x) mod (2^31 - 1)
+ * without overflowing 31 bits:
+ * (2^31 - 1) = 127773 * (7^5) + 2836
+ * From "Random number generators: good ones are hard to find",
+ * Park and Miller, Communications of the ACM, vol. 31, no. 10,
+ * October 1988, p. 1195.
+ */
+ long hi, lo, x;
+
+ /* Transform to [1, 0x7ffffffe] range. */
+ x = (*ctx % 0x7ffffffe) + 1;
+ hi = x / 127773;
+ lo = x % 127773;
+ x = 16807 * lo - 2836 * hi;
+ if (x < 0)
+ x += 0x7fffffff;
+ /* Transform to [0, 0x7ffffffd] range. */
+ x--;
+ *ctx = x;
+ return (x);
+}
+
+unsigned long rand_next = 1;
+
+int
+rand(void)
+{
+ return (do_rand(&rand_next));
+}
+
+void
+go(int which_child)
+{
+ int fd = -1;
+ static char buf[999];
+ char *break0 = sbrk(0);
+ uint64 iters = 0;
+
+ mkdir("grindir");
+ if(chdir("grindir") != 0){
+ printf("chdir grindir failed\n");
+ exit(1);
+ }
+ chdir("/");
+
+ while(1){
+ iters++;
+ if((iters % 500) == 0)
+ write(1, which_child?"B":"A", 1);
+ int what = rand() % 23;
+ if(what == 1){
+ close(open("grindir/../a", O_CREATE|O_RDWR));
+ } else if(what == 2){
+ close(open("grindir/../grindir/../b", O_CREATE|O_RDWR));
+ } else if(what == 3){
+ unlink("grindir/../a");
+ } else if(what == 4){
+ if(chdir("grindir") != 0){
+ printf("chdir grindir failed\n");
+ exit(1);
+ }
+ unlink("../b");
+ chdir("/");
+ } else if(what == 5){
+ close(fd);
+ fd = open("/grindir/../a", O_CREATE|O_RDWR);
+ } else if(what == 6){
+ close(fd);
+ fd = open("/./grindir/./../b", O_CREATE|O_RDWR);
+ } else if(what == 7){
+ write(fd, buf, sizeof(buf));
+ } else if(what == 8){
+ read(fd, buf, sizeof(buf));
+ } else if(what == 9){
+ mkdir("grindir/../a");
+ close(open("a/../a/./a", O_CREATE|O_RDWR));
+ unlink("a/a");
+ } else if(what == 10){
+ mkdir("/../b");
+ close(open("grindir/../b/b", O_CREATE|O_RDWR));
+ unlink("b/b");
+ } else if(what == 11){
+ unlink("b");
+ link("../grindir/./../a", "../b");
+ } else if(what == 12){
+ unlink("../grindir/../a");
+ link(".././b", "/grindir/../a");
+ } else if(what == 13){
+ int pid = fork();
+ if(pid == 0){
+ exit(0);
+ } else if(pid < 0){
+ printf("grind: fork failed\n");
+ exit(1);
+ }
+ wait(0);
+ } else if(what == 14){
+ int pid = fork();
+ if(pid == 0){
+ fork();
+ fork();
+ exit(0);
+ } else if(pid < 0){
+ printf("grind: fork failed\n");
+ exit(1);
+ }
+ wait(0);
+ } else if(what == 15){
+ sbrk(6011);
+ } else if(what == 16){
+ if(sbrk(0) > break0)
+ sbrk(-(sbrk(0) - break0));
+ } else if(what == 17){
+ int pid = fork();
+ if(pid == 0){
+ close(open("a", O_CREATE|O_RDWR));
+ exit(0);
+ } else if(pid < 0){
+ printf("grind: fork failed\n");
+ exit(1);
+ }
+ if(chdir("../grindir/..") != 0){
+ printf("chdir failed\n");
+ exit(1);
+ }
+ kill(pid);
+ wait(0);
+ } else if(what == 18){
+ int pid = fork();
+ if(pid == 0){
+ kill(getpid());
+ exit(0);
+ } else if(pid < 0){
+ printf("grind: fork failed\n");
+ exit(1);
+ }
+ wait(0);
+ } else if(what == 19){
+ int fds[2];
+ if(pipe(fds) < 0){
+ printf("grind: pipe failed\n");
+ exit(1);
+ }
+ int pid = fork();
+ if(pid == 0){
+ fork();
+ fork();
+ if(write(fds[1], "x", 1) != 1)
+ printf("grind: pipe write failed\n");
+ char c;
+ if(read(fds[0], &c, 1) != 1)
+ printf("grind: pipe read failed\n");
+ exit(0);
+ } else if(pid < 0){
+ printf("grind: fork failed\n");
+ exit(1);
+ }
+ close(fds[0]);
+ close(fds[1]);
+ wait(0);
+ } else if(what == 20){
+ int pid = fork();
+ if(pid == 0){
+ unlink("a");
+ mkdir("a");
+ chdir("a");
+ unlink("../a");
+ fd = open("x", O_CREATE|O_RDWR);
+ unlink("x");
+ exit(0);
+ } else if(pid < 0){
+ printf("fork failed\n");
+ exit(1);
+ }
+ wait(0);
+ } else if(what == 21){
+ unlink("c");
+ // should always succeed. check that there are free i-nodes,
+ // file descriptors, blocks.
+ int fd1 = open("c", O_CREATE|O_RDWR);
+ if(fd1 < 0){
+ printf("create c failed\n");
+ exit(1);
+ }
+ if(write(fd1, "x", 1) != 1){
+ printf("write c failed\n");
+ exit(1);
+ }
+ struct stat st;
+ if(fstat(fd1, &st) != 0){
+ printf("fstat failed\n");
+ exit(1);
+ }
+ if(st.size != 1){
+ printf("fstat reports wrong size %d\n", (int)st.size);
+ exit(1);
+ }
+ if(st.ino > 200){
+ printf("fstat reports crazy i-number %d\n", st.ino);
+ exit(1);
+ }
+ close(fd1);
+ unlink("c");
+ } else if(what == 22){
+ // echo hi | cat
+ int aa[2], bb[2];
+ if(pipe(aa) < 0){
+ fprintf(2, "pipe failed\n");
+ exit(1);
+ }
+ if(pipe(bb) < 0){
+ fprintf(2, "pipe failed\n");
+ exit(1);
+ }
+ int pid1 = fork();
+ if(pid1 == 0){
+ close(bb[0]);
+ close(bb[1]);
+ close(aa[0]);
+ close(1);
+ if(dup(aa[1]) != 1){
+ fprintf(2, "dup failed\n");
+ exit(1);
+ }
+ close(aa[1]);
+ char *args[3] = { "echo", "hi", 0 };
+ exec("grindir/../echo", args);
+ fprintf(2, "echo: not found\n");
+ exit(2);
+ } else if(pid1 < 0){
+ fprintf(2, "fork failed\n");
+ exit(3);
+ }
+ int pid2 = fork();
+ if(pid2 == 0){
+ close(aa[1]);
+ close(bb[0]);
+ close(0);
+ if(dup(aa[0]) != 0){
+ fprintf(2, "dup failed\n");
+ exit(4);
+ }
+ close(aa[0]);
+ close(1);
+ if(dup(bb[1]) != 1){
+ fprintf(2, "dup failed\n");
+ exit(5);
+ }
+ close(bb[1]);
+ char *args[2] = { "cat", 0 };
+ exec("/cat", args);
+ fprintf(2, "cat: not found\n");
+ exit(6);
+ } else if(pid2 < 0){
+ fprintf(2, "fork failed\n");
+ exit(7);
+ }
+ close(aa[0]);
+ close(aa[1]);
+ close(bb[1]);
+ char buf[3] = { 0, 0, 0 };
+ read(bb[0], buf+0, 1);
+ read(bb[0], buf+1, 1);
+ close(bb[0]);
+ int st1, st2;
+ wait(&st1);
+ wait(&st2);
+ if(st1 != 0 || st2 != 0 || strcmp(buf, "hi") != 0){
+ printf("exec pipeline failed %d %d \"%s\"\n", st1, st2, buf);
+ exit(1);
+ }
+ }
+ }
+}
+
+int
+main()
+{
+ unlink("a");
+ unlink("b");
+
+ int pid1 = fork();
+ if(pid1 < 0){
+ printf("grind: fork failed\n");
+ exit(1);
+ }
+ if(pid1 == 0){
+ rand_next = 31;
+ go(0);
+ exit(0);
+ }
+
+ int pid2 = fork();
+ if(pid2 < 0){
+ printf("grind: fork failed\n");
+ exit(1);
+ }
+ if(pid2 == 0){
+ rand_next = 7177;
+ go(1);
+ exit(0);
+ }
+
+ int st1 = -1;
+ wait(&st1);
+ if(st1 != 0){
+ kill(pid1);
+ kill(pid2);
+ }
+ int st2 = -1;
+ wait(&st2);
+
+ exit(0);
+}
diff --git a/user/sh.c b/user/sh.c
index a593bc0..83dd513 100644
--- a/user/sh.c
+++ b/user/sh.c
@@ -386,7 +386,7 @@ parseredirs(struct cmd *cmd, char **ps, char *es)
cmd = redircmd(cmd, q, eq, O_RDONLY, 0);
break;
case '>':
- cmd = redircmd(cmd, q, eq, O_WRONLY|O_CREATE, 1);
+ cmd = redircmd(cmd, q, eq, O_WRONLY|O_CREATE|O_TRUNC, 1);
break;
case '+': // >>
cmd = redircmd(cmd, q, eq, O_WRONLY|O_CREATE, 1);
diff --git a/user/ulib.c b/user/ulib.c
index ddda0f5..4775939 100644
--- a/user/ulib.c
+++ b/user/ulib.c
@@ -103,7 +103,34 @@ memmove(void *vdst, const void *vsrc, int n)
dst = vdst;
src = vsrc;
- while(n-- > 0)
- *dst++ = *src++;
+ if (src > dst) {
+ while(n-- > 0)
+ *dst++ = *src++;
+ } else {
+ dst += n;
+ src += n;
+ while(n-- > 0)
+ *--dst = *--src;
+ }
return vdst;
}
+
+int
+memcmp(const void *s1, const void *s2, uint n)
+{
+ const char *p1 = s1, *p2 = s2;
+ while (n-- > 0) {
+ if (*p1 != *p2) {
+ return *p1 - *p2;
+ }
+ p1++;
+ p2++;
+ }
+ return 0;
+}
+
+void *
+memcpy(void *dst, const void *src, uint n)
+{
+ return memmove(dst, src, n);
+}
diff --git a/user/user.h b/user/user.h
index 03af731..b71ecda 100644
--- a/user/user.h
+++ b/user/user.h
@@ -38,3 +38,5 @@ void* memset(void*, int, uint);
void* malloc(uint);
void free(void*);
int atoi(const char*);
+int memcmp(const void *, const void *, uint);
+void *memcpy(void *, const void *, uint);
diff --git a/user/usertests.c b/user/usertests.c
index db9f680..dfe0039 100644
--- a/user/usertests.c
+++ b/user/usertests.c
@@ -22,6 +22,352 @@
char buf[BUFSZ];
char name[3];
+// what if you pass ridiculous pointers to system calls
+// that read user memory with copyin?
+void
+copyin(char *s)
+{
+ uint64 addrs[] = { 0x80000000LL, 0xffffffffffffffff };
+
+ for(int ai = 0; ai < 2; ai++){
+ uint64 addr = addrs[ai];
+
+ int fd = open("copyin1", O_CREATE|O_WRONLY);
+ if(fd < 0){
+ printf("open(copyin1) failed\n");
+ exit(1);
+ }
+ int n = write(fd, (void*)addr, 8192);
+ if(n >= 0){
+ printf("write(fd, %p, 8192) returned %d, not -1\n", addr, n);
+ exit(1);
+ }
+ close(fd);
+ unlink("copyin1");
+
+ n = write(1, (char*)addr, 8192);
+ if(n > 0){
+ printf("write(1, %p, 8192) returned %d, not -1 or 0\n", addr, n);
+ exit(1);
+ }
+
+ int fds[2];
+ if(pipe(fds) < 0){
+ printf("pipe() failed\n");
+ exit(1);
+ }
+ n = write(fds[1], (char*)addr, 8192);
+ if(n > 0){
+ printf("write(pipe, %p, 8192) returned %d, not -1 or 0\n", addr, n);
+ exit(1);
+ }
+ close(fds[0]);
+ close(fds[1]);
+ }
+}
+
+// what if you pass ridiculous pointers to system calls
+// that write user memory with copyout?
+void
+copyout(char *s)
+{
+ uint64 addrs[] = { 0x80000000LL, 0xffffffffffffffff };
+
+ for(int ai = 0; ai < 2; ai++){
+ uint64 addr = addrs[ai];
+
+ int fd = open("README", 0);
+ if(fd < 0){
+ printf("open(README) failed\n");
+ exit(1);
+ }
+ int n = read(fd, (void*)addr, 8192);
+ if(n > 0){
+ printf("read(fd, %p, 8192) returned %d, not -1 or 0\n", addr, n);
+ exit(1);
+ }
+ close(fd);
+
+ int fds[2];
+ if(pipe(fds) < 0){
+ printf("pipe() failed\n");
+ exit(1);
+ }
+ n = write(fds[1], "x", 1);
+ if(n != 1){
+ printf("pipe write failed\n");
+ exit(1);
+ }
+ n = read(fds[0], (void*)addr, 8192);
+ if(n > 0){
+ printf("read(pipe, %p, 8192) returned %d, not -1 or 0\n", addr, n);
+ exit(1);
+ }
+ close(fds[0]);
+ close(fds[1]);
+ }
+}
+
+// what if you pass ridiculous string pointers to system calls?
+void
+copyinstr1(char *s)
+{
+ uint64 addrs[] = { 0x80000000LL, 0xffffffffffffffff };
+
+ for(int ai = 0; ai < 2; ai++){
+ uint64 addr = addrs[ai];
+
+ int fd = open((char *)addr, O_CREATE|O_WRONLY);
+ if(fd >= 0){
+ printf("open(%p) returned %d, not -1\n", addr, fd);
+ exit(1);
+ }
+ }
+}
+
+// what if a string system call argument is exactly the size
+// of the kernel buffer it is copied into, so that the null
+// would fall just beyond the end of the kernel buffer?
+void
+copyinstr2(char *s)
+{
+ char b[MAXPATH+1];
+
+ for(int i = 0; i < MAXPATH; i++)
+ b[i] = 'x';
+ b[MAXPATH] = '\0';
+
+ int ret = unlink(b);
+ if(ret != -1){
+ printf("unlink(%s) returned %d, not -1\n", b, ret);
+ exit(1);
+ }
+
+ int fd = open(b, O_CREATE | O_WRONLY);
+ if(fd != -1){
+ printf("open(%s) returned %d, not -1\n", b, fd);
+ exit(1);
+ }
+
+ ret = link(b, b);
+ if(ret != -1){
+ printf("link(%s, %s) returned %d, not -1\n", b, b, ret);
+ exit(1);
+ }
+
+ char *args[] = { "xx", 0 };
+ ret = exec(b, args);
+ if(ret != -1){
+ printf("exec(%s) returned %d, not -1\n", b, fd);
+ exit(1);
+ }
+
+ int pid = fork();
+ if(pid < 0){
+ printf("fork failed\n");
+ exit(1);
+ }
+ if(pid == 0){
+ static char big[PGSIZE+1];
+ for(int i = 0; i < PGSIZE; i++)
+ big[i] = 'x';
+ big[PGSIZE] = '\0';
+ char *args2[] = { big, big, big, 0 };
+ ret = exec("echo", args2);
+ if(ret != -1){
+ printf("exec(echo, BIG) returned %d, not -1\n", fd);
+ exit(1);
+ }
+ exit(747); // OK
+ }
+
+ int st = 0;
+ wait(&st);
+ if(st != 747){
+ printf("exec(echo, BIG) succeeded, should have failed\n");
+ exit(1);
+ }
+}
+
+// what if a string argument crosses over the end of last user page?
+void
+copyinstr3(char *s)
+{
+ sbrk(8192);
+ uint64 top = (uint64) sbrk(0);
+ if((top % PGSIZE) != 0){
+ sbrk(PGSIZE - (top % PGSIZE));
+ }
+ top = (uint64) sbrk(0);
+ if(top % PGSIZE){
+ printf("oops\n");
+ exit(1);
+ }
+
+ char *b = (char *) (top - 1);
+ *b = 'x';
+
+ int ret = unlink(b);
+ if(ret != -1){
+ printf("unlink(%s) returned %d, not -1\n", b, ret);
+ exit(1);
+ }
+
+ int fd = open(b, O_CREATE | O_WRONLY);
+ if(fd != -1){
+ printf("open(%s) returned %d, not -1\n", b, fd);
+ exit(1);
+ }
+
+ ret = link(b, b);
+ if(ret != -1){
+ printf("link(%s, %s) returned %d, not -1\n", b, b, ret);
+ exit(1);
+ }
+
+ char *args[] = { "xx", 0 };
+ ret = exec(b, args);
+ if(ret != -1){
+ printf("exec(%s) returned %d, not -1\n", b, fd);
+ exit(1);
+ }
+}
+
+// test O_TRUNC.
+void
+truncate1(char *s)
+{
+ char buf[32];
+
+ unlink("truncfile");
+ int fd1 = open("truncfile", O_CREATE|O_WRONLY|O_TRUNC);
+ write(fd1, "abcd", 4);
+ close(fd1);
+
+ int fd2 = open("truncfile", O_RDONLY);
+ int n = read(fd2, buf, sizeof(buf));
+ if(n != 4){
+ printf("%s: read %d bytes, wanted 4\n", s, n);
+ exit(1);
+ }
+
+ fd1 = open("truncfile", O_WRONLY|O_TRUNC);
+
+ int fd3 = open("truncfile", O_RDONLY);
+ n = read(fd3, buf, sizeof(buf));
+ if(n != 0){
+ printf("aaa fd3=%d\n", fd3);
+ printf("%s: read %d bytes, wanted 0\n", s, n);
+ exit(1);
+ }
+
+ n = read(fd2, buf, sizeof(buf));
+ if(n != 0){
+ printf("bbb fd2=%d\n", fd2);
+ printf("%s: read %d bytes, wanted 0\n", s, n);
+ exit(1);
+ }
+
+ write(fd1, "abcdef", 6);
+
+ n = read(fd3, buf, sizeof(buf));
+ if(n != 6){
+ printf("%s: read %d bytes, wanted 6\n", s, n);
+ exit(1);
+ }
+
+ n = read(fd2, buf, sizeof(buf));
+ if(n != 2){
+ printf("%s: read %d bytes, wanted 2\n", s, n);
+ exit(1);
+ }
+
+ unlink("truncfile");
+
+ close(fd1);
+ close(fd2);
+ close(fd3);
+}
+
+// write to an open FD whose file has just been truncated.
+// this causes a write at an offset beyond the end of the file.
+// such writes fail on xv6 (unlike POSIX) but at least
+// they don't crash.
+void
+truncate2(char *s)
+{
+ unlink("truncfile");
+
+ int fd1 = open("truncfile", O_CREATE|O_TRUNC|O_WRONLY);
+ write(fd1, "abcd", 4);
+
+ int fd2 = open("truncfile", O_TRUNC|O_WRONLY);
+
+ int n = write(fd1, "x", 1);
+ if(n != -1){
+ printf("%s: write returned %d, expected -1\n", s, n);
+ exit(1);
+ }
+
+ unlink("truncfile");
+ close(fd1);
+ close(fd2);
+}
+
+void
+truncate3(char *s)
+{
+ int pid, xstatus;
+
+ close(open("truncfile", O_CREATE|O_TRUNC|O_WRONLY));
+
+ pid = fork();
+ if(pid < 0){
+ printf("%s: fork failed\n", s);
+ exit(1);
+ }
+
+ if(pid == 0){
+ for(int i = 0; i < 100; i++){
+ char buf[32];
+ int fd = open("truncfile", O_WRONLY);
+ if(fd < 0){
+ printf("%s: open failed\n", s);
+ exit(1);
+ }
+ int n = write(fd, "1234567890", 10);
+ if(n != 10){
+ printf("%s: write got %d, expected 10\n", s, n);
+ exit(1);
+ }
+ close(fd);
+ fd = open("truncfile", O_RDONLY);
+ read(fd, buf, sizeof(buf));
+ close(fd);
+ }
+ exit(0);
+ }
+
+ for(int i = 0; i < 150; i++){
+ int fd = open("truncfile", O_CREATE|O_WRONLY|O_TRUNC);
+ if(fd < 0){
+ printf("%s: open failed\n", s);
+ exit(1);
+ }
+ int n = write(fd, "xxx", 3);
+ if(n != 3){
+ printf("%s: write got %d, expected 3\n", s, n);
+ exit(1);
+ }
+ close(fd);
+ }
+
+ wait(&xstatus);
+ unlink("truncfile");
+ exit(xstatus);
+}
+
+
// does chdir() call iput(p->cwd) in a transaction?
void
iputtest(char *s)
@@ -1038,11 +1384,15 @@ concreate(char *s)
close(open(file, 0));
close(open(file, 0));
close(open(file, 0));
+ close(open(file, 0));
+ close(open(file, 0));
} else {
unlink(file);
unlink(file);
unlink(file);
unlink(file);
+ unlink(file);
+ unlink(file);
}
if(pid == 0)
exit(0);
@@ -1106,7 +1456,7 @@ bigdir(char *s)
name[2] = '0' + (i % 64);
name[3] = '\0';
if(link("bd", name) != 0){
- printf("%s: bigdir link failed\n", s);
+ printf("%s: bigdir link(bd, %s) failed\n", s, name);
exit(1);
}
}
@@ -1335,8 +1685,8 @@ bigfile(char *s)
enum { N = 20, SZ=600 };
int fd, i, total, cc;
- unlink("bigfile");
- fd = open("bigfile", O_CREATE | O_RDWR);
+ unlink("bigfile.dat");
+ fd = open("bigfile.dat", O_CREATE | O_RDWR);
if(fd < 0){
printf("%s: cannot create bigfile", s);
exit(1);
@@ -1350,7 +1700,7 @@ bigfile(char *s)
}
close(fd);
- fd = open("bigfile", 0);
+ fd = open("bigfile.dat", 0);
if(fd < 0){
printf("%s: cannot open bigfile\n", s);
exit(1);
@@ -1379,7 +1729,7 @@ bigfile(char *s)
printf("%s: read bigfile wrong total\n", s);
exit(1);
}
- unlink("bigfile");
+ unlink("bigfile.dat");
}
void
@@ -1418,6 +1768,14 @@ fourteen(char *s)
printf("%s: mkdir 12345678901234/123456789012345 succeeded!\n", s);
exit(1);
}
+
+ // clean up
+ unlink("123456789012345/12345678901234");
+ unlink("12345678901234/12345678901234");
+ unlink("12345678901234/12345678901234/12345678901234");
+ unlink("123456789012345/123456789012345/123456789012345");
+ unlink("12345678901234/123456789012345");
+ unlink("12345678901234");
}
void
@@ -1512,7 +1870,8 @@ dirfile(char *s)
close(fd);
}
-// test that iput() is called at the end of _namei()
+// test that iput() is called at the end of _namei().
+// also tests empty file names.
void
iref(char *s)
{
@@ -1539,6 +1898,12 @@ iref(char *s)
unlink("xx");
}
+ // clean up
+ for(i = 0; i < NINODE + 1; i++){
+ chdir("..");
+ unlink("irefd");
+ }
+
chdir("/");
}
@@ -2087,13 +2452,35 @@ badarg(char *s)
exit(0);
}
+//
+// use sbrk() to count how many free physical memory pages there are.
+//
+int
+countfree()
+{
+ uint64 sz0 = (uint64)sbrk(0);
+ int n = 0;
+
+ while(1){
+ uint64 a = (uint64) sbrk(4096);
+ if(a == 0xffffffffffffffff){
+ break;
+ }
+ // modify the memory to make sure it's really allocated.
+ *(char *)(a - 1) = 1;
+ n += 1;
+ }
+ sbrk(-((uint64)sbrk(0) - sz0));
+ return n;
+}
+
// run each test in its own process. run returns 1 if child's exit()
// indicates success.
int
run(void f(char *), char *s) {
int pid;
int xstatus;
-
+
printf("test %s: ", s);
if((pid = fork()) < 0) {
printf("runtest: fork error\n");
@@ -2105,9 +2492,9 @@ run(void f(char *), char *s) {
} else {
wait(&xstatus);
if(xstatus != 0)
- printf("FAILED\n", s);
+ printf("FAILED\n");
else
- printf("OK\n", s);
+ printf("OK\n");
return xstatus == 0;
}
}
@@ -2115,15 +2502,30 @@ run(void f(char *), char *s) {
int
main(int argc, char *argv[])
{
- char *n = 0;
- if(argc > 1) {
- n = argv[1];
+ int continuous = 0;
+ char *justone = 0;
+
+ if(argc == 2 && strcmp(argv[1], "-c") == 0){
+ continuous = 1;
+ } else if(argc == 2 && argv[1][0] != '-'){
+ justone = argv[1];
+ } else if(argc > 1){
+ printf("Usage: usertests [-c] [testname]\n");
+ exit(1);
}
struct test {
void (*f)(char *);
char *s;
} tests[] = {
+ {copyin, "copyin"},
+ {copyout, "copyout"},
+ {copyinstr1, "copyinstr1"},
+ {copyinstr2, "copyinstr2"},
+ {copyinstr3, "copyinstr3"},
+ {truncate1, "truncate1"},
+ {truncate2, "truncate2"},
+ {truncate3, "truncate3"},
{reparent2, "reparent2"},
{pgbug, "pgbug" },
{sbrkbugs, "sbrkbugs" },
@@ -2173,25 +2575,48 @@ main(int argc, char *argv[])
{bigdir, "bigdir"}, // slow
{ 0, 0},
};
-
- printf("usertests starting\n");
- if(open("usertests.ran", 0) >= 0){
- printf("already ran user tests -- rebuild fs.img (rm fs.img; make fs.img)\n");
- exit(1);
+ if(continuous){
+ printf("continuous usertests starting\n");
+ while(1){
+ int fail = 0;
+ int free0 = countfree();
+ for (struct test *t = tests; t->s != 0; t++) {
+ if(!run(t->f, t->s)){
+ fail = 1;
+ break;
+ }
+ }
+ if(fail){
+ printf("SOME TESTS FAILED\n");
+ exit(1);
+ }
+ int free1 = countfree();
+ if(free1 < free0){
+ printf("FAILED -- lost some free pages\n");
+ exit(1);
+ }
+ }
}
- close(open("usertests.ran", O_CREATE));
+ printf("usertests starting\n");
+ int free0 = countfree();
int fail = 0;
for (struct test *t = tests; t->s != 0; t++) {
- if((n == 0) || strcmp(t->s, n) == 0) {
+ if((justone == 0) || strcmp(t->s, justone) == 0) {
if(!run(t->f, t->s))
fail = 1;
}
}
- if(!fail)
- printf("ALL TESTS PASSED\n");
- else
+
+ if(fail){
printf("SOME TESTS FAILED\n");
- exit(1); // not reached.
+ exit(1);
+ } else if(countfree() < free0){
+ printf("FAILED -- lost some free pages\n");
+ exit(1);
+ } else {
+ printf("ALL TESTS PASSED\n");
+ exit(0);
+ }
}