概述
为了加快系统读取磁盘(及外设)的速度,在内存中开辟一块区域缓存磁盘上的数据,这块区域为disk cache(即磁盘高速缓存)
本章主要探讨disk cache的数据结构、读写磁盘块内容的算法等等。
缓冲区的相关数据结构
**缓冲区包括两大部分:**缓冲头部和数据区。缓冲头部用于索引、查找、记录缓冲区状态等,数据区是存放缓存的磁盘的数据。
缓冲头部的数据结构如下:
- 设备号、块号、状态(设备号指的是逻辑设备号)
- 指向数据区的指针
- 指向散列队列上/下一个缓冲区头部的指针
- 指向空闲表上/下一个缓冲区头部的指针
数据区用来存放数据,没有什么数据结构可言。
缓冲头部中,引入了两个数据结构:空闲表和散列队列(两者都是双向链表):这两个数据结构都是利用缓冲头部中存放的指针实现的。其中,空闲表用来记录空闲缓冲区及延迟写缓冲区(。。。。。)。散列队列有多个,是用来记录哪些磁盘块已经在缓冲区了。
缓冲区分配算法getblk
当进程需要读取磁盘块中的数据时,首先检查在缓冲区中是否已经存在。若存在则进行相应操作;若不存在则需将磁盘块中的数据加载到缓冲区中,再进行相应操作。
os检查磁盘块数据是否已经在缓冲区中时,分为以下五种结果:
- 1.os发现该磁盘块数据已经在散列队列中,且它的缓冲区状态是空闲的。
- 2.os发现该磁盘块数据已经在散列队列中,但它的缓冲区状态为忙。
- 3.os发现散列队列中找不到该块,因此从空闲表中分配一个缓冲区。
- 4.os发现散列队列中找不到该块,并且,从空闲表中分配了一个缓冲区的时候,发现其有“延迟写”的标记。
- 5.os发现散列队列中找不到该块,并且空闲缓冲区已经为空。
对于以上五种情况,分别采取不同的措施:
- 1.将该缓冲区状态标位忙,且从空闲表中取下(可以使得其他进程无法获取)
- 2.这种情况表明有其他进程也在使用该磁盘块,应该阻塞(睡眠)当前进程,等待被brelse算法(释放缓冲区时进行的动作)唤醒。
- 3.os把空闲表中的第一个缓冲区摘下,并标记为忙,指定新的设备号、磁盘块号。
- 4.os把摘下的带有“延迟写”标志的缓冲区异步写到磁盘,然后标为空闲,放入空闲链表头部。再进行3操作
- 5.进行睡眠等待brelse算法唤醒。
缓冲区释放算法brelse
当内核结束使用缓冲区时,按照brelse算法释放缓冲区
brelse算法:
- 唤醒正在等待“无论哪个缓冲区变为空闲”这一事件发生的所有进程(即上述第四种情况)
- 唤醒正在等待“这个缓冲区变为空闲”这一事件发生的所有进程(即上述第二种情况)
- 关中断(为了执行以下操作)
- 如果缓冲区内容有效且缓冲区非“旧”,放入空闲表尾部;否则放入头部
- 开中断
- 给缓冲区解锁 ???(什么时候上锁了)
区分几种写入方式
- 同步写:等待IO事件结束在释放缓冲区。
- 异步写:进程不等待IO事件完成,继续往下执行。内核IO完成后释放缓冲区。
- 延迟写:把该缓冲区标为“延迟写”,并释放该缓冲区,在此搜索到时在写入磁盘中。