xv6 file system

Created on Oct 1, 2021

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

  1. 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)

  1. commit(), when no fs syscall occurs, logging layer commit() current logs ( modification stored on buffer), write they directly on disk.
  2. 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;