vm
directory
of NACHOS. Your goal is to implement demand-paged virtual memory.
The main things that you have
to do are summarized as follows.
SWAP
. The swap file should
be accessed using the NACHOS OpenFile
class.
You can use the filesystem stub routines (the default), so that the
SWAP
file is created as a Unix file. You do not need to test again later using Part 2.
sort
program in the
test
directory is an example of
a program designed to stress the virtual memory system.
Page tables were used in assignment 2 to simplify memory allocation
and to isolate failures from one address space from affecting other
programs. In this assignment we will use page tables to tell the
hardware which pages are resident in physical memory and which are
only resident on the disk. If the valid bit in a particular page table
entry is set, the hardware assumes that the corresponding virtual page
is loaded into physical memory in the physical page frame specified by
the physicalPage field. Whenever the program generates an access to
that virtual page, the hardware accesses the physical page. If the
valid bit is not set, the hardware generates a page fault exception
whenever the program accesses that virtual page. Your exception
handler will then find a free physical page frame, read the page in
from the backing store (typically a paging file) to that physical page
frame, update the page table to reflect the new virtual to physical
mapping, and restart the program. The hardware will then resume the
execution of the program at the instruction that generated the
fault. This time the access should go through, since the page has been
loaded into physical memory.Additional Information
To find a free frame, your exception fault handler may need to eject a cached page from its physical page frame. If the ejected page has been modified in the physical memory, the page fault handling code must write the page out to the backing store before reading the accessed page into its physical page frame. The hardware maintains some information that will help the page fault handler determine which steps need to be taken on a page fault. In addition to the valid bit, every page table entry contains a use and a dirty bit. The hardware sets the use bit every time it accesses the corresponding page; if the access is a write the hardware also sets the dirty bit. Your code may use these bits in its page fault handling code. For example, your code can use the dirty bit to determine if it needs to write an ejected page back to the backing store. When a page is read in from disk, the page fault handler should clear the dirty and use bits in its page table entry. If the page is ever ejected, the page fault handler checks its dirty bit. If the dirty bit is still clear, the copy of the page on disk is identical to the copy in physical memory and there is no need to write the page back to disk before ejecting it.
On a page fault, the kernel must decide which page to replace; ideally, it will throw out a page that will not be referenced for a long time, keeping pages in memory those that are soon to be referenced. Another consideration is that the operating system may be able to avoid the overhead of writing modified pages to disk inside the page fault handler by writing modified pages to disk in advance. The page fault handler can take advantage of the clean physical page frame to complete subsequent page faults more quickly. FIFO replacement policy is the easiest one to implement, so you may want to start from there to test your page swapping mechanism. But in reality, FIFO replacement policy is rarely used due to its bad performance. You will have to implement some other more efficient replacement policy in your final version, such as FIFO with second chance or LRU.
Click here for suggested implementation steps.
Part II: Building a File System
The multiprogramming and virtual memory assignments made use of the
Nachos file system with the stub version.
The last phase of your project is to use the Nachos' own file system
and enhance its functionality. Your implementation should be under sub-directory "filesys".
The first step is to read and understand the partial file system we have written for you under filesys sub-directory. Run the program `nachos -f -cp test/small small' for a simple test case of our code - `-f' formats the emulated physical disk, and `-cp' copies the UNIX file `test/small' onto that disk.
The files to focus on are:
Our file system has a UNIX-like interface, so you may also wish to read the UNIX man pages for creat, open, close, read, write, lseek, and unlink (e.g., type "man creat"). Our file system has calls that are similar (but not identical) to these; the file system translates these calls into physical disk operations. One major difference is that our file system is implemented in C++. Create (like UNIX creat), Open (open), and Remove (unlink) are defined on the FileSystem object, since they involve manipulating file names and directories. FileSystem::Open returns a pointer to an OpenFile object, which is used for direct file operations such as Seek (lseek), Read (read), Write (write). An open file is "closed" by deleting the OpenFile object.
Many of the data structures in our file system are stored both in memory and on disk. To provide some uniformity, all these data structures have a "FetchFrom" procedure that reads the data off disk and into memory, and a "WriteBack" procedure that stores the data back to disk. Note that the in memory and on disk representations do not have to be identical.
You are asked to modify the file system to allow the maximum size of a file to be as large as
100Kbytes. In the basic
file system, each file is limited to a file size of just under 4Kbytes.
Each file has a header (class FileHeader) that is a table of direct
pointers to the disk blocks for that file (called i-node in Unix). Since the header is stored
in one disk sector with 128 bytes, the maximum size of a file is limited by the number
of pointers that will fit in one disk sector. Two things need to be done.
Tasks (What to Extend)
There are two options to solve this problem. The first option is to initially allocate sufficient space for the i-node structure as if the size were 100K bytes. But you donot actually allocate disk blocks for data until they are needed when executing system call Write(). The second option is to initially set the file size as 0 and gradually expand the file size. You choose one option in the code implementation. In your submitted writeup, you should compare these two designs, discuss the trade-offs, and explain what you have chosen with detailed implementation steps.
Here are some things you should be sure to get right:
Issues to Consider
Notice that for the input program file, you can still use the regular Unix file system to read its content.
Currently, the basic file system code assumes it is accessed by a single thread at a time. You can still keep this assumption for this part of the assignment while in a real system, synchronization is needed to allow multiple threads to use file system concurrently.
Given everybody is busy espcially towards the end of the quarter, it is very useful to play trade-offs in completing this project. Understand the design options, but choose something simple and easy to do. You should first try to complete this project with minimal efforts to pass these test programs. The hidden test program used in grading are very similar to these public cases and complex test cases will not be used for grading. When requirements for certain features are vague or not specified, choose something that is easy to do.
Click here for suggested implementation steps.
For the following outputs, [pid] is the id of the process on which behalf the operation is performed. [virtualPage] is the involved virtual page number (i.e. the page index into the process virtual address space) and [physicalPage] is the involved physical page number (i.e., the page index into the physical memory of the Nachos virtual machine).
L [pid]: [virtualPage] -> [physicalPage]
S [pid]: [physicalPage]
E [pid]: [physicalPage]
D [pid]: [virtualPage]
Z [pid]: [virtualPage]
For the following outputs, [pid] is the id of the process on which behalf the operation is performed. [fileID] is the ID of the file upon which the operation is performed. [oldSize] previous size of the object (in bytes or entries) and [newSize] is the size it was extended to.
F [pid][fileID]: [oldSize] -> [newSize]
You need to design and develop test cases. You will be able to test part 1 without having part 2 implemented.
You will be able to test part 2 without having part 1 implemented.
You can wrap your part 1 and part 2 implementations in #defines to
allow each to be "removed" allowing the other to be tested
independently.
As a simplification,
you donot need to test cases that work with both virtual memory and extended file system.
Testing Strategy
The following tips are useful:
Examples of usage:
csil$ pwd cs170/nachos/code/filesys csil$ ./nachos -f -cp ../test2/Prog1 Prog1 -x Prog1
If there are more than one file referenced in Prog1 (via Exec), to pass each on the command line as such:
csil$ ./nachos -f -cp ../test2/Prog1 Prog1 -cp ../test2/Prog2 Prog2 -x Prog1
Now the Open and close calls will need to work in a _flat_ namespace there is no "mkdir" in nachos so all files on the Nachos disk are in the same un-named directory. This might mean changing the .c files you are testing part 2 with by removing all references to ../test.
HW3_WRITEUP
in which you have to mention
which portions of the assignment you have been able to complete. And for the ones
that are incomplete, what is their current status.
When you just submit something that does not work and give no explanations, expect to receive no credit.
This report will be graded.
You can turnin up to 3 times per project and not more than that!
The earlier versions will be discarded.
Note: only one turnin per group is accepted!