date: 2019-03-25
tags: OS 6.828
这里会记录阅读6.828课程lecture note的我的个人笔记。可能会中英混杂,不是很适合外人阅读,也请见谅。
我们为什么需要file system
file system有哪些有趣的点?
之后我们来看一下xv6的实现。因为lecture note里头的东西太乱了,不妨我们直接看xv6 book中对应的内容。
xv6的fs实现分为7层。从下向上其顺序和功能如下:
/usr/rtm/xv6/fs.c/usr/rtm/xv6/fs.c
这样的地址接口buffer layer的代码位于bio.c
其主要接口为bwrite
和bread
。
// Return a locked buf with the contents of the indicated block.
struct buf*
bread(uint dev, uint blockno) {
struct buf *b;
b = bget(dev, blockno);
if((b->flags & B_VALID) == 0) {
iderw(b);
}
return b;
}
// Write b's contents to disk. Must be locked.
void
bwrite(struct buf *b)
{
if(!holdingsleep(&b->lock))
panic("bwrite");
b->flags |= B_DIRTY;
iderw(b);
}
更深入一点的话,buf
的结构和bget
的实现如下:
// buf.h
struct buf {
int flags;
uint dev;
uint blockno;
struct sleeplock lock;
uint refcnt;
struct buf *prev; // LRU cache list
struct buf *next;
struct buf *qnext; // disk queue
uchar data[BSIZE];
};
#define B_VALID 0x2 // buffer has been read from disk
#define B_DIRTY 0x4 // buffer needs to be written to disk
// bio.c
// Look through buffer cache for block on device dev.
// If not found, allocate a buffer.
// In either case, return locked buffer.
static struct buf*
bget(uint dev, uint blockno) {
struct buf *b;
acquire(&bcache.lock);
// Is the block already cached?
for(b = bcache.head.next; b != &bcache.head; b = b->next){
if(b->dev == dev && b->blockno == blockno){
b->refcnt++;
release(&bcache.lock);
acquiresleep(&b->lock);
return b;
}
}
// Not cached; recycle an unused buffer.
// Even if refcnt==0, B_DIRTY indicates a buffer is in use
// because log.c has modified it but not yet committed it.
for(b = bcache.head.prev; b != &bcache.head; b = b->prev){
if(b->refcnt == 0 && (b->flags & B_DIRTY) == 0) {
b->dev = dev;
b->blockno = blockno;
b->flags = 0;
b->refcnt = 1;
release(&bcache.lock);
acquiresleep(&b->lock);
return b;
}
}
panic("bget: no buffers");
}
注意这里bget
就是从链表里头取一个空的,并不会做MRU (most recent used)的删除操作,如果没有空的就报错。而这个释放的操作是用brelse
来进行的。
// Release a locked buffer.
// Move to the head of the MRU list.
void
brelse(struct buf *b) {
if(!holdingsleep(&b->lock))
panic("brelse");
releasesleep(&b->lock);
acquire(&bcache.lock);
b->refcnt--;
if (b->refcnt == 0) {
// no one is waiting for it.
b->next->prev = b->prev;
b->prev->next = b->next;
b->next = bcache.head.next;
b->prev = &bcache.head;
bcache.head.next->prev = b;
bcache.head.next = b;
}
release(&bcache.lock);
}
大致就是把引用计数清空,并把这个buf移到链表最前面。
常见的一个crash recovery的方法是写logging。我们先来看一下xv6的logging,再来了解linux的EXT3