by cszhao1980
系统定义了NBUF个缓存区域,每个514个字节:
4720: char buffers[NBUF][514];
【注】:514个字节稍稍大于一个物理盘块的size,多出的2个byte的用途不明。
而“缓存头”数组buf[NBUF]的每个entry对应一个缓存区域,其b_addr被设置为对应的缓存区
的首地址,如:&buffers[1]。对于缓存的使用都是通过其缓存头数组entry来完成。
【思考题】:为什么这里可以直接使用逻辑地址,如:&buffers[1]?
Unix使用两种(带头结点的)双向循环链表(队列)来管理这些缓存,即
(1) AV队列:即空闲队列,对首为buf bfreelist;
(2) B队列:即设备的任务队列,对首为某设备(devtab类型)。
显然,可以有多个b队列。
【注】:在b队列当中,对首是devtab类型,而成员都是buf类型。该链表得以形成的原因是两种类
型都用同名的成员(b_forw和b_back)作为前后指针,而且,它们的这两种struct中的位置是相同的。
总的原则是,空闲的缓存将挂在AV队列中,当需要操作某设备时就从AV队列中取下,挂到该
设备的b队列中,而设备操作完成后,又重新将其放还到AV队列中。
系统的某些实现使这一过程显得有些晦涩:
(1) 在设备操作完成后,会将缓存放回到AV队列,但没有将该缓存从原设备的b队列中取
下来——这一步是在再次分配该缓存时完成的。即在分配缓存时,分为3步
i. 从AV队列中取下;
ii. 从原设备队列中取下;
iii. 挂到新设备队列中。
(2) 问题来了,在系统初启阶段,所有缓存都没有分配过设备,那么其“原设备队列”在哪?
为解决这一问题,系统定义了一个特殊的设备队列——空闲设备队列,其设备号为-1,其
首指针为我们的老朋友buf freelist。
之所以会采用这样的设计,是为了支持“延迟写”技术,以提高效率。所谓“延迟写”即写入缓存
的内容不会马上被写入磁盘——真正的写入是在用户程序或“定时”程序调用flush时完成的。
(1) 要支持“延迟写”,缓存必须仍挂在设备队列中,否则磁盘内容就会丢失;
(2) 如果直到真正写入后,缓存才可以释放回AV队列,有可能造成缓存资源紧张;
所以系统采用了这样的方式:
(1) 一旦对缓存的写入结束,该缓存即释放入AV队列,但其flag设置了B_DELWRI标志;
(2) 如果该缓存被再次分配,会检查器B_DELWRI标志,如其置位,则首先执行写入,再
将此缓存分配给新设备。
博客地址:http://blog.csdn.net/cszhao1980
博客专栏地址:http://blog.csdn.net/column/details/lions-unix.html