MIT6.S081
  • 简介
  • Lec01 Introduction and Examples (Robert)
    • 1.1 课程内容简介
    • 1.2 操作系统结构
    • 1.3 Why Hard and Interesting
    • 1.4 课程结构和资源
    • 1.5 read, write, exit系统调用
    • 1.6 open系统调用
    • 1.7 Shell
    • 1.8 fork系统调用
    • 1.9 exec, wait系统调用
    • 1.10 I/O Redirect
  • Lec03 OS Organization and System Calls (Frans)
    • 3.1 上一节课回顾
    • 3.2 操作系统隔离性(isolation)
    • 3.3 操作系统防御性(Defensive)
    • 3.4 硬件对于强隔离的支持
    • 3.5 User/Kernel mode切换
    • 3.6 宏内核 vs 微内核 (Monolithic Kernel vs Micro Kernel)
    • 3.7 编译运行kernel
    • 3.8 QEMU
    • 3.9 XV6 启动过程
  • Lec04 Page tables (Frans)
    • 4.1 课程内容简介
    • 4.2 地址空间(Address Spaces)
    • 4.3 页表(Page Table)
    • 4.4 页表缓存(Translation Lookaside Buffer)
    • 4.5 Kernel Page Table
    • 4.6 kvminit 函数
    • 4.7 kvminithart 函数
    • 4.8 walk 函数
  • Lec05 Calling conventions and stack frames RISC-V (TA)
    • 5.1 C程序到汇编程序的转换
    • 5.2 RISC-V vs x86
    • 5.3 gdb和汇编代码执行
    • 5.4 RISC-V寄存器
    • 5.5 Stack
    • 5.6 Struct
  • Lec06 Isolation & system call entry/exit (Robert)
    • 6.1 Trap机制
    • 6.2 Trap代码执行流程
    • 6.3 ECALL指令之前的状态
    • 6.4 ECALL指令之后的状态
    • 6.5 uservec函数
    • 6.6 usertrap函数
    • 6.7 usertrapret函数
    • 6.8 userret函数
  • Lec08 Page faults (Frans)
    • 8.1 Page Fault Basics
    • 8.2 Lazy page allocation
    • 8.3 Zero Fill On Demand
    • 8.4 Copy On Write Fork
    • 8.5 Demand Paging
    • 8.6 Memory Mapped Files
  • Lec09 Interrupts (Frans)
    • 9.1 真实操作系统内存使用情况
    • 9.2 Interrupt硬件部分
    • 9.3 设备驱动概述
    • 9.4 在XV6中设置中断
    • 9.5 UART驱动的top部分
    • 9.6 UART驱动的bottom部分
    • 9.7 Interrupt相关的并发
    • 9.8 UART读取键盘输入
    • 9.9 Interrupt的演进
  • Lec10 Multiprocessors and locking (Frans)
    • 10.1 为什么要使用锁?
    • 10.2 锁如何避免race condition?
    • 10.3 什么时候使用锁?
    • 10.4 锁的特性和死锁
    • 10.5 锁与性能
    • 10.6 XV6中UART模块对于锁的使用
    • 10.7 自旋锁(Spin lock)的实现(一)
    • 10.8 自旋锁(Spin lock)的实现(二)
  • Lec11 Thread switching (Robert)
    • 11.1 线程(Thread)概述
    • 11.2 XV6线程调度
    • 11.3 XV6线程切换(一)
    • 11.4 XV6线程切换(二)
    • 11.5 XV6进程切换示例程序
    • 11.6 XV6线程切换 --- yield/sched函数
    • 11.7 XV6线程切换 --- switch函数
    • 11.8 XV6线程切换 --- scheduler函数
    • 11.9 XV6线程第一次调用switch函数
  • Lec13 Sleep & Wake up (Robert)
    • 13.1 线程切换过程中锁的限制
    • 13.2 Sleep&Wakeup 接口
    • 13.3 Lost wakeup
    • 13.4 如何避免Lost wakeup
    • 13.5 Pipe中的sleep和wakeup
    • 13.6 exit系统调用
    • 13.7 wait系统调用
    • 13.8 kill系统调用
  • Lec14 File systems (Frans)
    • 14.1 Why Interesting
    • 14.2 File system实现概述
    • 14.3 How file system uses disk
    • 14.4 inode
    • 14.5 File system工作示例
    • 14.6 XV6创建inode代码展示
    • 14.7 Sleep Lock
  • Lec15 Crash recovery (Frans)
    • 15.1 File system crash概述
    • 15.2 File system crash示例
    • 15.3 File system logging
    • 15.4 log_write函数
    • 15.5 end_op函数
    • 15.6 File system recovering
    • 15.7 Log写磁盘流程
    • 15.8 File system challenges
  • Lec16 File system performance and fast crash recovery (Robert)
    • 16.1 Why logging
    • 16.2 XV6 File system logging回顾
    • 16.3 ext3 file system log format
    • 16.4 ext3如何提升性能
    • 16.5 ext3文件系统调用格式
    • 16.6 ext3 transaction commit步骤
    • 16.7 ext3 file system恢复过程
    • 16.8 为什么新transaction需要等前一个transaction中系统调用执行完成
    • 16.9 总结
  • Lec17 Virtual memory for applications (Frans)
    • 17.1 应用程序使用虚拟内存所需要的特性
    • 17.2 支持应用程序使用虚拟内存的系统调用
    • 17.3 虚拟内存系统如何支持用户应用程序
    • 17.4 构建大的缓存表
    • 17.5 Baker's Real-Time Copying Garbage Collector
    • 17.6 使用虚拟内存特性的GC
    • 17.7 使用虚拟内存特性的GC代码展示
  • Lec18 OS organization (Robert)
    • 18.1 Monolithic kernel
    • 18.2 Micro kernel
    • 18.3 Why micro kernel?
    • 18.4 L4 micro kernel
    • 18.5 Improving IPC by Kernel Design
    • 18.6 Run Linux on top of L4 micro kernel
    • 18.7 L4 Linux性能分析
  • Lec19 Virtual Machines (Robert)
    • 19.1 Why Virtual Machine?
    • 19.2 Trap-and-Emulate --- Trap
    • 19.3 Trap-and-Emulate --- Emulate
    • 19.4 Trap-and-Emulate --- Page Table
    • 19.5 Trap-and-Emulate --- Devices
    • 19.6 硬件对虚拟机的支持
    • 19.7 Dune: Safe User-level Access to Privileged CPU Features
  • Lec20 Kernels and HLL (Frans)
    • 20.1 C语言实现操作系统的优劣势
    • 20.2 高级编程语言实现操作系统的优劣势
    • 20.3 高级编程语言选择 --- Golang
    • 20.4 Biscuit
    • 20.5 Heap exhaustion
    • 20.6 Heap exhaustion solution
    • 20.7 Evaluation: HLL benefits
    • 20.8 Evaluation: HLL performance cost(1)
    • 20.9 Evaluation: HLL performance cost(2)
    • 20.10 Should one use HLL for a new kernel?
  • Lec21 Networking (Robert)
    • 21.1计算机网络概述
    • 21.2 二层网络 --- Ethernet
    • 21.3 二/三层地址转换 --- ARP
    • 21.4 三层网络 --- Internet
    • 21.5 四层网络 --- UDP
    • 21.6 网络协议栈(Network Stack)
    • 21.7 Ring Buffer
    • 21.8 Receive Livelock
    • 21.9 如何解决Livelock
  • Lec22 Meltdown (Robert)
    • 22.1 Meltdown发生的背景
    • 22.2 Speculative execution(1)
    • 22.3 Speculative execution(2)
    • 22.4 CPU caches
    • 22.5 Flush and Reload
    • 22.6 Meltdown Attack
    • 22.7 Meltdown Fix
  • Lec23 RCU (Robert)
    • 23.1 使用锁带来的问题
    • 23.2 读写锁 (Read-Write Lock)
    • 23.3 RCU实现(1) - 基本实现
    • 23.4 RCU实现(2) - Memory barrier
    • 23.5 RCU实现(3) - 读写规则
    • 23.6 RCU用例代码
    • 23.7 RCU总结
