Lab 4 : File System
Computer Science 377
Due: Monday, December 13th, 11:59 PM
Build a file system
The system calls and multiprogramming assignments made use of the Nachos
file system. The fourth phase of Nachos is to actually build some parts
of this file system. As in the first two assignments, we give you some
of the code you need; your job is to complete the file system and enhance
it.
The first step is to read and understand the partial file system we
have written for you. 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:
-
fstest.cc
--- a simple test case for our file system.
-
filesys.{h, cc} ---
top-level interface to the file system.
-
directory.{h, cc} --- translates
file names to disk file headers; the directory data structure is stored
as a file.
-
filehdr.{h, cc} ---
manages the data structure representing the layout of a file's data on
disk.
-
openfile.{h, cc} ---
translates file reads and writes to disk sector reads and writes.
-
synchdisk.{h,cc} --- provides
synchronous access to the asynchronous physical disk, so that threads block
until their requests have completed.
-
disk.{h, cc}
--- emulates a physical disk, by sending requests to
read and write disk blocks to a UNIX file and then generating an interrupt
after some period of time. The details
of how to make read and write requests varies tremendously from disk device
to disk device; in practice, you would want to hide these details behind
something like the abstraction provided by this module.
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.
While our code implements all the major pieces of a file system, it
has some limitations. Your job will be to fix these limitations. Keep in
mind that there are, of course, interactions between the various parts
of this assignment.
The Assignment
Problem 1
Complete the basic file system by adding synchronization to allow multiple
threads to use file system concurrently. Currently, the file system code
assumes it is accessed by a single thread at a time. In addition to ensuring
that internal data structures are not corrupted, your modified file system
must observe the following constraints (these are the same as in UNIX):
-
The same file may be read/written by more than one thread concurrently.
Each thread separately opens the file, giving it its own private seek position
within the file. Thus, two threads can both sequentially read through the
same file without interfering with one another.
-
All file system operations must be atomic and serializable. For example,
if one thread is in the middle of a file write, a thread concurrently reading
the file will see either all of the change or none of it. Further, if the
OpenFile::Write operation finishes before the call to OpenFile::Read is
started, the Read must reflect the modified version of the file.
-
When a file is deleted, threads with the file already open may continue
to read and write the file until they close the file. Deleting a file (FileSystem::Remove)
must prevent further opens on that file, but the disk blocks for the file
cannot be reclaimed until the file has been closed by all threads that
currently have the file open.
Hint: to do this part, you will probably find you need to maintain
a table of open files.
Problem 2
Modify the file system to allow the maximum size of a file to be as
large as the disk (128Kbytes). 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. Since
the header is stored in one disk sector, the maximum size of a file is
limited by the number of pointers that will fit in one disk sector. Increasing
the limit to 128KBytes will probably but not necessarily require you to
implement doubly indirect blocks.
Problem 3
Implement extensible files. In the basic file system, the file size
is specified when the file is created. One advantage of this is that the
FileHeader data structure, once created, never changes. In UNIX and most
other file systems, a file is initially created with size 0 and is then
expanded every time a write is made off the end of the file. Modify the
file system to allow this; as one test case, allow the directory file to
expand beyond its current limit of ten files. In doing this part, be careful
that concurrent accesses to the file header remain properly synchronized.