+Modify the file system to keep a cache of file blocks. When a request
+is made to read or write a block, check to see if it is in the
+cache, and if so, use the cached data without going to
+disk. Otherwise, fetch the block from disk into the cache, evicting an
+older entry if necessary. You are limited to a cache no greater than 64
+sectors in size.
+
+You must implement a cache replacement algorithm that is at least as
+good as the ``clock'' algorithm. We encourage you to account for
+the generally greater value of metadata compared to data. Experiment
+to see what combination of accessed, dirty, and other information
+results in the best performance, as measured by the number of disk
+accesses.
+
+You can keep a cached copy of the free map permanently in memory if you
+like. It doesn't have to count against the cache size.
+
+The provided inode code uses a ``bounce buffer'' allocated with
+@func{malloc} to translate the disk's sector-by-sector interface into
+the system call interface's byte-by-byte interface. You should get rid
+of these bounce buffers. Instead, copy data into and out of sectors in
+the buffer cache directly.
+
+Your cache should be @dfn{write-behind}, that is,
+keep dirty blocks in the cache, instead of immediately writing modified
+data to disk. Write dirty blocks to disk whenever they are evicted.
+Because write-behind makes your file system more fragile in the face of
+crashes, in addition you should periodically write all dirty, cached
+blocks back to disk. The cache should also be written back to disk in
+@func{filesys_done}, so that halting Pintos flushes the cache.
+
+If you have @func{timer_sleep} from the first project working, write-behind is
+an excellent application. Otherwise, you may implement a less general
+facility, but make sure that it does not exhibit busy-waiting.
+
+You should also implement @dfn{read-ahead}, that is,
+automatically fetch the next block of a file
+into the cache when one block of a file is read, in case that block is
+about to be read.
+Read-ahead is only really useful when done asynchronously. That means,
+if a process requests disk block 1 from the file, it should block until disk
+block 1 is read in, but once that read is complete, control should
+return to the process immediately. The read-ahead request for disk
+block 2 should be handled asynchronously, in the background.
+
+@strong{We recommend integrating the cache into your design early.} In
+the past, many groups have tried to tack the cache onto a design late in
+the design process. This is very difficult. These groups have often
+turned in projects that failed most or all of the tests.
+
+@node File System Synchronization
+@subsection Synchronization
+
+The provided file system requires external synchronization, that is,
+callers must ensure that only one thread can be running in the file
+system code at once. Your submission must adopt a finer-grained
+synchronization strategy that does not require external synchronization.
+To the extent possible, operations on independent entities should be
+independent, so that they do not need to wait on each other.
+
+Operations on different cache blocks must be independent. In
+particular, when I/O is required on a particular block, operations on
+other blocks that do not require I/O should proceed without having to
+wait for the I/O to complete.
+
+Multiple processes must be able to access a single file at once.
+Multiple reads of a single file must be able to complete without
+waiting for one another. When writing to a file does not extend the
+file, multiple processes should also be able to write a single file at
+once. A read of a file by one process when the file is being written by
+another process is allowed to show that none, all, or part of the write
+has completed. (However, after the @code{write} system call returns to
+its caller, all subsequent readers must see the change.) Similarly,
+when two processes simultaneously write to the same part of a file,
+their data may be interleaved.
+
+On the other hand, extending a file and writing data into the new
+section must be atomic. Suppose processes A and B both have a given
+file open and both are positioned at end-of-file. If A reads and B
+writes the file at the same time, A may read all, part, or none of what
+B writes. However, A may not read data other than what B writes, e.g.@:
+if B's data is all nonzero bytes, A is not allowed to see any zeros.
+
+Operations on different directories should take place concurrently.
+Operations on the same directory may wait for one another.
+
+Keep in mind that only data shared by multiple threads needs to be
+synchronized. In the base file system, @struct{file} and @struct{dir}
+are accessed only by a single thread.
+
+@node Project 4 FAQ
+@section FAQ