Powered by GitBook
On this page

Was this helpful?

  1. Lec16 File system performance and fast crash recovery (Robert)

16.7 ext3 file system恢复过程

Previous16.6 ext3 transaction commit步骤Next16.8 为什么新transaction需要等前一个transaction中系统调用执行完成

Last updated 4 years ago

Was this helpful?

为了简化重启时恢复软件的工作,当决定释放某段log空间时,文件系统会更新super block中的指针将其指向当前最早的transaction的起始位置。

之后如果crash并重启,恢复软件会读取super block,并找到log的起始位置。所以如果crash了,内存中的所有数据都会消失,例如文件系统中记录的哪些block被写入到了磁盘中这些信息都会丢失,所以可以假设这时内存中没有可用的数据,唯一可用的数据存在于磁盘中。当然我们这里的讨论都是基于磁盘还是完好的,所以你可以认为只是一次电力故障,系统突然停止了运行过程,在电力恢复时,断电那一瞬间磁盘中的数据还存在。我们并没有考虑磁盘被损坏或者被摧毁的情况。

crash或许会打断任何在进行中的transaction,或许transaction正在commit,或许transaction正在向文件系统写block。让我重新画一个例子,我们在log中有一个super block,之后是transaction T6,T7,T8,在T8之后是一个已近被释放了log空间的T5,假设T8已经用了T5的一部分空间。并且现在super block指向的是T6的起始位置,因为T6是最早的transaction。

