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.3 ext3 file system log format

Previous16.2 XV6 File system logging回顾Next16.4 ext3如何提升性能

Last updated 4 years ago

Was this helpful?

ext3文件系统就是基于今天要阅读的,再加上几年的开发得到的,并且ext3也曾经广泛的应用过。ext3是针对之前一种的文件系统(ext2)logging方案的修改,所以ext3就是在几乎不改变之前的ext2文件系统的前提下,在其上增加一层logging系统。所以某种程度来说,logging是一个容易升级的模块。

ext3的数据结构与XV6是类似的。在内存中,存在block cache,这是一种write-back cache(注,区别于write-through cache,指的是cache稍后才会同步到真正的后端)。block cache中缓存了一些block,其中的一些是干净的数据,因为它们与磁盘上的数据是一致的;其他一些是脏数据,因为从磁盘读出来之后被修改过;有一些被固定在cache中,基于前面介绍的write-ahead rule和freeing rule,不被允许写回到磁盘中。

除此之外,ext3还维护了一些transaction信息。它可以维护多个在不同阶段的transaction的信息。每个transaction的信息包含有:

  • 一个序列号

  • 一系列该transaction修改的block编号。这些block编号指向的是在cache中的block,因为任何修改最初都是在cache中完成。

  • 以及一系列的handle,handle对应了系统调用,并且这些系统调用是transaction的一部分,会读写cache中的block

在磁盘上,与XV6一样:

  • 会有一个文件系统树,包含了inode,目录,文件等等

  • 会有bitmap block来表明每个data block是被分配的还是空闲的

  • 在磁盘的一个指定区域,会保存log

目前为止,这与XV6非常相似。主要的区别在于ext3可以同时跟踪多个在不同执行阶段的transaction。

接下来我们详细看一下ext3的log中有什么,这与XV6中的log有点不一样。在log的最开始,是super block。这是log的super block,而不是文件系统的super block。log的super block包含了log中第一个有效的transaction的起始位置和序列号。起始位置就是磁盘上log分区的block编号,序列号就是前面提到的每个transaction都有的序列号。log是磁盘上一段固定大小的连续的block。log中,除了super block以外的block存储了transaction。每个transaction在log中包含了:

  • 一个descriptor block,其中包含了log数据对应的实际block编号,这与XV6中的header block很像。

  • 之后是针对每一个block编号的更新数据。

  • 最后当一个transaction完成并commit了,会有一个commit block

因为log中可能有多个transaction,commit block之后可能会跟着下一个transaction的descriptor block,data block和commit block。所以log可能会很长并包含多个transaction。我们可以认为super block中的起始位置和序列号属于最早的,排名最靠前的,并且是有效的transaction。

这里有一些细节对于后面的内容很重要。在crash之后的恢复过程会扫描log,为了将descriptor block和commit block与data block区分开,descriptor block和commit block会以一个32bit的魔法数字作为起始。这个魔法数字不太可能出现在数据中,并且可以帮助恢复软件区分不同的block。

学生提问:有没有可能使用一个descriptor block管理两个transaction?是不是只能一个transaction结束了才能开始下一个transaction?

Robert教授:Log中会有多个transaction,但是的确一个时间只有一个正在进行的transaction。上面的图片没能很好的说明这一点,当前正在进行的transaction对应的是正在执行写操作的系统调用。所以当前正在进行的transaction只存在于内存中,对应的系统调用只会更新cache中的block,也就是内存中的文件系统block。当ext3决定结束当前正在进行的transaction,它会做两件事情:首先开始一个新的transaction,这将会是下一个transaction;其次将刚刚完成的transaction写入到磁盘中,这可能要花一点时间。所以完整的故事是,磁盘上的log分区有一系列旧的transaction,这些transaction已经commit了,除此之外,还有一个位于内存的正在进行的transaction。在磁盘上的transaction,只能以log记录的形式存在,并且还没有写到对应的文件系统block中。logging系统在后台会从最早的transaction开始,将transaction中的data block写入到对应的文件系统中。当整个transaction的data block都写完了,之后logging系统才能释放并重用log中的空间。所以log其实是个循环的数据结构,如果用到了log的最后,logging系统会从log的最开始位置重新使用。

记住这里的log的结构,它对于后面的内容也很重要。

论文