4: mmap() – eager and lazy

In this homework, we learn a little bit about memory management by adding a widely used Unix feature to xv6: mmap(). While mmap can be (and is) used to allocate large chunks of memory, the more interesting use of mmap() is that of mapping a file into memory. This means, you call mmap once, with a file descriptor as argument, and the file immediately appears in virtual memory.

There are at least two main ways to do this. The first is eager: when mmap is called, have the kernel read the file as instructed, put it somewhere convenient in memory, and return a pointer to the location. The second is lazy: take note of the user's request, and return without doing anything further. When the user tries to access the memory, deal with the resulting page-fault, reading in only those pages that the user tries to read, when the user tries to read them.

Getting started Heading link

As in the past, git fetch the latest changes, then checkout the origin/hw4 branch which contains some minimal template code, and some more extensive testing code. To test your solution, rebuild and start xv6, then run eager_mmaplazy_mmap and bad_mmap from the xv6 command line.

sys_mmap() Heading link

The system call sys_mmap() has already been created for you, only it doesn’t do much yet. The majority of the homework solution should go here, or in functions called by sys_mmap(). When you run the test programs lazy_mmap and eager_mmap, they crash with the current sys_mmap() implementation. This is to be expected.

Eager solution Heading link

In the eager solution, where the lazy argument is 0sys_mmap() allocates and maps all the memory needed for the file contents (see allocuvm() for an example of how to do this, but for the heap), and reads all of the file contents into the newly allocated memory. To read part of a file, you can use fileread() in file.c, or use it as a template for your own implementation using readi(). Basically, you just want the code that runs for type == FD_INODE.

For both the eager and the lazy solution, you should map mmap() regions into addresses 0x40000000 and above – halfway between zero and the kernel area at 0x80000000. You should expect there to be more than one call to mmap(), so you can’t overwrite/reuse any mmap areas you created in earlier calls. You’ll want to store any state you need to keep inside struct proc.

To test your program, run the user program eager_mmap which exists in the hw4 branch from the xv6 command line.

Lazy solution Heading link

The lazy solution works quite differently. When the lazy argument is 1sys_mmap() should not allocate or map any memory, nor does it read anything from disk. Instead, it records the request in struct proc, and returns a pointer immediately. Initially, this pointer points to an unallocated and unmapped part of the virtual address space.

Later, when the process tries to read from or write to the memory area it just mmap ed, a page fault occurs. You should create page fault handling code (in trap.c, or called from trap.c) that allocates the appropriate page to serve this read/write, and fills the page with the appropriate contents from the file. To figure out what address the program tried to access, just read the CR2 register. There is a handy helper function for this, called rcr2(), defined in x86.h.

To test your program, run the user program lazy_mmap. The hw4 template has a modification to exit(), that prints out the number of system free pages before exiting. The lazy solution should have about 17 more free pages than the eager solution. A full sample of the correct solution output is provided below.

Bonus problem Heading link

Using some of your code for homework 3, and the display device file from the hw3 template, implement mmap() for the display device file, and a modify imshow.c to use mmap() instead of read() and write().

Turn-in Heading link

As in the past, follow this invitation link to get a turn-in repo. push your local hw4 branch to a branch named hw4 in your turn-in repo. To verify the correctness of your patch, clone the turn in repo in a new folder, checkout hw4, build and test.

Sample output Heading link

$ eager_mmap
About to make first mmap. Next, you should see the first sentence from README
xv6 is a re-implementation of Dennis Ritchie's and Ken Thompson's Unix
Version 6 (v6)

Second mmap coming
xv6 @ UIC ROCKS!!!

Exiting process. System free pages is 56761
$ lazy_mmap
About to make first mmap. Next, you should see the first sentence from README
xv6 is a re-implementation of Dennis Ritchie's and Ken Thompson's Unix
Version 6 (v6)

Second mmap coming
xv6 @ UIC ROCKS!!!

Exiting process. System free pages is 56778