Project: File System
Introduction
In this project, you will implement a disk-based file system called FSX492, which is a simple
derivation of the Unix Fast File System (https://pages.cs.wisc.edu/~remzi/OSTEP/file-ffs.
...
Project: File System
Introduction
In this project, you will implement a disk-based file system called FSX492, which is a simple
derivation of the Unix Fast File System (https://pages.cs.wisc.edu/~remzi/OSTEP/file-ffs.pdf).
You will use the FUSE toolkit to implement the file system as a user-space process. Instead of a
physical disk, you will be provided a file-based virtual disk, which can be accessed through a
customized block device interface.
You can do this project in a team of three students. Only ONE student per team must submit.
Important: put comments everywhere in your code to explain to the CAs what your code is doing!
Technical Background
Figure 1: Architecture of FUSE
FUSE (File System in User Space) is a kernel module and library which allow you to implement
POSIX file systems within a user-space process. Figure 1 shows the architecture of FUSE. All
operations to the FUSE file system can be intercepted by callbacks placed by users through the
FUSE interfaces. For instance, you can mount a “disk” to “/whatever/path/you/like”, in the format
of a FUSE file system. Any operations you issued to this file system (e.g., open / read / write /
close to directories or files under “/whatever/path/you/like”) will be redirected to FUSE (“libfuse”
in Figure 1), where you can intercept the operations by registering callbacks to FUSE.
Specifics of FSX492
Figure 2: Format of the file-based virtual disk
The specifics of FSX492 can be found below.
1) File-based virtual block storage device.
We have already prepared for you a virtual block storage device within a single file on the host
file system. FSX492 will run on this virtual block storage device. This device is divided into blocks
of 1024 bytes, and into five regions (see Figure 2): the superblock, a bitmap for allocating inodes,
a bitmap for allocating data blocks, a table of all the inodes, and the rest of the blocks which are
available for data storage for files and directories.
2) Superblock
The superblock is the first block in the file system, and contains the information needed to find
the rest of the file system structures. The following C constants and structure can be used to
implement the superblock:
Note that uint32_t is a standard C type found in the header file and refers to an
unsigned 32 bit integer. (similarly, uint16_t is an unsigned 16 bit integer and int16_t and int32_t
are signed 16 and 32 bit integers).
3) Inodes
These are standard Unix-style inodes. Each inode represents a file or directory (in a sense the
inode is that file or directory) which can be uniquely identified by its inode number. The root
directory is always found in inode 1; inode 0 is reserved (this allows ‘0’ to be used as a null value).
The following C structure can be used to implement an inode:
The direct array and the indir_1 and indir_2 fields store block numbers that “point” to blocks
of storage. The blocks pointed to by direct array elements are blocks in the file. The blocks pointed
to by the indir_1 and indir_2 fields are blocks that contain arrays of block numbers. For
indir_1, those block numbers point to file blocks. For indir_2, those block numbers point to
other blocks that contain arrays of block numbers that point to file blocks (we do not require more
than 2-layers of indirections). There are PTRS_PER_BLK 32-bit block numbers per block, giving a
maximum file size of about 64MB.
enum {PTRS_PER_BLK = FS_BLOCK_SIZE / sizeof(uint32_t) };
4) Directories
Directories are one block in length, which limits the size of a directory to 32 entries.
This will simplify your implementation quite a bit, as you can allocate that one block in ‘mkdir’ and
not have to worry about extending it when you are adding a new entry. Directory entries are quite
simple, with two flags indicating whether an entry is valid or not and whether it is a directory, an
inode number, and a name. Note that the maximum name length is 27 bytes, allowing entries to
always have a terminating '\0' byte.
The following C constant and structure can be used to implement a directory entry:
[Show More]