现在crash并重启,恢复软件读取super block就可以知道log的起始位置,之后恢复软件会在log中一直扫描并尝试找到log的结束位置,现在我们需要有一种方式确定log的结束位置。我们知道每个transaction包含了一个descriptor block,里面记录了该transaction中包含了多少个data block,假设descriptor block记录了17个block,那么恢复软件会扫描17个data block,最后是commit block。这样可以一直扫描到T8。

在扫描T8时有两种可能,一种可能是T8完成了commit,并且包含了commit block。这时恢复软件并不知道T8就是最后一个transaction,所以它会接着看T8的commit block的下一个block,来看看这是不是一个有效的descriptor block。我们知道这不是一个descriptor block,而是一个包含在T5内的随机block。现在的问题是恢复软件如何可靠的区分出来呢?是的,每个descriptor和commit block都以某个魔法数字作为起始,这是一个32bit的数字。所以如果扫描完了T8,下一个block以魔法数字作为起始,那么恢复软件就会认为这是一个descriptor block。(注,也有可能T5正好完美的跟在T8后面,也就是说T8的commit block之后就是T5的descriptor block,同时T5的commit block也存在,所以这里必然还需要一些其他的机制,我猜是用到了transaction的序列号)

但是,现在我们看到的block可能是包含了任意数据的data block,所以它可能是文件中的一个data block并且也是以魔法数字作为起始。所以这里的最后一个细节是,logging系统需要能区分一个以魔法数字作为起始的descriptor block和一个以魔法数字作为起始的data block。你可以想到各种方法来实现这种区分,ext3是这样做的,当它向log写一个block时,如果这个block既不是descriptor block也不是commit block,但是又以魔法数字作为起始,文件系统会以0替换前32bit,并在transaction的descriptor block中为该data block设置一个bit。这个bit表示,对应的data block本来是以魔法数字作为起始,但是现在我们将其替换成了0。而恢复软件会检查这个bit位,在将block写回到文件系统之前,会用魔法数字替换0。

因此,在log中,除了descriptor和commit block,不会有其他的block以这32bit的魔法数字作为起始。所以我们不会有模棱两可的判断,如果一个commit block之后的block以魔法数字作为起始,那么它必然是一个descriptor block。所以恢复软件会从super block指向的位置开始一直扫描,直到:

  • 某个commit block之后的一个block并不是descriptor block

  • 或者某个commit block之后是descriptor block,但是根据descriptor block找到的并不是一个commit block

这时,恢复软件会停止扫描,并认为最后一个有效的commit block是log的结束位置。或许在最后一个commit block之后会跟一个并没有commit完成的transaction(注,上面的第二种情况),但是恢复软件会忽略未完成的transaction,因为这个transaction并没有包含所有的写操作,所以它并不能原子性的恢复。之后恢复软件会回到log的最开始位置,并将每个log block写入到文件系统的实际位置,直到走到最后一个有效的commit block。之后才是启动剩下的操作系统,并且运行普通的程序。在恢复完成之前,是不能运行任何程序的,因为这个时候文件系统并不是有效的。

学生提问:XV6相比这里的log机制,缺少了什么呢?

Robert教授:XV6主要缺失的是在log中包含多个transaction的能力,在XV6的log中最多只会有一个transaction,所以在XV6中缺少了并发的能力。比如说当我在执行transaction T7的系统调用时,ext3可以同时向磁盘提交T6,而这在XV6中这是不可能的,因为log只保存了一个transaction。所以我们必须先完成一个transaction的所有工作,之后才能开始下一个transaction。所以XV6是简单且正确的,但是缺少了并发的能力。

学生提问:但是在XV6我还是可以有多个transaction,只是说不能异步的执行它们,对吗?

Robert教授:这里其实有点模糊,XV6实际上允许在一个transaction中包含多个系统调用(注,详见15.8),所以XV6有一些并发和batching的能力,但是当XV6决定要commit一个transaction时,在完全完成这个transaction之前,是不能执行任何新的系统调用的。因为直到前一个transaction完全完成,并没有log空间来存放新的系统调用。所以XV6要么是在运行一些系统调用,要么是在commit transaction,但是它不能同时干这两件事情,而ext3可以同时干这两件事情。