next up previous contents
Next: Common Errors Up: Experience With Nachos Assignments Previous: Virtual Memory

File System

Locking is a major pain because WriteAt calls ReadAt (on occasion). One probably wants to lock for both reads and writes, but if one already has the lock (while writing) and then calls read, potential deadlock scenarios appear immediately. Here are some particularly tricky cases:

  1. It is tempting to have a single lock per file, which one acquires as the first step in beginning a read or write. However, there are cases where WriteAt also calls ReadAt. Specifically, if WriteAt needs to write a partial sector, it must first read the sector and then update the subset of that sector the WriteAt refers to. However, if ReadAt attempts to acquire the same lock that WriteAt already holds, deadlock results.
  2. Consider updating an directory (as part of create). To properly update the directory, it is read from disk, then modified in memory, then written back out to disk. For correctness, access to the directory must be locked for the duration of all operations (not just while reading or writing). Otherwise, two threads could attempt to update the directory simultaneously. If both threads read the directory, modified separate in-memory copies and then wrote out the changes, only one set of changes would make it out to disk. Note that it is insufficient to lock the directory only during the reads and writes; a lock must be held across both operations. Thus, acquiring locks within ReadAt or WriteAt is insufficient.
  3. A similar scenario occurs when updating the freelist as part of removing a file. One must first read the bitmap, update it, and then flush the changes back out to disk. The bitmap routines FetchFrom and WriteBack call ReadAt and WriteAt respectively.

Thomas Narten
Mon Feb 3 15:00:27 EST 1997