xv6对于文件操作会经历写日志的过程,首先向日志中写入操作,然后再写入到文件系统中。
log分为以下阶段
- 写入log
- 提交log
- 写入文件系统
- 删除日志
这样可以保证机器发生crash时,保证文件系统的安全,并能够从crash中恢复。
log的数据结构定义如下,其中block保存磁盘块的索引,这样就能调用bread和bwrite函数实现向磁盘中的读写操作。
struct logheader {
int n;
int block[LOGSIZE];
};
struct log {
struct spinlock lock;
int start;
int size;
int outstanding; // how many FS sys calls are executing.
int committing; // in commit(), please wait.
int dev;
struct logheader lh;
};
struct log log;
// called at the start of each FS system call.
void
begin_op(void)
{
acquire(&log.lock);
while(1){
if(log.committing){
sleep(&log, &log.lock);
} else if(log.lh.n + (log.outstanding+1)*MAXOPBLOCKS > LOGSIZE){
// this op might exhaust log space; wait for commit.
sleep(&log, &log.lock);
} else {
log.outstanding += 1;
release(&log.lock);
break;
}
}
}
beginop函数主要检查是否正在提交日志,或者日志剩余容量不足,否则就将日志的引用计数加一。
endop除了要将引用计数jianyi外,还需要判断是否能够提交日志,如果能够提交日志,则调用commit提交日志。
// called at the end of each FS system call.
// commits if this was the last outstanding operation.
void
end_op(void)
{
int do_commit = 0;
acquire(&log.lock);
log.outstanding -= 1;
if(log.committing)
panic("log.committing");
if(log.outstanding == 0){
do_commit = 1;
log.committing = 1;
} else {
// begin_op() may be waiting for log space,
// and decrementing log.outstanding has decreased
// the amount of reserved space.
wakeup(&log);
}
release(&log.lock);
if(do_commit){
// call commit w/o holding locks, since not allowed
// to sleep with locks.
commit();
acquire(&log.lock);
log.committing = 0;
wakeup(&log);
release(&log.lock);
}
}
commit操作要执行以下操作
- 调用write_log()函数,将缓存中修改过的块写入日志。
- 调用write_head()函数,将日志的头块写入磁盘,实际进行提交操作。
- 调用install_trans(0)函数,将日志中的写操作安装到相应的位置(即写回到文件系统的主位置)。
- 将日志的记录数重置为0,表示日志已经提交。
- 再次调用write_head()函数,擦除日志中的事务信息,即将头块中的块号清零。
实现擦除操作是因为在第二次调用前将log.lh.n 置为 0,然后调用write_head(),将对应buf中的n置为0,表示没有日志的状态。
至于从log中恢复的操作,只需从buf中读取log,然后应用到磁盘中即可。
计算机领域的任何问题都可以通过增加一个间接的中间层来解决
文件系统中的抽象层由低到高为硬盘到文件描述符等,如下所示。
xv6中目前实现的是一级文件系统如下所示,由12个直接索引和1个间接索引实现。
最大的大小为$(256+12)* 1024$ ,在bigfile实验中,要求实现一个二级间接索引,此时文件大小为$(256*256+256+11)*1024$。
TODO
TODO
有关mmap的介绍可以查看这两个网站
通过将文件直接映射进内存以实现对文件的高效读写,