CS135 Homework 2: FAT, part 1

Overview

The purpose of this assignment is to begin developing a real filesystem. Because of the complexity of writing a working filesystem, the assignment is divided into two parts. In this first part, you will develop a lot of scaffolding and enough code for your filesystem to do something testable. In the second part, you will complete the filesystem.

You may write in any language that is supported on Wilkes, but as mentioned in class, I strongly recommend C or C++.

The Assignment

Your assignment is to develop a FAT-like filesystem that supports the following features:

  1. The general structure of the filesystem is similar to the Microsoft FAT design (see below).
  2. The filesystem supports the following operations at a minimum: getattr, access, readdir, and mkdir. (Note that at this point it is not necessary to support file I/O, or even files.)
  3. Your mkdir operation must allocate space from the free list.
  4. The filesystem is backed by a preallocated 10-MB file with a fixed name, such as "fat_disk". The size of the file should be a #defined constant, of course.
  5. When the filesystem is invoked, if the backing file doesn't exist, it is created and initialized. However, if it does exist, it should be attached and its previous contents should be visible.
  6. Subdirectories must be supported.
  7. Your directories may be fixed-size; it is not necessary to be able to create an arbitrary number of entries in a directory.
  8. Directory entries may also be fixed-size, as long as the name length is moderately reasonable. (Nothing under 16 characters is "reasonable" in my book; my minimal implementation compromises with a maximum of 32.)
  9. File sizes may be limited to either 32 or 64 bits.
  10. The acid test of your filesystem should be that is possible to create directories, list them (with ls -la returning reasonable results including "." and ".."), and cd into them.
  11. Other operations are up to you. We will be extending the filesystem to support files, rmdir, etc. in the next assignment, so you are welcome to implement those things. However, they will not be tested in the current assignment.

Why this particular set of features? It's the minimum necessary to have a filesystem where you can do something visible: create and list directories. You'll find that you need to create quite a bit of scaffolding to get that far (in particular, the code that creates an initialized FAT filesystem from scratch).

FAT Design

When I refer to a "FAT-like" filesystem, I mean the following:

  1. Allocation is managed by an in-core table with one entry per filesystem block. Each entry contains either 0 or the number of another block. In toto, the table constitutes a set of linked lists of blocks.
  2. The free list is a linked list (held in the in-core table) reached from the superblock. (An alternative would be to use the Microsoft FAT design, which marks free blocks with a special code and requires scanning the FAT to find free blocks.)
  3. The on-disk copy of the block table is read at mount (filesystem initialization) time and is updated at your discretion. (It is only necessary to update it at exit time, but I recommend more frequent updates to make debugging easier.)
  4. All file metadata is kept in the directory entry. At a minimum, this should include the file type (directory or file), the size in bytes, the name, and the number of the first block. (Subsequent blocks are located via the block table.) Other metadata, such as ownership, permissions, and timestamps, are up to you but are not required.
  5. The block size is up to you.

For reference, my minimal implementation used a block size of 512 bytes, had six fields in the superblock (including a magic number), and had four fields in the directory entry. To it easy to store the superblock in a filesystem block, I used the following union:

union {
    struct fat_superblock s;
    char		pad[512];
}
			superblock;
(Note that the superblock is only 512 bytes, even if you use a different block size for your filesystem. That design makes it possible to read the superblock without knowing the block size, which is a useful feature. If the filesystem uses blocks larger than 512 bytes, the remaining space in the larger "block" is simply wasted.)

I also found it useful to create a few macros to do things like seeking to a particular block, converting back and forth between byte offsets and block numbers, etc.

Submission

Submit your code (it should be a single file) as assignment 2 with cs135submit. If you implement any additional features, describe them prominently in comments at the top of the file.


© 2010, Geoff Kuenning

This page is maintained by Geoff Kuenning.