xv6 lec15 Crash recovery

15.1 File system crash概述

15.2 File system crash示例

  • 对于echo在根目录中创建一个新文件x的过程中读写block

15.3 File system logging

  • logging可以确保:
    • 文件系统的系统调用是原子性的
    • 支持快速恢复(fast recovery)
    • 原则上可以很高效
  • log的执行流程:
    • 写文件时,先写write(write log);
    • 当写文件操作结束时,在commit写文件操作,也就是在log的某个位置记录属于同一个文件系统的操作的个数(commit log);
    • log block中存储了所有写block的内容,如果要执行这些操作,直接就是将写在log中的数据写到data区(install log);
    • 完成之后,就可以清除log了(clean log),由于log的write ahead rule,能够保证微文件系统调用write等的原子性
  • log的header中存储了n和block编号的数组

15.4 log_write函数

  • 文件系统的操作以begin_opend_op来表现一个事务的开始与结束,end_op的时候才会去将数据写入到log
  • ialloc中已经写了一个inode,也就是将这个inode标记为已用,之后便是写log
  • 在写log的时候需要bpin住相关的block

15.5 end_op函数

  • end_op函数中中的会执行commit操作,这里是后写log header
  • 这里是指先将log拷贝到内存中,在将内存中的文件数据落盘

15.6 File system recovering

  • xv6启动之后的文件恢复主要就是initlog函数中的recover_from_log,而recover_from_log函数主要就是将log中的块复制到磁盘中的正确的位置

15.7 Log写磁盘流程

  • log write是之记录一个txn中在log中的写,但是真实的写磁盘(包括写log)是bwrite

15.8 File system challenges

  • 对于log的第一个挑战是,在一个事务还有结束的时候,如果将一个block cache中block eviction,也就是写入磁盘,如果中途发生了crash,那么就破坏了事务的原子性,那么bpin的作用就是用来保证txn的原子性,bpin其实就是增加block bufferrefcnt,在install_trans(这个函数用来把log中的block写入到真实磁盘中)会bunpinblock cache中的block cache
  • 对于log的第二个挑战是,由于在xv6中只有30个block块,对于write系统调用,如果一个写操作的写入的block超过了30,那么就会分成多个小的写操作,每个小的写操作是一个事务,这是由于写操作的语义不是原子的,为什么不是原子的?
  • 因为至少还需要log 的header块
  • 第三个挑战是,并发的文件系统调用,由于log block只有30个,所以要限制多尔文件系统调用的txn的所有block不能超过30,分开commit会存在问题吗?
  • 在begin_op中会检测当前txn是否可以开启,begin_op中通过比较活跃txn个数与最大允许txn的个数,log结构体存在outstanding字段记录当前活跃txn,
  • 对于阻塞睡眠的开启文件系统系统调用的事务,如果当前log的header的数量与当前正在活跃的txn的可能会使用的log中block超过了一个阈值LOGSIZE,那么尝试区开启文件系统调用的进程会sleepoutstanding(活跃)事务的数目为0时,会去wakeup之前sleep的进程,在wakeup中只是把sleeping的进程改为runnable,但是如果调度到相关的进程还是会睡眠,因为现在log.committing = 1,其实这里的outstanding有些迷惑,outstanding用来体现活跃txn可能使用的log block(即使不会占用那么多log block),所以如果outstanding等于0了,就表示这种可能性也没有了
posted @ 2022-04-12 16:20  抿了抿嘴丶  阅读(37)  评论(0编辑  收藏  举报