diff options
-rw-r--r-- | Makefile | 1 | ||||
-rw-r--r-- | conf/lab.mk | 2 | ||||
-rwxr-xr-x | grade-lab-mmap | 57 | ||||
-rw-r--r-- | kernel/fcntl.h | 10 | ||||
-rw-r--r-- | kernel/param.h | 8 | ||||
-rw-r--r-- | user/mmaptest.c | 304 | ||||
-rw-r--r-- | user/user.h | 9 |
7 files changed, 382 insertions, 9 deletions
@@ -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 |