从硬件+操作系统的角度解释为什么操作系统的IO单位是磁盘块

不同版本的操作系统的 buffer_head 代表的大小可能不一样,但是都是内存和硬盘交换数据的基本单元。

意思是:每次磁盘驱动程序,能写入到硬盘缓存区的数据大小 = buffer_head 代表的大小,线程会等待磁盘缓冲区的内容真正刷入扇区中

写入完成后再唤醒线程,再次将一个块写入到磁盘缓冲区。

 

我们用旧一点的 Linux 版本验证一下,下图出自 毛德操的《Linux源代码情景分析》

在磁盘的驱动程序向磁盘相关的控制寄存器写入控制信息之后(写入起始扇区号,读还是写等信息)

能向硬盘的写入的 字(16位)数是固定的 一个扇区的字节数,总共写入的字节数 = 扇区大小 * 2

当前语境下的 buffer_head 是 1024 字节,扇区是 512 字节,也就是磁盘块 1024 字节,扇区 512 字节,写入磁盘缓冲区的大小就是磁盘块的大小

随后驱动程序再次写相关的控制寄存器,开启真正的磁盘IO,使得磁盘缓冲区内容写入物理扇区,在此期间写入数据的IO进程如果是阻塞模式需要等待写入完成。

磁盘缓冲区写入到扇区完成后会发出中断,中断程序会唤醒IO进程,IO进程再将下一个 buffer_head 写入磁盘缓冲区,重复上述步骤,这种频繁唤醒睡眠的机制很低效,在新版本应该有优化

 

 

 

 

驱动程序是硬件厂商(当前考虑硬盘)结合目标操作系统编写的,需要依赖目标操作系统的数据结构(结构体定义),那么也就可以硬件厂商会根据 linux 不同版本的 buffer_head 的大小,还要自己制造的硬件的规格,控制一次能写入磁盘缓冲区的数据大小,让他刚好等于 buffer_head,遵循 linux 的初衷。

 

节点大小为一个磁盘块,使得一次IO操作就能完成一个节点的写入,读/写一个块 只用一次 中断唤醒,提高效率

 

关于中断程序和驱动程序的区别:

 

 

驱动程序

主要负责对硬件设备的读写,因为不同硬件制造厂商制造硬件的规格各不相同,就要按照自己的规格结合目标操作系统写出良好的驱动程序。

读写当然属于硬件规格的范畴,而且多事一些对控制寄存器和数据寄存器的读写操作(如果操作系统支持 in,out 指令,输入输出几乎都用in ,out)

包括写外设的某些控制寄存器,以准备读写,以及把数据写出到硬件的数据寄存器(CPU拷贝)
或者开启 DMA 进行数据拷贝

 

中断程序

以硬盘为例,当硬盘读数据到硬盘硬件上的缓存区(应该是寄存器组)完毕,就会通过硬件中断让CPU调用 读取中断程序,主要是拷贝
硬盘缓冲区上的数据到内存中的缓存页上

唤醒在缓冲页上等待的进程,因为进程要读取/写某个缓存页,并且阻塞的话,会进入buffer的
等待队列,中断程序做的就是唤醒他
如果还有已经从磁盘缓冲区读到内存的缓存页待操作,就调整req的下一个缓存页,处理下一个请求页(唤醒该页上等待的进程等)

如果是写入完成,会把缓存页的干净标志设为1

 

一个请求可能请求 N 个扇区,但是一次中断只完成了 M 个扇区的读取,这次中断只能从硬盘缓冲区拷贝 M 个缓存页到 内存
接下去的 N - M 仍然需要多个中断程序来完成

不同缓冲区可能对应连续的扇区,但是还是得按缓冲区为单位操作,每次只能读/写一个缓冲区(buffer_head)

 

posted @ 2020-11-16 22:21  执生  阅读(50)  评论(0编辑  收藏