xv6 file system
xv6 File system overview
In general, There are 3 different ascpect on unix-like file system, file descriptor, file/directory and block. In xv6, they are distributed into 7 layers:
Block interface
The xv file system’s block interface consists of 34 layers(disk, buffer cache , logging and bitmap) Goal: achieve crash recovery
Disk
Disk is the most primitive layer of fs, which provide directly block R/W in device.
Buffer cache
This layer maintains a LRU Buffer queue to cache block data on disk, providing
- data structure
struct {
struct spinlock lock;
struct buf buf[NBUF];
//maintain an LRU queue
struct buf head;// entry for the queue
} bcache;
// head -> free buffs -> used buffs -> head
Logging
every modify on disk must be handled by logging layer to achieve crach tolerence logging layer organizes all temporary modification on disk. any modification on block from upper layer
Log methods: !(images/cs/xv6-fs-log.png)
commit()
, when no fs syscall occurs, logging layer commit() current logs ( modification stored on buffer), write they directly on disk.- when crash happened, fs can recovery data from logs block in disk, and write logs on data block.
Bitmap
bitmap is used to indicate which block is free or used on one device. It use 1 bit to represent 1 block on device.
provide lower level balloc(), bfree()
.
Inode/Dir interface
This layer combine inode block and data block to form a complete file, like hello.c
, or a directory.
In this interface, we operate fs on file level, ignoring the blocks operation.
How a file organized ? inode layer
Let’s introduce inode
struct inode {
uint dev; // Device number
uint inum; // Inode number
int ref; // Reference count
struct sleeplock lock; // protects everything below here
int valid; // inode has been read from diskon
//-----------inode stored in disk-----------
short type; // File type
short major; // Major device number (T_DEVICE only)
short minor; // Minor device number (T_DEVICE only)
short nlink; // Number of links to inode in file system
uint size; // Size of file (bytes)
uint addrs[NDIRECT+1]; // Data block addresses
};
// And inode layer has its own space to cache disk inode
struct {
struct spinlock lock;
struct inode inode[NINODE];
} icache;
ref and nlink
2 of the most important fields are ref
and nlink
, the first one only cached in memory, means how many c pointer in memory pointing to it (fd, working dir), the second one means how many links point to this inode in only in fs structure, like a directory points to a inode, another inode points to this inode, etc.
The iupdate()
can write inode in cache to disk.
Directory layer
directory layer provides dir structure
struct dirent {
ushort inum;
char name[DIRSIZ];
};
If a file’s type is dir, its data block is just a dirent structure.
In this layer, fs provides methods:
dirlookup()
, if someone what to find something in a directory
dirlink()
, insert a directory under another directory.
Path names
provide a useful layer where user can find inode by pathname
namei() namex()
File discriptor interface
In unix-like system, everything is represented as a file.
struct file {
enum { FD_NONE, FD_PIPE, FD_INODE, FD_DEVICE } type;
int ref; // reference count
char readable;
char writable;
struct pipe *pipe; // FD_PIPE
struct inode *ip; // FD_INODE and FD_DEVICE
uint off; // FD_INODE
short major; // FD_DEVICE
};
file is a wrapper around either an inode or a pipe, plus an i/o offset.
xv6 fs maintain all opening file by ftable
struct {
struct spinlock lock;
struct file file[NFILE];
} ftable;