diff options
| author | Frans Kaashoek <kaashoek@mit.edu> | 2020-08-10 13:05:17 -0400 | 
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-08-10 13:05:17 -0400 | 
| commit | c31d35d8031c88b7e1ea8657cc9806dfdd4c3ef9 (patch) | |
| tree | a6c903e1c61c08f4cb87700c320752a737081dcb /user | |
| parent | 90eb90b5e203299427c3fde8c996a48835fc93cf (diff) | |
| parent | d8fe1773b26758c7c7b8f36724cd822555b33612 (diff) | |
| download | xv6-labs-c31d35d8031c88b7e1ea8657cc9806dfdd4c3ef9.tar.gz xv6-labs-c31d35d8031c88b7e1ea8657cc9806dfdd4c3ef9.tar.bz2 xv6-labs-c31d35d8031c88b7e1ea8657cc9806dfdd4c3ef9.zip | |
Merge branch 'riscv' into riscv
Diffstat (limited to 'user')
| -rw-r--r-- | user/alarmtest.c | 88 | ||||
| -rw-r--r-- | user/cat.c | 8 | ||||
| -rw-r--r-- | user/grind.c | 333 | ||||
| -rw-r--r-- | user/sh.c | 2 | ||||
| -rw-r--r-- | user/ulib.c | 31 | ||||
| -rw-r--r-- | user/user.h | 2 | ||||
| -rw-r--r-- | user/usertests.c | 471 | 
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"); -  } -} @@ -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); +} @@ -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); +  }  } | 
