summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile1
-rw-r--r--conf/lab.mk2
-rwxr-xr-xgrade-lab-mmap57
-rw-r--r--kernel/fcntl.h10
-rw-r--r--kernel/param.h8
-rw-r--r--user/mmaptest.c304
-rw-r--r--user/user.h9
7 files changed, 382 insertions, 9 deletions
diff --git a/Makefile b/Makefile
index 8e50dfe..4c3d16a 100644
--- a/Makefile
+++ b/Makefile
@@ -240,7 +240,6 @@ UPROGS += \
$U/_bigfile
endif
-
UPROGS += \
$U/_nettests
diff --git a/conf/lab.mk b/conf/lab.mk
index 748adb5..68b06fc 100644
--- a/conf/lab.mk
+++ b/conf/lab.mk
@@ -1 +1 @@
-LAB=fs
+LAB=mmap
diff --git a/grade-lab-mmap b/grade-lab-mmap
new file mode 100755
index 0000000..b5c2820
--- /dev/null
+++ b/grade-lab-mmap
@@ -0,0 +1,57 @@
+#!/usr/bin/env python3
+
+import re
+from gradelib import *
+
+r = Runner(save("xv6.out"))
+
+@test(0, "running mmaptest")
+def test_mmaptest():
+ r.run_qemu(shell_script([
+ 'mmaptest'
+ ]), timeout=180)
+
+@test(20, "mmaptest: mmap f", parent=test_mmaptest)
+def test_mmaptest_mmap_f():
+ r.match('^test mmap f: OK$')
+
+@test(10, "mmaptest: mmap private", parent=test_mmaptest)
+def test_mmaptest_mmap_private():
+ r.match('^test mmap private: OK$')
+
+@test(10, "mmaptest: mmap read-only", parent=test_mmaptest)
+def test_mmaptest_mmap_readonly():
+ r.match('^test mmap read-only: OK$')
+
+@test(10, "mmaptest: mmap read/write", parent=test_mmaptest)
+def test_mmaptest_mmap_readwrite():
+ r.match('^test mmap read/write: OK$')
+
+@test(10, "mmaptest: mmap dirty", parent=test_mmaptest)
+def test_mmaptest_mmap_dirty():
+ r.match('^test mmap dirty: OK$')
+
+@test(10, "mmaptest: not-mapped unmap", parent=test_mmaptest)
+def test_mmaptest_mmap_unmap():
+ r.match('^test not-mapped unmap: OK$')
+
+@test(10, "mmaptest: two files", parent=test_mmaptest)
+def test_mmaptest_mmap_two():
+ r.match('^test mmap two files: OK$')
+
+@test(40, "mmaptest: fork_test", parent=test_mmaptest)
+def test_mmaptest_fork_test():
+ r.match('^fork_test OK$')
+
+@test(19, "usertests")
+def test_usertests():
+ r.run_qemu(shell_script([
+ 'usertests -q'
+ ]), timeout=300)
+ r.match('^ALL TESTS PASSED$')
+
+@test(1, "time")
+def test_time():
+ check_time()
+
+run_tests()
diff --git a/kernel/fcntl.h b/kernel/fcntl.h
index d7bb43b..832894c 100644
--- a/kernel/fcntl.h
+++ b/kernel/fcntl.h
@@ -4,3 +4,13 @@
#define O_NOFOLLOW 0x010
#define O_CREATE 0x200
#define O_TRUNC 0x400
+
+#ifdef LAB_MMAP
+#define PROT_NONE 0x0
+#define PROT_READ 0x1
+#define PROT_WRITE 0x2
+#define PROT_EXEC 0x4
+
+#define MAP_SHARED 0x01
+#define MAP_PRIVATE 0x02
+#endif
diff --git a/kernel/param.h b/kernel/param.h
index 431741f..4ed7a51 100644
--- a/kernel/param.h
+++ b/kernel/param.h
@@ -13,11 +13,5 @@
#define MAXOPBLOCKS 10 // max # of blocks any FS op writes
#define LOGSIZE (MAXOPBLOCKS*3) // max data blocks in on-disk log
#define NBUF (MAXOPBLOCKS*3) // size of disk block cache
-#ifdef LAB_FS
-#define FSSIZE 200000 // size of file system in blocks
-#else
-#define FSSIZE 2000 // size of file system in blocks
-#endif
+#define FSSIZE 200000 // size of file system in blocks
#define MAXPATH 128 // maximum file path name
-
-
diff --git a/user/mmaptest.c b/user/mmaptest.c
new file mode 100644
index 0000000..4a94e44
--- /dev/null
+++ b/user/mmaptest.c
@@ -0,0 +1,304 @@
+#include "kernel/param.h"
+#include "kernel/fcntl.h"
+#include "kernel/types.h"
+#include "kernel/stat.h"
+#include "kernel/riscv.h"
+#include "kernel/fs.h"
+#include "user/user.h"
+
+void mmap_test();
+void fork_test();
+char buf[BSIZE];
+
+#define MAP_FAILED ((char *) -1)
+
+int
+main(int argc, char *argv[])
+{
+ mmap_test();
+ fork_test();
+ printf("mmaptest: all tests succeeded\n");
+ exit(0);
+}
+
+char *testname = "???";
+
+void
+err(char *why)
+{
+ printf("mmaptest: %s failed: %s, pid=%d\n", testname, why, getpid());
+ exit(1);
+}
+
+//
+// check the content of the two mapped pages.
+//
+void
+_v1(char *p)
+{
+ int i;
+ for (i = 0; i < PGSIZE*2; i++) {
+ if (i < PGSIZE + (PGSIZE/2)) {
+ if (p[i] != 'A') {
+ printf("mismatch at %d, wanted 'A', got 0x%x\n", i, p[i]);
+ err("v1 mismatch (1)");
+ }
+ } else {
+ if (p[i] != 0) {
+ printf("mismatch at %d, wanted zero, got 0x%x\n", i, p[i]);
+ err("v1 mismatch (2)");
+ }
+ }
+ }
+}
+
+//
+// create a file to be mapped, containing
+// 1.5 pages of 'A' and half a page of zeros.
+//
+void
+makefile(const char *f)
+{
+ int i;
+ int n = PGSIZE/BSIZE;
+
+ unlink(f);
+ int fd = open(f, O_WRONLY | O_CREATE);
+ if (fd == -1)
+ err("open");
+ memset(buf, 'A', BSIZE);
+ // write 1.5 page
+ for (i = 0; i < n + n/2; i++) {
+ if (write(fd, buf, BSIZE) != BSIZE)
+ err("write 0 makefile");
+ }
+ if (close(fd) == -1)
+ err("close");
+}
+
+void
+mmap_test(void)
+{
+ int fd;
+ int i;
+ const char * const f = "mmap.dur";
+ printf("mmap_test starting\n");
+ testname = "mmap_test";
+
+ //
+ // create a file with known content, map it into memory, check that
+ // the mapped memory has the same bytes as originally written to the
+ // file.
+ //
+ makefile(f);
+ if ((fd = open(f, O_RDONLY)) == -1)
+ err("open (1)");
+
+ printf("test mmap f\n");
+ //
+ // this call to mmap() asks the kernel to map the content
+ // of open file fd into the address space. the first
+ // 0 argument indicates that the kernel should choose the
+ // virtual address. the second argument indicates how many
+ // bytes to map. the third argument indicates that the
+ // mapped memory should be read-only. the fourth argument
+ // indicates that, if the process modifies the mapped memory,
+ // that the modifications should not be written back to
+ // the file nor shared with other processes mapping the
+ // same file (of course in this case updates are prohibited
+ // due to PROT_READ). the fifth argument is the file descriptor
+ // of the file to be mapped. the last argument is the starting
+ // offset in the file.
+ //
+ char *p = mmap(0, PGSIZE*2, PROT_READ, MAP_PRIVATE, fd, 0);
+ if (p == MAP_FAILED)
+ err("mmap (1)");
+ _v1(p);
+ if (munmap(p, PGSIZE*2) == -1)
+ err("munmap (1)");
+
+ printf("test mmap f: OK\n");
+
+ printf("test mmap private\n");
+ // should be able to map file opened read-only with private writable
+ // mapping
+ p = mmap(0, PGSIZE*2, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
+ if (p == MAP_FAILED)
+ err("mmap (2)");
+ if (close(fd) == -1)
+ err("close (1)");
+ _v1(p);
+ for (i = 0; i < PGSIZE*2; i++)
+ p[i] = 'Z';
+ if (munmap(p, PGSIZE*2) == -1)
+ err("munmap (2)");
+
+ printf("test mmap private: OK\n");
+
+ printf("test mmap read-only\n");
+
+ // check that mmap doesn't allow read/write mapping of a
+ // file opened read-only.
+ if ((fd = open(f, O_RDONLY)) == -1)
+ err("open (2)");
+ p = mmap(0, PGSIZE*3, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+ if (p != MAP_FAILED)
+ err("mmap (3)");
+ if (close(fd) == -1)
+ err("close (2)");
+
+ printf("test mmap read-only: OK\n");
+
+ printf("test mmap read/write\n");
+
+ // check that mmap does allow read/write mapping of a
+ // file opened read/write.
+ if ((fd = open(f, O_RDWR)) == -1)
+ err("open (3)");
+ p = mmap(0, PGSIZE*3, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+ if (p == MAP_FAILED)
+ err("mmap (4)");
+ if (close(fd) == -1)
+ err("close (3)");
+
+ // check that the mapping still works after close(fd).
+ _v1(p);
+
+ // write the mapped memory.
+ for (i = 0; i < PGSIZE*2; i++)
+ p[i] = 'Z';
+
+ // unmap just the first two of three pages of mapped memory.
+ if (munmap(p, PGSIZE*2) == -1)
+ err("munmap (3)");
+
+ printf("test mmap read/write: OK\n");
+
+ printf("test mmap dirty\n");
+
+ // check that the writes to the mapped memory were
+ // written to the file.
+ if ((fd = open(f, O_RDWR)) == -1)
+ err("open (4)");
+ for (i = 0; i < PGSIZE + (PGSIZE/2); i++){
+ char b;
+ if (read(fd, &b, 1) != 1)
+ err("read (1)");
+ if (b != 'Z')
+ err("file does not contain modifications");
+ }
+ if (close(fd) == -1)
+ err("close (4)");
+
+ printf("test mmap dirty: OK\n");
+
+ printf("test not-mapped unmap\n");
+
+ // unmap the rest of the mapped memory.
+ if (munmap(p+PGSIZE*2, PGSIZE) == -1)
+ err("munmap (4)");
+
+ printf("test not-mapped unmap: OK\n");
+
+ printf("test mmap two files\n");
+
+ //
+ // mmap two files at the same time.
+ //
+ int fd1;
+ if((fd1 = open("mmap1", O_RDWR|O_CREATE)) < 0)
+ err("open (5)");
+ if(write(fd1, "12345", 5) != 5)
+ err("write (1)");
+ char *p1 = mmap(0, PGSIZE, PROT_READ, MAP_PRIVATE, fd1, 0);
+ if(p1 == MAP_FAILED)
+ err("mmap (5)");
+ if (close(fd1) == -1)
+ err("close (5)");
+ if (unlink("mmap1") == -1)
+ err("unlink (1)");
+
+ int fd2;
+ if((fd2 = open("mmap2", O_RDWR|O_CREATE)) < 0)
+ err("open (6)");
+ if(write(fd2, "67890", 5) != 5)
+ err("write (2)");
+ char *p2 = mmap(0, PGSIZE, PROT_READ, MAP_PRIVATE, fd2, 0);
+ if(p2 == MAP_FAILED)
+ err("mmap (6)");
+ if (close(fd2) == -1)
+ err("close (6)");
+ if (unlink("mmap2") == -1)
+ err("unlink (2)");
+
+ if(memcmp(p1, "12345", 5) != 0)
+ err("mmap1 mismatch");
+ if(memcmp(p2, "67890", 5) != 0)
+ err("mmap2 mismatch");
+
+ if (munmap(p1, PGSIZE) == -1)
+ err("munmap (5)");
+ if(memcmp(p2, "67890", 5) != 0)
+ err("mmap2 mismatch (2)");
+ if (munmap(p2, PGSIZE) == -1)
+ err("munmap (6)");
+
+ printf("test mmap two files: OK\n");
+
+ printf("mmap_test: ALL OK\n");
+}
+
+//
+// mmap a file, then fork.
+// check that the child sees the mapped file.
+//
+void
+fork_test(void)
+{
+ int fd;
+ int pid;
+ const char * const f = "mmap.dur";
+
+ printf("fork_test starting\n");
+ testname = "fork_test";
+
+ // mmap the file twice.
+ makefile(f);
+ if ((fd = open(f, O_RDONLY)) == -1)
+ err("open (7)");
+ if (unlink(f) == -1)
+ err("unlink (3)");
+ char *p1 = mmap(0, PGSIZE*2, PROT_READ, MAP_SHARED, fd, 0);
+ if (p1 == MAP_FAILED)
+ err("mmap (7)");
+ char *p2 = mmap(0, PGSIZE*2, PROT_READ, MAP_SHARED, fd, 0);
+ if (p2 == MAP_FAILED)
+ err("mmap (8)");
+
+ // read just 2nd page.
+ if(*(p1+PGSIZE) != 'A')
+ err("fork mismatch (1)");
+
+ if((pid = fork()) < 0)
+ err("fork");
+ if (pid == 0) {
+ _v1(p1);
+ if (munmap(p1, PGSIZE) == -1) // just the first page
+ err("munmap (7)");
+ exit(0); // tell the parent that the mapping looks OK.
+ }
+
+ int status = -1;
+ wait(&status);
+
+ if(status != 0){
+ printf("fork_test failed\n");
+ exit(1);
+ }
+
+ // check that the parent's mappings are still there.
+ _v1(p1);
+ _v1(p2);
+
+ printf("fork_test OK\n");
+}
diff --git a/user/user.h b/user/user.h
index c1bccdd..ed7737a 100644
--- a/user/user.h
+++ b/user/user.h
@@ -35,11 +35,14 @@ int pgaccess(void *base, int len, void *mask);
// usyscall region
int ugetpid(void);
#endif
+<<<<<<< HEAD
+=======
int trace(int);
int sysinfo(struct sysinfo*);
int sigalarm(int ticks, void (*handler)());
int sigreturn(void);
int symlink(char *, char *);
+>>>>>>> fs
// ulib.c
int stat(const char*, struct stat*);
@@ -57,6 +60,12 @@ void free(void*);
int atoi(const char*);
int memcmp(const void *, const void *, uint);
void *memcpy(void *, const void *, uint);
+<<<<<<< HEAD
+#ifdef LAB_LOCK
+int statistics(void*, int);
+#endif
+=======
// statistics.c
int statistics(void*, int);
+>>>>>>> fs