Due Friday, Dec 3rd, 2004 (6:00 PM), no late submission accepted
Submissions received before Wednesday, Dec 1st, 2004 (6:00 PM) will get 10% extra credit
The purpose of this project is to add a new filesystem to GeekOS, as well as the standard operations for file management.
A working project 3 or project 4 is not required for this project. If you do not build this project on top of project 4, you must make the following changes:
The main part of this project is to develop a new filesystem for the GeekOS. This filesystem will reside on the second IDE disk drive in the Bochs emulator. This will allow you to continue to use your existing PFAT drive to load user programs while you test your filesystem. The second IDE disk's image is called diskd.img. It is 10MB by default.
GOSFS will provide a filesystem that includes multiple directories and long file name support.
Since GEEKOS will have two types of filesystems (PFAT and GOSFS), it will have a virtual filesystem layer (VFS) to handle sending requests to an appropriate filesystem (see figure below). We have provided an implementation of the VFS layer in the file vfs.c. The VFS layer will call the appropriate GOSFS routines when a file operation refers a file in the GOSFS filesystem.
The implementation of PFAT is in pfat.c. You will
implement GOSFS in gosfs.c and relevant system calls in syscall.c.
VFS picks the functions
to call based on supplied structures containing function pointers, one
for each operation. For example, see Init_PFAT in pfat.c: this initializes the
PFAT filesystem with VFS by passing it a pointer to s_pfatFilesystemOps, a
structure that contains function pointers to PFAT routines for mounting
(and formatting) a filesystem. Other PFAT functions are stored in
different structures (e.g., look at the PFAT_Open routine, which passes
structure to VFS). You will analogously use s_gosfsFilesystemOps,
s_gosfsMountPointOps, s_gosfsDirOps, and s_gosfsFileOps
You should also add a call to Init_GOSFS provided gosfs.c
in main.c to register the GOSFS filesystem. In general,
use the PFAT implementation as your guide to interfacing GOSFS with VFS.
Open files are tracked in memory with a file descriptor, defined as struct File. Each user
space process will have a file
descriptor table that records which files the process can
currently read and write.
process can have up to USER_MAX_FILES files
open at once. The file descriptor table is implemented asa struct
File *fileList[USER_MAX_FILES] array that you must add to struct
User_Context. Note that not all the entries in the fileList
are necessarily open files, since usually a process has less than USER_MAX_FILES
files open at
once. If fileList[i] is NULL,
it represents a
free slot (file descriptor is not used). This descriptor will be filled
out by the code in VFS; e.g., see Open in vfs.h,
whose pFile argument is a
pointer to a free slot in the table.
Your filesystem should support long filenames (at most 128 bytes, which includes a null at the end). A file's full path (which includes directories and subdirectories) will be no more than 1024 characters in total.
You should keep track of free disk blocks using a bit vector (as described in the textbook, Section 12.5.1, page 431). A library called bitset is provided (see bitset.h and bitset.c) that manages a set of bits and provides functions to find bits that are 0 (i.e. correspond to free disk blocks).
The block size for GOSFS is 4 KB; IDE sectors (a.k.a. disk blocks) are 512 bytes, so a block is 8 sectors. Thus one bit in a bitset corresponds to a 4KB block. For example, a bitset that is 8192 bits (1024 bytes) will keep track of 8192 * 4KB = 32 MB of data.
The filenode for a directory is represented by the GOSFS_DIRENTRY_ISDIRECTORY flag set in the GOSFS_Dir_Entry->flags field. The location of the block that holds the data for the directory will be stored in the first entry in the blocksList array of the directory's filenode (hence entries blocksList..blocksList[GOSFS_NUM_BLOCK_PTRS-1] are unused).
The Mount system call allows you to associate a filesystem with a place in the file name hierarchy. The Mount call is implemented as part of the VFS code we supply (see Mount function in vfs.c); you will implement your Init_GOSFS function so that VFS's mount code will call your function GOSFS_Mount() in gosfs.c. Among other things, it must ensure that the filesystem being mounted is GOSFS. See new syscalls below for details.
You have to implement the sematics of the new system calls as described below. As you can see, the semantics is very similar to the UNIX file system.
|Call||User Function||Return on success||Return on failure||Reasons for failure||Comment|
|SYS_MOUNT||Mount(char *dev, char *prefix, char *fstype)||0||-1||
|SYS_OPEN||Open(char *path, int mode)||new file descriptor number||-1||
||if Delete(file) is called and file is still open in other threads or even in the thread that called Delete(), all the subsequent operations on that file (except Close()) should fail|
|SYS_READ||Read(int fd, char *buffer, int length)||number of bytes read||-1||
|SYS_READENTRY||Read_Entry(int fd, VFS_Dir_Entry *entry)||0||-1||
|SYS_WRITE||Write(int fd, char *buffer, int length)||number of bytes written||-1||
|SYS_STAT||Stat(char *path, VFS_File_Stat *stat)||0||-1||
|SYS_FSTAT||FStat(int fd, VFS_File_Stat *stat)||0||-1||
|SYS_SEEK||Seek(int fd, int offset)||0||-1||
||offset is an absolute position; could be equal to fileSize or greater, then Write appends, see above|
||Should NOT create directories recursively; e.g. CreateDirectory("/d/d1/d2/d3/d4"), will fail if /d/d1/d2/d3 does not exist already.|
|SYS_SYNC||Sync(void)||0||-1||None||Forces any outstanding operations to be written to disk.|
|SYS_FORMAT||Format(char *dev, char *fstype)||0||-1||
||You only have to implement the format of the GOSFS filesystem.|
A guideline is provided above. The first block (0) is called the SUPERBLOCK, and it contains filesystem housekeeping data. Blocks >= 1 contain files and directories.
When you do a Format() , you make a raw disk usable with GOSFS. That is: